diff options
author | serxa <serxa@yandex-team.ru> | 2022-02-10 16:49:08 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:49:08 +0300 |
commit | d6d7db348c2cc64e71243cab9940ee6778f4317d (patch) | |
tree | bac67f42a02f9368eb4d329f5d79b77d0a6adc18 | |
parent | 8d57b69dee81198a59c39e64704f7dc9f04b4fbf (diff) | |
download | ydb-d6d7db348c2cc64e71243cab9940ee6778f4317d.tar.gz |
Restoring authorship annotation for <serxa@yandex-team.ru>. Commit 1 of 2.
458 files changed, 30235 insertions, 30235 deletions
diff --git a/library/cpp/actors/core/actor.cpp b/library/cpp/actors/core/actor.cpp index 6f9ba6a42b..d46d3e9b50 100644 --- a/library/cpp/actors/core/actor.cpp +++ b/library/cpp/actors/core/actor.cpp @@ -1,7 +1,7 @@ #include "actor.h" #include "executor_thread.h" #include "mailbox.h" -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> namespace NActors { Y_POD_THREAD(TActivationContext*) @@ -88,7 +88,7 @@ namespace NActors { } i64 TActivationContext::GetCurrentEventTicks() { - return GetCycleCountFast() - TlsActivationContext->EventStart; + return GetCycleCountFast() - TlsActivationContext->EventStart; } double TActivationContext::GetCurrentEventTicksAsSeconds() { diff --git a/library/cpp/actors/core/actor_ut.cpp b/library/cpp/actors/core/actor_ut.cpp index e1b765ec72..0146b5a6de 100644 --- a/library/cpp/actors/core/actor_ut.cpp +++ b/library/cpp/actors/core/actor_ut.cpp @@ -35,7 +35,7 @@ struct TTestEndDecorator : TDecorator { }; Y_UNIT_TEST_SUITE(ActorBenchmark) { - static constexpr bool DefaultNoRealtime = true; + static constexpr bool DefaultNoRealtime = true; static constexpr ui32 DefaultSpinThreshold = 1000000; static constexpr ui32 TotalEventsAmount = 1000; @@ -43,49 +43,49 @@ Y_UNIT_TEST_SUITE(ActorBenchmark) { public: TDummyActor() : TActor<TDummyActor>(&TDummyActor::StateFunc) {} STFUNC(StateFunc) { - (void)ev; + (void)ev; (void)ctx; } }; - enum ERole { - Leader, - Follower - }; - + enum ERole { + Leader, + Follower + }; + class TSendReceiveActor : public TActorBootstrapped<TSendReceiveActor> { public: static constexpr auto ActorActivityType() { return ACTORLIB_COMMON; } - TSendReceiveActor(double* elapsedTime, TActorId receiver, bool allocation, ERole role, ui32 neighbours = 0) - : EventsCounter(TotalEventsAmount) - , ElapsedTime(elapsedTime) - , Receiver(receiver) - , AllocatesMemory(allocation) - , Role(role) - , MailboxNeighboursCount(neighbours) + TSendReceiveActor(double* elapsedTime, TActorId receiver, bool allocation, ERole role, ui32 neighbours = 0) + : EventsCounter(TotalEventsAmount) + , ElapsedTime(elapsedTime) + , Receiver(receiver) + , AllocatesMemory(allocation) + , Role(role) + , MailboxNeighboursCount(neighbours) {} void Bootstrap(const TActorContext &ctx) { if (!Receiver) { this->Receiver = SelfId(); - } else { - EventsCounter /= 2; // We want to measure CPU requirement for one-way send + } else { + EventsCounter /= 2; // We want to measure CPU requirement for one-way send } Timer.Reset(); Become(&TThis::StateFunc); for (ui32 i = 0; i < MailboxNeighboursCount; ++i) { ctx.RegisterWithSameMailbox(new TDummyActor()); } - if (Role == Leader) { - Send(Receiver, new TEvents::TEvPing()); - } + if (Role == Leader) { + Send(Receiver, new TEvents::TEvPing()); + } } STATEFN(StateFunc) { - if (EventsCounter == 0 && ElapsedTime != nullptr) { + if (EventsCounter == 0 && ElapsedTime != nullptr) { *ElapsedTime = Timer.Passed() / TotalEventsAmount; PassAway(); } @@ -97,91 +97,91 @@ Y_UNIT_TEST_SUITE(ActorBenchmark) { ev->DropRewrite(); TActivationContext::Send(ev.Release()); } - EventsCounter--; + EventsCounter--; } private: THPTimer Timer; - ui64 EventsCounter; + ui64 EventsCounter; double* ElapsedTime; TActorId Receiver; bool AllocatesMemory; - ERole Role; + ERole Role; ui32 MailboxNeighboursCount; }; - void AddBasicPool(THolder<TActorSystemSetup>& setup, ui32 threads, bool activateEveryEvent) { - TBasicExecutorPoolConfig basic; - basic.PoolId = setup->GetExecutorsCount(); - basic.PoolName = TStringBuilder() << "b" << basic.PoolId; - basic.Threads = threads; - basic.SpinThreshold = DefaultSpinThreshold; - basic.TimePerMailbox = TDuration::Hours(1); - if (activateEveryEvent) { - basic.EventsPerMailbox = 1; - } else { - basic.EventsPerMailbox = Max<ui32>(); - } - setup->CpuManager.Basic.emplace_back(std::move(basic)); - } - - void AddUnitedPool(THolder<TActorSystemSetup>& setup, ui32 concurrency, bool activateEveryEvent) { - TUnitedExecutorPoolConfig united; - united.PoolId = setup->GetExecutorsCount(); - united.PoolName = TStringBuilder() << "u" << united.PoolId; - united.Concurrency = concurrency; - united.TimePerMailbox = TDuration::Hours(1); - if (activateEveryEvent) { - united.EventsPerMailbox = 1; - } else { - united.EventsPerMailbox = Max<ui32>(); - } - setup->CpuManager.United.emplace_back(std::move(united)); - } - - THolder<TActorSystemSetup> GetActorSystemSetup(ui32 unitedCpuCount, bool preemption) { - auto setup = MakeHolder<NActors::TActorSystemSetup>(); - setup->NodeId = 1; - setup->CpuManager.UnitedWorkers.CpuCount = unitedCpuCount; - setup->CpuManager.UnitedWorkers.SpinThresholdUs = DefaultSpinThreshold; - setup->CpuManager.UnitedWorkers.NoRealtime = DefaultNoRealtime; - if (preemption) { - setup->CpuManager.UnitedWorkers.PoolLimitUs = 500; - setup->CpuManager.UnitedWorkers.EventLimitUs = 100; - setup->CpuManager.UnitedWorkers.LimitPrecisionUs = 100; - } else { - setup->CpuManager.UnitedWorkers.PoolLimitUs = 100'000'000'000; - setup->CpuManager.UnitedWorkers.EventLimitUs = 10'000'000'000; - setup->CpuManager.UnitedWorkers.LimitPrecisionUs = 10'000'000'000; - } - setup->Scheduler = new TBasicSchedulerThread(NActors::TSchedulerConfig(512, 0)); - return setup; - } - - enum class EPoolType { - Basic, - United - }; - - THolder<TActorSystemSetup> InitActorSystemSetup(EPoolType poolType, ui32 poolsCount, ui32 threads, bool activateEveryEvent, bool preemption) { - if (poolType == EPoolType::Basic) { - THolder<TActorSystemSetup> setup = GetActorSystemSetup(0, false); - for (ui32 i = 0; i < poolsCount; ++i) { - AddBasicPool(setup, threads, activateEveryEvent); - } - return setup; - } else if (poolType == EPoolType::United) { - THolder<TActorSystemSetup> setup = GetActorSystemSetup(poolsCount * threads, preemption); - for (ui32 i = 0; i < poolsCount; ++i) { - AddUnitedPool(setup, threads, activateEveryEvent); - } - return setup; + void AddBasicPool(THolder<TActorSystemSetup>& setup, ui32 threads, bool activateEveryEvent) { + TBasicExecutorPoolConfig basic; + basic.PoolId = setup->GetExecutorsCount(); + basic.PoolName = TStringBuilder() << "b" << basic.PoolId; + basic.Threads = threads; + basic.SpinThreshold = DefaultSpinThreshold; + basic.TimePerMailbox = TDuration::Hours(1); + if (activateEveryEvent) { + basic.EventsPerMailbox = 1; + } else { + basic.EventsPerMailbox = Max<ui32>(); } - Y_FAIL(); - } - - double BenchSendReceive(bool allocation, NActors::TMailboxType::EType mType, EPoolType poolType) { - THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, 1, false, false); + setup->CpuManager.Basic.emplace_back(std::move(basic)); + } + + void AddUnitedPool(THolder<TActorSystemSetup>& setup, ui32 concurrency, bool activateEveryEvent) { + TUnitedExecutorPoolConfig united; + united.PoolId = setup->GetExecutorsCount(); + united.PoolName = TStringBuilder() << "u" << united.PoolId; + united.Concurrency = concurrency; + united.TimePerMailbox = TDuration::Hours(1); + if (activateEveryEvent) { + united.EventsPerMailbox = 1; + } else { + united.EventsPerMailbox = Max<ui32>(); + } + setup->CpuManager.United.emplace_back(std::move(united)); + } + + THolder<TActorSystemSetup> GetActorSystemSetup(ui32 unitedCpuCount, bool preemption) { + auto setup = MakeHolder<NActors::TActorSystemSetup>(); + setup->NodeId = 1; + setup->CpuManager.UnitedWorkers.CpuCount = unitedCpuCount; + setup->CpuManager.UnitedWorkers.SpinThresholdUs = DefaultSpinThreshold; + setup->CpuManager.UnitedWorkers.NoRealtime = DefaultNoRealtime; + if (preemption) { + setup->CpuManager.UnitedWorkers.PoolLimitUs = 500; + setup->CpuManager.UnitedWorkers.EventLimitUs = 100; + setup->CpuManager.UnitedWorkers.LimitPrecisionUs = 100; + } else { + setup->CpuManager.UnitedWorkers.PoolLimitUs = 100'000'000'000; + setup->CpuManager.UnitedWorkers.EventLimitUs = 10'000'000'000; + setup->CpuManager.UnitedWorkers.LimitPrecisionUs = 10'000'000'000; + } + setup->Scheduler = new TBasicSchedulerThread(NActors::TSchedulerConfig(512, 0)); + return setup; + } + + enum class EPoolType { + Basic, + United + }; + + THolder<TActorSystemSetup> InitActorSystemSetup(EPoolType poolType, ui32 poolsCount, ui32 threads, bool activateEveryEvent, bool preemption) { + if (poolType == EPoolType::Basic) { + THolder<TActorSystemSetup> setup = GetActorSystemSetup(0, false); + for (ui32 i = 0; i < poolsCount; ++i) { + AddBasicPool(setup, threads, activateEveryEvent); + } + return setup; + } else if (poolType == EPoolType::United) { + THolder<TActorSystemSetup> setup = GetActorSystemSetup(poolsCount * threads, preemption); + for (ui32 i = 0; i < poolsCount; ++i) { + AddUnitedPool(setup, threads, activateEveryEvent); + } + return setup; + } + Y_FAIL(); + } + + double BenchSendReceive(bool allocation, NActors::TMailboxType::EType mType, EPoolType poolType) { + THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, 1, false, false); TActorSystem actorSystem(setup); actorSystem.Start(); @@ -197,86 +197,86 @@ Y_UNIT_TEST_SUITE(ActorBenchmark) { pad.Park(); actorSystem.Stop(); - return 1e9 * elapsedTime; + return 1e9 * elapsedTime; } - double BenchSendActivateReceive(ui32 poolsCount, ui32 threads, bool allocation, EPoolType poolType) { - THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, poolsCount, threads, true, false); - TActorSystem actorSystem(setup); + double BenchSendActivateReceive(ui32 poolsCount, ui32 threads, bool allocation, EPoolType poolType) { + THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, poolsCount, threads, true, false); + TActorSystem actorSystem(setup); actorSystem.Start(); TThreadParkPad pad; TAtomic actorsAlive = 0; double elapsedTime = 0; - ui32 followerPoolId = 0; + ui32 followerPoolId = 0; - ui32 leaderPoolId = poolsCount == 1 ? 0 : 1; - TActorId followerId = actorSystem.Register( - new TSendReceiveActor(nullptr, {}, allocation, Follower), TMailboxType::HTSwap, followerPoolId); + ui32 leaderPoolId = poolsCount == 1 ? 0 : 1; + TActorId followerId = actorSystem.Register( + new TSendReceiveActor(nullptr, {}, allocation, Follower), TMailboxType::HTSwap, followerPoolId); THolder<IActor> leader{ new TTestEndDecorator(THolder( new TSendReceiveActor(&elapsedTime, followerId, allocation, Leader)), &pad, &actorsAlive)}; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); - + actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); + pad.Park(); actorSystem.Stop(); - return 1e9 * elapsedTime; + return 1e9 * elapsedTime; } - double BenchSendActivateReceiveWithMailboxNeighbours(ui32 MailboxNeighbourActors, EPoolType poolType) { - THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, 1, false, false); - TActorSystem actorSystem(setup); + double BenchSendActivateReceiveWithMailboxNeighbours(ui32 MailboxNeighbourActors, EPoolType poolType) { + THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, 1, false, false); + TActorSystem actorSystem(setup); actorSystem.Start(); TThreadParkPad pad; TAtomic actorsAlive = 0; double elapsedTime = 0; - TActorId followerId = actorSystem.Register( - new TSendReceiveActor(nullptr, {}, false, Follower, MailboxNeighbourActors), TMailboxType::HTSwap); + TActorId followerId = actorSystem.Register( + new TSendReceiveActor(nullptr, {}, false, Follower, MailboxNeighbourActors), TMailboxType::HTSwap); THolder<IActor> leader{ new TTestEndDecorator(THolder( new TSendReceiveActor(&elapsedTime, followerId, false, Leader, MailboxNeighbourActors)), &pad, &actorsAlive)}; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap); + actorSystem.Register(leader.Release(), TMailboxType::HTSwap); pad.Park(); actorSystem.Stop(); - return 1e9 * elapsedTime; + return 1e9 * elapsedTime; } - double BenchContentedThreads(ui32 threads, ui32 actorsPairsCount, EPoolType poolType) { - THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, threads, true, false); - TActorSystem actorSystem(setup); + double BenchContentedThreads(ui32 threads, ui32 actorsPairsCount, EPoolType poolType) { + THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, threads, true, false); + TActorSystem actorSystem(setup); actorSystem.Start(); TThreadParkPad pad; TAtomic actorsAlive = 0; THPTimer Timer; - TVector<double> dummy(actorsPairsCount); + TVector<double> dummy(actorsPairsCount); Timer.Reset(); for (ui32 i = 0; i < actorsPairsCount; ++i) { - ui32 followerPoolId = 0; - ui32 leaderPoolId = 0; - TActorId followerId = actorSystem.Register( - new TSendReceiveActor(nullptr, {}, true, Follower), TMailboxType::HTSwap, followerPoolId); + ui32 followerPoolId = 0; + ui32 leaderPoolId = 0; + TActorId followerId = actorSystem.Register( + new TSendReceiveActor(nullptr, {}, true, Follower), TMailboxType::HTSwap, followerPoolId); THolder<IActor> leader{ new TTestEndDecorator(THolder( new TSendReceiveActor(&dummy[i], followerId, true, Leader)), &pad, &actorsAlive)}; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); + actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); } pad.Park(); auto elapsedTime = Timer.Passed() / TotalEventsAmount; actorSystem.Stop(); - return 1e9 * elapsedTime; + return 1e9 * elapsedTime; } auto Mean(const TVector<double>& data) { - return Accumulate(data.begin(), data.end(), 0.0) / data.size(); + return Accumulate(data.begin(), data.end(), 0.0) / data.size(); } auto Deviation(const TVector<double>& data) { @@ -285,19 +285,19 @@ Y_UNIT_TEST_SUITE(ActorBenchmark) { for (const auto& x : data) { deviation += (x - mean) * (x - mean); } - return std::sqrt(deviation / data.size()); + return std::sqrt(deviation / data.size()); } struct TStats { double Mean; double Deviation; TString ToString() { - return TStringBuilder() << Mean << " ± " << Deviation << " ns " << std::ceil(Deviation / Mean * 1000) / 10.0 << "%"; + return TStringBuilder() << Mean << " ± " << Deviation << " ns " << std::ceil(Deviation / Mean * 1000) / 10.0 << "%"; } }; template <typename Func> - TStats CountStats(Func func, ui32 itersCount = 5) { + TStats CountStats(Func func, ui32 itersCount = 5) { TVector<double> elapsedTimes; for (ui32 i = 0; i < itersCount; ++i) { auto elapsedTime = func(); @@ -314,171 +314,171 @@ Y_UNIT_TEST_SUITE(ActorBenchmark) { TMailboxType::TinyReadAsFilled }; - Y_UNIT_TEST(SendReceive1Pool1ThreadAlloc) { - for (const auto& mType : MailboxTypes) { - auto stats = CountStats([mType] { - return BenchSendReceive(true, mType, EPoolType::Basic); - }); - Cerr << stats.ToString() << " " << mType << Endl; - } - } - - Y_UNIT_TEST(SendReceive1Pool1ThreadAllocUnited) { + Y_UNIT_TEST(SendReceive1Pool1ThreadAlloc) { for (const auto& mType : MailboxTypes) { auto stats = CountStats([mType] { - return BenchSendReceive(true, mType, EPoolType::United); + return BenchSendReceive(true, mType, EPoolType::Basic); }); Cerr << stats.ToString() << " " << mType << Endl; } } + Y_UNIT_TEST(SendReceive1Pool1ThreadAllocUnited) { + for (const auto& mType : MailboxTypes) { + auto stats = CountStats([mType] { + return BenchSendReceive(true, mType, EPoolType::United); + }); + Cerr << stats.ToString() << " " << mType << Endl; + } + } + Y_UNIT_TEST(SendReceive1Pool1ThreadNoAlloc) { for (const auto& mType : MailboxTypes) { auto stats = CountStats([mType] { - return BenchSendReceive(false, mType, EPoolType::Basic); + return BenchSendReceive(false, mType, EPoolType::Basic); }); Cerr << stats.ToString() << " " << mType << Endl; } } - - Y_UNIT_TEST(SendReceive1Pool1ThreadNoAllocUnited) { - for (const auto& mType : MailboxTypes) { - auto stats = CountStats([mType] { - return BenchSendReceive(false, mType, EPoolType::United); - }); - Cerr << stats.ToString() << " " << mType << Endl; - } - } - + + Y_UNIT_TEST(SendReceive1Pool1ThreadNoAllocUnited) { + for (const auto& mType : MailboxTypes) { + auto stats = CountStats([mType] { + return BenchSendReceive(false, mType, EPoolType::United); + }); + Cerr << stats.ToString() << " " << mType << Endl; + } + } + Y_UNIT_TEST(SendActivateReceive1Pool1ThreadAlloc) { auto stats = CountStats([] { - return BenchSendActivateReceive(1, 1, true, EPoolType::Basic); - }); - Cerr << stats.ToString() << Endl; - } - - Y_UNIT_TEST(SendActivateReceive1Pool1ThreadAllocUnited) { - auto stats = CountStats([] { - return BenchSendActivateReceive(1, 1, true, EPoolType::United); + return BenchSendActivateReceive(1, 1, true, EPoolType::Basic); }); Cerr << stats.ToString() << Endl; } + Y_UNIT_TEST(SendActivateReceive1Pool1ThreadAllocUnited) { + auto stats = CountStats([] { + return BenchSendActivateReceive(1, 1, true, EPoolType::United); + }); + Cerr << stats.ToString() << Endl; + } + Y_UNIT_TEST(SendActivateReceive1Pool1ThreadNoAlloc) { auto stats = CountStats([] { - return BenchSendActivateReceive(1, 1, false, EPoolType::Basic); - }); - Cerr << stats.ToString() << Endl; - } - - Y_UNIT_TEST(SendActivateReceive1Pool1ThreadNoAllocUnited) { - auto stats = CountStats([] { - return BenchSendActivateReceive(1, 1, false, EPoolType::United); + return BenchSendActivateReceive(1, 1, false, EPoolType::Basic); }); Cerr << stats.ToString() << Endl; } + Y_UNIT_TEST(SendActivateReceive1Pool1ThreadNoAllocUnited) { + auto stats = CountStats([] { + return BenchSendActivateReceive(1, 1, false, EPoolType::United); + }); + Cerr << stats.ToString() << Endl; + } + Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsAlloc) { auto stats = CountStats([] { - return BenchSendActivateReceive(1, 2, true, EPoolType::Basic); - }); - Cerr << stats.ToString() << Endl; - } - - Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsAllocUnited) { - auto stats = CountStats([] { - return BenchSendActivateReceive(1, 2, true, EPoolType::United); + return BenchSendActivateReceive(1, 2, true, EPoolType::Basic); }); Cerr << stats.ToString() << Endl; } + Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsAllocUnited) { + auto stats = CountStats([] { + return BenchSendActivateReceive(1, 2, true, EPoolType::United); + }); + Cerr << stats.ToString() << Endl; + } + Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsNoAlloc) { auto stats = CountStats([] { - return BenchSendActivateReceive(1, 2, false, EPoolType::Basic); - }); - Cerr << stats.ToString() << Endl; - } - - Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsNoAllocUnited) { - auto stats = CountStats([] { - return BenchSendActivateReceive(1, 2, false, EPoolType::United); - }); - Cerr << stats.ToString() << Endl; - } - - Y_UNIT_TEST(SendActivateReceive2Pool1ThreadAlloc) { - auto stats = CountStats([] { - return BenchSendActivateReceive(2, 1, true, EPoolType::Basic); - }); - Cerr << stats.ToString() << Endl; - } - - Y_UNIT_TEST(SendActivateReceive2Pool1ThreadAllocUnited) { - auto stats = CountStats([] { - return BenchSendActivateReceive(2, 1, true, EPoolType::United); + return BenchSendActivateReceive(1, 2, false, EPoolType::Basic); }); Cerr << stats.ToString() << Endl; } - Y_UNIT_TEST(SendActivateReceive2Pool1ThreadNoAlloc) { + Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsNoAllocUnited) { auto stats = CountStats([] { - return BenchSendActivateReceive(2, 1, false, EPoolType::Basic); + return BenchSendActivateReceive(1, 2, false, EPoolType::United); }); Cerr << stats.ToString() << Endl; } - Y_UNIT_TEST(SendActivateReceive2Pool1ThreadNoAllocUnited) { + Y_UNIT_TEST(SendActivateReceive2Pool1ThreadAlloc) { auto stats = CountStats([] { - return BenchSendActivateReceive(2, 1, false, EPoolType::United); + return BenchSendActivateReceive(2, 1, true, EPoolType::Basic); }); Cerr << stats.ToString() << Endl; } - void RunBenchContentedThreads(ui32 threads, EPoolType poolType) { - for (ui32 actorPairs = 1; actorPairs <= 2 * threads; actorPairs++) { - auto stats = CountStats([threads, actorPairs, poolType] { - return BenchContentedThreads(threads, actorPairs, poolType); - }); - Cerr << stats.ToString() << " actorPairs: " << actorPairs << Endl; - } - } - - Y_UNIT_TEST(SendActivateReceive1Pool1Threads) { RunBenchContentedThreads(1, EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool1ThreadsUnited) { RunBenchContentedThreads(1, EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool2Threads) { RunBenchContentedThreads(2, EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsUnited) { RunBenchContentedThreads(2, EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool3Threads) { RunBenchContentedThreads(3, EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool3ThreadsUnited) { RunBenchContentedThreads(3, EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool4Threads) { RunBenchContentedThreads(4, EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool4ThreadsUnited) { RunBenchContentedThreads(4, EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool5Threads) { RunBenchContentedThreads(5, EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool5ThreadsUnited) { RunBenchContentedThreads(5, EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool6Threads) { RunBenchContentedThreads(6, EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool6ThreadsUnited) { RunBenchContentedThreads(6, EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool7Threads) { RunBenchContentedThreads(7, EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool7ThreadsUnited) { RunBenchContentedThreads(7, EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool8Threads) { RunBenchContentedThreads(8, EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool8ThreadsUnited) { RunBenchContentedThreads(8, EPoolType::United); } - + Y_UNIT_TEST(SendActivateReceive2Pool1ThreadAllocUnited) { + auto stats = CountStats([] { + return BenchSendActivateReceive(2, 1, true, EPoolType::United); + }); + Cerr << stats.ToString() << Endl; + } + + Y_UNIT_TEST(SendActivateReceive2Pool1ThreadNoAlloc) { + auto stats = CountStats([] { + return BenchSendActivateReceive(2, 1, false, EPoolType::Basic); + }); + Cerr << stats.ToString() << Endl; + } + + Y_UNIT_TEST(SendActivateReceive2Pool1ThreadNoAllocUnited) { + auto stats = CountStats([] { + return BenchSendActivateReceive(2, 1, false, EPoolType::United); + }); + Cerr << stats.ToString() << Endl; + } + + void RunBenchContentedThreads(ui32 threads, EPoolType poolType) { + for (ui32 actorPairs = 1; actorPairs <= 2 * threads; actorPairs++) { + auto stats = CountStats([threads, actorPairs, poolType] { + return BenchContentedThreads(threads, actorPairs, poolType); + }); + Cerr << stats.ToString() << " actorPairs: " << actorPairs << Endl; + } + } + + Y_UNIT_TEST(SendActivateReceive1Pool1Threads) { RunBenchContentedThreads(1, EPoolType::Basic); } + Y_UNIT_TEST(SendActivateReceive1Pool1ThreadsUnited) { RunBenchContentedThreads(1, EPoolType::United); } + Y_UNIT_TEST(SendActivateReceive1Pool2Threads) { RunBenchContentedThreads(2, EPoolType::Basic); } + Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsUnited) { RunBenchContentedThreads(2, EPoolType::United); } + Y_UNIT_TEST(SendActivateReceive1Pool3Threads) { RunBenchContentedThreads(3, EPoolType::Basic); } + Y_UNIT_TEST(SendActivateReceive1Pool3ThreadsUnited) { RunBenchContentedThreads(3, EPoolType::United); } + Y_UNIT_TEST(SendActivateReceive1Pool4Threads) { RunBenchContentedThreads(4, EPoolType::Basic); } + Y_UNIT_TEST(SendActivateReceive1Pool4ThreadsUnited) { RunBenchContentedThreads(4, EPoolType::United); } + Y_UNIT_TEST(SendActivateReceive1Pool5Threads) { RunBenchContentedThreads(5, EPoolType::Basic); } + Y_UNIT_TEST(SendActivateReceive1Pool5ThreadsUnited) { RunBenchContentedThreads(5, EPoolType::United); } + Y_UNIT_TEST(SendActivateReceive1Pool6Threads) { RunBenchContentedThreads(6, EPoolType::Basic); } + Y_UNIT_TEST(SendActivateReceive1Pool6ThreadsUnited) { RunBenchContentedThreads(6, EPoolType::United); } + Y_UNIT_TEST(SendActivateReceive1Pool7Threads) { RunBenchContentedThreads(7, EPoolType::Basic); } + Y_UNIT_TEST(SendActivateReceive1Pool7ThreadsUnited) { RunBenchContentedThreads(7, EPoolType::United); } + Y_UNIT_TEST(SendActivateReceive1Pool8Threads) { RunBenchContentedThreads(8, EPoolType::Basic); } + Y_UNIT_TEST(SendActivateReceive1Pool8ThreadsUnited) { RunBenchContentedThreads(8, EPoolType::United); } + Y_UNIT_TEST(SendActivateReceiveWithMailboxNeighbours) { TVector<ui32> NeighbourActors = {0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256}; for (const auto& neighbour : NeighbourActors) { auto stats = CountStats([neighbour] { - return BenchSendActivateReceiveWithMailboxNeighbours(neighbour, EPoolType::Basic); - }); - Cerr << stats.ToString() << " neighbourActors: " << neighbour << Endl; - } - } - - Y_UNIT_TEST(SendActivateReceiveWithMailboxNeighboursUnited) { - TVector<ui32> NeighbourActors = {0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256}; - for (const auto& neighbour : NeighbourActors) { - auto stats = CountStats([neighbour] { - return BenchSendActivateReceiveWithMailboxNeighbours(neighbour, EPoolType::United); + return BenchSendActivateReceiveWithMailboxNeighbours(neighbour, EPoolType::Basic); }); - Cerr << stats.ToString() << " neighbourActors: " << neighbour << Endl; + Cerr << stats.ToString() << " neighbourActors: " << neighbour << Endl; } } + + Y_UNIT_TEST(SendActivateReceiveWithMailboxNeighboursUnited) { + TVector<ui32> NeighbourActors = {0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256}; + for (const auto& neighbour : NeighbourActors) { + auto stats = CountStats([neighbour] { + return BenchSendActivateReceiveWithMailboxNeighbours(neighbour, EPoolType::United); + }); + Cerr << stats.ToString() << " neighbourActors: " << neighbour << Endl; + } + } } Y_UNIT_TEST_SUITE(TestDecorator) { diff --git a/library/cpp/actors/core/actorid.h b/library/cpp/actors/core/actorid.h index d972b1a0ff..b8c41f5dd8 100644 --- a/library/cpp/actors/core/actorid.h +++ b/library/cpp/actors/core/actorid.h @@ -180,7 +180,7 @@ namespace NActors { }; static_assert(sizeof(TActorId) == 16, "expect sizeof(TActorId) == 16"); - static_assert(MaxPools < TActorId::MaxPoolID); // current implementation of united pool has limit MaxPools on pool id + static_assert(MaxPools < TActorId::MaxPoolID); // current implementation of united pool has limit MaxPools on pool id } template <> diff --git a/library/cpp/actors/core/actorsystem.cpp b/library/cpp/actors/core/actorsystem.cpp index c58698a206..b2bed85f92 100644 --- a/library/cpp/actors/core/actorsystem.cpp +++ b/library/cpp/actors/core/actorsystem.cpp @@ -1,7 +1,7 @@ #include "defs.h" #include "actorsystem.h" #include "callstack.h" -#include "cpu_manager.h" +#include "cpu_manager.h" #include "mailbox.h" #include "events.h" #include "interconnect.h" @@ -9,10 +9,10 @@ #include "scheduler_queue.h" #include "scheduler_actor.h" #include "log.h" -#include "probes.h" +#include "probes.h" #include "ask.h" #include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> #include <util/generic/hash.h> #include <util/system/rwlock.h> #include <util/random/random.h> @@ -38,8 +38,8 @@ namespace NActors { TActorSystem::TActorSystem(THolder<TActorSystemSetup>& setup, void* appData, TIntrusivePtr<NLog::TSettings> loggerSettings) : NodeId(setup->NodeId) - , CpuManager(new TCpuManager(setup)) - , ExecutorPoolCount(CpuManager->GetExecutorsCount()) + , CpuManager(new TCpuManager(setup)) + , ExecutorPoolCount(CpuManager->GetExecutorsCount()) , Scheduler(setup->Scheduler) , InterconnectCount((ui32)setup->Interconnect.ProxyActors.size()) , CurrentTimestamp(0) @@ -105,10 +105,10 @@ namespace NActors { Y_VERIFY_DEBUG(recipient == ev->GetRecipientRewrite()); const ui32 recpPool = recipient.PoolID(); if (recipient && recpPool < ExecutorPoolCount) { - if (CpuManager->GetExecutorPool(recpPool)->Send(ev)) { + if (CpuManager->GetExecutorPool(recpPool)->Send(ev)) { return true; - } - } + } + } Send(ev->ForwardOnNondelivery(TEvents::TEvUndelivered::ReasonActorUnknown)); return false; @@ -142,7 +142,7 @@ namespace NActors { const TActorId& parentId) { Y_VERIFY(executorPool < ExecutorPoolCount, "executorPool# %" PRIu32 ", ExecutorPoolCount# %" PRIu32, (ui32)executorPool, (ui32)ExecutorPoolCount); - return CpuManager->GetExecutorPool(executorPool)->Register(actor, mailboxType, revolvingCounter, parentId); + return CpuManager->GetExecutorPool(executorPool)->Register(actor, mailboxType, revolvingCounter, parentId); } NThreading::TFuture<THolder<IEventBase>> TActorSystem::AskGeneric(TMaybe<ui32> expectedEventType, @@ -199,20 +199,20 @@ namespace NActors { return ServiceMap->RegisterLocalService(serviceId, actorId); } - void TActorSystem::GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - CpuManager->GetPoolStats(poolId, poolStats, statsCopy); - } - + void TActorSystem::GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { + CpuManager->GetPoolStats(poolId, poolStats, statsCopy); + } + void TActorSystem::Start() { Y_VERIFY(StartExecuted == false); StartExecuted = true; - ScheduleQueue.Reset(new NSchedulerQueue::TQueueType()); + ScheduleQueue.Reset(new NSchedulerQueue::TQueueType()); TVector<NSchedulerQueue::TReader*> scheduleReaders; scheduleReaders.push_back(&ScheduleQueue->Reader); - CpuManager->PrepareStart(scheduleReaders, this); + CpuManager->PrepareStart(scheduleReaders, this); Scheduler->Prepare(this, &CurrentTimestamp, &CurrentMonotonic); - Scheduler->PrepareSchedules(&scheduleReaders.front(), (ui32)scheduleReaders.size()); + Scheduler->PrepareSchedules(&scheduleReaders.front(), (ui32)scheduleReaders.size()); // setup interconnect proxies { @@ -243,7 +243,7 @@ namespace NActors { SystemSetup.Destroy(); Scheduler->PrepareStart(); - CpuManager->Start(); + CpuManager->Start(); Send(MakeSchedulerActorId(), new TEvSchedulerInitialize(scheduleReaders, &CurrentTimestamp, &CurrentMonotonic)); Scheduler->Start(); } @@ -259,9 +259,9 @@ namespace NActors { } Scheduler->PrepareStop(); - CpuManager->PrepareStop(); + CpuManager->PrepareStop(); Scheduler->Stop(); - CpuManager->Shutdown(); + CpuManager->Shutdown(); } void TActorSystem::Cleanup() { @@ -269,7 +269,7 @@ namespace NActors { if (CleanupExecuted || !StartExecuted) return; CleanupExecuted = true; - CpuManager->Cleanup(); + CpuManager->Cleanup(); Scheduler.Destroy(); } diff --git a/library/cpp/actors/core/actorsystem.h b/library/cpp/actors/core/actorsystem.h index 40499d7586..d6d88ba0c2 100644 --- a/library/cpp/actors/core/actorsystem.h +++ b/library/cpp/actors/core/actorsystem.h @@ -1,27 +1,27 @@ #pragma once #include "defs.h" - -#include "actor.h" -#include "balancer.h" -#include "config.h" + +#include "actor.h" +#include "balancer.h" +#include "config.h" #include "event.h" #include "log_settings.h" #include "scheduler_cookie.h" #include "mon_stats.h" - + #include <library/cpp/threading/future/future.h> #include <library/cpp/actors/util/ticket_lock.h> - + #include <util/generic/vector.h> #include <util/datetime/base.h> #include <util/system/mutex.h> namespace NActors { class TActorSystem; - class TCpuManager; + class TCpuManager; class IExecutorPool; - struct TWorkerContext; + struct TWorkerContext; inline TActorId MakeInterconnectProxyId(ui32 destNodeId) { char data[12]; @@ -62,9 +62,9 @@ namespace NActors { virtual ~IExecutorPool() { } - // for workers - virtual ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) = 0; - virtual void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingCounter) = 0; + // for workers + virtual ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) = 0; + virtual void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingCounter) = 0; /** * Schedule one-shot event that will be send at given time point in the future. @@ -72,9 +72,9 @@ namespace NActors { * @param deadline the wallclock time point in future when event must be send * @param ev the event to send * @param cookie cookie that will be piggybacked with event - * @param workerId index of thread which will perform event dispatching + * @param workerId index of thread which will perform event dispatching */ - virtual void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0; + virtual void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0; /** * Schedule one-shot event that will be send at given time point in the future. @@ -82,9 +82,9 @@ namespace NActors { * @param deadline the monotonic time point in future when event must be send * @param ev the event to send * @param cookie cookie that will be piggybacked with event - * @param workerId index of thread which will perform event dispatching + * @param workerId index of thread which will perform event dispatching */ - virtual void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0; + virtual void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0; /** * Schedule one-shot event that will be send after given delay. @@ -92,9 +92,9 @@ namespace NActors { * @param delta the time from now to delay event sending * @param ev the event to send * @param cookie cookie that will be piggybacked with event - * @param workerId index of thread which will perform event dispatching + * @param workerId index of thread which will perform event dispatching */ - virtual void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0; + virtual void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0; // for actorsystem virtual bool Send(TAutoPtr<IEventHandle>& ev) = 0; @@ -104,7 +104,7 @@ namespace NActors { virtual TActorId Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) = 0; // lifecycle stuff - virtual void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) = 0; + virtual void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) = 0; virtual void Start() = 0; virtual void PrepareStop() = 0; virtual void Shutdown() = 0; @@ -115,7 +115,7 @@ namespace NActors { Y_UNUSED(poolStats); Y_UNUSED(statsCopy); } - + virtual TString GetName() const { return TString(); } @@ -127,7 +127,7 @@ namespace NActors { // generic virtual TAffinity* Affinity() const = 0; - virtual void SetRealTimeMode() const {} + virtual void SetRealTimeMode() const {} }; // could be proxy to in-pool schedulers (for NUMA-aware executors) @@ -137,7 +137,7 @@ namespace NActors { } virtual void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) = 0; - virtual void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) = 0; + virtual void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) = 0; virtual void PrepareStart() { /* empty */ } virtual void Start() = 0; virtual void PrepareStop() = 0; @@ -180,14 +180,14 @@ namespace NActors { struct TActorSystemSetup { ui32 NodeId = 0; - // Either Executors or CpuManager must be initialized + // Either Executors or CpuManager must be initialized ui32 ExecutorsCount = 0; TArrayHolder<TAutoPtr<IExecutorPool>> Executors; - - TAutoPtr<IBalancer> Balancer; // main implementation will be implicitly created if not set - - TCpuManagerConfig CpuManager; - + + TAutoPtr<IBalancer> Balancer; // main implementation will be implicitly created if not set + + TCpuManagerConfig CpuManager; + TAutoPtr<ISchedulerThread> Scheduler; ui32 MaxActivityType = 5; // for default entries @@ -195,18 +195,18 @@ namespace NActors { using TLocalServices = TVector<std::pair<TActorId, TActorSetupCmd>>; TLocalServices LocalServices; - - ui32 GetExecutorsCount() const { - return Executors ? ExecutorsCount : CpuManager.GetExecutorsCount(); - } - - TString GetPoolName(ui32 poolId) const { - return Executors ? Executors[poolId]->GetName() : CpuManager.GetPoolName(poolId); - } - - ui32 GetThreads(ui32 poolId) const { - return Executors ? Executors[poolId]->GetThreads() : CpuManager.GetThreads(poolId); - } + + ui32 GetExecutorsCount() const { + return Executors ? ExecutorsCount : CpuManager.GetExecutorsCount(); + } + + TString GetPoolName(ui32 poolId) const { + return Executors ? Executors[poolId]->GetName() : CpuManager.GetPoolName(poolId); + } + + ui32 GetThreads(ui32 poolId) const { + return Executors ? Executors[poolId]->GetThreads() : CpuManager.GetThreads(poolId); + } }; class TActorSystem : TNonCopyable { @@ -214,9 +214,9 @@ namespace NActors { public: const ui32 NodeId; - + private: - THolder<TCpuManager> CpuManager; + THolder<TCpuManager> CpuManager; const ui32 ExecutorPoolCount; TAutoPtr<ISchedulerThread> Scheduler; @@ -353,7 +353,7 @@ namespace NActors { return LoggerSettings0.Get(); } - void GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const; + void GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const; void DeferPreStop(std::function<void()> fn) { DeferredPreStop.push_back(std::move(fn)); diff --git a/library/cpp/actors/core/balancer.cpp b/library/cpp/actors/core/balancer.cpp index cc5417b0b5..6ee975bec1 100644 --- a/library/cpp/actors/core/balancer.cpp +++ b/library/cpp/actors/core/balancer.cpp @@ -1,293 +1,293 @@ -#include "balancer.h" - -#include "probes.h" - -#include <library/cpp/actors/util/intrinsics.h> -#include <library/cpp/actors/util/datetime.h> - -#include <util/system/spinlock.h> - -#include <algorithm> - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - // Describes balancing-related state of pool, the most notable is `Importance` to add new cpu - struct TLevel { - // Balancer will try to give more cpu to overloaded pools - enum ELoadClass { - Underloaded = 0, - Moderate = 1, - Overloaded = 2, - }; - - double ScaleFactor; - ELoadClass LoadClass; - ui64 Importance; // pool with lower importance is allowed to pass cpu to pool with higher, but the opposite is forbidden - - TLevel() {} - - TLevel(const TBalancingConfig& cfg, TPoolId poolId, ui64 currentCpus, double cpuIdle) { - ScaleFactor = double(currentCpus) / cfg.Cpus; - if (cpuIdle > 1.3) { // TODO: add a better underload criterion, based on estimated latency w/o 1 cpu - LoadClass = Underloaded; - } else if (cpuIdle < 0.2) { // TODO: add a better overload criterion, based on latency - LoadClass = Overloaded; - } else { - LoadClass = Moderate; - } - Importance = MakeImportance(LoadClass, cfg.Priority, ScaleFactor, cpuIdle, poolId); - } - - private: - // Importance is simple ui64 value (from highest to lowest): - // 2 Bits: LoadClass - // 8 Bits: Priority - // 10 Bits: -ScaleFactor (for max-min fairness with weights equal to TBalancingConfig::Cpus) - // 10 Bits: -CpuIdle - // 6 Bits: PoolId - static ui64 MakeImportance(ELoadClass load, ui8 priority, double scaleFactor, double cpuIdle, TPoolId poolId) { - ui64 idle = std::clamp<i64>(1024 - cpuIdle * 512, 0, 1023); - ui64 scale = std::clamp<i64>(1024 - scaleFactor * 32, 0, 1023); - - Y_VERIFY(ui64(load) < (1ull << 2ull)); - Y_VERIFY(ui64(priority) < (1ull << 8ull)); - Y_VERIFY(ui64(scale) < (1ull << 10ull)); - Y_VERIFY(ui64(idle) < (1ull << 10ull)); - Y_VERIFY(ui64(poolId) < (1ull << 6ull)); - - static_assert(ui64(MaxPools) <= (1ull << 6ull)); - - ui64 importance = - (ui64(load) << ui64(6 + 10 + 10 + 8)) | - (ui64(priority) << ui64(6 + 10 + 10)) | - (ui64(scale) << ui64(6 + 10)) | - (ui64(idle) << ui64(6)) | - ui64(poolId); - return importance; - } - }; - - // Main balancer implemenation - class TBalancer: public IBalancer { - private: - struct TCpu; - struct TPool; - - bool Disabled = true; - TSpinLock Lock; - ui64 NextBalanceTs; - TVector<TCpu> Cpus; // Indexed by CpuId, can have gaps - TVector<TPool> Pools; // Indexed by PoolId, can have gaps - TBalancerConfig Config; - - public: - // Setup - TBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts); - bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) override; - ~TBalancer(); - - // Balancing - bool TryLock(ui64 ts) override; - void SetPoolStats(TPoolId pool, const TBalancerStats& stats) override; - void Balance() override; - void Unlock() override; - - private: - void MoveCpu(TPool& from, TPool& to); - }; - - struct TBalancer::TPool { - TBalancingConfig Config; - TPoolId PoolId; - TString PoolName; - - // Input data for balancing - TBalancerStats Prev; - TBalancerStats Next; - - // Derived stats - double CpuLoad; - double CpuIdle; - - // Classification - // NOTE: We want to avoid passing cpu back and forth, so we must consider not only current level, - // NOTE: but expected levels after movements also - TLevel CurLevel; // Level with current amount of cpu - TLevel AddLevel; // Level after one cpu acception - TLevel SubLevel; // Level after one cpu donation - - // Balancing state - ui64 CurrentCpus = 0; // Total number of cpus assigned for this pool (zero means pools is not balanced) - ui64 PrevCpus = 0; // Cpus in last period - - explicit TPool(const TBalancingConfig& cfg = {}) - : Config(cfg) - {} - - void Configure(const TBalancingConfig& cfg, const TString& poolName) { - Config = cfg; - // Enforce constraints - Config.MinCpus = std::clamp<ui32>(Config.MinCpus, 1, Config.Cpus); - Config.MaxCpus = Max<ui32>(Config.MaxCpus, Config.Cpus); - PoolName = poolName; - } - }; - - struct TBalancer::TCpu { - TCpuState* State = nullptr; // Cpu state, nullptr means cpu is not used (gap) - TCpuAllocation Alloc; - TPoolId Current; - TPoolId Assigned; - }; - - TBalancer::TBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts) - : NextBalanceTs(ts) - , Config(config) - { - for (TPoolId pool = 0; pool < MaxPools; pool++) { - Pools.emplace_back(); - Pools.back().PoolId = pool; - } - for (const TUnitedExecutorPoolConfig& united : unitedPools) { - Pools[united.PoolId].Configure(united.Balancing, united.PoolName); - } - } - - TBalancer::~TBalancer() { - } - - bool TBalancer::AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* state) { - // Setup - TCpuId cpuId = cpuAlloc.CpuId; - if (Cpus.size() <= cpuId) { - Cpus.resize(cpuId + 1); - } - TCpu& cpu = Cpus[cpuId]; - cpu.State = state; - cpu.Alloc = cpuAlloc; - - // Fill every pool with cpus up to TBalancingConfig::Cpus - TPoolId pool = 0; - for (TPool& p : Pools) { - if (p.CurrentCpus < p.Config.Cpus) { - p.CurrentCpus++; - break; - } - pool++; - } - if (pool != MaxPools) { // cpu under balancer control - state->SwitchPool(pool); - state->AssignPool(pool); - Disabled = false; - return true; - } - return false; // non-balanced cpu - } - - bool TBalancer::TryLock(ui64 ts) { - if (!Disabled && NextBalanceTs < ts && Lock.TryAcquire()) { - NextBalanceTs = ts + Us2Ts(Config.PeriodUs); - return true; - } - return false; - } - - void TBalancer::SetPoolStats(TPoolId pool, const TBalancerStats& stats) { - Y_VERIFY(pool < MaxPools); - TPool& p = Pools[pool]; - p.Prev = p.Next; - p.Next = stats; - } - - void TBalancer::Balance() { - // Update every cpu state - for (TCpu& cpu : Cpus) { - if (cpu.State) { - cpu.State->Load(cpu.Assigned, cpu.Current); - if (cpu.Current < MaxPools && cpu.Current != cpu.Assigned) { - return; // previous movement has not been applied yet, wait - } - } - } - - // Process stats, classify and compute pool importance - TStackVec<TPool*, MaxPools> order; - for (TPool& pool : Pools) { - if (pool.Config.Cpus == 0) { - continue; // skip gaps (non-existent or non-united pools) - } - if (pool.Prev.Ts == 0 || pool.Prev.Ts >= pool.Next.Ts) { - return; // invalid stats - } - - // Compute derived stats - pool.CpuLoad = (pool.Next.CpuUs - pool.Prev.CpuUs) / Ts2Us(pool.Next.Ts - pool.Prev.Ts); - if (pool.Prev.IdleUs == ui64(-1) || pool.Next.IdleUs == ui64(-1)) { - pool.CpuIdle = pool.CurrentCpus - pool.CpuLoad; // for tests - } else { - pool.CpuIdle = (pool.Next.IdleUs - pool.Prev.IdleUs) / Ts2Us(pool.Next.Ts - pool.Prev.Ts); - } - - // Compute levels - pool.CurLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus, pool.CpuIdle); - pool.AddLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus + 1, pool.CpuIdle); // we expect taken cpu to became utilized - pool.SubLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus - 1, pool.CpuIdle - 1); - - // Prepare for balancing - pool.PrevCpus = pool.CurrentCpus; - order.push_back(&pool); - } - - // Sort pools by importance - std::sort(order.begin(), order.end(), [] (TPool* l, TPool* r) {return l->CurLevel.Importance < r->CurLevel.Importance; }); - for (TPool* pool : order) { - LWPROBE(PoolStats, pool->PoolId, pool->PoolName, pool->CurrentCpus, pool->CurLevel.LoadClass, pool->Config.Priority, pool->CurLevel.ScaleFactor, pool->CpuIdle, pool->CpuLoad, pool->CurLevel.Importance, pool->AddLevel.Importance, pool->SubLevel.Importance); - } - - // Move cpus from lower importance to higher importance pools - for (auto toIter = order.rbegin(); toIter != order.rend(); ++toIter) { - TPool& to = **toIter; - if (to.CurLevel.LoadClass == TLevel::Overloaded && // if pool is overloaded - to.CurrentCpus < to.Config.MaxCpus) // and constraints would not be violated - { - for (auto fromIter = order.begin(); (*fromIter)->CurLevel.Importance < to.CurLevel.Importance; ++fromIter) { - TPool& from = **fromIter; - if (from.CurrentCpus == from.PrevCpus && // if not balanced yet - from.CurrentCpus > from.Config.MinCpus && // and constraints would not be violated - from.SubLevel.Importance < to.AddLevel.Importance) // and which of two pools is more important would not change after cpu movement - { - MoveCpu(from, to); - from.CurrentCpus--; - to.CurrentCpus++; - break; - } - } - } - } - } - - void TBalancer::MoveCpu(TBalancer::TPool& from, TBalancer::TPool& to) { - for (auto ci = Cpus.rbegin(), ce = Cpus.rend(); ci != ce; ci++) { - TCpu& cpu = *ci; - if (!cpu.State) { - continue; - } - if (cpu.Assigned == from.PoolId) { - cpu.State->AssignPool(to.PoolId); - cpu.Assigned = to.PoolId; - LWPROBE(MoveCpu, from.PoolId, to.PoolId, from.PoolName, to.PoolName, cpu.Alloc.CpuId); - return; - } - } - Y_FAIL(); - } - - void TBalancer::Unlock() { - Lock.Release(); - } - - IBalancer* MakeBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts) { - return new TBalancer(config, unitedPools, ts); - } -} +#include "balancer.h" + +#include "probes.h" + +#include <library/cpp/actors/util/intrinsics.h> +#include <library/cpp/actors/util/datetime.h> + +#include <util/system/spinlock.h> + +#include <algorithm> + +namespace NActors { + LWTRACE_USING(ACTORLIB_PROVIDER); + + // Describes balancing-related state of pool, the most notable is `Importance` to add new cpu + struct TLevel { + // Balancer will try to give more cpu to overloaded pools + enum ELoadClass { + Underloaded = 0, + Moderate = 1, + Overloaded = 2, + }; + + double ScaleFactor; + ELoadClass LoadClass; + ui64 Importance; // pool with lower importance is allowed to pass cpu to pool with higher, but the opposite is forbidden + + TLevel() {} + + TLevel(const TBalancingConfig& cfg, TPoolId poolId, ui64 currentCpus, double cpuIdle) { + ScaleFactor = double(currentCpus) / cfg.Cpus; + if (cpuIdle > 1.3) { // TODO: add a better underload criterion, based on estimated latency w/o 1 cpu + LoadClass = Underloaded; + } else if (cpuIdle < 0.2) { // TODO: add a better overload criterion, based on latency + LoadClass = Overloaded; + } else { + LoadClass = Moderate; + } + Importance = MakeImportance(LoadClass, cfg.Priority, ScaleFactor, cpuIdle, poolId); + } + + private: + // Importance is simple ui64 value (from highest to lowest): + // 2 Bits: LoadClass + // 8 Bits: Priority + // 10 Bits: -ScaleFactor (for max-min fairness with weights equal to TBalancingConfig::Cpus) + // 10 Bits: -CpuIdle + // 6 Bits: PoolId + static ui64 MakeImportance(ELoadClass load, ui8 priority, double scaleFactor, double cpuIdle, TPoolId poolId) { + ui64 idle = std::clamp<i64>(1024 - cpuIdle * 512, 0, 1023); + ui64 scale = std::clamp<i64>(1024 - scaleFactor * 32, 0, 1023); + + Y_VERIFY(ui64(load) < (1ull << 2ull)); + Y_VERIFY(ui64(priority) < (1ull << 8ull)); + Y_VERIFY(ui64(scale) < (1ull << 10ull)); + Y_VERIFY(ui64(idle) < (1ull << 10ull)); + Y_VERIFY(ui64(poolId) < (1ull << 6ull)); + + static_assert(ui64(MaxPools) <= (1ull << 6ull)); + + ui64 importance = + (ui64(load) << ui64(6 + 10 + 10 + 8)) | + (ui64(priority) << ui64(6 + 10 + 10)) | + (ui64(scale) << ui64(6 + 10)) | + (ui64(idle) << ui64(6)) | + ui64(poolId); + return importance; + } + }; + + // Main balancer implemenation + class TBalancer: public IBalancer { + private: + struct TCpu; + struct TPool; + + bool Disabled = true; + TSpinLock Lock; + ui64 NextBalanceTs; + TVector<TCpu> Cpus; // Indexed by CpuId, can have gaps + TVector<TPool> Pools; // Indexed by PoolId, can have gaps + TBalancerConfig Config; + + public: + // Setup + TBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts); + bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) override; + ~TBalancer(); + + // Balancing + bool TryLock(ui64 ts) override; + void SetPoolStats(TPoolId pool, const TBalancerStats& stats) override; + void Balance() override; + void Unlock() override; + + private: + void MoveCpu(TPool& from, TPool& to); + }; + + struct TBalancer::TPool { + TBalancingConfig Config; + TPoolId PoolId; + TString PoolName; + + // Input data for balancing + TBalancerStats Prev; + TBalancerStats Next; + + // Derived stats + double CpuLoad; + double CpuIdle; + + // Classification + // NOTE: We want to avoid passing cpu back and forth, so we must consider not only current level, + // NOTE: but expected levels after movements also + TLevel CurLevel; // Level with current amount of cpu + TLevel AddLevel; // Level after one cpu acception + TLevel SubLevel; // Level after one cpu donation + + // Balancing state + ui64 CurrentCpus = 0; // Total number of cpus assigned for this pool (zero means pools is not balanced) + ui64 PrevCpus = 0; // Cpus in last period + + explicit TPool(const TBalancingConfig& cfg = {}) + : Config(cfg) + {} + + void Configure(const TBalancingConfig& cfg, const TString& poolName) { + Config = cfg; + // Enforce constraints + Config.MinCpus = std::clamp<ui32>(Config.MinCpus, 1, Config.Cpus); + Config.MaxCpus = Max<ui32>(Config.MaxCpus, Config.Cpus); + PoolName = poolName; + } + }; + + struct TBalancer::TCpu { + TCpuState* State = nullptr; // Cpu state, nullptr means cpu is not used (gap) + TCpuAllocation Alloc; + TPoolId Current; + TPoolId Assigned; + }; + + TBalancer::TBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts) + : NextBalanceTs(ts) + , Config(config) + { + for (TPoolId pool = 0; pool < MaxPools; pool++) { + Pools.emplace_back(); + Pools.back().PoolId = pool; + } + for (const TUnitedExecutorPoolConfig& united : unitedPools) { + Pools[united.PoolId].Configure(united.Balancing, united.PoolName); + } + } + + TBalancer::~TBalancer() { + } + + bool TBalancer::AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* state) { + // Setup + TCpuId cpuId = cpuAlloc.CpuId; + if (Cpus.size() <= cpuId) { + Cpus.resize(cpuId + 1); + } + TCpu& cpu = Cpus[cpuId]; + cpu.State = state; + cpu.Alloc = cpuAlloc; + + // Fill every pool with cpus up to TBalancingConfig::Cpus + TPoolId pool = 0; + for (TPool& p : Pools) { + if (p.CurrentCpus < p.Config.Cpus) { + p.CurrentCpus++; + break; + } + pool++; + } + if (pool != MaxPools) { // cpu under balancer control + state->SwitchPool(pool); + state->AssignPool(pool); + Disabled = false; + return true; + } + return false; // non-balanced cpu + } + + bool TBalancer::TryLock(ui64 ts) { + if (!Disabled && NextBalanceTs < ts && Lock.TryAcquire()) { + NextBalanceTs = ts + Us2Ts(Config.PeriodUs); + return true; + } + return false; + } + + void TBalancer::SetPoolStats(TPoolId pool, const TBalancerStats& stats) { + Y_VERIFY(pool < MaxPools); + TPool& p = Pools[pool]; + p.Prev = p.Next; + p.Next = stats; + } + + void TBalancer::Balance() { + // Update every cpu state + for (TCpu& cpu : Cpus) { + if (cpu.State) { + cpu.State->Load(cpu.Assigned, cpu.Current); + if (cpu.Current < MaxPools && cpu.Current != cpu.Assigned) { + return; // previous movement has not been applied yet, wait + } + } + } + + // Process stats, classify and compute pool importance + TStackVec<TPool*, MaxPools> order; + for (TPool& pool : Pools) { + if (pool.Config.Cpus == 0) { + continue; // skip gaps (non-existent or non-united pools) + } + if (pool.Prev.Ts == 0 || pool.Prev.Ts >= pool.Next.Ts) { + return; // invalid stats + } + + // Compute derived stats + pool.CpuLoad = (pool.Next.CpuUs - pool.Prev.CpuUs) / Ts2Us(pool.Next.Ts - pool.Prev.Ts); + if (pool.Prev.IdleUs == ui64(-1) || pool.Next.IdleUs == ui64(-1)) { + pool.CpuIdle = pool.CurrentCpus - pool.CpuLoad; // for tests + } else { + pool.CpuIdle = (pool.Next.IdleUs - pool.Prev.IdleUs) / Ts2Us(pool.Next.Ts - pool.Prev.Ts); + } + + // Compute levels + pool.CurLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus, pool.CpuIdle); + pool.AddLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus + 1, pool.CpuIdle); // we expect taken cpu to became utilized + pool.SubLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus - 1, pool.CpuIdle - 1); + + // Prepare for balancing + pool.PrevCpus = pool.CurrentCpus; + order.push_back(&pool); + } + + // Sort pools by importance + std::sort(order.begin(), order.end(), [] (TPool* l, TPool* r) {return l->CurLevel.Importance < r->CurLevel.Importance; }); + for (TPool* pool : order) { + LWPROBE(PoolStats, pool->PoolId, pool->PoolName, pool->CurrentCpus, pool->CurLevel.LoadClass, pool->Config.Priority, pool->CurLevel.ScaleFactor, pool->CpuIdle, pool->CpuLoad, pool->CurLevel.Importance, pool->AddLevel.Importance, pool->SubLevel.Importance); + } + + // Move cpus from lower importance to higher importance pools + for (auto toIter = order.rbegin(); toIter != order.rend(); ++toIter) { + TPool& to = **toIter; + if (to.CurLevel.LoadClass == TLevel::Overloaded && // if pool is overloaded + to.CurrentCpus < to.Config.MaxCpus) // and constraints would not be violated + { + for (auto fromIter = order.begin(); (*fromIter)->CurLevel.Importance < to.CurLevel.Importance; ++fromIter) { + TPool& from = **fromIter; + if (from.CurrentCpus == from.PrevCpus && // if not balanced yet + from.CurrentCpus > from.Config.MinCpus && // and constraints would not be violated + from.SubLevel.Importance < to.AddLevel.Importance) // and which of two pools is more important would not change after cpu movement + { + MoveCpu(from, to); + from.CurrentCpus--; + to.CurrentCpus++; + break; + } + } + } + } + } + + void TBalancer::MoveCpu(TBalancer::TPool& from, TBalancer::TPool& to) { + for (auto ci = Cpus.rbegin(), ce = Cpus.rend(); ci != ce; ci++) { + TCpu& cpu = *ci; + if (!cpu.State) { + continue; + } + if (cpu.Assigned == from.PoolId) { + cpu.State->AssignPool(to.PoolId); + cpu.Assigned = to.PoolId; + LWPROBE(MoveCpu, from.PoolId, to.PoolId, from.PoolName, to.PoolName, cpu.Alloc.CpuId); + return; + } + } + Y_FAIL(); + } + + void TBalancer::Unlock() { + Lock.Release(); + } + + IBalancer* MakeBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts) { + return new TBalancer(config, unitedPools, ts); + } +} diff --git a/library/cpp/actors/core/balancer.h b/library/cpp/actors/core/balancer.h index 9763ec79e1..cf4ea776f0 100644 --- a/library/cpp/actors/core/balancer.h +++ b/library/cpp/actors/core/balancer.h @@ -1,27 +1,27 @@ -#pragma once - -#include "defs.h" -#include "config.h" -#include "cpu_state.h" - -namespace NActors { - // Per-pool statistics used by balancer - struct TBalancerStats { - ui64 Ts = 0; // Measurement timestamp - ui64 CpuUs = 0; // Total cpu microseconds consumed by pool on all cpus since start - ui64 IdleUs = ui64(-1); // Total cpu microseconds in spinning or waiting on futex - }; - - // Pool cpu balancer - struct IBalancer { - virtual ~IBalancer() {} - virtual bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) = 0; - virtual bool TryLock(ui64 ts) = 0; - virtual void SetPoolStats(TPoolId pool, const TBalancerStats& stats) = 0; - virtual void Balance() = 0; - virtual void Unlock() = 0; - // TODO: add method for reconfiguration on fly - }; - - IBalancer* MakeBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts); -} +#pragma once + +#include "defs.h" +#include "config.h" +#include "cpu_state.h" + +namespace NActors { + // Per-pool statistics used by balancer + struct TBalancerStats { + ui64 Ts = 0; // Measurement timestamp + ui64 CpuUs = 0; // Total cpu microseconds consumed by pool on all cpus since start + ui64 IdleUs = ui64(-1); // Total cpu microseconds in spinning or waiting on futex + }; + + // Pool cpu balancer + struct IBalancer { + virtual ~IBalancer() {} + virtual bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) = 0; + virtual bool TryLock(ui64 ts) = 0; + virtual void SetPoolStats(TPoolId pool, const TBalancerStats& stats) = 0; + virtual void Balance() = 0; + virtual void Unlock() = 0; + // TODO: add method for reconfiguration on fly + }; + + IBalancer* MakeBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts); +} diff --git a/library/cpp/actors/core/balancer_ut.cpp b/library/cpp/actors/core/balancer_ut.cpp index 7e5e95f4b9..ac4ebdccb3 100644 --- a/library/cpp/actors/core/balancer_ut.cpp +++ b/library/cpp/actors/core/balancer_ut.cpp @@ -1,225 +1,225 @@ -#include "balancer.h" - -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/lwtrace/all.h> -#include <library/cpp/testing/unittest/registar.h> - -#include <util/stream/str.h> - -using namespace NActors; - -//////////////////////////////////////////////////////////////////////////////// - -Y_UNIT_TEST_SUITE(PoolCpuBalancer) { - struct TTest { - TCpuManagerConfig Config; - TCpuMask Available; - THolder<IBalancer> Balancer; - TVector<TCpuState> CpuStates; - TVector<ui64> CpuUs; - ui64 Now = 0; - - void SetCpuCount(size_t count) { - Config.UnitedWorkers.CpuCount = count; - for (TCpuId cpuId = 0; cpuId < count; cpuId++) { - Available.Set(cpuId); - } - } - - void AddPool(ui32 minCpus, ui32 cpus, ui32 maxCpus, ui8 priority = 0) { - TUnitedExecutorPoolConfig u; - u.PoolId = TPoolId(Config.United.size()); - u.Balancing.Cpus = cpus; - u.Balancing.MinCpus = minCpus; - u.Balancing.MaxCpus = maxCpus; - u.Balancing.Priority = priority; - Config.United.push_back(u); - } - - void Start() { - TCpuAllocationConfig allocation(Available, Config); - Balancer.Reset(MakeBalancer(Config.UnitedWorkers.Balancer, Config.United, 0)); - CpuStates.resize(allocation.Items.size()); // do not resize it later to avoid dangling pointers - CpuUs.resize(CpuStates.size()); - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - bool added = Balancer->AddCpu(cpuAlloc, &CpuStates[cpuAlloc.CpuId]); - UNIT_ASSERT(added); - } - } - - void Balance(ui64 deltaTs, const TVector<ui64>& cpuUs) { - Now += deltaTs; - ui64 ts = Now; - if (Balancer->TryLock(ts)) { - for (TPoolId pool = 0; pool < cpuUs.size(); pool++) { - CpuUs[pool] += cpuUs[pool]; - TBalancerStats stats; - stats.Ts = ts; - stats.CpuUs = CpuUs[pool]; - Balancer->SetPoolStats(pool, stats); - } - Balancer->Balance(); - Balancer->Unlock(); - } - } - - void ApplyMovements() { - for (TCpuState& state : CpuStates) { - TPoolId current; - TPoolId assigned; - state.Load(assigned, current); - state.SwitchPool(assigned); - } - } - - static TString ToStr(const TVector<ui64>& values) { - TStringStream ss; - ss << "{"; - for (auto v : values) { - ss << " " << v; - } - ss << " }"; - return ss.Str(); - } - - void AssertPoolsCurrentCpus(const TVector<ui64>& cpuRequired) { - TVector<ui64> cpuCurrent; - cpuCurrent.resize(cpuRequired.size()); - for (TCpuState& state : CpuStates) { - TPoolId current; - TPoolId assigned; - state.Load(assigned, current); - cpuCurrent[current]++; - } - for (TPoolId pool = 0; pool < cpuRequired.size(); pool++) { - UNIT_ASSERT_C(cpuCurrent[pool] == cpuRequired[pool], - "cpu distribution mismatch, required " << ToStr(cpuRequired) << " but got " << ToStr(cpuCurrent)); - } - } - }; - - Y_UNIT_TEST(StartLwtrace) { - NLWTrace::StartLwtraceFromEnv(); - } - - Y_UNIT_TEST(AllOverloaded) { - TTest t; - int cpus = 10; - t.SetCpuCount(cpus); - t.AddPool(1, 1, 10); // pool=0 - t.AddPool(1, 2, 10); // pool=1 - t.AddPool(1, 3, 10); // pool=2 - t.AddPool(1, 4, 10); // pool=2 - t.Start(); - ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); - ui64 totalCpuUs = cpus * Ts2Us(dts); // pretend every pool has consumed as whole actorsystem, overload - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {totalCpuUs, totalCpuUs, totalCpuUs, totalCpuUs}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 2, 3, 4}); - } - - Y_UNIT_TEST(OneOverloaded) { - TTest t; - int cpus = 10; - t.SetCpuCount(cpus); - t.AddPool(1, 1, 10); // pool=0 - t.AddPool(1, 2, 10); // pool=1 - t.AddPool(1, 3, 10); // pool=2 - t.AddPool(1, 4, 10); // pool=2 - t.Start(); - ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); - ui64 totalCpuUs = cpus * Ts2Us(dts); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {totalCpuUs, 0, 0, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({7, 1, 1, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, totalCpuUs, 0, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 7, 1, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, 0, totalCpuUs, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 1, 7, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, 0, 0, totalCpuUs}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 1, 1, 7}); - } - - Y_UNIT_TEST(TwoOverloadedFairness) { - TTest t; - int cpus = 10; - t.SetCpuCount(cpus); - t.AddPool(1, 1, 10); // pool=0 - t.AddPool(1, 2, 10); // pool=1 - t.AddPool(1, 3, 10); // pool=2 - t.AddPool(1, 4, 10); // pool=2 - t.Start(); - ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); - ui64 totalCpuUs = cpus * Ts2Us(dts); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {totalCpuUs, totalCpuUs, 0, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({3, 5, 1, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {totalCpuUs, 0, totalCpuUs, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({2, 1, 6, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {totalCpuUs, 0, 0, totalCpuUs}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({2, 1, 1, 6}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, totalCpuUs, totalCpuUs, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 3, 5, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, totalCpuUs, 0, totalCpuUs}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 3, 1, 5}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, 0, totalCpuUs, totalCpuUs}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 1, 3, 5}); - } - - Y_UNIT_TEST(TwoOverloadedPriority) { - TTest t; - int cpus = 20; - t.SetCpuCount(cpus); - t.AddPool(1, 5, 20, 0); // pool=0 - t.AddPool(1, 5, 20, 1); // pool=1 - t.AddPool(1, 5, 20, 2); // pool=2 - t.AddPool(1, 5, 20, 3); // pool=3 - t.Start(); - ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); - ui64 mErlang = Ts2Us(dts) / 1000; - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 4500 * mErlang, 9500 * mErlang}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({2, 3, 5, 10}); - t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 4500 * mErlang, 8500 * mErlang}); - t.ApplyMovements(); - t.AssertPoolsCurrentCpus({3, 3, 5, 9}); - // NOTE: this operation require one move, but we do not make global analysis, so multiple steps (1->2 & 0->1) are required (can be optimized later) - for (int i = 0; i < 3; i++) { - t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 5500 * mErlang, 8500 * mErlang}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({2, 3, 6, 9}); - } -} +#include "balancer.h" + +#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/lwtrace/all.h> +#include <library/cpp/testing/unittest/registar.h> + +#include <util/stream/str.h> + +using namespace NActors; + +//////////////////////////////////////////////////////////////////////////////// + +Y_UNIT_TEST_SUITE(PoolCpuBalancer) { + struct TTest { + TCpuManagerConfig Config; + TCpuMask Available; + THolder<IBalancer> Balancer; + TVector<TCpuState> CpuStates; + TVector<ui64> CpuUs; + ui64 Now = 0; + + void SetCpuCount(size_t count) { + Config.UnitedWorkers.CpuCount = count; + for (TCpuId cpuId = 0; cpuId < count; cpuId++) { + Available.Set(cpuId); + } + } + + void AddPool(ui32 minCpus, ui32 cpus, ui32 maxCpus, ui8 priority = 0) { + TUnitedExecutorPoolConfig u; + u.PoolId = TPoolId(Config.United.size()); + u.Balancing.Cpus = cpus; + u.Balancing.MinCpus = minCpus; + u.Balancing.MaxCpus = maxCpus; + u.Balancing.Priority = priority; + Config.United.push_back(u); + } + + void Start() { + TCpuAllocationConfig allocation(Available, Config); + Balancer.Reset(MakeBalancer(Config.UnitedWorkers.Balancer, Config.United, 0)); + CpuStates.resize(allocation.Items.size()); // do not resize it later to avoid dangling pointers + CpuUs.resize(CpuStates.size()); + for (const TCpuAllocation& cpuAlloc : allocation.Items) { + bool added = Balancer->AddCpu(cpuAlloc, &CpuStates[cpuAlloc.CpuId]); + UNIT_ASSERT(added); + } + } + + void Balance(ui64 deltaTs, const TVector<ui64>& cpuUs) { + Now += deltaTs; + ui64 ts = Now; + if (Balancer->TryLock(ts)) { + for (TPoolId pool = 0; pool < cpuUs.size(); pool++) { + CpuUs[pool] += cpuUs[pool]; + TBalancerStats stats; + stats.Ts = ts; + stats.CpuUs = CpuUs[pool]; + Balancer->SetPoolStats(pool, stats); + } + Balancer->Balance(); + Balancer->Unlock(); + } + } + + void ApplyMovements() { + for (TCpuState& state : CpuStates) { + TPoolId current; + TPoolId assigned; + state.Load(assigned, current); + state.SwitchPool(assigned); + } + } + + static TString ToStr(const TVector<ui64>& values) { + TStringStream ss; + ss << "{"; + for (auto v : values) { + ss << " " << v; + } + ss << " }"; + return ss.Str(); + } + + void AssertPoolsCurrentCpus(const TVector<ui64>& cpuRequired) { + TVector<ui64> cpuCurrent; + cpuCurrent.resize(cpuRequired.size()); + for (TCpuState& state : CpuStates) { + TPoolId current; + TPoolId assigned; + state.Load(assigned, current); + cpuCurrent[current]++; + } + for (TPoolId pool = 0; pool < cpuRequired.size(); pool++) { + UNIT_ASSERT_C(cpuCurrent[pool] == cpuRequired[pool], + "cpu distribution mismatch, required " << ToStr(cpuRequired) << " but got " << ToStr(cpuCurrent)); + } + } + }; + + Y_UNIT_TEST(StartLwtrace) { + NLWTrace::StartLwtraceFromEnv(); + } + + Y_UNIT_TEST(AllOverloaded) { + TTest t; + int cpus = 10; + t.SetCpuCount(cpus); + t.AddPool(1, 1, 10); // pool=0 + t.AddPool(1, 2, 10); // pool=1 + t.AddPool(1, 3, 10); // pool=2 + t.AddPool(1, 4, 10); // pool=2 + t.Start(); + ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); + ui64 totalCpuUs = cpus * Ts2Us(dts); // pretend every pool has consumed as whole actorsystem, overload + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {totalCpuUs, totalCpuUs, totalCpuUs, totalCpuUs}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({1, 2, 3, 4}); + } + + Y_UNIT_TEST(OneOverloaded) { + TTest t; + int cpus = 10; + t.SetCpuCount(cpus); + t.AddPool(1, 1, 10); // pool=0 + t.AddPool(1, 2, 10); // pool=1 + t.AddPool(1, 3, 10); // pool=2 + t.AddPool(1, 4, 10); // pool=2 + t.Start(); + ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); + ui64 totalCpuUs = cpus * Ts2Us(dts); + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {totalCpuUs, 0, 0, 0}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({7, 1, 1, 1}); + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {0, totalCpuUs, 0, 0}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({1, 7, 1, 1}); + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {0, 0, totalCpuUs, 0}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({1, 1, 7, 1}); + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {0, 0, 0, totalCpuUs}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({1, 1, 1, 7}); + } + + Y_UNIT_TEST(TwoOverloadedFairness) { + TTest t; + int cpus = 10; + t.SetCpuCount(cpus); + t.AddPool(1, 1, 10); // pool=0 + t.AddPool(1, 2, 10); // pool=1 + t.AddPool(1, 3, 10); // pool=2 + t.AddPool(1, 4, 10); // pool=2 + t.Start(); + ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); + ui64 totalCpuUs = cpus * Ts2Us(dts); + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {totalCpuUs, totalCpuUs, 0, 0}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({3, 5, 1, 1}); + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {totalCpuUs, 0, totalCpuUs, 0}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({2, 1, 6, 1}); + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {totalCpuUs, 0, 0, totalCpuUs}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({2, 1, 1, 6}); + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {0, totalCpuUs, totalCpuUs, 0}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({1, 3, 5, 1}); + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {0, totalCpuUs, 0, totalCpuUs}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({1, 3, 1, 5}); + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {0, 0, totalCpuUs, totalCpuUs}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({1, 1, 3, 5}); + } + + Y_UNIT_TEST(TwoOverloadedPriority) { + TTest t; + int cpus = 20; + t.SetCpuCount(cpus); + t.AddPool(1, 5, 20, 0); // pool=0 + t.AddPool(1, 5, 20, 1); // pool=1 + t.AddPool(1, 5, 20, 2); // pool=2 + t.AddPool(1, 5, 20, 3); // pool=3 + t.Start(); + ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); + ui64 mErlang = Ts2Us(dts) / 1000; + for (int i = 0; i < cpus; i++) { + t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 4500 * mErlang, 9500 * mErlang}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({2, 3, 5, 10}); + t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 4500 * mErlang, 8500 * mErlang}); + t.ApplyMovements(); + t.AssertPoolsCurrentCpus({3, 3, 5, 9}); + // NOTE: this operation require one move, but we do not make global analysis, so multiple steps (1->2 & 0->1) are required (can be optimized later) + for (int i = 0; i < 3; i++) { + t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 5500 * mErlang, 8500 * mErlang}); + t.ApplyMovements(); + } + t.AssertPoolsCurrentCpus({2, 3, 6, 9}); + } +} diff --git a/library/cpp/actors/core/config.h b/library/cpp/actors/core/config.h index 2486bf4c43..750bdd3a07 100644 --- a/library/cpp/actors/core/config.h +++ b/library/cpp/actors/core/config.h @@ -1,239 +1,239 @@ -#pragma once - -#include "defs.h" -#include <library/cpp/actors/util/cpumask.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> -#include <util/datetime/base.h> -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/generic/vector.h> - -namespace NActors { - - struct TBalancingConfig { - // Default cpu count (used during overload). Zero value disables this pool balancing - // 1) Sum of `Cpus` on all pools cannot be changed without restart - // (changing cpu mode between Shared and Assigned is not implemented yet) - // 2) This sum must be equal to TUnitedWorkersConfig::CpuCount, - // otherwise `CpuCount - SUM(Cpus)` cpus will be in Shared mode (i.e. actorsystem 2.0) - ui32 Cpus = 0; - - ui32 MinCpus = 0; // Lower balancing bound, should be at least 1, and not greater than `Cpus` - ui32 MaxCpus = 0; // Higher balancing bound, should be not lower than `Cpus` - ui8 Priority = 0; // Priority of pool to obtain cpu due to balancing (higher is better) - ui64 ToleratedLatencyUs = 0; // p100-latency threshold indicating that more cpus are required by pool - }; - - struct TBalancerConfig { - ui64 PeriodUs = 15000000; // Time between balancer steps - }; - - struct TBasicExecutorPoolConfig { - static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TDuration::MilliSeconds(10); - static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100; - - ui32 PoolId = 0; - TString PoolName; - ui32 Threads = 1; - ui64 SpinThreshold = 100; - TCpuMask Affinity; // Executor thread affinity - TDuration TimePerMailbox = DEFAULT_TIME_PER_MAILBOX; - ui32 EventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX; - int RealtimePriority = 0; - ui32 MaxActivityType = 1; - }; - - struct TIOExecutorPoolConfig { - ui32 PoolId = 0; - TString PoolName; - ui32 Threads = 1; - TCpuMask Affinity; // Executor thread affinity - ui32 MaxActivityType = 1; - }; - - struct TUnitedExecutorPoolConfig { - static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TDuration::MilliSeconds(10); - static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100; - - ui32 PoolId = 0; - TString PoolName; - - // Resource sharing - ui32 Concurrency = 0; // Limits simultaneously running mailboxes count if set to non-zero value (do not set if Balancing.Cpus != 0) - TPoolWeight Weight = 0; // Weight in fair cpu-local pool scheduler - TCpuMask Allowed; // Allowed CPUs for workers to run this pool on (ignored if balancer works, i.e. actorsystem 1.5) - - // Single mailbox execution limits - TDuration TimePerMailbox = DEFAULT_TIME_PER_MAILBOX; - ui32 EventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX; - - // Introspection - ui32 MaxActivityType = 1; - - // Long-term balancing - TBalancingConfig Balancing; - }; - - struct TUnitedWorkersConfig { - ui32 CpuCount = 0; // Total CPUs running united workers (i.e. TBasicExecutorPoolConfig::Threads analog); set to zero to disable united workers - ui64 SpinThresholdUs = 100; // Limit for active spinning in case all pools became idle - ui64 PoolLimitUs = 500; // Soft limit on pool execution - ui64 EventLimitUs = 100; // Hard limit on last event execution exceeding pool limit - ui64 LimitPrecisionUs = 100; // Maximum delay of timer on limit excess (delay needed to avoid settimer syscall on every pool switch) - ui64 FastWorkerPriority = 10; // Real-time priority of workers not exceeding hard limits - ui64 IdleWorkerPriority = 20; // Real-time priority of standby workers waiting for hard preemption on timers (should be greater than FastWorkerPriority) - TCpuMask Allowed; // Allowed CPUs for workers to run on (every worker has affinity for exactly one cpu) - bool NoRealtime = false; // For environments w/o permissions for RT-threads - bool NoAffinity = false; // For environments w/o permissions for cpu affinity - TBalancerConfig Balancer; - }; - - struct TCpuManagerConfig { - TUnitedWorkersConfig UnitedWorkers; - TVector<TBasicExecutorPoolConfig> Basic; - TVector<TIOExecutorPoolConfig> IO; - TVector<TUnitedExecutorPoolConfig> United; - - ui32 GetExecutorsCount() const { - return Basic.size() + IO.size() + United.size(); - } - - TString GetPoolName(ui32 poolId) const { - for (const auto& p : Basic) { - if (p.PoolId == poolId) { - return p.PoolName; - } - } - for (const auto& p : IO) { - if (p.PoolId == poolId) { - return p.PoolName; - } - } - for (const auto& p : United) { - if (p.PoolId == poolId) { - return p.PoolName; - } - } - Y_FAIL("undefined pool id: %" PRIu32, (ui32)poolId); - } - - ui32 GetThreads(ui32 poolId) const { - for (const auto& p : Basic) { - if (p.PoolId == poolId) { - return p.Threads; - } - } - for (const auto& p : IO) { - if (p.PoolId == poolId) { - return p.Threads; - } - } - for (const auto& p : United) { - if (p.PoolId == poolId) { - return p.Concurrency ? p.Concurrency : UnitedWorkers.CpuCount; - } - } - Y_FAIL("undefined pool id: %" PRIu32, (ui32)poolId); - } - }; - - struct TSchedulerConfig { - TSchedulerConfig( - ui64 resolution = 1024, - ui64 spinThreshold = 100, - ui64 progress = 10000, - bool useSchedulerActor = false) - : ResolutionMicroseconds(resolution) - , SpinThreshold(spinThreshold) - , ProgressThreshold(progress) - , UseSchedulerActor(useSchedulerActor) - {} - - ui64 ResolutionMicroseconds = 1024; - ui64 SpinThreshold = 100; - ui64 ProgressThreshold = 10000; - bool UseSchedulerActor = false; // False is default because tests use scheduler thread - ui64 RelaxedSendPaceEventsPerSecond = 200000; - ui64 RelaxedSendPaceEventsPerCycle = RelaxedSendPaceEventsPerSecond * ResolutionMicroseconds / 1000000; - // For resolution >= 250000 microseconds threshold is SendPace - // For resolution <= 250 microseconds threshold is 20 * SendPace - ui64 RelaxedSendThresholdEventsPerSecond = RelaxedSendPaceEventsPerSecond * - (20 - ((20 - 1) * ClampVal(ResolutionMicroseconds, ui64(250), ui64(250000)) - 250) / (250000 - 250)); - ui64 RelaxedSendThresholdEventsPerCycle = RelaxedSendThresholdEventsPerSecond * ResolutionMicroseconds / 1000000; - - // Optional subsection for scheduler counters (usually subsystem=utils) - NMonitoring::TDynamicCounterPtr MonCounters = nullptr; - }; - - struct TCpuAllocation { - struct TPoolAllocation { - TPoolId PoolId; - TPoolWeight Weight; - - TPoolAllocation(TPoolId poolId = 0, TPoolWeight weight = 0) - : PoolId(poolId) - , Weight(weight) - {} - }; - - TCpuId CpuId; - TVector<TPoolAllocation> AllowedPools; - - TPoolsMask GetPoolsMask() const { - TPoolsMask mask = 0; - for (const auto& pa : AllowedPools) { - if (pa.PoolId < MaxPools) { - mask &= (1ull << pa.PoolId); - } - } - return mask; - } - - bool HasPool(TPoolId pool) const { - for (const auto& pa : AllowedPools) { - if (pa.PoolId == pool) { - return true; - } - } - return false; - } - }; - - struct TCpuAllocationConfig { - TVector<TCpuAllocation> Items; - - TCpuAllocationConfig(const TCpuMask& available, const TCpuManagerConfig& cfg) { - for (const TUnitedExecutorPoolConfig& pool : cfg.United) { - Y_VERIFY(pool.PoolId < MaxPools, "wrong PoolId of united executor pool: %s(%d)", - pool.PoolName.c_str(), (pool.PoolId)); - } - ui32 allocated[MaxPools] = {0}; - for (TCpuId cpu = 0; cpu < available.Size() && Items.size() < cfg.UnitedWorkers.CpuCount; cpu++) { - if (available.IsSet(cpu)) { - TCpuAllocation item; - item.CpuId = cpu; - for (const TUnitedExecutorPoolConfig& pool : cfg.United) { - if (cfg.UnitedWorkers.Allowed.IsEmpty() || cfg.UnitedWorkers.Allowed.IsSet(cpu)) { - if (pool.Allowed.IsEmpty() || pool.Allowed.IsSet(cpu)) { - item.AllowedPools.emplace_back(pool.PoolId, pool.Weight); - allocated[pool.PoolId]++; - } - } - } - if (!item.AllowedPools.empty()) { - Items.push_back(item); - } - } - } - for (const TUnitedExecutorPoolConfig& pool : cfg.United) { - Y_VERIFY(allocated[pool.PoolId] > 0, "unable to allocate cpu for united executor pool: %s(%d)", - pool.PoolName.c_str(), (pool.PoolId)); - } - } - - operator bool() const { - return !Items.empty(); - } - }; - -} +#pragma once + +#include "defs.h" +#include <library/cpp/actors/util/cpumask.h> +#include <library/cpp/monlib/dynamic_counters/counters.h> +#include <util/datetime/base.h> +#include <util/generic/ptr.h> +#include <util/generic/string.h> +#include <util/generic/vector.h> + +namespace NActors { + + struct TBalancingConfig { + // Default cpu count (used during overload). Zero value disables this pool balancing + // 1) Sum of `Cpus` on all pools cannot be changed without restart + // (changing cpu mode between Shared and Assigned is not implemented yet) + // 2) This sum must be equal to TUnitedWorkersConfig::CpuCount, + // otherwise `CpuCount - SUM(Cpus)` cpus will be in Shared mode (i.e. actorsystem 2.0) + ui32 Cpus = 0; + + ui32 MinCpus = 0; // Lower balancing bound, should be at least 1, and not greater than `Cpus` + ui32 MaxCpus = 0; // Higher balancing bound, should be not lower than `Cpus` + ui8 Priority = 0; // Priority of pool to obtain cpu due to balancing (higher is better) + ui64 ToleratedLatencyUs = 0; // p100-latency threshold indicating that more cpus are required by pool + }; + + struct TBalancerConfig { + ui64 PeriodUs = 15000000; // Time between balancer steps + }; + + struct TBasicExecutorPoolConfig { + static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TDuration::MilliSeconds(10); + static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100; + + ui32 PoolId = 0; + TString PoolName; + ui32 Threads = 1; + ui64 SpinThreshold = 100; + TCpuMask Affinity; // Executor thread affinity + TDuration TimePerMailbox = DEFAULT_TIME_PER_MAILBOX; + ui32 EventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX; + int RealtimePriority = 0; + ui32 MaxActivityType = 1; + }; + + struct TIOExecutorPoolConfig { + ui32 PoolId = 0; + TString PoolName; + ui32 Threads = 1; + TCpuMask Affinity; // Executor thread affinity + ui32 MaxActivityType = 1; + }; + + struct TUnitedExecutorPoolConfig { + static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TDuration::MilliSeconds(10); + static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100; + + ui32 PoolId = 0; + TString PoolName; + + // Resource sharing + ui32 Concurrency = 0; // Limits simultaneously running mailboxes count if set to non-zero value (do not set if Balancing.Cpus != 0) + TPoolWeight Weight = 0; // Weight in fair cpu-local pool scheduler + TCpuMask Allowed; // Allowed CPUs for workers to run this pool on (ignored if balancer works, i.e. actorsystem 1.5) + + // Single mailbox execution limits + TDuration TimePerMailbox = DEFAULT_TIME_PER_MAILBOX; + ui32 EventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX; + + // Introspection + ui32 MaxActivityType = 1; + + // Long-term balancing + TBalancingConfig Balancing; + }; + + struct TUnitedWorkersConfig { + ui32 CpuCount = 0; // Total CPUs running united workers (i.e. TBasicExecutorPoolConfig::Threads analog); set to zero to disable united workers + ui64 SpinThresholdUs = 100; // Limit for active spinning in case all pools became idle + ui64 PoolLimitUs = 500; // Soft limit on pool execution + ui64 EventLimitUs = 100; // Hard limit on last event execution exceeding pool limit + ui64 LimitPrecisionUs = 100; // Maximum delay of timer on limit excess (delay needed to avoid settimer syscall on every pool switch) + ui64 FastWorkerPriority = 10; // Real-time priority of workers not exceeding hard limits + ui64 IdleWorkerPriority = 20; // Real-time priority of standby workers waiting for hard preemption on timers (should be greater than FastWorkerPriority) + TCpuMask Allowed; // Allowed CPUs for workers to run on (every worker has affinity for exactly one cpu) + bool NoRealtime = false; // For environments w/o permissions for RT-threads + bool NoAffinity = false; // For environments w/o permissions for cpu affinity + TBalancerConfig Balancer; + }; + + struct TCpuManagerConfig { + TUnitedWorkersConfig UnitedWorkers; + TVector<TBasicExecutorPoolConfig> Basic; + TVector<TIOExecutorPoolConfig> IO; + TVector<TUnitedExecutorPoolConfig> United; + + ui32 GetExecutorsCount() const { + return Basic.size() + IO.size() + United.size(); + } + + TString GetPoolName(ui32 poolId) const { + for (const auto& p : Basic) { + if (p.PoolId == poolId) { + return p.PoolName; + } + } + for (const auto& p : IO) { + if (p.PoolId == poolId) { + return p.PoolName; + } + } + for (const auto& p : United) { + if (p.PoolId == poolId) { + return p.PoolName; + } + } + Y_FAIL("undefined pool id: %" PRIu32, (ui32)poolId); + } + + ui32 GetThreads(ui32 poolId) const { + for (const auto& p : Basic) { + if (p.PoolId == poolId) { + return p.Threads; + } + } + for (const auto& p : IO) { + if (p.PoolId == poolId) { + return p.Threads; + } + } + for (const auto& p : United) { + if (p.PoolId == poolId) { + return p.Concurrency ? p.Concurrency : UnitedWorkers.CpuCount; + } + } + Y_FAIL("undefined pool id: %" PRIu32, (ui32)poolId); + } + }; + + struct TSchedulerConfig { + TSchedulerConfig( + ui64 resolution = 1024, + ui64 spinThreshold = 100, + ui64 progress = 10000, + bool useSchedulerActor = false) + : ResolutionMicroseconds(resolution) + , SpinThreshold(spinThreshold) + , ProgressThreshold(progress) + , UseSchedulerActor(useSchedulerActor) + {} + + ui64 ResolutionMicroseconds = 1024; + ui64 SpinThreshold = 100; + ui64 ProgressThreshold = 10000; + bool UseSchedulerActor = false; // False is default because tests use scheduler thread + ui64 RelaxedSendPaceEventsPerSecond = 200000; + ui64 RelaxedSendPaceEventsPerCycle = RelaxedSendPaceEventsPerSecond * ResolutionMicroseconds / 1000000; + // For resolution >= 250000 microseconds threshold is SendPace + // For resolution <= 250 microseconds threshold is 20 * SendPace + ui64 RelaxedSendThresholdEventsPerSecond = RelaxedSendPaceEventsPerSecond * + (20 - ((20 - 1) * ClampVal(ResolutionMicroseconds, ui64(250), ui64(250000)) - 250) / (250000 - 250)); + ui64 RelaxedSendThresholdEventsPerCycle = RelaxedSendThresholdEventsPerSecond * ResolutionMicroseconds / 1000000; + + // Optional subsection for scheduler counters (usually subsystem=utils) + NMonitoring::TDynamicCounterPtr MonCounters = nullptr; + }; + + struct TCpuAllocation { + struct TPoolAllocation { + TPoolId PoolId; + TPoolWeight Weight; + + TPoolAllocation(TPoolId poolId = 0, TPoolWeight weight = 0) + : PoolId(poolId) + , Weight(weight) + {} + }; + + TCpuId CpuId; + TVector<TPoolAllocation> AllowedPools; + + TPoolsMask GetPoolsMask() const { + TPoolsMask mask = 0; + for (const auto& pa : AllowedPools) { + if (pa.PoolId < MaxPools) { + mask &= (1ull << pa.PoolId); + } + } + return mask; + } + + bool HasPool(TPoolId pool) const { + for (const auto& pa : AllowedPools) { + if (pa.PoolId == pool) { + return true; + } + } + return false; + } + }; + + struct TCpuAllocationConfig { + TVector<TCpuAllocation> Items; + + TCpuAllocationConfig(const TCpuMask& available, const TCpuManagerConfig& cfg) { + for (const TUnitedExecutorPoolConfig& pool : cfg.United) { + Y_VERIFY(pool.PoolId < MaxPools, "wrong PoolId of united executor pool: %s(%d)", + pool.PoolName.c_str(), (pool.PoolId)); + } + ui32 allocated[MaxPools] = {0}; + for (TCpuId cpu = 0; cpu < available.Size() && Items.size() < cfg.UnitedWorkers.CpuCount; cpu++) { + if (available.IsSet(cpu)) { + TCpuAllocation item; + item.CpuId = cpu; + for (const TUnitedExecutorPoolConfig& pool : cfg.United) { + if (cfg.UnitedWorkers.Allowed.IsEmpty() || cfg.UnitedWorkers.Allowed.IsSet(cpu)) { + if (pool.Allowed.IsEmpty() || pool.Allowed.IsSet(cpu)) { + item.AllowedPools.emplace_back(pool.PoolId, pool.Weight); + allocated[pool.PoolId]++; + } + } + } + if (!item.AllowedPools.empty()) { + Items.push_back(item); + } + } + } + for (const TUnitedExecutorPoolConfig& pool : cfg.United) { + Y_VERIFY(allocated[pool.PoolId] > 0, "unable to allocate cpu for united executor pool: %s(%d)", + pool.PoolName.c_str(), (pool.PoolId)); + } + } + + operator bool() const { + return !Items.empty(); + } + }; + +} diff --git a/library/cpp/actors/core/cpu_manager.cpp b/library/cpp/actors/core/cpu_manager.cpp index 39089b5d83..26aca975e9 100644 --- a/library/cpp/actors/core/cpu_manager.cpp +++ b/library/cpp/actors/core/cpu_manager.cpp @@ -1,108 +1,108 @@ -#include "cpu_manager.h" -#include "probes.h" - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - void TCpuManager::Setup() { - TAffinity available; - available.Current(); - TCpuAllocationConfig allocation(available, Config); - - if (allocation) { - if (!Balancer) { - Balancer.Reset(MakeBalancer(Config.UnitedWorkers.Balancer, Config.United, GetCycleCountFast())); - } - UnitedWorkers.Reset(new TUnitedWorkers(Config.UnitedWorkers, Config.United, allocation, Balancer.Get())); - } - - Executors.Reset(new TAutoPtr<IExecutorPool>[ExecutorPoolCount]); - - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - Executors[excIdx].Reset(CreateExecutorPool(excIdx)); - } - } - - void TCpuManager::PrepareStart(TVector<NSchedulerQueue::TReader*>& scheduleReaders, TActorSystem* actorSystem) { - if (UnitedWorkers) { - UnitedWorkers->Prepare(actorSystem, scheduleReaders); - } - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - NSchedulerQueue::TReader* readers; - ui32 readersCount = 0; - Executors[excIdx]->Prepare(actorSystem, &readers, &readersCount); - for (ui32 i = 0; i != readersCount; ++i, ++readers) { - scheduleReaders.push_back(readers); - } - } - } - - void TCpuManager::Start() { - if (UnitedWorkers) { - UnitedWorkers->Start(); - } - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - Executors[excIdx]->Start(); - } - } - - void TCpuManager::PrepareStop() { - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - Executors[excIdx]->PrepareStop(); - } - if (UnitedWorkers) { - UnitedWorkers->PrepareStop(); - } - } - - void TCpuManager::Shutdown() { - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - Executors[excIdx]->Shutdown(); - } - if (UnitedWorkers) { - UnitedWorkers->Shutdown(); - } - for (ui32 round = 0, done = 0; done < ExecutorPoolCount && round < 3; ++round) { - done = 0; - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - if (Executors[excIdx]->Cleanup()) { - ++done; - } - } - } - } - - void TCpuManager::Cleanup() { - for (ui32 round = 0, done = 0; done < ExecutorPoolCount; ++round) { - Y_VERIFY(round < 10, "actorsystem cleanup could not be completed in 10 rounds"); - done = 0; - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - if (Executors[excIdx]->Cleanup()) { - ++done; - } - } - } - Executors.Destroy(); - UnitedWorkers.Destroy(); - } - - IExecutorPool* TCpuManager::CreateExecutorPool(ui32 poolId) { - for (TBasicExecutorPoolConfig& cfg : Config.Basic) { - if (cfg.PoolId == poolId) { - return new TBasicExecutorPool(cfg); - } - } - for (TIOExecutorPoolConfig& cfg : Config.IO) { - if (cfg.PoolId == poolId) { - return new TIOExecutorPool(cfg); - } - } - for (TUnitedExecutorPoolConfig& cfg : Config.United) { - if (cfg.PoolId == poolId) { - IExecutorPool* result = new TUnitedExecutorPool(cfg, UnitedWorkers.Get()); - return result; - } - } - Y_FAIL("missing PoolId: %d", int(poolId)); - } -} +#include "cpu_manager.h" +#include "probes.h" + +namespace NActors { + LWTRACE_USING(ACTORLIB_PROVIDER); + + void TCpuManager::Setup() { + TAffinity available; + available.Current(); + TCpuAllocationConfig allocation(available, Config); + + if (allocation) { + if (!Balancer) { + Balancer.Reset(MakeBalancer(Config.UnitedWorkers.Balancer, Config.United, GetCycleCountFast())); + } + UnitedWorkers.Reset(new TUnitedWorkers(Config.UnitedWorkers, Config.United, allocation, Balancer.Get())); + } + + Executors.Reset(new TAutoPtr<IExecutorPool>[ExecutorPoolCount]); + + for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { + Executors[excIdx].Reset(CreateExecutorPool(excIdx)); + } + } + + void TCpuManager::PrepareStart(TVector<NSchedulerQueue::TReader*>& scheduleReaders, TActorSystem* actorSystem) { + if (UnitedWorkers) { + UnitedWorkers->Prepare(actorSystem, scheduleReaders); + } + for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { + NSchedulerQueue::TReader* readers; + ui32 readersCount = 0; + Executors[excIdx]->Prepare(actorSystem, &readers, &readersCount); + for (ui32 i = 0; i != readersCount; ++i, ++readers) { + scheduleReaders.push_back(readers); + } + } + } + + void TCpuManager::Start() { + if (UnitedWorkers) { + UnitedWorkers->Start(); + } + for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { + Executors[excIdx]->Start(); + } + } + + void TCpuManager::PrepareStop() { + for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { + Executors[excIdx]->PrepareStop(); + } + if (UnitedWorkers) { + UnitedWorkers->PrepareStop(); + } + } + + void TCpuManager::Shutdown() { + for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { + Executors[excIdx]->Shutdown(); + } + if (UnitedWorkers) { + UnitedWorkers->Shutdown(); + } + for (ui32 round = 0, done = 0; done < ExecutorPoolCount && round < 3; ++round) { + done = 0; + for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { + if (Executors[excIdx]->Cleanup()) { + ++done; + } + } + } + } + + void TCpuManager::Cleanup() { + for (ui32 round = 0, done = 0; done < ExecutorPoolCount; ++round) { + Y_VERIFY(round < 10, "actorsystem cleanup could not be completed in 10 rounds"); + done = 0; + for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { + if (Executors[excIdx]->Cleanup()) { + ++done; + } + } + } + Executors.Destroy(); + UnitedWorkers.Destroy(); + } + + IExecutorPool* TCpuManager::CreateExecutorPool(ui32 poolId) { + for (TBasicExecutorPoolConfig& cfg : Config.Basic) { + if (cfg.PoolId == poolId) { + return new TBasicExecutorPool(cfg); + } + } + for (TIOExecutorPoolConfig& cfg : Config.IO) { + if (cfg.PoolId == poolId) { + return new TIOExecutorPool(cfg); + } + } + for (TUnitedExecutorPoolConfig& cfg : Config.United) { + if (cfg.PoolId == poolId) { + IExecutorPool* result = new TUnitedExecutorPool(cfg, UnitedWorkers.Get()); + return result; + } + } + Y_FAIL("missing PoolId: %d", int(poolId)); + } +} diff --git a/library/cpp/actors/core/cpu_manager.h b/library/cpp/actors/core/cpu_manager.h index 454035477b..fc67bfd34c 100644 --- a/library/cpp/actors/core/cpu_manager.h +++ b/library/cpp/actors/core/cpu_manager.h @@ -1,57 +1,57 @@ -#pragma once - -#include "actorsystem.h" -#include "executor_pool_basic.h" -#include "executor_pool_io.h" -#include "executor_pool_united.h" - -namespace NActors { - class TCpuManager : public TNonCopyable { - const ui32 ExecutorPoolCount; - TArrayHolder<TAutoPtr<IExecutorPool>> Executors; - THolder<TUnitedWorkers> UnitedWorkers; - THolder<IBalancer> Balancer; - TCpuManagerConfig Config; - public: - explicit TCpuManager(THolder<TActorSystemSetup>& setup) - : ExecutorPoolCount(setup->GetExecutorsCount()) - , Balancer(setup->Balancer) - , Config(setup->CpuManager) - { - if (setup->Executors) { // Explicit mode w/o united pools - Executors.Reset(setup->Executors.Release()); - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - IExecutorPool* pool = Executors[excIdx].Get(); - Y_VERIFY(dynamic_cast<TUnitedExecutorPool*>(pool) == nullptr, - "united executor pool is prohibited in explicit mode of NActors::TCpuManager"); - } - } else { - Setup(); - } - } - - void Setup(); - void PrepareStart(TVector<NSchedulerQueue::TReader*>& scheduleReaders, TActorSystem* actorSystem); - void Start(); - void PrepareStop(); - void Shutdown(); - void Cleanup(); - - ui32 GetExecutorsCount() const { - return ExecutorPoolCount; - } - - IExecutorPool* GetExecutorPool(ui32 poolId) { - return Executors[poolId].Get(); - } - - void GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - if (poolId < ExecutorPoolCount) { - Executors[poolId]->GetCurrentStats(poolStats, statsCopy); - } - } - - private: - IExecutorPool* CreateExecutorPool(ui32 poolId); - }; -} +#pragma once + +#include "actorsystem.h" +#include "executor_pool_basic.h" +#include "executor_pool_io.h" +#include "executor_pool_united.h" + +namespace NActors { + class TCpuManager : public TNonCopyable { + const ui32 ExecutorPoolCount; + TArrayHolder<TAutoPtr<IExecutorPool>> Executors; + THolder<TUnitedWorkers> UnitedWorkers; + THolder<IBalancer> Balancer; + TCpuManagerConfig Config; + public: + explicit TCpuManager(THolder<TActorSystemSetup>& setup) + : ExecutorPoolCount(setup->GetExecutorsCount()) + , Balancer(setup->Balancer) + , Config(setup->CpuManager) + { + if (setup->Executors) { // Explicit mode w/o united pools + Executors.Reset(setup->Executors.Release()); + for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { + IExecutorPool* pool = Executors[excIdx].Get(); + Y_VERIFY(dynamic_cast<TUnitedExecutorPool*>(pool) == nullptr, + "united executor pool is prohibited in explicit mode of NActors::TCpuManager"); + } + } else { + Setup(); + } + } + + void Setup(); + void PrepareStart(TVector<NSchedulerQueue::TReader*>& scheduleReaders, TActorSystem* actorSystem); + void Start(); + void PrepareStop(); + void Shutdown(); + void Cleanup(); + + ui32 GetExecutorsCount() const { + return ExecutorPoolCount; + } + + IExecutorPool* GetExecutorPool(ui32 poolId) { + return Executors[poolId].Get(); + } + + void GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { + if (poolId < ExecutorPoolCount) { + Executors[poolId]->GetCurrentStats(poolStats, statsCopy); + } + } + + private: + IExecutorPool* CreateExecutorPool(ui32 poolId); + }; +} diff --git a/library/cpp/actors/core/cpu_state.h b/library/cpp/actors/core/cpu_state.h index b8030149a7..34febf7ccf 100644 --- a/library/cpp/actors/core/cpu_state.h +++ b/library/cpp/actors/core/cpu_state.h @@ -1,215 +1,215 @@ -#pragma once - -#include "defs.h" - -#include <library/cpp/actors/util/futex.h> - -namespace NActors { - - class alignas(64) TCpuState { - // Atomic cachelign-aligned 64-bit state, see description below - TAtomic State = 0; - char Padding[64 - sizeof(TAtomic)]; - - // Bits 0-31: Currently executing pool - // - value less than MaxPools means cpu is executing corresponding pool (fast-worker is executing or waiting for slow-workers) - // - one of Cpu* values in case of idle cpu - // - used as futex by blocked fast-worker - static constexpr ui64 CurrentBits = 32; - static constexpr ui64 CurrentMask = ui64((1ull << CurrentBits) - 1); - - // Bits 32-63: Assigned pool - // - value is set by balancer - // - NOT used as futex - // - Not balanced - static constexpr ui64 AssignedOffs = 32; - static constexpr ui64 AssignedMask = ~CurrentMask; - - public: - TCpuState() { - Y_UNUSED(Padding); - } - - void Load(TPoolId& assigned, TPoolId& current) const { - TAtomicBase state = AtomicLoad(&State); - assigned = (state & AssignedMask) >> AssignedOffs; - current = state & CurrentMask; - } - - TPoolId CurrentPool() const { - return TPoolId(AtomicLoad(&State) & CurrentMask); - } - - void SwitchPool(TPoolId pool) { - while (true) { - TAtomicBase state = AtomicLoad(&State); - if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) { - return; - } - } - } - - TPoolId AssignedPool() const { - return TPoolId((AtomicLoad(&State) & AssignedMask) >> AssignedOffs); - } - - // Assigns new pool to cpu and wakes it up if cpu is idle - void AssignPool(TPoolId pool) { - while (true) { - TAtomicBase state = AtomicLoad(&State); - TPoolId current(state & CurrentMask); - if (Y_UNLIKELY(current == CpuStopped)) { - return; // it would be better to shutdown instead of balancing - } - // Idle cpu must be woken up after balancing to handle pending tokens (if any) in assigned/schedulable pool(s) - if (current == CpuSpinning) { - if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | pool, state)) { - return; // successfully woken up - } - } else if (current == CpuBlocked) { - if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | pool, state)) { - FutexWake(); - return; // successfully woken up - } - } else { - if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | (state & ~AssignedMask), state)) { - return; // wakeup is not required - } - } - } - } - - void Stop() { - while (true) { - TAtomicBase state = AtomicLoad(&State); - if (AtomicCas(&State, (state & ~CurrentMask) | CpuStopped, state)) { - FutexWake(); - return; // successfully stopped - } - } - } - - // Start waiting, returns false in case of actorsystem shutdown - bool StartSpinning() { - while (true) { - TAtomicBase state = AtomicLoad(&State); - TPoolId current(state & CurrentMask); - if (Y_UNLIKELY(current == CpuStopped)) { - return false; - } - Y_VERIFY_DEBUG(current < MaxPools, "unexpected already waiting state of cpu (%d)", (int)current); - if (AtomicCas(&State, (state & ~CurrentMask) | CpuSpinning, state)) { // successfully marked as spinning - return true; - } - } - } - - bool StartBlocking() { - while (true) { - TAtomicBase state = AtomicLoad(&State); - TPoolId current(state & CurrentMask); - if (current == CpuSpinning) { - if (AtomicCas(&State, (state & ~CurrentMask) | CpuBlocked, state)) { - return false; // successful switch - } - } else { - return true; // wakeup - } - } - } - - bool Block(ui64 timeoutNs, TPoolId& result) { -#ifdef _linux_ - timespec timeout; - timeout.tv_sec = timeoutNs / 1'000'000'000; - timeout.tv_nsec = timeoutNs % 1'000'000'000; - SysFutex(Futex(), FUTEX_WAIT_PRIVATE, CpuBlocked, &timeout, nullptr, 0); -#else - NanoSleep(timeoutNs); // non-linux wake is not supported, cpu will go idle on wake after blocked state -#endif - TAtomicBase state = AtomicLoad(&State); - TPoolId current(state & CurrentMask); - if (current == CpuBlocked) { - return false; // timeout - } else { - result = current; - return true; // wakeup - } - } - - enum EWakeResult { - Woken, // successfully woken up - NotIdle, // cpu is already not idle - Forbidden, // cpu is assigned to another pool - Stopped, // cpu is shutdown - }; - - EWakeResult WakeWithoutToken(TPoolId pool) { - while (true) { - TAtomicBase state = RelaxedLoad(&State); - TPoolId current(state & CurrentMask); - TPoolId assigned((state & AssignedMask) >> AssignedOffs); - if (assigned == CpuShared || assigned == pool) { - if (current == CpuSpinning) { - if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) { - return Woken; - } - } else if (current == CpuBlocked) { - if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) { - FutexWake(); - return Woken; - } - } else if (current == CpuStopped) { - return Stopped; - } else { - return NotIdle; - } - } else { - return Forbidden; - } - } - } - - EWakeResult WakeWithTokenAcquired(TPoolId token) { - while (true) { - TAtomicBase state = RelaxedLoad(&State); - TPoolId current(state & CurrentMask); - // NOTE: We ignore assigned value because we already have token, so - // NOTE: not assigned pool may be run here. This will be fixed - // NOTE: after we finish with current activation - if (current == CpuSpinning) { - if (AtomicCas(&State, (state & ~CurrentMask) | token, state)) { - return Woken; - } - } else if (current == CpuBlocked) { - if (AtomicCas(&State, (state & ~CurrentMask) | token, state)) { - FutexWake(); - return Woken; - } - } else if (current == CpuStopped) { - return Stopped; - } else { - return NotIdle; - } - } - } - - bool IsPoolReassigned(TPoolId current) const { - TAtomicBase state = AtomicLoad(&State); - TPoolId assigned((state & AssignedMask) >> AssignedOffs); - return assigned != current; - } - - private: - void* Futex() { - return (void*)&State; // little endian assumed - } - - void FutexWake() { -#ifdef _linux_ - SysFutex(Futex(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); -#endif - } - }; - -} +#pragma once + +#include "defs.h" + +#include <library/cpp/actors/util/futex.h> + +namespace NActors { + + class alignas(64) TCpuState { + // Atomic cachelign-aligned 64-bit state, see description below + TAtomic State = 0; + char Padding[64 - sizeof(TAtomic)]; + + // Bits 0-31: Currently executing pool + // - value less than MaxPools means cpu is executing corresponding pool (fast-worker is executing or waiting for slow-workers) + // - one of Cpu* values in case of idle cpu + // - used as futex by blocked fast-worker + static constexpr ui64 CurrentBits = 32; + static constexpr ui64 CurrentMask = ui64((1ull << CurrentBits) - 1); + + // Bits 32-63: Assigned pool + // - value is set by balancer + // - NOT used as futex + // - Not balanced + static constexpr ui64 AssignedOffs = 32; + static constexpr ui64 AssignedMask = ~CurrentMask; + + public: + TCpuState() { + Y_UNUSED(Padding); + } + + void Load(TPoolId& assigned, TPoolId& current) const { + TAtomicBase state = AtomicLoad(&State); + assigned = (state & AssignedMask) >> AssignedOffs; + current = state & CurrentMask; + } + + TPoolId CurrentPool() const { + return TPoolId(AtomicLoad(&State) & CurrentMask); + } + + void SwitchPool(TPoolId pool) { + while (true) { + TAtomicBase state = AtomicLoad(&State); + if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) { + return; + } + } + } + + TPoolId AssignedPool() const { + return TPoolId((AtomicLoad(&State) & AssignedMask) >> AssignedOffs); + } + + // Assigns new pool to cpu and wakes it up if cpu is idle + void AssignPool(TPoolId pool) { + while (true) { + TAtomicBase state = AtomicLoad(&State); + TPoolId current(state & CurrentMask); + if (Y_UNLIKELY(current == CpuStopped)) { + return; // it would be better to shutdown instead of balancing + } + // Idle cpu must be woken up after balancing to handle pending tokens (if any) in assigned/schedulable pool(s) + if (current == CpuSpinning) { + if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | pool, state)) { + return; // successfully woken up + } + } else if (current == CpuBlocked) { + if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | pool, state)) { + FutexWake(); + return; // successfully woken up + } + } else { + if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | (state & ~AssignedMask), state)) { + return; // wakeup is not required + } + } + } + } + + void Stop() { + while (true) { + TAtomicBase state = AtomicLoad(&State); + if (AtomicCas(&State, (state & ~CurrentMask) | CpuStopped, state)) { + FutexWake(); + return; // successfully stopped + } + } + } + + // Start waiting, returns false in case of actorsystem shutdown + bool StartSpinning() { + while (true) { + TAtomicBase state = AtomicLoad(&State); + TPoolId current(state & CurrentMask); + if (Y_UNLIKELY(current == CpuStopped)) { + return false; + } + Y_VERIFY_DEBUG(current < MaxPools, "unexpected already waiting state of cpu (%d)", (int)current); + if (AtomicCas(&State, (state & ~CurrentMask) | CpuSpinning, state)) { // successfully marked as spinning + return true; + } + } + } + + bool StartBlocking() { + while (true) { + TAtomicBase state = AtomicLoad(&State); + TPoolId current(state & CurrentMask); + if (current == CpuSpinning) { + if (AtomicCas(&State, (state & ~CurrentMask) | CpuBlocked, state)) { + return false; // successful switch + } + } else { + return true; // wakeup + } + } + } + + bool Block(ui64 timeoutNs, TPoolId& result) { +#ifdef _linux_ + timespec timeout; + timeout.tv_sec = timeoutNs / 1'000'000'000; + timeout.tv_nsec = timeoutNs % 1'000'000'000; + SysFutex(Futex(), FUTEX_WAIT_PRIVATE, CpuBlocked, &timeout, nullptr, 0); +#else + NanoSleep(timeoutNs); // non-linux wake is not supported, cpu will go idle on wake after blocked state +#endif + TAtomicBase state = AtomicLoad(&State); + TPoolId current(state & CurrentMask); + if (current == CpuBlocked) { + return false; // timeout + } else { + result = current; + return true; // wakeup + } + } + + enum EWakeResult { + Woken, // successfully woken up + NotIdle, // cpu is already not idle + Forbidden, // cpu is assigned to another pool + Stopped, // cpu is shutdown + }; + + EWakeResult WakeWithoutToken(TPoolId pool) { + while (true) { + TAtomicBase state = RelaxedLoad(&State); + TPoolId current(state & CurrentMask); + TPoolId assigned((state & AssignedMask) >> AssignedOffs); + if (assigned == CpuShared || assigned == pool) { + if (current == CpuSpinning) { + if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) { + return Woken; + } + } else if (current == CpuBlocked) { + if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) { + FutexWake(); + return Woken; + } + } else if (current == CpuStopped) { + return Stopped; + } else { + return NotIdle; + } + } else { + return Forbidden; + } + } + } + + EWakeResult WakeWithTokenAcquired(TPoolId token) { + while (true) { + TAtomicBase state = RelaxedLoad(&State); + TPoolId current(state & CurrentMask); + // NOTE: We ignore assigned value because we already have token, so + // NOTE: not assigned pool may be run here. This will be fixed + // NOTE: after we finish with current activation + if (current == CpuSpinning) { + if (AtomicCas(&State, (state & ~CurrentMask) | token, state)) { + return Woken; + } + } else if (current == CpuBlocked) { + if (AtomicCas(&State, (state & ~CurrentMask) | token, state)) { + FutexWake(); + return Woken; + } + } else if (current == CpuStopped) { + return Stopped; + } else { + return NotIdle; + } + } + } + + bool IsPoolReassigned(TPoolId current) const { + TAtomicBase state = AtomicLoad(&State); + TPoolId assigned((state & AssignedMask) >> AssignedOffs); + return assigned != current; + } + + private: + void* Futex() { + return (void*)&State; // little endian assumed + } + + void FutexWake() { +#ifdef _linux_ + SysFutex(Futex(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); +#endif + } + }; + +} diff --git a/library/cpp/actors/core/defs.h b/library/cpp/actors/core/defs.h index 980b7d767b..d331e98833 100644 --- a/library/cpp/actors/core/defs.h +++ b/library/cpp/actors/core/defs.h @@ -13,30 +13,30 @@ #define ACTORSLIB_COLLECT_EXEC_STATS namespace NActors { - using TPoolId = ui8; - using TPoolsMask = ui64; - static constexpr TPoolId PoolBits = 6; - static constexpr TPoolId MaxPools = (1 << PoolBits) - 1; // maximum amount of pools (poolid=63 is reserved) - static constexpr TPoolsMask WaitPoolsFlag = (1ull << MaxPools); // wait-for-slow-workers flag bitmask - - // Special TPoolId values used by TCpuState - static constexpr TPoolId CpuSpinning = MaxPools; // fast-worker is actively spinning, no slow-workers - static constexpr TPoolId CpuBlocked = MaxPools + 1; // fast-worker is blocked, no slow-workers - static constexpr TPoolId CpuStopped = TPoolId(-1); // special value indicating worker should stop - static constexpr TPoolId CpuShared = MaxPools; // special value for `assigned` meaning balancer disabled, pool scheduler is used instead - - using TPoolWeight = ui16; - static constexpr TPoolWeight MinPoolWeight = 1; - static constexpr TPoolWeight DefPoolWeight = 32; - static constexpr TPoolWeight MaxPoolWeight = 1024; - - using TWorkerId = ui16; - static constexpr TWorkerId WorkerBits = 11; - static constexpr TWorkerId MaxWorkers = 1 << WorkerBits; - - using TThreadId = ui64; - static constexpr TThreadId UnknownThreadId = ui64(-1); + using TPoolId = ui8; + using TPoolsMask = ui64; + static constexpr TPoolId PoolBits = 6; + static constexpr TPoolId MaxPools = (1 << PoolBits) - 1; // maximum amount of pools (poolid=63 is reserved) + static constexpr TPoolsMask WaitPoolsFlag = (1ull << MaxPools); // wait-for-slow-workers flag bitmask + // Special TPoolId values used by TCpuState + static constexpr TPoolId CpuSpinning = MaxPools; // fast-worker is actively spinning, no slow-workers + static constexpr TPoolId CpuBlocked = MaxPools + 1; // fast-worker is blocked, no slow-workers + static constexpr TPoolId CpuStopped = TPoolId(-1); // special value indicating worker should stop + static constexpr TPoolId CpuShared = MaxPools; // special value for `assigned` meaning balancer disabled, pool scheduler is used instead + + using TPoolWeight = ui16; + static constexpr TPoolWeight MinPoolWeight = 1; + static constexpr TPoolWeight DefPoolWeight = 32; + static constexpr TPoolWeight MaxPoolWeight = 1024; + + using TWorkerId = ui16; + static constexpr TWorkerId WorkerBits = 11; + static constexpr TWorkerId MaxWorkers = 1 << WorkerBits; + + using TThreadId = ui64; + static constexpr TThreadId UnknownThreadId = ui64(-1); + struct TMailboxType { enum EType { Inherited = -1, // inherit mailbox from parent diff --git a/library/cpp/actors/core/event_pb.h b/library/cpp/actors/core/event_pb.h index d7546b901a..bf9695da95 100644 --- a/library/cpp/actors/core/event_pb.h +++ b/library/cpp/actors/core/event_pb.h @@ -291,10 +291,10 @@ namespace NActors { } public: - void ReservePayload(size_t size) { - Payload.reserve(size); - } - + void ReservePayload(size_t size) { + Payload.reserve(size); + } + ui32 AddPayload(TRope&& rope) { const ui32 id = Payload.size(); Payload.push_back(std::move(rope)); diff --git a/library/cpp/actors/core/executor_pool_base.cpp b/library/cpp/actors/core/executor_pool_base.cpp index c3b9999168..7340458631 100644 --- a/library/cpp/actors/core/executor_pool_base.cpp +++ b/library/cpp/actors/core/executor_pool_base.cpp @@ -1,8 +1,8 @@ #include "executor_pool_base.h" #include "executor_thread.h" #include "mailbox.h" -#include "probes.h" -#include <library/cpp/actors/util/datetime.h> +#include "probes.h" +#include <library/cpp/actors/util/datetime.h> namespace NActors { LWTRACE_USING(ACTORLIB_PROVIDER); @@ -11,44 +11,44 @@ namespace NActors { actor->SelfActorId = self; actor->Registered(sys, owner); } - - TExecutorPoolBaseMailboxed::TExecutorPoolBaseMailboxed(ui32 poolId, ui32 maxActivityType) + + TExecutorPoolBaseMailboxed::TExecutorPoolBaseMailboxed(ui32 poolId, ui32 maxActivityType) : IExecutorPool(poolId) , ActorSystem(nullptr) , MailboxTable(new TMailboxTable) #ifdef ACTORSLIB_COLLECT_EXEC_STATS , Stats(maxActivityType) #endif - {} - - TExecutorPoolBaseMailboxed::~TExecutorPoolBaseMailboxed() { - MailboxTable.Destroy(); + {} + + TExecutorPoolBaseMailboxed::~TExecutorPoolBaseMailboxed() { + MailboxTable.Destroy(); } - TExecutorPoolBase::TExecutorPoolBase(ui32 poolId, ui32 threads, TAffinity* affinity, ui32 maxActivityType) - : TExecutorPoolBaseMailboxed(poolId, maxActivityType) - , PoolThreads(threads) - , ThreadsAffinity(affinity) - {} - + TExecutorPoolBase::TExecutorPoolBase(ui32 poolId, ui32 threads, TAffinity* affinity, ui32 maxActivityType) + : TExecutorPoolBaseMailboxed(poolId, maxActivityType) + , PoolThreads(threads) + , ThreadsAffinity(affinity) + {} + TExecutorPoolBase::~TExecutorPoolBase() { while (Activations.Pop(0)) ; } - void TExecutorPoolBaseMailboxed::ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingWriteCounter) { - Y_UNUSED(workerId); + void TExecutorPoolBaseMailboxed::ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingWriteCounter) { + Y_UNUSED(workerId); MailboxTable->ReclaimMailbox(mailboxType, hint, revolvingWriteCounter); } - ui64 TExecutorPoolBaseMailboxed::AllocateID() { + ui64 TExecutorPoolBaseMailboxed::AllocateID() { return ActorSystem->AllocateIDSpace(1); } - bool TExecutorPoolBaseMailboxed::Send(TAutoPtr<IEventHandle>& ev) { + bool TExecutorPoolBaseMailboxed::Send(TAutoPtr<IEventHandle>& ev) { Y_VERIFY_DEBUG(ev->GetRecipientRewrite().PoolID() == PoolId); #ifdef ACTORSLIB_COLLECT_EXEC_STATS - RelaxedStore(&ev->SendTime, (::NHPTimer::STime)GetCycleCountFast()); + RelaxedStore(&ev->SendTime, (::NHPTimer::STime)GetCycleCountFast()); #endif return MailboxTable->SendTo(ev, this); } @@ -57,8 +57,8 @@ namespace NActors { ScheduleActivationEx(activation, AtomicIncrement(ActivationsRevolvingCounter)); } - TActorId TExecutorPoolBaseMailboxed::Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingWriteCounter, const TActorId& parentId) { - NHPTimer::STime hpstart = GetCycleCountFast(); + TActorId TExecutorPoolBaseMailboxed::Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingWriteCounter, const TActorId& parentId) { + NHPTimer::STime hpstart = GetCycleCountFast(); #ifdef ACTORSLIB_COLLECT_EXEC_STATS ui32 at = actor->GetActivityType(); if (at >= Stats.MaxActivityType()) @@ -72,7 +72,7 @@ namespace NActors { TMailboxHeader* mailbox = nullptr; if (revolvingWriteCounter == 0) - revolvingWriteCounter = AtomicIncrement(RegisterRevolvingCounter); + revolvingWriteCounter = AtomicIncrement(RegisterRevolvingCounter); { ui32 hintBackoff = 0; @@ -105,34 +105,34 @@ namespace NActors { switch (mailboxType) { case TMailboxType::Simple: - UnlockFromExecution((TMailboxTable::TSimpleMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); + UnlockFromExecution((TMailboxTable::TSimpleMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); break; case TMailboxType::Revolving: - UnlockFromExecution((TMailboxTable::TRevolvingMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); + UnlockFromExecution((TMailboxTable::TRevolvingMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); break; case TMailboxType::HTSwap: - UnlockFromExecution((TMailboxTable::THTSwapMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); + UnlockFromExecution((TMailboxTable::THTSwapMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); break; case TMailboxType::ReadAsFilled: - UnlockFromExecution((TMailboxTable::TReadAsFilledMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); + UnlockFromExecution((TMailboxTable::TReadAsFilledMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); break; case TMailboxType::TinyReadAsFilled: - UnlockFromExecution((TMailboxTable::TTinyReadAsFilledMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); + UnlockFromExecution((TMailboxTable::TTinyReadAsFilledMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); break; default: Y_FAIL(); } - NHPTimer::STime elapsed = GetCycleCountFast() - hpstart; + NHPTimer::STime elapsed = GetCycleCountFast() - hpstart; if (elapsed > 1000000) { LWPROBE(SlowRegisterNew, PoolId, NHPTimer::GetSeconds(elapsed) * 1000.0); } return actorId; - } - - TActorId TExecutorPoolBaseMailboxed::Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) { - NHPTimer::STime hpstart = GetCycleCountFast(); + } + + TActorId TExecutorPoolBaseMailboxed::Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) { + NHPTimer::STime hpstart = GetCycleCountFast(); #ifdef ACTORSLIB_COLLECT_EXEC_STATS ui32 at = actor->GetActivityType(); if (at >= Stats.MaxActivityType()) @@ -146,19 +146,19 @@ namespace NActors { const TActorId actorId(ActorSystem->NodeId, PoolId, localActorId, hint); DoActorInit(ActorSystem, actor, actorId, parentId); - NHPTimer::STime elapsed = GetCycleCountFast() - hpstart; + NHPTimer::STime elapsed = GetCycleCountFast() - hpstart; if (elapsed > 1000000) { LWPROBE(SlowRegisterAdd, PoolId, NHPTimer::GetSeconds(elapsed) * 1000.0); } return actorId; - } - + } + TAffinity* TExecutorPoolBase::Affinity() const { return ThreadsAffinity.Get(); } - bool TExecutorPoolBaseMailboxed::Cleanup() { + bool TExecutorPoolBaseMailboxed::Cleanup() { return MailboxTable->Cleanup(); } diff --git a/library/cpp/actors/core/executor_pool_base.h b/library/cpp/actors/core/executor_pool_base.h index c84ce1af77..22247ae1c7 100644 --- a/library/cpp/actors/core/executor_pool_base.h +++ b/library/cpp/actors/core/executor_pool_base.h @@ -8,7 +8,7 @@ #include <library/cpp/actors/util/threadparkpad.h> namespace NActors { - class TExecutorPoolBaseMailboxed: public IExecutorPool { + class TExecutorPoolBaseMailboxed: public IExecutorPool { protected: TActorSystem* ActorSystem; THolder<TMailboxTable> MailboxTable; @@ -17,33 +17,33 @@ namespace NActors { // registrations might be done in threads from other pools) TExecutorThreadStats Stats; #endif - TAtomic RegisterRevolvingCounter = 0; - ui64 AllocateID(); + TAtomic RegisterRevolvingCounter = 0; + ui64 AllocateID(); public: - TExecutorPoolBaseMailboxed(ui32 poolId, ui32 maxActivityType); - ~TExecutorPoolBaseMailboxed(); - void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingWriteCounter) override; + TExecutorPoolBaseMailboxed(ui32 poolId, ui32 maxActivityType); + ~TExecutorPoolBaseMailboxed(); + void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingWriteCounter) override; bool Send(TAutoPtr<IEventHandle>& ev) override; TActorId Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingWriteCounter, const TActorId& parentId) override; TActorId Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) override; bool Cleanup() override; - }; + }; - class TExecutorPoolBase: public TExecutorPoolBaseMailboxed { - protected: - const ui32 PoolThreads; - TIntrusivePtr<TAffinity> ThreadsAffinity; - TAtomic Semaphore = 0; - TUnorderedCache<ui32, 512, 4> Activations; - TAtomic ActivationsRevolvingCounter = 0; - volatile bool StopFlag = false; - public: - TExecutorPoolBase(ui32 poolId, ui32 threads, TAffinity* affinity, ui32 maxActivityType); - ~TExecutorPoolBase(); - void ScheduleActivation(ui32 activation) override; + class TExecutorPoolBase: public TExecutorPoolBaseMailboxed { + protected: + const ui32 PoolThreads; + TIntrusivePtr<TAffinity> ThreadsAffinity; + TAtomic Semaphore = 0; + TUnorderedCache<ui32, 512, 4> Activations; + TAtomic ActivationsRevolvingCounter = 0; + volatile bool StopFlag = false; + public: + TExecutorPoolBase(ui32 poolId, ui32 threads, TAffinity* affinity, ui32 maxActivityType); + ~TExecutorPoolBase(); + void ScheduleActivation(ui32 activation) override; TAffinity* Affinity() const override; ui32 GetThreads() const override; }; - - void DoActorInit(TActorSystem*, IActor*, const TActorId&, const TActorId&); + + void DoActorInit(TActorSystem*, IActor*, const TActorId&, const TActorId&); } diff --git a/library/cpp/actors/core/executor_pool_basic.cpp b/library/cpp/actors/core/executor_pool_basic.cpp index 4dce16939a..16541889c6 100644 --- a/library/cpp/actors/core/executor_pool_basic.cpp +++ b/library/cpp/actors/core/executor_pool_basic.cpp @@ -1,8 +1,8 @@ #include "executor_pool_basic.h" -#include "probes.h" +#include "probes.h" #include "mailbox.h" #include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> #ifdef _linux_ #include <pthread.h> @@ -12,7 +12,7 @@ namespace NActors { LWTRACE_USING(ACTORLIB_PROVIDER); constexpr TDuration TBasicExecutorPool::DEFAULT_TIME_PER_MAILBOX; - + TBasicExecutorPool::TBasicExecutorPool( ui32 poolId, ui32 threads, @@ -23,7 +23,7 @@ namespace NActors { ui32 eventsPerMailbox, int realtimePriority, ui32 maxActivityType) - : TExecutorPoolBase(poolId, threads, affinity, maxActivityType) + : TExecutorPoolBase(poolId, threads, affinity, maxActivityType) , SpinThreshold(spinThreshold) , SpinThresholdCycles(spinThreshold * NHPTimer::GetCyclesPerSecond() * 0.000001) // convert microseconds to cycles , Threads(new TThreadCtx[threads]) @@ -38,45 +38,45 @@ namespace NActors { { } - TBasicExecutorPool::TBasicExecutorPool(const TBasicExecutorPoolConfig& cfg) - : TBasicExecutorPool( - cfg.PoolId, - cfg.Threads, - cfg.SpinThreshold, - cfg.PoolName, - new TAffinity(cfg.Affinity), - cfg.TimePerMailbox, - cfg.EventsPerMailbox, - cfg.RealtimePriority, - cfg.MaxActivityType - ) - {} - + TBasicExecutorPool::TBasicExecutorPool(const TBasicExecutorPoolConfig& cfg) + : TBasicExecutorPool( + cfg.PoolId, + cfg.Threads, + cfg.SpinThreshold, + cfg.PoolName, + new TAffinity(cfg.Affinity), + cfg.TimePerMailbox, + cfg.EventsPerMailbox, + cfg.RealtimePriority, + cfg.MaxActivityType + ) + {} + TBasicExecutorPool::~TBasicExecutorPool() { Threads.Destroy(); } - ui32 TBasicExecutorPool::GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { - ui32 workerId = wctx.WorkerId; - Y_VERIFY_DEBUG(workerId < PoolThreads); + ui32 TBasicExecutorPool::GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { + ui32 workerId = wctx.WorkerId; + Y_VERIFY_DEBUG(workerId < PoolThreads); NHPTimer::STime elapsed = 0; NHPTimer::STime parked = 0; NHPTimer::STime blocked = 0; - NHPTimer::STime hpstart = GetCycleCountFast(); + NHPTimer::STime hpstart = GetCycleCountFast(); NHPTimer::STime hpnow; - TThreadCtx& threadCtx = Threads[workerId]; + TThreadCtx& threadCtx = Threads[workerId]; AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_NONE); if (Y_UNLIKELY(AtomicGet(threadCtx.BlockedFlag) != TThreadCtx::BS_NONE)) { do { if (AtomicCas(&threadCtx.BlockedFlag, TThreadCtx::BS_BLOCKED, TThreadCtx::BS_BLOCKING)) { - hpnow = GetCycleCountFast(); + hpnow = GetCycleCountFast(); elapsed += hpnow - hpstart; if (threadCtx.BlockedPad.Park()) // interrupted return 0; - hpstart = GetCycleCountFast(); + hpstart = GetCycleCountFast(); blocked += hpstart - hpnow; } } while (AtomicGet(threadCtx.BlockedFlag) != TThreadCtx::BS_NONE && !AtomicLoad(&StopFlag)); @@ -94,7 +94,7 @@ namespace NActors { // counter just turned into a duration and we should store that // duration. Otherwise another thread raced with us and // subtracted some other timestamp t2. - const i64 t = GetCycleCountFast(); + const i64 t = GetCycleCountFast(); const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, t); if (x < 0 && x + t > 0) AtomicStore(&MaxUtilizationAccumulator, x + t); @@ -106,14 +106,14 @@ namespace NActors { if (SpinThreshold > 0) { // spin configured period AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_ACTIVE); - ui64 start = GetCycleCountFast(); + ui64 start = GetCycleCountFast(); bool doSpin = true; while (true) { for (ui32 j = 0; doSpin && j < 12; ++j) { - if (GetCycleCountFast() >= (start + SpinThresholdCycles)) { - doSpin = false; - break; - } + if (GetCycleCountFast() >= (start + SpinThresholdCycles)) { + doSpin = false; + break; + } for (ui32 i = 0; i < 12; ++i) { if (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_ACTIVE) { SpinLockPause(); @@ -122,7 +122,7 @@ namespace NActors { break; } } - } + } if (!doSpin) { break; } @@ -134,23 +134,23 @@ namespace NActors { if (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_ACTIVE) { if (AtomicCas(&threadCtx.WaitingFlag, TThreadCtx::WS_BLOCKED, TThreadCtx::WS_ACTIVE)) { do { - hpnow = GetCycleCountFast(); + hpnow = GetCycleCountFast(); elapsed += hpnow - hpstart; if (threadCtx.Pad.Park()) // interrupted return 0; - hpstart = GetCycleCountFast(); + hpstart = GetCycleCountFast(); parked += hpstart - hpnow; } while (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_BLOCKED); } - } + } } else { AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_BLOCKED); do { - hpnow = GetCycleCountFast(); + hpnow = GetCycleCountFast(); elapsed += hpnow - hpstart; if (threadCtx.Pad.Park()) // interrupted return 0; - hpstart = GetCycleCountFast(); + hpstart = GetCycleCountFast(); parked += hpstart - hpnow; } while (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_BLOCKED); } @@ -170,7 +170,7 @@ namespace NActors { // arbitrary order, which would cause counter to oscillate // around zero. When it crosses zero is a good indication of a // correct value. - const i64 t = GetCycleCountFast(); + const i64 t = GetCycleCountFast(); const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, -t); if (x > 0 && x - t < 0) AtomicStore(&MaxUtilizationAccumulator, x); @@ -183,17 +183,17 @@ namespace NActors { // ok, has work suggested, must dequeue while (!RelaxedLoad(&StopFlag)) { if (const ui32 activation = Activations.Pop(++revolvingCounter)) { - hpnow = GetCycleCountFast(); + hpnow = GetCycleCountFast(); elapsed += hpnow - hpstart; - wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, elapsed); + wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, elapsed); if (parked > 0) { - wctx.AddParkedCycles(parked); + wctx.AddParkedCycles(parked); } if (blocked > 0) { - wctx.AddBlockedCycles(blocked); + wctx.AddBlockedCycles(blocked); } return activation; - } + } SpinLockPause(); } @@ -201,7 +201,7 @@ namespace NActors { return 0; } - inline void TBasicExecutorPool::WakeUpLoop() { + inline void TBasicExecutorPool::WakeUpLoop() { for (ui32 i = 0;;) { TThreadCtx& threadCtx = Threads[i % PoolThreads]; switch (AtomicLoad(&threadCtx.WaitingFlag)) { @@ -230,7 +230,7 @@ namespace NActors { Activations.Push(activation, revolvingCounter); const TAtomic x = AtomicIncrement(Semaphore); if (x <= 0) { // we must find someone to wake-up - WakeUpLoop(); + WakeUpLoop(); } } @@ -247,7 +247,7 @@ namespace NActors { } } - void TBasicExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { + void TBasicExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { TAffinityGuard affinityGuard(Affinity()); ActorSystem = actorSystem; @@ -259,7 +259,7 @@ namespace NActors { Threads[i].Thread.Reset( new TExecutorThread( i, - 0, // CpuId is not used in BASIC pool + 0, // CpuId is not used in BASIC pool actorSystem, this, MailboxTable.Get(), @@ -277,7 +277,7 @@ namespace NActors { TAffinityGuard affinityGuard(Affinity()); ThreadUtilization = 0; - AtomicAdd(MaxUtilizationCounter, -(i64)GetCycleCountFast()); + AtomicAdd(MaxUtilizationCounter, -(i64)GetCycleCountFast()); for (ui32 i = 0; i != PoolThreads; ++i) { Threads[i].Thread->Start(); @@ -297,27 +297,27 @@ namespace NActors { Threads[i].Thread->Join(); } - void TBasicExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_VERIFY_DEBUG(workerId < PoolThreads); + void TBasicExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { + Y_VERIFY_DEBUG(workerId < PoolThreads); - Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); + Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); } - void TBasicExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_VERIFY_DEBUG(workerId < PoolThreads); + void TBasicExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { + Y_VERIFY_DEBUG(workerId < PoolThreads); const auto current = ActorSystem->Monotonic(); if (deadline < current) deadline = current; - ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie); + ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie); } - void TBasicExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_VERIFY_DEBUG(workerId < PoolThreads); + void TBasicExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { + Y_VERIFY_DEBUG(workerId < PoolThreads); const auto deadline = ActorSystem->Monotonic() + delta; - ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie); + ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie); } void TBasicExecutorPool::SetRealTimeMode() const { @@ -421,7 +421,7 @@ namespace NActors { ; // other thread woke this sleeping thread } // if thread has already been awakened then we must awaken the other - WakeUpLoop(); + WakeUpLoop(); } } } diff --git a/library/cpp/actors/core/executor_pool_basic.h b/library/cpp/actors/core/executor_pool_basic.h index 023190f7fe..83224ed9d3 100644 --- a/library/cpp/actors/core/executor_pool_basic.h +++ b/library/cpp/actors/core/executor_pool_basic.h @@ -67,8 +67,8 @@ namespace NActors { TMutex ChangeThreadsLock; public: - static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TBasicExecutorPoolConfig::DEFAULT_TIME_PER_MAILBOX; - static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX; + static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TBasicExecutorPoolConfig::DEFAULT_TIME_PER_MAILBOX; + static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX; TBasicExecutorPool(ui32 poolId, ui32 threads, @@ -79,18 +79,18 @@ namespace NActors { ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX, int realtimePriority = 0, ui32 maxActivityType = 1); - explicit TBasicExecutorPool(const TBasicExecutorPoolConfig& cfg); + explicit TBasicExecutorPool(const TBasicExecutorPoolConfig& cfg); ~TBasicExecutorPool(); - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingReadCounter) override; + ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingReadCounter) override; - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; + void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; + void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; + void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; - void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; + void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; void Start() override; void PrepareStop() override; void Shutdown() override; @@ -106,6 +106,6 @@ namespace NActors { void SetThreadCount(ui32 threads); private: - void WakeUpLoop(); + void WakeUpLoop(); }; } diff --git a/library/cpp/actors/core/executor_pool_basic_ut.cpp b/library/cpp/actors/core/executor_pool_basic_ut.cpp index 76dff693af..be87e5df33 100644 --- a/library/cpp/actors/core/executor_pool_basic_ut.cpp +++ b/library/cpp/actors/core/executor_pool_basic_ut.cpp @@ -377,59 +377,59 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) { Sleep(TDuration::MilliSeconds(1)); } } - - Y_UNIT_TEST(CheckStats) { - const size_t size = 4; - const size_t msgCount = 1e4; - TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50); - - auto setup = GetActorSystemSetup(executorPool); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - auto actor = new TTestSenderActor(); - auto actorId = actorSystem.Register(actor); - actor->Start(actor->SelfId(), msgCount); - actorSystem.Send(actorId, new TEvMsg()); - - while (actor->GetCounter()) { - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter()); - - Sleep(TDuration::MilliSeconds(1)); - } - - TVector<TExecutorThreadStats> stats; - TExecutorPoolStats poolStats; - actorSystem.GetPoolStats(0, poolStats, stats); - // Sum all per-thread counters into the 0th element - for (ui32 idx = 1; idx < stats.size(); ++idx) { - stats[0].Aggregate(stats[idx]); - } - - UNIT_ASSERT_VALUES_EQUAL(stats[0].SentEvents, msgCount - 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].NonDeliveredEvents, 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EmptyMailboxActivation, 0); - //UNIT_ASSERT_VALUES_EQUAL(stats[0].CpuNs, 0); // depends on total duration of test, so undefined - UNIT_ASSERT(stats[0].ElapsedTicks > 0); - UNIT_ASSERT(stats[0].ParkedTicks > 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].BlockedTicks, 0); - UNIT_ASSERT(stats[0].ActivationTimeHistogram.TotalSamples >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EventDeliveryTimeHistogram.TotalSamples, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EventProcessingCountHistogram.TotalSamples, msgCount); - UNIT_ASSERT(stats[0].EventProcessingTimeHistogram.TotalSamples > 0); - UNIT_ASSERT(stats[0].ElapsedTicksByActivity[0] > 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEventsByActivity[0], msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ActorsAliveByActivity[0], 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ScheduledEventsByActivity[0], 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolDestroyedActors, 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolAllocatedMailboxes, 4095); // one line - UNIT_ASSERT(stats[0].MailboxPushedOutByTime + stats[0].MailboxPushedOutByEventCount >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); - UNIT_ASSERT_VALUES_EQUAL(stats[0].MailboxPushedOutBySoftPreemption, 0); - } + + Y_UNIT_TEST(CheckStats) { + const size_t size = 4; + const size_t msgCount = 1e4; + TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50); + + auto setup = GetActorSystemSetup(executorPool); + TActorSystem actorSystem(setup); + actorSystem.Start(); + + auto begin = TInstant::Now(); + + auto actor = new TTestSenderActor(); + auto actorId = actorSystem.Register(actor); + actor->Start(actor->SelfId(), msgCount); + actorSystem.Send(actorId, new TEvMsg()); + + while (actor->GetCounter()) { + auto now = TInstant::Now(); + UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter()); + + Sleep(TDuration::MilliSeconds(1)); + } + + TVector<TExecutorThreadStats> stats; + TExecutorPoolStats poolStats; + actorSystem.GetPoolStats(0, poolStats, stats); + // Sum all per-thread counters into the 0th element + for (ui32 idx = 1; idx < stats.size(); ++idx) { + stats[0].Aggregate(stats[idx]); + } + + UNIT_ASSERT_VALUES_EQUAL(stats[0].SentEvents, msgCount - 1); + UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); + UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, 0); + UNIT_ASSERT_VALUES_EQUAL(stats[0].NonDeliveredEvents, 0); + UNIT_ASSERT_VALUES_EQUAL(stats[0].EmptyMailboxActivation, 0); + //UNIT_ASSERT_VALUES_EQUAL(stats[0].CpuNs, 0); // depends on total duration of test, so undefined + UNIT_ASSERT(stats[0].ElapsedTicks > 0); + UNIT_ASSERT(stats[0].ParkedTicks > 0); + UNIT_ASSERT_VALUES_EQUAL(stats[0].BlockedTicks, 0); + UNIT_ASSERT(stats[0].ActivationTimeHistogram.TotalSamples >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); + UNIT_ASSERT_VALUES_EQUAL(stats[0].EventDeliveryTimeHistogram.TotalSamples, msgCount); + UNIT_ASSERT_VALUES_EQUAL(stats[0].EventProcessingCountHistogram.TotalSamples, msgCount); + UNIT_ASSERT(stats[0].EventProcessingTimeHistogram.TotalSamples > 0); + UNIT_ASSERT(stats[0].ElapsedTicksByActivity[0] > 0); + UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEventsByActivity[0], msgCount); + UNIT_ASSERT_VALUES_EQUAL(stats[0].ActorsAliveByActivity[0], 1); + UNIT_ASSERT_VALUES_EQUAL(stats[0].ScheduledEventsByActivity[0], 0); + UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); + UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolDestroyedActors, 0); + UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolAllocatedMailboxes, 4095); // one line + UNIT_ASSERT(stats[0].MailboxPushedOutByTime + stats[0].MailboxPushedOutByEventCount >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); + UNIT_ASSERT_VALUES_EQUAL(stats[0].MailboxPushedOutBySoftPreemption, 0); + } } diff --git a/library/cpp/actors/core/executor_pool_io.cpp b/library/cpp/actors/core/executor_pool_io.cpp index fb557ae6b0..29e64220db 100644 --- a/library/cpp/actors/core/executor_pool_io.cpp +++ b/library/cpp/actors/core/executor_pool_io.cpp @@ -1,59 +1,59 @@ #include "executor_pool_io.h" #include "mailbox.h" #include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> namespace NActors { - TIOExecutorPool::TIOExecutorPool(ui32 poolId, ui32 threads, const TString& poolName, TAffinity* affinity, ui32 maxActivityType) - : TExecutorPoolBase(poolId, threads, affinity, maxActivityType) + TIOExecutorPool::TIOExecutorPool(ui32 poolId, ui32 threads, const TString& poolName, TAffinity* affinity, ui32 maxActivityType) + : TExecutorPoolBase(poolId, threads, affinity, maxActivityType) , Threads(new TThreadCtx[threads]) , PoolName(poolName) - {} - - TIOExecutorPool::TIOExecutorPool(const TIOExecutorPoolConfig& cfg) - : TIOExecutorPool( - cfg.PoolId, - cfg.Threads, - cfg.PoolName, - new TAffinity(cfg.Affinity), - cfg.MaxActivityType - ) - {} - + {} + + TIOExecutorPool::TIOExecutorPool(const TIOExecutorPoolConfig& cfg) + : TIOExecutorPool( + cfg.PoolId, + cfg.Threads, + cfg.PoolName, + new TAffinity(cfg.Affinity), + cfg.MaxActivityType + ) + {} + TIOExecutorPool::~TIOExecutorPool() { Threads.Destroy(); while (ThreadQueue.Pop(0)) ; } - ui32 TIOExecutorPool::GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { - ui32 workerId = wctx.WorkerId; - Y_VERIFY_DEBUG(workerId < PoolThreads); + ui32 TIOExecutorPool::GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { + ui32 workerId = wctx.WorkerId; + Y_VERIFY_DEBUG(workerId < PoolThreads); NHPTimer::STime elapsed = 0; NHPTimer::STime parked = 0; - NHPTimer::STime hpstart = GetCycleCountFast(); + NHPTimer::STime hpstart = GetCycleCountFast(); NHPTimer::STime hpnow; const TAtomic x = AtomicDecrement(Semaphore); if (x < 0) { - TThreadCtx& threadCtx = Threads[workerId]; - ThreadQueue.Push(workerId + 1, revolvingCounter); - hpnow = GetCycleCountFast(); + TThreadCtx& threadCtx = Threads[workerId]; + ThreadQueue.Push(workerId + 1, revolvingCounter); + hpnow = GetCycleCountFast(); elapsed += hpnow - hpstart; if (threadCtx.Pad.Park()) return 0; - hpstart = GetCycleCountFast(); + hpstart = GetCycleCountFast(); parked += hpstart - hpnow; } while (!RelaxedLoad(&StopFlag)) { if (const ui32 activation = Activations.Pop(++revolvingCounter)) { - hpnow = GetCycleCountFast(); + hpnow = GetCycleCountFast(); elapsed += hpnow - hpstart; - wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, elapsed); + wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, elapsed); if (parked > 0) { - wctx.AddParkedCycles(parked); + wctx.AddParkedCycles(parked); } return activation; } @@ -63,12 +63,12 @@ namespace NActors { return 0; } - void TIOExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); + void TIOExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { + Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); } - void TIOExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_UNUSED(workerId); + void TIOExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { + Y_UNUSED(workerId); const auto current = ActorSystem->Monotonic(); if (deadline < current) @@ -78,8 +78,8 @@ namespace NActors { ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie); } - void TIOExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_UNUSED(workerId); + void TIOExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { + Y_UNUSED(workerId); const auto deadline = ActorSystem->Monotonic() + delta; TTicketLock::TGuard guard(&ScheduleLock); @@ -101,7 +101,7 @@ namespace NActors { } } - void TIOExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { + void TIOExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { TAffinityGuard affinityGuard(Affinity()); ActorSystem = actorSystem; @@ -109,7 +109,7 @@ namespace NActors { ScheduleQueue.Reset(new NSchedulerQueue::TQueueType()); for (ui32 i = 0; i != PoolThreads; ++i) { - Threads[i].Thread.Reset(new TExecutorThread(i, 0, actorSystem, this, MailboxTable.Get(), PoolName)); + Threads[i].Thread.Reset(new TExecutorThread(i, 0, actorSystem, this, MailboxTable.Get(), PoolName)); } *scheduleReaders = &ScheduleQueue->Reader; diff --git a/library/cpp/actors/core/executor_pool_io.h b/library/cpp/actors/core/executor_pool_io.h index e576d642a1..00de73bacd 100644 --- a/library/cpp/actors/core/executor_pool_io.h +++ b/library/cpp/actors/core/executor_pool_io.h @@ -25,20 +25,20 @@ namespace NActors { const TString PoolName; public: - TIOExecutorPool(ui32 poolId, ui32 threads, const TString& poolName = "", TAffinity* affinity = nullptr, + TIOExecutorPool(ui32 poolId, ui32 threads, const TString& poolName = "", TAffinity* affinity = nullptr, ui32 maxActivityType = 1); - explicit TIOExecutorPool(const TIOExecutorPoolConfig& cfg); + explicit TIOExecutorPool(const TIOExecutorPoolConfig& cfg); ~TIOExecutorPool(); - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override; + ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override; - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; + void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; + void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; + void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; - void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; + void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; void Start() override; void PrepareStop() override; void Shutdown() override; diff --git a/library/cpp/actors/core/executor_pool_united.cpp b/library/cpp/actors/core/executor_pool_united.cpp index dac6245635..d932714aa9 100644 --- a/library/cpp/actors/core/executor_pool_united.cpp +++ b/library/cpp/actors/core/executor_pool_united.cpp @@ -1,1428 +1,1428 @@ -#include "executor_pool_united.h" - -#include "balancer.h" -#include "cpu_state.h" -#include "executor_thread.h" -#include "probes.h" +#include "executor_pool_united.h" + +#include "balancer.h" +#include "cpu_state.h" +#include "executor_thread.h" +#include "probes.h" #include "mailbox.h" -#include "scheduler_queue.h" +#include "scheduler_queue.h" #include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/util/futex.h> -#include <library/cpp/actors/util/intrinsics.h> -#include <library/cpp/actors/util/timerfd.h> - -#include <util/system/datetime.h> -#include <util/system/hp_timer.h> +#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/futex.h> +#include <library/cpp/actors/util/intrinsics.h> +#include <library/cpp/actors/util/timerfd.h> -#include <algorithm> +#include <util/system/datetime.h> +#include <util/system/hp_timer.h> +#include <algorithm> + namespace NActors { LWTRACE_USING(ACTORLIB_PROVIDER); - struct TUnitedWorkers::TWorker: public TNonCopyable { - TAutoPtr<TExecutorThread> Thread; - volatile TThreadId ThreadId = UnknownThreadId; - NSchedulerQueue::TQueueType SchedulerQueue; - }; - - struct TUnitedWorkers::TPool: public TNonCopyable { - TAtomic Waiters = 0; // Number of idle cpus, waiting for activations in this pool - char Padding[64 - sizeof(TAtomic)]; - - TUnorderedCache<ui32, 512, 4> Activations; // MPMC-queue for mailbox activations - TAtomic Active = 0; // Number of mailboxes ready for execution or currently executing - TAtomic Tokens = 0; // Pending tokens (token is required for worker to start execution, guarantees concurrency limit and activation availability) - volatile bool StopFlag = false; - - // Configuration - TPoolId PoolId; - TAtomicBase Concurrency; // Max concurrent workers running this pool - IExecutorPool* ExecutorPool; - TMailboxTable* MailboxTable; - ui64 TimePerMailboxTs; - ui32 EventsPerMailbox; - - // Cpus this pool is allowed to run on - // Cpus are specified in wake order - TStackVec<TCpu*, 15> WakeOrderCpus; - - ~TPool() { - while (Activations.Pop(0)) {} - } - - void Stop() { - AtomicStore(&StopFlag, true); - } - - bool IsUnited() const { - return WakeOrderCpus.size(); - } - - // Add activation of newly scheduled mailbox. Returns generated token (unless concurrency is exceeded) - bool PushActivation(ui32 activation, ui64 revolvingCounter) { - Activations.Push(activation, revolvingCounter); - TAtomicBase active = AtomicIncrement(Active); - if (active <= Concurrency) { // token generated - AtomicIncrement(Tokens); - return true; - } - return false; - } - - template <bool Relaxed> - static bool TryAcquireTokenImpl(TAtomic* tokens) { - while (true) { - TAtomicBase value; - if constexpr (Relaxed) { - value = RelaxedLoad(tokens); - } else { - value = AtomicLoad(tokens); - } - if (value > 0) { - if (AtomicCas(tokens, value - 1, value)) { - return true; // token acquired - } - } else { - return false; // no more tokens - } - } - } - - // Try acquire pending token. Must be done before execution - bool TryAcquireToken() { - return TryAcquireTokenImpl<false>(&Tokens); - } - - // Try acquire pending token. Must be done before execution - bool TryAcquireTokenRelaxed() { - return TryAcquireTokenImpl<true>(&Tokens); - } - - // Get activation. Requires acquired token. - void BeginExecution(ui32& activation, ui64 revolvingCounter) { - while (!RelaxedLoad(&StopFlag)) { - if (activation = Activations.Pop(++revolvingCounter)) { - return; - } - SpinLockPause(); - } - activation = 0; // should stop - } - - // End currently active execution and start new one if token is available. - // Reuses token if it's not destroyed. - // Returned `true` means successful switch, `activation` is filled. - // Returned `false` means execution has ended, no need to call StopExecution() - bool NextExecution(ui32& activation, ui64 revolvingCounter) { - if (AtomicDecrement(Active) >= Concurrency) { // reuse just released token - BeginExecution(activation, revolvingCounter); - return true; - } else if (TryAcquireToken()) { // another token acquired - BeginExecution(activation, revolvingCounter); - return true; - } - return false; // no more tokens available - } - - // Stop active execution. Returns released token (unless it is destroyed) - bool StopExecution() { - TAtomicBase active = AtomicDecrement(Active); - if (active >= Concurrency) { // token released - AtomicIncrement(Tokens); - return true; - } - return false; // token destroyed - } - - // Switch worker context into this pool - void Switch(TWorkerContext& wctx, ui64 softDeadlineTs, TExecutorThreadStats& stats) { - wctx.Switch(ExecutorPool, MailboxTable, TimePerMailboxTs, EventsPerMailbox, softDeadlineTs, &stats); - } - }; - - class TPoolScheduler { - class TSchedulable { - // Lower PoolBits store PoolId - // All other higher bits store virtual runtime in cycles - using TValue = ui64; - TValue Value; - - static constexpr ui64 PoolIdMask = ui64((1ull << PoolBits) - 1); - static constexpr ui64 VRunTsMask = ~PoolIdMask; - - public: - explicit TSchedulable(TPoolId poolId = MaxPools, ui64 vrunts = 0) - : Value((poolId & PoolIdMask) | (vrunts & VRunTsMask)) - {} - - TPoolId GetPoolId() const { - return Value & PoolIdMask; - } - - ui64 GetVRunTs() const { - // Do not truncate pool id - // NOTE: it decrease accuracy, but improves performance - return Value; - } - - ui64 GetPreciseVRunTs() const { - return Value & VRunTsMask; - } - - void SetVRunTs(ui64 vrunts) { - Value = (Value & PoolIdMask) | (vrunts & VRunTsMask); - } - - void Account(ui64 base, ui64 ts) { - // Add at least minimum amount to change Value - SetVRunTs(base + Max(ts, PoolIdMask + 1)); - } - }; - - // For min-heap of Items - struct TCmp { - bool operator()(TSchedulable lhs, TSchedulable rhs) const { - return lhs.GetVRunTs() > rhs.GetVRunTs(); - } - }; - - TPoolId Size = 0; // total number of pools on this cpu - TPoolId Current = 0; // index of current pool in `Items` - - // At the beginning `Current` items are orginized as binary min-heap -- ready to be scheduled - // The rest `Size - Current` items are unordered (required to keep track of last vrunts) - TSchedulable Items[MaxPools]; // virtual runtime in cycles for each pool - ui64 MinVRunTs = 0; // virtual runtime used by waking pools (system's vrunts) - ui64 Ts = 0; // real timestamp of current execution start (for accounting) - - // Maps PoolId into it's inverse weight - ui64 InvWeights[MaxPools]; - static constexpr ui64 VRunTsOverflow = ui64(1ull << 62ull) / MaxPoolWeight; - - public: - void AddPool(TPoolId pool, TPoolWeight weight) { - Items[Size] = TSchedulable(pool, MinVRunTs); - Size++; - InvWeights[pool] = MaxPoolWeight / std::clamp(weight ? weight : DefPoolWeight, MinPoolWeight, MaxPoolWeight); - } - - // Iterate over pools in scheduling order - // should be used in construction: - // for (TPoolId pool = Begin(); pool != End(); pool = Next()) - TPoolId Begin() { - // Wrap vruntime around to avoid overflow, if required - if (Y_UNLIKELY(MinVRunTs >= VRunTsOverflow)) { - for (TPoolId i = 0; i < Size; i++) { - ui64 ts = Items[i].GetPreciseVRunTs(); - Items[i].SetVRunTs(ts >= VRunTsOverflow ? ts - VRunTsOverflow : 0); + struct TUnitedWorkers::TWorker: public TNonCopyable { + TAutoPtr<TExecutorThread> Thread; + volatile TThreadId ThreadId = UnknownThreadId; + NSchedulerQueue::TQueueType SchedulerQueue; + }; + + struct TUnitedWorkers::TPool: public TNonCopyable { + TAtomic Waiters = 0; // Number of idle cpus, waiting for activations in this pool + char Padding[64 - sizeof(TAtomic)]; + + TUnorderedCache<ui32, 512, 4> Activations; // MPMC-queue for mailbox activations + TAtomic Active = 0; // Number of mailboxes ready for execution or currently executing + TAtomic Tokens = 0; // Pending tokens (token is required for worker to start execution, guarantees concurrency limit and activation availability) + volatile bool StopFlag = false; + + // Configuration + TPoolId PoolId; + TAtomicBase Concurrency; // Max concurrent workers running this pool + IExecutorPool* ExecutorPool; + TMailboxTable* MailboxTable; + ui64 TimePerMailboxTs; + ui32 EventsPerMailbox; + + // Cpus this pool is allowed to run on + // Cpus are specified in wake order + TStackVec<TCpu*, 15> WakeOrderCpus; + + ~TPool() { + while (Activations.Pop(0)) {} + } + + void Stop() { + AtomicStore(&StopFlag, true); + } + + bool IsUnited() const { + return WakeOrderCpus.size(); + } + + // Add activation of newly scheduled mailbox. Returns generated token (unless concurrency is exceeded) + bool PushActivation(ui32 activation, ui64 revolvingCounter) { + Activations.Push(activation, revolvingCounter); + TAtomicBase active = AtomicIncrement(Active); + if (active <= Concurrency) { // token generated + AtomicIncrement(Tokens); + return true; + } + return false; + } + + template <bool Relaxed> + static bool TryAcquireTokenImpl(TAtomic* tokens) { + while (true) { + TAtomicBase value; + if constexpr (Relaxed) { + value = RelaxedLoad(tokens); + } else { + value = AtomicLoad(tokens); } - MinVRunTs -= VRunTsOverflow; - } - Current = Size; - std::make_heap(Items, Items + Current, TCmp()); - return Next(); - } - - constexpr TPoolId End() const { - return MaxPools; - } - - TPoolId Next() { - if (Current > 0) { - std::pop_heap(Items, Items + Current, TCmp()); - Current--; - return CurrentPool(); - } else { - return End(); - } - } - - // Scheduling was successful, we are going to run CurrentPool() - void Scheduled() { - MinVRunTs = Max(MinVRunTs, Items[Current].GetPreciseVRunTs()); - // NOTE: Ts is propagated on Account() to avoid gaps - } - - // Schedule specific pool that woke up cpu after idle - void ScheduledAfterIdle(TPoolId pool, ui64 ts) { - if (Y_UNLIKELY(ts < Ts)) { // anomaly: time goes backwards (e.g. rdtsc is reset to zero on cpu reset) - Ts = ts; // just skip anomalous time slice - return; - } - MinVRunTs += (ts - Ts) * (MaxPoolWeight / DefPoolWeight); // propagate system's vrunts to blur difference between pools - Ts = ts; // propagate time w/o accounting to any pool - - // Set specified pool as current, it requires scan - for (Current = 0; Current < Size && pool != Items[Current].GetPoolId(); Current++) {} - Y_VERIFY(Current < Size); - } - - // Account currently running pool till now (ts) - void Account(ui64 ts) { - // Skip time slice for the first run and when time goes backwards (e.g. rdtsc is reset to zero on cpu reset) - if (Y_LIKELY(Ts > 0 && Ts <= ts)) { - TPoolId pool = CurrentPool(); - Y_VERIFY(pool < MaxPools); - Items[Current].Account(MinVRunTs, (ts - Ts) * InvWeights[pool]); - } - Ts = ts; // propagate time - } - - TPoolId CurrentPool() const { - return Items[Current].GetPoolId(); - } - }; - - // Cyclic array of timers for idle workers to wait for hard preemption on - struct TIdleQueue: public TNonCopyable { - TArrayHolder<TTimerFd> Timers; - size_t Size; - TAtomic EnqueueCounter = 0; - TAtomic DequeueCounter = 0; - - explicit TIdleQueue(size_t size) - : Timers(new TTimerFd[size]) - , Size(size) - {} - - void Stop() { - for (size_t i = 0; i < Size; i++) { - Timers[i].Wake(); - } - } - - // Returns timer which new idle-worker should wait for - TTimerFd* Enqueue() { - return &Timers[AtomicGetAndIncrement(EnqueueCounter) % Size]; - } - - // Returns timer that hard preemption should trigger to wake idle-worker - TTimerFd* Dequeue() { - return &Timers[AtomicGetAndIncrement(DequeueCounter) % Size]; - } - }; - - // Base class for cpu-local managers that help workers on single cpu to cooperate - struct TCpuLocalManager: public TThrRefBase { - TUnitedWorkers* United; - - explicit TCpuLocalManager(TUnitedWorkers* united) - : United(united) - {} - - virtual TWorkerId WorkerCount() const = 0; - virtual void AddWorker(TWorkerId workerId) = 0; - virtual void Stop() = 0; - }; - - // Represents cpu with single associated worker that is able to execute any pool. - // It always executes pool assigned by balancer and switch pool only if assigned pool has changed - struct TAssignedCpu: public TCpuLocalManager { - bool Started = false; - - TAssignedCpu(TUnitedWorkers* united) - : TCpuLocalManager(united) - {} - - TWorkerId WorkerCount() const override { - return 1; - } - - void AddWorker(TWorkerId workerId) override { - Y_UNUSED(workerId); - } - - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { - ui32 activation; - if (Y_UNLIKELY(!Started)) { - Started = true; - } else if (Y_UNLIKELY(United->IsPoolReassigned(wctx))) { - United->StopExecution(wctx.PoolId); // stop current execution and switch pool if reassigned - } else if (United->NextExecution(wctx.PoolId, activation, revolvingCounter)) { - return activation; // another activation from currently executing pool (or 0 if stopped) - } - - // Switch to another pool, it blocks until token is acquired - if (Y_UNLIKELY(!SwitchPool(wctx))) { - return 0; // stopped - } - United->SwitchPool(wctx, 0); - United->BeginExecution(wctx.PoolId, activation, revolvingCounter); - return activation; - } - - void Stop() override { - } - - private: - // Sets next pool to run, and acquires token, blocks if there are no tokens - bool SwitchPool(TWorkerContext& wctx) { - if (Y_UNLIKELY(United->IsStopped())) { - return false; - } - - // Run balancer (if it's time to) - United->Balance(); - - // Select pool to execute - wctx.PoolId = United->AssignedPool(wctx); - Y_VERIFY(wctx.PoolId != CpuShared); - if (United->TryAcquireToken(wctx.PoolId)) { - return true; - } - - // No more work -- wait for activations (spinning, then blocked) - wctx.PoolId = United->Idle(wctx.PoolId, wctx); - - // Wakeup or stop occured - if (Y_UNLIKELY(wctx.PoolId == CpuStopped)) { - return false; - } - return true; // United->Idle() has already acquired token - } - }; - - // Lock-free data structure that help workers on single cpu to discover their state and do hard preemptions - struct TSharedCpu: public TCpuLocalManager { - // Current lease - volatile TLease::TValue CurrentLease; - char Padding1[64 - sizeof(TLease)]; - - // Slow pools - // the highest bit: 1=wait-for-slow-workers mode 0=else - // any lower bit (poolId is bit position): 1=pool-is-slow 0=pool-is-fast - volatile TPoolsMask SlowPoolsMask = 0; - char Padding2[64 - sizeof(TPoolsMask)]; - - // Must be accessed under never expiring lease to avoid races - TPoolScheduler PoolSched; - TWorkerId FastWorker = MaxWorkers; - TTimerFd* PreemptionTimer = nullptr; - ui64 HardPreemptionTs = 0; - bool Started = false; - - TIdleQueue IdleQueue; - - struct TConfig { - const TCpuId CpuId; - const TWorkerId Workers; - ui64 SoftLimitTs; - ui64 HardLimitTs; - ui64 EventLimitTs; - ui64 LimitPrecisionTs; - const int IdleWorkerPriority; - const int FastWorkerPriority; - const bool NoRealtime; - const bool NoAffinity; - const TCpuAllocation CpuAlloc; - - TConfig(const TCpuAllocation& allocation, const TUnitedWorkersConfig& united) - : CpuId(allocation.CpuId) - , Workers(allocation.AllowedPools.size() + 1) - , SoftLimitTs(Us2Ts(united.PoolLimitUs)) - , HardLimitTs(Us2Ts(united.PoolLimitUs + united.EventLimitUs)) - , EventLimitTs(Us2Ts(united.EventLimitUs)) - , LimitPrecisionTs(Us2Ts(united.LimitPrecisionUs)) - , IdleWorkerPriority(std::clamp<ui64>(united.IdleWorkerPriority ? united.IdleWorkerPriority : 20, 1, 99)) - , FastWorkerPriority(std::clamp<ui64>(united.FastWorkerPriority ? united.FastWorkerPriority : 10, 1, IdleWorkerPriority - 1)) - , NoRealtime(united.NoRealtime) - , NoAffinity(united.NoAffinity) - , CpuAlloc(allocation) - {} - }; - - TConfig Config; - TVector<TWorkerId> Workers; - - TSharedCpu(const TConfig& cfg, TUnitedWorkers* united) - : TCpuLocalManager(united) - , IdleQueue(cfg.Workers) - , Config(cfg) - { - for (const auto& pa : Config.CpuAlloc.AllowedPools) { - PoolSched.AddPool(pa.PoolId, pa.Weight); - } - } - - TWorkerId WorkerCount() const override { - return Config.Workers; - } - - void AddWorker(TWorkerId workerId) override { - if (Workers.empty()) { - // Grant lease to the first worker - AtomicStore(&CurrentLease, TLease(workerId, NeverExpire).Value); - } - Workers.push_back(workerId); - } - - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { - ui32 activation; - if (!wctx.Lease.IsNeverExpiring()) { - if (wctx.SoftDeadlineTs < GetCycleCountFast()) { // stop if lease has expired or is near to be expired - United->StopExecution(wctx.PoolId); - } else if (United->NextExecution(wctx.PoolId, activation, revolvingCounter)) { - return activation; // another activation from currently executing pool (or 0 if stopped) - } - } - - // Switch to another pool, it blocks until token is acquired - if (Y_UNLIKELY(!SwitchPool(wctx))) { - return 0; // stopped - } - United->BeginExecution(wctx.PoolId, activation, revolvingCounter); - return activation; - } - - void Stop() override { - IdleQueue.Stop(); - } - - private: - enum EPriority { - IdlePriority, // highest (real-time, Config.IdleWorkerPriority) - FastPriority, // normal (real-time, Config.FastWorkerPriority) - SlowPriority, // lowest (not real-time) - }; - - enum EWorkerAction { - // Fast-worker - ExecuteFast, - WaitForSlow, - - // Slow-worker - BecameIdle, - WakeFast, - - // Idle-worker - BecameFast, - Standby, - - // Common - Stopped, - }; - - // Thread-safe; should be called from worker - // Blocks for idle-workers; sets lease and next pool to run - bool SwitchPool(TWorkerContext& wctx) { - TTimerFd* idleTimer = nullptr; - while (true) { - if (DisablePreemptionAndTryExtend(wctx.Lease)) { // if fast-worker - if (Y_UNLIKELY(!Started)) { - SetPriority(0, FastPriority); - Started = true; - } - while (true) { - switch (FastWorkerAction(wctx)) { - case ExecuteFast: - United->SwitchPool(wctx, wctx.Lease.GetPreciseExpireTs() - Config.EventLimitTs); - EnablePreemptionAndGrant(wctx.Lease); - return true; - case WaitForSlow: - FastWorkerSleep(GetCycleCountFast() + Config.SoftLimitTs); - break; - case Stopped: return false; - default: Y_FAIL(); + if (value > 0) { + if (AtomicCas(tokens, value - 1, value)) { + return true; // token acquired + } + } else { + return false; // no more tokens + } + } + } + + // Try acquire pending token. Must be done before execution + bool TryAcquireToken() { + return TryAcquireTokenImpl<false>(&Tokens); + } + + // Try acquire pending token. Must be done before execution + bool TryAcquireTokenRelaxed() { + return TryAcquireTokenImpl<true>(&Tokens); + } + + // Get activation. Requires acquired token. + void BeginExecution(ui32& activation, ui64 revolvingCounter) { + while (!RelaxedLoad(&StopFlag)) { + if (activation = Activations.Pop(++revolvingCounter)) { + return; + } + SpinLockPause(); + } + activation = 0; // should stop + } + + // End currently active execution and start new one if token is available. + // Reuses token if it's not destroyed. + // Returned `true` means successful switch, `activation` is filled. + // Returned `false` means execution has ended, no need to call StopExecution() + bool NextExecution(ui32& activation, ui64 revolvingCounter) { + if (AtomicDecrement(Active) >= Concurrency) { // reuse just released token + BeginExecution(activation, revolvingCounter); + return true; + } else if (TryAcquireToken()) { // another token acquired + BeginExecution(activation, revolvingCounter); + return true; + } + return false; // no more tokens available + } + + // Stop active execution. Returns released token (unless it is destroyed) + bool StopExecution() { + TAtomicBase active = AtomicDecrement(Active); + if (active >= Concurrency) { // token released + AtomicIncrement(Tokens); + return true; + } + return false; // token destroyed + } + + // Switch worker context into this pool + void Switch(TWorkerContext& wctx, ui64 softDeadlineTs, TExecutorThreadStats& stats) { + wctx.Switch(ExecutorPool, MailboxTable, TimePerMailboxTs, EventsPerMailbox, softDeadlineTs, &stats); + } + }; + + class TPoolScheduler { + class TSchedulable { + // Lower PoolBits store PoolId + // All other higher bits store virtual runtime in cycles + using TValue = ui64; + TValue Value; + + static constexpr ui64 PoolIdMask = ui64((1ull << PoolBits) - 1); + static constexpr ui64 VRunTsMask = ~PoolIdMask; + + public: + explicit TSchedulable(TPoolId poolId = MaxPools, ui64 vrunts = 0) + : Value((poolId & PoolIdMask) | (vrunts & VRunTsMask)) + {} + + TPoolId GetPoolId() const { + return Value & PoolIdMask; + } + + ui64 GetVRunTs() const { + // Do not truncate pool id + // NOTE: it decrease accuracy, but improves performance + return Value; + } + + ui64 GetPreciseVRunTs() const { + return Value & VRunTsMask; + } + + void SetVRunTs(ui64 vrunts) { + Value = (Value & PoolIdMask) | (vrunts & VRunTsMask); + } + + void Account(ui64 base, ui64 ts) { + // Add at least minimum amount to change Value + SetVRunTs(base + Max(ts, PoolIdMask + 1)); + } + }; + + // For min-heap of Items + struct TCmp { + bool operator()(TSchedulable lhs, TSchedulable rhs) const { + return lhs.GetVRunTs() > rhs.GetVRunTs(); + } + }; + + TPoolId Size = 0; // total number of pools on this cpu + TPoolId Current = 0; // index of current pool in `Items` + + // At the beginning `Current` items are orginized as binary min-heap -- ready to be scheduled + // The rest `Size - Current` items are unordered (required to keep track of last vrunts) + TSchedulable Items[MaxPools]; // virtual runtime in cycles for each pool + ui64 MinVRunTs = 0; // virtual runtime used by waking pools (system's vrunts) + ui64 Ts = 0; // real timestamp of current execution start (for accounting) + + // Maps PoolId into it's inverse weight + ui64 InvWeights[MaxPools]; + static constexpr ui64 VRunTsOverflow = ui64(1ull << 62ull) / MaxPoolWeight; + + public: + void AddPool(TPoolId pool, TPoolWeight weight) { + Items[Size] = TSchedulable(pool, MinVRunTs); + Size++; + InvWeights[pool] = MaxPoolWeight / std::clamp(weight ? weight : DefPoolWeight, MinPoolWeight, MaxPoolWeight); + } + + // Iterate over pools in scheduling order + // should be used in construction: + // for (TPoolId pool = Begin(); pool != End(); pool = Next()) + TPoolId Begin() { + // Wrap vruntime around to avoid overflow, if required + if (Y_UNLIKELY(MinVRunTs >= VRunTsOverflow)) { + for (TPoolId i = 0; i < Size; i++) { + ui64 ts = Items[i].GetPreciseVRunTs(); + Items[i].SetVRunTs(ts >= VRunTsOverflow ? ts - VRunTsOverflow : 0); + } + MinVRunTs -= VRunTsOverflow; + } + Current = Size; + std::make_heap(Items, Items + Current, TCmp()); + return Next(); + } + + constexpr TPoolId End() const { + return MaxPools; + } + + TPoolId Next() { + if (Current > 0) { + std::pop_heap(Items, Items + Current, TCmp()); + Current--; + return CurrentPool(); + } else { + return End(); + } + } + + // Scheduling was successful, we are going to run CurrentPool() + void Scheduled() { + MinVRunTs = Max(MinVRunTs, Items[Current].GetPreciseVRunTs()); + // NOTE: Ts is propagated on Account() to avoid gaps + } + + // Schedule specific pool that woke up cpu after idle + void ScheduledAfterIdle(TPoolId pool, ui64 ts) { + if (Y_UNLIKELY(ts < Ts)) { // anomaly: time goes backwards (e.g. rdtsc is reset to zero on cpu reset) + Ts = ts; // just skip anomalous time slice + return; + } + MinVRunTs += (ts - Ts) * (MaxPoolWeight / DefPoolWeight); // propagate system's vrunts to blur difference between pools + Ts = ts; // propagate time w/o accounting to any pool + + // Set specified pool as current, it requires scan + for (Current = 0; Current < Size && pool != Items[Current].GetPoolId(); Current++) {} + Y_VERIFY(Current < Size); + } + + // Account currently running pool till now (ts) + void Account(ui64 ts) { + // Skip time slice for the first run and when time goes backwards (e.g. rdtsc is reset to zero on cpu reset) + if (Y_LIKELY(Ts > 0 && Ts <= ts)) { + TPoolId pool = CurrentPool(); + Y_VERIFY(pool < MaxPools); + Items[Current].Account(MinVRunTs, (ts - Ts) * InvWeights[pool]); + } + Ts = ts; // propagate time + } + + TPoolId CurrentPool() const { + return Items[Current].GetPoolId(); + } + }; + + // Cyclic array of timers for idle workers to wait for hard preemption on + struct TIdleQueue: public TNonCopyable { + TArrayHolder<TTimerFd> Timers; + size_t Size; + TAtomic EnqueueCounter = 0; + TAtomic DequeueCounter = 0; + + explicit TIdleQueue(size_t size) + : Timers(new TTimerFd[size]) + , Size(size) + {} + + void Stop() { + for (size_t i = 0; i < Size; i++) { + Timers[i].Wake(); + } + } + + // Returns timer which new idle-worker should wait for + TTimerFd* Enqueue() { + return &Timers[AtomicGetAndIncrement(EnqueueCounter) % Size]; + } + + // Returns timer that hard preemption should trigger to wake idle-worker + TTimerFd* Dequeue() { + return &Timers[AtomicGetAndIncrement(DequeueCounter) % Size]; + } + }; + + // Base class for cpu-local managers that help workers on single cpu to cooperate + struct TCpuLocalManager: public TThrRefBase { + TUnitedWorkers* United; + + explicit TCpuLocalManager(TUnitedWorkers* united) + : United(united) + {} + + virtual TWorkerId WorkerCount() const = 0; + virtual void AddWorker(TWorkerId workerId) = 0; + virtual void Stop() = 0; + }; + + // Represents cpu with single associated worker that is able to execute any pool. + // It always executes pool assigned by balancer and switch pool only if assigned pool has changed + struct TAssignedCpu: public TCpuLocalManager { + bool Started = false; + + TAssignedCpu(TUnitedWorkers* united) + : TCpuLocalManager(united) + {} + + TWorkerId WorkerCount() const override { + return 1; + } + + void AddWorker(TWorkerId workerId) override { + Y_UNUSED(workerId); + } + + ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { + ui32 activation; + if (Y_UNLIKELY(!Started)) { + Started = true; + } else if (Y_UNLIKELY(United->IsPoolReassigned(wctx))) { + United->StopExecution(wctx.PoolId); // stop current execution and switch pool if reassigned + } else if (United->NextExecution(wctx.PoolId, activation, revolvingCounter)) { + return activation; // another activation from currently executing pool (or 0 if stopped) + } + + // Switch to another pool, it blocks until token is acquired + if (Y_UNLIKELY(!SwitchPool(wctx))) { + return 0; // stopped + } + United->SwitchPool(wctx, 0); + United->BeginExecution(wctx.PoolId, activation, revolvingCounter); + return activation; + } + + void Stop() override { + } + + private: + // Sets next pool to run, and acquires token, blocks if there are no tokens + bool SwitchPool(TWorkerContext& wctx) { + if (Y_UNLIKELY(United->IsStopped())) { + return false; + } + + // Run balancer (if it's time to) + United->Balance(); + + // Select pool to execute + wctx.PoolId = United->AssignedPool(wctx); + Y_VERIFY(wctx.PoolId != CpuShared); + if (United->TryAcquireToken(wctx.PoolId)) { + return true; + } + + // No more work -- wait for activations (spinning, then blocked) + wctx.PoolId = United->Idle(wctx.PoolId, wctx); + + // Wakeup or stop occured + if (Y_UNLIKELY(wctx.PoolId == CpuStopped)) { + return false; + } + return true; // United->Idle() has already acquired token + } + }; + + // Lock-free data structure that help workers on single cpu to discover their state and do hard preemptions + struct TSharedCpu: public TCpuLocalManager { + // Current lease + volatile TLease::TValue CurrentLease; + char Padding1[64 - sizeof(TLease)]; + + // Slow pools + // the highest bit: 1=wait-for-slow-workers mode 0=else + // any lower bit (poolId is bit position): 1=pool-is-slow 0=pool-is-fast + volatile TPoolsMask SlowPoolsMask = 0; + char Padding2[64 - sizeof(TPoolsMask)]; + + // Must be accessed under never expiring lease to avoid races + TPoolScheduler PoolSched; + TWorkerId FastWorker = MaxWorkers; + TTimerFd* PreemptionTimer = nullptr; + ui64 HardPreemptionTs = 0; + bool Started = false; + + TIdleQueue IdleQueue; + + struct TConfig { + const TCpuId CpuId; + const TWorkerId Workers; + ui64 SoftLimitTs; + ui64 HardLimitTs; + ui64 EventLimitTs; + ui64 LimitPrecisionTs; + const int IdleWorkerPriority; + const int FastWorkerPriority; + const bool NoRealtime; + const bool NoAffinity; + const TCpuAllocation CpuAlloc; + + TConfig(const TCpuAllocation& allocation, const TUnitedWorkersConfig& united) + : CpuId(allocation.CpuId) + , Workers(allocation.AllowedPools.size() + 1) + , SoftLimitTs(Us2Ts(united.PoolLimitUs)) + , HardLimitTs(Us2Ts(united.PoolLimitUs + united.EventLimitUs)) + , EventLimitTs(Us2Ts(united.EventLimitUs)) + , LimitPrecisionTs(Us2Ts(united.LimitPrecisionUs)) + , IdleWorkerPriority(std::clamp<ui64>(united.IdleWorkerPriority ? united.IdleWorkerPriority : 20, 1, 99)) + , FastWorkerPriority(std::clamp<ui64>(united.FastWorkerPriority ? united.FastWorkerPriority : 10, 1, IdleWorkerPriority - 1)) + , NoRealtime(united.NoRealtime) + , NoAffinity(united.NoAffinity) + , CpuAlloc(allocation) + {} + }; + + TConfig Config; + TVector<TWorkerId> Workers; + + TSharedCpu(const TConfig& cfg, TUnitedWorkers* united) + : TCpuLocalManager(united) + , IdleQueue(cfg.Workers) + , Config(cfg) + { + for (const auto& pa : Config.CpuAlloc.AllowedPools) { + PoolSched.AddPool(pa.PoolId, pa.Weight); + } + } + + TWorkerId WorkerCount() const override { + return Config.Workers; + } + + void AddWorker(TWorkerId workerId) override { + if (Workers.empty()) { + // Grant lease to the first worker + AtomicStore(&CurrentLease, TLease(workerId, NeverExpire).Value); + } + Workers.push_back(workerId); + } + + ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { + ui32 activation; + if (!wctx.Lease.IsNeverExpiring()) { + if (wctx.SoftDeadlineTs < GetCycleCountFast()) { // stop if lease has expired or is near to be expired + United->StopExecution(wctx.PoolId); + } else if (United->NextExecution(wctx.PoolId, activation, revolvingCounter)) { + return activation; // another activation from currently executing pool (or 0 if stopped) + } + } + + // Switch to another pool, it blocks until token is acquired + if (Y_UNLIKELY(!SwitchPool(wctx))) { + return 0; // stopped + } + United->BeginExecution(wctx.PoolId, activation, revolvingCounter); + return activation; + } + + void Stop() override { + IdleQueue.Stop(); + } + + private: + enum EPriority { + IdlePriority, // highest (real-time, Config.IdleWorkerPriority) + FastPriority, // normal (real-time, Config.FastWorkerPriority) + SlowPriority, // lowest (not real-time) + }; + + enum EWorkerAction { + // Fast-worker + ExecuteFast, + WaitForSlow, + + // Slow-worker + BecameIdle, + WakeFast, + + // Idle-worker + BecameFast, + Standby, + + // Common + Stopped, + }; + + // Thread-safe; should be called from worker + // Blocks for idle-workers; sets lease and next pool to run + bool SwitchPool(TWorkerContext& wctx) { + TTimerFd* idleTimer = nullptr; + while (true) { + if (DisablePreemptionAndTryExtend(wctx.Lease)) { // if fast-worker + if (Y_UNLIKELY(!Started)) { + SetPriority(0, FastPriority); + Started = true; + } + while (true) { + switch (FastWorkerAction(wctx)) { + case ExecuteFast: + United->SwitchPool(wctx, wctx.Lease.GetPreciseExpireTs() - Config.EventLimitTs); + EnablePreemptionAndGrant(wctx.Lease); + return true; + case WaitForSlow: + FastWorkerSleep(GetCycleCountFast() + Config.SoftLimitTs); + break; + case Stopped: return false; + default: Y_FAIL(); + } + } + } else if (wctx.Lease.IsNeverExpiring()) { // if idle-worker + switch (IdleWorkerAction(idleTimer, wctx.Lease.GetWorkerId())) { + case BecameFast: + SetPriority(0, FastPriority); + break; // try acquire new lease + case Standby: + if (!idleTimer) { + idleTimer = IdleQueue.Enqueue(); } - } - } else if (wctx.Lease.IsNeverExpiring()) { // if idle-worker - switch (IdleWorkerAction(idleTimer, wctx.Lease.GetWorkerId())) { - case BecameFast: - SetPriority(0, FastPriority); - break; // try acquire new lease - case Standby: - if (!idleTimer) { - idleTimer = IdleQueue.Enqueue(); - } - SetPriority(0, IdlePriority); - idleTimer->Wait(); + SetPriority(0, IdlePriority); + idleTimer->Wait(); break; - case Stopped: return false; - default: Y_FAIL(); + case Stopped: return false; + default: Y_FAIL(); } - } else { // lease has expired and hard preemption occured, so we are executing in a slow-worker - wctx.IncrementPreemptedEvents(); - switch (SlowWorkerAction(wctx.PoolId)) { - case WakeFast: - WakeFastWorker(); + } else { // lease has expired and hard preemption occured, so we are executing in a slow-worker + wctx.IncrementPreemptedEvents(); + switch (SlowWorkerAction(wctx.PoolId)) { + case WakeFast: + WakeFastWorker(); [[fallthrough]]; // no break; pass through - case BecameIdle: - wctx.Lease = wctx.Lease.NeverExpire(); - wctx.PoolId = MaxPools; - idleTimer = nullptr; + case BecameIdle: + wctx.Lease = wctx.Lease.NeverExpire(); + wctx.PoolId = MaxPools; + idleTimer = nullptr; break; - case Stopped: return false; - default: Y_FAIL(); + case Stopped: return false; + default: Y_FAIL(); } } - } - } - - enum ETryRunPool { - RunFastPool, - RunSlowPool, - NoTokens, - }; - - ETryRunPool TryRun(TPoolId pool) { - while (true) { - // updates WaitPoolsFlag in SlowPoolsMask according to scheduled pool slowness - TPoolsMask slow = AtomicLoad(&SlowPoolsMask); - if ((1ull << pool) & slow) { // we are about to execute slow pool (fast-worker will just wait, token is NOT required) - if (slow & WaitPoolsFlag) { - return RunSlowPool; // wait flag is already set - } else { - if (AtomicCas(&SlowPoolsMask, slow | WaitPoolsFlag, slow)) { // try set wait flag - return RunSlowPool; // wait flag has been successfully set - } - } - } else { // we are about to execute fast pool, token required - if (slow & WaitPoolsFlag) { // reset wait flag if required - if (AtomicCas(&SlowPoolsMask, slow & ~WaitPoolsFlag, slow)) { // try reset wait flag - return United->TryAcquireToken(pool) ? RunFastPool : NoTokens; // wait flag has been successfully reset - } - } else { - return United->TryAcquireToken(pool) ? RunFastPool : NoTokens; // wait flag is already reset + } + } + + enum ETryRunPool { + RunFastPool, + RunSlowPool, + NoTokens, + }; + + ETryRunPool TryRun(TPoolId pool) { + while (true) { + // updates WaitPoolsFlag in SlowPoolsMask according to scheduled pool slowness + TPoolsMask slow = AtomicLoad(&SlowPoolsMask); + if ((1ull << pool) & slow) { // we are about to execute slow pool (fast-worker will just wait, token is NOT required) + if (slow & WaitPoolsFlag) { + return RunSlowPool; // wait flag is already set + } else { + if (AtomicCas(&SlowPoolsMask, slow | WaitPoolsFlag, slow)) { // try set wait flag + return RunSlowPool; // wait flag has been successfully set + } } - } - } - } - - EWorkerAction FastWorkerAction(TWorkerContext& wctx) { - if (Y_UNLIKELY(United->IsStopped())) { - return Stopped; - } - - // Account current pool - ui64 ts = GetCycleCountFast(); - PoolSched.Account(ts); - - // Select next pool to execute - for (wctx.PoolId = PoolSched.Begin(); wctx.PoolId != PoolSched.End(); wctx.PoolId = PoolSched.Next()) { - switch (TryRun(wctx.PoolId)) { - case RunFastPool: - PoolSched.Scheduled(); - wctx.Lease = PostponePreemption(wctx.Lease.GetWorkerId(), ts); - return ExecuteFast; - case RunSlowPool: - PoolSched.Scheduled(); - ResetPreemption(wctx.Lease.GetWorkerId(), ts); // there is no point in preemption during wait - return WaitForSlow; - case NoTokens: // concurrency limit reached, or no more work in pool - break; // just try next pool (if any) - } - } - - // No more work, no slow-workers -- wait for activations (active, then blocked) - wctx.PoolId = United->Idle(CpuShared, wctx); - - // Wakeup or stop occured - if (Y_UNLIKELY(wctx.PoolId == CpuStopped)) { - return Stopped; - } - ts = GetCycleCountFast(); - PoolSched.ScheduledAfterIdle(wctx.PoolId, ts); - wctx.Lease = PostponePreemption(wctx.Lease.GetWorkerId(), ts); - return ExecuteFast; // United->Idle() has already acquired token - } - - EWorkerAction IdleWorkerAction(TTimerFd* idleTimer, TWorkerId workerId) { - if (Y_UNLIKELY(United->IsStopped())) { - return Stopped; - } - if (!idleTimer) { // either worker start or became idle -- hard preemption is not required - return Standby; - } - - TLease lease = TLease(AtomicLoad(&CurrentLease)); - ui64 ts = GetCycleCountFast(); - if (lease.GetExpireTs() < ts) { // current lease has expired - if (TryBeginHardPreemption(lease)) { - SetPoolIsSlowFlag(PoolSched.CurrentPool()); - TWorkerId preempted = lease.GetWorkerId(); - SetPriority(United->GetWorkerThreadId(preempted), SlowPriority); - LWPROBE(HardPreemption, Config.CpuId, PoolSched.CurrentPool(), preempted, workerId); - EndHardPreemption(workerId); - return BecameFast; - } else { - // Lease has been changed just now, no way we need preemption right now, so no retry needed - return Standby; - } + } else { // we are about to execute fast pool, token required + if (slow & WaitPoolsFlag) { // reset wait flag if required + if (AtomicCas(&SlowPoolsMask, slow & ~WaitPoolsFlag, slow)) { // try reset wait flag + return United->TryAcquireToken(pool) ? RunFastPool : NoTokens; // wait flag has been successfully reset + } + } else { + return United->TryAcquireToken(pool) ? RunFastPool : NoTokens; // wait flag is already reset + } + } + } + } + + EWorkerAction FastWorkerAction(TWorkerContext& wctx) { + if (Y_UNLIKELY(United->IsStopped())) { + return Stopped; + } + + // Account current pool + ui64 ts = GetCycleCountFast(); + PoolSched.Account(ts); + + // Select next pool to execute + for (wctx.PoolId = PoolSched.Begin(); wctx.PoolId != PoolSched.End(); wctx.PoolId = PoolSched.Next()) { + switch (TryRun(wctx.PoolId)) { + case RunFastPool: + PoolSched.Scheduled(); + wctx.Lease = PostponePreemption(wctx.Lease.GetWorkerId(), ts); + return ExecuteFast; + case RunSlowPool: + PoolSched.Scheduled(); + ResetPreemption(wctx.Lease.GetWorkerId(), ts); // there is no point in preemption during wait + return WaitForSlow; + case NoTokens: // concurrency limit reached, or no more work in pool + break; // just try next pool (if any) + } + } + + // No more work, no slow-workers -- wait for activations (active, then blocked) + wctx.PoolId = United->Idle(CpuShared, wctx); + + // Wakeup or stop occured + if (Y_UNLIKELY(wctx.PoolId == CpuStopped)) { + return Stopped; + } + ts = GetCycleCountFast(); + PoolSched.ScheduledAfterIdle(wctx.PoolId, ts); + wctx.Lease = PostponePreemption(wctx.Lease.GetWorkerId(), ts); + return ExecuteFast; // United->Idle() has already acquired token + } + + EWorkerAction IdleWorkerAction(TTimerFd* idleTimer, TWorkerId workerId) { + if (Y_UNLIKELY(United->IsStopped())) { + return Stopped; + } + if (!idleTimer) { // either worker start or became idle -- hard preemption is not required + return Standby; + } + + TLease lease = TLease(AtomicLoad(&CurrentLease)); + ui64 ts = GetCycleCountFast(); + if (lease.GetExpireTs() < ts) { // current lease has expired + if (TryBeginHardPreemption(lease)) { + SetPoolIsSlowFlag(PoolSched.CurrentPool()); + TWorkerId preempted = lease.GetWorkerId(); + SetPriority(United->GetWorkerThreadId(preempted), SlowPriority); + LWPROBE(HardPreemption, Config.CpuId, PoolSched.CurrentPool(), preempted, workerId); + EndHardPreemption(workerId); + return BecameFast; + } else { + // Lease has been changed just now, no way we need preemption right now, so no retry needed + return Standby; + } } else { - // Lease has not expired yet (maybe never expiring lease) - return Standby; - } - } - - EWorkerAction SlowWorkerAction(TPoolId pool) { - if (Y_UNLIKELY(United->IsStopped())) { - return Stopped; - } - while (true) { - TPoolsMask slow = AtomicLoad(&SlowPoolsMask); - if (slow & (1ull << pool)) { - if (slow == (1ull << pool) & WaitPoolsFlag) { // the last slow pool is going to became fast - if (AtomicCas(&SlowPoolsMask, 0, slow)) { // reset both pool-is-slow flag and WaitPoolsFlag - return WakeFast; - } - } else { // there are (a) several slow-worker or (b) one slow-worker w/o waiting fast-worker - if (AtomicCas(&SlowPoolsMask, slow & ~(1ull << pool), slow)) { // reset pool-is-slow flag - return BecameIdle; - } - } - } else { - // SlowWorkerAction has been called between TryBeginHardPreemption and SetPoolIsSlowFlag - // flag for this pool is not set yet, but we can be sure pool is slow: - // - because SlowWorkerAction has been called; - // - this mean lease has expired and hard preemption occured. - // So just wait other worker to call SetPoolIsSlowFlag - LWPROBE(SlowWorkerActionRace, Config.CpuId, pool, slow); + // Lease has not expired yet (maybe never expiring lease) + return Standby; + } + } + + EWorkerAction SlowWorkerAction(TPoolId pool) { + if (Y_UNLIKELY(United->IsStopped())) { + return Stopped; + } + while (true) { + TPoolsMask slow = AtomicLoad(&SlowPoolsMask); + if (slow & (1ull << pool)) { + if (slow == (1ull << pool) & WaitPoolsFlag) { // the last slow pool is going to became fast + if (AtomicCas(&SlowPoolsMask, 0, slow)) { // reset both pool-is-slow flag and WaitPoolsFlag + return WakeFast; + } + } else { // there are (a) several slow-worker or (b) one slow-worker w/o waiting fast-worker + if (AtomicCas(&SlowPoolsMask, slow & ~(1ull << pool), slow)) { // reset pool-is-slow flag + return BecameIdle; + } + } + } else { + // SlowWorkerAction has been called between TryBeginHardPreemption and SetPoolIsSlowFlag + // flag for this pool is not set yet, but we can be sure pool is slow: + // - because SlowWorkerAction has been called; + // - this mean lease has expired and hard preemption occured. + // So just wait other worker to call SetPoolIsSlowFlag + LWPROBE(SlowWorkerActionRace, Config.CpuId, pool, slow); + } + } + } + + void SetPoolIsSlowFlag(TPoolId pool) { + while (true) { + TPoolsMask slow = AtomicLoad(&SlowPoolsMask); + if ((slow & (1ull << pool)) == 0) { // if pool is fast + if (AtomicCas(&SlowPoolsMask, slow | (1ull << pool), slow)) { // set pool-is-slow flag + return; + } + } else { + Y_FAIL("two slow-workers executing the same pool on the same core"); + return; // pool is already slow + } + } + } + + bool TryBeginHardPreemption(TLease lease) { + return AtomicCas(&CurrentLease, HardPreemptionLease, lease); + } + + void EndHardPreemption(TWorkerId to) { + ATOMIC_COMPILER_BARRIER(); + if (!AtomicCas(&CurrentLease, TLease(to, NeverExpire), HardPreemptionLease)) { + Y_FAIL("hard preemption failed"); + } + } + + bool DisablePreemptionAndTryExtend(TLease lease) { + return AtomicCas(&CurrentLease, lease.NeverExpire(), lease); + } + + void EnablePreemptionAndGrant(TLease lease) { + ATOMIC_COMPILER_BARRIER(); + if (!AtomicCas(&CurrentLease, lease, lease.NeverExpire())) { + Y_FAIL("lease grant failed"); + } + } + + void FastWorkerSleep(ui64 deadlineTs) { + while (true) { + TPoolsMask slow = AtomicLoad(&SlowPoolsMask); + if ((slow & WaitPoolsFlag) == 0) { + return; // woken by WakeFast action } - } - } - - void SetPoolIsSlowFlag(TPoolId pool) { - while (true) { - TPoolsMask slow = AtomicLoad(&SlowPoolsMask); - if ((slow & (1ull << pool)) == 0) { // if pool is fast - if (AtomicCas(&SlowPoolsMask, slow | (1ull << pool), slow)) { // set pool-is-slow flag - return; - } - } else { - Y_FAIL("two slow-workers executing the same pool on the same core"); - return; // pool is already slow + ui64 ts = GetCycleCountFast(); + if (deadlineTs <= ts) { + if (AtomicCas(&SlowPoolsMask, slow & ~WaitPoolsFlag, slow)) { // try reset wait flag + return; // wait flag has been successfully reset after timeout + } + } else { // should wait + ui64 timeoutNs = Ts2Ns(deadlineTs - ts); +#ifdef _linux_ + timespec timeout; + timeout.tv_sec = timeoutNs / 1'000'000'000; + timeout.tv_nsec = timeoutNs % 1'000'000'000; + SysFutex(FastWorkerFutex(), FUTEX_WAIT_PRIVATE, FastWorkerFutexValue(slow), &timeout, nullptr, 0); +#else + NanoSleep(timeoutNs); // non-linux wake is not supported, cpu will go idle on slow -> fast switch +#endif } - } - } - - bool TryBeginHardPreemption(TLease lease) { - return AtomicCas(&CurrentLease, HardPreemptionLease, lease); - } - - void EndHardPreemption(TWorkerId to) { - ATOMIC_COMPILER_BARRIER(); - if (!AtomicCas(&CurrentLease, TLease(to, NeverExpire), HardPreemptionLease)) { - Y_FAIL("hard preemption failed"); - } - } - - bool DisablePreemptionAndTryExtend(TLease lease) { - return AtomicCas(&CurrentLease, lease.NeverExpire(), lease); - } - - void EnablePreemptionAndGrant(TLease lease) { - ATOMIC_COMPILER_BARRIER(); - if (!AtomicCas(&CurrentLease, lease, lease.NeverExpire())) { - Y_FAIL("lease grant failed"); - } - } - - void FastWorkerSleep(ui64 deadlineTs) { - while (true) { - TPoolsMask slow = AtomicLoad(&SlowPoolsMask); - if ((slow & WaitPoolsFlag) == 0) { - return; // woken by WakeFast action - } - ui64 ts = GetCycleCountFast(); - if (deadlineTs <= ts) { - if (AtomicCas(&SlowPoolsMask, slow & ~WaitPoolsFlag, slow)) { // try reset wait flag - return; // wait flag has been successfully reset after timeout + } + } + + void WakeFastWorker() { +#ifdef _linux_ + SysFutex(FastWorkerFutex(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); +#endif + } + +#ifdef _linux_ + ui32* FastWorkerFutex() { + // Actually we wait on one highest bit, but futex value size is 4 bytes on all platforms + static_assert(sizeof(TPoolsMask) >= 4, "cannot be used as futex value on linux"); + return (ui32*)&SlowPoolsMask + 1; // higher 32 bits (little endian assumed) + } + + ui32 FastWorkerFutexValue(TPoolsMask slow) { + return ui32(slow >> 32); // higher 32 bits + } +#endif + + void SetPriority(TThreadId tid, EPriority priority) { + if (Config.NoRealtime) { + return; + } +#ifdef _linux_ + int policy; + struct sched_param param; + switch (priority) { + case IdlePriority: + policy = SCHED_FIFO; + param.sched_priority = Config.IdleWorkerPriority; + break; + case FastPriority: + policy = SCHED_FIFO; + param.sched_priority = Config.FastWorkerPriority; + break; + case SlowPriority: + policy = SCHED_OTHER; + param.sched_priority = 0; + break; + } + int ret = sched_setscheduler(tid, policy, ¶m); + switch (ret) { + case 0: return; + case EINVAL: + Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> EINVAL", tid, policy, param.sched_priority); + case EPERM: + // Requirements: + // * CAP_SYS_NICE capability to run real-time processes and set cpu affinity. + // Either run under root or set application capabilities: + // sudo setcap cap_sys_nice=eip BINARY + // * Non-zero rt-runtime (in case cgroups are used). + // Either (a) disable global limit on RT processes bandwidth: + // sudo sysctl -w kernel.sched_rt_runtime_us=-1 + // Or (b) set non-zero rt-runtime for your cgroup: + // echo -1 > /sys/fs/cgroup/cpu/[cgroup]/cpu.rt_runtime_us + // (also set the same value for every parent cgroup) + // https://www.kernel.org/doc/Documentation/scheduler/sched-rt-group.txt + Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> EPERM", tid, policy, param.sched_priority); + case ESRCH: + Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> ESRCH", tid, policy, param.sched_priority); + default: + Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> %d", tid, policy, param.sched_priority, ret); + } +#else + Y_UNUSED(tid); + Y_UNUSED(priority); +#endif + } + + void ResetPreemption(TWorkerId fastWorkerId, ui64 ts) { + if (Y_UNLIKELY(!PreemptionTimer)) { + return; + } + if (FastWorker == fastWorkerId && HardPreemptionTs > 0) { + PreemptionTimer->Reset(); + LWPROBE(ResetPreemptionTimer, Config.CpuId, FastWorker, PreemptionTimer->Fd, Ts2Ms(ts), Ts2Ms(HardPreemptionTs)); + HardPreemptionTs = 0; + } + } + + TLease PostponePreemption(TWorkerId fastWorkerId, ui64 ts) { + // Select new timer after hard preemption + if (FastWorker != fastWorkerId) { + FastWorker = fastWorkerId; + PreemptionTimer = IdleQueue.Dequeue(); + HardPreemptionTs = 0; + } + + ui64 hardPreemptionTs = ts + Config.HardLimitTs; + if (hardPreemptionTs > HardPreemptionTs) { + // Reset timer (at most once in TickIntervalTs, sacrifice precision) + HardPreemptionTs = hardPreemptionTs + Config.LimitPrecisionTs; + PreemptionTimer->Set(HardPreemptionTs); + LWPROBE(SetPreemptionTimer, Config.CpuId, FastWorker, PreemptionTimer->Fd, Ts2Ms(ts), Ts2Ms(HardPreemptionTs)); + } + + return TLease(fastWorkerId, hardPreemptionTs); + } + }; + + // Proxy for start and switching TUnitedExecutorPool-s on single cpu via GetReadyActivation() + // (does not implement any other method in IExecutorPool) + class TCpuExecutorPool: public IExecutorPool { + const TString Name; + + public: + explicit TCpuExecutorPool(const TString& name) + : IExecutorPool(MaxPools) + , Name(name) + {} + + TString GetName() const override { + return Name; + } + + void SetRealTimeMode() const override { + // derived classes controls rt-priority - do nothing + } + + // Should never be called + void ReclaimMailbox(TMailboxType::EType, ui32, TWorkerId, ui64) override { Y_FAIL(); } + void Schedule(TInstant, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_FAIL(); } + void Schedule(TMonotonic, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_FAIL(); } + void Schedule(TDuration, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_FAIL(); } + bool Send(TAutoPtr<IEventHandle>&) override { Y_FAIL(); } + void ScheduleActivation(ui32) override { Y_FAIL(); } + void ScheduleActivationEx(ui32, ui64) override { Y_FAIL(); } + TActorId Register(IActor*, TMailboxType::EType, ui64, const TActorId&) override { Y_FAIL(); } + TActorId Register(IActor*, TMailboxHeader*, ui32, const TActorId&) override { Y_FAIL(); } + void Prepare(TActorSystem*, NSchedulerQueue::TReader**, ui32*) override { Y_FAIL(); } + void Start() override { Y_FAIL(); } + void PrepareStop() override { Y_FAIL(); } + void Shutdown() override { Y_FAIL(); } + bool Cleanup() override { Y_FAIL(); } + }; + + // Proxy executor pool working with cpu-local scheduler (aka actorsystem 2.0) + class TSharedCpuExecutorPool: public TCpuExecutorPool { + TSharedCpu* Local; + TIntrusivePtr<TAffinity> SingleCpuAffinity; // no migration support yet + public: + explicit TSharedCpuExecutorPool(TSharedCpu* local, const TUnitedWorkersConfig& config) + : TCpuExecutorPool("u-" + ToString(local->Config.CpuId)) + , Local(local) + , SingleCpuAffinity(config.NoAffinity ? nullptr : new TAffinity(TCpuMask(local->Config.CpuId))) + {} + + TAffinity* Affinity() const override { + return SingleCpuAffinity.Get(); + } + + ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override { + return Local->GetReadyActivation(wctx, revolvingCounter); + } + }; + + // Proxy executor pool working with balancer and assigned pools (aka actorsystem 1.5) + class TAssignedCpuExecutorPool: public TCpuExecutorPool { + TAssignedCpu* Local; + TIntrusivePtr<TAffinity> CpuAffinity; + public: + explicit TAssignedCpuExecutorPool(TAssignedCpu* local, const TUnitedWorkersConfig& config) + : TCpuExecutorPool("United") + , Local(local) + , CpuAffinity(config.NoAffinity ? nullptr : new TAffinity(config.Allowed)) + {} + + TAffinity* Affinity() const override { + return CpuAffinity.Get(); + } + + ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override { + return Local->GetReadyActivation(wctx, revolvingCounter); + } + }; + + // Representation of a single cpu and it's state visible to other cpus and pools + struct TUnitedWorkers::TCpu: public TNonCopyable { + struct TScopedWaiters { + TCpu& Cpu; + TPool* AssignedPool; // nullptr if CpuShared + + // Subscribe on wakeups from allowed pools + TScopedWaiters(TCpu& cpu, TPool* assignedPool) : Cpu(cpu), AssignedPool(assignedPool) { + if (!AssignedPool) { + for (TPool* pool : Cpu.AllowedPools) { + AtomicIncrement(pool->Waiters); + } + } else { + AtomicIncrement(AssignedPool->Waiters); + } + } + + // Unsubscribe from pools we've subscribed on + ~TScopedWaiters() { + if (!AssignedPool) { + for (TPool* pool : Cpu.AllowedPools) { + AtomicDecrement(pool->Waiters); + } + } else { + AtomicDecrement(AssignedPool->Waiters); + } + } + }; + + // Current cpu state important for other cpus and balancer + TCpuState State; + + // Thread-safe per pool stats + // NOTE: It's guaranteed that cpu never executes two instance of the same pool + TVector<TExecutorThreadStats> PoolStats; + + // Configuration + TCpuId CpuId; + THolder<TCpuLocalManager> LocalManager; + THolder<TCpuExecutorPool> ExecutorPool; + + // Pools allowed to run on this cpu + TStackVec<TPool*, 15> AllowedPools; + + void Stop() { + if (LocalManager) { + State.Stop(); + LocalManager->Stop(); + } + } + + bool StartSpinning(TUnitedWorkers* united, TPool* assignedPool, TPoolId& result) { + // Mark cpu as idle + if (Y_UNLIKELY(!State.StartSpinning())) { + result = CpuStopped; + return true; + } + + // Avoid using multiple atomic seq_cst loads in cycle, use barrier once and relaxed ops + AtomicBarrier(); + + // Check there is no pending tokens (can be released before Waiters increment) + if (!assignedPool) { + for (TPool* pool : AllowedPools) { + if (pool->TryAcquireTokenRelaxed()) { + result = WakeWithTokenAcquired(united, pool->PoolId); + return true; // token acquired or stop } - } else { // should wait - ui64 timeoutNs = Ts2Ns(deadlineTs - ts); -#ifdef _linux_ - timespec timeout; - timeout.tv_sec = timeoutNs / 1'000'000'000; - timeout.tv_nsec = timeoutNs % 1'000'000'000; - SysFutex(FastWorkerFutex(), FUTEX_WAIT_PRIVATE, FastWorkerFutexValue(slow), &timeout, nullptr, 0); -#else - NanoSleep(timeoutNs); // non-linux wake is not supported, cpu will go idle on slow -> fast switch -#endif - } - } - } - - void WakeFastWorker() { -#ifdef _linux_ - SysFutex(FastWorkerFutex(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); -#endif - } - -#ifdef _linux_ - ui32* FastWorkerFutex() { - // Actually we wait on one highest bit, but futex value size is 4 bytes on all platforms - static_assert(sizeof(TPoolsMask) >= 4, "cannot be used as futex value on linux"); - return (ui32*)&SlowPoolsMask + 1; // higher 32 bits (little endian assumed) - } - - ui32 FastWorkerFutexValue(TPoolsMask slow) { - return ui32(slow >> 32); // higher 32 bits - } -#endif - - void SetPriority(TThreadId tid, EPriority priority) { - if (Config.NoRealtime) { - return; - } -#ifdef _linux_ - int policy; - struct sched_param param; - switch (priority) { - case IdlePriority: - policy = SCHED_FIFO; - param.sched_priority = Config.IdleWorkerPriority; - break; - case FastPriority: - policy = SCHED_FIFO; - param.sched_priority = Config.FastWorkerPriority; - break; - case SlowPriority: - policy = SCHED_OTHER; - param.sched_priority = 0; - break; - } - int ret = sched_setscheduler(tid, policy, ¶m); - switch (ret) { - case 0: return; - case EINVAL: - Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> EINVAL", tid, policy, param.sched_priority); - case EPERM: - // Requirements: - // * CAP_SYS_NICE capability to run real-time processes and set cpu affinity. - // Either run under root or set application capabilities: - // sudo setcap cap_sys_nice=eip BINARY - // * Non-zero rt-runtime (in case cgroups are used). - // Either (a) disable global limit on RT processes bandwidth: - // sudo sysctl -w kernel.sched_rt_runtime_us=-1 - // Or (b) set non-zero rt-runtime for your cgroup: - // echo -1 > /sys/fs/cgroup/cpu/[cgroup]/cpu.rt_runtime_us - // (also set the same value for every parent cgroup) - // https://www.kernel.org/doc/Documentation/scheduler/sched-rt-group.txt - Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> EPERM", tid, policy, param.sched_priority); - case ESRCH: - Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> ESRCH", tid, policy, param.sched_priority); - default: - Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> %d", tid, policy, param.sched_priority, ret); - } -#else - Y_UNUSED(tid); - Y_UNUSED(priority); -#endif - } - - void ResetPreemption(TWorkerId fastWorkerId, ui64 ts) { - if (Y_UNLIKELY(!PreemptionTimer)) { - return; - } - if (FastWorker == fastWorkerId && HardPreemptionTs > 0) { - PreemptionTimer->Reset(); - LWPROBE(ResetPreemptionTimer, Config.CpuId, FastWorker, PreemptionTimer->Fd, Ts2Ms(ts), Ts2Ms(HardPreemptionTs)); - HardPreemptionTs = 0; - } - } - - TLease PostponePreemption(TWorkerId fastWorkerId, ui64 ts) { - // Select new timer after hard preemption - if (FastWorker != fastWorkerId) { - FastWorker = fastWorkerId; - PreemptionTimer = IdleQueue.Dequeue(); - HardPreemptionTs = 0; - } - - ui64 hardPreemptionTs = ts + Config.HardLimitTs; - if (hardPreemptionTs > HardPreemptionTs) { - // Reset timer (at most once in TickIntervalTs, sacrifice precision) - HardPreemptionTs = hardPreemptionTs + Config.LimitPrecisionTs; - PreemptionTimer->Set(HardPreemptionTs); - LWPROBE(SetPreemptionTimer, Config.CpuId, FastWorker, PreemptionTimer->Fd, Ts2Ms(ts), Ts2Ms(HardPreemptionTs)); - } - - return TLease(fastWorkerId, hardPreemptionTs); - } - }; - - // Proxy for start and switching TUnitedExecutorPool-s on single cpu via GetReadyActivation() - // (does not implement any other method in IExecutorPool) - class TCpuExecutorPool: public IExecutorPool { - const TString Name; - - public: - explicit TCpuExecutorPool(const TString& name) - : IExecutorPool(MaxPools) - , Name(name) - {} - - TString GetName() const override { - return Name; - } - - void SetRealTimeMode() const override { - // derived classes controls rt-priority - do nothing - } - - // Should never be called - void ReclaimMailbox(TMailboxType::EType, ui32, TWorkerId, ui64) override { Y_FAIL(); } - void Schedule(TInstant, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_FAIL(); } - void Schedule(TMonotonic, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_FAIL(); } - void Schedule(TDuration, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_FAIL(); } - bool Send(TAutoPtr<IEventHandle>&) override { Y_FAIL(); } - void ScheduleActivation(ui32) override { Y_FAIL(); } - void ScheduleActivationEx(ui32, ui64) override { Y_FAIL(); } - TActorId Register(IActor*, TMailboxType::EType, ui64, const TActorId&) override { Y_FAIL(); } - TActorId Register(IActor*, TMailboxHeader*, ui32, const TActorId&) override { Y_FAIL(); } - void Prepare(TActorSystem*, NSchedulerQueue::TReader**, ui32*) override { Y_FAIL(); } - void Start() override { Y_FAIL(); } - void PrepareStop() override { Y_FAIL(); } - void Shutdown() override { Y_FAIL(); } - bool Cleanup() override { Y_FAIL(); } - }; - - // Proxy executor pool working with cpu-local scheduler (aka actorsystem 2.0) - class TSharedCpuExecutorPool: public TCpuExecutorPool { - TSharedCpu* Local; - TIntrusivePtr<TAffinity> SingleCpuAffinity; // no migration support yet - public: - explicit TSharedCpuExecutorPool(TSharedCpu* local, const TUnitedWorkersConfig& config) - : TCpuExecutorPool("u-" + ToString(local->Config.CpuId)) - , Local(local) - , SingleCpuAffinity(config.NoAffinity ? nullptr : new TAffinity(TCpuMask(local->Config.CpuId))) - {} - - TAffinity* Affinity() const override { - return SingleCpuAffinity.Get(); - } - - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override { - return Local->GetReadyActivation(wctx, revolvingCounter); - } - }; - - // Proxy executor pool working with balancer and assigned pools (aka actorsystem 1.5) - class TAssignedCpuExecutorPool: public TCpuExecutorPool { - TAssignedCpu* Local; - TIntrusivePtr<TAffinity> CpuAffinity; - public: - explicit TAssignedCpuExecutorPool(TAssignedCpu* local, const TUnitedWorkersConfig& config) - : TCpuExecutorPool("United") - , Local(local) - , CpuAffinity(config.NoAffinity ? nullptr : new TAffinity(config.Allowed)) - {} - - TAffinity* Affinity() const override { - return CpuAffinity.Get(); - } - - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override { - return Local->GetReadyActivation(wctx, revolvingCounter); - } - }; - - // Representation of a single cpu and it's state visible to other cpus and pools - struct TUnitedWorkers::TCpu: public TNonCopyable { - struct TScopedWaiters { - TCpu& Cpu; - TPool* AssignedPool; // nullptr if CpuShared - - // Subscribe on wakeups from allowed pools - TScopedWaiters(TCpu& cpu, TPool* assignedPool) : Cpu(cpu), AssignedPool(assignedPool) { - if (!AssignedPool) { - for (TPool* pool : Cpu.AllowedPools) { - AtomicIncrement(pool->Waiters); + } + } else { + if (assignedPool->TryAcquireTokenRelaxed()) { + result = WakeWithTokenAcquired(united, assignedPool->PoolId); + return true; // token acquired or stop + } + } + + // At this point we can be sure wakeup won't be lost + // So we can actively spin or block w/o checking for pending tokens + return false; + } + + bool ActiveWait(ui64 spinThresholdTs, TPoolId& result) { + ui64 deadline = GetCycleCountFast() + spinThresholdTs; + while (GetCycleCountFast() < deadline) { + for (ui32 i = 0; i < 12; ++i) { + TPoolId current = State.CurrentPool(); + if (current == CpuSpinning) { + SpinLockPause(); + } else { + result = current; + return true; // wakeup } - } else { - AtomicIncrement(AssignedPool->Waiters); - } - } - - // Unsubscribe from pools we've subscribed on - ~TScopedWaiters() { - if (!AssignedPool) { - for (TPool* pool : Cpu.AllowedPools) { - AtomicDecrement(pool->Waiters); - } - } else { - AtomicDecrement(AssignedPool->Waiters); - } - } - }; - - // Current cpu state important for other cpus and balancer - TCpuState State; - - // Thread-safe per pool stats - // NOTE: It's guaranteed that cpu never executes two instance of the same pool - TVector<TExecutorThreadStats> PoolStats; - - // Configuration - TCpuId CpuId; - THolder<TCpuLocalManager> LocalManager; - THolder<TCpuExecutorPool> ExecutorPool; - - // Pools allowed to run on this cpu - TStackVec<TPool*, 15> AllowedPools; - - void Stop() { - if (LocalManager) { - State.Stop(); - LocalManager->Stop(); - } - } - - bool StartSpinning(TUnitedWorkers* united, TPool* assignedPool, TPoolId& result) { - // Mark cpu as idle - if (Y_UNLIKELY(!State.StartSpinning())) { - result = CpuStopped; - return true; - } - - // Avoid using multiple atomic seq_cst loads in cycle, use barrier once and relaxed ops - AtomicBarrier(); - - // Check there is no pending tokens (can be released before Waiters increment) - if (!assignedPool) { - for (TPool* pool : AllowedPools) { - if (pool->TryAcquireTokenRelaxed()) { - result = WakeWithTokenAcquired(united, pool->PoolId); - return true; // token acquired or stop - } - } - } else { - if (assignedPool->TryAcquireTokenRelaxed()) { - result = WakeWithTokenAcquired(united, assignedPool->PoolId); - return true; // token acquired or stop - } - } - - // At this point we can be sure wakeup won't be lost - // So we can actively spin or block w/o checking for pending tokens - return false; - } - - bool ActiveWait(ui64 spinThresholdTs, TPoolId& result) { - ui64 deadline = GetCycleCountFast() + spinThresholdTs; - while (GetCycleCountFast() < deadline) { - for (ui32 i = 0; i < 12; ++i) { - TPoolId current = State.CurrentPool(); - if (current == CpuSpinning) { - SpinLockPause(); - } else { - result = current; - return true; // wakeup - } - } - } - return false; // spin threshold exceeded, no wakeups - } - - bool StartBlocking(TPoolId& result) { - // Switch into blocked state - if (State.StartBlocking()) { - result = State.CurrentPool(); - return true; - } else { - return false; - } - } - - bool BlockedWait(TPoolId& result, ui64 timeoutNs) { - return State.Block(timeoutNs, result); - } - - void SwitchPool(TPoolId pool) { - return State.SwitchPool(pool); - } - - private: - TPoolId WakeWithTokenAcquired(TUnitedWorkers* united, TPoolId token) { - switch (State.WakeWithTokenAcquired(token)) { - case TCpuState::Woken: // we've got token and successfully woken up this cpu - // NOTE: sending thread may also wakeup another worker, which wont be able to acquire token and will go idle (it's ok) - return token; - case TCpuState::NotIdle: { // wakeup event has also occured - TPoolId wakeup = State.CurrentPool(); - if (wakeup != token) { // token and wakeup for different pools - united->TryWake(wakeup); // rewake another cpu to avoid losing wakeup - } - return token; - } - case TCpuState::Forbidden: - Y_FAIL(); - case TCpuState::Stopped: - return CpuStopped; - } - } - }; - - TUnitedWorkers::TUnitedWorkers( - const TUnitedWorkersConfig& config, - const TVector<TUnitedExecutorPoolConfig>& unitedPools, - const TCpuAllocationConfig& allocation, - IBalancer* balancer) - : Balancer(balancer) - , Config(config) - , Allocation(allocation) - { - // Find max pool id and initialize pools - PoolCount = 0; - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - for (const auto& pa : cpuAlloc.AllowedPools) { - PoolCount = Max<size_t>(PoolCount, pa.PoolId + 1); - } - } - Pools.Reset(new TPool[PoolCount]); - - // Find max cpu id and initialize cpus - CpuCount = 0; - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - CpuCount = Max<size_t>(CpuCount, cpuAlloc.CpuId + 1); - } - Cpus.Reset(new TCpu[CpuCount]); - - // Setup allocated cpus - // NOTE: leave gaps for not allocated cpus (default-initialized) - WorkerCount = 0; - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - TCpu& cpu = Cpus[cpuAlloc.CpuId]; - cpu.CpuId = cpuAlloc.CpuId; - cpu.PoolStats.resize(PoolCount); // NOTE: also may have gaps - for (const auto& pa : cpuAlloc.AllowedPools) { - cpu.AllowedPools.emplace_back(&Pools[pa.PoolId]); - } - - // Setup balancing and cpu-local manager - if (!Balancer->AddCpu(cpuAlloc, &cpu.State)) { - cpu.State.SwitchPool(0); // set initial state to non-idle to avoid losing wakeups on start - cpu.State.AssignPool(CpuShared); - TSharedCpu* local = new TSharedCpu(TSharedCpu::TConfig(cpuAlloc, Config), this); - cpu.LocalManager.Reset(local); - cpu.ExecutorPool.Reset(new TSharedCpuExecutorPool(local, Config)); - } else { - TAssignedCpu* local = new TAssignedCpu(this); - cpu.LocalManager.Reset(local); - cpu.ExecutorPool.Reset(new TAssignedCpuExecutorPool(local, Config)); - } - WorkerCount += cpu.LocalManager->WorkerCount(); - } - - // Initialize workers - Workers.Reset(new TWorker[WorkerCount]); - - // Setup pools - // NOTE: leave gaps for not united pools (default-initialized) - for (const TUnitedExecutorPoolConfig& cfg : unitedPools) { - TPool& pool = Pools[cfg.PoolId]; - Y_VERIFY(cfg.PoolId < MaxPools); - pool.PoolId = cfg.PoolId; - pool.Concurrency = cfg.Concurrency ? cfg.Concurrency : Config.CpuCount; - pool.ExecutorPool = nullptr; // should be set later using SetupPool() - pool.MailboxTable = nullptr; // should be set later using SetupPool() - pool.TimePerMailboxTs = DurationToCycles(cfg.TimePerMailbox); - pool.EventsPerMailbox = cfg.EventsPerMailbox; - - // Reinitialize per cpu pool stats with right MaxActivityType - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - TCpu& cpu = Cpus[cpuAlloc.CpuId]; - cpu.PoolStats[cfg.PoolId] = TExecutorThreadStats(cfg.MaxActivityType); - } - - // Setup WakeOrderCpus: left to right exclusive cpus, then left to right shared cpus. - // Waking exclusive cpus first reduce load on shared cpu and improve latency isolation, which is - // the point of using exclusive cpu. But note that number of actively spinning idle cpus may increase, - // so cpu consumption on light load is higher. - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - TCpu& cpu = Cpus[cpuAlloc.CpuId]; - if (cpu.AllowedPools.size() == 1 && cpu.AllowedPools[0] == &pool) { - pool.WakeOrderCpus.emplace_back(&cpu); - } - } - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - TCpu& cpu = Cpus[cpuAlloc.CpuId]; - if (cpu.AllowedPools.size() > 1 && cpuAlloc.HasPool(pool.PoolId)) { - pool.WakeOrderCpus.emplace_back(&cpu); - } - } - } - } - - TUnitedWorkers::~TUnitedWorkers() { - } - - void TUnitedWorkers::Prepare(TActorSystem* actorSystem, TVector<NSchedulerQueue::TReader*>& scheduleReaders) { - // Setup allocated cpus - // NOTE: leave gaps for not allocated cpus (default-initialized) - TWorkerId workers = 0; - for (TCpuId cpuId = 0; cpuId < CpuCount; cpuId++) { - TCpu& cpu = Cpus[cpuId]; - - // Setup cpu-local workers - if (cpu.LocalManager) { - for (size_t i = 0; i < cpu.LocalManager->WorkerCount(); i++) { - TWorkerId workerId = workers++; - cpu.LocalManager->AddWorker(workerId); - - // Setup worker - Y_VERIFY(workerId < WorkerCount); - Workers[workerId].Thread.Reset(new TExecutorThread( - workerId, - cpu.CpuId, - actorSystem, - cpu.ExecutorPool.Get(), // use cpu-local manager as proxy executor for all workers on cpu - nullptr, // MailboxTable is pool-specific, will be set on pool switch - cpu.ExecutorPool->GetName())); - // NOTE: TWorker::ThreadId will be initialized after in Start() - - scheduleReaders.push_back(&Workers[workerId].SchedulerQueue.Reader); - } - } - } - } - - void TUnitedWorkers::Start() { - for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { - Workers[workerId].Thread->Start(); - } - for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { - AtomicStore(&Workers[workerId].ThreadId, Workers[workerId].Thread->GetThreadId()); - } + } + } + return false; // spin threshold exceeded, no wakeups + } + + bool StartBlocking(TPoolId& result) { + // Switch into blocked state + if (State.StartBlocking()) { + result = State.CurrentPool(); + return true; + } else { + return false; + } + } + + bool BlockedWait(TPoolId& result, ui64 timeoutNs) { + return State.Block(timeoutNs, result); + } + + void SwitchPool(TPoolId pool) { + return State.SwitchPool(pool); + } + + private: + TPoolId WakeWithTokenAcquired(TUnitedWorkers* united, TPoolId token) { + switch (State.WakeWithTokenAcquired(token)) { + case TCpuState::Woken: // we've got token and successfully woken up this cpu + // NOTE: sending thread may also wakeup another worker, which wont be able to acquire token and will go idle (it's ok) + return token; + case TCpuState::NotIdle: { // wakeup event has also occured + TPoolId wakeup = State.CurrentPool(); + if (wakeup != token) { // token and wakeup for different pools + united->TryWake(wakeup); // rewake another cpu to avoid losing wakeup + } + return token; + } + case TCpuState::Forbidden: + Y_FAIL(); + case TCpuState::Stopped: + return CpuStopped; + } + } + }; + + TUnitedWorkers::TUnitedWorkers( + const TUnitedWorkersConfig& config, + const TVector<TUnitedExecutorPoolConfig>& unitedPools, + const TCpuAllocationConfig& allocation, + IBalancer* balancer) + : Balancer(balancer) + , Config(config) + , Allocation(allocation) + { + // Find max pool id and initialize pools + PoolCount = 0; + for (const TCpuAllocation& cpuAlloc : allocation.Items) { + for (const auto& pa : cpuAlloc.AllowedPools) { + PoolCount = Max<size_t>(PoolCount, pa.PoolId + 1); + } + } + Pools.Reset(new TPool[PoolCount]); + + // Find max cpu id and initialize cpus + CpuCount = 0; + for (const TCpuAllocation& cpuAlloc : allocation.Items) { + CpuCount = Max<size_t>(CpuCount, cpuAlloc.CpuId + 1); + } + Cpus.Reset(new TCpu[CpuCount]); + + // Setup allocated cpus + // NOTE: leave gaps for not allocated cpus (default-initialized) + WorkerCount = 0; + for (const TCpuAllocation& cpuAlloc : allocation.Items) { + TCpu& cpu = Cpus[cpuAlloc.CpuId]; + cpu.CpuId = cpuAlloc.CpuId; + cpu.PoolStats.resize(PoolCount); // NOTE: also may have gaps + for (const auto& pa : cpuAlloc.AllowedPools) { + cpu.AllowedPools.emplace_back(&Pools[pa.PoolId]); + } + + // Setup balancing and cpu-local manager + if (!Balancer->AddCpu(cpuAlloc, &cpu.State)) { + cpu.State.SwitchPool(0); // set initial state to non-idle to avoid losing wakeups on start + cpu.State.AssignPool(CpuShared); + TSharedCpu* local = new TSharedCpu(TSharedCpu::TConfig(cpuAlloc, Config), this); + cpu.LocalManager.Reset(local); + cpu.ExecutorPool.Reset(new TSharedCpuExecutorPool(local, Config)); + } else { + TAssignedCpu* local = new TAssignedCpu(this); + cpu.LocalManager.Reset(local); + cpu.ExecutorPool.Reset(new TAssignedCpuExecutorPool(local, Config)); + } + WorkerCount += cpu.LocalManager->WorkerCount(); + } + + // Initialize workers + Workers.Reset(new TWorker[WorkerCount]); + + // Setup pools + // NOTE: leave gaps for not united pools (default-initialized) + for (const TUnitedExecutorPoolConfig& cfg : unitedPools) { + TPool& pool = Pools[cfg.PoolId]; + Y_VERIFY(cfg.PoolId < MaxPools); + pool.PoolId = cfg.PoolId; + pool.Concurrency = cfg.Concurrency ? cfg.Concurrency : Config.CpuCount; + pool.ExecutorPool = nullptr; // should be set later using SetupPool() + pool.MailboxTable = nullptr; // should be set later using SetupPool() + pool.TimePerMailboxTs = DurationToCycles(cfg.TimePerMailbox); + pool.EventsPerMailbox = cfg.EventsPerMailbox; + + // Reinitialize per cpu pool stats with right MaxActivityType + for (const TCpuAllocation& cpuAlloc : allocation.Items) { + TCpu& cpu = Cpus[cpuAlloc.CpuId]; + cpu.PoolStats[cfg.PoolId] = TExecutorThreadStats(cfg.MaxActivityType); + } + + // Setup WakeOrderCpus: left to right exclusive cpus, then left to right shared cpus. + // Waking exclusive cpus first reduce load on shared cpu and improve latency isolation, which is + // the point of using exclusive cpu. But note that number of actively spinning idle cpus may increase, + // so cpu consumption on light load is higher. + for (const TCpuAllocation& cpuAlloc : allocation.Items) { + TCpu& cpu = Cpus[cpuAlloc.CpuId]; + if (cpu.AllowedPools.size() == 1 && cpu.AllowedPools[0] == &pool) { + pool.WakeOrderCpus.emplace_back(&cpu); + } + } + for (const TCpuAllocation& cpuAlloc : allocation.Items) { + TCpu& cpu = Cpus[cpuAlloc.CpuId]; + if (cpu.AllowedPools.size() > 1 && cpuAlloc.HasPool(pool.PoolId)) { + pool.WakeOrderCpus.emplace_back(&cpu); + } + } + } } - inline TThreadId TUnitedWorkers::GetWorkerThreadId(TWorkerId workerId) const { - volatile TThreadId* threadId = &Workers[workerId].ThreadId; -#ifdef _linux_ - while (AtomicLoad(threadId) == UnknownThreadId) { - NanoSleep(1000); + TUnitedWorkers::~TUnitedWorkers() { + } + + void TUnitedWorkers::Prepare(TActorSystem* actorSystem, TVector<NSchedulerQueue::TReader*>& scheduleReaders) { + // Setup allocated cpus + // NOTE: leave gaps for not allocated cpus (default-initialized) + TWorkerId workers = 0; + for (TCpuId cpuId = 0; cpuId < CpuCount; cpuId++) { + TCpu& cpu = Cpus[cpuId]; + + // Setup cpu-local workers + if (cpu.LocalManager) { + for (size_t i = 0; i < cpu.LocalManager->WorkerCount(); i++) { + TWorkerId workerId = workers++; + cpu.LocalManager->AddWorker(workerId); + + // Setup worker + Y_VERIFY(workerId < WorkerCount); + Workers[workerId].Thread.Reset(new TExecutorThread( + workerId, + cpu.CpuId, + actorSystem, + cpu.ExecutorPool.Get(), // use cpu-local manager as proxy executor for all workers on cpu + nullptr, // MailboxTable is pool-specific, will be set on pool switch + cpu.ExecutorPool->GetName())); + // NOTE: TWorker::ThreadId will be initialized after in Start() + + scheduleReaders.push_back(&Workers[workerId].SchedulerQueue.Reader); + } + } } -#endif - return AtomicLoad(threadId); - } - - inline NSchedulerQueue::TWriter* TUnitedWorkers::GetScheduleWriter(TWorkerId workerId) const { - return &Workers[workerId].SchedulerQueue.Writer; - } - - void TUnitedWorkers::SetupPool(TPoolId pool, IExecutorPool* executorPool, TMailboxTable* mailboxTable) { - Pools[pool].ExecutorPool = executorPool; - Pools[pool].MailboxTable = mailboxTable; } - void TUnitedWorkers::PrepareStop() { + void TUnitedWorkers::Start() { + for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { + Workers[workerId].Thread->Start(); + } + for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { + AtomicStore(&Workers[workerId].ThreadId, Workers[workerId].Thread->GetThreadId()); + } + } + + inline TThreadId TUnitedWorkers::GetWorkerThreadId(TWorkerId workerId) const { + volatile TThreadId* threadId = &Workers[workerId].ThreadId; +#ifdef _linux_ + while (AtomicLoad(threadId) == UnknownThreadId) { + NanoSleep(1000); + } +#endif + return AtomicLoad(threadId); + } + + inline NSchedulerQueue::TWriter* TUnitedWorkers::GetScheduleWriter(TWorkerId workerId) const { + return &Workers[workerId].SchedulerQueue.Writer; + } + + void TUnitedWorkers::SetupPool(TPoolId pool, IExecutorPool* executorPool, TMailboxTable* mailboxTable) { + Pools[pool].ExecutorPool = executorPool; + Pools[pool].MailboxTable = mailboxTable; + } + + void TUnitedWorkers::PrepareStop() { AtomicStore(&StopFlag, true); - for (TPoolId pool = 0; pool < PoolCount; pool++) { - Pools[pool].Stop(); - } - for (TCpuId cpuId = 0; cpuId < CpuCount; cpuId++) { - Cpus[cpuId].Stop(); - } - } - - void TUnitedWorkers::Shutdown() { - for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { - Workers[workerId].Thread->Join(); - } - } - - inline void TUnitedWorkers::PushActivation(TPoolId pool, ui32 activation, ui64 revolvingCounter) { - if (Pools[pool].PushActivation(activation, revolvingCounter)) { // token generated - TryWake(pool); + for (TPoolId pool = 0; pool < PoolCount; pool++) { + Pools[pool].Stop(); } + for (TCpuId cpuId = 0; cpuId < CpuCount; cpuId++) { + Cpus[cpuId].Stop(); + } } - inline bool TUnitedWorkers::TryAcquireToken(TPoolId pool) { - return Pools[pool].TryAcquireToken(); + void TUnitedWorkers::Shutdown() { + for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { + Workers[workerId].Thread->Join(); + } } - inline void TUnitedWorkers::TryWake(TPoolId pool) { - // Avoid using multiple atomic seq_cst loads in cycle, use barrier once - AtomicBarrier(); - - // Scan every allowed cpu in pool's wakeup order and try to wake the first idle cpu - if (RelaxedLoad(&Pools[pool].Waiters) > 0) { - for (TCpu* cpu : Pools[pool].WakeOrderCpus) { - if (cpu->State.WakeWithoutToken(pool) == TCpuState::Woken) { - return; // successful wake up - } - } - } + inline void TUnitedWorkers::PushActivation(TPoolId pool, ui32 activation, ui64 revolvingCounter) { + if (Pools[pool].PushActivation(activation, revolvingCounter)) { // token generated + TryWake(pool); + } + } - // Cpu has not been woken up + inline bool TUnitedWorkers::TryAcquireToken(TPoolId pool) { + return Pools[pool].TryAcquireToken(); } - inline void TUnitedWorkers::BeginExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter) { - Pools[pool].BeginExecution(activation, revolvingCounter); + inline void TUnitedWorkers::TryWake(TPoolId pool) { + // Avoid using multiple atomic seq_cst loads in cycle, use barrier once + AtomicBarrier(); + + // Scan every allowed cpu in pool's wakeup order and try to wake the first idle cpu + if (RelaxedLoad(&Pools[pool].Waiters) > 0) { + for (TCpu* cpu : Pools[pool].WakeOrderCpus) { + if (cpu->State.WakeWithoutToken(pool) == TCpuState::Woken) { + return; // successful wake up + } + } + } + + // Cpu has not been woken up + } + + inline void TUnitedWorkers::BeginExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter) { + Pools[pool].BeginExecution(activation, revolvingCounter); } - inline bool TUnitedWorkers::NextExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter) { - return Pools[pool].NextExecution(activation, revolvingCounter); - } + inline bool TUnitedWorkers::NextExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter) { + return Pools[pool].NextExecution(activation, revolvingCounter); + } - inline void TUnitedWorkers::StopExecution(TPoolId pool) { - if (Pools[pool].StopExecution()) { // pending token - TryWake(pool); - } + inline void TUnitedWorkers::StopExecution(TPoolId pool) { + if (Pools[pool].StopExecution()) { // pending token + TryWake(pool); + } } - inline void TUnitedWorkers::Balance() { - ui64 ts = GetCycleCountFast(); - if (Balancer->TryLock(ts)) { - for (TPoolId pool = 0; pool < PoolCount; pool++) { - if (Pools[pool].IsUnited()) { - ui64 ElapsedTs = 0; - ui64 ParkedTs = 0; - for (TCpu* cpu : Pools[pool].WakeOrderCpus) { - const TExecutorThreadStats& cpuStats = cpu->PoolStats[pool]; - ElapsedTs += cpuStats.ElapsedTicks; - ParkedTs += cpuStats.ParkedTicks; - } - TBalancerStats stats; - stats.Ts = ts; - stats.CpuUs = Ts2Us(ElapsedTs); - stats.IdleUs = Ts2Us(ParkedTs); - Balancer->SetPoolStats(pool, stats); - } - } - Balancer->Balance(); - Balancer->Unlock(); - } + inline void TUnitedWorkers::Balance() { + ui64 ts = GetCycleCountFast(); + if (Balancer->TryLock(ts)) { + for (TPoolId pool = 0; pool < PoolCount; pool++) { + if (Pools[pool].IsUnited()) { + ui64 ElapsedTs = 0; + ui64 ParkedTs = 0; + for (TCpu* cpu : Pools[pool].WakeOrderCpus) { + const TExecutorThreadStats& cpuStats = cpu->PoolStats[pool]; + ElapsedTs += cpuStats.ElapsedTicks; + ParkedTs += cpuStats.ParkedTicks; + } + TBalancerStats stats; + stats.Ts = ts; + stats.CpuUs = Ts2Us(ElapsedTs); + stats.IdleUs = Ts2Us(ParkedTs); + Balancer->SetPoolStats(pool, stats); + } + } + Balancer->Balance(); + Balancer->Unlock(); + } + } + + inline TPoolId TUnitedWorkers::AssignedPool(TWorkerContext& wctx) { + return Cpus[wctx.CpuId].State.AssignedPool(); + } + + inline bool TUnitedWorkers::IsPoolReassigned(TWorkerContext& wctx) { + return Cpus[wctx.CpuId].State.IsPoolReassigned(wctx.PoolId); + } + + inline void TUnitedWorkers::SwitchPool(TWorkerContext& wctx, ui64 softDeadlineTs) { + Pools[wctx.PoolId].Switch(wctx, softDeadlineTs, Cpus[wctx.CpuId].PoolStats[wctx.PoolId]); + Cpus[wctx.CpuId].SwitchPool(wctx.PoolId); + } + + TPoolId TUnitedWorkers::Idle(TPoolId assigned, TWorkerContext& wctx) { + wctx.SwitchToIdle(); + + TPoolId result; + TTimeTracker timeTracker; + TCpu& cpu = Cpus[wctx.CpuId]; + TPool* assignedPool = assigned == CpuShared ? nullptr : &Pools[assigned]; + TCpu::TScopedWaiters scopedWaiters(cpu, assignedPool); + while (true) { + if (cpu.StartSpinning(this, assignedPool, result)) { + break; // token already acquired (or stop) + } + result = WaitSequence(cpu, wctx, timeTracker); + if (Y_UNLIKELY(result == CpuStopped) || TryAcquireToken(result)) { + break; // token acquired (or stop) + } + } + + wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed()); + return result; } - inline TPoolId TUnitedWorkers::AssignedPool(TWorkerContext& wctx) { - return Cpus[wctx.CpuId].State.AssignedPool(); + TPoolId TUnitedWorkers::WaitSequence(TCpu& cpu, TWorkerContext& wctx, TTimeTracker& timeTracker) { + TPoolId result; + if (cpu.ActiveWait(Us2Ts(Config.SpinThresholdUs), result)) { + wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed()); + return result; + } + if (cpu.StartBlocking(result)) { + wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed()); + return result; + } + wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed()); + bool wakeup; + do { + wakeup = cpu.BlockedWait(result, Config.Balancer.PeriodUs * 1000); + wctx.AddParkedCycles(timeTracker.Elapsed()); + } while (!wakeup); + return result; } - inline bool TUnitedWorkers::IsPoolReassigned(TWorkerContext& wctx) { - return Cpus[wctx.CpuId].State.IsPoolReassigned(wctx.PoolId); - } - - inline void TUnitedWorkers::SwitchPool(TWorkerContext& wctx, ui64 softDeadlineTs) { - Pools[wctx.PoolId].Switch(wctx, softDeadlineTs, Cpus[wctx.CpuId].PoolStats[wctx.PoolId]); - Cpus[wctx.CpuId].SwitchPool(wctx.PoolId); - } - - TPoolId TUnitedWorkers::Idle(TPoolId assigned, TWorkerContext& wctx) { - wctx.SwitchToIdle(); - - TPoolId result; - TTimeTracker timeTracker; - TCpu& cpu = Cpus[wctx.CpuId]; - TPool* assignedPool = assigned == CpuShared ? nullptr : &Pools[assigned]; - TCpu::TScopedWaiters scopedWaiters(cpu, assignedPool); - while (true) { - if (cpu.StartSpinning(this, assignedPool, result)) { - break; // token already acquired (or stop) - } - result = WaitSequence(cpu, wctx, timeTracker); - if (Y_UNLIKELY(result == CpuStopped) || TryAcquireToken(result)) { - break; // token acquired (or stop) - } - } - - wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed()); - return result; - } - - TPoolId TUnitedWorkers::WaitSequence(TCpu& cpu, TWorkerContext& wctx, TTimeTracker& timeTracker) { - TPoolId result; - if (cpu.ActiveWait(Us2Ts(Config.SpinThresholdUs), result)) { - wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed()); - return result; - } - if (cpu.StartBlocking(result)) { - wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed()); - return result; - } - wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed()); - bool wakeup; - do { - wakeup = cpu.BlockedWait(result, Config.Balancer.PeriodUs * 1000); - wctx.AddParkedCycles(timeTracker.Elapsed()); - } while (!wakeup); - return result; - } - - void TUnitedWorkers::GetCurrentStats(TPoolId pool, TVector<TExecutorThreadStats>& statsCopy) const { - size_t idx = 1; - statsCopy.resize(idx + Pools[pool].WakeOrderCpus.size()); - for (TCpu* cpu : Pools[pool].WakeOrderCpus) { - TExecutorThreadStats& s = statsCopy[idx++]; - s = TExecutorThreadStats(); - s.Aggregate(cpu->PoolStats[pool]); - } - } - - TUnitedExecutorPool::TUnitedExecutorPool(const TUnitedExecutorPoolConfig& cfg, TUnitedWorkers* united) - : TExecutorPoolBaseMailboxed(cfg.PoolId, cfg.MaxActivityType) - , United(united) - , PoolName(cfg.PoolName) - { - United->SetupPool(TPoolId(cfg.PoolId), this, MailboxTable.Get()); - } - - void TUnitedExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { - ActorSystem = actorSystem; - - // Schedule readers are initialized through TUnitedWorkers::Prepare - *scheduleReaders = nullptr; - *scheduleSz = 0; - } - - void TUnitedExecutorPool::Start() { - // workers are actually started in TUnitedWorkers::Start() - } - - void TUnitedExecutorPool::PrepareStop() { - } - - void TUnitedExecutorPool::Shutdown() { - // workers are actually joined in TUnitedWorkers::Shutdown() - } - - TAffinity* TUnitedExecutorPool::Affinity() const { - Y_FAIL(); // should never be called, TCpuExecutorPool is used instead - } - - ui32 TUnitedExecutorPool::GetThreads() const { - return 0; - } - - ui32 TUnitedExecutorPool::GetReadyActivation(TWorkerContext&, ui64) { - Y_FAIL(); // should never be called, TCpu*ExecutorPool is used instead - } - - inline void TUnitedExecutorPool::ScheduleActivation(ui32 activation) { - TUnitedExecutorPool::ScheduleActivationEx(activation, AtomicIncrement(ActivationsRevolvingCounter)); - } - - inline void TUnitedExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) { - United->PushActivation(PoolId, activation, revolvingCounter); - } - - void TUnitedExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - TUnitedExecutorPool::Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); - } - - void TUnitedExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_VERIFY_DEBUG(workerId < United->GetWorkerCount()); - const auto current = ActorSystem->Monotonic(); - if (deadline < current) { - deadline = current; - } - United->GetScheduleWriter(workerId)->Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - - void TUnitedExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_VERIFY_DEBUG(workerId < United->GetWorkerCount()); - const auto deadline = ActorSystem->Monotonic() + delta; - United->GetScheduleWriter(workerId)->Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - - void TUnitedExecutorPool::GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - Y_UNUSED(poolStats); - if (statsCopy.empty()) { - statsCopy.resize(1); - } - statsCopy[0] = TExecutorThreadStats(); - statsCopy[0].Aggregate(Stats); - United->GetCurrentStats(PoolId, statsCopy); + void TUnitedWorkers::GetCurrentStats(TPoolId pool, TVector<TExecutorThreadStats>& statsCopy) const { + size_t idx = 1; + statsCopy.resize(idx + Pools[pool].WakeOrderCpus.size()); + for (TCpu* cpu : Pools[pool].WakeOrderCpus) { + TExecutorThreadStats& s = statsCopy[idx++]; + s = TExecutorThreadStats(); + s.Aggregate(cpu->PoolStats[pool]); + } + } + + TUnitedExecutorPool::TUnitedExecutorPool(const TUnitedExecutorPoolConfig& cfg, TUnitedWorkers* united) + : TExecutorPoolBaseMailboxed(cfg.PoolId, cfg.MaxActivityType) + , United(united) + , PoolName(cfg.PoolName) + { + United->SetupPool(TPoolId(cfg.PoolId), this, MailboxTable.Get()); + } + + void TUnitedExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { + ActorSystem = actorSystem; + + // Schedule readers are initialized through TUnitedWorkers::Prepare + *scheduleReaders = nullptr; + *scheduleSz = 0; + } + + void TUnitedExecutorPool::Start() { + // workers are actually started in TUnitedWorkers::Start() + } + + void TUnitedExecutorPool::PrepareStop() { + } + + void TUnitedExecutorPool::Shutdown() { + // workers are actually joined in TUnitedWorkers::Shutdown() + } + + TAffinity* TUnitedExecutorPool::Affinity() const { + Y_FAIL(); // should never be called, TCpuExecutorPool is used instead + } + + ui32 TUnitedExecutorPool::GetThreads() const { + return 0; + } + + ui32 TUnitedExecutorPool::GetReadyActivation(TWorkerContext&, ui64) { + Y_FAIL(); // should never be called, TCpu*ExecutorPool is used instead + } + + inline void TUnitedExecutorPool::ScheduleActivation(ui32 activation) { + TUnitedExecutorPool::ScheduleActivationEx(activation, AtomicIncrement(ActivationsRevolvingCounter)); + } + + inline void TUnitedExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) { + United->PushActivation(PoolId, activation, revolvingCounter); + } + + void TUnitedExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { + TUnitedExecutorPool::Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); + } + + void TUnitedExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { + Y_VERIFY_DEBUG(workerId < United->GetWorkerCount()); + const auto current = ActorSystem->Monotonic(); + if (deadline < current) { + deadline = current; + } + United->GetScheduleWriter(workerId)->Push(deadline.MicroSeconds(), ev.Release(), cookie); } + + void TUnitedExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { + Y_VERIFY_DEBUG(workerId < United->GetWorkerCount()); + const auto deadline = ActorSystem->Monotonic() + delta; + United->GetScheduleWriter(workerId)->Push(deadline.MicroSeconds(), ev.Release(), cookie); + } + + void TUnitedExecutorPool::GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { + Y_UNUSED(poolStats); + if (statsCopy.empty()) { + statsCopy.resize(1); + } + statsCopy[0] = TExecutorThreadStats(); + statsCopy[0].Aggregate(Stats); + United->GetCurrentStats(PoolId, statsCopy); + } } diff --git a/library/cpp/actors/core/executor_pool_united.h b/library/cpp/actors/core/executor_pool_united.h index a090ba2466..8f5cabe365 100644 --- a/library/cpp/actors/core/executor_pool_united.h +++ b/library/cpp/actors/core/executor_pool_united.h @@ -1,133 +1,133 @@ #pragma once #include "actorsystem.h" -#include "balancer.h" +#include "balancer.h" #include "scheduler_queue.h" #include "executor_pool_base.h" - + #include <library/cpp/actors/util/unordered_cache.h> - + #include <library/cpp/monlib/dynamic_counters/counters.h> -#include <library/cpp/actors/util/unordered_cache.h> -#include <library/cpp/containers/stack_vector/stack_vec.h> - -#include <util/generic/noncopyable.h> - +#include <library/cpp/actors/util/unordered_cache.h> +#include <library/cpp/containers/stack_vector/stack_vec.h> + +#include <util/generic/noncopyable.h> + namespace NActors { - class TMailboxTable; - - class TUnitedWorkers: public TNonCopyable { - struct TWorker; - struct TPool; - struct TCpu; - - size_t WorkerCount; - TArrayHolder<TWorker> Workers; // indexed by WorkerId - size_t PoolCount; - TArrayHolder<TPool> Pools; // indexed by PoolId, so may include not used (not united) pools - size_t CpuCount; - TArrayHolder<TCpu> Cpus; // indexed by CpuId, so may include not allocated CPUs - - IBalancer* Balancer; // external pool cpu balancer - - TUnitedWorkersConfig Config; - TCpuAllocationConfig Allocation; - - volatile bool StopFlag = false; - - public: - TUnitedWorkers( - const TUnitedWorkersConfig& config, - const TVector<TUnitedExecutorPoolConfig>& unitedPools, - const TCpuAllocationConfig& allocation, - IBalancer* balancer); - ~TUnitedWorkers(); - void Prepare(TActorSystem* actorSystem, TVector<NSchedulerQueue::TReader*>& scheduleReaders); - void Start(); - void PrepareStop(); - void Shutdown(); - - bool IsStopped() const { - return RelaxedLoad(&StopFlag); - } - - TWorkerId GetWorkerCount() const { - return WorkerCount; - } - - // Returns thread id of a worker - TThreadId GetWorkerThreadId(TWorkerId workerId) const; - - // Returns per worker schedule writers - NSchedulerQueue::TWriter* GetScheduleWriter(TWorkerId workerId) const; - - // Sets executor for specified pool - void SetupPool(TPoolId pool, IExecutorPool* executorPool, TMailboxTable* mailboxTable); - - // Add activation of newly scheduled mailbox and wake cpu to execute it if required - void PushActivation(TPoolId pool, ui32 activation, ui64 revolvingCounter); - - // Try acquire pending token. Must be done before execution - bool TryAcquireToken(TPoolId pool); - - // Try to wake idle cpu waiting for tokens on specified pool - void TryWake(TPoolId pool); - - // Get activation from pool; requires pool's token - void BeginExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter); - - // Stop currently active execution and start new one if token is available - // NOTE: Reuses token if it's not destroyed - bool NextExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter); - - // Stop active execution - void StopExecution(TPoolId pool); - - // Runs balancer to assign pools to cpus - void Balance(); - - // Returns pool to be executed by worker or `CpuShared` - TPoolId AssignedPool(TWorkerContext& wctx); - - // Checks if balancer has assigned another pool for worker's cpu - bool IsPoolReassigned(TWorkerContext& wctx); - - // Switch worker context into specified pool - void SwitchPool(TWorkerContext& wctx, ui64 softDeadlineTs); - - // Wait for tokens from any pool allowed on specified cpu - TPoolId Idle(TPoolId assigned, TWorkerContext& wctx); - - // Fill stats for specified pool - void GetCurrentStats(TPoolId pool, TVector<TExecutorThreadStats>& statsCopy) const; - - private: - TPoolId WaitSequence(TCpu& cpu, TWorkerContext& wctx, TTimeTracker& timeTracker); - }; - - class TUnitedExecutorPool: public TExecutorPoolBaseMailboxed { - TUnitedWorkers* United; - const TString PoolName; - TAtomic ActivationsRevolvingCounter = 0; - public: - TUnitedExecutorPool(const TUnitedExecutorPoolConfig& cfg, TUnitedWorkers* united); - - void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; + class TMailboxTable; + + class TUnitedWorkers: public TNonCopyable { + struct TWorker; + struct TPool; + struct TCpu; + + size_t WorkerCount; + TArrayHolder<TWorker> Workers; // indexed by WorkerId + size_t PoolCount; + TArrayHolder<TPool> Pools; // indexed by PoolId, so may include not used (not united) pools + size_t CpuCount; + TArrayHolder<TCpu> Cpus; // indexed by CpuId, so may include not allocated CPUs + + IBalancer* Balancer; // external pool cpu balancer + + TUnitedWorkersConfig Config; + TCpuAllocationConfig Allocation; + + volatile bool StopFlag = false; + + public: + TUnitedWorkers( + const TUnitedWorkersConfig& config, + const TVector<TUnitedExecutorPoolConfig>& unitedPools, + const TCpuAllocationConfig& allocation, + IBalancer* balancer); + ~TUnitedWorkers(); + void Prepare(TActorSystem* actorSystem, TVector<NSchedulerQueue::TReader*>& scheduleReaders); + void Start(); + void PrepareStop(); + void Shutdown(); + + bool IsStopped() const { + return RelaxedLoad(&StopFlag); + } + + TWorkerId GetWorkerCount() const { + return WorkerCount; + } + + // Returns thread id of a worker + TThreadId GetWorkerThreadId(TWorkerId workerId) const; + + // Returns per worker schedule writers + NSchedulerQueue::TWriter* GetScheduleWriter(TWorkerId workerId) const; + + // Sets executor for specified pool + void SetupPool(TPoolId pool, IExecutorPool* executorPool, TMailboxTable* mailboxTable); + + // Add activation of newly scheduled mailbox and wake cpu to execute it if required + void PushActivation(TPoolId pool, ui32 activation, ui64 revolvingCounter); + + // Try acquire pending token. Must be done before execution + bool TryAcquireToken(TPoolId pool); + + // Try to wake idle cpu waiting for tokens on specified pool + void TryWake(TPoolId pool); + + // Get activation from pool; requires pool's token + void BeginExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter); + + // Stop currently active execution and start new one if token is available + // NOTE: Reuses token if it's not destroyed + bool NextExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter); + + // Stop active execution + void StopExecution(TPoolId pool); + + // Runs balancer to assign pools to cpus + void Balance(); + + // Returns pool to be executed by worker or `CpuShared` + TPoolId AssignedPool(TWorkerContext& wctx); + + // Checks if balancer has assigned another pool for worker's cpu + bool IsPoolReassigned(TWorkerContext& wctx); + + // Switch worker context into specified pool + void SwitchPool(TWorkerContext& wctx, ui64 softDeadlineTs); + + // Wait for tokens from any pool allowed on specified cpu + TPoolId Idle(TPoolId assigned, TWorkerContext& wctx); + + // Fill stats for specified pool + void GetCurrentStats(TPoolId pool, TVector<TExecutorThreadStats>& statsCopy) const; + + private: + TPoolId WaitSequence(TCpu& cpu, TWorkerContext& wctx, TTimeTracker& timeTracker); + }; + + class TUnitedExecutorPool: public TExecutorPoolBaseMailboxed { + TUnitedWorkers* United; + const TString PoolName; + TAtomic ActivationsRevolvingCounter = 0; + public: + TUnitedExecutorPool(const TUnitedExecutorPoolConfig& cfg, TUnitedWorkers* united); + + void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; void Start() override; void PrepareStop() override; void Shutdown() override; - TAffinity* Affinity() const override; - ui32 GetThreads() const override; - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingReadCounter) override; - void ScheduleActivation(ui32 activation) override; - void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - + TAffinity* Affinity() const override; + ui32 GetThreads() const override; + ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingReadCounter) override; + void ScheduleActivation(ui32 activation) override; + void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; + void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; + void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; + void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; + void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const override; - + TString GetName() const override { return PoolName; } diff --git a/library/cpp/actors/core/executor_pool_united_ut.cpp b/library/cpp/actors/core/executor_pool_united_ut.cpp index d4df17f1b8..97e1f91557 100644 --- a/library/cpp/actors/core/executor_pool_united_ut.cpp +++ b/library/cpp/actors/core/executor_pool_united_ut.cpp @@ -18,18 +18,18 @@ struct TEvMsg : public NActors::TEventBase<TEvMsg, 10347> { //////////////////////////////////////////////////////////////////////////////// -inline ui64 DoTimedWork(ui64 workUs) { - ui64 startUs = ThreadCPUTime(); - ui64 endUs = startUs + workUs; - ui64 nowUs = startUs; - do { - ui64 endTs = GetCycleCountFast() + Us2Ts(endUs - nowUs); - while (GetCycleCountFast() <= endTs) {} - nowUs = ThreadCPUTime(); - } while (nowUs <= endUs); - return nowUs - startUs; -} - +inline ui64 DoTimedWork(ui64 workUs) { + ui64 startUs = ThreadCPUTime(); + ui64 endUs = startUs + workUs; + ui64 nowUs = startUs; + do { + ui64 endTs = GetCycleCountFast() + Us2Ts(endUs - nowUs); + while (GetCycleCountFast() <= endTs) {} + nowUs = ThreadCPUTime(); + } while (nowUs <= endUs); + return nowUs - startUs; +} + class TTestSenderActor : public IActor { private: using EActivityType = IActor::EActivityType ; @@ -48,7 +48,7 @@ public: , Action(action) {} - void Start(TActorId receiver, size_t count) { + void Start(TActorId receiver, size_t count) { AtomicSet(Counter, count); Receiver = receiver; } @@ -68,14 +68,14 @@ public: } private: - STFUNC(Execute) { + STFUNC(Execute) { Y_UNUSED(ctx); switch (ev->GetTypeRewrite()) { hFunc(TEvMsg, Handle); } } - void Handle(TEvMsg::TPtr &ev) { + void Handle(TEvMsg::TPtr &ev) { Y_UNUSED(ev); Action(); TAtomicBase count = AtomicDecrement(Counter); @@ -86,57 +86,57 @@ private: } }; -// Single cpu balancer that switches pool on every activation; not thread-safe -struct TRoundRobinBalancer: public IBalancer { - TCpuState* State; - TMap<TPoolId, TPoolId> NextPool; - - bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) override { - State = cpu; - TPoolId prev = cpuAlloc.AllowedPools.rbegin()->PoolId; - for (auto& p : cpuAlloc.AllowedPools) { - NextPool[prev] = p.PoolId; - prev = p.PoolId; - } - return true; - } - - bool TryLock(ui64) override { return true; } - void SetPoolStats(TPoolId, const TBalancerStats&) override {} - void Unlock() override {} - - void Balance() override { - TPoolId assigned; - TPoolId current; - State->Load(assigned, current); - State->AssignPool(NextPool[assigned]); - } -}; - -void AddUnitedPool(THolder<TActorSystemSetup>& setup, ui32 concurrency = 0) { - TUnitedExecutorPoolConfig united; - united.PoolId = setup->GetExecutorsCount(); - united.Concurrency = concurrency; - setup->CpuManager.United.emplace_back(std::move(united)); -} - -THolder<TActorSystemSetup> GetActorSystemSetup(ui32 cpuCount) { +// Single cpu balancer that switches pool on every activation; not thread-safe +struct TRoundRobinBalancer: public IBalancer { + TCpuState* State; + TMap<TPoolId, TPoolId> NextPool; + + bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) override { + State = cpu; + TPoolId prev = cpuAlloc.AllowedPools.rbegin()->PoolId; + for (auto& p : cpuAlloc.AllowedPools) { + NextPool[prev] = p.PoolId; + prev = p.PoolId; + } + return true; + } + + bool TryLock(ui64) override { return true; } + void SetPoolStats(TPoolId, const TBalancerStats&) override {} + void Unlock() override {} + + void Balance() override { + TPoolId assigned; + TPoolId current; + State->Load(assigned, current); + State->AssignPool(NextPool[assigned]); + } +}; + +void AddUnitedPool(THolder<TActorSystemSetup>& setup, ui32 concurrency = 0) { + TUnitedExecutorPoolConfig united; + united.PoolId = setup->GetExecutorsCount(); + united.Concurrency = concurrency; + setup->CpuManager.United.emplace_back(std::move(united)); +} + +THolder<TActorSystemSetup> GetActorSystemSetup(ui32 cpuCount) { auto setup = MakeHolder<NActors::TActorSystemSetup>(); setup->NodeId = 1; - setup->CpuManager.UnitedWorkers.CpuCount = cpuCount; - setup->CpuManager.UnitedWorkers.NoRealtime = true; // unavailable in test environment + setup->CpuManager.UnitedWorkers.CpuCount = cpuCount; + setup->CpuManager.UnitedWorkers.NoRealtime = true; // unavailable in test environment setup->Scheduler = new TBasicSchedulerThread(NActors::TSchedulerConfig(512, 0)); return setup; } -Y_UNIT_TEST_SUITE(UnitedExecutorPool) { +Y_UNIT_TEST_SUITE(UnitedExecutorPool) { -#ifdef _linux_ +#ifdef _linux_ - Y_UNIT_TEST(OnePoolManyCpus) { + Y_UNIT_TEST(OnePoolManyCpus) { const size_t msgCount = 1e4; - auto setup = GetActorSystemSetup(4); - AddUnitedPool(setup); + auto setup = GetActorSystemSetup(4); + AddUnitedPool(setup); TActorSystem actorSystem(setup); actorSystem.Start(); @@ -153,186 +153,186 @@ Y_UNIT_TEST_SUITE(UnitedExecutorPool) { Sleep(TDuration::MilliSeconds(1)); } - - TVector<TExecutorThreadStats> stats; - TExecutorPoolStats poolStats; - actorSystem.GetPoolStats(0, poolStats, stats); - // Sum all per-thread counters into the 0th element - for (ui32 idx = 1; idx < stats.size(); ++idx) { - stats[0].Aggregate(stats[idx]); - } - - UNIT_ASSERT_VALUES_EQUAL(stats[0].SentEvents, msgCount - 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); - //UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, 0); // depends on execution time and system load, so may be non-zero - UNIT_ASSERT_VALUES_EQUAL(stats[0].NonDeliveredEvents, 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EmptyMailboxActivation, 0); - //UNIT_ASSERT_VALUES_EQUAL(stats[0].CpuNs, 0); // depends on total duration of test, so undefined - UNIT_ASSERT(stats[0].ElapsedTicks > 0); - UNIT_ASSERT(stats[0].ParkedTicks == 0); // per-pool parked time does not make sense for united pools - UNIT_ASSERT_VALUES_EQUAL(stats[0].BlockedTicks, 0); - UNIT_ASSERT(stats[0].ActivationTimeHistogram.TotalSamples >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EventDeliveryTimeHistogram.TotalSamples, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EventProcessingCountHistogram.TotalSamples, msgCount); - UNIT_ASSERT(stats[0].EventProcessingTimeHistogram.TotalSamples > 0); - UNIT_ASSERT(stats[0].ElapsedTicksByActivity[0] > 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEventsByActivity[0], msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ActorsAliveByActivity[0], 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ScheduledEventsByActivity[0], 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolDestroyedActors, 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolAllocatedMailboxes, 4095); // one line - UNIT_ASSERT(stats[0].MailboxPushedOutByTime + stats[0].MailboxPushedOutByEventCount + stats[0].MailboxPushedOutBySoftPreemption >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); + + TVector<TExecutorThreadStats> stats; + TExecutorPoolStats poolStats; + actorSystem.GetPoolStats(0, poolStats, stats); + // Sum all per-thread counters into the 0th element + for (ui32 idx = 1; idx < stats.size(); ++idx) { + stats[0].Aggregate(stats[idx]); + } + + UNIT_ASSERT_VALUES_EQUAL(stats[0].SentEvents, msgCount - 1); + UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); + //UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, 0); // depends on execution time and system load, so may be non-zero + UNIT_ASSERT_VALUES_EQUAL(stats[0].NonDeliveredEvents, 0); + UNIT_ASSERT_VALUES_EQUAL(stats[0].EmptyMailboxActivation, 0); + //UNIT_ASSERT_VALUES_EQUAL(stats[0].CpuNs, 0); // depends on total duration of test, so undefined + UNIT_ASSERT(stats[0].ElapsedTicks > 0); + UNIT_ASSERT(stats[0].ParkedTicks == 0); // per-pool parked time does not make sense for united pools + UNIT_ASSERT_VALUES_EQUAL(stats[0].BlockedTicks, 0); + UNIT_ASSERT(stats[0].ActivationTimeHistogram.TotalSamples >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); + UNIT_ASSERT_VALUES_EQUAL(stats[0].EventDeliveryTimeHistogram.TotalSamples, msgCount); + UNIT_ASSERT_VALUES_EQUAL(stats[0].EventProcessingCountHistogram.TotalSamples, msgCount); + UNIT_ASSERT(stats[0].EventProcessingTimeHistogram.TotalSamples > 0); + UNIT_ASSERT(stats[0].ElapsedTicksByActivity[0] > 0); + UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEventsByActivity[0], msgCount); + UNIT_ASSERT_VALUES_EQUAL(stats[0].ActorsAliveByActivity[0], 1); + UNIT_ASSERT_VALUES_EQUAL(stats[0].ScheduledEventsByActivity[0], 0); + UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); + UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolDestroyedActors, 0); + UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolAllocatedMailboxes, 4095); // one line + UNIT_ASSERT(stats[0].MailboxPushedOutByTime + stats[0].MailboxPushedOutByEventCount + stats[0].MailboxPushedOutBySoftPreemption >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); } - Y_UNIT_TEST(ManyPoolsOneSharedCpu) { + Y_UNIT_TEST(ManyPoolsOneSharedCpu) { const size_t msgCount = 1e4; - const size_t pools = 4; - auto setup = GetActorSystemSetup(1); - for (size_t pool = 0; pool < pools; pool++) { - AddUnitedPool(setup); - } + const size_t pools = 4; + auto setup = GetActorSystemSetup(1); + for (size_t pool = 0; pool < pools; pool++) { + AddUnitedPool(setup); + } TActorSystem actorSystem(setup); actorSystem.Start(); auto begin = TInstant::Now(); - TVector<TTestSenderActor*> actors; - for (size_t pool = 0; pool < pools; pool++) { - auto actor = new TTestSenderActor(); - auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool); - actor->Start(actor->SelfId(), msgCount); - actorSystem.Send(actorId, new TEvMsg()); - actors.push_back(actor); + TVector<TTestSenderActor*> actors; + for (size_t pool = 0; pool < pools; pool++) { + auto actor = new TTestSenderActor(); + auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool); + actor->Start(actor->SelfId(), msgCount); + actorSystem.Send(actorId, new TEvMsg()); + actors.push_back(actor); } while (true) { - size_t left = 0; - for (auto actor : actors) { - left += actor->GetCounter(); + size_t left = 0; + for (auto actor : actors) { + left += actor->GetCounter(); } - if (left == 0) { + if (left == 0) { break; } auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "left " << left); + UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "left " << left); Sleep(TDuration::MilliSeconds(1)); } - - for (size_t pool = 0; pool < pools; pool++) { - TVector<TExecutorThreadStats> stats; - TExecutorPoolStats poolStats; - actorSystem.GetPoolStats(pool, poolStats, stats); - // Sum all per-thread counters into the 0th element - for (ui32 idx = 1; idx < stats.size(); ++idx) { - stats[0].Aggregate(stats[idx]); - } - - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); - } + + for (size_t pool = 0; pool < pools; pool++) { + TVector<TExecutorThreadStats> stats; + TExecutorPoolStats poolStats; + actorSystem.GetPoolStats(pool, poolStats, stats); + // Sum all per-thread counters into the 0th element + for (ui32 idx = 1; idx < stats.size(); ++idx) { + stats[0].Aggregate(stats[idx]); + } + + UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); + UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); + } } - Y_UNIT_TEST(ManyPoolsOneAssignedCpu) { - const size_t msgCount = 1e4; - const size_t pools = 4; - auto setup = GetActorSystemSetup(1); - setup->Balancer.Reset(new TRoundRobinBalancer()); - for (size_t pool = 0; pool < pools; pool++) { - AddUnitedPool(setup); - } + Y_UNIT_TEST(ManyPoolsOneAssignedCpu) { + const size_t msgCount = 1e4; + const size_t pools = 4; + auto setup = GetActorSystemSetup(1); + setup->Balancer.Reset(new TRoundRobinBalancer()); + for (size_t pool = 0; pool < pools; pool++) { + AddUnitedPool(setup); + } + TActorSystem actorSystem(setup); + actorSystem.Start(); + + auto begin = TInstant::Now(); + + TVector<TTestSenderActor*> actors; + for (size_t pool = 0; pool < pools; pool++) { + auto actor = new TTestSenderActor(); + auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool); + actor->Start(actor->SelfId(), msgCount); + actorSystem.Send(actorId, new TEvMsg()); + actors.push_back(actor); + } + + while (true) { + size_t left = 0; + for (auto actor : actors) { + left += actor->GetCounter(); + } + if (left == 0) { + break; + } + auto now = TInstant::Now(); + UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "left " << left); + Sleep(TDuration::MilliSeconds(1)); + } + + for (size_t pool = 0; pool < pools; pool++) { + TVector<TExecutorThreadStats> stats; + TExecutorPoolStats poolStats; + actorSystem.GetPoolStats(pool, poolStats, stats); + // Sum all per-thread counters into the 0th element + for (ui32 idx = 1; idx < stats.size(); ++idx) { + stats[0].Aggregate(stats[idx]); + } + + UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); + UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); + } + } + + Y_UNIT_TEST(ManyPoolsOneCpuSlowEvents) { + const size_t msgCount = 3; + const size_t pools = 4; + auto setup = GetActorSystemSetup(1); + for (size_t pool = 0; pool < pools; pool++) { + AddUnitedPool(setup); + } TActorSystem actorSystem(setup); actorSystem.Start(); auto begin = TInstant::Now(); - TVector<TTestSenderActor*> actors; - for (size_t pool = 0; pool < pools; pool++) { - auto actor = new TTestSenderActor(); - auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool); - actor->Start(actor->SelfId(), msgCount); - actorSystem.Send(actorId, new TEvMsg()); - actors.push_back(actor); + TVector<TTestSenderActor*> actors; + for (size_t pool = 0; pool < pools; pool++) { + auto actor = new TTestSenderActor([]() { + DoTimedWork(100'000); + }); + auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool); + actor->Start(actor->SelfId(), msgCount); + actorSystem.Send(actorId, new TEvMsg()); + actors.push_back(actor); } while (true) { - size_t left = 0; - for (auto actor : actors) { - left += actor->GetCounter(); + size_t left = 0; + for (auto actor : actors) { + left += actor->GetCounter(); } - if (left == 0) { + if (left == 0) { break; } auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "left " << left); + UNIT_ASSERT_C(now - begin < TDuration::Seconds(15), "left " << left); Sleep(TDuration::MilliSeconds(1)); } - for (size_t pool = 0; pool < pools; pool++) { - TVector<TExecutorThreadStats> stats; - TExecutorPoolStats poolStats; - actorSystem.GetPoolStats(pool, poolStats, stats); - // Sum all per-thread counters into the 0th element - for (ui32 idx = 1; idx < stats.size(); ++idx) { - stats[0].Aggregate(stats[idx]); - } - - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); + for (size_t pool = 0; pool < pools; pool++) { + TVector<TExecutorThreadStats> stats; + TExecutorPoolStats poolStats; + actorSystem.GetPoolStats(pool, poolStats, stats); + // Sum all per-thread counters into the 0th element + for (ui32 idx = 1; idx < stats.size(); ++idx) { + stats[0].Aggregate(stats[idx]); + } + + UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); + UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, msgCount); // every 100ms event should be preempted + UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); } - } - - Y_UNIT_TEST(ManyPoolsOneCpuSlowEvents) { - const size_t msgCount = 3; - const size_t pools = 4; - auto setup = GetActorSystemSetup(1); - for (size_t pool = 0; pool < pools; pool++) { - AddUnitedPool(setup); - } - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - TVector<TTestSenderActor*> actors; - for (size_t pool = 0; pool < pools; pool++) { - auto actor = new TTestSenderActor([]() { - DoTimedWork(100'000); - }); - auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool); - actor->Start(actor->SelfId(), msgCount); - actorSystem.Send(actorId, new TEvMsg()); - actors.push_back(actor); - } - - while (true) { - size_t left = 0; - for (auto actor : actors) { - left += actor->GetCounter(); - } - if (left == 0) { - break; - } - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(15), "left " << left); - Sleep(TDuration::MilliSeconds(1)); - } - - for (size_t pool = 0; pool < pools; pool++) { - TVector<TExecutorThreadStats> stats; - TExecutorPoolStats poolStats; - actorSystem.GetPoolStats(pool, poolStats, stats); - // Sum all per-thread counters into the 0th element - for (ui32 idx = 1; idx < stats.size(); ++idx) { - stats[0].Aggregate(stats[idx]); - } - - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, msgCount); // every 100ms event should be preempted - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); - } - } + } -#endif +#endif } diff --git a/library/cpp/actors/core/executor_thread.cpp b/library/cpp/actors/core/executor_thread.cpp index 446b651efd..1fd93f1a42 100644 --- a/library/cpp/actors/core/executor_thread.cpp +++ b/library/cpp/actors/core/executor_thread.cpp @@ -7,18 +7,18 @@ #include <library/cpp/actors/prof/tag.h> #include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> #include <library/cpp/actors/util/thread.h> #ifdef BALLOC #include <library/cpp/balloc/optional/operators.h> #endif -#ifdef _linux_ -#include <sys/syscall.h> -#include <unistd.h> -#endif - +#ifdef _linux_ +#include <sys/syscall.h> +#include <unistd.h> +#endif + #include <util/system/type_name.h> #include <util/system/datetime.h> @@ -28,42 +28,42 @@ namespace NActors { constexpr TDuration TExecutorThread::DEFAULT_TIME_PER_MAILBOX; TExecutorThread::TExecutorThread( - TWorkerId workerId, - TWorkerId cpuId, - TActorSystem* actorSystem, - IExecutorPool* executorPool, - TMailboxTable* mailboxTable, - const TString& threadName, - TDuration timePerMailbox, - ui32 eventsPerMailbox) - : ActorSystem(actorSystem) + TWorkerId workerId, + TWorkerId cpuId, + TActorSystem* actorSystem, + IExecutorPool* executorPool, + TMailboxTable* mailboxTable, + const TString& threadName, + TDuration timePerMailbox, + ui32 eventsPerMailbox) + : ActorSystem(actorSystem) , ExecutorPool(executorPool) - , Ctx(workerId, cpuId, actorSystem ? actorSystem->GetMaxActivityType() : 1) + , Ctx(workerId, cpuId, actorSystem ? actorSystem->GetMaxActivityType() : 1) , ThreadName(threadName) - { - Ctx.Switch( - ExecutorPool, - mailboxTable, - NHPTimer::GetClockRate() * timePerMailbox.SecondsFloat(), - eventsPerMailbox, - ui64(-1), // infinite soft deadline - &Ctx.WorkerStats); - } + { + Ctx.Switch( + ExecutorPool, + mailboxTable, + NHPTimer::GetClockRate() * timePerMailbox.SecondsFloat(), + eventsPerMailbox, + ui64(-1), // infinite soft deadline + &Ctx.WorkerStats); + } TActorId TExecutorThread::RegisterActor(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId, const TActorId& parentId) { if (poolId == Max<ui32>()) - return Ctx.Executor->Register(actor, mailboxType, ++RevolvingWriteCounter, parentId ? parentId : CurrentRecipient); + return Ctx.Executor->Register(actor, mailboxType, ++RevolvingWriteCounter, parentId ? parentId : CurrentRecipient); else return ActorSystem->Register(actor, mailboxType, poolId, ++RevolvingWriteCounter, parentId ? parentId : CurrentRecipient); } TActorId TExecutorThread::RegisterActor(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) { - return Ctx.Executor->Register(actor, mailbox, hint, parentId ? parentId : CurrentRecipient); + return Ctx.Executor->Register(actor, mailbox, hint, parentId ? parentId : CurrentRecipient); } void TExecutorThread::UnregisterActor(TMailboxHeader* mailbox, ui64 localActorId) { IActor* actor = mailbox->DetachActor(localActorId); - Ctx.DecrementActorsAliveByActivity(actor->GetActivityType()); + Ctx.DecrementActorsAliveByActivity(actor->GetActivityType()); DyingActors.push_back(THolder(actor)); } @@ -73,17 +73,17 @@ namespace NActors { void TExecutorThread::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { ++CurrentActorScheduledEventsCounter; - Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId); + Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId); } void TExecutorThread::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { ++CurrentActorScheduledEventsCounter; - Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId); + Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId); } void TExecutorThread::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { ++CurrentActorScheduledEventsCounter; - Ctx.Executor->Schedule(delta, ev, cookie, Ctx.WorkerId); + Ctx.Executor->Schedule(delta, ev, cookie, Ctx.WorkerId); } template <class T> @@ -96,7 +96,7 @@ namespace NActors { } catch (...) { return "unknown-type"; } - } + } inline TString ActorTypeName(const IActor* actor, ui32 activityType) { return actor ? SafeTypeName(actor) : ("activityType_" + ToString(activityType) + " (destroyed)"); @@ -113,8 +113,8 @@ namespace NActors { baseEv ? SafeTypeName(baseEv) : (ev ? ToString(ev->Type) : TString("nullptr")), currentRecipient.ToString(), SafeTypeName(actor)); - } - + } + inline void LwTraceSlowEvent(IEventHandle* ev, ui32 evTypeForTracing, const IActor* actor, ui32 poolId, ui32 activityType, const TActorId& currentRecipient, double eventMs) { // Event could have been destroyed by actor->Receive(); @@ -126,25 +126,25 @@ namespace NActors { currentRecipient.ToString(), ActorTypeName(actor, activityType)); } - + template <typename TMailbox> void TExecutorThread::Execute(TMailbox* mailbox, ui32 hint) { Y_VERIFY_DEBUG(DyingActors.empty()); bool reclaimAsFree = false; - NHPTimer::STime hpstart = GetCycleCountFast(); + NHPTimer::STime hpstart = GetCycleCountFast(); NHPTimer::STime hpprev = hpstart; - IActor* actor = nullptr; + IActor* actor = nullptr; ui32 prevActivityType = std::numeric_limits<ui32>::max(); - TActorId recipient; - for (ui32 executed = 0; executed < Ctx.EventsPerMailbox; ++executed) { + TActorId recipient; + for (ui32 executed = 0; executed < Ctx.EventsPerMailbox; ++executed) { TAutoPtr<IEventHandle> ev(mailbox->Pop()); if (!!ev) { NHPTimer::STime hpnow; - recipient = ev->GetRecipientRewrite(); - if (actor = mailbox->FindActor(recipient.LocalId())) { + recipient = ev->GetRecipientRewrite(); + if (actor = mailbox->FindActor(recipient.LocalId())) { TActorContext ctx(*mailbox, *this, hpprev, recipient); TlsActivationContext = &ctx; @@ -156,16 +156,16 @@ namespace NActors { CurrentActorScheduledEventsCounter = 0; if (executed == 0) { - double usec = Ctx.AddActivationStats(AtomicLoad(&mailbox->ScheduleMoment), hpprev); - if (usec > 500) { - GLOBAL_LWPROBE(ACTORLIB_PROVIDER, SlowActivation, Ctx.PoolId, usec / 1000.0); + double usec = Ctx.AddActivationStats(AtomicLoad(&mailbox->ScheduleMoment), hpprev); + if (usec > 500) { + GLOBAL_LWPROBE(ACTORLIB_PROVIDER, SlowActivation, Ctx.PoolId, usec / 1000.0); } - } + } - i64 usecDeliv = Ctx.AddEventDeliveryStats(ev->SendTime, hpprev); + i64 usecDeliv = Ctx.AddEventDeliveryStats(ev->SendTime, hpprev); if (usecDeliv > 5000) { double sinceActivationMs = NHPTimer::GetSeconds(hpprev - hpstart) * 1000.0; - LwTraceSlowDelivery(ev.Get(), actor, Ctx.PoolId, CurrentRecipient, NHPTimer::GetSeconds(hpprev - ev->SendTime) * 1000.0, sinceActivationMs, executed); + LwTraceSlowDelivery(ev.Get(), actor, Ctx.PoolId, CurrentRecipient, NHPTimer::GetSeconds(hpprev - ev->SendTime) * 1000.0, sinceActivationMs, executed); } ui32 evTypeForTracing = ev->Type; @@ -179,7 +179,7 @@ namespace NActors { actor->Receive(ev, ctx); size_t dyingActorsCnt = DyingActors.size(); - Ctx.UpdateActorsStats(dyingActorsCnt); + Ctx.UpdateActorsStats(dyingActorsCnt); if (dyingActorsCnt) { DropUnregistered(); actor = nullptr; @@ -188,11 +188,11 @@ namespace NActors { if (mailbox->IsEmpty()) // was not-free and become free, we must reclaim mailbox reclaimAsFree = true; - hpnow = GetCycleCountFast(); - NHPTimer::STime elapsed = Ctx.AddEventProcessingStats(hpprev, hpnow, activityType, CurrentActorScheduledEventsCounter); - if (elapsed > 1000000) { - LwTraceSlowEvent(ev.Get(), evTypeForTracing, actor, Ctx.PoolId, activityType, CurrentRecipient, NHPTimer::GetSeconds(elapsed) * 1000.0); - } + hpnow = GetCycleCountFast(); + NHPTimer::STime elapsed = Ctx.AddEventProcessingStats(hpprev, hpnow, activityType, CurrentActorScheduledEventsCounter); + if (elapsed > 1000000) { + LwTraceSlowEvent(ev.Get(), evTypeForTracing, actor, Ctx.PoolId, activityType, CurrentRecipient, NHPTimer::GetSeconds(elapsed) * 1000.0); + } // The actor might have been destroyed if (actor) @@ -204,99 +204,99 @@ namespace NActors { if (nonDelivered.Get()) { ActorSystem->Send(nonDelivered); } else { - Ctx.IncrementNonDeliveredEvents(); + Ctx.IncrementNonDeliveredEvents(); } - hpnow = GetCycleCountFast(); + hpnow = GetCycleCountFast(); } hpprev = hpnow; - // Soft preemption in united pool - if (Ctx.SoftDeadlineTs < (ui64)hpnow) { - AtomicStore(&mailbox->ScheduleMoment, hpnow); - Ctx.IncrementMailboxPushedOutBySoftPreemption(); - LWTRACK(MailboxPushedOutBySoftPreemption, - Ctx.Orbit, - Ctx.PoolId, - Ctx.Executor->GetName(), - executed + 1, - CyclesToDuration(hpnow - hpstart), - Ctx.WorkerId, - recipient.ToString(), - SafeTypeName(actor)); - break; - } - + // Soft preemption in united pool + if (Ctx.SoftDeadlineTs < (ui64)hpnow) { + AtomicStore(&mailbox->ScheduleMoment, hpnow); + Ctx.IncrementMailboxPushedOutBySoftPreemption(); + LWTRACK(MailboxPushedOutBySoftPreemption, + Ctx.Orbit, + Ctx.PoolId, + Ctx.Executor->GetName(), + executed + 1, + CyclesToDuration(hpnow - hpstart), + Ctx.WorkerId, + recipient.ToString(), + SafeTypeName(actor)); + break; + } + // time limit inside one mailbox passed, let others do some work - if (hpnow - hpstart > (i64)Ctx.TimePerMailboxTs) { - AtomicStore(&mailbox->ScheduleMoment, hpnow); - Ctx.IncrementMailboxPushedOutByTime(); - LWTRACK(MailboxPushedOutByTime, - Ctx.Orbit, - Ctx.PoolId, - Ctx.Executor->GetName(), - executed + 1, - CyclesToDuration(hpnow - hpstart), - Ctx.WorkerId, - recipient.ToString(), - SafeTypeName(actor)); + if (hpnow - hpstart > (i64)Ctx.TimePerMailboxTs) { + AtomicStore(&mailbox->ScheduleMoment, hpnow); + Ctx.IncrementMailboxPushedOutByTime(); + LWTRACK(MailboxPushedOutByTime, + Ctx.Orbit, + Ctx.PoolId, + Ctx.Executor->GetName(), + executed + 1, + CyclesToDuration(hpnow - hpstart), + Ctx.WorkerId, + recipient.ToString(), + SafeTypeName(actor)); break; } - if (executed + 1 == Ctx.EventsPerMailbox) { - AtomicStore(&mailbox->ScheduleMoment, hpnow); - Ctx.IncrementMailboxPushedOutByEventCount(); - LWTRACK(MailboxPushedOutByEventCount, - Ctx.Orbit, - Ctx.PoolId, - Ctx.Executor->GetName(), - executed + 1, - CyclesToDuration(hpnow - hpstart), - Ctx.WorkerId, - recipient.ToString(), - SafeTypeName(actor)); + if (executed + 1 == Ctx.EventsPerMailbox) { + AtomicStore(&mailbox->ScheduleMoment, hpnow); + Ctx.IncrementMailboxPushedOutByEventCount(); + LWTRACK(MailboxPushedOutByEventCount, + Ctx.Orbit, + Ctx.PoolId, + Ctx.Executor->GetName(), + executed + 1, + CyclesToDuration(hpnow - hpstart), + Ctx.WorkerId, + recipient.ToString(), + SafeTypeName(actor)); break; } } else { if (executed == 0) - Ctx.IncrementEmptyMailboxActivation(); - LWTRACK(MailboxEmpty, - Ctx.Orbit, - Ctx.PoolId, - Ctx.Executor->GetName(), - executed, - CyclesToDuration(GetCycleCountFast() - hpstart), - Ctx.WorkerId, - recipient.ToString(), - SafeTypeName(actor)); + Ctx.IncrementEmptyMailboxActivation(); + LWTRACK(MailboxEmpty, + Ctx.Orbit, + Ctx.PoolId, + Ctx.Executor->GetName(), + executed, + CyclesToDuration(GetCycleCountFast() - hpstart), + Ctx.WorkerId, + recipient.ToString(), + SafeTypeName(actor)); break; // empty queue, leave } } NProfiling::TMemoryTagScope::Reset(0); TlsActivationContext = nullptr; - UnlockFromExecution(mailbox, Ctx.Executor, reclaimAsFree, hint, Ctx.WorkerId, RevolvingWriteCounter); - } - - TThreadId TExecutorThread::GetThreadId() const { -#ifdef _linux_ - while (AtomicLoad(&ThreadId) == UnknownThreadId) { - NanoSleep(1000); - } -#endif - return ThreadId; + UnlockFromExecution(mailbox, Ctx.Executor, reclaimAsFree, hint, Ctx.WorkerId, RevolvingWriteCounter); } + TThreadId TExecutorThread::GetThreadId() const { +#ifdef _linux_ + while (AtomicLoad(&ThreadId) == UnknownThreadId) { + NanoSleep(1000); + } +#endif + return ThreadId; + } + void* TExecutorThread::ThreadProc() { -#ifdef _linux_ - pid_t tid = syscall(SYS_gettid); - AtomicSet(ThreadId, (ui64)tid); -#endif - +#ifdef _linux_ + pid_t tid = syscall(SYS_gettid); + AtomicSet(ThreadId, (ui64)tid); +#endif + #ifdef BALLOC ThreadDisableBalloc(); #endif - + if (ThreadName) { ::SetCurrentThreadName(ThreadName); } @@ -304,20 +304,20 @@ namespace NActors { ExecutorPool->SetRealTimeMode(); TAffinityGuard affinity(ExecutorPool->Affinity()); - NHPTimer::STime hpnow = GetCycleCountFast(); + NHPTimer::STime hpnow = GetCycleCountFast(); NHPTimer::STime hpprev = hpnow; ui64 execCount = 0; ui64 readyActivationCount = 0; i64 execCycles = 0; i64 nonExecCycles = 0; - + for (;;) { - if (ui32 activation = ExecutorPool->GetReadyActivation(Ctx, ++RevolvingReadCounter)) { - LWTRACK(ActivationBegin, Ctx.Orbit, Ctx.CpuId, Ctx.PoolId, Ctx.WorkerId, NHPTimer::GetSeconds(Ctx.Lease.GetPreciseExpireTs()) * 1e3); + if (ui32 activation = ExecutorPool->GetReadyActivation(Ctx, ++RevolvingReadCounter)) { + LWTRACK(ActivationBegin, Ctx.Orbit, Ctx.CpuId, Ctx.PoolId, Ctx.WorkerId, NHPTimer::GetSeconds(Ctx.Lease.GetPreciseExpireTs()) * 1e3); readyActivationCount++; - if (TMailboxHeader* header = Ctx.MailboxTable->Get(activation)) { + if (TMailboxHeader* header = Ctx.MailboxTable->Get(activation)) { if (header->LockForExecution()) { - hpnow = GetCycleCountFast(); + hpnow = GetCycleCountFast(); nonExecCycles += hpnow - hpprev; hpprev = hpnow; switch (header->Type) { @@ -337,27 +337,27 @@ namespace NActors { Execute(static_cast<TMailboxTable::TTinyReadAsFilledMailbox*>(header), activation); break; } - hpnow = GetCycleCountFast(); + hpnow = GetCycleCountFast(); execCycles += hpnow - hpprev; hpprev = hpnow; execCount++; if (execCycles + nonExecCycles > 39000000) { // every 15 ms at 2.6GHz, so 1000 items is 15 sec (solomon interval) - LWPROBE(ExecutorThreadStats, ExecutorPool->PoolId, ExecutorPool->GetName(), Ctx.WorkerId, + LWPROBE(ExecutorThreadStats, ExecutorPool->PoolId, ExecutorPool->GetName(), Ctx.WorkerId, execCount, readyActivationCount, NHPTimer::GetSeconds(execCycles) * 1000.0, NHPTimer::GetSeconds(nonExecCycles) * 1000.0); execCount = 0; readyActivationCount = 0; execCycles = 0; nonExecCycles = 0; - Ctx.UpdateThreadTime(); + Ctx.UpdateThreadTime(); } } } - LWTRACK(ActivationEnd, Ctx.Orbit, Ctx.CpuId, Ctx.PoolId, Ctx.WorkerId); - Ctx.Orbit.Reset(); - } else { // no activation means PrepareStop was called so thread must terminate + LWTRACK(ActivationEnd, Ctx.Orbit, Ctx.CpuId, Ctx.PoolId, Ctx.WorkerId); + Ctx.Orbit.Reset(); + } else { // no activation means PrepareStop was called so thread must terminate break; - } + } } return nullptr; } diff --git a/library/cpp/actors/core/executor_thread.h b/library/cpp/actors/core/executor_thread.h index 9d3c573f0d..5599c82e58 100644 --- a/library/cpp/actors/core/executor_thread.h +++ b/library/cpp/actors/core/executor_thread.h @@ -5,23 +5,23 @@ #include "actor.h" #include "actorsystem.h" #include "callstack.h" -#include "probes.h" -#include "worker_context.h" - -#include <library/cpp/actors/util/datetime.h> +#include "probes.h" +#include "worker_context.h" +#include <library/cpp/actors/util/datetime.h> + #include <util/system/thread.h> namespace NActors { - + class TExecutorThread: public ISimpleThread { public: static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TDuration::MilliSeconds(10); static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100; - TExecutorThread(TWorkerId workerId, - TWorkerId cpuId, + TExecutorThread(TWorkerId workerId, + TWorkerId cpuId, TActorSystem* actorSystem, IExecutorPool* executorPool, TMailboxTable* mailboxTable, @@ -29,16 +29,16 @@ namespace NActors { TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX, ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX); - TExecutorThread(TWorkerId workerId, - TActorSystem* actorSystem, - IExecutorPool* executorPool, - TMailboxTable* mailboxTable, - const TString& threadName, - TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX, - ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX) - : TExecutorThread(workerId, 0, actorSystem, executorPool, mailboxTable, threadName, timePerMailbox, eventsPerMailbox) - {} - + TExecutorThread(TWorkerId workerId, + TActorSystem* actorSystem, + IExecutorPool* executorPool, + TMailboxTable* mailboxTable, + const TString& threadName, + TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX, + ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX) + : TExecutorThread(workerId, 0, actorSystem, executorPool, mailboxTable, threadName, timePerMailbox, eventsPerMailbox) + {} + TActorId RegisterActor(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>(), const TActorId& parentId = TActorId()); TActorId RegisterActor(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId = TActorId()); @@ -50,22 +50,22 @@ namespace NActors { void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr); void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr); - bool Send(TAutoPtr<IEventHandle> ev) { -#ifdef USE_ACTOR_CALLSTACK - ev->Callstack = TCallstack::GetTlsCallstack(); - ev->Callstack.Trace(); + bool Send(TAutoPtr<IEventHandle> ev) { +#ifdef USE_ACTOR_CALLSTACK + ev->Callstack = TCallstack::GetTlsCallstack(); + ev->Callstack.Trace(); #endif - Ctx.IncrementSentEvents(); - return ActorSystem->Send(ev); + Ctx.IncrementSentEvents(); + return ActorSystem->Send(ev); } - void GetCurrentStats(TExecutorThreadStats& statsCopy) const { - Ctx.GetCurrentStats(statsCopy); + void GetCurrentStats(TExecutorThreadStats& statsCopy) const { + Ctx.GetCurrentStats(statsCopy); } - TThreadId GetThreadId() const; // blocks, must be called after Start() - TWorkerId GetWorkerId() const { return Ctx.WorkerId; } - + TThreadId GetThreadId() const; // blocks, must be called after Start() + TWorkerId GetWorkerId() const { return Ctx.WorkerId; } + private: void* ThreadProc(); @@ -76,37 +76,37 @@ namespace NActors { TActorSystem* const ActorSystem; private: - // Pool-specific + // Pool-specific IExecutorPool* const ExecutorPool; - // Event-specific (currently executing) + // Event-specific (currently executing) TVector<THolder<IActor>> DyingActors; TActorId CurrentRecipient; - ui64 CurrentActorScheduledEventsCounter = 0; + ui64 CurrentActorScheduledEventsCounter = 0; - // Thread-specific - TWorkerContext Ctx; - ui64 RevolvingReadCounter = 0; - ui64 RevolvingWriteCounter = 0; + // Thread-specific + TWorkerContext Ctx; + ui64 RevolvingReadCounter = 0; + ui64 RevolvingWriteCounter = 0; const TString ThreadName; - volatile TThreadId ThreadId = UnknownThreadId; + volatile TThreadId ThreadId = UnknownThreadId; }; template <typename TMailbox> - void UnlockFromExecution(TMailbox* mailbox, IExecutorPool* executorPool, bool asFree, ui32 hint, TWorkerId workerId, ui64& revolvingWriteCounter) { + void UnlockFromExecution(TMailbox* mailbox, IExecutorPool* executorPool, bool asFree, ui32 hint, TWorkerId workerId, ui64& revolvingWriteCounter) { mailbox->UnlockFromExecution1(); const bool needReschedule1 = (nullptr != mailbox->Head()); if (!asFree) { if (mailbox->UnlockFromExecution2(needReschedule1)) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); + RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); executorPool->ScheduleActivationEx(hint, ++revolvingWriteCounter); } } else { if (mailbox->UnlockAsFree(needReschedule1)) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); + RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); executorPool->ScheduleActivationEx(hint, ++revolvingWriteCounter); } - executorPool->ReclaimMailbox(TMailbox::MailboxType, hint, workerId, ++revolvingWriteCounter); + executorPool->ReclaimMailbox(TMailbox::MailboxType, hint, workerId, ++revolvingWriteCounter); } } } diff --git a/library/cpp/actors/core/lease.h b/library/cpp/actors/core/lease.h index 650ae7b122..3bde281960 100644 --- a/library/cpp/actors/core/lease.h +++ b/library/cpp/actors/core/lease.h @@ -1,56 +1,56 @@ -#pragma once - -#include "defs.h" - -namespace NActors { - // Value representing specific worker's permission for exclusive use of CPU till specific deadline - struct TLease { - // Lower WorkerBits store current fast worker id - // All other higher bits store expiration (hard preemption) timestamp - using TValue = ui64; - TValue Value; - - static constexpr ui64 WorkerIdMask = ui64((1ull << WorkerBits) - 1); - static constexpr ui64 ExpireTsMask = ~WorkerIdMask; - - explicit constexpr TLease(ui64 value) - : Value(value) - {} - - constexpr TLease(TWorkerId workerId, ui64 expireTs) - : Value((workerId & WorkerIdMask) | (expireTs & ExpireTsMask)) - {} - - TWorkerId GetWorkerId() const { - return Value & WorkerIdMask; - } - - TLease NeverExpire() const { - return TLease(Value | ExpireTsMask); - } - - bool IsNeverExpiring() const { - return (Value & ExpireTsMask) == ExpireTsMask; - } - - ui64 GetExpireTs() const { - // Do not truncate worker id - // NOTE: it decrease accuracy, but improves performance - return Value; - } - - ui64 GetPreciseExpireTs() const { - return Value & ExpireTsMask; - } - - operator TValue() const { - return Value; - } - }; - - // Special expire timestamp values - static constexpr ui64 NeverExpire = ui64(-1); - - // Special hard-preemption-in-progress lease - static constexpr TLease HardPreemptionLease = TLease(TLease::WorkerIdMask, NeverExpire); -} +#pragma once + +#include "defs.h" + +namespace NActors { + // Value representing specific worker's permission for exclusive use of CPU till specific deadline + struct TLease { + // Lower WorkerBits store current fast worker id + // All other higher bits store expiration (hard preemption) timestamp + using TValue = ui64; + TValue Value; + + static constexpr ui64 WorkerIdMask = ui64((1ull << WorkerBits) - 1); + static constexpr ui64 ExpireTsMask = ~WorkerIdMask; + + explicit constexpr TLease(ui64 value) + : Value(value) + {} + + constexpr TLease(TWorkerId workerId, ui64 expireTs) + : Value((workerId & WorkerIdMask) | (expireTs & ExpireTsMask)) + {} + + TWorkerId GetWorkerId() const { + return Value & WorkerIdMask; + } + + TLease NeverExpire() const { + return TLease(Value | ExpireTsMask); + } + + bool IsNeverExpiring() const { + return (Value & ExpireTsMask) == ExpireTsMask; + } + + ui64 GetExpireTs() const { + // Do not truncate worker id + // NOTE: it decrease accuracy, but improves performance + return Value; + } + + ui64 GetPreciseExpireTs() const { + return Value & ExpireTsMask; + } + + operator TValue() const { + return Value; + } + }; + + // Special expire timestamp values + static constexpr ui64 NeverExpire = ui64(-1); + + // Special hard-preemption-in-progress lease + static constexpr TLease HardPreemptionLease = TLease(TLease::WorkerIdMask, NeverExpire); +} diff --git a/library/cpp/actors/core/log.cpp b/library/cpp/actors/core/log.cpp index 5f63b5af58..c05a32f020 100644 --- a/library/cpp/actors/core/log.cpp +++ b/library/cpp/actors/core/log.cpp @@ -311,13 +311,13 @@ namespace NActors { void TLoggerActor::RenderComponentPriorities(IOutputStream& str) { using namespace NLog; - HTML(str) { + HTML(str) { H4() { str << "Priority Settings for the Components"; } - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { TABLEH() { str << "Component"; } @@ -330,16 +330,16 @@ namespace NActors { TABLEH() { str << "Sampling Rate"; } - } - } - TABLEBODY() { + } + } + TABLEBODY() { for (EComponent i = Settings->MinVal; i < Settings->MaxVal; i++) { auto name = Settings->ComponentName(i); if (!*name) continue; NLog::TComponentSettings componentSettings = Settings->GetComponentSettings(i); - TABLER() { + TABLER() { TABLED() { str << "<a href='logger?c=" << i << "'>" << name << "</a>"; } @@ -352,11 +352,11 @@ namespace NActors { TABLED() { str << componentSettings.Raw.X.SamplingRate; } - } + } } - } - } - } + } + } + } } /* @@ -412,53 +412,53 @@ namespace NActors { if (hasComponent && !hasPriority && !hasSamplingPriority && !hasSamplingRate) { NLog::TComponentSettings componentSettings = Settings->GetComponentSettings(component); ui32 samplingRate = componentSettings.Raw.X.SamplingRate; - HTML(str) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12") { + HTML(str) { + DIV_CLASS("row") { + DIV_CLASS("col-md-12") { H4() { str << "Current log settings for " << Settings->ComponentName(component) << Endl; } - UL() { - LI() { + UL() { + LI() { str << "Priority: " << NLog::PriorityToString(NLog::EPrio(componentSettings.Raw.X.Level)); - } - LI() { + } + LI() { str << "Sampling priority: " << NLog::PriorityToString(NLog::EPrio(componentSettings.Raw.X.SamplingLevel)); - } - LI() { + } + LI() { str << "Sampling rate: " << samplingRate; - } - } - } - } + } + } + } + } - DIV_CLASS("row") { - DIV_CLASS("col-md-12") { + DIV_CLASS("row") { + DIV_CLASS("col-md-12") { H4() { str << "Change priority" << Endl; } - UL() { + UL() { for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { - LI() { + LI() { str << "<a href='logger?c=" << component << "&p=" << p << "'>" << NLog::PriorityToString(NLog::EPrio(p)) << "</a>"; - } + } } - } + } H4() { str << "Change sampling priority" << Endl; } - UL() { + UL() { for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { - LI() { + LI() { str << "<a href='logger?c=" << component << "&sp=" << p << "'>" << NLog::PriorityToString(NLog::EPrio(p)) << "</a>"; - } + } } - } + } H4() { str << "Change sampling rate" << Endl; } @@ -470,9 +470,9 @@ namespace NActors { H4() { str << "<a href='logger'>Cancel</a>" << Endl; } - } - } - } + } + } + } } else { TString explanation; @@ -489,64 +489,64 @@ namespace NActors { Settings->SetAllowDrop(allowDrop); } - HTML(str) { + HTML(str) { if (!explanation.empty()) { - DIV_CLASS("row") { + DIV_CLASS("row") { DIV_CLASS("col-md-12 alert alert-info") { str << explanation; } - } + } } - DIV_CLASS("row") { - DIV_CLASS("col-md-6") { + DIV_CLASS("row") { + DIV_CLASS("col-md-6") { RenderComponentPriorities(str); } DIV_CLASS("col-md-6") { H4() { str << "Change priority for all components"; } - TABLE_CLASS("table table-condensed") { - TABLEHEAD() { - TABLER() { + TABLE_CLASS("table table-condensed") { + TABLEHEAD() { + TABLER() { TABLEH() { str << "Priority"; } - } - } - TABLEBODY() { + } + } + TABLEBODY() { for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { - TABLER() { + TABLER() { TABLED() { str << "<a href = 'logger?c=-1&p=" << p << "'>" << NLog::PriorityToString(NLog::EPrio(p)) << "</a>"; - } - } + } + } } - } - } + } + } H4() { str << "Change sampling priority for all components"; } - TABLE_CLASS("table table-condensed") { - TABLEHEAD() { - TABLER() { + TABLE_CLASS("table table-condensed") { + TABLEHEAD() { + TABLER() { TABLEH() { str << "Priority"; } - } - } - TABLEBODY() { + } + } + TABLEBODY() { for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { - TABLER() { + TABLER() { TABLED() { str << "<a href = 'logger?c=-1&sp=" << p << "'>" << NLog::PriorityToString(NLog::EPrio(p)) << "</a>"; - } - } + } + } } - } - } + } + } H4() { str << "Change sampling rate for all components"; } @@ -563,27 +563,27 @@ namespace NActors { str << "<input type=\"hidden\" name=\"allowdrop\" value=\"" << (Settings->AllowDrop ? "0" : "1") << "\"/>" << Endl; str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"" << (Settings->AllowDrop ? "Disable" : "Enable") << "\"/>" << Endl; str << "</form>" << Endl; - } - } + } + } Metrics->GetOutputHtml(str); - } + } } ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str())); } - constexpr size_t TimeBufSize = 512; - + constexpr size_t TimeBufSize = 512; + bool TLoggerActor::OutputRecord(TInstant time, NLog::EPrio priority, NLog::EComponent component, const TString& formatted) noexcept try { const auto logPrio = ::ELogPriority(ui16(priority)); - char buf[TimeBufSize]; + char buf[TimeBufSize]; switch (Settings->Format) { case NActors::NLog::TSettings::PLAIN_FULL_FORMAT: { TStringBuilder logRecord; if (Settings->UseLocalTimestamps) { - logRecord << FormatLocalTimestamp(time, buf); + logRecord << FormatLocalTimestamp(time, buf); } else { logRecord << time; } @@ -649,12 +649,12 @@ namespace NActors { Become(&TThis::StateFunc); } - const char* TLoggerActor::FormatLocalTimestamp(TInstant time, char* buf) { + const char* TLoggerActor::FormatLocalTimestamp(TInstant time, char* buf) { struct tm localTime; time.LocalTime(&localTime); - int r = strftime(buf, TimeBufSize, "%Y-%m-%d-%H-%M-%S", &localTime); - Y_VERIFY(r != 0); - return buf; + int r = strftime(buf, TimeBufSize, "%Y-%m-%d-%H-%M-%S", &localTime); + Y_VERIFY(r != 0); + return buf; } TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident, diff --git a/library/cpp/actors/core/log.h b/library/cpp/actors/core/log.h index c11a7cf3c1..32a5abfed2 100644 --- a/library/cpp/actors/core/log.h +++ b/library/cpp/actors/core/log.h @@ -255,7 +255,7 @@ namespace NActors { void RenderComponentPriorities(IOutputStream& str); void LogIgnoredCount(TInstant now); void WriteMessageStat(const NLog::TEvLog& ev); - static const char* FormatLocalTimestamp(TInstant time, char* buf); + static const char* FormatLocalTimestamp(TInstant time, char* buf); }; //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/actors/core/mailbox.cpp b/library/cpp/actors/core/mailbox.cpp index d84b4f9e46..92763dbb1e 100644 --- a/library/cpp/actors/core/mailbox.cpp +++ b/library/cpp/actors/core/mailbox.cpp @@ -1,8 +1,8 @@ #include "mailbox.h" #include "actorsystem.h" -#include <library/cpp/actors/util/datetime.h> - +#include <library/cpp/actors/util/datetime.h> + #include <util/system/sanitizers.h> namespace NActors { @@ -183,7 +183,7 @@ namespace NActors { #endif mailbox->Queue.Push(ev.Release()); if (mailbox->MarkForSchedule()) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); + RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); executorPool->ScheduleActivation(hint); } } @@ -207,7 +207,7 @@ namespace NActors { #endif mailbox->QueueWriter.Push(ev.Release()); if (mailbox->MarkForSchedule()) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); + RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); executorPool->ScheduleActivation(hint); } } @@ -219,7 +219,7 @@ namespace NActors { #endif mailbox->Queue.Push(ev.Release()); if (mailbox->MarkForSchedule()) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); + RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); executorPool->ScheduleActivation(hint); } } @@ -234,7 +234,7 @@ namespace NActors { #endif mailbox->Queue.Push(ev.Release()); if (mailbox->MarkForSchedule()) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); + RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); executorPool->ScheduleActivation(hint); } } @@ -249,7 +249,7 @@ namespace NActors { #endif mailbox->Queue.Push(ev.Release()); if (mailbox->MarkForSchedule()) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); + RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); executorPool->ScheduleActivation(hint); } } @@ -347,7 +347,7 @@ namespace NActors { TMailboxHeader::TMailboxHeader(TMailboxType::EType type) : ExecutionState(TExecutionState::Free) - , Reserved(0) + , Reserved(0) , Type(type) , ActorPack(TMailboxActorPack::Simple) , Knobs(0) diff --git a/library/cpp/actors/core/mailbox.h b/library/cpp/actors/core/mailbox.h index 0bd9c4d314..4022915e1d 100644 --- a/library/cpp/actors/core/mailbox.h +++ b/library/cpp/actors/core/mailbox.h @@ -54,7 +54,7 @@ namespace NActors { }; volatile ui32 ExecutionState; - ui32 Reserved : 4; // never changes, always zero + ui32 Reserved : 4; // never changes, always zero ui32 Type : 4; // never changes ui32 ActorPack : 2; ui32 Knobs : 22; diff --git a/library/cpp/actors/core/mon_stats.h b/library/cpp/actors/core/mon_stats.h index d55552af0c..e2db1e32e6 100644 --- a/library/cpp/actors/core/mon_stats.h +++ b/library/cpp/actors/core/mon_stats.h @@ -63,15 +63,15 @@ namespace NActors { }; struct TExecutorThreadStats { - ui64 SentEvents = 0; - ui64 ReceivedEvents = 0; - ui64 PreemptedEvents = 0; // Number of events experienced hard preemption - ui64 NonDeliveredEvents = 0; - ui64 EmptyMailboxActivation = 0; - ui64 CpuNs = 0; // nanoseconds thread was executing on CPU (accounts for preemtion) - NHPTimer::STime ElapsedTicks = 0; - NHPTimer::STime ParkedTicks = 0; - NHPTimer::STime BlockedTicks = 0; + ui64 SentEvents = 0; + ui64 ReceivedEvents = 0; + ui64 PreemptedEvents = 0; // Number of events experienced hard preemption + ui64 NonDeliveredEvents = 0; + ui64 EmptyMailboxActivation = 0; + ui64 CpuNs = 0; // nanoseconds thread was executing on CPU (accounts for preemtion) + NHPTimer::STime ElapsedTicks = 0; + NHPTimer::STime ParkedTicks = 0; + NHPTimer::STime BlockedTicks = 0; TLogHistogram ActivationTimeHistogram; TLogHistogram EventDeliveryTimeHistogram; TLogHistogram EventProcessingCountHistogram; @@ -80,19 +80,19 @@ namespace NActors { TVector<ui64> ReceivedEventsByActivity; TVector<i64> ActorsAliveByActivity; // the sum should be positive, but per-thread might be negative TVector<ui64> ScheduledEventsByActivity; - ui64 PoolActorRegistrations = 0; - ui64 PoolDestroyedActors = 0; - ui64 PoolAllocatedMailboxes = 0; - ui64 MailboxPushedOutBySoftPreemption = 0; - ui64 MailboxPushedOutByTime = 0; - ui64 MailboxPushedOutByEventCount = 0; + ui64 PoolActorRegistrations = 0; + ui64 PoolDestroyedActors = 0; + ui64 PoolAllocatedMailboxes = 0; + ui64 MailboxPushedOutBySoftPreemption = 0; + ui64 MailboxPushedOutByTime = 0; + ui64 MailboxPushedOutByEventCount = 0; TExecutorThreadStats(size_t activityVecSize = 1) // must be not empty as 0 used as default - : ElapsedTicksByActivity(activityVecSize) + : ElapsedTicksByActivity(activityVecSize) , ReceivedEventsByActivity(activityVecSize) , ActorsAliveByActivity(activityVecSize) , ScheduledEventsByActivity(activityVecSize) - {} + {} template <typename T> static void AggregateOne(TVector<T>& self, const TVector<T>& other) { @@ -107,14 +107,14 @@ namespace NActors { void Aggregate(const TExecutorThreadStats& other) { SentEvents += RelaxedLoad(&other.SentEvents); ReceivedEvents += RelaxedLoad(&other.ReceivedEvents); - PreemptedEvents += RelaxedLoad(&other.PreemptedEvents); + PreemptedEvents += RelaxedLoad(&other.PreemptedEvents); NonDeliveredEvents += RelaxedLoad(&other.NonDeliveredEvents); EmptyMailboxActivation += RelaxedLoad(&other.EmptyMailboxActivation); - CpuNs += RelaxedLoad(&other.CpuNs); + CpuNs += RelaxedLoad(&other.CpuNs); ElapsedTicks += RelaxedLoad(&other.ElapsedTicks); ParkedTicks += RelaxedLoad(&other.ParkedTicks); BlockedTicks += RelaxedLoad(&other.BlockedTicks); - MailboxPushedOutBySoftPreemption += RelaxedLoad(&other.MailboxPushedOutBySoftPreemption); + MailboxPushedOutBySoftPreemption += RelaxedLoad(&other.MailboxPushedOutBySoftPreemption); MailboxPushedOutByTime += RelaxedLoad(&other.MailboxPushedOutByTime); MailboxPushedOutByEventCount += RelaxedLoad(&other.MailboxPushedOutByEventCount); diff --git a/library/cpp/actors/core/probes.cpp b/library/cpp/actors/core/probes.cpp index 7ace83e102..0a9b256f70 100644 --- a/library/cpp/actors/core/probes.cpp +++ b/library/cpp/actors/core/probes.cpp @@ -1,28 +1,28 @@ #include "probes.h" -#include "actorsystem.h" - -#include <util/string/builder.h> - +#include "actorsystem.h" + +#include <util/string/builder.h> + LWTRACE_DEFINE_PROVIDER(ACTORLIB_PROVIDER); - -namespace NActors { - TVector<NLWTrace::TDashboard> LWTraceDashboards(TActorSystemSetup* setup) { - TVector<NLWTrace::TDashboard> result; - - NLWTrace::TDashboard slowDash; - ui32 pools = setup->GetExecutorsCount(); - size_t top = 30; - slowDash.SetName("ActorSystem slow events"); - slowDash.SetDescription(TStringBuilder() << "TOP" << top << " slow event executions >1M cycles for every pool (refresh page to update)"); - for (ui32 pool = 0; pool < pools; pool++) { - auto* row = slowDash.AddRows(); - auto* cell = row->AddCells(); - cell->SetTitle(TStringBuilder() << pool << ":" << setup->GetPoolName(pool)); - cell->SetUrl(TStringBuilder() << "?mode=log&id=.ACTORLIB_PROVIDER.SlowEvent.ppoolId=" << pool << "&s=eventMs&reverse=y&head=30"); - } - result.push_back(slowDash); - - return result; - } -} + +namespace NActors { + TVector<NLWTrace::TDashboard> LWTraceDashboards(TActorSystemSetup* setup) { + TVector<NLWTrace::TDashboard> result; + + NLWTrace::TDashboard slowDash; + ui32 pools = setup->GetExecutorsCount(); + size_t top = 30; + slowDash.SetName("ActorSystem slow events"); + slowDash.SetDescription(TStringBuilder() << "TOP" << top << " slow event executions >1M cycles for every pool (refresh page to update)"); + for (ui32 pool = 0; pool < pools; pool++) { + auto* row = slowDash.AddRows(); + auto* cell = row->AddCells(); + cell->SetTitle(TStringBuilder() << pool << ":" << setup->GetPoolName(pool)); + cell->SetUrl(TStringBuilder() << "?mode=log&id=.ACTORLIB_PROVIDER.SlowEvent.ppoolId=" << pool << "&s=eventMs&reverse=y&head=30"); + } + result.push_back(slowDash); + + return result; + } +} diff --git a/library/cpp/actors/core/probes.h b/library/cpp/actors/core/probes.h index 4912d6dd26..0733cd010d 100644 --- a/library/cpp/actors/core/probes.h +++ b/library/cpp/actors/core/probes.h @@ -1,12 +1,12 @@ #pragma once #include <library/cpp/lwtrace/all.h> -#include <util/generic/vector.h> - -#define LWACTORID(x) (x).RawX1(), (x).RawX2(), (x).NodeId(), (x).PoolID() -#define LWTYPE_ACTORID ui64, ui64, ui32, ui32 -#define LWNAME_ACTORID(n) n "Raw1", n "Raw2", n "NodeId", n "PoolId" +#include <util/generic/vector.h> +#define LWACTORID(x) (x).RawX1(), (x).RawX2(), (x).NodeId(), (x).PoolID() +#define LWTYPE_ACTORID ui64, ui64, ui32, ui32 +#define LWNAME_ACTORID(n) n "Raw1", n "Raw2", n "NodeId", n "PoolId" + #define ACTORLIB_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ PROBE(SlowEvent, GROUPS("ActorLibSlow"), \ TYPES(ui32, double, TString, TString, TString), \ @@ -23,27 +23,27 @@ PROBE(SlowRegisterAdd, GROUPS("ActorLibSlow"), \ TYPES(ui32, double), \ NAMES("poolId", "registerAddMs")) \ - PROBE(MailboxPushedOutBySoftPreemption, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ - TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ - NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ - PROBE(MailboxPushedOutByTime, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ - TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ - NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ - PROBE(MailboxPushedOutByEventCount, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ - TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ - NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ - PROBE(MailboxEmpty, GROUPS("ActorLibMailbox"), \ - TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ - NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ - PROBE(ActivationBegin, GROUPS(), \ - TYPES(ui32, ui32, ui32, double), \ - NAMES("cpu", "poolId", "workerId", "expireMs")) \ - PROBE(ActivationEnd, GROUPS(), \ - TYPES(ui32, ui32, ui32), \ - NAMES("cpu", "poolId", "workerId")) \ + PROBE(MailboxPushedOutBySoftPreemption, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ + TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ + NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ + PROBE(MailboxPushedOutByTime, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ + TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ + NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ + PROBE(MailboxPushedOutByEventCount, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ + TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ + NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ + PROBE(MailboxEmpty, GROUPS("ActorLibMailbox"), \ + TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ + NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ + PROBE(ActivationBegin, GROUPS(), \ + TYPES(ui32, ui32, ui32, double), \ + NAMES("cpu", "poolId", "workerId", "expireMs")) \ + PROBE(ActivationEnd, GROUPS(), \ + TYPES(ui32, ui32, ui32), \ + NAMES("cpu", "poolId", "workerId")) \ PROBE(ExecutorThreadStats, GROUPS("ActorLibStats"), \ - TYPES(ui32, TString, ui64, ui64, ui64, double, double), \ - NAMES("poolId", "pool", "workerId", "execCount", "readyActivationCount", "execMs", "nonExecMs")) \ + TYPES(ui32, TString, ui64, ui64, ui64, double, double), \ + NAMES("poolId", "pool", "workerId", "execCount", "readyActivationCount", "execMs", "nonExecMs")) \ PROBE(SlowICReadLoopAdjustSize, GROUPS("ActorLibSlowIC"), \ TYPES(double), \ NAMES("icReadLoopAdjustSizeMs")) \ @@ -75,102 +75,102 @@ TYPES(ui64, ui64, ui32, ui32, ui64, ui64), \ NAMES("timeUs", "timerfd_expirations", "eventsGottenFromQueues", "eventsSent", \ "eventsInSendQueue", "eventSchedulingErrorUs")) \ - PROBE(ForwardEvent, GROUPS("Orbit", "InterconnectSessionTCP"), \ - TYPES(ui32, ui32, ui32, LWTYPE_ACTORID, LWTYPE_ACTORID, ui64, ui32), \ - NAMES("peerId", "type", "flags", LWNAME_ACTORID("r"), LWNAME_ACTORID("s"), \ - "cookie", "eventSerializedSize")) \ - PROBE(EnqueueEvent, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui64, TDuration, ui16, ui64, ui64), \ - NAMES("peerId", "numEventsInReadyChannels", "enqueueBlockedTotalMs", "channelId", "queueSizeInEvents", "queueSizeInBytes")) \ - PROBE(SerializeToPacketBegin, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui16, ui64), \ - NAMES("peerId", "channelId", "outputQueueSize")) \ - PROBE(SerializeToPacketEnd, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui16, ui64, ui64), \ - NAMES("peerId", "channelId", "outputQueueSize", "offsetInPacket")) \ - PROBE(FillSendingBuffer, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui32, ui64, TDuration), \ - NAMES("peerId", "taskBytesGenerated", "numEventsInReadyChannelsBehind", "fillBlockedTotalMs")) \ - PROBE(PacketGenerated, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui64, ui64, ui64, ui64), \ - NAMES("peerId", "bytesUnwritten", "inflightBytes", "packetsGenerated", "packetSize")) \ - PROBE(PacketWrittenToSocket, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui64, bool, ui64, ui64, TDuration, int), \ - NAMES("peerId", "packetsWrittenToSocket", "triedWriting", "packetDataSize", "bytesUnwritten", "writeBlockedTotalMs", "fd")) \ - PROBE(GenerateTraffic, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double, ui64, ui32, ui64), \ - NAMES("peerId", "generateTrafficMs", "dataBytesSent", "generatedPackets", "generatedBytes")) \ - PROBE(WriteToSocket, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui64, ui64, ui64, ui64, TDuration, int), \ - NAMES("peerId", "bytesWritten", "packetsWritten", "packetsWrittenToSocket", "bytesUnwritten", "writeBlockedTotalMs", "fd")) \ - PROBE(UpdateFromInputSession, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "pingMs")) \ - PROBE(UnblockByDropConfirmed, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "updateDeliveryMs")) \ - PROBE(DropConfirmed, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui64, ui64), \ - NAMES("peerId", "droppedBytes", "inflightBytes")) \ - PROBE(StartRam, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32), \ - NAMES("peerId")) \ - PROBE(FinishRam, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "ramMs")) \ - PROBE(SkipGenerateTraffic, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "elapsedSinceRamMs")) \ - PROBE(StartBatching, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "batchPeriodMs")) \ - PROBE(FinishBatching, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "finishBatchDeliveryMs")) \ - PROBE(BlockedWrite, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double, ui64), \ - NAMES("peerId", "sendQueueSize", "writtenBytes")) \ - PROBE(ReadyWrite, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double, double), \ - NAMES("peerId", "readyWriteDeliveryMs", "blockMs")) \ - PROBE(EpollStartWaitIn, GROUPS("EpollThread"), \ - TYPES(), \ - NAMES()) \ - PROBE(EpollFinishWaitIn, GROUPS("EpollThread"), \ - TYPES(i32), \ - NAMES("eventsCount")) \ - PROBE(EpollWaitOut, GROUPS("EpollThread"), \ - TYPES(i32), \ - NAMES("eventsCount")) \ - PROBE(EpollSendReadyRead, GROUPS("EpollThread"), \ - TYPES(bool, bool, int), \ - NAMES("hangup", "event", "fd")) \ - PROBE(EpollSendReadyWrite, GROUPS("EpollThread"), \ - TYPES(bool, bool, int), \ - NAMES("hangup", "event", "fd")) \ - PROBE(HardPreemption, GROUPS("UnitedWorker"), \ - TYPES(ui32, ui32, ui32, ui32), \ - NAMES("cpu", "prevPoolId", "prevWorkerId", "nextWorkerId")) \ - PROBE(SetPreemptionTimer, GROUPS("UnitedWorker", "PreemptionTimer"), \ - TYPES(ui32, ui32, int, double, double), \ - NAMES("cpu", "workerId", "fd", "nowMs", "preemptMs")) \ - PROBE(ResetPreemptionTimer, GROUPS("UnitedWorker", "PreemptionTimer"), \ - TYPES(ui32, ui32, int, double, double), \ - NAMES("cpu", "workerId", "fd", "nowMs", "preemptMs")) \ - PROBE(SlowWorkerActionRace, GROUPS("UnitedWorker"), \ - TYPES(ui32, ui32, ui64), \ - NAMES("cpu", "poolId", "slowPoolsMask")) \ - PROBE(PoolStats, GROUPS("PoolCpuBalancer"), \ - TYPES(ui32, TString, ui64, ui8, ui8, double, double, double, ui64, ui64, ui64), \ - NAMES("poolId", "pool", "currentCpus", "loadClass", "priority", "scaleFactor", "cpuIdle", "cpuLoad", "importance", "addImportance", "subImportance")) \ - PROBE(MoveCpu, GROUPS("PoolCpuBalancer"), \ - TYPES(ui32, ui64, TString, TString, ui32), \ - NAMES("fromPoolId", "toPoolId", "fromPool", "toPool", "cpu")) \ + PROBE(ForwardEvent, GROUPS("Orbit", "InterconnectSessionTCP"), \ + TYPES(ui32, ui32, ui32, LWTYPE_ACTORID, LWTYPE_ACTORID, ui64, ui32), \ + NAMES("peerId", "type", "flags", LWNAME_ACTORID("r"), LWNAME_ACTORID("s"), \ + "cookie", "eventSerializedSize")) \ + PROBE(EnqueueEvent, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, ui64, TDuration, ui16, ui64, ui64), \ + NAMES("peerId", "numEventsInReadyChannels", "enqueueBlockedTotalMs", "channelId", "queueSizeInEvents", "queueSizeInBytes")) \ + PROBE(SerializeToPacketBegin, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, ui16, ui64), \ + NAMES("peerId", "channelId", "outputQueueSize")) \ + PROBE(SerializeToPacketEnd, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, ui16, ui64, ui64), \ + NAMES("peerId", "channelId", "outputQueueSize", "offsetInPacket")) \ + PROBE(FillSendingBuffer, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, ui32, ui64, TDuration), \ + NAMES("peerId", "taskBytesGenerated", "numEventsInReadyChannelsBehind", "fillBlockedTotalMs")) \ + PROBE(PacketGenerated, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, ui64, ui64, ui64, ui64), \ + NAMES("peerId", "bytesUnwritten", "inflightBytes", "packetsGenerated", "packetSize")) \ + PROBE(PacketWrittenToSocket, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, ui64, bool, ui64, ui64, TDuration, int), \ + NAMES("peerId", "packetsWrittenToSocket", "triedWriting", "packetDataSize", "bytesUnwritten", "writeBlockedTotalMs", "fd")) \ + PROBE(GenerateTraffic, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, double, ui64, ui32, ui64), \ + NAMES("peerId", "generateTrafficMs", "dataBytesSent", "generatedPackets", "generatedBytes")) \ + PROBE(WriteToSocket, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, ui64, ui64, ui64, ui64, TDuration, int), \ + NAMES("peerId", "bytesWritten", "packetsWritten", "packetsWrittenToSocket", "bytesUnwritten", "writeBlockedTotalMs", "fd")) \ + PROBE(UpdateFromInputSession, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, double), \ + NAMES("peerId", "pingMs")) \ + PROBE(UnblockByDropConfirmed, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, double), \ + NAMES("peerId", "updateDeliveryMs")) \ + PROBE(DropConfirmed, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, ui64, ui64), \ + NAMES("peerId", "droppedBytes", "inflightBytes")) \ + PROBE(StartRam, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32), \ + NAMES("peerId")) \ + PROBE(FinishRam, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, double), \ + NAMES("peerId", "ramMs")) \ + PROBE(SkipGenerateTraffic, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, double), \ + NAMES("peerId", "elapsedSinceRamMs")) \ + PROBE(StartBatching, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, double), \ + NAMES("peerId", "batchPeriodMs")) \ + PROBE(FinishBatching, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, double), \ + NAMES("peerId", "finishBatchDeliveryMs")) \ + PROBE(BlockedWrite, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, double, ui64), \ + NAMES("peerId", "sendQueueSize", "writtenBytes")) \ + PROBE(ReadyWrite, GROUPS("InterconnectSessionTCP"), \ + TYPES(ui32, double, double), \ + NAMES("peerId", "readyWriteDeliveryMs", "blockMs")) \ + PROBE(EpollStartWaitIn, GROUPS("EpollThread"), \ + TYPES(), \ + NAMES()) \ + PROBE(EpollFinishWaitIn, GROUPS("EpollThread"), \ + TYPES(i32), \ + NAMES("eventsCount")) \ + PROBE(EpollWaitOut, GROUPS("EpollThread"), \ + TYPES(i32), \ + NAMES("eventsCount")) \ + PROBE(EpollSendReadyRead, GROUPS("EpollThread"), \ + TYPES(bool, bool, int), \ + NAMES("hangup", "event", "fd")) \ + PROBE(EpollSendReadyWrite, GROUPS("EpollThread"), \ + TYPES(bool, bool, int), \ + NAMES("hangup", "event", "fd")) \ + PROBE(HardPreemption, GROUPS("UnitedWorker"), \ + TYPES(ui32, ui32, ui32, ui32), \ + NAMES("cpu", "prevPoolId", "prevWorkerId", "nextWorkerId")) \ + PROBE(SetPreemptionTimer, GROUPS("UnitedWorker", "PreemptionTimer"), \ + TYPES(ui32, ui32, int, double, double), \ + NAMES("cpu", "workerId", "fd", "nowMs", "preemptMs")) \ + PROBE(ResetPreemptionTimer, GROUPS("UnitedWorker", "PreemptionTimer"), \ + TYPES(ui32, ui32, int, double, double), \ + NAMES("cpu", "workerId", "fd", "nowMs", "preemptMs")) \ + PROBE(SlowWorkerActionRace, GROUPS("UnitedWorker"), \ + TYPES(ui32, ui32, ui64), \ + NAMES("cpu", "poolId", "slowPoolsMask")) \ + PROBE(PoolStats, GROUPS("PoolCpuBalancer"), \ + TYPES(ui32, TString, ui64, ui8, ui8, double, double, double, ui64, ui64, ui64), \ + NAMES("poolId", "pool", "currentCpus", "loadClass", "priority", "scaleFactor", "cpuIdle", "cpuLoad", "importance", "addImportance", "subImportance")) \ + PROBE(MoveCpu, GROUPS("PoolCpuBalancer"), \ + TYPES(ui32, ui64, TString, TString, ui32), \ + NAMES("fromPoolId", "toPoolId", "fromPool", "toPool", "cpu")) \ /**/ LWTRACE_DECLARE_PROVIDER(ACTORLIB_PROVIDER) - -namespace NActors { - struct TActorSystemSetup; - TVector<NLWTrace::TDashboard> LWTraceDashboards(TActorSystemSetup* setup); -} + +namespace NActors { + struct TActorSystemSetup; + TVector<NLWTrace::TDashboard> LWTraceDashboards(TActorSystemSetup* setup); +} diff --git a/library/cpp/actors/core/scheduler_actor.cpp b/library/cpp/actors/core/scheduler_actor.cpp index febc5e40dd..7e38a41e30 100644 --- a/library/cpp/actors/core/scheduler_actor.cpp +++ b/library/cpp/actors/core/scheduler_actor.cpp @@ -116,11 +116,11 @@ namespace NActors { void TryUpdateTime(NHPTimer::STime* lastTimeUpdate) { NHPTimer::STime hpnow; - GetTimeFast(&hpnow); + GetTimeFast(&hpnow); const ui64 elapsedCycles = hpnow > *lastTimeUpdate ? hpnow - *lastTimeUpdate : 0; if (elapsedCycles > Cfg.ResolutionMicroseconds * (NHPTimer::GetCyclesPerSecond() / IntrasecondThreshold)) { UpdateTime(); - GetTimeFast(lastTimeUpdate); + GetTimeFast(lastTimeUpdate); } } diff --git a/library/cpp/actors/core/scheduler_basic.cpp b/library/cpp/actors/core/scheduler_basic.cpp index fba200e16b..715cfb787d 100644 --- a/library/cpp/actors/core/scheduler_basic.cpp +++ b/library/cpp/actors/core/scheduler_basic.cpp @@ -1,9 +1,9 @@ #include "scheduler_basic.h" #include "scheduler_queue.h" -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> #include <library/cpp/actors/util/thread.h> - + #ifdef BALLOC #include <library/cpp/balloc/optional/operators.h> #endif @@ -61,7 +61,7 @@ namespace NActors { ui64 activeTick = AlignUp<ui64>(throttledMonotonic, IntrasecondThreshold); TAutoPtr<TMomentMap> activeSec; - NHPTimer::STime hpprev = GetCycleCountFast(); + NHPTimer::STime hpprev = GetCycleCountFast(); ui64 nextTimestamp = TInstant::Now().MicroSeconds(); ui64 nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds()); @@ -170,7 +170,7 @@ namespace NActors { } } - NHPTimer::STime hpnow = GetCycleCountFast(); + NHPTimer::STime hpnow = GetCycleCountFast(); if (MonCounters) { *MonCounters->QueueSize -= eventsSent + eventsDropped; @@ -202,7 +202,7 @@ namespace NActors { NanoSleep(delta * 1000); // ok, looks like we should sleep a bit. // Don't count sleep in elapsed microseconds - hpprev = GetCycleCountFast(); + hpprev = GetCycleCountFast(); nextTimestamp = TInstant::Now().MicroSeconds(); nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds()); } @@ -218,7 +218,7 @@ namespace NActors { *CurrentMonotonic = GetMonotonicMicroSeconds(); } - void TBasicSchedulerThread::PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) { + void TBasicSchedulerThread::PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) { Y_VERIFY(scheduleReadersCount > 0); TotalReaders = scheduleReadersCount; Readers.Reset(new NSchedulerQueue::TReader*[scheduleReadersCount]); diff --git a/library/cpp/actors/core/scheduler_basic.h b/library/cpp/actors/core/scheduler_basic.h index 2ccde39235..16a5b005bd 100644 --- a/library/cpp/actors/core/scheduler_basic.h +++ b/library/cpp/actors/core/scheduler_basic.h @@ -42,7 +42,7 @@ namespace NActors { ~TBasicSchedulerThread(); void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) override; - void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override; + void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override; void PrepareStart() override; void Start() override; @@ -61,7 +61,7 @@ namespace NActors { *currentMonotonic = GetMonotonicMicroSeconds(); } - void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override { + void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override { Y_UNUSED(readers); Y_UNUSED(scheduleReadersCount); } diff --git a/library/cpp/actors/core/ut/ya.make b/library/cpp/actors/core/ut/ya.make index 3ee28d5850..64ab864b4a 100644 --- a/library/cpp/actors/core/ut/ya.make +++ b/library/cpp/actors/core/ut/ya.make @@ -33,11 +33,11 @@ SRCS( actor_ut.cpp actorsystem_ut.cpp ask_ut.cpp - balancer_ut.cpp + balancer_ut.cpp event_pb_payload_ut.cpp event_pb_ut.cpp executor_pool_basic_ut.cpp - executor_pool_united_ut.cpp + executor_pool_united_ut.cpp log_ut.cpp memory_tracker_ut.cpp scheduler_actor_ut.cpp diff --git a/library/cpp/actors/core/worker_context.cpp b/library/cpp/actors/core/worker_context.cpp index ada6c997d4..55b50f4708 100644 --- a/library/cpp/actors/core/worker_context.cpp +++ b/library/cpp/actors/core/worker_context.cpp @@ -1,7 +1,7 @@ -#include "worker_context.h" -#include "probes.h" - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - -} +#include "worker_context.h" +#include "probes.h" + +namespace NActors { + LWTRACE_USING(ACTORLIB_PROVIDER); + +} diff --git a/library/cpp/actors/core/worker_context.h b/library/cpp/actors/core/worker_context.h index b4c37a7629..d4a9a5e6ee 100644 --- a/library/cpp/actors/core/worker_context.h +++ b/library/cpp/actors/core/worker_context.h @@ -1,175 +1,175 @@ -#pragma once - -#include "defs.h" - -#include "actorsystem.h" -#include "event.h" -#include "lease.h" -#include "mailbox.h" -#include "mon_stats.h" - -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/util/intrinsics.h> -#include <library/cpp/actors/util/thread.h> - -#include <library/cpp/lwtrace/shuttle.h> - -namespace NActors { - struct TWorkerContext { - const TWorkerId WorkerId; - const TCpuId CpuId; - TLease Lease; - IExecutorPool* Executor = nullptr; - TMailboxTable* MailboxTable = nullptr; - ui64 TimePerMailboxTs = 0; - ui32 EventsPerMailbox = 0; - ui64 SoftDeadlineTs = ui64(-1); - TExecutorThreadStats* Stats = &WorkerStats; // pool stats - TExecutorThreadStats WorkerStats; - TPoolId PoolId = MaxPools; - mutable NLWTrace::TOrbit Orbit; - - TWorkerContext(TWorkerId workerId, TCpuId cpuId, size_t activityVecSize) - : WorkerId(workerId) - , CpuId(cpuId) - , Lease(WorkerId, NeverExpire) - , WorkerStats(activityVecSize) - {} - -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - void GetCurrentStats(TExecutorThreadStats& statsCopy) const { - statsCopy = TExecutorThreadStats(); - statsCopy.Aggregate(*Stats); - } - - void AddElapsedCycles(ui32 activityType, i64 elapsed) { - Y_VERIFY_DEBUG(activityType < Stats->MaxActivityType()); - RelaxedStore(&Stats->ElapsedTicks, RelaxedLoad(&Stats->ElapsedTicks) + elapsed); - RelaxedStore(&Stats->ElapsedTicksByActivity[activityType], RelaxedLoad(&Stats->ElapsedTicksByActivity[activityType]) + elapsed); - } - - void AddParkedCycles(i64 elapsed) { - RelaxedStore(&Stats->ParkedTicks, RelaxedLoad(&Stats->ParkedTicks) + elapsed); - } - - void AddBlockedCycles(i64 elapsed) { - RelaxedStore(&Stats->BlockedTicks, RelaxedLoad(&Stats->BlockedTicks) + elapsed); - } - - void IncrementSentEvents() { - RelaxedStore(&Stats->SentEvents, RelaxedLoad(&Stats->SentEvents) + 1); - } - - void IncrementPreemptedEvents() { - RelaxedStore(&Stats->PreemptedEvents, RelaxedLoad(&Stats->PreemptedEvents) + 1); - } - - void DecrementActorsAliveByActivity(ui32 activityType) { - if (activityType >= Stats->MaxActivityType()) { - activityType = 0; - } - RelaxedStore(&Stats->ActorsAliveByActivity[activityType], Stats->ActorsAliveByActivity[activityType] - 1); - } - - inline void IncrementNonDeliveredEvents() { - RelaxedStore(&Stats->NonDeliveredEvents, RelaxedLoad(&Stats->NonDeliveredEvents) + 1); - } - - inline void IncrementMailboxPushedOutBySoftPreemption() { - RelaxedStore(&Stats->MailboxPushedOutBySoftPreemption, RelaxedLoad(&Stats->MailboxPushedOutBySoftPreemption) + 1); - } - - inline void IncrementMailboxPushedOutByTime() { - RelaxedStore(&Stats->MailboxPushedOutByTime, RelaxedLoad(&Stats->MailboxPushedOutByTime) + 1); - } - - inline void IncrementMailboxPushedOutByEventCount() { - RelaxedStore(&Stats->MailboxPushedOutByEventCount, RelaxedLoad(&Stats->MailboxPushedOutByEventCount) + 1); - } - - inline void IncrementEmptyMailboxActivation() { - RelaxedStore(&Stats->EmptyMailboxActivation, RelaxedLoad(&Stats->EmptyMailboxActivation) + 1); - } - - double AddActivationStats(i64 scheduleTs, i64 deliveredTs) { - i64 ts = deliveredTs > scheduleTs ? deliveredTs - scheduleTs : 0; - double usec = NHPTimer::GetSeconds(ts) * 1000000.0; - Stats->ActivationTimeHistogram.Add(usec); - return usec; - } - - ui64 AddEventDeliveryStats(i64 sentTs, i64 deliveredTs) { - ui64 usecDeliv = deliveredTs > sentTs ? NHPTimer::GetSeconds(deliveredTs - sentTs) * 1000000 : 0; - Stats->EventDeliveryTimeHistogram.Add(usecDeliv); - return usecDeliv; - } - - i64 AddEventProcessingStats(i64 deliveredTs, i64 processedTs, ui32 activityType, ui64 scheduled) { - i64 elapsed = processedTs - deliveredTs; - ui64 usecElapsed = NHPTimer::GetSeconds(elapsed) * 1000000; - activityType = (activityType >= Stats->MaxActivityType()) ? 0 : activityType; - Stats->EventProcessingCountHistogram.Add(usecElapsed); - Stats->EventProcessingTimeHistogram.Add(usecElapsed, elapsed); - RelaxedStore(&Stats->ReceivedEvents, RelaxedLoad(&Stats->ReceivedEvents) + 1); - RelaxedStore(&Stats->ReceivedEventsByActivity[activityType], RelaxedLoad(&Stats->ReceivedEventsByActivity[activityType]) + 1); - RelaxedStore(&Stats->ScheduledEventsByActivity[activityType], RelaxedLoad(&Stats->ScheduledEventsByActivity[activityType]) + scheduled); - AddElapsedCycles(activityType, elapsed); - return elapsed; - } - - void UpdateActorsStats(size_t dyingActorsCnt) { - if (dyingActorsCnt) { - AtomicAdd(Executor->DestroyedActors, dyingActorsCnt); - } - RelaxedStore(&Stats->PoolDestroyedActors, (ui64)RelaxedLoad(&Executor->DestroyedActors)); - RelaxedStore(&Stats->PoolActorRegistrations, (ui64)RelaxedLoad(&Executor->ActorRegistrations)); - RelaxedStore(&Stats->PoolAllocatedMailboxes, MailboxTable->GetAllocatedMailboxCount()); - } - - void UpdateThreadTime() { - RelaxedStore(&WorkerStats.CpuNs, ThreadCPUTime() * 1000); - } -#else - void GetCurrentStats(TExecutorThreadStats&) const {} - inline void AddElapsedCycles(ui32, i64) {} - inline void AddParkedCycles(i64) {} - inline void AddBlockedCycles(i64) {} - inline void IncrementSentEvents() {} - inline void IncrementPreemptedEvents() {} - inline void IncrementMailboxPushedOutBySoftPreemption() {} - inline void IncrementMailboxPushedOutByTime() {} - inline void IncrementMailboxPushedOutByEventCount() {} - inline void IncrementEmptyMailboxActivation() {} - void DecrementActorsAliveByActivity(ui32) {} - void IncrementNonDeliveredEvents() {} - double AddActivationStats(i64, i64) { return 0; } - ui64 AddEventDeliveryStats(i64, i64) { return 0; } - i64 AddEventProcessingStats(i64, i64, ui32, ui64) { return 0; } - void UpdateActorsStats(size_t, IExecutorPool*) {} - void UpdateThreadTime() {} -#endif - - void Switch(IExecutorPool* executor, - TMailboxTable* mailboxTable, - ui64 timePerMailboxTs, - ui32 eventsPerMailbox, - ui64 softDeadlineTs, - TExecutorThreadStats* stats) - { - Executor = executor; - MailboxTable = mailboxTable; - TimePerMailboxTs = timePerMailboxTs; - EventsPerMailbox = eventsPerMailbox; - SoftDeadlineTs = softDeadlineTs; - Stats = stats; - PoolId = Executor ? Executor->PoolId : MaxPools; - } - - void SwitchToIdle() { - Executor = nullptr; - MailboxTable = nullptr; - //Stats = &WorkerStats; // TODO: in actorsystem 2.0 idle stats cannot be related to specific pool - PoolId = MaxPools; - } - }; -} +#pragma once + +#include "defs.h" + +#include "actorsystem.h" +#include "event.h" +#include "lease.h" +#include "mailbox.h" +#include "mon_stats.h" + +#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/intrinsics.h> +#include <library/cpp/actors/util/thread.h> + +#include <library/cpp/lwtrace/shuttle.h> + +namespace NActors { + struct TWorkerContext { + const TWorkerId WorkerId; + const TCpuId CpuId; + TLease Lease; + IExecutorPool* Executor = nullptr; + TMailboxTable* MailboxTable = nullptr; + ui64 TimePerMailboxTs = 0; + ui32 EventsPerMailbox = 0; + ui64 SoftDeadlineTs = ui64(-1); + TExecutorThreadStats* Stats = &WorkerStats; // pool stats + TExecutorThreadStats WorkerStats; + TPoolId PoolId = MaxPools; + mutable NLWTrace::TOrbit Orbit; + + TWorkerContext(TWorkerId workerId, TCpuId cpuId, size_t activityVecSize) + : WorkerId(workerId) + , CpuId(cpuId) + , Lease(WorkerId, NeverExpire) + , WorkerStats(activityVecSize) + {} + +#ifdef ACTORSLIB_COLLECT_EXEC_STATS + void GetCurrentStats(TExecutorThreadStats& statsCopy) const { + statsCopy = TExecutorThreadStats(); + statsCopy.Aggregate(*Stats); + } + + void AddElapsedCycles(ui32 activityType, i64 elapsed) { + Y_VERIFY_DEBUG(activityType < Stats->MaxActivityType()); + RelaxedStore(&Stats->ElapsedTicks, RelaxedLoad(&Stats->ElapsedTicks) + elapsed); + RelaxedStore(&Stats->ElapsedTicksByActivity[activityType], RelaxedLoad(&Stats->ElapsedTicksByActivity[activityType]) + elapsed); + } + + void AddParkedCycles(i64 elapsed) { + RelaxedStore(&Stats->ParkedTicks, RelaxedLoad(&Stats->ParkedTicks) + elapsed); + } + + void AddBlockedCycles(i64 elapsed) { + RelaxedStore(&Stats->BlockedTicks, RelaxedLoad(&Stats->BlockedTicks) + elapsed); + } + + void IncrementSentEvents() { + RelaxedStore(&Stats->SentEvents, RelaxedLoad(&Stats->SentEvents) + 1); + } + + void IncrementPreemptedEvents() { + RelaxedStore(&Stats->PreemptedEvents, RelaxedLoad(&Stats->PreemptedEvents) + 1); + } + + void DecrementActorsAliveByActivity(ui32 activityType) { + if (activityType >= Stats->MaxActivityType()) { + activityType = 0; + } + RelaxedStore(&Stats->ActorsAliveByActivity[activityType], Stats->ActorsAliveByActivity[activityType] - 1); + } + + inline void IncrementNonDeliveredEvents() { + RelaxedStore(&Stats->NonDeliveredEvents, RelaxedLoad(&Stats->NonDeliveredEvents) + 1); + } + + inline void IncrementMailboxPushedOutBySoftPreemption() { + RelaxedStore(&Stats->MailboxPushedOutBySoftPreemption, RelaxedLoad(&Stats->MailboxPushedOutBySoftPreemption) + 1); + } + + inline void IncrementMailboxPushedOutByTime() { + RelaxedStore(&Stats->MailboxPushedOutByTime, RelaxedLoad(&Stats->MailboxPushedOutByTime) + 1); + } + + inline void IncrementMailboxPushedOutByEventCount() { + RelaxedStore(&Stats->MailboxPushedOutByEventCount, RelaxedLoad(&Stats->MailboxPushedOutByEventCount) + 1); + } + + inline void IncrementEmptyMailboxActivation() { + RelaxedStore(&Stats->EmptyMailboxActivation, RelaxedLoad(&Stats->EmptyMailboxActivation) + 1); + } + + double AddActivationStats(i64 scheduleTs, i64 deliveredTs) { + i64 ts = deliveredTs > scheduleTs ? deliveredTs - scheduleTs : 0; + double usec = NHPTimer::GetSeconds(ts) * 1000000.0; + Stats->ActivationTimeHistogram.Add(usec); + return usec; + } + + ui64 AddEventDeliveryStats(i64 sentTs, i64 deliveredTs) { + ui64 usecDeliv = deliveredTs > sentTs ? NHPTimer::GetSeconds(deliveredTs - sentTs) * 1000000 : 0; + Stats->EventDeliveryTimeHistogram.Add(usecDeliv); + return usecDeliv; + } + + i64 AddEventProcessingStats(i64 deliveredTs, i64 processedTs, ui32 activityType, ui64 scheduled) { + i64 elapsed = processedTs - deliveredTs; + ui64 usecElapsed = NHPTimer::GetSeconds(elapsed) * 1000000; + activityType = (activityType >= Stats->MaxActivityType()) ? 0 : activityType; + Stats->EventProcessingCountHistogram.Add(usecElapsed); + Stats->EventProcessingTimeHistogram.Add(usecElapsed, elapsed); + RelaxedStore(&Stats->ReceivedEvents, RelaxedLoad(&Stats->ReceivedEvents) + 1); + RelaxedStore(&Stats->ReceivedEventsByActivity[activityType], RelaxedLoad(&Stats->ReceivedEventsByActivity[activityType]) + 1); + RelaxedStore(&Stats->ScheduledEventsByActivity[activityType], RelaxedLoad(&Stats->ScheduledEventsByActivity[activityType]) + scheduled); + AddElapsedCycles(activityType, elapsed); + return elapsed; + } + + void UpdateActorsStats(size_t dyingActorsCnt) { + if (dyingActorsCnt) { + AtomicAdd(Executor->DestroyedActors, dyingActorsCnt); + } + RelaxedStore(&Stats->PoolDestroyedActors, (ui64)RelaxedLoad(&Executor->DestroyedActors)); + RelaxedStore(&Stats->PoolActorRegistrations, (ui64)RelaxedLoad(&Executor->ActorRegistrations)); + RelaxedStore(&Stats->PoolAllocatedMailboxes, MailboxTable->GetAllocatedMailboxCount()); + } + + void UpdateThreadTime() { + RelaxedStore(&WorkerStats.CpuNs, ThreadCPUTime() * 1000); + } +#else + void GetCurrentStats(TExecutorThreadStats&) const {} + inline void AddElapsedCycles(ui32, i64) {} + inline void AddParkedCycles(i64) {} + inline void AddBlockedCycles(i64) {} + inline void IncrementSentEvents() {} + inline void IncrementPreemptedEvents() {} + inline void IncrementMailboxPushedOutBySoftPreemption() {} + inline void IncrementMailboxPushedOutByTime() {} + inline void IncrementMailboxPushedOutByEventCount() {} + inline void IncrementEmptyMailboxActivation() {} + void DecrementActorsAliveByActivity(ui32) {} + void IncrementNonDeliveredEvents() {} + double AddActivationStats(i64, i64) { return 0; } + ui64 AddEventDeliveryStats(i64, i64) { return 0; } + i64 AddEventProcessingStats(i64, i64, ui32, ui64) { return 0; } + void UpdateActorsStats(size_t, IExecutorPool*) {} + void UpdateThreadTime() {} +#endif + + void Switch(IExecutorPool* executor, + TMailboxTable* mailboxTable, + ui64 timePerMailboxTs, + ui32 eventsPerMailbox, + ui64 softDeadlineTs, + TExecutorThreadStats* stats) + { + Executor = executor; + MailboxTable = mailboxTable; + TimePerMailboxTs = timePerMailboxTs; + EventsPerMailbox = eventsPerMailbox; + SoftDeadlineTs = softDeadlineTs; + Stats = stats; + PoolId = Executor ? Executor->PoolId : MaxPools; + } + + void SwitchToIdle() { + Executor = nullptr; + MailboxTable = nullptr; + //Stats = &WorkerStats; // TODO: in actorsystem 2.0 idle stats cannot be related to specific pool + PoolId = MaxPools; + } + }; +} diff --git a/library/cpp/actors/core/ya.make b/library/cpp/actors/core/ya.make index 880a9d00db..9cb2e2d396 100644 --- a/library/cpp/actors/core/ya.make +++ b/library/cpp/actors/core/ya.make @@ -30,16 +30,16 @@ SRCS( actorsystem.h ask.cpp ask.h - balancer.h - balancer.cpp + balancer.h + balancer.cpp buffer.cpp buffer.h callstack.cpp callstack.h - config.h - cpu_manager.cpp - cpu_manager.h - cpu_state.h + config.h + cpu_manager.cpp + cpu_manager.h + cpu_state.h defs.h event.cpp event.h @@ -56,8 +56,8 @@ SRCS( executor_pool_basic.h executor_pool_io.cpp executor_pool_io.h - executor_pool_united.cpp - executor_pool_united.h + executor_pool_united.cpp + executor_pool_united.h executor_thread.cpp executor_thread.h hfunc.h @@ -66,7 +66,7 @@ SRCS( invoke.h io_dispatcher.cpp io_dispatcher.h - lease.h + lease.h log.cpp log.h log_settings.cpp @@ -82,9 +82,9 @@ SRCS( mon.h mon_stats.h monotonic.cpp - monotonic.h - worker_context.cpp - worker_context.h + monotonic.h + worker_context.cpp + worker_context.h probes.cpp probes.h process_stats.cpp diff --git a/library/cpp/actors/dnscachelib/dnscache.cpp b/library/cpp/actors/dnscachelib/dnscache.cpp index 649339ddb2..026491bcf1 100644 --- a/library/cpp/actors/dnscachelib/dnscache.cpp +++ b/library/cpp/actors/dnscachelib/dnscache.cpp @@ -1,5 +1,5 @@ #include "dnscache.h" -#include "probes.h" +#include "probes.h" #include "timekeeper.h" #include <contrib/libs/c-ares/ares.h> @@ -8,8 +8,8 @@ const TDnsCache::THost TDnsCache::NullHost; -LWTRACE_USING(DNSCACHELIB_PROVIDER); - +LWTRACE_USING(DNSCACHELIB_PROVIDER); + static_assert(sizeof(ares_channel) == sizeof(void*), "expect sizeof(ares_channel) == sizeof(void *)"); TDnsCache::TDnsCache(bool allowIpv4, bool allowIpv6, time_t lifetime, time_t neg, ui32 timeout) @@ -33,11 +33,11 @@ TDnsCache::TDnsCache(bool allowIpv4, bool allowIpv6, time_t lifetime, time_t neg ares_channel chan; if (ares_init(&chan) != ARES_SUCCESS) { - LWPROBE(AresInitFailed); + LWPROBE(AresInitFailed); ythrow yexception() << "ares_init() failed"; } Channel = chan; - LWPROBE(Created); + LWPROBE(Created); } TDnsCache::~TDnsCache(void) { @@ -45,7 +45,7 @@ TDnsCache::~TDnsCache(void) { ares_cancel(chan); ares_destroy(chan); - LWPROBE(Destroyed); + LWPROBE(Destroyed); #ifdef _win_ ares_library_cleanup(); @@ -112,7 +112,7 @@ NAddr::IRemoteAddrPtr TDnsCache::GetAddr( } } - LWPROBE(FamilyMismatch, family, AllowIpV4, AllowIpV6); + LWPROBE(FamilyMismatch, family, AllowIpV4, AllowIpV6); return nullptr; } @@ -170,7 +170,7 @@ bool TDnsCache::THost::IsStale(int family, const TDnsCache* ctx) const noexcept const TDnsCache::THost& TDnsCache::Resolve(const TString& hostname, int family, bool cacheOnly) { if (!ValidateHName(hostname)) { - LWPROBE(ResolveNullHost, hostname, family); + LWPROBE(ResolveNullHost, hostname, family); return NullHost; } @@ -185,15 +185,15 @@ TDnsCache::Resolve(const TString& hostname, int family, bool cacheOnly) { if (!p->second.IsStale(family, this)) { /* Recently resolved, just return cached value */ ACacheHits += 1; - THost& host = p->second; - LWPROBE(ResolveFromCache, hostname, family, host.AddrsV4ToString(), host.AddrsV6ToString(), ACacheHits); - return host; - } else { - LWPROBE(ResolveCacheTimeout, hostname); + THost& host = p->second; + LWPROBE(ResolveFromCache, hostname, family, host.AddrsV4ToString(), host.AddrsV6ToString(), ACacheHits); + return host; + } else { + LWPROBE(ResolveCacheTimeout, hostname); } } else { /* Never resolved, create cache entry */ - LWPROBE(ResolveCacheNew, hostname); + LWPROBE(ResolveCacheNew, hostname); p = HostCache.insert(std::make_pair(hostname, THost())).first; } ACacheMisses += 1; @@ -227,7 +227,7 @@ TDnsCache::Resolve(const TString& hostname, int family, bool cacheOnly) { WaitTask(inprogress); - LWPROBE(ResolveDone, hostname, family, p->second.AddrsV4ToString(), p->second.AddrsV6ToString()); + LWPROBE(ResolveDone, hostname, family, p->second.AddrsV4ToString(), p->second.AddrsV6ToString()); return p->second; } @@ -415,31 +415,31 @@ void TDnsCache::GHBACallback(void* arg, int status, int, struct hostent* info) { } AtomicSet(p->second.InProgress, 0); } - + TString TDnsCache::THost::AddrsV4ToString() const { - TStringStream ss; - bool first = false; - for (TIpHost addr : AddrsV4) { + TStringStream ss; + bool first = false; + for (TIpHost addr : AddrsV4) { ss << (first ? "" : " ") << IpToString(addr); - first = false; - } - return ss.Str(); -} - + first = false; + } + return ss.Str(); +} + TString TDnsCache::THost::AddrsV6ToString() const { - TStringStream ss; - bool first = false; - for (in6_addr addr : AddrsV6) { - struct sockaddr_in6 sin6; - Zero(sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = addr; - - NAddr::TIPv6Addr addr6(sin6); + TStringStream ss; + bool first = false; + for (in6_addr addr : AddrsV6) { + struct sockaddr_in6 sin6; + Zero(sin6); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = addr; + + NAddr::TIPv6Addr addr6(sin6); ss << (first ? "" : " ") << NAddr::PrintHost(addr6); - first = false; - } - return ss.Str(); -} + first = false; + } + return ss.Str(); +} TDnsCache::TAresLibInit TDnsCache::InitAresLib; diff --git a/library/cpp/actors/dnscachelib/dnscache.h b/library/cpp/actors/dnscachelib/dnscache.h index 3313a251a1..03eec356d2 100644 --- a/library/cpp/actors/dnscachelib/dnscache.h +++ b/library/cpp/actors/dnscachelib/dnscache.h @@ -65,7 +65,7 @@ private: time_t ResolvedV6 = 0; time_t NotFoundV6 = 0; TAtomic InProgressV6 = 0; - + TString AddrsV4ToString() const; TString AddrsV6ToString() const; diff --git a/library/cpp/actors/dnscachelib/probes.cpp b/library/cpp/actors/dnscachelib/probes.cpp index 07734ab20f..441e0609f9 100644 --- a/library/cpp/actors/dnscachelib/probes.cpp +++ b/library/cpp/actors/dnscachelib/probes.cpp @@ -1,3 +1,3 @@ -#include "probes.h" - -LWTRACE_DEFINE_PROVIDER(DNSCACHELIB_PROVIDER) +#include "probes.h" + +LWTRACE_DEFINE_PROVIDER(DNSCACHELIB_PROVIDER) diff --git a/library/cpp/actors/dnscachelib/probes.h b/library/cpp/actors/dnscachelib/probes.h index 313b7b8712..6416e997b7 100644 --- a/library/cpp/actors/dnscachelib/probes.h +++ b/library/cpp/actors/dnscachelib/probes.h @@ -1,7 +1,7 @@ -#pragma once - +#pragma once + #include <library/cpp/lwtrace/all.h> - + #define DNSCACHELIB_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ PROBE(Created, GROUPS(), TYPES(), NAMES()) \ PROBE(Destroyed, GROUPS(), TYPES(), NAMES()) \ @@ -30,6 +30,6 @@ GROUPS(), \ TYPES(TString), \ NAMES("hostname")) \ - /**/ - -LWTRACE_DECLARE_PROVIDER(DNSCACHELIB_PROVIDER) + /**/ + +LWTRACE_DECLARE_PROVIDER(DNSCACHELIB_PROVIDER) diff --git a/library/cpp/actors/dnscachelib/ya.make b/library/cpp/actors/dnscachelib/ya.make index e3a6ad6202..3ee25102c1 100644 --- a/library/cpp/actors/dnscachelib/ya.make +++ b/library/cpp/actors/dnscachelib/ya.make @@ -11,8 +11,8 @@ OWNER( SRCS( dnscache.cpp dnscache.h - probes.cpp - probes.h + probes.cpp + probes.h timekeeper.h ) diff --git a/library/cpp/actors/helpers/flow_controlled_queue.cpp b/library/cpp/actors/helpers/flow_controlled_queue.cpp index d75cc54023..46addfa708 100644 --- a/library/cpp/actors/helpers/flow_controlled_queue.cpp +++ b/library/cpp/actors/helpers/flow_controlled_queue.cpp @@ -2,7 +2,7 @@ #include <library/cpp/actors/core/interconnect.h> #include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> #include <util/generic/deque.h> #include <util/datetime/cputimer.h> @@ -29,7 +29,7 @@ public: , Source(source) , Cookie(cookie) , Flags(flags) - , StartCounter(GetCycleCountFast()) + , StartCounter(GetCycleCountFast()) {} STATEFN(StateWait) { @@ -41,7 +41,7 @@ public: } TDuration AccumulatedLatency() const { - const ui64 cc = GetCycleCountFast() - StartCounter; + const ui64 cc = GetCycleCountFast() - StartCounter; return CyclesToDuration(cc); } diff --git a/library/cpp/actors/interconnect/interconnect_channel.cpp b/library/cpp/actors/interconnect/interconnect_channel.cpp index a66ba2a154..9aee8fd5a2 100644 --- a/library/cpp/actors/interconnect/interconnect_channel.cpp +++ b/library/cpp/actors/interconnect/interconnect_channel.cpp @@ -3,13 +3,13 @@ #include <library/cpp/actors/core/events.h> #include <library/cpp/actors/core/executor_thread.h> #include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/probes.h> +#include <library/cpp/actors/core/probes.h> #include <library/cpp/actors/protos/services_common.pb.h> #include <library/cpp/actors/prof/tag.h> #include <library/cpp/digest/crc32c/crc32c.h> -LWTRACE_USING(ACTORLIB_PROVIDER); - +LWTRACE_USING(ACTORLIB_PROVIDER); + namespace NActors { DECLARE_WILSON_EVENT(EventSentToSocket); DECLARE_WILSON_EVENT(EventReceivedFromSocket); @@ -25,8 +25,8 @@ namespace NActors { // WILSON_TRACE(*ctx, &traceId, EventSentToSocket); // } traceId.Serialize(&event.Descr.TraceId); - LWTRACK(SerializeToPacketEnd, event.Orbit, PeerNodeId, ChannelId, OutputQueueSize, task.GetDataSize()); - task.Orbit.Take(event.Orbit); + LWTRACK(SerializeToPacketEnd, event.Orbit, PeerNodeId, ChannelId, OutputQueueSize, task.GetDataSize()); + task.Orbit.Take(event.Orbit); event.Descr.Flags = (event.Descr.Flags & ~IEventHandle::FlagForwardOnNondelivery) | (ExtendedFormat ? IEventHandle::FlagExtendedFormat : 0); @@ -58,7 +58,7 @@ namespace NActors { switch (State) { case EState::INITIAL: event.InitChecksum(); - LWTRACK(SerializeToPacketBegin, event.Orbit, PeerNodeId, ChannelId, OutputQueueSize); + LWTRACK(SerializeToPacketBegin, event.Orbit, PeerNodeId, ChannelId, OutputQueueSize); if (event.Event) { State = EState::CHUNKER; IEventBase *base = event.Event.Get(); diff --git a/library/cpp/actors/interconnect/interconnect_channel.h b/library/cpp/actors/interconnect/interconnect_channel.h index e4a0ae3cda..a26cb7a92c 100644 --- a/library/cpp/actors/interconnect/interconnect_channel.h +++ b/library/cpp/actors/interconnect/interconnect_channel.h @@ -42,11 +42,11 @@ namespace NActors { class TEventOutputChannel : public TInterconnectLoggingBase { public: - TEventOutputChannel(TEventHolderPool& pool, ui16 id, ui32 peerNodeId, ui32 maxSerializedEventSize, + TEventOutputChannel(TEventHolderPool& pool, ui16 id, ui32 peerNodeId, ui32 maxSerializedEventSize, std::shared_ptr<IInterconnectMetrics> metrics, TSessionParams params) - : TInterconnectLoggingBase(Sprintf("OutputChannel %" PRIu16 " [node %" PRIu32 "]", id, peerNodeId)) + : TInterconnectLoggingBase(Sprintf("OutputChannel %" PRIu16 " [node %" PRIu32 "]", id, peerNodeId)) , Pool(pool) - , PeerNodeId(peerNodeId) + , PeerNodeId(peerNodeId) , ChannelId(id) , Metrics(std::move(metrics)) , Params(std::move(params)) @@ -56,11 +56,11 @@ namespace NActors { ~TEventOutputChannel() { } - std::pair<ui32, TEventHolder*> Push(IEventHandle& ev) { + std::pair<ui32, TEventHolder*> Push(IEventHandle& ev) { TEventHolder& event = Pool.Allocate(Queue); const ui32 bytes = event.Fill(ev) + sizeof(TEventDescr); OutputQueueSize += bytes; - return std::make_pair(bytes, &event); + return std::make_pair(bytes, &event); } void DropConfirmed(ui64 confirm); @@ -86,7 +86,7 @@ namespace NActors { void NotifyUndelivered(); TEventHolderPool& Pool; - const ui32 PeerNodeId; + const ui32 PeerNodeId; const ui16 ChannelId; std::shared_ptr<IInterconnectMetrics> Metrics; const TSessionParams Params; diff --git a/library/cpp/actors/interconnect/interconnect_common.h b/library/cpp/actors/interconnect/interconnect_common.h index 285709a00c..104573daaa 100644 --- a/library/cpp/actors/interconnect/interconnect_common.h +++ b/library/cpp/actors/interconnect/interconnect_common.h @@ -2,7 +2,7 @@ #include <library/cpp/actors/core/actorid.h> #include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> #include <library/cpp/monlib/dynamic_counters/counters.h> #include <library/cpp/monlib/metrics/metric_registry.h> #include <util/generic/map.h> @@ -82,7 +82,7 @@ namespace NActors { TAtomicBase MaxDestructorQueueSize = 1024 * 1024 * 1024; TString ClusterUUID; TVector<TString> AcceptUUID; - ui64 StartTime = GetCycleCountFast(); + ui64 StartTime = GetCycleCountFast(); TString TechnicalSelfHostName; TInitWhiteboardCallback InitWhiteboard; TUpdateWhiteboardCallback UpdateWhiteboard; diff --git a/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp b/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp index 0abe9fe659..e445c42f70 100644 --- a/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp +++ b/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp @@ -1,7 +1,7 @@ #include "interconnect_tcp_session.h" #include "interconnect_tcp_proxy.h" #include <library/cpp/actors/core/probes.h> -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> namespace NActors { LWTRACE_USING(ACTORLIB_PROVIDER); @@ -195,7 +195,7 @@ namespace NActors { ConfirmedByInput = HeaderConfirm; if (AtomicGet(Context->ControlPacketId) <= HeaderConfirm && !NewPingProtocol) { ui64 sendTime = AtomicGet(Context->ControlPacketSendTimer); - TDuration duration = CyclesToDuration(GetCycleCountFast() - sendTime); + TDuration duration = CyclesToDuration(GetCycleCountFast() - sendTime); const auto durationUs = duration.MicroSeconds(); Metrics->UpdateLegacyPingTimeHist(durationUs); PingQ.push_back(duration); @@ -217,7 +217,7 @@ namespace NActors { Send(SessionId, new TEvProcessPingRequest(HeaderSerial & ~TTcpPacketBuf::PingRequestMask)); } else if (HeaderSerial & TTcpPacketBuf::PingResponseMask) { const ui64 sent = HeaderSerial & ~TTcpPacketBuf::PingResponseMask; - const ui64 received = GetCycleCountFast(); + const ui64 received = GetCycleCountFast(); HandlePingResponse(CyclesToDuration(received - sent)); } else if (HeaderSerial & TTcpPacketBuf::ClockMask) { HandleClock(TInstant::MicroSeconds(HeaderSerial & ~TTcpPacketBuf::ClockMask)); diff --git a/library/cpp/actors/interconnect/interconnect_tcp_session.cpp b/library/cpp/actors/interconnect/interconnect_tcp_session.cpp index 2ded7f9f53..8da77bcd1d 100644 --- a/library/cpp/actors/interconnect/interconnect_tcp_session.cpp +++ b/library/cpp/actors/interconnect/interconnect_tcp_session.cpp @@ -5,7 +5,7 @@ #include <library/cpp/actors/core/probes.h> #include <library/cpp/actors/core/log.h> #include <library/cpp/actors/core/interconnect.h> -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> #include <library/cpp/actors/protos/services_common.pb.h> #include <library/cpp/monlib/service/pages/templates.h> @@ -128,20 +128,20 @@ namespace NActors { auto& oChannel = ChannelScheduler->GetOutputChannel(evChannel); const bool wasWorking = oChannel.IsWorking(); - const auto [dataSize, event] = oChannel.Push(*ev); - LWTRACK(ForwardEvent, event->Orbit, Proxy->PeerNodeId, event->Descr.Type, event->Descr.Flags, LWACTORID(event->Descr.Recipient), LWACTORID(event->Descr.Sender), event->Descr.Cookie, event->EventSerializedSize); - - TotalOutputQueueSize += dataSize; + const auto [dataSize, event] = oChannel.Push(*ev); + LWTRACK(ForwardEvent, event->Orbit, Proxy->PeerNodeId, event->Descr.Type, event->Descr.Flags, LWACTORID(event->Descr.Recipient), LWACTORID(event->Descr.Sender), event->Descr.Cookie, event->EventSerializedSize); + + TotalOutputQueueSize += dataSize; Proxy->Metrics->AddOutputBuffersTotalSize(dataSize); - if (!wasWorking) { - // this channel has returned to work -- it was empty and this we have just put first event in the queue - ChannelScheduler->AddToHeap(oChannel, EqualizeCounter); + if (!wasWorking) { + // this channel has returned to work -- it was empty and this we have just put first event in the queue + ChannelScheduler->AddToHeap(oChannel, EqualizeCounter); } SetOutputStuckFlag(true); ++NumEventsInReadyChannels; - LWTRACK(EnqueueEvent, event->Orbit, Proxy->PeerNodeId, NumEventsInReadyChannels, GetWriteBlockedTotal(), evChannel, oChannel.GetQueueSize(), oChannel.GetBufferedAmountOfData()); + LWTRACK(EnqueueEvent, event->Orbit, Proxy->PeerNodeId, NumEventsInReadyChannels, GetWriteBlockedTotal(), evChannel, oChannel.GetQueueSize(), oChannel.GetBufferedAmountOfData()); WILSON_TRACE(*TlsActivationContext, &ev->TraceId, OutputQueuePush, QueueSizeInEvents = oChannel.GetQueueSize(), QueueSizeInBytes = oChannel.GetBufferedAmountOfData()); @@ -179,7 +179,7 @@ namespace NActors { } else { TActivationContext::Send(ev); } - LWPROBE(StartBatching, Proxy->PeerNodeId, batchPeriod.MillisecondsFloat()); + LWPROBE(StartBatching, Proxy->PeerNodeId, batchPeriod.MillisecondsFloat()); LOG_DEBUG_IC_SESSION("ICS17", "batching started"); } } @@ -315,7 +315,7 @@ namespace NActors { // update ping time Ping = msg.Ping; - LWPROBE(UpdateFromInputSession, Proxy->PeerNodeId, Ping.MillisecondsFloat()); + LWPROBE(UpdateFromInputSession, Proxy->PeerNodeId, Ping.MillisecondsFloat()); bool needConfirm = false; @@ -342,7 +342,7 @@ namespace NActors { // generate more traffic if we have unblocked state now if (unblockedSomething) { - LWPROBE(UnblockByDropConfirmed, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - ev->SendTime) * 1000.0); + LWPROBE(UnblockByDropConfirmed, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - ev->SendTime) * 1000.0); GenerateTraffic(); } @@ -380,7 +380,7 @@ namespace NActors { void TInterconnectSessionTCP::HandleRam(TEvRam::TPtr& ev) { if (ev->Get() == RamInQueue) { - LWPROBE(FinishRam, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - ev->SendTime) * 1000.0); + LWPROBE(FinishRam, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - ev->SendTime) * 1000.0); RamInQueue = nullptr; GenerateTraffic(); } @@ -391,7 +391,7 @@ namespace NActors { IssuePingRequest(); if (RamInQueue && !RamInQueue->Batching) { - LWPROBE(SkipGenerateTraffic, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - RamStartedCycles) * 1000.0); + LWPROBE(SkipGenerateTraffic, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - RamStartedCycles) * 1000.0); return; // we'll do it a bit later } else { RamInQueue = nullptr; @@ -399,51 +399,51 @@ namespace NActors { LOG_DEBUG_IC_SESSION("ICS19", "GenerateTraffic"); - // There is a tradeoff between fairness and efficiency. - // The less traffic is generated here, the less buffering is after fair scheduler, - // the more fair system is, the less latency is present. - // The more traffic is generated here, the less syscalls and actor-system overhead occurs, - // the less cpu is consumed. - static const ui64 generateLimit = 64 * 1024; - + // There is a tradeoff between fairness and efficiency. + // The less traffic is generated here, the less buffering is after fair scheduler, + // the more fair system is, the less latency is present. + // The more traffic is generated here, the less syscalls and actor-system overhead occurs, + // the less cpu is consumed. + static const ui64 generateLimit = 64 * 1024; + const ui64 sizeBefore = TotalOutputQueueSize; - ui32 generatedPackets = 0; - ui64 generatedBytes = 0; - ui64 generateStarted = GetCycleCountFast(); + ui32 generatedPackets = 0; + ui64 generatedBytes = 0; + ui64 generateStarted = GetCycleCountFast(); // apply traffic changes auto accountTraffic = [&] { ChannelScheduler->ForEach([](TEventOutputChannel& channel) { channel.AccountTraffic(); }); }; - // first, we create as many data packets as we can generate under certain conditions; they include presence - // of events in channels queues and in flight fitting into requested limit; after we hit one of these conditions - // we exit cycle - while (Socket && NumEventsInReadyChannels && InflightDataAmount < GetTotalInflightAmountOfData() && !ReceiveContext->WriteBlockedByFullSendBuffer) { - if (generatedBytes >= generateLimit) { - // resume later but ensure that we have issued at least one packet + // first, we create as many data packets as we can generate under certain conditions; they include presence + // of events in channels queues and in flight fitting into requested limit; after we hit one of these conditions + // we exit cycle + while (Socket && NumEventsInReadyChannels && InflightDataAmount < GetTotalInflightAmountOfData() && !ReceiveContext->WriteBlockedByFullSendBuffer) { + if (generatedBytes >= generateLimit) { + // resume later but ensure that we have issued at least one packet RamInQueue = new TEvRam(false); Send(SelfId(), RamInQueue); - RamStartedCycles = GetCycleCountFast(); - LWPROBE(StartRam, Proxy->PeerNodeId); - break; + RamStartedCycles = GetCycleCountFast(); + LWPROBE(StartRam, Proxy->PeerNodeId); + break; } - try { - generatedBytes += MakePacket(true); - ++generatedPackets; - } catch (const TExSerializedEventTooLarge& ex) { - // terminate session if the event can't be serialized properly - accountTraffic(); - LOG_CRIT_IC("ICS31", "serialized event Type# 0x%08" PRIx32 " is too large", ex.Type); - return Terminate(TDisconnectReason::EventTooLarge()); + try { + generatedBytes += MakePacket(true); + ++generatedPackets; + } catch (const TExSerializedEventTooLarge& ex) { + // terminate session if the event can't be serialized properly + accountTraffic(); + LOG_CRIT_IC("ICS31", "serialized event Type# 0x%08" PRIx32 " is too large", ex.Type); + return Terminate(TDisconnectReason::EventTooLarge()); } } - if (Socket) { - WriteData(); - } - - LWPROBE(GenerateTraffic, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - generateStarted) * 1000.0, sizeBefore - TotalOutputQueueSize, generatedPackets, generatedBytes); - + if (Socket) { + WriteData(); + } + + LWPROBE(GenerateTraffic, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - generateStarted) * 1000.0, sizeBefore - TotalOutputQueueSize, generatedPackets, generatedBytes); + accountTraffic(); EqualizeCounter += ChannelScheduler->Equalize(); } @@ -520,10 +520,10 @@ namespace NActors { ReceiveContext->WriteBlockedByFullSendBuffer ? "true" : "false"); if (std::exchange(ReceiveContext->WriteBlockedByFullSendBuffer, false)) { Proxy->Metrics->IncUsefulWriteWakeups(); - ui64 nowCycles = GetCycleCountFast(); - double blockedUs = NHPTimer::GetSeconds(nowCycles - WriteBlockedCycles) * 1000000.0; - LWPROBE(ReadyWrite, Proxy->PeerNodeId, NHPTimer::GetSeconds(nowCycles - ev->SendTime) * 1000.0, blockedUs / 1000.0); - WriteBlockedTotal += TDuration::MicroSeconds(blockedUs); + ui64 nowCycles = GetCycleCountFast(); + double blockedUs = NHPTimer::GetSeconds(nowCycles - WriteBlockedCycles) * 1000000.0; + LWPROBE(ReadyWrite, Proxy->PeerNodeId, NHPTimer::GetSeconds(nowCycles - ev->SendTime) * 1000.0, blockedUs / 1000.0); + WriteBlockedTotal += TDuration::MicroSeconds(blockedUs); GenerateTraffic(); } else if (!ev->Cookie) { Proxy->Metrics->IncSpuriousWriteWakeups(); @@ -602,7 +602,7 @@ namespace NActors { Y_VERIFY(static_cast<size_t>(r) <= BytesUnwritten); BytesUnwritten -= r; written += r; - ui64 packets = 0; + ui64 packets = 0; // advance SendQueuePos to eat all processed items for (size_t amount = r; amount && SendQueuePos->DropBufs(amount); ++SendQueuePos) { @@ -610,11 +610,11 @@ namespace NActors { LastSentSerial = Max(LastSentSerial, SendQueuePos->GetSerial()); } ++PacketsWrittenToSocket; - ++packets; - LWTRACK(PacketWrittenToSocket, SendQueuePos->Orbit, Proxy->PeerNodeId, PacketsWrittenToSocket, SendQueuePos->TriedWriting, SendQueuePos->GetDataSize(), BytesUnwritten, GetWriteBlockedTotal(), (SOCKET)*Socket); + ++packets; + LWTRACK(PacketWrittenToSocket, SendQueuePos->Orbit, Proxy->PeerNodeId, PacketsWrittenToSocket, SendQueuePos->TriedWriting, SendQueuePos->GetDataSize(), BytesUnwritten, GetWriteBlockedTotal(), (SOCKET)*Socket); } - - LWPROBE(WriteToSocket, Proxy->PeerNodeId, r, packets, PacketsWrittenToSocket, BytesUnwritten, GetWriteBlockedTotal(), (SOCKET)*Socket); + + LWPROBE(WriteToSocket, Proxy->PeerNodeId, r, packets, PacketsWrittenToSocket, BytesUnwritten, GetWriteBlockedTotal(), (SOCKET)*Socket); } else if (-r != EAGAIN && -r != EWOULDBLOCK) { const TString message = r == 0 ? "connection closed by peer" : err ? err @@ -635,8 +635,8 @@ namespace NActors { // TEvPollerReadyWrite event from poller; set up flag meaning this and wait for that event Y_VERIFY(!ReceiveContext->WriteBlockedByFullSendBuffer); ReceiveContext->WriteBlockedByFullSendBuffer = true; - WriteBlockedCycles = GetCycleCountFast(); - LWPROBE(BlockedWrite, Proxy->PeerNodeId, SendQueue.size(), written); + WriteBlockedCycles = GetCycleCountFast(); + LWPROBE(BlockedWrite, Proxy->PeerNodeId, SendQueue.size(), written); LOG_DEBUG_IC_SESSION("ICS18", "hit send buffer limit"); if (PollerToken) { @@ -718,7 +718,7 @@ namespace NActors { } } - ui64 TInterconnectSessionTCP::MakePacket(bool data, TMaybe<ui64> pingMask) { + ui64 TInterconnectSessionTCP::MakePacket(bool data, TMaybe<ui64> pingMask) { Y_VERIFY(Socket); TSendQueue::iterator packet; @@ -759,7 +759,7 @@ namespace NActors { } if (AtomicGet(ReceiveContext->ControlPacketId) == 0) { - AtomicSet(ReceiveContext->ControlPacketSendTimer, GetCycleCountFast()); + AtomicSet(ReceiveContext->ControlPacketSendTimer, GetCycleCountFast()); AtomicSet(ReceiveContext->ControlPacketId, OutputCounter); } @@ -788,8 +788,8 @@ namespace NActors { packet->Sign(); // count number of bytes pending for write - ui64 packetSize = (Params.UseModernFrame ? sizeof(TTcpPacketHeader_v2) : sizeof(TTcpPacketHeader_v1)) + packet->GetDataSize(); - BytesUnwritten += packetSize; + ui64 packetSize = (Params.UseModernFrame ? sizeof(TTcpPacketHeader_v2) : sizeof(TTcpPacketHeader_v1)) + packet->GetDataSize(); + BytesUnwritten += packetSize; LOG_DEBUG_IC_SESSION("ICS22", "outgoing packet Serial# %" PRIu64 " Confirm# %" PRIu64 " DataSize# %zu" " InflightDataAmount# %" PRIu64 " BytesUnwritten# %" PRIu64, serial, lastInputSerial, packet->GetDataSize(), @@ -799,13 +799,13 @@ namespace NActors { ResetFlushLogic(); ++PacketsGenerated; - LWTRACK(PacketGenerated, packet->Orbit, Proxy->PeerNodeId, BytesUnwritten, InflightDataAmount, PacketsGenerated, packetSize); + LWTRACK(PacketGenerated, packet->Orbit, Proxy->PeerNodeId, BytesUnwritten, InflightDataAmount, PacketsGenerated, packetSize); if (!data) { WriteData(); } - - return packetSize; + + return packetSize; } bool TInterconnectSessionTCP::DropConfirmed(ui64 confirm) { @@ -836,14 +836,14 @@ namespace NActors { channel.DropConfirmed(lastDroppedSerial); }); - const ui64 current = InflightDataAmount; - const ui64 limit = GetTotalInflightAmountOfData(); - const bool unblockedSomething = current >= limit && current < limit + droppedDataAmount; + const ui64 current = InflightDataAmount; + const ui64 limit = GetTotalInflightAmountOfData(); + const bool unblockedSomething = current >= limit && current < limit + droppedDataAmount; PacketsConfirmed += numDropped; InflightDataAmount -= droppedDataAmount; Proxy->Metrics->SubInflightDataAmount(droppedDataAmount); - LWPROBE(DropConfirmed, Proxy->PeerNodeId, droppedDataAmount, InflightDataAmount); + LWPROBE(DropConfirmed, Proxy->PeerNodeId, droppedDataAmount, InflightDataAmount); LOG_DEBUG_IC_SESSION("ICS24", "exit InflightDataAmount: %" PRIu64 " bytes droppedDataAmount: %" PRIu64 " bytes" " dropped %" PRIu32 " packets", InflightDataAmount, droppedDataAmount, numDropped); @@ -896,7 +896,7 @@ namespace NActors { } } - LWTRACK(FillSendingBuffer, task.Orbit, Proxy->PeerNodeId, bytesGenerated, NumEventsInReadyChannels, WriteBlockedTotal); + LWTRACK(FillSendingBuffer, task.Orbit, Proxy->PeerNodeId, bytesGenerated, NumEventsInReadyChannels, WriteBlockedTotal); Y_VERIFY(bytesGenerated); // ensure we are not stalled in serialization } @@ -967,15 +967,15 @@ namespace NActors { auto& lastpair = OutputQueueUtilization.Last(); if (state) - lastpair.first -= GetCycleCountFast(); + lastpair.first -= GetCycleCountFast(); else - lastpair.first += GetCycleCountFast(); + lastpair.first += GetCycleCountFast(); OutputStuckFlag = state; } void TInterconnectSessionTCP::SwitchStuckPeriod() { - auto now = GetCycleCountFast(); + auto now = GetCycleCountFast(); if (OutputQueueUtilization.Size() != 0) { auto& lastpair = OutputQueueUtilization.Last(); lastpair.second = now - lastpair.second; @@ -1005,7 +1005,7 @@ namespace NActors { } ui64 TInterconnectSessionTCP::GetMaxCyclesPerEvent() const { - return DurationToCycles(TDuration::MicroSeconds(50)); + return DurationToCycles(TDuration::MicroSeconds(50)); } void TInterconnectSessionTCP::IssuePingRequest() { @@ -1013,7 +1013,7 @@ namespace NActors { if (now >= LastPingTimestamp + PingPeriodicity) { LOG_DEBUG_IC_SESSION("ICS22", "Issuing ping request"); if (Socket) { - MakePacket(false, GetCycleCountFast() | TTcpPacketBuf::PingRequestMask); + MakePacket(false, GetCycleCountFast() | TTcpPacketBuf::PingRequestMask); } if (Socket) { MakePacket(false, TInstant::Now().MicroSeconds() | TTcpPacketBuf::ClockMask); diff --git a/library/cpp/actors/interconnect/interconnect_tcp_session.h b/library/cpp/actors/interconnect/interconnect_tcp_session.h index 7fc00dbcc5..e347d9b799 100644 --- a/library/cpp/actors/interconnect/interconnect_tcp_session.h +++ b/library/cpp/actors/interconnect/interconnect_tcp_session.h @@ -6,7 +6,7 @@ #include <library/cpp/actors/core/log.h> #include <library/cpp/actors/helpers/mon_histogram_helper.h> #include <library/cpp/actors/protos/services_common.pb.h> -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> #include <library/cpp/actors/util/rope.h> #include <library/cpp/actors/util/funnel_queue.h> #include <library/cpp/actors/util/recentwnd.h> @@ -38,12 +38,12 @@ namespace NActors { public: TSlowPathChecker(TTraceCallback&& callback) : Callback(std::move(callback)) - , Start(GetCycleCountFast()) + , Start(GetCycleCountFast()) { } ~TSlowPathChecker() { - const NHPTimer::STime end = GetCycleCountFast(); + const NHPTimer::STime end = GetCycleCountFast(); const NHPTimer::STime elapsed = end - Start; if (elapsed > 1000000) { Callback(NHPTimer::GetSeconds(elapsed) * 1000); @@ -63,7 +63,7 @@ namespace NActors { class TTimeLimit { public: TTimeLimit(ui64 limitInCycles) - : UpperLimit(limitInCycles == 0 ? 0 : GetCycleCountFast() + limitInCycles) + : UpperLimit(limitInCycles == 0 ? 0 : GetCycleCountFast() + limitInCycles) { } @@ -73,7 +73,7 @@ namespace NActors { } bool CheckExceeded() { - return UpperLimit != 0 && GetCycleCountFast() > UpperLimit; + return UpperLimit != 0 && GetCycleCountFast() > UpperLimit; } const ui64 UpperLimit; @@ -125,7 +125,7 @@ namespace NActors { std::unordered_map<ui16, TRope> ChannelMap; TReceiveContext() { - GetTimeFast(&StartTime); + GetTimeFast(&StartTime); } // returns false if sessions needs to be terminated and packet not to be processed @@ -378,7 +378,7 @@ namespace NActors { void SetNewConnection(TEvHandshakeDone::TPtr& ev); TEvRam* RamInQueue = nullptr; - ui64 RamStartedCycles = 0; + ui64 RamStartedCycles = 0; void HandleRam(TEvRam::TPtr& ev); void GenerateTraffic(); @@ -389,7 +389,7 @@ namespace NActors { void Handle(TEvPollerRegisterResult::TPtr ev); void WriteData(); - ui64 MakePacket(bool data, TMaybe<ui64> pingMask = {}); + ui64 MakePacket(bool data, TMaybe<ui64> pingMask = {}); void FillSendingBuffer(TTcpPacketOutTask& packet, ui64 serial); bool DropConfirmed(ui64 confirm); void ShutdownSocket(TDisconnectReason reason); @@ -452,21 +452,21 @@ namespace NActors { TSendQueue SendQueue; TSendQueue SendQueueCache; TSendQueue::iterator SendQueuePos; - ui64 WriteBlockedCycles = 0; // start of current block period - TDuration WriteBlockedTotal; // total incremental duration that session has been blocked + ui64 WriteBlockedCycles = 0; // start of current block period + TDuration WriteBlockedTotal; // total incremental duration that session has been blocked ui64 BytesUnwritten = 0; void TrimSendQueueCache(); - TDuration GetWriteBlockedTotal() const { + TDuration GetWriteBlockedTotal() const { if (ReceiveContext->WriteBlockedByFullSendBuffer) { - double blockedUs = NHPTimer::GetSeconds(GetCycleCountFast() - WriteBlockedCycles) * 1000000.0; - return WriteBlockedTotal + TDuration::MicroSeconds(blockedUs); // append current blocking period if any - } else { - return WriteBlockedTotal; - } - } - + double blockedUs = NHPTimer::GetSeconds(GetCycleCountFast() - WriteBlockedCycles) * 1000000.0; + return WriteBlockedTotal + TDuration::MicroSeconds(blockedUs); // append current blocking period if any + } else { + return WriteBlockedTotal; + } + } + ui64 OutputCounter; ui64 LastSentSerial = 0; diff --git a/library/cpp/actors/interconnect/packet.cpp b/library/cpp/actors/interconnect/packet.cpp index e2c289ed59..55c9679414 100644 --- a/library/cpp/actors/interconnect/packet.cpp +++ b/library/cpp/actors/interconnect/packet.cpp @@ -1,11 +1,11 @@ #include "packet.h" -#include <library/cpp/actors/core/probes.h> - +#include <library/cpp/actors/core/probes.h> + #include <util/system/datetime.h> -LWTRACE_USING(ACTORLIB_PROVIDER); - +LWTRACE_USING(ACTORLIB_PROVIDER); + ui32 TEventHolder::Fill(IEventHandle& ev) { Serial = 0; Descr.Type = ev.Type; @@ -27,6 +27,6 @@ ui32 TEventHolder::Fill(IEventHandle& ev) { } else { EventSerializedSize = 0; } - + return EventSerializedSize; } diff --git a/library/cpp/actors/interconnect/packet.h b/library/cpp/actors/interconnect/packet.h index 4ba50a2b5f..f062633b0b 100644 --- a/library/cpp/actors/interconnect/packet.h +++ b/library/cpp/actors/interconnect/packet.h @@ -8,7 +8,7 @@ #include <library/cpp/actors/util/rope.h> #include <library/cpp/actors/prof/tag.h> #include <library/cpp/digest/crc32c/crc32c.h> -#include <library/cpp/lwtrace/shuttle.h> +#include <library/cpp/lwtrace/shuttle.h> #include <util/generic/string.h> #include <util/generic/list.h> @@ -108,7 +108,7 @@ struct TEventHolder : TNonCopyable { ui64 Serial; ui32 EventSerializedSize; ui32 EventActuallySerialized; - mutable NLWTrace::TOrbit Orbit; + mutable NLWTrace::TOrbit Orbit; ui32 Fill(IEventHandle& ev); @@ -136,7 +136,7 @@ struct TEventHolder : TNonCopyable { void Clear() { Event.Reset(); Buffer.Reset(); - Orbit.Reset(); + Orbit.Reset(); } }; @@ -154,7 +154,7 @@ struct TTcpPacketOutTask : TNonCopyable { bool TriedWriting; char *FreeArea; char *End; - mutable NLWTrace::TOrbit Orbit; + mutable NLWTrace::TOrbit Orbit; public: TTcpPacketOutTask(const TSessionParams& params) @@ -189,7 +189,7 @@ public: TriedWriting = false; FreeArea = Params.UseModernFrame ? Packet.v2.Data : Packet.v1.Data; End = FreeArea + TTcpPacketBuf::PacketDataLen; - Orbit.Reset(); + Orbit.Reset(); } bool IsEmpty() const { diff --git a/library/cpp/actors/interconnect/poller_actor.cpp b/library/cpp/actors/interconnect/poller_actor.cpp index e75cbcaef4..ef363b208e 100644 --- a/library/cpp/actors/interconnect/poller_actor.cpp +++ b/library/cpp/actors/interconnect/poller_actor.cpp @@ -5,7 +5,7 @@ #include <library/cpp/actors/core/actorsystem.h> #include <library/cpp/actors/core/hfunc.h> #include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/probes.h> +#include <library/cpp/actors/core/probes.h> #include <library/cpp/actors/protos/services_common.pb.h> #include <library/cpp/actors/util/funnel_queue.h> @@ -17,9 +17,9 @@ #include <variant> namespace NActors { - - LWTRACE_USING(ACTORLIB_PROVIDER); - + + LWTRACE_USING(ACTORLIB_PROVIDER); + namespace { int LastSocketError() { #if defined(_win_) diff --git a/library/cpp/actors/interconnect/profiler.h b/library/cpp/actors/interconnect/profiler.h index 77a59e3179..d9192e1559 100644 --- a/library/cpp/actors/interconnect/profiler.h +++ b/library/cpp/actors/interconnect/profiler.h @@ -1,7 +1,7 @@ #pragma once -#include <library/cpp/actors/util/datetime.h> - +#include <library/cpp/actors/util/datetime.h> + namespace NActors { class TProfiled { @@ -14,7 +14,7 @@ namespace NActors { EType Type; // entry kind int Line; const char *Marker; // name of the profiled function/part - ui64 Timestamp; // cycles + ui64 Timestamp; // cycles }; bool Enable = false; @@ -44,7 +44,7 @@ namespace NActors { type, line, marker, - GetCycleCountFast() + GetCycleCountFast() }); } } diff --git a/library/cpp/actors/memory_log/memlog.cpp b/library/cpp/actors/memory_log/memlog.cpp index 8e6b46727d..a7ffa24623 100644 --- a/library/cpp/actors/memory_log/memlog.cpp +++ b/library/cpp/actors/memory_log/memlog.cpp @@ -1,7 +1,7 @@ #include "memlog.h" -#include <library/cpp/actors/util/datetime.h> - +#include <library/cpp/actors/util/datetime.h> + #include <util/system/info.h> #include <util/system/atomic.h> #include <util/system/align.h> @@ -270,7 +270,7 @@ bool MemLogWrite(const char* begin, size_t msgSize, bool addLF) noexcept { Y_VERIFY(AlignDown(&prolog, TMemoryLog::MemcpyAlignment) == &prolog); int snprintfResult = snprintf(prolog, prologSize + 1, - "TS %020" PRIu64 " TI %020" PRIu64 " ", GetCycleCountFast(), threadId); + "TS %020" PRIu64 " TI %020" PRIu64 " ", GetCycleCountFast(), threadId); if (snprintfResult < 0) { return false; @@ -341,7 +341,7 @@ bool MemLogVPrintF(const char* format, va_list params) noexcept { int prologSize = snprintf(buf, TMemoryLog::MAX_MESSAGE_SIZE - 2, "TS %020" PRIu64 " TI %020" PRIu64 " ", - GetCycleCountFast(), + GetCycleCountFast(), threadId); if (Y_UNLIKELY(prologSize < 0)) { diff --git a/library/cpp/actors/testlib/test_runtime.cpp b/library/cpp/actors/testlib/test_runtime.cpp index 6fa25b9965..008e25b416 100644 --- a/library/cpp/actors/testlib/test_runtime.cpp +++ b/library/cpp/actors/testlib/test_runtime.cpp @@ -6,7 +6,7 @@ #include <library/cpp/actors/core/executor_pool_io.h> #include <library/cpp/actors/core/log.h> #include <library/cpp/actors/core/scheduler_basic.h> -#include <library/cpp/actors/util/datetime.h> +#include <library/cpp/actors/util/datetime.h> #include <library/cpp/actors/protos/services_common.pb.h> #include <library/cpp/random_provider/random_provider.h> #include <library/cpp/actors/interconnect/interconnect.h> @@ -248,7 +248,7 @@ namespace NActors { Node->ActorSystemMonotonic = currentMonotonic; } - void PrepareSchedules(NSchedulerQueue::TReader **readers, ui32 scheduleReadersCount) override { + void PrepareSchedules(NSchedulerQueue::TReader **readers, ui32 scheduleReadersCount) override { Y_UNUSED(readers); Y_UNUSED(scheduleReadersCount); } @@ -282,33 +282,33 @@ namespace NActors { } // for threads - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override { - Y_UNUSED(wctx); + ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override { + Y_UNUSED(wctx); Y_UNUSED(revolvingCounter); Y_FAIL(); } - void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingCounter) override { - Y_UNUSED(workerId); + void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingCounter) override { + Y_UNUSED(workerId); Node->MailboxTable->ReclaimMailbox(mailboxType, hint, revolvingCounter); } - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override { - DoSchedule(deadline, ev, cookie, workerId); + void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override { + DoSchedule(deadline, ev, cookie, workerId); } - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override { - DoSchedule(TInstant::FromValue(deadline.GetValue()), ev, cookie, workerId); + void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override { + DoSchedule(TInstant::FromValue(deadline.GetValue()), ev, cookie, workerId); } - void Schedule(TDuration delay, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override { + void Schedule(TDuration delay, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override { TInstant deadline = Runtime->GetTimeProvider()->Now() + delay; - DoSchedule(deadline, ev, cookie, workerId); + DoSchedule(deadline, ev, cookie, workerId); } - void DoSchedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) { - Y_UNUSED(workerId); - + void DoSchedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) { + Y_UNUSED(workerId); + TGuard<TMutex> guard(Runtime->Mutex); bool verbose = (Runtime->CurrentDispatchContext ? !Runtime->CurrentDispatchContext->Options->Quiet : true) && VERBOSE; if (Runtime->BlockedOutput.find(ev->Sender) != Runtime->BlockedOutput.end()) { @@ -372,7 +372,7 @@ namespace NActors { TMailboxHeader* mailbox = node->MailboxTable->Get(mailboxHint); IActor* recipientActor = mailbox->FindActor(ev->GetRecipientRewrite().LocalId()); if (recipientActor) { - TActorContext ctx(*mailbox, *node->ExecutorThread, GetCycleCountFast(), ev->GetRecipientRewrite()); + TActorContext ctx(*mailbox, *node->ExecutorThread, GetCycleCountFast(), ev->GetRecipientRewrite()); TActivationContext *prevTlsActivationContext = TlsActivationContext; TlsActivationContext = &ctx; recipientActor->Receive(ev, ctx); @@ -412,7 +412,7 @@ namespace NActors { } // lifecycle stuff - void Prepare(TActorSystem *actorSystem, NSchedulerQueue::TReader **scheduleReaders, ui32 *scheduleSz) override { + void Prepare(TActorSystem *actorSystem, NSchedulerQueue::TReader **scheduleReaders, ui32 *scheduleSz) override { Y_UNUSED(actorSystem); Y_UNUSED(scheduleReaders); Y_UNUSED(scheduleSz); @@ -507,7 +507,7 @@ namespace NActors { node->SchedulerPool.Reset(CreateExecutorPoolStub(this, nodeIndex, node, 0)); node->MailboxTable.Reset(new TMailboxTable()); node->ActorSystem = MakeActorSystem(nodeIndex, node); - node->ExecutorThread.Reset(new TExecutorThread(0, 0, node->ActorSystem.Get(), node->SchedulerPool.Get(), node->MailboxTable.Get(), "TestExecutor")); + node->ExecutorThread.Reset(new TExecutorThread(0, 0, node->ActorSystem.Get(), node->SchedulerPool.Get(), node->MailboxTable.Get(), "TestExecutor")); } else { node->ActorSystem = MakeActorSystem(nodeIndex, node); } @@ -904,19 +904,19 @@ namespace NActors { switch (mailboxType) { case TMailboxType::Simple: - UnlockFromExecution((TMailboxTable::TSimpleMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); + UnlockFromExecution((TMailboxTable::TSimpleMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); break; case TMailboxType::Revolving: - UnlockFromExecution((TMailboxTable::TRevolvingMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); + UnlockFromExecution((TMailboxTable::TRevolvingMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); break; case TMailboxType::HTSwap: - UnlockFromExecution((TMailboxTable::THTSwapMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); + UnlockFromExecution((TMailboxTable::THTSwapMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); break; case TMailboxType::ReadAsFilled: - UnlockFromExecution((TMailboxTable::TReadAsFilledMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); + UnlockFromExecution((TMailboxTable::TReadAsFilledMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); break; case TMailboxType::TinyReadAsFilled: - UnlockFromExecution((TMailboxTable::TTinyReadAsFilledMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); + UnlockFromExecution((TMailboxTable::TTinyReadAsFilledMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); break; default: Y_FAIL("Unsupported mailbox type"); @@ -1029,13 +1029,13 @@ namespace NActors { } bool TTestActorRuntimeBase::DispatchEvents(const TDispatchOptions& options) { - return DispatchEvents(options, TInstant::Max()); - } - + return DispatchEvents(options, TInstant::Max()); + } + bool TTestActorRuntimeBase::DispatchEvents(const TDispatchOptions& options, TDuration simTimeout) { - return DispatchEvents(options, TInstant::MicroSeconds(CurrentTimestamp) + simTimeout); - } - + return DispatchEvents(options, TInstant::MicroSeconds(CurrentTimestamp) + simTimeout); + } + bool TTestActorRuntimeBase::DispatchEvents(const TDispatchOptions& options, TInstant simDeadline) { TGuard<TMutex> guard(Mutex); return DispatchEventsInternal(options, simDeadline); @@ -1251,7 +1251,7 @@ namespace NActors { } if (!localContext.FoundNonEmptyMailboxes.empty()) - return true; + return true; if (options.CustomFinalCondition && options.CustomFinalCondition()) return true; @@ -1266,15 +1266,15 @@ namespace NActors { Cerr << "Dispatch complete with non-empty queue at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n"; } - return true; + return true; } } } - if (TInstant::MicroSeconds(CurrentTimestamp) > simDeadline) { - return false; - } - + if (TInstant::MicroSeconds(CurrentTimestamp) > simDeadline) { + return false; + } + if (dispatchTime >= deadline) { if (verbose) { Cerr << "Reach deadline at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n"; @@ -1333,7 +1333,7 @@ namespace NActors { Cerr << "Process selected events at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n"; } - deadline = dispatchTime + DispatchTimeout; + deadline = dispatchTime + DispatchTimeout; continue; } @@ -1351,7 +1351,7 @@ namespace NActors { dispatchTime += waitDelay; MailboxesHasEvents.WaitT(Mutex, waitDelay); } - return false; + return false; } void TTestActorRuntimeBase::HandleNonEmptyMailboxesForEachContext(TEventMailboxId mboxId) { @@ -1452,8 +1452,8 @@ namespace NActors { ++dispatchCount; { if (!DispatchEventsInternal(TDispatchOptions(), deadline)) { - return; // Timed out; event was not found - } + return; // Timed out; event was not found + } } Y_VERIFY(dispatchCount < 1000, "Hard limit to prevent endless loop"); @@ -1572,7 +1572,7 @@ namespace NActors { // Save actorId by value in order to prevent ctx from being invalidated during another Send call. TActorId actorId = ev->GetRecipientRewrite(); node->ActorToActorId[recipientActor] = ev->GetRecipientRewrite(); - TActorContext ctx(*mailbox, *node->ExecutorThread, GetCycleCountFast(), actorId); + TActorContext ctx(*mailbox, *node->ExecutorThread, GetCycleCountFast(), actorId); TActivationContext *prevTlsActivationContext = TlsActivationContext; TlsActivationContext = &ctx; CurrentRecipient = actorId; diff --git a/library/cpp/actors/testlib/test_runtime.h b/library/cpp/actors/testlib/test_runtime.h index 26e3b45c98..863e2cdb49 100644 --- a/library/cpp/actors/testlib/test_runtime.h +++ b/library/cpp/actors/testlib/test_runtime.h @@ -253,9 +253,9 @@ namespace NActors { void PushEventsFront(TEventsList& events); void PushMailboxEventsFront(ui32 hint, ui32 nodeId, TEventsList& events); // doesn't dispatch events for edge actors - bool DispatchEvents(const TDispatchOptions& options = TDispatchOptions()); - bool DispatchEvents(const TDispatchOptions& options, TDuration simTimeout); - bool DispatchEvents(const TDispatchOptions& options, TInstant simDeadline); + bool DispatchEvents(const TDispatchOptions& options = TDispatchOptions()); + bool DispatchEvents(const TDispatchOptions& options, TDuration simTimeout); + bool DispatchEvents(const TDispatchOptions& options, TInstant simDeadline); void Send(IEventHandle* ev, ui32 senderNodeIndex = 0, bool viaActorSystem = false); void Schedule(IEventHandle* ev, const TDuration& duration, ui32 nodeIndex = 0); void ClearCounters(); @@ -288,7 +288,7 @@ namespace NActors { TActorSystem* GetAnyNodeActorSystem(); TActorSystem* GetActorSystem(ui32 nodeId); template <typename TEvent> - TEvent* GrabEdgeEventIf(TAutoPtr<IEventHandle>& handle, std::function<bool(const TEvent&)> predicate, TDuration simTimeout = TDuration::Max()) { + TEvent* GrabEdgeEventIf(TAutoPtr<IEventHandle>& handle, std::function<bool(const TEvent&)> predicate, TDuration simTimeout = TDuration::Max()) { handle.Destroy(); const ui32 eventType = TEvent::EventType; WaitForEdgeEvents([&](TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) { @@ -305,14 +305,14 @@ namespace NActors { return false; }, {}, simTimeout); - if (simTimeout == TDuration::Max()) + if (simTimeout == TDuration::Max()) Y_VERIFY(handle); - - if (handle) { - return reinterpret_cast<TAutoPtr<TEventHandle<TEvent>>&>(handle)->Get(); - } else { - return nullptr; - } + + if (handle) { + return reinterpret_cast<TAutoPtr<TEventHandle<TEvent>>&>(handle)->Get(); + } else { + return nullptr; + } } template<class TEvent> @@ -354,9 +354,9 @@ namespace NActors { } template <typename TEvent> - TEvent* GrabEdgeEvent(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) { + TEvent* GrabEdgeEvent(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) { std::function<bool(const TEvent&)> truth = [](const TEvent&) { return true; }; - return GrabEdgeEventIf(handle, truth, simTimeout); + return GrabEdgeEventIf(handle, truth, simTimeout); } template <typename TEvent> @@ -400,9 +400,9 @@ namespace NActors { } template <typename TEvent> - TEvent* GrabEdgeEventRethrow(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) { + TEvent* GrabEdgeEventRethrow(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) { try { - return GrabEdgeEvent<TEvent>(handle, simTimeout); + return GrabEdgeEvent<TEvent>(handle, simTimeout); } catch (...) { ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage(); } diff --git a/library/cpp/actors/util/affinity.cpp b/library/cpp/actors/util/affinity.cpp index cc1b6e70ec..69f9048ec1 100644 --- a/library/cpp/actors/util/affinity.cpp +++ b/library/cpp/actors/util/affinity.cpp @@ -16,17 +16,17 @@ public: #endif } - explicit TImpl(const ui8* cpus, ui32 size) { + explicit TImpl(const ui8* cpus, ui32 size) { #ifdef _linux_ CPU_ZERO(&Mask); - for (ui32 i = 0; i != size; ++i) { - if (cpus[i]) { - CPU_SET(i, &Mask); - } - } + for (ui32 i = 0; i != size; ++i) { + if (cpus[i]) { + CPU_SET(i, &Mask); + } + } #else - Y_UNUSED(cpus); - Y_UNUSED(size); + Y_UNUSED(cpus); + Y_UNUSED(size); #endif } @@ -36,18 +36,18 @@ public: Y_VERIFY_DEBUG(ar == 0); #endif } - - operator TCpuMask() const { - TCpuMask result; -#ifdef _linux_ - for (ui32 i = 0; i != CPU_SETSIZE; ++i) { - result.Cpus.emplace_back(CPU_ISSET(i, &Mask)); - } - result.RemoveTrailingZeros(); -#endif - return result; - } - + + operator TCpuMask() const { + TCpuMask result; +#ifdef _linux_ + for (ui32 i = 0; i != CPU_SETSIZE; ++i) { + result.Cpus.emplace_back(CPU_ISSET(i, &Mask)); + } + result.RemoveTrailingZeros(); +#endif + return result; + } + }; TAffinity::TAffinity() { @@ -57,37 +57,37 @@ TAffinity::~TAffinity() { } TAffinity::TAffinity(const ui8* x, ui32 sz) { - if (x && sz) { - Impl.Reset(new TImpl(x, sz)); - } -} - -TAffinity::TAffinity(const TCpuMask& mask) { - if (!mask.IsEmpty()) { - static_assert(sizeof(ui8) == sizeof(mask.Cpus[0])); - const ui8* x = reinterpret_cast<const ui8*>(&mask.Cpus[0]); - const ui32 sz = mask.Size(); + if (x && sz) { Impl.Reset(new TImpl(x, sz)); - } + } } +TAffinity::TAffinity(const TCpuMask& mask) { + if (!mask.IsEmpty()) { + static_assert(sizeof(ui8) == sizeof(mask.Cpus[0])); + const ui8* x = reinterpret_cast<const ui8*>(&mask.Cpus[0]); + const ui32 sz = mask.Size(); + Impl.Reset(new TImpl(x, sz)); + } +} + void TAffinity::Current() { Impl.Reset(new TImpl()); } void TAffinity::Set() const { - if (!!Impl) { + if (!!Impl) { Impl->Set(); - } + } } bool TAffinity::Empty() const { - return !Impl; -} - -TAffinity::operator TCpuMask() const { - if (!!Impl) { - return *Impl; - } - return TCpuMask(); + return !Impl; } + +TAffinity::operator TCpuMask() const { + if (!!Impl) { + return *Impl; + } + return TCpuMask(); +} diff --git a/library/cpp/actors/util/affinity.h b/library/cpp/actors/util/affinity.h index ae106ed180..c807d03b76 100644 --- a/library/cpp/actors/util/affinity.h +++ b/library/cpp/actors/util/affinity.h @@ -1,27 +1,27 @@ #pragma once #include "defs.h" -#include "cpumask.h" +#include "cpumask.h" -// Platform-specific class to set or get thread affinity +// Platform-specific class to set or get thread affinity class TAffinity: public TThrRefBase, TNonCopyable { class TImpl; THolder<TImpl> Impl; public: TAffinity(); - TAffinity(const ui8* cpus, ui32 size); - explicit TAffinity(const TCpuMask& mask); + TAffinity(const ui8* cpus, ui32 size); + explicit TAffinity(const TCpuMask& mask); ~TAffinity(); void Current(); void Set() const; bool Empty() const; - - operator TCpuMask() const; + + operator TCpuMask() const; }; -// Scoped affinity setter +// Scoped affinity setter class TAffinityGuard : TNonCopyable { bool Stacked; TAffinity OldAffinity; diff --git a/library/cpp/actors/util/cpumask.h b/library/cpp/actors/util/cpumask.h index 29741aa1d6..1f72ae3895 100644 --- a/library/cpp/actors/util/cpumask.h +++ b/library/cpp/actors/util/cpumask.h @@ -1,133 +1,133 @@ -#pragma once - -#include "defs.h" - -#include <library/cpp/containers/stack_vector/stack_vec.h> - -#include <util/string/split.h> -#include <util/generic/yexception.h> - -using TCpuId = ui32; - -// Simple data structure to operate with set of cpus -struct TCpuMask { - TStackVec<bool, 1024> Cpus; - - // Creates empty mask - TCpuMask() {} - - // Creates mask with single cpu set - explicit TCpuMask(TCpuId cpuId) { - Set(cpuId); - } - - // Initialize mask from raw boolean array - template <class T> - TCpuMask(const T* cpus, TCpuId size) { - Cpus.reserve(size); - for (TCpuId i = 0; i != size; ++i) { - Cpus.emplace_back(bool(cpus[i])); - } - } - - // Parse a numerical list of processors. The numbers are separated by commas and may include ranges. For example: 0,5,7,9-11 - explicit TCpuMask(const TString& cpuList) { - try { - for (TStringBuf s : StringSplitter(cpuList).Split(',')) { - TCpuId l, r; - if (s.find('-') != TString::npos) { - StringSplitter(s).Split('-').CollectInto(&l, &r); - } else { - l = r = FromString<TCpuId>(s); - } - if (r >= Cpus.size()) { - Cpus.resize(r + 1, false); - } - for (TCpuId cpu = l; cpu <= r; cpu++) { - Cpus[cpu] = true; - } - } - } catch (...) { - ythrow TWithBackTrace<yexception>() << "Exception occured while parsing cpu list '" << cpuList << "': " << CurrentExceptionMessage(); - } - } - - // Returns size of underlying vector - TCpuId Size() const { - return Cpus.size(); - } - - // Returns number of set bits in mask - TCpuId CpuCount() const { - TCpuId result = 0; - for (bool value : Cpus) { - result += value; - } - return result; - } - - bool IsEmpty() const { - for (bool value : Cpus) { - if (value) { - return false; - } - } - return true; - } - - bool IsSet(TCpuId cpu) const { - return cpu < Cpus.size() && Cpus[cpu]; - } - - void Set(TCpuId cpu) { - if (cpu >= Cpus.size()) { - Cpus.resize(cpu + 1, false); - } - Cpus[cpu] = true; - } - - void Reset(TCpuId cpu) { - if (cpu < Cpus.size()) { - Cpus[cpu] = false; - } - } - - void RemoveTrailingZeros() { - while (!Cpus.empty() && !Cpus.back()) { - Cpus.pop_back(); - } - } - - explicit operator bool() const { - return !IsEmpty(); - } - - TCpuMask operator &(const TCpuMask& rhs) const { - TCpuMask result; - TCpuId size = Max(Size(), rhs.Size()); - result.Cpus.reserve(size); - for (TCpuId cpu = 0; cpu < size; cpu++) { - result.Cpus.emplace_back(IsSet(cpu) && rhs.IsSet(cpu)); - } - return result; - } - - TCpuMask operator |(const TCpuMask& rhs) const { - TCpuMask result; - TCpuId size = Max(Size(), rhs.Size()); - result.Cpus.reserve(size); - for (TCpuId cpu = 0; cpu < size; cpu++) { - result.Cpus.emplace_back(IsSet(cpu) || rhs.IsSet(cpu)); - } - return result; - } - - TCpuMask operator -(const TCpuMask& rhs) const { - TCpuMask result; - result.Cpus.reserve(Size()); - for (TCpuId cpu = 0; cpu < Size(); cpu++) { - result.Cpus.emplace_back(IsSet(cpu) && !rhs.IsSet(cpu)); - } - return result; - } -}; +#pragma once + +#include "defs.h" + +#include <library/cpp/containers/stack_vector/stack_vec.h> + +#include <util/string/split.h> +#include <util/generic/yexception.h> + +using TCpuId = ui32; + +// Simple data structure to operate with set of cpus +struct TCpuMask { + TStackVec<bool, 1024> Cpus; + + // Creates empty mask + TCpuMask() {} + + // Creates mask with single cpu set + explicit TCpuMask(TCpuId cpuId) { + Set(cpuId); + } + + // Initialize mask from raw boolean array + template <class T> + TCpuMask(const T* cpus, TCpuId size) { + Cpus.reserve(size); + for (TCpuId i = 0; i != size; ++i) { + Cpus.emplace_back(bool(cpus[i])); + } + } + + // Parse a numerical list of processors. The numbers are separated by commas and may include ranges. For example: 0,5,7,9-11 + explicit TCpuMask(const TString& cpuList) { + try { + for (TStringBuf s : StringSplitter(cpuList).Split(',')) { + TCpuId l, r; + if (s.find('-') != TString::npos) { + StringSplitter(s).Split('-').CollectInto(&l, &r); + } else { + l = r = FromString<TCpuId>(s); + } + if (r >= Cpus.size()) { + Cpus.resize(r + 1, false); + } + for (TCpuId cpu = l; cpu <= r; cpu++) { + Cpus[cpu] = true; + } + } + } catch (...) { + ythrow TWithBackTrace<yexception>() << "Exception occured while parsing cpu list '" << cpuList << "': " << CurrentExceptionMessage(); + } + } + + // Returns size of underlying vector + TCpuId Size() const { + return Cpus.size(); + } + + // Returns number of set bits in mask + TCpuId CpuCount() const { + TCpuId result = 0; + for (bool value : Cpus) { + result += value; + } + return result; + } + + bool IsEmpty() const { + for (bool value : Cpus) { + if (value) { + return false; + } + } + return true; + } + + bool IsSet(TCpuId cpu) const { + return cpu < Cpus.size() && Cpus[cpu]; + } + + void Set(TCpuId cpu) { + if (cpu >= Cpus.size()) { + Cpus.resize(cpu + 1, false); + } + Cpus[cpu] = true; + } + + void Reset(TCpuId cpu) { + if (cpu < Cpus.size()) { + Cpus[cpu] = false; + } + } + + void RemoveTrailingZeros() { + while (!Cpus.empty() && !Cpus.back()) { + Cpus.pop_back(); + } + } + + explicit operator bool() const { + return !IsEmpty(); + } + + TCpuMask operator &(const TCpuMask& rhs) const { + TCpuMask result; + TCpuId size = Max(Size(), rhs.Size()); + result.Cpus.reserve(size); + for (TCpuId cpu = 0; cpu < size; cpu++) { + result.Cpus.emplace_back(IsSet(cpu) && rhs.IsSet(cpu)); + } + return result; + } + + TCpuMask operator |(const TCpuMask& rhs) const { + TCpuMask result; + TCpuId size = Max(Size(), rhs.Size()); + result.Cpus.reserve(size); + for (TCpuId cpu = 0; cpu < size; cpu++) { + result.Cpus.emplace_back(IsSet(cpu) || rhs.IsSet(cpu)); + } + return result; + } + + TCpuMask operator -(const TCpuMask& rhs) const { + TCpuMask result; + result.Cpus.reserve(Size()); + for (TCpuId cpu = 0; cpu < Size(); cpu++) { + result.Cpus.emplace_back(IsSet(cpu) && !rhs.IsSet(cpu)); + } + return result; + } +}; diff --git a/library/cpp/actors/util/datetime.h b/library/cpp/actors/util/datetime.h index cbec5965d6..4bdf57bbde 100644 --- a/library/cpp/actors/util/datetime.h +++ b/library/cpp/actors/util/datetime.h @@ -1,82 +1,82 @@ -#pragma once - -#include <util/system/defaults.h> -#include <util/system/hp_timer.h> -#include <util/system/platform.h> - -#if defined(_win_) -#include <intrin.h> -#pragma intrinsic(__rdtsc) -#endif // _win_ - -#if defined(_darwin_) && !defined(_x86_) -#include <mach/mach_time.h> -#endif - -// GetCycleCount() from util/system/datetime.h uses rdtscp, which is more accurate than rdtsc, -// but rdtscp disables processor's out-of-order execution, so it can be slow -Y_FORCE_INLINE ui64 GetCycleCountFast() { -#if defined(_MSC_VER) - // Generates the rdtsc instruction, which returns the processor time stamp. - // The processor time stamp records the number of clock cycles since the last reset. - return __rdtsc(); -#elif defined(__clang__) && !defined(_arm64_) - return __builtin_readcyclecounter(); -#elif defined(_x86_64_) - unsigned hi, lo; - __asm__ __volatile__("rdtsc" - : "=a"(lo), "=d"(hi)); - return ((unsigned long long)lo) | (((unsigned long long)hi) << 32); -#elif defined(_i386_) - ui64 x; - __asm__ volatile("rdtsc\n\t" - : "=A"(x)); - return x; -#elif defined(_darwin_) - return mach_absolute_time(); -#elif defined(_arm32_) - return MicroSeconds(); -#elif defined(_arm64_) - ui64 x; - - __asm__ __volatile__("isb; mrs %0, cntvct_el0" - : "=r"(x)); - - return x; -#else -#error "unsupported arch" -#endif -} - -// NHPTimer::GetTime fast analog -Y_FORCE_INLINE void GetTimeFast(NHPTimer::STime* pTime) noexcept { - *pTime = GetCycleCountFast(); -} - -namespace NActors { - inline double Ts2Ns(ui64 ts) { - return NHPTimer::GetSeconds(ts) * 1e9; - } - - inline double Ts2Us(ui64 ts) { - return NHPTimer::GetSeconds(ts) * 1e6; - } - - inline double Ts2Ms(ui64 ts) { - return NHPTimer::GetSeconds(ts) * 1e3; - } - - inline ui64 Us2Ts(double us) { - return ui64(NHPTimer::GetClockRate() * us / 1e6); - } - - struct TTimeTracker { - ui64 Ts; - TTimeTracker(): Ts(GetCycleCountFast()) {} - ui64 Elapsed() { - ui64 ts = GetCycleCountFast(); - std::swap(Ts, ts); - return Ts - ts; - } - }; -} +#pragma once + +#include <util/system/defaults.h> +#include <util/system/hp_timer.h> +#include <util/system/platform.h> + +#if defined(_win_) +#include <intrin.h> +#pragma intrinsic(__rdtsc) +#endif // _win_ + +#if defined(_darwin_) && !defined(_x86_) +#include <mach/mach_time.h> +#endif + +// GetCycleCount() from util/system/datetime.h uses rdtscp, which is more accurate than rdtsc, +// but rdtscp disables processor's out-of-order execution, so it can be slow +Y_FORCE_INLINE ui64 GetCycleCountFast() { +#if defined(_MSC_VER) + // Generates the rdtsc instruction, which returns the processor time stamp. + // The processor time stamp records the number of clock cycles since the last reset. + return __rdtsc(); +#elif defined(__clang__) && !defined(_arm64_) + return __builtin_readcyclecounter(); +#elif defined(_x86_64_) + unsigned hi, lo; + __asm__ __volatile__("rdtsc" + : "=a"(lo), "=d"(hi)); + return ((unsigned long long)lo) | (((unsigned long long)hi) << 32); +#elif defined(_i386_) + ui64 x; + __asm__ volatile("rdtsc\n\t" + : "=A"(x)); + return x; +#elif defined(_darwin_) + return mach_absolute_time(); +#elif defined(_arm32_) + return MicroSeconds(); +#elif defined(_arm64_) + ui64 x; + + __asm__ __volatile__("isb; mrs %0, cntvct_el0" + : "=r"(x)); + + return x; +#else +#error "unsupported arch" +#endif +} + +// NHPTimer::GetTime fast analog +Y_FORCE_INLINE void GetTimeFast(NHPTimer::STime* pTime) noexcept { + *pTime = GetCycleCountFast(); +} + +namespace NActors { + inline double Ts2Ns(ui64 ts) { + return NHPTimer::GetSeconds(ts) * 1e9; + } + + inline double Ts2Us(ui64 ts) { + return NHPTimer::GetSeconds(ts) * 1e6; + } + + inline double Ts2Ms(ui64 ts) { + return NHPTimer::GetSeconds(ts) * 1e3; + } + + inline ui64 Us2Ts(double us) { + return ui64(NHPTimer::GetClockRate() * us / 1e6); + } + + struct TTimeTracker { + ui64 Ts; + TTimeTracker(): Ts(GetCycleCountFast()) {} + ui64 Elapsed() { + ui64 ts = GetCycleCountFast(); + std::swap(Ts, ts); + return Ts - ts; + } + }; +} diff --git a/library/cpp/actors/util/thread.h b/library/cpp/actors/util/thread.h index d742c8c585..4cab922647 100644 --- a/library/cpp/actors/util/thread.h +++ b/library/cpp/actors/util/thread.h @@ -5,7 +5,7 @@ #include <util/system/execpath.h> #include <util/system/thread.h> #include <util/system/thread.h> -#include <time.h> +#include <time.h> inline void SetCurrentThreadName(const TString& name, const ui32 maxCharsFromProcessName = 8) { diff --git a/library/cpp/actors/util/timerfd.h b/library/cpp/actors/util/timerfd.h index 3189e2a672..a9b35ff9e7 100644 --- a/library/cpp/actors/util/timerfd.h +++ b/library/cpp/actors/util/timerfd.h @@ -1,65 +1,65 @@ -#pragma once - -#include "datetime.h" - -#include <util/generic/noncopyable.h> - -#ifdef _linux_ - -#include <util/system/yassert.h> -#include <errno.h> -#include <sys/timerfd.h> - -struct TTimerFd: public TNonCopyable { - int Fd; - - TTimerFd() { - Fd = timerfd_create(CLOCK_MONOTONIC, 0); - Y_VERIFY(Fd != -1, "timerfd_create(CLOCK_MONOTONIC, 0) -> -1; errno:%d: %s", int(errno), strerror(errno)); - } - - ~TTimerFd() { - close(Fd); - } - - void Set(ui64 ts) { - ui64 now = GetCycleCountFast(); - Arm(now >= ts? 1: NHPTimer::GetSeconds(ts - now) * 1e9); - } - - void Reset() { - Arm(0); // disarm timer - } - - void Wait() { - ui64 expirations; - ssize_t s = read(Fd, &expirations, sizeof(ui64)); - Y_UNUSED(s); // Y_VERIFY(s == sizeof(ui64)); - } - - void Wake() { - Arm(1); - } -private: - void Arm(ui64 ns) { - struct itimerspec spec; - spec.it_value.tv_sec = ns / 1'000'000'000; - spec.it_value.tv_nsec = ns % 1'000'000'000; - spec.it_interval.tv_sec = 0; - spec.it_interval.tv_nsec = 0; - int ret = timerfd_settime(Fd, 0, &spec, nullptr); - Y_VERIFY(ret != -1, "timerfd_settime(%d, 0, %" PRIu64 "ns, 0) -> %d; errno:%d: %s", Fd, ns, ret, int(errno), strerror(errno)); - } -}; - -#else - -struct TTimerFd: public TNonCopyable { - int Fd = 0; - void Set(ui64) {} - void Reset() {} - void Wait() {} - void Wake() {} -}; - -#endif +#pragma once + +#include "datetime.h" + +#include <util/generic/noncopyable.h> + +#ifdef _linux_ + +#include <util/system/yassert.h> +#include <errno.h> +#include <sys/timerfd.h> + +struct TTimerFd: public TNonCopyable { + int Fd; + + TTimerFd() { + Fd = timerfd_create(CLOCK_MONOTONIC, 0); + Y_VERIFY(Fd != -1, "timerfd_create(CLOCK_MONOTONIC, 0) -> -1; errno:%d: %s", int(errno), strerror(errno)); + } + + ~TTimerFd() { + close(Fd); + } + + void Set(ui64 ts) { + ui64 now = GetCycleCountFast(); + Arm(now >= ts? 1: NHPTimer::GetSeconds(ts - now) * 1e9); + } + + void Reset() { + Arm(0); // disarm timer + } + + void Wait() { + ui64 expirations; + ssize_t s = read(Fd, &expirations, sizeof(ui64)); + Y_UNUSED(s); // Y_VERIFY(s == sizeof(ui64)); + } + + void Wake() { + Arm(1); + } +private: + void Arm(ui64 ns) { + struct itimerspec spec; + spec.it_value.tv_sec = ns / 1'000'000'000; + spec.it_value.tv_nsec = ns % 1'000'000'000; + spec.it_interval.tv_sec = 0; + spec.it_interval.tv_nsec = 0; + int ret = timerfd_settime(Fd, 0, &spec, nullptr); + Y_VERIFY(ret != -1, "timerfd_settime(%d, 0, %" PRIu64 "ns, 0) -> %d; errno:%d: %s", Fd, ns, ret, int(errno), strerror(errno)); + } +}; + +#else + +struct TTimerFd: public TNonCopyable { + int Fd = 0; + void Set(ui64) {} + void Reset() {} + void Wait() {} + void Wake() {} +}; + +#endif diff --git a/library/cpp/actors/util/ya.make b/library/cpp/actors/util/ya.make index 37488c3962..a8bfd05d5a 100644 --- a/library/cpp/actors/util/ya.make +++ b/library/cpp/actors/util/ya.make @@ -8,8 +8,8 @@ OWNER( SRCS( affinity.cpp affinity.h - cpumask.h - datetime.h + cpumask.h + datetime.h defs.h funnel_queue.h futex.h @@ -26,7 +26,7 @@ SRCS( threadparkpad.cpp threadparkpad.h ticket_lock.h - timerfd.h + timerfd.h unordered_cache.h ) diff --git a/library/cpp/bucket_quoter/bucket_quoter.h b/library/cpp/bucket_quoter/bucket_quoter.h index 3d92ef8450..74eeee2601 100644 --- a/library/cpp/bucket_quoter/bucket_quoter.h +++ b/library/cpp/bucket_quoter/bucket_quoter.h @@ -2,7 +2,7 @@ #include <util/datetime/base.h> #include <util/system/mutex.h> -#include <util/system/hp_timer.h> +#include <util/system/hp_timer.h> /* Token bucket. * Makes flow of *inflow* units per second in average, with up to *capacity* bursts. @@ -39,54 +39,54 @@ */ -struct TInstantTimerMs { - using TTime = TInstant; - static constexpr ui64 Resolution = 1000ull; // milliseconds - static TTime Now() { - return TInstant::Now(); - } - static ui64 Duration(TTime from, TTime to) { - return (to - from).MilliSeconds(); - } -}; - -struct THPTimerUs { - using TTime = NHPTimer::STime; +struct TInstantTimerMs { + using TTime = TInstant; + static constexpr ui64 Resolution = 1000ull; // milliseconds + static TTime Now() { + return TInstant::Now(); + } + static ui64 Duration(TTime from, TTime to) { + return (to - from).MilliSeconds(); + } +}; + +struct THPTimerUs { + using TTime = NHPTimer::STime; static constexpr ui64 Resolution = 1000000ull; // microseconds - static TTime Now() { - NHPTimer::STime ret; - NHPTimer::GetTime(&ret); - return ret; - } - static ui64 Duration(TTime from, TTime to) { - i64 cycles = to - from; - if (cycles > 0) { - return ui64(double(cycles) * double(Resolution) / NHPTimer::GetClockRate()); - } else { - return 0; - } - } -}; - -template <typename StatCounter, typename Lock = TMutex, typename Timer = TInstantTimerMs> + static TTime Now() { + NHPTimer::STime ret; + NHPTimer::GetTime(&ret); + return ret; + } + static ui64 Duration(TTime from, TTime to) { + i64 cycles = to - from; + if (cycles > 0) { + return ui64(double(cycles) * double(Resolution) / NHPTimer::GetClockRate()); + } else { + return 0; + } + } +}; + +template <typename StatCounter, typename Lock = TMutex, typename Timer = TInstantTimerMs> class TBucketQuoter { public: - using TTime = typename Timer::TTime; - - struct TResult { - i64 Before; - i64 After; - ui64 Seqno; - }; - + using TTime = typename Timer::TTime; + + struct TResult { + i64 Before; + i64 After; + ui64 Seqno; + }; + /* fixed quota */ - TBucketQuoter(ui64 inflow, ui64 capacity, StatCounter* msgPassed = nullptr, - StatCounter* bucketUnderflows = nullptr, StatCounter* tokensUsed = nullptr, + TBucketQuoter(ui64 inflow, ui64 capacity, StatCounter* msgPassed = nullptr, + StatCounter* bucketUnderflows = nullptr, StatCounter* tokensUsed = nullptr, StatCounter* usecWaited = nullptr, bool fill = false, StatCounter* aggregateInflow = nullptr) : MsgPassed(msgPassed) , BucketUnderflows(bucketUnderflows) , TokensUsed(tokensUsed) - , UsecWaited(usecWaited) + , UsecWaited(usecWaited) , AggregateInflow(aggregateInflow) , Bucket(fill ? capacity : 0) , LastAdd(Timer::Now()) @@ -99,13 +99,13 @@ public: } /* adjustable quotas */ - TBucketQuoter(TAtomic* inflow, TAtomic* capacity, StatCounter* msgPassed = nullptr, - StatCounter* bucketUnderflows = nullptr, StatCounter* tokensUsed = nullptr, + TBucketQuoter(TAtomic* inflow, TAtomic* capacity, StatCounter* msgPassed = nullptr, + StatCounter* bucketUnderflows = nullptr, StatCounter* tokensUsed = nullptr, StatCounter* usecWaited = nullptr, bool fill = false, StatCounter* aggregateInflow = nullptr) : MsgPassed(msgPassed) , BucketUnderflows(bucketUnderflows) , TokensUsed(tokensUsed) - , UsecWaited(usecWaited) + , UsecWaited(usecWaited) , AggregateInflow(aggregateInflow) , Bucket(fill ? AtomicGet(*capacity) : 0) , LastAdd(Timer::Now()) @@ -116,22 +116,22 @@ public: } bool IsAvail() { - TGuard<Lock> g(BucketMutex); - FillBucket(); - if (Bucket < 0) { - if (BucketUnderflows) { - (*BucketUnderflows)++; - } - } - return (Bucket >= 0); - } - - bool IsAvail(TResult& res) { - TGuard<Lock> g(BucketMutex); - res.Before = Bucket; + TGuard<Lock> g(BucketMutex); + FillBucket(); + if (Bucket < 0) { + if (BucketUnderflows) { + (*BucketUnderflows)++; + } + } + return (Bucket >= 0); + } + + bool IsAvail(TResult& res) { + TGuard<Lock> g(BucketMutex); + res.Before = Bucket; FillBucket(); - res.After = Bucket; - res.Seqno = ++Seqno; + res.After = Bucket; + res.Seqno = ++Seqno; if (Bucket < 0) { if (BucketUnderflows) { (*BucketUnderflows)++; @@ -140,58 +140,58 @@ public: return (Bucket >= 0); } - ui64 GetAvail() { - TGuard<Lock> g(BucketMutex); - FillBucket(); - return Max<i64>(0, Bucket); - } - - ui64 GetAvail(TResult& res) { - TGuard<Lock> g(BucketMutex); - res.Before = Bucket; - FillBucket(); - res.After = Bucket; - res.Seqno = ++Seqno; - return Max<i64>(0, Bucket); - } - + ui64 GetAvail() { + TGuard<Lock> g(BucketMutex); + FillBucket(); + return Max<i64>(0, Bucket); + } + + ui64 GetAvail(TResult& res) { + TGuard<Lock> g(BucketMutex); + res.Before = Bucket; + FillBucket(); + res.After = Bucket; + res.Seqno = ++Seqno; + return Max<i64>(0, Bucket); + } + void Use(ui64 tokens, bool sleep = false) { - TGuard<Lock> g(BucketMutex); - UseNoLock(tokens, sleep); - } - - void Use(ui64 tokens, TResult& res, bool sleep = false) { - TGuard<Lock> g(BucketMutex); - res.Before = Bucket; - UseNoLock(tokens, sleep); - res.After = Bucket; - res.Seqno = ++Seqno; + TGuard<Lock> g(BucketMutex); + UseNoLock(tokens, sleep); } - i64 UseAndFill(ui64 tokens) { - TGuard<Lock> g(BucketMutex); - UseNoLock(tokens); - FillBucket(); - return Bucket; - } - - void Add(ui64 tokens) { - TGuard<Lock> g(BucketMutex); - AddNoLock(tokens); - } - - void Add(ui64 tokens, TResult& res) { - TGuard<Lock> g(BucketMutex); - res.Before = Bucket; - AddNoLock(tokens); - res.After = Bucket; - res.Seqno = ++Seqno; - } - - ui32 GetWaitTime() { - TGuard<Lock> g(BucketMutex); - + void Use(ui64 tokens, TResult& res, bool sleep = false) { + TGuard<Lock> g(BucketMutex); + res.Before = Bucket; + UseNoLock(tokens, sleep); + res.After = Bucket; + res.Seqno = ++Seqno; + } + + i64 UseAndFill(ui64 tokens) { + TGuard<Lock> g(BucketMutex); + UseNoLock(tokens); FillBucket(); + return Bucket; + } + + void Add(ui64 tokens) { + TGuard<Lock> g(BucketMutex); + AddNoLock(tokens); + } + + void Add(ui64 tokens, TResult& res) { + TGuard<Lock> g(BucketMutex); + res.Before = Bucket; + AddNoLock(tokens); + res.After = Bucket; + res.Seqno = ++Seqno; + } + + ui32 GetWaitTime() { + TGuard<Lock> g(BucketMutex); + + FillBucket(); if (Bucket >= 0) { return 0; } @@ -200,37 +200,37 @@ public: return usec; } - ui32 GetWaitTime(TResult& res) { - TGuard<Lock> g(BucketMutex); - res.Before = Bucket; - FillBucket(); - res.After = Bucket; - res.Seqno = ++Seqno; - if (Bucket >= 0) { - return 0; - } - ui32 usec = (-Bucket * 1000000) / (*InflowTokensPerSecond); - return usec; - } - + ui32 GetWaitTime(TResult& res) { + TGuard<Lock> g(BucketMutex); + res.Before = Bucket; + FillBucket(); + res.After = Bucket; + res.Seqno = ++Seqno; + if (Bucket >= 0) { + return 0; + } + ui32 usec = (-Bucket * 1000000) / (*InflowTokensPerSecond); + return usec; + } + void Sleep() { while (!IsAvail()) { ui32 delay = GetWaitTime(); if (delay != 0) { usleep(delay); - if (UsecWaited) { - (*UsecWaited) += delay; - } + if (UsecWaited) { + (*UsecWaited) += delay; + } } } } private: void FillBucket() { - TTime now = Timer::Now(); + TTime now = Timer::Now(); - ui64 elapsed = Timer::Duration(LastAdd, now); - if (*InflowTokensPerSecond * elapsed >= Timer::Resolution) { + ui64 elapsed = Timer::Duration(LastAdd, now); + if (*InflowTokensPerSecond * elapsed >= Timer::Resolution) { ui64 inflow = *InflowTokensPerSecond * elapsed / Timer::Resolution; if (AggregateInflow) { *AggregateInflow += inflow; @@ -244,35 +244,35 @@ private: } } - void UseNoLock(ui64 tokens, bool sleep = false) { - if (sleep) - Sleep(); - Bucket -= tokens; - if (TokensUsed) { - (*TokensUsed) += tokens; - } - if (MsgPassed) { - (*MsgPassed)++; - } - } - - void AddNoLock(ui64 tokens) { - Bucket += tokens; - if (Bucket > *BucketTokensCapacity) { - Bucket = *BucketTokensCapacity; - } - } - + void UseNoLock(ui64 tokens, bool sleep = false) { + if (sleep) + Sleep(); + Bucket -= tokens; + if (TokensUsed) { + (*TokensUsed) += tokens; + } + if (MsgPassed) { + (*MsgPassed)++; + } + } + + void AddNoLock(ui64 tokens) { + Bucket += tokens; + if (Bucket > *BucketTokensCapacity) { + Bucket = *BucketTokensCapacity; + } + } + StatCounter* MsgPassed; StatCounter* BucketUnderflows; StatCounter* TokensUsed; - StatCounter* UsecWaited; + StatCounter* UsecWaited; StatCounter* AggregateInflow; i64 Bucket; - TTime LastAdd; - Lock BucketMutex; - ui64 Seqno = 0; + TTime LastAdd; + Lock BucketMutex; + ui64 Seqno = 0; TAtomic* InflowTokensPerSecond; TAtomic* BucketTokensCapacity; diff --git a/library/cpp/containers/stack_vector/stack_vec.h b/library/cpp/containers/stack_vector/stack_vec.h index fcc5d9a2a5..5b4d370e1f 100644 --- a/library/cpp/containers/stack_vector/stack_vec.h +++ b/library/cpp/containers/stack_vector/stack_vec.h @@ -41,7 +41,7 @@ namespace NPrivate { using typename Alloc::value_type; template <class U> - struct rebind: public ::NPrivate::TRebind<Alloc, TSelf, T, U> { + struct rebind: public ::NPrivate::TRebind<Alloc, TSelf, T, U> { }; public: @@ -82,7 +82,7 @@ namespace NPrivate { private: std::aligned_storage_t<sizeof(T), alignof(T)> StackBasedStorage[CountOnStack]; - bool IsStorageUsed = false; + bool IsStorageUsed = false; private: Alloc& FallbackAllocator() noexcept { diff --git a/library/cpp/http/server/http.cpp b/library/cpp/http/server/http.cpp index 128583bdd7..b461c242ab 100644 --- a/library/cpp/http/server/http.cpp +++ b/library/cpp/http/server/http.cpp @@ -456,7 +456,7 @@ public: TOptions Options_; ICallBack* Cb_ = nullptr; THttpServer* Parent_ = nullptr; - TWakeupPollAble WakeupPollAble; + TWakeupPollAble WakeupPollAble; TMutex StopMutex; private: diff --git a/library/cpp/lwtrace/all.h b/library/cpp/lwtrace/all.h index d7aa57c49d..c086bede4a 100644 --- a/library/cpp/lwtrace/all.h +++ b/library/cpp/lwtrace/all.h @@ -1,195 +1,195 @@ -#pragma once - -#include "control.h" -#include "event.h" +#pragma once + +#include "control.h" +#include "event.h" #include "preprocessor.h" -#include "probe.h" +#include "probe.h" #include "start.h" - -// + +// // Full documentation: https://wiki.yandex-team.ru/development/poisk/arcadia/library/lwtrace/ -// -// Short usage instruction: -// -// 1. Declare probes provider in header file 'probes.h': -// #include <yweb/robot/kiwi/lwtrace/all.h> -// #define MY_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ // name of your provider -// PROBE(MyProbe, GROUPS("MyGroup1", "MyGroup2"), TYPES(), NAMES()) \ // probe specification w/o argiments +// +// Short usage instruction: +// +// 1. Declare probes provider in header file 'probes.h': +// #include <yweb/robot/kiwi/lwtrace/all.h> +// #define MY_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ // name of your provider +// PROBE(MyProbe, GROUPS("MyGroup1", "MyGroup2"), TYPES(), NAMES()) \ // probe specification w/o argiments // PROBE(MyAnotherProbe, GROUPS("MyGroup2"), TYPES(int, TString), NAMES("arg1", "arg2")) \ // another probe with arguments -// PROBE(MyScopedProbe, GROUPS(), TYPES(ui64, int), NAMES("duration", "stage")) \ // scoped probe with argument -// /**/ -// LWTRACE_DECLARE_PROVIDER(MY_PROVIDER) -// -// 2. Define provider in source file 'provider.cpp': -// #include "probes.h" -// LWTRACE_DEFINE_PROVIDER(MY_PROVIDER) -// -// 3. Call probes from provider in your code: -// #include "probes.h" -// int main() { -// GLOBAL_LWPROBE(MY_PROVIDER, MyProbe); -// GLOBAL_LWPROBE(MY_PROVIDER, MyAnotherProbe, 123, stroka); -// ... or ... -// LWTRACE_USING(MY_PROVIDER); // expands into using namespace -// LWPROBE(MyProbe); -// LWPROBE(MyAnotherProbe, 123, stroka); -// } -// -// 4. Attach provider to your monitoring service: -// #include <yweb/robot/kiwi/util/monservice.h> -// #include "probes.h" -// class TMyMonSrvc: public NKiwi::TMonService { -// TMyMonSrvc(TProbeRegistry& probes) -// { -// THolder<NKiwi::TTraceMonPage> tr(new NKiwi::TTraceMonPage()); -// tr->GetProbes().AddProbesList(LWTRACE_GET_PROBES(MY_PROVIDER)); -// Register(tr.Release()); -// } -// }; -// -// 5. Compile and run application -// -// 6. Create file 'mysuper.tr' with trace query: -// Blocks { # Log all calls to probes from MyGroup1 -// ProbeDesc { Group: "MyGroup1" } -// Action { -// LogAction { LogTimestamp: true } -// } -// } -// Blocks { # Log first 10 calls to MyAnother with arg1 > 1000 -// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" } -// Predicate { -// Operators { Type: OT_GT; Param: "arg1"; Value: "1000" } -// } -// Action { -// LogAction { MaxRecords: 10 } -// } -// } -// Blocks { # Start following executon of all 4 blocks each time MyAnotherProbe was called with arg2 == "start" -// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" } -// Predicate { -// Operators { Type: OT_EQ; Param: "arg2"; Value: "start" } -// } -// Action { StartAction {} } -// } -// Blocks { # Stop following executon of all 4 blocks each time MyAnotherProbe was called with arg2 == "stop" -// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" } -// Predicate { -// Operators { Type: OT_EQ; Param: "arg2"; Value: "stop" } -// } -// Action { StopAction {} } -// } -// -// 7. Send trace query to the server with HTTP POST: -// yweb/robot/kiwi/scripts/trace.sh new uniq-id-for-my-trace hostname:monport < mysuper.tr -// -// 8. With browser go to: http://hostname:monport/trace -// -// 9. Delete query from server: -// yweb/robot/kiwi/scripts/trace.sh delete uniq-id-for-my-trace hostname:monport -// -// -// CONFIGURATION AND SUPPORT: -// 1. Turning off all calls to probes. -// Add to project's CMakeLists.txt: add_definitions(-DLWTRACE_DISABLE_PROBES) -// -// 2. Turning off all calls to events. -// Add to project's CMakeLists.txt: add_definitions(-DLWTRACE_DISABLE_EVENTS) -// -// 3. Increasing maximum number of probe parameters: -// Add more lines in FOREACH_PARAMNUM macro definition in preprocessor.h -// -// -// ISSUES -// 1. Note that executors for different blocks are attached in order of their declaration in trace script. -// Executor can be called by a program as soon as it is attached, therefore there is no guarantee that -// all blocks are started simultaneously -// - -#ifndef LWTRACE_DISABLE - -// Declare user provider (see USAGE INSTRUCTION) -#define LWTRACE_DECLARE_PROVIDER(provider) LWTRACE_DECLARE_PROVIDER_I(provider) - -// Define user provider (see USAGE INSTRUCTION) -#define LWTRACE_DEFINE_PROVIDER(provider) LWTRACE_DEFINE_PROVIDER_I(provider) - -// Import names from provider -#define LWTRACE_USING(provider) using namespace LWTRACE_GET_NAMESPACE(provider); - -// Probes and events list accessor -#define LWTRACE_GET_PROBES(provider) LWTRACE_GET_PROBES_I(provider) -#define LWTRACE_GET_EVENTS(provider) LWTRACE_GET_EVENTS_I(provider) - -#ifndef LWTRACE_DISABLE_PROBES - -// Call a probe -// NOTE: LWPROBE() should be used in source files only with previous call to LWTRACE_USING(MY_PROVIDER) -// NOTE: in header files GLOBAL_LWPROBE() should be used instead -// NOTE: if lots of calls needed in header file, it's convenient to define/undef the following macro: -// NOTE: #define MY_PROBE(name, ...) GLOBAL_LWPROBE(MY_PROVIDER, name, ## __VA_ARGS__) -#define GLOBAL_LWPROBE(provider, probe, ...) LWPROBE_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), ##__VA_ARGS__) -#define LWPROBE(probe, ...) LWPROBE_I(LWTRACE_GET_NAME(probe), ##__VA_ARGS__) +// PROBE(MyScopedProbe, GROUPS(), TYPES(ui64, int), NAMES("duration", "stage")) \ // scoped probe with argument +// /**/ +// LWTRACE_DECLARE_PROVIDER(MY_PROVIDER) +// +// 2. Define provider in source file 'provider.cpp': +// #include "probes.h" +// LWTRACE_DEFINE_PROVIDER(MY_PROVIDER) +// +// 3. Call probes from provider in your code: +// #include "probes.h" +// int main() { +// GLOBAL_LWPROBE(MY_PROVIDER, MyProbe); +// GLOBAL_LWPROBE(MY_PROVIDER, MyAnotherProbe, 123, stroka); +// ... or ... +// LWTRACE_USING(MY_PROVIDER); // expands into using namespace +// LWPROBE(MyProbe); +// LWPROBE(MyAnotherProbe, 123, stroka); +// } +// +// 4. Attach provider to your monitoring service: +// #include <yweb/robot/kiwi/util/monservice.h> +// #include "probes.h" +// class TMyMonSrvc: public NKiwi::TMonService { +// TMyMonSrvc(TProbeRegistry& probes) +// { +// THolder<NKiwi::TTraceMonPage> tr(new NKiwi::TTraceMonPage()); +// tr->GetProbes().AddProbesList(LWTRACE_GET_PROBES(MY_PROVIDER)); +// Register(tr.Release()); +// } +// }; +// +// 5. Compile and run application +// +// 6. Create file 'mysuper.tr' with trace query: +// Blocks { # Log all calls to probes from MyGroup1 +// ProbeDesc { Group: "MyGroup1" } +// Action { +// LogAction { LogTimestamp: true } +// } +// } +// Blocks { # Log first 10 calls to MyAnother with arg1 > 1000 +// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" } +// Predicate { +// Operators { Type: OT_GT; Param: "arg1"; Value: "1000" } +// } +// Action { +// LogAction { MaxRecords: 10 } +// } +// } +// Blocks { # Start following executon of all 4 blocks each time MyAnotherProbe was called with arg2 == "start" +// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" } +// Predicate { +// Operators { Type: OT_EQ; Param: "arg2"; Value: "start" } +// } +// Action { StartAction {} } +// } +// Blocks { # Stop following executon of all 4 blocks each time MyAnotherProbe was called with arg2 == "stop" +// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" } +// Predicate { +// Operators { Type: OT_EQ; Param: "arg2"; Value: "stop" } +// } +// Action { StopAction {} } +// } +// +// 7. Send trace query to the server with HTTP POST: +// yweb/robot/kiwi/scripts/trace.sh new uniq-id-for-my-trace hostname:monport < mysuper.tr +// +// 8. With browser go to: http://hostname:monport/trace +// +// 9. Delete query from server: +// yweb/robot/kiwi/scripts/trace.sh delete uniq-id-for-my-trace hostname:monport +// +// +// CONFIGURATION AND SUPPORT: +// 1. Turning off all calls to probes. +// Add to project's CMakeLists.txt: add_definitions(-DLWTRACE_DISABLE_PROBES) +// +// 2. Turning off all calls to events. +// Add to project's CMakeLists.txt: add_definitions(-DLWTRACE_DISABLE_EVENTS) +// +// 3. Increasing maximum number of probe parameters: +// Add more lines in FOREACH_PARAMNUM macro definition in preprocessor.h +// +// +// ISSUES +// 1. Note that executors for different blocks are attached in order of their declaration in trace script. +// Executor can be called by a program as soon as it is attached, therefore there is no guarantee that +// all blocks are started simultaneously +// + +#ifndef LWTRACE_DISABLE + +// Declare user provider (see USAGE INSTRUCTION) +#define LWTRACE_DECLARE_PROVIDER(provider) LWTRACE_DECLARE_PROVIDER_I(provider) + +// Define user provider (see USAGE INSTRUCTION) +#define LWTRACE_DEFINE_PROVIDER(provider) LWTRACE_DEFINE_PROVIDER_I(provider) + +// Import names from provider +#define LWTRACE_USING(provider) using namespace LWTRACE_GET_NAMESPACE(provider); + +// Probes and events list accessor +#define LWTRACE_GET_PROBES(provider) LWTRACE_GET_PROBES_I(provider) +#define LWTRACE_GET_EVENTS(provider) LWTRACE_GET_EVENTS_I(provider) + +#ifndef LWTRACE_DISABLE_PROBES + +// Call a probe +// NOTE: LWPROBE() should be used in source files only with previous call to LWTRACE_USING(MY_PROVIDER) +// NOTE: in header files GLOBAL_LWPROBE() should be used instead +// NOTE: if lots of calls needed in header file, it's convenient to define/undef the following macro: +// NOTE: #define MY_PROBE(name, ...) GLOBAL_LWPROBE(MY_PROVIDER, name, ## __VA_ARGS__) +#define GLOBAL_LWPROBE(provider, probe, ...) LWPROBE_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), ##__VA_ARGS__) +#define LWPROBE(probe, ...) LWPROBE_I(LWTRACE_GET_NAME(probe), ##__VA_ARGS__) #define GLOBAL_LWPROBE_ENABLED(provider, probe) LWPROBE_ENABLED_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe)) #define LWPROBE_ENABLED(probe) LWPROBE_ENABLED_I(LWTRACE_GET_NAME(probe)) -#define LWPROBE_OBJ(probe, ...) LWPROBE_I(probe, ##__VA_ARGS__) - -// Calls a probe when scope is beeing left -// NOTE: arguments are passed by value and stored until scope exit -// NOTE: probe should be declared with first params of type ui64, argument for which is automaticaly generated (duration in microseconds) -// NOTE: *_DURATION() macros take through "..." all arguments except the first one -#define GLOBAL_LWPROBE_DURATION(provider, probe, ...) LWPROBE_DURATION_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_TYPE(probe), lwtrace_scoped_##provider##probe, LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), ##__VA_ARGS__) -#define LWPROBE_DURATION(probe, ...) LWPROBE_DURATION_I(LWTRACE_GET_TYPE(probe), lwtrace_scoped_##probe, LWTRACE_GET_NAME(probe), ##__VA_ARGS__) - -// Probe with orbit support -#define GLOBAL_LWTRACK(provider, probe, orbit, ...) LWTRACK_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), orbit, ##__VA_ARGS__) -#define LWTRACK(probe, orbit, ...) LWTRACK_I(LWTRACE_GET_NAME(probe), orbit, ##__VA_ARGS__) -#define LWTRACK_OBJ(probe, orbit, ...) LWTRACK_I(probe, orbit, ##__VA_ARGS__) - -#else -#define GLOBAL_LWPROBE(provider, probe, ...) -#define LWPROBE(probe, ...) +#define LWPROBE_OBJ(probe, ...) LWPROBE_I(probe, ##__VA_ARGS__) + +// Calls a probe when scope is beeing left +// NOTE: arguments are passed by value and stored until scope exit +// NOTE: probe should be declared with first params of type ui64, argument for which is automaticaly generated (duration in microseconds) +// NOTE: *_DURATION() macros take through "..." all arguments except the first one +#define GLOBAL_LWPROBE_DURATION(provider, probe, ...) LWPROBE_DURATION_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_TYPE(probe), lwtrace_scoped_##provider##probe, LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), ##__VA_ARGS__) +#define LWPROBE_DURATION(probe, ...) LWPROBE_DURATION_I(LWTRACE_GET_TYPE(probe), lwtrace_scoped_##probe, LWTRACE_GET_NAME(probe), ##__VA_ARGS__) + +// Probe with orbit support +#define GLOBAL_LWTRACK(provider, probe, orbit, ...) LWTRACK_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), orbit, ##__VA_ARGS__) +#define LWTRACK(probe, orbit, ...) LWTRACK_I(LWTRACE_GET_NAME(probe), orbit, ##__VA_ARGS__) +#define LWTRACK_OBJ(probe, orbit, ...) LWTRACK_I(probe, orbit, ##__VA_ARGS__) + +#else +#define GLOBAL_LWPROBE(provider, probe, ...) +#define LWPROBE(probe, ...) #define GLOBAL_LWPROBE_ENABLED(provider, probe) false #define LWPROBE_ENABLED(probe) false -#define LWPROBE_OBJ(probe, ...) Y_UNUSED(probe) -#define GLOBAL_LWPROBE_DURATION(provider, probe, ...) -#define LWPROBE_DURATION(probe, ...) -#define GLOBAL_LWTRACK(provider, probe, orbit, ...) -#define LWTRACK(probe, orbit, ...) -#define LWTRACK_OBJ(probe, orbit, ...) Y_UNUSED(probe) -#endif - -#ifndef LWTRACE_DISABLE_EVENTS - -// Call an event -// NOTE: LWEVENT() should be used in source files only with previous call to LWTRACE_USING(MY_PROVIDER) -// NOTE: in header files GLOBAL_LWEVENT() should be used instead -// NOTE: if lots of calls needed in header file, it's convenient to define/undef the following macro: -// NOTE: #define MY_EVENT(name, ...) GLOBAL_LWEVENT(MY_PROVIDER, name, ## __VA_ARGS__) -#define GLOBAL_LWEVENT(provider, event, ...) LWEVENT_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(event), ##__VA_ARGS__) -#define LWEVENT(event, ...) LWEVENT_I(LWTRACE_GET_NAME(event), ##__VA_ARGS__) - -#else -#define GLOBAL_LWEVENT(provider, event, ...) -#define LWEVENT(event, ...) -#endif - -#else - -#define LWTRACE_DECLARE_PROVIDER(provider) -#define LWTRACE_DEFINE_PROVIDER(provider) -#define LWTRACE_USING(provider) -#define LWTRACE_GET_PROBES(provider) NULL -#define LWTRACE_GET_EVENTS(provider) NULL -#define GLOBAL_LWPROBE(provider, probe, ...) -#define LWPROBE(probe, ...) +#define LWPROBE_OBJ(probe, ...) Y_UNUSED(probe) +#define GLOBAL_LWPROBE_DURATION(provider, probe, ...) +#define LWPROBE_DURATION(probe, ...) +#define GLOBAL_LWTRACK(provider, probe, orbit, ...) +#define LWTRACK(probe, orbit, ...) +#define LWTRACK_OBJ(probe, orbit, ...) Y_UNUSED(probe) +#endif + +#ifndef LWTRACE_DISABLE_EVENTS + +// Call an event +// NOTE: LWEVENT() should be used in source files only with previous call to LWTRACE_USING(MY_PROVIDER) +// NOTE: in header files GLOBAL_LWEVENT() should be used instead +// NOTE: if lots of calls needed in header file, it's convenient to define/undef the following macro: +// NOTE: #define MY_EVENT(name, ...) GLOBAL_LWEVENT(MY_PROVIDER, name, ## __VA_ARGS__) +#define GLOBAL_LWEVENT(provider, event, ...) LWEVENT_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(event), ##__VA_ARGS__) +#define LWEVENT(event, ...) LWEVENT_I(LWTRACE_GET_NAME(event), ##__VA_ARGS__) + +#else +#define GLOBAL_LWEVENT(provider, event, ...) +#define LWEVENT(event, ...) +#endif + +#else + +#define LWTRACE_DECLARE_PROVIDER(provider) +#define LWTRACE_DEFINE_PROVIDER(provider) +#define LWTRACE_USING(provider) +#define LWTRACE_GET_PROBES(provider) NULL +#define LWTRACE_GET_EVENTS(provider) NULL +#define GLOBAL_LWPROBE(provider, probe, ...) +#define LWPROBE(probe, ...) #define GLOBAL_LWPROBE_ENABLED(provider, probe) false #define LWPROBE_ENABLED(probe) false -#define GLOBAL_LWPROBE_DURATION(provider, probe, ...) -#define LWPROBE_DURATION(probe, ...) -#define GLOBAL_LWTRACK(provider, probe, orbit, ...) -#define LWTRACK(probe, orbit, ...) -#define GLOBAL_LWEVENT(provider, event, ...) -#define LWEVENT(event, ...) - -#endif +#define GLOBAL_LWPROBE_DURATION(provider, probe, ...) +#define LWPROBE_DURATION(probe, ...) +#define GLOBAL_LWTRACK(provider, probe, orbit, ...) +#define LWTRACK(probe, orbit, ...) +#define GLOBAL_LWEVENT(provider, event, ...) +#define LWEVENT(event, ...) + +#endif diff --git a/library/cpp/lwtrace/check.cpp b/library/cpp/lwtrace/check.cpp index 4e34fc5d49..5f4da9712e 100644 --- a/library/cpp/lwtrace/check.cpp +++ b/library/cpp/lwtrace/check.cpp @@ -1,18 +1,18 @@ -#include "check.h" +#include "check.h" #include <util/stream/output.h> -#include <util/string/cast.h> - -namespace NLWTrace { - int TCheck::ObjCount = 0; -} - -template <> -NLWTrace::TCheck FromStringImpl(const char* data, size_t len) { - return NLWTrace::TCheck(FromString<int, char>(data, len)); -} - -template <> -void Out<NLWTrace::TCheck>(IOutputStream& o, TTypeTraits<NLWTrace::TCheck>::TFuncParam t) { - Out<int>(o, t.Value); -} +#include <util/string/cast.h> + +namespace NLWTrace { + int TCheck::ObjCount = 0; +} + +template <> +NLWTrace::TCheck FromStringImpl(const char* data, size_t len) { + return NLWTrace::TCheck(FromString<int, char>(data, len)); +} + +template <> +void Out<NLWTrace::TCheck>(IOutputStream& o, TTypeTraits<NLWTrace::TCheck>::TFuncParam t) { + Out<int>(o, t.Value); +} diff --git a/library/cpp/lwtrace/check.h b/library/cpp/lwtrace/check.h index 71503cbc7b..e346e04dfb 100644 --- a/library/cpp/lwtrace/check.h +++ b/library/cpp/lwtrace/check.h @@ -1,78 +1,78 @@ -#pragma once +#pragma once + +namespace NLWTrace { + struct TCheck { + int Value; + static int ObjCount; + + TCheck() + : Value(0) + { + ObjCount++; + } + + explicit TCheck(int value) + : Value(value) + { + ObjCount++; + } + + TCheck(const TCheck& o) + : Value(o.Value) + { + ObjCount++; + } + + ~TCheck() { + ObjCount--; + } + + bool operator<(const TCheck& rhs) const { + return Value < rhs.Value; + } + bool operator>(const TCheck& rhs) const { + return Value > rhs.Value; + } + bool operator<=(const TCheck& rhs) const { + return Value <= rhs.Value; + } + bool operator>=(const TCheck& rhs) const { + return Value >= rhs.Value; + } + bool operator==(const TCheck& rhs) const { + return Value == rhs.Value; + } + bool operator!=(const TCheck& rhs) const { + return Value != rhs.Value; + } + TCheck operator+(const TCheck& rhs) const { + return TCheck(Value + rhs.Value); + } + TCheck operator-(const TCheck& rhs) const { + return TCheck(Value - rhs.Value); + } + TCheck operator*(const TCheck& rhs) const { + return TCheck(Value * rhs.Value); + } + TCheck operator/(const TCheck& rhs) const { + return TCheck(Value / rhs.Value); + } + TCheck operator%(const TCheck& rhs) const { + return TCheck(Value % rhs.Value); + } + + void Add(const TCheck rhs) { + Value += rhs.Value; + } + void Sub(const TCheck rhs) { + Value -= rhs.Value; + } + void Inc() { + ++Value; + } + void Dec() { + --Value; + } + }; -namespace NLWTrace { - struct TCheck { - int Value; - static int ObjCount; - - TCheck() - : Value(0) - { - ObjCount++; - } - - explicit TCheck(int value) - : Value(value) - { - ObjCount++; - } - - TCheck(const TCheck& o) - : Value(o.Value) - { - ObjCount++; - } - - ~TCheck() { - ObjCount--; - } - - bool operator<(const TCheck& rhs) const { - return Value < rhs.Value; - } - bool operator>(const TCheck& rhs) const { - return Value > rhs.Value; - } - bool operator<=(const TCheck& rhs) const { - return Value <= rhs.Value; - } - bool operator>=(const TCheck& rhs) const { - return Value >= rhs.Value; - } - bool operator==(const TCheck& rhs) const { - return Value == rhs.Value; - } - bool operator!=(const TCheck& rhs) const { - return Value != rhs.Value; - } - TCheck operator+(const TCheck& rhs) const { - return TCheck(Value + rhs.Value); - } - TCheck operator-(const TCheck& rhs) const { - return TCheck(Value - rhs.Value); - } - TCheck operator*(const TCheck& rhs) const { - return TCheck(Value * rhs.Value); - } - TCheck operator/(const TCheck& rhs) const { - return TCheck(Value / rhs.Value); - } - TCheck operator%(const TCheck& rhs) const { - return TCheck(Value % rhs.Value); - } - - void Add(const TCheck rhs) { - Value += rhs.Value; - } - void Sub(const TCheck rhs) { - Value -= rhs.Value; - } - void Inc() { - ++Value; - } - void Dec() { - --Value; - } - }; - -} +} diff --git a/library/cpp/lwtrace/control.h b/library/cpp/lwtrace/control.h index 16b24eafd2..478488e653 100644 --- a/library/cpp/lwtrace/control.h +++ b/library/cpp/lwtrace/control.h @@ -1,5 +1,5 @@ -#pragma once - +#pragma once + #include "custom_action.h" #include "event.h" #include "log.h" @@ -10,199 +10,199 @@ #include <google/protobuf/repeated_field.h> -#include <util/generic/deque.h> -#include <util/generic/hash.h> -#include <util/generic/noncopyable.h> -#include <util/generic/ptr.h> -#include <util/generic/set.h> -#include <util/generic/vector.h> - -namespace NLWTrace { +#include <util/generic/deque.h> +#include <util/generic/hash.h> +#include <util/generic/noncopyable.h> +#include <util/generic/ptr.h> +#include <util/generic/set.h> +#include <util/generic/vector.h> + +namespace NLWTrace { using TProbeMap = THashMap<std::pair<TString, TString>, TProbe*>; - // Interface for probe ownership management - class IBox: public virtual TThrRefBase { - private: - bool Owns; + // Interface for probe ownership management + class IBox: public virtual TThrRefBase { + private: + bool Owns; - public: - explicit IBox(bool ownsProbe = false) - : Owns(ownsProbe) + public: + explicit IBox(bool ownsProbe = false) + : Owns(ownsProbe) { } - - bool OwnsProbe() { - return Owns; - } - - virtual TProbe* GetProbe() = 0; - }; - - using TBoxPtr = TIntrusivePtr<IBox>; - - // Simple not-owning box, that just holds pointer to static/global probe (e.g. created by LWTRACE_DEFINE_PROVIDER) - class TStaticBox: public IBox { - private: - TProbe* Probe; - - public: - explicit TStaticBox(TProbe* probe) - : IBox(false) - , Probe(probe) + + bool OwnsProbe() { + return Owns; + } + + virtual TProbe* GetProbe() = 0; + }; + + using TBoxPtr = TIntrusivePtr<IBox>; + + // Simple not-owning box, that just holds pointer to static/global probe (e.g. created by LWTRACE_DEFINE_PROVIDER) + class TStaticBox: public IBox { + private: + TProbe* Probe; + + public: + explicit TStaticBox(TProbe* probe) + : IBox(false) + , Probe(probe) { } - - TProbe* GetProbe() override { - return Probe; - } - }; - - // Just a set of unique probes - // TODO[serxa]: get rid of different ProbeRegistries, use unique one (singleton) with auto registration - class TProbeRegistry: public TNonCopyable { - private: - TMutex Mutex; - - // Probe* pointer uniquely identifies a probe and boxptr actually owns TProbe object (if required) - using TProbes = THashMap<TProbe*, TBoxPtr>; - TProbes Probes; - - // Probe provider-name pairs must be unique, keep track of them - using TIds = TSet<std::pair<TString, TString>>; - TIds Ids; - - public: - // Add probes from null-terminated array of probe pointers. Probe can be added multiple times. Thread-safe. - // Implies probes you pass will live forever (e.g. created by LWTRACE_DEFINE_PROVIDER) - void AddProbesList(TProbe** reg); - - // Manage probes that are created/destructed dynamically - void AddProbe(const TBoxPtr& box); - void RemoveProbe(TProbe* probe); - - // Helper class to make thread-safe iteration over probes - class TProbesAccessor { - private: - TGuard<TMutex> Guard; - TProbes& Probes; - public: - explicit TProbesAccessor(TProbeRegistry* registry) - : Guard(registry->Mutex) - , Probes(registry->Probes) - {} - - explicit TProbesAccessor(TProbeRegistry& registry) - : TProbesAccessor(®istry) - {} - - auto begin() { return Probes.begin(); } - auto end() { return Probes.end(); } - }; - - friend class TProbesAccessor; - - private: - void AddProbeNoLock(const TBoxPtr& box); - void RemoveProbeNoLock(TProbe* probe); - }; - - // Represents a compiled trace query, holds executors attached to probes - class TSession: public TNonCopyable { - public: - typedef THashMap<TString, TAtomicBase> TTraceVariables; - - private: - const TInstant StartTime; - const ui64 TraceIdx; - TProbeRegistry& Registry; - TDuration StoreDuration; - TDuration ReadDuration; - TCyclicLog CyclicLog; - TDurationLog DurationLog; - TCyclicDepot CyclicDepot; - TDurationDepot DurationDepot; - TAtomic LastTrackId; + + TProbe* GetProbe() override { + return Probe; + } + }; + + // Just a set of unique probes + // TODO[serxa]: get rid of different ProbeRegistries, use unique one (singleton) with auto registration + class TProbeRegistry: public TNonCopyable { + private: + TMutex Mutex; + + // Probe* pointer uniquely identifies a probe and boxptr actually owns TProbe object (if required) + using TProbes = THashMap<TProbe*, TBoxPtr>; + TProbes Probes; + + // Probe provider-name pairs must be unique, keep track of them + using TIds = TSet<std::pair<TString, TString>>; + TIds Ids; + + public: + // Add probes from null-terminated array of probe pointers. Probe can be added multiple times. Thread-safe. + // Implies probes you pass will live forever (e.g. created by LWTRACE_DEFINE_PROVIDER) + void AddProbesList(TProbe** reg); + + // Manage probes that are created/destructed dynamically + void AddProbe(const TBoxPtr& box); + void RemoveProbe(TProbe* probe); + + // Helper class to make thread-safe iteration over probes + class TProbesAccessor { + private: + TGuard<TMutex> Guard; + TProbes& Probes; + public: + explicit TProbesAccessor(TProbeRegistry* registry) + : Guard(registry->Mutex) + , Probes(registry->Probes) + {} + + explicit TProbesAccessor(TProbeRegistry& registry) + : TProbesAccessor(®istry) + {} + + auto begin() { return Probes.begin(); } + auto end() { return Probes.end(); } + }; + + friend class TProbesAccessor; + + private: + void AddProbeNoLock(const TBoxPtr& box); + void RemoveProbeNoLock(TProbe* probe); + }; + + // Represents a compiled trace query, holds executors attached to probes + class TSession: public TNonCopyable { + public: + typedef THashMap<TString, TAtomicBase> TTraceVariables; + + private: + const TInstant StartTime; + const ui64 TraceIdx; + TProbeRegistry& Registry; + TDuration StoreDuration; + TDuration ReadDuration; + TCyclicLog CyclicLog; + TDurationLog DurationLog; + TCyclicDepot CyclicDepot; + TDurationDepot DurationDepot; + TAtomic LastTrackId; TAtomic LastSpanId; - typedef TVector<std::pair<TProbe*, IExecutor*>> TProbes; - TProbes Probes; - bool Attached; - NLWTrace::TQuery Query; - TTraceVariables TraceVariables; - TTraceResources TraceResources; - void InsertExecutor(TTraceVariables& traceVariables, - size_t bi, const NLWTrace::TPredicate* pred, - const google::protobuf::RepeatedPtrField<NLWTrace::TAction>& actions, - TProbe* probe, const bool destructiveActionsAllowed, - const TCustomActionFactory& customActionFactory); - - private: - void Destroy(); - - public: - TSession(ui64 traceIdx, - TProbeRegistry& registry, - const NLWTrace::TQuery& query, - const bool destructiveActionsAllowed, - const TCustomActionFactory& customActionFactory); - ~TSession(); - void Detach(); - size_t GetEventsCount() const; - size_t GetThreadsCount() const; - const NLWTrace::TQuery& GetQuery() const { - return Query; - } - TInstant GetStartTime() const { - return StartTime; - } - ui64 GetTraceIdx() const { - return TraceIdx; - } - TTraceResources& Resources() { - return TraceResources; - } - const TTraceResources& Resources() const { - return TraceResources; - } - - template <class TReader> - void ReadThreads(TReader& r) const { - CyclicLog.ReadThreads(r); - DurationLog.ReadThreads(r); - } - - template <class TReader> - void ReadItems(TReader& r) const { - CyclicLog.ReadItems(r); - DurationLog.ReadItems(GetCycleCount(), DurationToCycles(ReadDuration), r); - } - - template <class TReader> - void ReadItems(ui64 now, ui64 duration, TReader& r) const { - CyclicLog.ReadItems(r); - DurationLog.ReadItems(now, duration, r); - } - - template <class TReader> - void ReadDepotThreads(TReader& r) const { - CyclicDepot.ReadThreads(r); - DurationDepot.ReadThreads(r); - } - - template <class TReader> - void ReadDepotItems(TReader& r) const { - CyclicDepot.ReadItems(r); - DurationDepot.ReadItems(GetCycleCount(), DurationToCycles(ReadDuration), r); - } - - template <class TReader> - void ReadDepotItems(ui64 now, ui64 duration, TReader& r) const { - CyclicDepot.ReadItems(r); - DurationDepot.ReadItems(now, duration, r); - } - void ToProtobuf(TLogPb& pb) const; - }; - + typedef TVector<std::pair<TProbe*, IExecutor*>> TProbes; + TProbes Probes; + bool Attached; + NLWTrace::TQuery Query; + TTraceVariables TraceVariables; + TTraceResources TraceResources; + void InsertExecutor(TTraceVariables& traceVariables, + size_t bi, const NLWTrace::TPredicate* pred, + const google::protobuf::RepeatedPtrField<NLWTrace::TAction>& actions, + TProbe* probe, const bool destructiveActionsAllowed, + const TCustomActionFactory& customActionFactory); + + private: + void Destroy(); + + public: + TSession(ui64 traceIdx, + TProbeRegistry& registry, + const NLWTrace::TQuery& query, + const bool destructiveActionsAllowed, + const TCustomActionFactory& customActionFactory); + ~TSession(); + void Detach(); + size_t GetEventsCount() const; + size_t GetThreadsCount() const; + const NLWTrace::TQuery& GetQuery() const { + return Query; + } + TInstant GetStartTime() const { + return StartTime; + } + ui64 GetTraceIdx() const { + return TraceIdx; + } + TTraceResources& Resources() { + return TraceResources; + } + const TTraceResources& Resources() const { + return TraceResources; + } + + template <class TReader> + void ReadThreads(TReader& r) const { + CyclicLog.ReadThreads(r); + DurationLog.ReadThreads(r); + } + + template <class TReader> + void ReadItems(TReader& r) const { + CyclicLog.ReadItems(r); + DurationLog.ReadItems(GetCycleCount(), DurationToCycles(ReadDuration), r); + } + + template <class TReader> + void ReadItems(ui64 now, ui64 duration, TReader& r) const { + CyclicLog.ReadItems(r); + DurationLog.ReadItems(now, duration, r); + } + + template <class TReader> + void ReadDepotThreads(TReader& r) const { + CyclicDepot.ReadThreads(r); + DurationDepot.ReadThreads(r); + } + + template <class TReader> + void ReadDepotItems(TReader& r) const { + CyclicDepot.ReadItems(r); + DurationDepot.ReadItems(GetCycleCount(), DurationToCycles(ReadDuration), r); + } + + template <class TReader> + void ReadDepotItems(ui64 now, ui64 duration, TReader& r) const { + CyclicDepot.ReadItems(r); + DurationDepot.ReadItems(now, duration, r); + } + void ToProtobuf(TLogPb& pb) const; + }; + // Deserialization result. // Either IsSuccess is true or FailedEventNames contains event names // we were not able to deserialize. @@ -218,112 +218,112 @@ namespace NLWTrace { } }; - // Just a registry of all active trace queries - // Facade for all interactions with probes/traces - class TManager: public TNonCopyable { - private: - TProbeRegistry& Registry; - TMutex Mtx; + // Just a registry of all active trace queries + // Facade for all interactions with probes/traces + class TManager: public TNonCopyable { + private: + TProbeRegistry& Registry; + TMutex Mtx; ui64 LastTraceIdx = 1; - typedef THashMap<TString, TSession*> TTraces; // traceId -> TSession - TTraces Traces; - bool DestructiveActionsAllowed; - TCustomActionFactory CustomActionFactory; + typedef THashMap<TString, TSession*> TTraces; // traceId -> TSession + TTraces Traces; + bool DestructiveActionsAllowed; + TCustomActionFactory CustomActionFactory; THolder<TRunLogShuttleActionExecutor<TCyclicDepot>> SerializingExecutor; - - public: + + public: static constexpr ui64 RemoteTraceIdx = 0; public: - TManager(TProbeRegistry& registry, bool allowDestructiveActions); - ~TManager(); - bool HasTrace(const TString& id) const; - const TSession* GetTrace(const TString& id) const; - void New(const TString& id, const NLWTrace::TQuery& query); - void Delete(const TString& id); - void Stop(const TString& id); - - template <class TReader> - void ReadProbes(TReader& reader) const { - TProbeRegistry::TProbesAccessor probes(Registry); - for (auto& kv : probes) { - TProbe* probe = kv.first; - reader.Push(probe); - } - } - - template <class TReader> - void ReadTraces(TReader& reader) const { - TGuard<TMutex> g(Mtx); - for (const auto& Trace : Traces) { - const TString& id = Trace.first; - const TSession* trace = Trace.second; - reader.Push(id, trace); - } - } - - template <class TReader> - void ReadLog(const TString& id, TReader& reader) { - TGuard<TMutex> g(Mtx); - TTraces::iterator it = Traces.find(id); - if (it == Traces.end()) { - ythrow yexception() << "trace id '" << id << "' is not used"; - } else { - TSession* trace = it->second; - trace->ReadItems(reader); - } - } - - template <class TReader> - void ReadLog(const TString& id, ui64 now, TReader& reader) { - TGuard<TMutex> g(Mtx); - TTraces::iterator it = Traces.find(id); - if (it == Traces.end()) { - ythrow yexception() << "trace id '" << id << "' is not used"; - } else { - TSession* trace = it->second; - trace->ReadItems(now, reader); - } - } - - template <class TReader> - void ReadDepot(const TString& id, TReader& reader) { - TGuard<TMutex> g(Mtx); - TTraces::iterator it = Traces.find(id); - if (it == Traces.end()) { - ythrow yexception() << "trace id '" << id << "' is not used"; - } else { - TSession* trace = it->second; - trace->ReadDepotItems(reader); - } - } - - template <class TReader> - void ReadDepot(const TString& id, ui64 now, TReader& reader) { - TGuard<TMutex> g(Mtx); - TTraces::iterator it = Traces.find(id); - if (it == Traces.end()) { - ythrow yexception() << "trace id '" << id << "' is not used"; - } else { - TSession* trace = it->second; - trace->ReadDepotItems(now, reader); - } - } - - bool GetDestructiveActionsAllowed() { - return DestructiveActionsAllowed; - } - - void RegisterCustomAction(const TString& name, const TCustomActionFactory::TCallback& callback) { - CustomActionFactory.Register(name, callback); - } - - template <class T> - void RegisterCustomAction() { - CustomActionFactory.Register(T::GetActionName(), [=](TProbe* probe, const TCustomAction& action, TSession* trace) { - return new T(probe, action, trace); - }); - } + TManager(TProbeRegistry& registry, bool allowDestructiveActions); + ~TManager(); + bool HasTrace(const TString& id) const; + const TSession* GetTrace(const TString& id) const; + void New(const TString& id, const NLWTrace::TQuery& query); + void Delete(const TString& id); + void Stop(const TString& id); + + template <class TReader> + void ReadProbes(TReader& reader) const { + TProbeRegistry::TProbesAccessor probes(Registry); + for (auto& kv : probes) { + TProbe* probe = kv.first; + reader.Push(probe); + } + } + + template <class TReader> + void ReadTraces(TReader& reader) const { + TGuard<TMutex> g(Mtx); + for (const auto& Trace : Traces) { + const TString& id = Trace.first; + const TSession* trace = Trace.second; + reader.Push(id, trace); + } + } + + template <class TReader> + void ReadLog(const TString& id, TReader& reader) { + TGuard<TMutex> g(Mtx); + TTraces::iterator it = Traces.find(id); + if (it == Traces.end()) { + ythrow yexception() << "trace id '" << id << "' is not used"; + } else { + TSession* trace = it->second; + trace->ReadItems(reader); + } + } + + template <class TReader> + void ReadLog(const TString& id, ui64 now, TReader& reader) { + TGuard<TMutex> g(Mtx); + TTraces::iterator it = Traces.find(id); + if (it == Traces.end()) { + ythrow yexception() << "trace id '" << id << "' is not used"; + } else { + TSession* trace = it->second; + trace->ReadItems(now, reader); + } + } + + template <class TReader> + void ReadDepot(const TString& id, TReader& reader) { + TGuard<TMutex> g(Mtx); + TTraces::iterator it = Traces.find(id); + if (it == Traces.end()) { + ythrow yexception() << "trace id '" << id << "' is not used"; + } else { + TSession* trace = it->second; + trace->ReadDepotItems(reader); + } + } + + template <class TReader> + void ReadDepot(const TString& id, ui64 now, TReader& reader) { + TGuard<TMutex> g(Mtx); + TTraces::iterator it = Traces.find(id); + if (it == Traces.end()) { + ythrow yexception() << "trace id '" << id << "' is not used"; + } else { + TSession* trace = it->second; + trace->ReadDepotItems(now, reader); + } + } + + bool GetDestructiveActionsAllowed() { + return DestructiveActionsAllowed; + } + + void RegisterCustomAction(const TString& name, const TCustomActionFactory::TCallback& callback) { + CustomActionFactory.Register(name, callback); + } + + template <class T> + void RegisterCustomAction() { + CustomActionFactory.Register(T::GetActionName(), [=](TProbe* probe, const TCustomAction& action, TSession* trace) { + return new T(probe, action, trace); + }); + } TProbeMap GetProbesMap(); @@ -347,5 +347,5 @@ namespace NLWTrace { bool IsTraced(TOrbit& orbit) { return orbit.HasShuttle(TManager::RemoteTraceIdx); } - }; -} + }; +} diff --git a/library/cpp/lwtrace/custom_action.cpp b/library/cpp/lwtrace/custom_action.cpp index a379b34ec0..dc97b44ac0 100644 --- a/library/cpp/lwtrace/custom_action.cpp +++ b/library/cpp/lwtrace/custom_action.cpp @@ -1,21 +1,21 @@ -#include "custom_action.h" +#include "custom_action.h" #include "control.h" using namespace NLWTrace; -TCustomActionExecutor* TCustomActionFactory::Create(TProbe* probe, const TCustomAction& action, TSession* trace) const { - auto iter = Callbacks.find(action.GetName()); - if (iter != Callbacks.end()) { - return iter->second(probe, action, trace); - } else { - return nullptr; - } +TCustomActionExecutor* TCustomActionFactory::Create(TProbe* probe, const TCustomAction& action, TSession* trace) const { + auto iter = Callbacks.find(action.GetName()); + if (iter != Callbacks.end()) { + return iter->second(probe, action, trace); + } else { + return nullptr; + } } - -void TCustomActionFactory::Register(const TString& name, const TCustomActionFactory::TCallback& callback) { + +void TCustomActionFactory::Register(const TString& name, const TCustomActionFactory::TCallback& callback) { if (Callbacks.contains(name)) { - ythrow yexception() << "duplicate custom action '" << name << "'"; - } - Callbacks[name] = callback; -} + ythrow yexception() << "duplicate custom action '" << name << "'"; + } + Callbacks[name] = callback; +} diff --git a/library/cpp/lwtrace/custom_action.h b/library/cpp/lwtrace/custom_action.h index 92a3c66b84..6d950a39e1 100644 --- a/library/cpp/lwtrace/custom_action.h +++ b/library/cpp/lwtrace/custom_action.h @@ -8,68 +8,68 @@ #include <functional> -namespace NLWTrace { - class TSession; +namespace NLWTrace { + class TSession; - // Custom action can save any stuff (derived from IResource) in TSession object - // IMPORTANT: Derived class will be used from multiple threads! (see example3) - class IResource: public TAtomicRefCount<IResource> { - public: - virtual ~IResource() { - } - }; - using TResourcePtr = TIntrusivePtr<IResource>; + // Custom action can save any stuff (derived from IResource) in TSession object + // IMPORTANT: Derived class will be used from multiple threads! (see example3) + class IResource: public TAtomicRefCount<IResource> { + public: + virtual ~IResource() { + } + }; + using TResourcePtr = TIntrusivePtr<IResource>; + + // Trace resources that is used to hold/get/create any stuff + class TTraceResources: public THashMap<TString, TResourcePtr> { + public: + template <class T> + T& Get(const TString& name) { + auto iter = find(name); + if (iter == end()) { + iter = insert(value_type(name, TResourcePtr(new T()))).first; + } + return *static_cast<T*>(iter->second.Get()); + } + + template <class T> + const T* GetOrNull(const TString& name) const { + auto iter = find(name); + if (iter == end()) { + return nullptr; + } + return *iter->second; + } + }; + + // Base class of all custom actions + class TCustomActionExecutor: public IExecutor { + protected: + TProbe* const Probe; + bool Destructive; + + public: + TCustomActionExecutor(TProbe* probe, bool destructive) + : IExecutor() + , Probe(probe) + , Destructive(destructive) + { + } + + bool IsDestructive() { + return Destructive; + } + }; - // Trace resources that is used to hold/get/create any stuff - class TTraceResources: public THashMap<TString, TResourcePtr> { - public: - template <class T> - T& Get(const TString& name) { - auto iter = find(name); - if (iter == end()) { - iter = insert(value_type(name, TResourcePtr(new T()))).first; - } - return *static_cast<T*>(iter->second.Get()); - } - - template <class T> - const T* GetOrNull(const TString& name) const { - auto iter = find(name); - if (iter == end()) { - return nullptr; - } - return *iter->second; - } - }; - - // Base class of all custom actions - class TCustomActionExecutor: public IExecutor { - protected: - TProbe* const Probe; - bool Destructive; - - public: - TCustomActionExecutor(TProbe* probe, bool destructive) - : IExecutor() - , Probe(probe) - , Destructive(destructive) - { - } - - bool IsDestructive() { - return Destructive; - } - }; - - // Factory to produce custom action executors - class TCustomActionFactory { - public: - using TCallback = std::function<TCustomActionExecutor*(TProbe* probe, const TCustomAction& action, TSession* trace)>; - TCustomActionExecutor* Create(TProbe* probe, const TCustomAction& action, TSession* trace) const; - void Register(const TString& name, const TCallback& callback); - - private: - THashMap<TString, TCallback> Callbacks; - }; - -} + // Factory to produce custom action executors + class TCustomActionFactory { + public: + using TCallback = std::function<TCustomActionExecutor*(TProbe* probe, const TCustomAction& action, TSession* trace)>; + TCustomActionExecutor* Create(TProbe* probe, const TCustomAction& action, TSession* trace) const; + void Register(const TString& name, const TCallback& callback); + + private: + THashMap<TString, TCallback> Callbacks; + }; + +} diff --git a/library/cpp/lwtrace/event.h b/library/cpp/lwtrace/event.h index e53a620c45..417ec823d8 100644 --- a/library/cpp/lwtrace/event.h +++ b/library/cpp/lwtrace/event.h @@ -1,29 +1,29 @@ -#pragma once - +#pragma once + #include "preprocessor.h" -#include "signature.h" +#include "signature.h" #include "param_traits.h" #include <library/cpp/lwtrace/protos/lwtrace.pb.h> - -namespace NLWTrace { - // Common class for all events - struct TEvent { - const char* Name; - const char* Groups[LWTRACE_MAX_GROUPS + 1]; - TSignature Signature; - - const char* GetProvider() const { - return Groups[0]; - } - - void ToProtobuf(TEventPb& pb) const { - pb.SetName(Name); - for (const char* const* gi = Groups; *gi != nullptr; gi++) { - pb.AddGroups(*gi); - } - Signature.ToProtobuf(pb); - } - }; - -} + +namespace NLWTrace { + // Common class for all events + struct TEvent { + const char* Name; + const char* Groups[LWTRACE_MAX_GROUPS + 1]; + TSignature Signature; + + const char* GetProvider() const { + return Groups[0]; + } + + void ToProtobuf(TEventPb& pb) const { + pb.SetName(Name); + for (const char* const* gi = Groups; *gi != nullptr; gi++) { + pb.AddGroups(*gi); + } + Signature.ToProtobuf(pb); + } + }; + +} diff --git a/library/cpp/lwtrace/example1/lwtrace_example1.cpp b/library/cpp/lwtrace/example1/lwtrace_example1.cpp index 6b32c405ee..ff6891ec18 100644 --- a/library/cpp/lwtrace/example1/lwtrace_example1.cpp +++ b/library/cpp/lwtrace/example1/lwtrace_example1.cpp @@ -1,6 +1,6 @@ #include <library/cpp/lwtrace/all.h> -#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ +#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ PROBE(IterationProbe, GROUPS(), TYPES(i32, double), NAMES("n", "result")) \ /**/ @@ -11,7 +11,7 @@ void InitLWTrace() { NLWTrace::StartLwtraceFromEnv(); } -long double Fact(int n) { +long double Fact(int n) { if (n < 0) { ythrow yexception() << "N! is undefined for negative N (" << n << ")"; } diff --git a/library/cpp/lwtrace/example2/lwtrace_example2.cpp b/library/cpp/lwtrace/example2/lwtrace_example2.cpp index 7a4f7a1daf..faf95a7c61 100644 --- a/library/cpp/lwtrace/example2/lwtrace_example2.cpp +++ b/library/cpp/lwtrace/example2/lwtrace_example2.cpp @@ -5,18 +5,18 @@ #include <google/protobuf/text_format.h> #include <util/stream/file.h> -#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ - PROBE(StartupProbe, GROUPS(), TYPES(), NAMES()) \ - PROBE(IterationProbe, GROUPS(), TYPES(i64, double), NAMES("n", "result")) \ +#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(StartupProbe, GROUPS(), TYPES(), NAMES()) \ + PROBE(IterationProbe, GROUPS(), TYPES(i64, double), NAMES("n", "result")) \ PROBE(DurationProbe, GROUPS(), TYPES(ui64, i64, double), NAMES("duration", "n", "result")) \ - PROBE(ResultProbe, GROUPS(), TYPES(double), NAMES("factN")) \ - PROBE(AfterInputProbe, GROUPS(), TYPES(i32), NAMES("n")) \ + PROBE(ResultProbe, GROUPS(), TYPES(double), NAMES("factN")) \ + PROBE(AfterInputProbe, GROUPS(), TYPES(i32), NAMES("n")) \ /**/ LWTRACE_DECLARE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER) LWTRACE_DEFINE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER) -THolder<NLWTrace::TManager> traceManager; +THolder<NLWTrace::TManager> traceManager; struct TConfig { bool UnsafeLWTrace; @@ -24,7 +24,7 @@ struct TConfig { }; void InitLWTrace(TConfig& cfg) { - traceManager.Reset(new NLWTrace::TManager(*Singleton<NLWTrace::TProbeRegistry>(), cfg.UnsafeLWTrace)); + traceManager.Reset(new NLWTrace::TManager(*Singleton<NLWTrace::TProbeRegistry>(), cfg.UnsafeLWTrace)); } void AddLWTraceRequest(TConfig& cfg) { @@ -36,7 +36,7 @@ void AddLWTraceRequest(TConfig& cfg) { class TLogReader { public: - void Push(TThread::TId tid, const NLWTrace::TCyclicLog::TItem& item) { + void Push(TThread::TId tid, const NLWTrace::TCyclicLog::TItem& item) { Cout << "tid=" << tid << " probe=" << item.Probe->Event.Name; if (item.Timestamp != TInstant::Zero()) { Cout << " time=" << item.Timestamp; @@ -59,7 +59,7 @@ void DisplayLWTraceLog() { traceManager->ReadLog("TraceRequest1", reader); } -long double Fact(i64 n) { +long double Fact(i64 n) { if (n < 0) { ythrow yexception() << "N! is undefined for negative N (" << n << ")"; } @@ -94,14 +94,14 @@ int main(int argc, char** argv) { using namespace NLastGetopt; TOpts opts = NLastGetopt::TOpts::Default(); opts.AddLongOption('u', "unsafe-lwtrace", - "allow destructive LWTrace actions") - .OptionalValue(ToString(true)) - .DefaultValue(ToString(false)) - .StoreResult(&cfg.UnsafeLWTrace); + "allow destructive LWTrace actions") + .OptionalValue(ToString(true)) + .DefaultValue(ToString(false)) + .StoreResult(&cfg.UnsafeLWTrace); opts.AddLongOption('f', "trace-request", - "specify a file containing LWTrace request") - .DefaultValue("example_query.tr") - .StoreResult(&cfg.TraceRequestPath); + "specify a file containing LWTrace request") + .DefaultValue("example_query.tr") + .StoreResult(&cfg.TraceRequestPath); opts.AddHelpOption('h'); TOptsParseResult res(&opts, argc, argv); diff --git a/library/cpp/lwtrace/example3/example_query.tr b/library/cpp/lwtrace/example3/example_query.tr index 1f841b0932..e53c21c02d 100644 --- a/library/cpp/lwtrace/example3/example_query.tr +++ b/library/cpp/lwtrace/example3/example_query.tr @@ -4,10 +4,10 @@ Blocks { Provider: "LWTRACE_EXAMPLE_PROVIDER" } Action { - CustomAction { - Name: "MyAction" - Opts: "/dev/stdout" - } + CustomAction { + Name: "MyAction" + Opts: "/dev/stdout" + } } } diff --git a/library/cpp/lwtrace/example3/lwtrace_example3.cpp b/library/cpp/lwtrace/example3/lwtrace_example3.cpp index 4493dc0077..2fa2976a69 100644 --- a/library/cpp/lwtrace/example3/lwtrace_example3.cpp +++ b/library/cpp/lwtrace/example3/lwtrace_example3.cpp @@ -1,8 +1,8 @@ #include <library/cpp/lwtrace/all.h> #include <google/protobuf/text_format.h> -#include "my_action.h" +#include "my_action.h" -#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ +#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ PROBE(IterationProbe, GROUPS(), TYPES(i32, double), NAMES("n", "result")) \ /**/ @@ -10,12 +10,12 @@ LWTRACE_DECLARE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER) LWTRACE_DEFINE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER) void InitLWTrace() { - NLWTrace::StartLwtraceFromEnv([=](NLWTrace::TManager& mngr) { - mngr.RegisterCustomAction<TMyActionExecutor>(); - }); + NLWTrace::StartLwtraceFromEnv([=](NLWTrace::TManager& mngr) { + mngr.RegisterCustomAction<TMyActionExecutor>(); + }); } -long double Fact(int n) { +long double Fact(int n) { if (n < 0) { ythrow yexception() << "N! is undefined for negative N (" << n << ")"; } diff --git a/library/cpp/lwtrace/example3/my_action.h b/library/cpp/lwtrace/example3/my_action.h index 9a04293ba2..80a34ecca8 100644 --- a/library/cpp/lwtrace/example3/my_action.h +++ b/library/cpp/lwtrace/example3/my_action.h @@ -1,85 +1,85 @@ -#pragma once - +#pragma once + #include <library/cpp/lwtrace/all.h> -#include <util/stream/file.h> - -// Example of custom state for custom executors -// Holds file for output from TMyActionExecutor -class TMyFile: public NLWTrace::IResource { -private: - TMutex Mutex; +#include <util/stream/file.h> + +// Example of custom state for custom executors +// Holds file for output from TMyActionExecutor +class TMyFile: public NLWTrace::IResource { +private: + TMutex Mutex; THolder<TUnbufferedFileOutput> File; - -public: - // Note that this class must have default ctor (it's declared here just for clearness) - TMyFile() { - } - - // Note that dtor will be called by TManager::Delete() after detachment and destruction of all executors - ~TMyFile() { - } - - // Some kind of state initialization - // Can be called only from executor constructor, and should not be thread-safe - void Open(const TString& path) { - if (File) { - // We must avoid double open because each executor will call Open() on the same object - // if the same file was specified in Opts - return; - } + +public: + // Note that this class must have default ctor (it's declared here just for clearness) + TMyFile() { + } + + // Note that dtor will be called by TManager::Delete() after detachment and destruction of all executors + ~TMyFile() { + } + + // Some kind of state initialization + // Can be called only from executor constructor, and should not be thread-safe + void Open(const TString& path) { + if (File) { + // We must avoid double open because each executor will call Open() on the same object + // if the same file was specified in Opts + return; + } File.Reset(new TUnbufferedFileOutput(path)); - } - - // Outputs a line to opened file - // Can be called from DoExecute() and must be thread-safe - void Output(const TString& line) { - Y_VERIFY(File); - TGuard<TMutex> g(Mutex); // Because DoExecute() call can come from any thread - *File << line << Endl; - } -}; - -// Action that prints events to specified file -class TMyActionExecutor: public NLWTrace::TCustomActionExecutor { -private: - TMyFile& File; - -public: - TMyActionExecutor(NLWTrace::TProbe* probe, const NLWTrace::TCustomAction& action, NLWTrace::TSession* session) - : NLWTrace::TCustomActionExecutor(probe, false /* not destructive */) - , File(session->Resources().Get<TMyFile>("FileHolder/" + action.GetOpts(0))) // unique state id must include your d - { - if (action.GetOpts().size() != 1) { - yexception() << "wrong number of Opts in MyAction"; - } - File.Open(action.GetOpts(0)); - } - - static const char* GetActionName() { - static const char name[] = "MyAction"; - return name; - } - -private: - virtual bool DoExecute(NLWTrace::TOrbit&, const NLWTrace::TParams& params) { - // Serialize param values to strings + } + + // Outputs a line to opened file + // Can be called from DoExecute() and must be thread-safe + void Output(const TString& line) { + Y_VERIFY(File); + TGuard<TMutex> g(Mutex); // Because DoExecute() call can come from any thread + *File << line << Endl; + } +}; + +// Action that prints events to specified file +class TMyActionExecutor: public NLWTrace::TCustomActionExecutor { +private: + TMyFile& File; + +public: + TMyActionExecutor(NLWTrace::TProbe* probe, const NLWTrace::TCustomAction& action, NLWTrace::TSession* session) + : NLWTrace::TCustomActionExecutor(probe, false /* not destructive */) + , File(session->Resources().Get<TMyFile>("FileHolder/" + action.GetOpts(0))) // unique state id must include your d + { + if (action.GetOpts().size() != 1) { + yexception() << "wrong number of Opts in MyAction"; + } + File.Open(action.GetOpts(0)); + } + + static const char* GetActionName() { + static const char name[] = "MyAction"; + return name; + } + +private: + virtual bool DoExecute(NLWTrace::TOrbit&, const NLWTrace::TParams& params) { + // Serialize param values to strings TString paramValues[LWTRACE_MAX_PARAMS]; - Probe->Event.Signature.SerializeParams(params, paramValues); - - // Generate output line - TStringStream ss; - ss << "TMyActionExecutor>>> "; - ss << Probe->Event.Name; - for (ui32 i = 0; i < Probe->Event.Signature.ParamCount; ++i) { - ss << " " << Probe->Event.Signature.ParamNames[i] << "=" << paramValues[i]; - } - - // Write line to file - File.Output(ss.Str()); - - // Executors can chain if you specify multiple actions in one block (in trace query). - // So return true to continue execution of actions for given trace query block (on current triggered event) - // or return false if this action is the last for this block - return true; - } -}; + Probe->Event.Signature.SerializeParams(params, paramValues); + + // Generate output line + TStringStream ss; + ss << "TMyActionExecutor>>> "; + ss << Probe->Event.Name; + for (ui32 i = 0; i < Probe->Event.Signature.ParamCount; ++i) { + ss << " " << Probe->Event.Signature.ParamNames[i] << "=" << paramValues[i]; + } + + // Write line to file + File.Output(ss.Str()); + + // Executors can chain if you specify multiple actions in one block (in trace query). + // So return true to continue execution of actions for given trace query block (on current triggered event) + // or return false if this action is the last for this block + return true; + } +}; diff --git a/library/cpp/lwtrace/example3/start_with_query.sh b/library/cpp/lwtrace/example3/start_with_query.sh index 5cd221856f..09f4395f7c 100755 --- a/library/cpp/lwtrace/example3/start_with_query.sh +++ b/library/cpp/lwtrace/example3/start_with_query.sh @@ -1,6 +1,6 @@ #!/bin/bash -echo "Executing program with following trace query:" -cat example_query.tr -echo -n "Press any key to start program" -read -LWTRACE="example_query.tr" ./lwtrace-example3 +echo "Executing program with following trace query:" +cat example_query.tr +echo -n "Press any key to start program" +read +LWTRACE="example_query.tr" ./lwtrace-example3 diff --git a/library/cpp/lwtrace/example3/ya.make b/library/cpp/lwtrace/example3/ya.make index c5b31586e9..e3a16da2b2 100644 --- a/library/cpp/lwtrace/example3/ya.make +++ b/library/cpp/lwtrace/example3/ya.make @@ -1,9 +1,9 @@ -PROGRAM(lwtrace-example3) +PROGRAM(lwtrace-example3) -OWNER(serxa) +OWNER(serxa) SRCS( - lwtrace_example3.cpp + lwtrace_example3.cpp ) PEERDIR( diff --git a/library/cpp/lwtrace/example4/example_query.tr b/library/cpp/lwtrace/example4/example_query.tr index 46cd25ce91..54441f9082 100644 --- a/library/cpp/lwtrace/example4/example_query.tr +++ b/library/cpp/lwtrace/example4/example_query.tr @@ -1,6 +1,6 @@ Blocks { ProbeDesc { - Name: "BackTrack" + Name: "BackTrack" Provider: "LWTRACE_EXAMPLE_PROVIDER" } Action { diff --git a/library/cpp/lwtrace/example4/lwtrace_example4.cpp b/library/cpp/lwtrace/example4/lwtrace_example4.cpp index 7b55a07c75..1e99923d22 100644 --- a/library/cpp/lwtrace/example4/lwtrace_example4.cpp +++ b/library/cpp/lwtrace/example4/lwtrace_example4.cpp @@ -1,37 +1,37 @@ #include <library/cpp/lwtrace/all.h> -#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ - PROBE(BackTrack, GROUPS(), TYPES(NLWTrace::TSymbol), NAMES("frame")) \ +#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(BackTrack, GROUPS(), TYPES(NLWTrace::TSymbol), NAMES("frame")) \ /**/ LWTRACE_DECLARE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER) LWTRACE_DEFINE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER) -LWTRACE_USING(LWTRACE_EXAMPLE_PROVIDER); - -#define MY_BACKTRACK() LWPROBE(BackTrack, LWTRACE_LOCATION_SYMBOL) - +LWTRACE_USING(LWTRACE_EXAMPLE_PROVIDER); + +#define MY_BACKTRACK() LWPROBE(BackTrack, LWTRACE_LOCATION_SYMBOL) + void InitLWTrace() { NLWTrace::StartLwtraceFromEnv(); } -long double Fact(int n) { - MY_BACKTRACK(); +long double Fact(int n) { + MY_BACKTRACK(); if (n < 0) { - MY_BACKTRACK(); + MY_BACKTRACK(); ythrow yexception() << "N! is undefined for negative N (" << n << ")"; } double result = 1; for (; n > 1; --n) { - MY_BACKTRACK(); + MY_BACKTRACK(); result *= n; } - MY_BACKTRACK(); + MY_BACKTRACK(); return result; } void FactorialCalculator() { - MY_BACKTRACK(); + MY_BACKTRACK(); i32 n; Cout << "Enter a number: "; TString str; @@ -42,8 +42,8 @@ void FactorialCalculator() { int main() { InitLWTrace(); - MY_BACKTRACK(); + MY_BACKTRACK(); FactorialCalculator(); - MY_BACKTRACK(); + MY_BACKTRACK(); return 0; } diff --git a/library/cpp/lwtrace/example4/start_with_query.sh b/library/cpp/lwtrace/example4/start_with_query.sh index 5bc195c1ae..17cf93f3b0 100755 --- a/library/cpp/lwtrace/example4/start_with_query.sh +++ b/library/cpp/lwtrace/example4/start_with_query.sh @@ -1,3 +1,3 @@ #!/bin/bash export LWTRACE="example_query.tr" -./lwtrace-example4 +./lwtrace-example4 diff --git a/library/cpp/lwtrace/example4/ya.make b/library/cpp/lwtrace/example4/ya.make index a3004340a8..22dd209068 100644 --- a/library/cpp/lwtrace/example4/ya.make +++ b/library/cpp/lwtrace/example4/ya.make @@ -1,9 +1,9 @@ -PROGRAM(lwtrace-example4) +PROGRAM(lwtrace-example4) -OWNER(serxa) +OWNER(serxa) SRCS( - lwtrace_example4.cpp + lwtrace_example4.cpp ) PEERDIR( diff --git a/library/cpp/lwtrace/example5/example_query.tr b/library/cpp/lwtrace/example5/example_query.tr index 90887d4ddf..34f872d7ee 100644 --- a/library/cpp/lwtrace/example5/example_query.tr +++ b/library/cpp/lwtrace/example5/example_query.tr @@ -1,9 +1,9 @@ -Blocks { - ProbeDesc { - Group: "LWTRACE_EXAMPLE_PROVIDER" - } - Action { - PrintToStderrAction { } - } -} - +Blocks { + ProbeDesc { + Group: "LWTRACE_EXAMPLE_PROVIDER" + } + Action { + PrintToStderrAction { } + } +} + diff --git a/library/cpp/lwtrace/example5/lwtrace_example5.cpp b/library/cpp/lwtrace/example5/lwtrace_example5.cpp index 1c324473c2..3a5e3def30 100644 --- a/library/cpp/lwtrace/example5/lwtrace_example5.cpp +++ b/library/cpp/lwtrace/example5/lwtrace_example5.cpp @@ -1,30 +1,30 @@ #include <library/cpp/lwtrace/all.h> #include <library/cpp/lwtrace/lwprobe.h> - -template <ui64 N> -ui64 Fact() { + +template <ui64 N> +ui64 Fact() { ui64 result = N * Fact<N - 1>(); - + #ifndef LWTRACE_DISABLE - // Note that probe is create on the first pass - // LWTRACE_DECLARE_PROVIDER and LWTRACE_DEFINE_PROVIDER are not needed - // (Provider is created implicitly) - static NLWTrace::TLWProbe<ui64> factProbe( - "LWTRACE_EXAMPLE_PROVIDER", "FactProbe_" + ToString(N), {}, {"result"}); - - LWPROBE_OBJ(factProbe, result); + // Note that probe is create on the first pass + // LWTRACE_DECLARE_PROVIDER and LWTRACE_DEFINE_PROVIDER are not needed + // (Provider is created implicitly) + static NLWTrace::TLWProbe<ui64> factProbe( + "LWTRACE_EXAMPLE_PROVIDER", "FactProbe_" + ToString(N), {}, {"result"}); + + LWPROBE_OBJ(factProbe, result); #endif // LWTRACE_DISABLE - return result; -} - -template <> -ui64 Fact<0>() { - return 1; -} - -int main() { + return result; +} + +template <> +ui64 Fact<0>() { + return 1; +} + +int main() { Fact<6>(); // First run is required to create probes we can use later in trace query - NLWTrace::StartLwtraceFromEnv(); // parse trace query and create trace session + NLWTrace::StartLwtraceFromEnv(); // parse trace query and create trace session Cout << Fact<6>() << Endl; // actually trigger probes - return 0; -} + return 0; +} diff --git a/library/cpp/lwtrace/example5/start_with_query.sh b/library/cpp/lwtrace/example5/start_with_query.sh index 4df5e4e47c..9802100f5b 100755 --- a/library/cpp/lwtrace/example5/start_with_query.sh +++ b/library/cpp/lwtrace/example5/start_with_query.sh @@ -1,3 +1,3 @@ -#!/bin/bash -export LWTRACE="example_query.tr" -./lwtrace-example5 +#!/bin/bash +export LWTRACE="example_query.tr" +./lwtrace-example5 diff --git a/library/cpp/lwtrace/example5/ya.make b/library/cpp/lwtrace/example5/ya.make index 06dd4dc569..04ee4d29f2 100644 --- a/library/cpp/lwtrace/example5/ya.make +++ b/library/cpp/lwtrace/example5/ya.make @@ -1,13 +1,13 @@ -PROGRAM(lwtrace-example5) - -OWNER(serxa) - -SRCS( - lwtrace_example5.cpp -) - -PEERDIR( +PROGRAM(lwtrace-example5) + +OWNER(serxa) + +SRCS( + lwtrace_example5.cpp +) + +PEERDIR( library/cpp/lwtrace -) - -END() +) + +END() diff --git a/library/cpp/lwtrace/kill_action.cpp b/library/cpp/lwtrace/kill_action.cpp index 2b74dc4587..dad8b9afa4 100644 --- a/library/cpp/lwtrace/kill_action.cpp +++ b/library/cpp/lwtrace/kill_action.cpp @@ -10,12 +10,12 @@ using namespace NLWTrace; using namespace NLWTrace::NPrivate; -bool TKillActionExecutor::DoExecute(TOrbit&, const TParams&) { +bool TKillActionExecutor::DoExecute(TOrbit&, const TParams&) { #ifdef _win_ abort(); #else int r = kill(getpid(), SIGABRT); Y_VERIFY(r == 0, "kill failed"); - return true; + return true; #endif } diff --git a/library/cpp/lwtrace/kill_action.h b/library/cpp/lwtrace/kill_action.h index 14da9ffd50..1544e339e1 100644 --- a/library/cpp/lwtrace/kill_action.h +++ b/library/cpp/lwtrace/kill_action.h @@ -2,14 +2,14 @@ #include "probe.h" -namespace NLWTrace { - namespace NPrivate { - class TKillActionExecutor: public IExecutor { - public: - explicit TKillActionExecutor(const TProbe*) { - } - bool DoExecute(TOrbit& orbit, const TParams& params) override; - }; +namespace NLWTrace { + namespace NPrivate { + class TKillActionExecutor: public IExecutor { + public: + explicit TKillActionExecutor(const TProbe*) { + } + bool DoExecute(TOrbit& orbit, const TParams& params) override; + }; - } -} + } +} diff --git a/library/cpp/lwtrace/log.h b/library/cpp/lwtrace/log.h index 56981a97f8..b226a1534c 100644 --- a/library/cpp/lwtrace/log.h +++ b/library/cpp/lwtrace/log.h @@ -1,906 +1,906 @@ -#pragma once - +#pragma once + #include "probe.h" #include <util/datetime/base.h> #include <util/generic/algorithm.h> #include <util/generic/deque.h> -#include <util/generic/noncopyable.h> -#include <util/generic/vector.h> +#include <util/generic/noncopyable.h> +#include <util/generic/vector.h> #include <util/string/printf.h> #include <util/system/atomic.h> #include <util/system/hp_timer.h> -#include <util/system/mutex.h> -#include <util/system/spinlock.h> -#include <util/system/thread.h> +#include <util/system/mutex.h> +#include <util/system/spinlock.h> +#include <util/system/thread.h> #include <util/system/tls.h> - -namespace NLWTrace { - // Cyclic buffer that pushes items to its back and pop item from front on overflow - template <class TItem> - class TCyclicBuffer: public TNonCopyable { - private: - TVector<TItem> Data; - TItem* Front; // Points to the first item (valid iff Size > 0) - TItem* Back; // Points to the last item (valid iff Size > 0) - size_t Size; // Number of items in the buffer - - TItem* First() { - return &*Data.begin(); - } - - TItem* Last() { - return &*Data.end(); - } - - const TItem* First() const { - return &*Data.begin(); - } - - const TItem* Last() const { - return &*Data.end(); - } - - public: - explicit TCyclicBuffer(size_t capacity) - : Data(capacity) - , Size(0) - { - } - - TItem* Add() { - if (Size != 0) { - Inc(Back); - if (Back == Front) { - Inc(Front); // Forget (pop_front) old items - } else { - Size++; - } - } else { - Front = Back = First(); - Size = 1; - } - Back->Clear(); - return Back; - } - - TItem* GetFront() { - return Front; - } - - TItem* GetBack() { - return Back; - } - - const TItem* GetFront() const { - return Front; - } - - const TItem* GetBack() const { - return Back; - } - - size_t GetSize() const { - return Size; - } - - bool IsFull() const { - return Size == Data.size(); - } - - void Inc(TItem*& it) { - it++; - if (it == Last()) { - it = First(); - } - } - - void Inc(const TItem*& it) const { - it++; - if (it == Last()) { - it = First(); - } - } - - void Destroy() { - Data.clear(); - Size = 0; - } - - void Clear() { - Size = 0; - } - - void Swap(TCyclicBuffer& other) { - Data.swap(other.Data); - std::swap(Front, other.Front); - std::swap(Back, other.Back); - std::swap(Size, other.Size); - } - }; - - // Buffer that pushes items to its back and pop item from front on expire - template <class TItem> - class TDurationBuffer: public TNonCopyable { - protected: - TDeque<TItem> Data; - ui64 StoreDuration; - ui8 CleanupCounter = 0; - - public: - explicit TDurationBuffer(TDuration duration) - : StoreDuration(DurationToCycles(duration)) - { - } - - TItem* Add() { - if (!CleanupCounter) { - Cleanup(); - CleanupCounter = 128; // Make cleanup after every 128 additions - } - CleanupCounter--; - Data.emplace_back(); - return &Data.back(); - } - - TItem* GetFront() { - return &Data.front(); - } - - TItem* GetBack() { - return &Data.back(); - } - - const TItem* GetFront() const { - return &Data.front(); - } - - const TItem* GetBack() const { - return &Data.back(); - } - - size_t GetSize() const { - return Data.size(); - } - - bool Empty() const { - return Data.empty(); - } - - void Destroy() { - Data.clear(); - } - - void Swap(TDurationBuffer& other) { - Data.swap(other.Data); - std::swap(StoreDuration, other.StoreDuration); - } - - private: - void Cleanup() { - ui64 cutoff = GetCycleCount(); - if (cutoff > StoreDuration) { - cutoff -= StoreDuration; - while (!Data.empty() && Data.front().GetTimestampCycles() < cutoff) { - Data.pop_front(); - } - } - } - }; - - struct TLogItem { - TProbe* Probe = nullptr; - TParams Params; - size_t SavedParamsCount; - TInstant Timestamp; - ui64 TimestampCycles; - - TLogItem() { - } - - TLogItem(const TLogItem& other) - : Probe(other.Probe) - , SavedParamsCount(other.SavedParamsCount) - , Timestamp(other.Timestamp) - , TimestampCycles(other.TimestampCycles) - { - Clone(other); - } - - ~TLogItem() { - Destroy(); - } - - TLogItem& operator=(const TLogItem& other) { - Destroy(); - Probe = other.Probe; - SavedParamsCount = other.SavedParamsCount; - Timestamp = other.Timestamp; - TimestampCycles = other.TimestampCycles; - Clone(other); - return *this; - } - - void Clear() { - Destroy(); - Probe = nullptr; - } - - void ToProtobuf(TLogItemPb& pb) const { - pb.SetName(Probe->Event.Name); - pb.SetProvider(Probe->Event.GetProvider()); - if (SavedParamsCount > 0) { - TString paramValues[LWTRACE_MAX_PARAMS]; - Probe->Event.Signature.SerializeParams(Params, paramValues); - for (size_t pi = 0; pi < SavedParamsCount; pi++) { - pb.AddParams(paramValues[pi]); - } - } - pb.SetTimestamp(Timestamp.GetValue()); - pb.SetTimestampCycles(TimestampCycles); - } - - TTypedParam GetParam(const TString& param) const { - if (SavedParamsCount == 0) { - return TTypedParam(); - } else { - size_t idx = Probe->Event.Signature.FindParamIndex(param); - if (idx >= SavedParamsCount) { // Also covers idx=-1 case (not found) - return TTypedParam(); - } else { - EParamTypePb type = ParamTypeToProtobuf(Probe->Event.Signature.ParamTypes[idx]); - return TTypedParam(type, Params.Param[idx]); - } - } - } - - ui64 GetTimestampCycles() const { - return TimestampCycles; - } - - private: - void Clone(const TLogItem& other) { - if (Probe && SavedParamsCount > 0) { - Probe->Event.Signature.CloneParams(Params, other.Params); - } - } - - void Destroy() { - if (Probe && SavedParamsCount > 0) { - Probe->Event.Signature.DestroyParams(Params); - } - } - }; - - struct TTrackLog { - struct TItem : TLogItem { - TThread::TId ThreadId; - + +namespace NLWTrace { + // Cyclic buffer that pushes items to its back and pop item from front on overflow + template <class TItem> + class TCyclicBuffer: public TNonCopyable { + private: + TVector<TItem> Data; + TItem* Front; // Points to the first item (valid iff Size > 0) + TItem* Back; // Points to the last item (valid iff Size > 0) + size_t Size; // Number of items in the buffer + + TItem* First() { + return &*Data.begin(); + } + + TItem* Last() { + return &*Data.end(); + } + + const TItem* First() const { + return &*Data.begin(); + } + + const TItem* Last() const { + return &*Data.end(); + } + + public: + explicit TCyclicBuffer(size_t capacity) + : Data(capacity) + , Size(0) + { + } + + TItem* Add() { + if (Size != 0) { + Inc(Back); + if (Back == Front) { + Inc(Front); // Forget (pop_front) old items + } else { + Size++; + } + } else { + Front = Back = First(); + Size = 1; + } + Back->Clear(); + return Back; + } + + TItem* GetFront() { + return Front; + } + + TItem* GetBack() { + return Back; + } + + const TItem* GetFront() const { + return Front; + } + + const TItem* GetBack() const { + return Back; + } + + size_t GetSize() const { + return Size; + } + + bool IsFull() const { + return Size == Data.size(); + } + + void Inc(TItem*& it) { + it++; + if (it == Last()) { + it = First(); + } + } + + void Inc(const TItem*& it) const { + it++; + if (it == Last()) { + it = First(); + } + } + + void Destroy() { + Data.clear(); + Size = 0; + } + + void Clear() { + Size = 0; + } + + void Swap(TCyclicBuffer& other) { + Data.swap(other.Data); + std::swap(Front, other.Front); + std::swap(Back, other.Back); + std::swap(Size, other.Size); + } + }; + + // Buffer that pushes items to its back and pop item from front on expire + template <class TItem> + class TDurationBuffer: public TNonCopyable { + protected: + TDeque<TItem> Data; + ui64 StoreDuration; + ui8 CleanupCounter = 0; + + public: + explicit TDurationBuffer(TDuration duration) + : StoreDuration(DurationToCycles(duration)) + { + } + + TItem* Add() { + if (!CleanupCounter) { + Cleanup(); + CleanupCounter = 128; // Make cleanup after every 128 additions + } + CleanupCounter--; + Data.emplace_back(); + return &Data.back(); + } + + TItem* GetFront() { + return &Data.front(); + } + + TItem* GetBack() { + return &Data.back(); + } + + const TItem* GetFront() const { + return &Data.front(); + } + + const TItem* GetBack() const { + return &Data.back(); + } + + size_t GetSize() const { + return Data.size(); + } + + bool Empty() const { + return Data.empty(); + } + + void Destroy() { + Data.clear(); + } + + void Swap(TDurationBuffer& other) { + Data.swap(other.Data); + std::swap(StoreDuration, other.StoreDuration); + } + + private: + void Cleanup() { + ui64 cutoff = GetCycleCount(); + if (cutoff > StoreDuration) { + cutoff -= StoreDuration; + while (!Data.empty() && Data.front().GetTimestampCycles() < cutoff) { + Data.pop_front(); + } + } + } + }; + + struct TLogItem { + TProbe* Probe = nullptr; + TParams Params; + size_t SavedParamsCount; + TInstant Timestamp; + ui64 TimestampCycles; + + TLogItem() { + } + + TLogItem(const TLogItem& other) + : Probe(other.Probe) + , SavedParamsCount(other.SavedParamsCount) + , Timestamp(other.Timestamp) + , TimestampCycles(other.TimestampCycles) + { + Clone(other); + } + + ~TLogItem() { + Destroy(); + } + + TLogItem& operator=(const TLogItem& other) { + Destroy(); + Probe = other.Probe; + SavedParamsCount = other.SavedParamsCount; + Timestamp = other.Timestamp; + TimestampCycles = other.TimestampCycles; + Clone(other); + return *this; + } + + void Clear() { + Destroy(); + Probe = nullptr; + } + + void ToProtobuf(TLogItemPb& pb) const { + pb.SetName(Probe->Event.Name); + pb.SetProvider(Probe->Event.GetProvider()); + if (SavedParamsCount > 0) { + TString paramValues[LWTRACE_MAX_PARAMS]; + Probe->Event.Signature.SerializeParams(Params, paramValues); + for (size_t pi = 0; pi < SavedParamsCount; pi++) { + pb.AddParams(paramValues[pi]); + } + } + pb.SetTimestamp(Timestamp.GetValue()); + pb.SetTimestampCycles(TimestampCycles); + } + + TTypedParam GetParam(const TString& param) const { + if (SavedParamsCount == 0) { + return TTypedParam(); + } else { + size_t idx = Probe->Event.Signature.FindParamIndex(param); + if (idx >= SavedParamsCount) { // Also covers idx=-1 case (not found) + return TTypedParam(); + } else { + EParamTypePb type = ParamTypeToProtobuf(Probe->Event.Signature.ParamTypes[idx]); + return TTypedParam(type, Params.Param[idx]); + } + } + } + + ui64 GetTimestampCycles() const { + return TimestampCycles; + } + + private: + void Clone(const TLogItem& other) { + if (Probe && SavedParamsCount > 0) { + Probe->Event.Signature.CloneParams(Params, other.Params); + } + } + + void Destroy() { + if (Probe && SavedParamsCount > 0) { + Probe->Event.Signature.DestroyParams(Params); + } + } + }; + + struct TTrackLog { + struct TItem : TLogItem { + TThread::TId ThreadId; + TItem() = default; - - TItem(TThread::TId tid, const TLogItem& item) - : TLogItem(item) - , ThreadId(tid) - { - } - }; - - using TItems = TVector<TItem>; - TItems Items; - bool Truncated = false; - ui64 Id = 0; - - void Clear() { - Items.clear(); - Truncated = false; - } - - ui64 GetTimestampCycles() const { - return Items.empty() ? 0 : Items.front().GetTimestampCycles(); - } - }; - - // Log that uses per-thread cyclic buffers to store items - template <class T> - class TCyclicLogImpl: public TNonCopyable { - public: - using TLog = TCyclicLogImpl; - using TItem = T; - - private: - using TBuffer = TCyclicBuffer<TItem>; - - class TStorage { - private: - // Data that can be accessed in lock-free way from reader/writer - TAtomic Writers = 0; - mutable TBuffer* volatile CurBuffer = nullptr; - - // Data that can be accessed only from reader - // NOTE: multiple readers are serialized by TCyclicLogImpl::Lock - mutable TBuffer* OldBuffer = nullptr; - mutable TBuffer* NewBuffer = nullptr; - - TLog* volatile Log = nullptr; - - TThread::TId ThreadId = 0; - TAtomic EventsCount = 0; - - public: - TStorage() { - } - - explicit TStorage(TLog* log) - : CurBuffer(new TBuffer(log->GetCapacity())) - , OldBuffer(new TBuffer(log->GetCapacity())) - , NewBuffer(new TBuffer(log->GetCapacity())) - , Log(log) - , ThreadId(TThread::CurrentThreadId()) - { - Log->RegisterThread(this); - } - - ~TStorage() { - if (TLog* log = AtomicSwap(&Log, nullptr)) { - AtomicBarrier(); // Serialize `Log' and TCyclicLogImpl::Lock memory order - // NOTE: the following function swaps `this' with `new TStorage()' - log->UnregisterThreadAndMakeOrphan(this); - } else { - // NOTE: `Log' can be nullptr if either it is orphan storage or TryDismiss() succeeded - // NOTE: in both cases it is ok to call these deletes - delete CurBuffer; - delete OldBuffer; - delete NewBuffer; - } - } - - bool TryDismiss() { - // TCyclicLogImpl::Lock implied (no readers) - if (TLog* log = AtomicSwap(&Log, nullptr)) { - TBuffer* curBuffer = AtomicSwap(&CurBuffer, nullptr); - WaitForWriters(); - // At this point we guarantee that there is no and wont be active writer - delete curBuffer; - delete OldBuffer; - delete NewBuffer; - OldBuffer = nullptr; - NewBuffer = nullptr; - return true; - } else { - // ~TStorage() is in progress - return false; - } - } - - void WaitForWriters() const { - while (AtomicGet(Writers) > 0) { - SpinLockPause(); - } - } - - TThread::TId GetThreadId() const { - // TCyclicLogImpl::Lock implied (no readers) - return ThreadId; - } - - size_t GetEventsCount() const { - // TCyclicLogImpl::Lock implied (no readers) - return AtomicGet(EventsCount); - } - - void Swap(TStorage& other) { - // TCyclicLogImpl::Lock implied (no readers) - std::swap(CurBuffer, other.CurBuffer); - std::swap(OldBuffer, other.OldBuffer); - std::swap(NewBuffer, other.NewBuffer); - std::swap(Log, other.Log); - std::swap(ThreadId, other.ThreadId); - std::swap(EventsCount, other.EventsCount); - } - - TBuffer* StartWriter() { - AtomicIncrement(Writers); - return const_cast<TBuffer*>(AtomicGet(CurBuffer)); - } - - void StopWriter() { - AtomicDecrement(Writers); - } - - void IncEventsCount() { - AtomicIncrement(EventsCount); - } - - template <class TReader> - void ReadItems(TReader& r) const { - // TCyclicLogImpl::Lock implied - NewBuffer = AtomicSwap(&CurBuffer, NewBuffer); - WaitForWriters(); - - // Merge new buffer into old buffer - if (NewBuffer->IsFull()) { - std::swap(NewBuffer, OldBuffer); - } else { - if (NewBuffer->GetSize() > 0) { - for (const TItem *i = NewBuffer->GetFront(), *e = NewBuffer->GetBack();; NewBuffer->Inc(i)) { - TItem* oldSlot = OldBuffer->Add(); - *oldSlot = *i; - if (i == e) { - break; - } - } - } - } - - NewBuffer->Clear(); - - // Iterate over old buffer - if (OldBuffer->GetSize() > 0) { - for (const TItem *i = OldBuffer->GetFront(), *e = OldBuffer->GetBack();; OldBuffer->Inc(i)) { - r.Push(ThreadId, *i); - if (i == e) { - break; - } - } - } - } - }; - - size_t Capacity; - Y_THREAD(TStorage) - PerThreadStorage; - TSpinLock Lock; - // If thread exits its storage is destroyed, so we move it into OrphanStorages before destruction - TVector<TAtomicSharedPtr<TStorage>> OrphanStorages; - typedef TVector<TStorage*> TStoragesVec; - TStoragesVec StoragesVec; - TAtomic ThreadsCount; - - public: - explicit TCyclicLogImpl(size_t capacity) - : Capacity(capacity) - , PerThreadStorage(this) - , ThreadsCount(0) - { - } - - ~TCyclicLogImpl() { - for (bool again = true; again;) { - TGuard<TSpinLock> g(Lock); - AtomicBarrier(); // Serialize `storage->Log' and Lock memory order - again = false; - while (!StoragesVec.empty()) { - TStorage* storage = StoragesVec.back(); - // TStorage destructor can be called when TCyclicLogImpl is already destructed - // So we ensure this does not lead to problems - // NOTE: Y_THREAD(TStorage) destructs TStorage object for a specific thread only on that thread exit - // NOTE: this issue can lead to memleaks if threads never exit and many TCyclicLogImpl are created - if (storage->TryDismiss()) { - StoragesVec.pop_back(); - } else { - // Rare case when another thread is running ~TStorage() -- let it finish - again = true; - SpinLockPause(); - break; - } - } - } - } - - size_t GetCapacity() const { - return Capacity; - } - - size_t GetEventsCount() const { - size_t events = 0; - TGuard<TSpinLock> g(Lock); - for (auto i : StoragesVec) { - events += i->GetEventsCount(); - } - for (const auto& orphanStorage : OrphanStorages) { - events += orphanStorage->GetEventsCount(); - } - return events; - } - - size_t GetThreadsCount() const { - return AtomicGet(ThreadsCount); - } - - void RegisterThread(TStorage* storage) { - TGuard<TSpinLock> g(Lock); - StoragesVec.push_back(storage); - AtomicIncrement(ThreadsCount); - } - - void UnregisterThreadAndMakeOrphan(TStorage* storage) { - TGuard<TSpinLock> g(Lock); - // `storage' writers are not possible at this scope because - // UnregisterThreadAndMakeOrphan is only called from exiting threads. - // `storage' readers are not possible at this scope due to Lock guard. - - Erase(StoragesVec, storage); - TAtomicSharedPtr<TStorage> orphan(new TStorage()); - orphan->Swap(*storage); // Swap is required because we cannot take ownership from Y_THREAD(TStorage) object - OrphanStorages.push_back(orphan); - } - - template <class TReader> - void ReadThreads(TReader& r) const { - TGuard<TSpinLock> g(Lock); - for (auto i : StoragesVec) { - r.PushThread(i->GetThreadId()); - } - for (const auto& orphanStorage : OrphanStorages) { - r.PushThread(orphanStorage->GetThreadId()); - } - } - - template <class TReader> - void ReadItems(TReader& r) const { - TGuard<TSpinLock> g(Lock); - for (auto i : StoragesVec) { - i->ReadItems(r); - } - for (const auto& orphanStorage : OrphanStorages) { - orphanStorage->ReadItems(r); - } - } - - class TAccessor { - private: - TStorage& Storage; - TBuffer* Buffer; - - public: - explicit TAccessor(TLog& log) - : Storage(log.PerThreadStorage.Get()) - , Buffer(Storage.StartWriter()) - { - } - - ~TAccessor() { - Storage.StopWriter(); - } - - TItem* Add() { - if (Buffer) { - Storage.IncEventsCount(); - return Buffer->Add(); - } else { - // TStorage detached from trace due to trace destruction - // so we should not try log anything - return nullptr; - } - } - }; - - friend class TAccessor; - }; - - using TCyclicLog = TCyclicLogImpl<TLogItem>; - using TCyclicDepot = TCyclicLogImpl<TTrackLog>; - - // Log that uses per-thread buffers to store items up to given duration - template <class T> - class TDurationLogImpl: public TNonCopyable { - public: - using TLog = TDurationLogImpl; - using TItem = T; - - class TAccessor; - friend class TAccessor; - class TAccessor: public TGuard<TSpinLock> { - private: - TLog& Log; - - public: - explicit TAccessor(TLog& log) - : TGuard<TSpinLock>(log.PerThreadStorage.Get().Lock) - , Log(log) - { - } - - TItem* Add() { - return Log.PerThreadStorage.Get().Add(); - } - }; - - private: - class TStorage: public TDurationBuffer<TItem> { - private: - TLog* Log; - TThread::TId ThreadId; - ui64 EventsCount; - - public: - TSpinLock Lock; - - TStorage() - : TDurationBuffer<TItem>(TDuration::Zero()) - , Log(nullptr) - , ThreadId(0) - , EventsCount(0) - { - } - - explicit TStorage(TLog* log) - : TDurationBuffer<TItem>(log->GetDuration()) - , Log(log) - , ThreadId(TThread::CurrentThreadId()) - , EventsCount(0) - { - Log->RegisterThread(this); - } - - ~TStorage() { - if (Log) { - Log->UnregisterThread(this); - } - } - - void DetachFromTraceLog() { - Log = nullptr; - } - - TItem* Add() { - EventsCount++; - return TDurationBuffer<TItem>::Add(); - } - - bool Expired(ui64 now) const { - return this->Empty() ? true : this->GetBack()->GetTimestampCycles() + this->StoreDuration < now; - } - - TThread::TId GetThreadId() const { - return ThreadId; - } - - size_t GetEventsCount() const { - return EventsCount; - } - - void Swap(TStorage& other) { - TDurationBuffer<TItem>::Swap(other); - std::swap(Log, other.Log); - std::swap(ThreadId, other.ThreadId); - std::swap(EventsCount, other.EventsCount); - } - - template <class TReader> - void ReadItems(ui64 now, ui64 duration, TReader& r) const { - TGuard<TSpinLock> g(Lock); - if (now > duration) { - ui64 cutoff = now - duration; - for (const TItem& item : this->Data) { - if (item.GetTimestampCycles() >= cutoff) { - r.Push(ThreadId, item); - } - } - } else { - for (const TItem& item : this->Data) { - r.Push(ThreadId, item); - } - } - } - }; - - TDuration Duration; - Y_THREAD(TStorage) - PerThreadStorage; - TSpinLock Lock; - typedef TVector<TAtomicSharedPtr<TStorage>> TOrphanStorages; - TOrphanStorages OrphanStorages; // if thread exits its storage is destroyed, so we move it into OrphanStorages before destruction - TAtomic OrphanStoragesEventsCount = 0; - typedef TVector<TStorage*> TStoragesVec; - TStoragesVec StoragesVec; - TAtomic ThreadsCount; - - public: - explicit TDurationLogImpl(TDuration duration) - : Duration(duration) - , PerThreadStorage(this) - , ThreadsCount(0) - { - } - - ~TDurationLogImpl() { - for (auto storage : StoragesVec) { - // NOTE: Y_THREAD(TStorage) destructs TStorage object for a specific thread only on that thread exit - // NOTE: this issue can lead to memleaks if threads never exit and many TTraceLogs are created - storage->Destroy(); - - // TraceLogStorage destructor can be called when TTraceLog is already destructed - // So we ensure this does not lead to problems - storage->DetachFromTraceLog(); - } - } - - TDuration GetDuration() const { - return Duration; - } - - size_t GetEventsCount() const { - size_t events = AtomicGet(OrphanStoragesEventsCount); - TGuard<TSpinLock> g(Lock); - for (auto i : StoragesVec) { - events += i->GetEventsCount(); - } - return events; - } - - size_t GetThreadsCount() const { - return AtomicGet(ThreadsCount); - } - - void RegisterThread(TStorage* storage) { - TGuard<TSpinLock> g(Lock); - StoragesVec.push_back(storage); - AtomicIncrement(ThreadsCount); - } - - void UnregisterThread(TStorage* storage) { - TGuard<TSpinLock> g(Lock); - for (auto i = StoragesVec.begin(), e = StoragesVec.end(); i != e; ++i) { - if (*i == storage) { - StoragesVec.erase(i); - break; - } - } - TAtomicSharedPtr<TStorage> orphan(new TStorage()); - orphan->Swap(*storage); - orphan->DetachFromTraceLog(); - AtomicAdd(OrphanStoragesEventsCount, orphan->GetEventsCount()); - OrphanStorages.push_back(orphan); - CleanOrphanStorages(GetCycleCount()); - } - - void CleanOrphanStorages(ui64 now) { - EraseIf(OrphanStorages, [=](const TAtomicSharedPtr<TStorage>& ptr) { - const TStorage& storage = *ptr; - return storage.Expired(now); - }); - } - - template <class TReader> - void ReadThreads(TReader& r) const { - TGuard<TSpinLock> g(Lock); - for (TStorage* i : StoragesVec) { - r.PushThread(i->GetThreadId()); - } - for (const auto& orphanStorage : OrphanStorages) { - r.PushThread(orphanStorage->GetThreadId()); - } - } - - template <class TReader> - void ReadItems(ui64 now, ui64 duration, TReader& r) const { - TGuard<TSpinLock> g(Lock); - for (TStorage* storage : StoragesVec) { - storage->ReadItems(now, duration, r); - } - for (const auto& orphanStorage : OrphanStorages) { - orphanStorage->ReadItems(now, duration, r); - } - } - }; - - using TDurationLog = TDurationLogImpl<TLogItem>; - using TDurationDepot = TDurationLogImpl<TTrackLog>; - - // Log that uses one cyclic buffer to store items - // Each item is a result of execution of some event - class TInMemoryLog: public TNonCopyable { - public: - struct TItem { - const TEvent* Event; - TParams Params; - TInstant Timestamp; - - TItem() - : Event(nullptr) - { - } - - TItem(const TItem& other) - : Event(other.Event) - , Timestamp(other.Timestamp) - { - Clone(other); - } - - ~TItem() { - Destroy(); - } - - TItem& operator=(const TItem& other) { - Destroy(); - Event = other.Event; - Timestamp = other.Timestamp; - Clone(other); - return *this; - } - - void Clear() { - Destroy(); - Event = nullptr; - } - - private: - void Clone(const TItem& other) { - if (Event && Event->Signature.ParamCount > 0) { - Event->Signature.CloneParams(Params, other.Params); - } - } - - void Destroy() { - if (Event && Event->Signature.ParamCount > 0) { - Event->Signature.DestroyParams(Params); - } - } - }; - - class TAccessor; - friend class TAccessor; - class TAccessor: public TGuard<TMutex> { - private: - TInMemoryLog& Log; - - public: - explicit TAccessor(TInMemoryLog& log) - : TGuard<TMutex>(log.Lock) - , Log(log) - { - } - - TItem* Add() { - return Log.Storage.Add(); - } - }; - - private: - TMutex Lock; - TCyclicBuffer<TItem> Storage; - - public: - explicit TInMemoryLog(size_t capacity) - : Storage(capacity) - { - } - - template <class TReader> - void ReadItems(TReader& r) const { - TGuard<TMutex> g(Lock); - if (Storage.GetSize() > 0) { - for (const TItem *i = Storage.GetFront(), *e = Storage.GetBack();; Storage.Inc(i)) { - r.Push(*i); - if (i == e) { - break; - } - } - } - } - }; - -#ifndef LWTRACE_DISABLE - - // Class representing a specific event - template <LWTRACE_TEMPLATE_PARAMS> - struct TUserEvent { - TEvent Event; - - inline void operator()(TInMemoryLog& log, bool logTimestamp, LWTRACE_FUNCTION_PARAMS) const { - TInMemoryLog::TAccessor la(log); - if (TInMemoryLog::TItem* item = la.Add()) { - item->Event = &Event; - LWTRACE_PREPARE_PARAMS(item->Params); - if (logTimestamp) { - item->Timestamp = TInstant::Now(); - } - } - } - }; - -#endif - -} + + TItem(TThread::TId tid, const TLogItem& item) + : TLogItem(item) + , ThreadId(tid) + { + } + }; + + using TItems = TVector<TItem>; + TItems Items; + bool Truncated = false; + ui64 Id = 0; + + void Clear() { + Items.clear(); + Truncated = false; + } + + ui64 GetTimestampCycles() const { + return Items.empty() ? 0 : Items.front().GetTimestampCycles(); + } + }; + + // Log that uses per-thread cyclic buffers to store items + template <class T> + class TCyclicLogImpl: public TNonCopyable { + public: + using TLog = TCyclicLogImpl; + using TItem = T; + + private: + using TBuffer = TCyclicBuffer<TItem>; + + class TStorage { + private: + // Data that can be accessed in lock-free way from reader/writer + TAtomic Writers = 0; + mutable TBuffer* volatile CurBuffer = nullptr; + + // Data that can be accessed only from reader + // NOTE: multiple readers are serialized by TCyclicLogImpl::Lock + mutable TBuffer* OldBuffer = nullptr; + mutable TBuffer* NewBuffer = nullptr; + + TLog* volatile Log = nullptr; + + TThread::TId ThreadId = 0; + TAtomic EventsCount = 0; + + public: + TStorage() { + } + + explicit TStorage(TLog* log) + : CurBuffer(new TBuffer(log->GetCapacity())) + , OldBuffer(new TBuffer(log->GetCapacity())) + , NewBuffer(new TBuffer(log->GetCapacity())) + , Log(log) + , ThreadId(TThread::CurrentThreadId()) + { + Log->RegisterThread(this); + } + + ~TStorage() { + if (TLog* log = AtomicSwap(&Log, nullptr)) { + AtomicBarrier(); // Serialize `Log' and TCyclicLogImpl::Lock memory order + // NOTE: the following function swaps `this' with `new TStorage()' + log->UnregisterThreadAndMakeOrphan(this); + } else { + // NOTE: `Log' can be nullptr if either it is orphan storage or TryDismiss() succeeded + // NOTE: in both cases it is ok to call these deletes + delete CurBuffer; + delete OldBuffer; + delete NewBuffer; + } + } + + bool TryDismiss() { + // TCyclicLogImpl::Lock implied (no readers) + if (TLog* log = AtomicSwap(&Log, nullptr)) { + TBuffer* curBuffer = AtomicSwap(&CurBuffer, nullptr); + WaitForWriters(); + // At this point we guarantee that there is no and wont be active writer + delete curBuffer; + delete OldBuffer; + delete NewBuffer; + OldBuffer = nullptr; + NewBuffer = nullptr; + return true; + } else { + // ~TStorage() is in progress + return false; + } + } + + void WaitForWriters() const { + while (AtomicGet(Writers) > 0) { + SpinLockPause(); + } + } + + TThread::TId GetThreadId() const { + // TCyclicLogImpl::Lock implied (no readers) + return ThreadId; + } + + size_t GetEventsCount() const { + // TCyclicLogImpl::Lock implied (no readers) + return AtomicGet(EventsCount); + } + + void Swap(TStorage& other) { + // TCyclicLogImpl::Lock implied (no readers) + std::swap(CurBuffer, other.CurBuffer); + std::swap(OldBuffer, other.OldBuffer); + std::swap(NewBuffer, other.NewBuffer); + std::swap(Log, other.Log); + std::swap(ThreadId, other.ThreadId); + std::swap(EventsCount, other.EventsCount); + } + + TBuffer* StartWriter() { + AtomicIncrement(Writers); + return const_cast<TBuffer*>(AtomicGet(CurBuffer)); + } + + void StopWriter() { + AtomicDecrement(Writers); + } + + void IncEventsCount() { + AtomicIncrement(EventsCount); + } + + template <class TReader> + void ReadItems(TReader& r) const { + // TCyclicLogImpl::Lock implied + NewBuffer = AtomicSwap(&CurBuffer, NewBuffer); + WaitForWriters(); + + // Merge new buffer into old buffer + if (NewBuffer->IsFull()) { + std::swap(NewBuffer, OldBuffer); + } else { + if (NewBuffer->GetSize() > 0) { + for (const TItem *i = NewBuffer->GetFront(), *e = NewBuffer->GetBack();; NewBuffer->Inc(i)) { + TItem* oldSlot = OldBuffer->Add(); + *oldSlot = *i; + if (i == e) { + break; + } + } + } + } + + NewBuffer->Clear(); + + // Iterate over old buffer + if (OldBuffer->GetSize() > 0) { + for (const TItem *i = OldBuffer->GetFront(), *e = OldBuffer->GetBack();; OldBuffer->Inc(i)) { + r.Push(ThreadId, *i); + if (i == e) { + break; + } + } + } + } + }; + + size_t Capacity; + Y_THREAD(TStorage) + PerThreadStorage; + TSpinLock Lock; + // If thread exits its storage is destroyed, so we move it into OrphanStorages before destruction + TVector<TAtomicSharedPtr<TStorage>> OrphanStorages; + typedef TVector<TStorage*> TStoragesVec; + TStoragesVec StoragesVec; + TAtomic ThreadsCount; + + public: + explicit TCyclicLogImpl(size_t capacity) + : Capacity(capacity) + , PerThreadStorage(this) + , ThreadsCount(0) + { + } + + ~TCyclicLogImpl() { + for (bool again = true; again;) { + TGuard<TSpinLock> g(Lock); + AtomicBarrier(); // Serialize `storage->Log' and Lock memory order + again = false; + while (!StoragesVec.empty()) { + TStorage* storage = StoragesVec.back(); + // TStorage destructor can be called when TCyclicLogImpl is already destructed + // So we ensure this does not lead to problems + // NOTE: Y_THREAD(TStorage) destructs TStorage object for a specific thread only on that thread exit + // NOTE: this issue can lead to memleaks if threads never exit and many TCyclicLogImpl are created + if (storage->TryDismiss()) { + StoragesVec.pop_back(); + } else { + // Rare case when another thread is running ~TStorage() -- let it finish + again = true; + SpinLockPause(); + break; + } + } + } + } + + size_t GetCapacity() const { + return Capacity; + } + + size_t GetEventsCount() const { + size_t events = 0; + TGuard<TSpinLock> g(Lock); + for (auto i : StoragesVec) { + events += i->GetEventsCount(); + } + for (const auto& orphanStorage : OrphanStorages) { + events += orphanStorage->GetEventsCount(); + } + return events; + } + + size_t GetThreadsCount() const { + return AtomicGet(ThreadsCount); + } + + void RegisterThread(TStorage* storage) { + TGuard<TSpinLock> g(Lock); + StoragesVec.push_back(storage); + AtomicIncrement(ThreadsCount); + } + + void UnregisterThreadAndMakeOrphan(TStorage* storage) { + TGuard<TSpinLock> g(Lock); + // `storage' writers are not possible at this scope because + // UnregisterThreadAndMakeOrphan is only called from exiting threads. + // `storage' readers are not possible at this scope due to Lock guard. + + Erase(StoragesVec, storage); + TAtomicSharedPtr<TStorage> orphan(new TStorage()); + orphan->Swap(*storage); // Swap is required because we cannot take ownership from Y_THREAD(TStorage) object + OrphanStorages.push_back(orphan); + } + + template <class TReader> + void ReadThreads(TReader& r) const { + TGuard<TSpinLock> g(Lock); + for (auto i : StoragesVec) { + r.PushThread(i->GetThreadId()); + } + for (const auto& orphanStorage : OrphanStorages) { + r.PushThread(orphanStorage->GetThreadId()); + } + } + + template <class TReader> + void ReadItems(TReader& r) const { + TGuard<TSpinLock> g(Lock); + for (auto i : StoragesVec) { + i->ReadItems(r); + } + for (const auto& orphanStorage : OrphanStorages) { + orphanStorage->ReadItems(r); + } + } + + class TAccessor { + private: + TStorage& Storage; + TBuffer* Buffer; + + public: + explicit TAccessor(TLog& log) + : Storage(log.PerThreadStorage.Get()) + , Buffer(Storage.StartWriter()) + { + } + + ~TAccessor() { + Storage.StopWriter(); + } + + TItem* Add() { + if (Buffer) { + Storage.IncEventsCount(); + return Buffer->Add(); + } else { + // TStorage detached from trace due to trace destruction + // so we should not try log anything + return nullptr; + } + } + }; + + friend class TAccessor; + }; + + using TCyclicLog = TCyclicLogImpl<TLogItem>; + using TCyclicDepot = TCyclicLogImpl<TTrackLog>; + + // Log that uses per-thread buffers to store items up to given duration + template <class T> + class TDurationLogImpl: public TNonCopyable { + public: + using TLog = TDurationLogImpl; + using TItem = T; + + class TAccessor; + friend class TAccessor; + class TAccessor: public TGuard<TSpinLock> { + private: + TLog& Log; + + public: + explicit TAccessor(TLog& log) + : TGuard<TSpinLock>(log.PerThreadStorage.Get().Lock) + , Log(log) + { + } + + TItem* Add() { + return Log.PerThreadStorage.Get().Add(); + } + }; + + private: + class TStorage: public TDurationBuffer<TItem> { + private: + TLog* Log; + TThread::TId ThreadId; + ui64 EventsCount; + + public: + TSpinLock Lock; + + TStorage() + : TDurationBuffer<TItem>(TDuration::Zero()) + , Log(nullptr) + , ThreadId(0) + , EventsCount(0) + { + } + + explicit TStorage(TLog* log) + : TDurationBuffer<TItem>(log->GetDuration()) + , Log(log) + , ThreadId(TThread::CurrentThreadId()) + , EventsCount(0) + { + Log->RegisterThread(this); + } + + ~TStorage() { + if (Log) { + Log->UnregisterThread(this); + } + } + + void DetachFromTraceLog() { + Log = nullptr; + } + + TItem* Add() { + EventsCount++; + return TDurationBuffer<TItem>::Add(); + } + + bool Expired(ui64 now) const { + return this->Empty() ? true : this->GetBack()->GetTimestampCycles() + this->StoreDuration < now; + } + + TThread::TId GetThreadId() const { + return ThreadId; + } + + size_t GetEventsCount() const { + return EventsCount; + } + + void Swap(TStorage& other) { + TDurationBuffer<TItem>::Swap(other); + std::swap(Log, other.Log); + std::swap(ThreadId, other.ThreadId); + std::swap(EventsCount, other.EventsCount); + } + + template <class TReader> + void ReadItems(ui64 now, ui64 duration, TReader& r) const { + TGuard<TSpinLock> g(Lock); + if (now > duration) { + ui64 cutoff = now - duration; + for (const TItem& item : this->Data) { + if (item.GetTimestampCycles() >= cutoff) { + r.Push(ThreadId, item); + } + } + } else { + for (const TItem& item : this->Data) { + r.Push(ThreadId, item); + } + } + } + }; + + TDuration Duration; + Y_THREAD(TStorage) + PerThreadStorage; + TSpinLock Lock; + typedef TVector<TAtomicSharedPtr<TStorage>> TOrphanStorages; + TOrphanStorages OrphanStorages; // if thread exits its storage is destroyed, so we move it into OrphanStorages before destruction + TAtomic OrphanStoragesEventsCount = 0; + typedef TVector<TStorage*> TStoragesVec; + TStoragesVec StoragesVec; + TAtomic ThreadsCount; + + public: + explicit TDurationLogImpl(TDuration duration) + : Duration(duration) + , PerThreadStorage(this) + , ThreadsCount(0) + { + } + + ~TDurationLogImpl() { + for (auto storage : StoragesVec) { + // NOTE: Y_THREAD(TStorage) destructs TStorage object for a specific thread only on that thread exit + // NOTE: this issue can lead to memleaks if threads never exit and many TTraceLogs are created + storage->Destroy(); + + // TraceLogStorage destructor can be called when TTraceLog is already destructed + // So we ensure this does not lead to problems + storage->DetachFromTraceLog(); + } + } + + TDuration GetDuration() const { + return Duration; + } + + size_t GetEventsCount() const { + size_t events = AtomicGet(OrphanStoragesEventsCount); + TGuard<TSpinLock> g(Lock); + for (auto i : StoragesVec) { + events += i->GetEventsCount(); + } + return events; + } + + size_t GetThreadsCount() const { + return AtomicGet(ThreadsCount); + } + + void RegisterThread(TStorage* storage) { + TGuard<TSpinLock> g(Lock); + StoragesVec.push_back(storage); + AtomicIncrement(ThreadsCount); + } + + void UnregisterThread(TStorage* storage) { + TGuard<TSpinLock> g(Lock); + for (auto i = StoragesVec.begin(), e = StoragesVec.end(); i != e; ++i) { + if (*i == storage) { + StoragesVec.erase(i); + break; + } + } + TAtomicSharedPtr<TStorage> orphan(new TStorage()); + orphan->Swap(*storage); + orphan->DetachFromTraceLog(); + AtomicAdd(OrphanStoragesEventsCount, orphan->GetEventsCount()); + OrphanStorages.push_back(orphan); + CleanOrphanStorages(GetCycleCount()); + } + + void CleanOrphanStorages(ui64 now) { + EraseIf(OrphanStorages, [=](const TAtomicSharedPtr<TStorage>& ptr) { + const TStorage& storage = *ptr; + return storage.Expired(now); + }); + } + + template <class TReader> + void ReadThreads(TReader& r) const { + TGuard<TSpinLock> g(Lock); + for (TStorage* i : StoragesVec) { + r.PushThread(i->GetThreadId()); + } + for (const auto& orphanStorage : OrphanStorages) { + r.PushThread(orphanStorage->GetThreadId()); + } + } + + template <class TReader> + void ReadItems(ui64 now, ui64 duration, TReader& r) const { + TGuard<TSpinLock> g(Lock); + for (TStorage* storage : StoragesVec) { + storage->ReadItems(now, duration, r); + } + for (const auto& orphanStorage : OrphanStorages) { + orphanStorage->ReadItems(now, duration, r); + } + } + }; + + using TDurationLog = TDurationLogImpl<TLogItem>; + using TDurationDepot = TDurationLogImpl<TTrackLog>; + + // Log that uses one cyclic buffer to store items + // Each item is a result of execution of some event + class TInMemoryLog: public TNonCopyable { + public: + struct TItem { + const TEvent* Event; + TParams Params; + TInstant Timestamp; + + TItem() + : Event(nullptr) + { + } + + TItem(const TItem& other) + : Event(other.Event) + , Timestamp(other.Timestamp) + { + Clone(other); + } + + ~TItem() { + Destroy(); + } + + TItem& operator=(const TItem& other) { + Destroy(); + Event = other.Event; + Timestamp = other.Timestamp; + Clone(other); + return *this; + } + + void Clear() { + Destroy(); + Event = nullptr; + } + + private: + void Clone(const TItem& other) { + if (Event && Event->Signature.ParamCount > 0) { + Event->Signature.CloneParams(Params, other.Params); + } + } + + void Destroy() { + if (Event && Event->Signature.ParamCount > 0) { + Event->Signature.DestroyParams(Params); + } + } + }; + + class TAccessor; + friend class TAccessor; + class TAccessor: public TGuard<TMutex> { + private: + TInMemoryLog& Log; + + public: + explicit TAccessor(TInMemoryLog& log) + : TGuard<TMutex>(log.Lock) + , Log(log) + { + } + + TItem* Add() { + return Log.Storage.Add(); + } + }; + + private: + TMutex Lock; + TCyclicBuffer<TItem> Storage; + + public: + explicit TInMemoryLog(size_t capacity) + : Storage(capacity) + { + } + + template <class TReader> + void ReadItems(TReader& r) const { + TGuard<TMutex> g(Lock); + if (Storage.GetSize() > 0) { + for (const TItem *i = Storage.GetFront(), *e = Storage.GetBack();; Storage.Inc(i)) { + r.Push(*i); + if (i == e) { + break; + } + } + } + } + }; + +#ifndef LWTRACE_DISABLE + + // Class representing a specific event + template <LWTRACE_TEMPLATE_PARAMS> + struct TUserEvent { + TEvent Event; + + inline void operator()(TInMemoryLog& log, bool logTimestamp, LWTRACE_FUNCTION_PARAMS) const { + TInMemoryLog::TAccessor la(log); + if (TInMemoryLog::TItem* item = la.Add()) { + item->Event = &Event; + LWTRACE_PREPARE_PARAMS(item->Params); + if (logTimestamp) { + item->Timestamp = TInstant::Now(); + } + } + } + }; + +#endif + +} diff --git a/library/cpp/lwtrace/log_shuttle.cpp b/library/cpp/lwtrace/log_shuttle.cpp index 695aa90b31..1e9c00d0ef 100644 --- a/library/cpp/lwtrace/log_shuttle.cpp +++ b/library/cpp/lwtrace/log_shuttle.cpp @@ -1,32 +1,32 @@ -#include "log_shuttle.h" +#include "log_shuttle.h" #include "probes.h" - -namespace NLWTrace { + +namespace NLWTrace { LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER); #ifdef LWTRACE_DISABLE template <class TDepot> - bool TLogShuttle<TDepot>::DoFork(TShuttlePtr& child) { - Y_UNUSED(child); + bool TLogShuttle<TDepot>::DoFork(TShuttlePtr& child) { + Y_UNUSED(child); return false; } template <class TDepot> - bool TLogShuttle<TDepot>::DoJoin(const TShuttlePtr& child) { - Y_UNUSED(child); + bool TLogShuttle<TDepot>::DoJoin(const TShuttlePtr& child) { + Y_UNUSED(child); return false; } #else template <class TDepot> - bool TLogShuttle<TDepot>::DoFork(TShuttlePtr& child) { - if (child = Executor->RentShuttle()) { - child->SetParentSpanId(GetSpanId()); - Executor->Cast(child)->SetIgnore(true); + bool TLogShuttle<TDepot>::DoFork(TShuttlePtr& child) { + if (child = Executor->RentShuttle()) { + child->SetParentSpanId(GetSpanId()); + Executor->Cast(child)->SetIgnore(true); TParams params; - params.Param[0].CopyConstruct<ui64>(child->GetSpanId()); + params.Param[0].CopyConstruct<ui64>(child->GetSpanId()); bool result = DoAddProbe(&LWTRACE_GET_NAME(Fork).Probe, params, 0); TUserSignature<ui64>::DestroyParams(params); return result; @@ -64,4 +64,4 @@ namespace NLWTrace { template class TLogShuttle<TDurationDepot>; template class TLogShuttle<TCyclicDepot>; -} +} diff --git a/library/cpp/lwtrace/log_shuttle.h b/library/cpp/lwtrace/log_shuttle.h index 729a38615f..8c9dc3a587 100644 --- a/library/cpp/lwtrace/log_shuttle.h +++ b/library/cpp/lwtrace/log_shuttle.h @@ -1,160 +1,160 @@ -#pragma once - -#include "log.h" -#include "probe.h" - +#pragma once + +#include "log.h" +#include "probe.h" + #include <library/cpp/lwtrace/protos/lwtrace.pb.h> #include <util/system/spinlock.h> -namespace NLWTrace { - template <class TDepot> - class TRunLogShuttleActionExecutor; - - //////////////////////////////////////////////////////////////////////////////// - - struct THostTimeCalculator { +namespace NLWTrace { + template <class TDepot> + class TRunLogShuttleActionExecutor; + + //////////////////////////////////////////////////////////////////////////////// + + struct THostTimeCalculator { double K = 0; ui64 B = 0; - THostTimeCalculator() { + THostTimeCalculator() { TInstant now = TInstant::Now(); ui64 tsNow = GetCycleCount(); K = 1000000000 / NHPTimer::GetClockRate(); B = now.NanoSeconds() - K * tsNow; } - ui64 CyclesToEpochNanoseconds(ui64 cycles) const { + ui64 CyclesToEpochNanoseconds(ui64 cycles) const { return K*cycles + B; } - ui64 EpochNanosecondsToCycles(ui64 ns) const { + ui64 EpochNanosecondsToCycles(ui64 ns) const { return (ns - B) / K; } }; - inline ui64 CyclesToEpochNanoseconds(ui64 cycles) { + inline ui64 CyclesToEpochNanoseconds(ui64 cycles) { return Singleton<THostTimeCalculator>()->CyclesToEpochNanoseconds(cycles); } - inline ui64 EpochNanosecondsToCycles(ui64 ns) { + inline ui64 EpochNanosecondsToCycles(ui64 ns) { return Singleton<THostTimeCalculator>()->EpochNanosecondsToCycles(ns); } //////////////////////////////////////////////////////////////////////////////// - template <class TDepot> - class TLogShuttle: public IShuttle { - private: + template <class TDepot> + class TLogShuttle: public IShuttle { + private: using TExecutor = TRunLogShuttleActionExecutor<TDepot>; - TTrackLog TrackLog; + TTrackLog TrackLog; TExecutor* Executor; - bool Ignore = false; - size_t MaxTrackLength; + bool Ignore = false; + size_t MaxTrackLength; TAdaptiveLock Lock; TAtomic ForkFailed = 0; - - public: + + public: explicit TLogShuttle(TExecutor* executor) : IShuttle(executor->GetTraceIdx(), executor->NewSpanId()) , Executor(executor) , MaxTrackLength(Executor->GetAction().GetMaxTrackLength() ? Executor->GetAction().GetMaxTrackLength() : 100) - { - } - + { + } + bool DoAddProbe(TProbe* probe, const TParams& params, ui64 timestamp) override; - void DoEndOfTrack() override; - void DoDrop() override; + void DoEndOfTrack() override; + void DoDrop() override; void DoSerialize(TShuttleTrace& msg) override; - bool DoFork(TShuttlePtr& child) override; + bool DoFork(TShuttlePtr& child) override; bool DoJoin(const TShuttlePtr& child) override; - - void SetIgnore(bool ignore); - void Clear(); - - const TTrackLog& GetTrackLog() const { - return TrackLog; - } - }; - - //////////////////////////////////////////////////////////////////////////////// - - template <class TDepot> - class TLogShuttleActionBase: public IExecutor { - private: - const ui64 TraceIdx; - - public: - explicit TLogShuttleActionBase(ui64 traceIdx) - : TraceIdx(traceIdx) - { - } - ui64 GetTraceIdx() const { - return TraceIdx; - } - - static TLogShuttle<TDepot>* Cast(const TShuttlePtr& shuttle); - static TLogShuttle<TDepot>* Cast(IShuttle* shuttle); - }; - - //////////////////////////////////////////////////////////////////////////////// - - template <class TDepot> - class TRunLogShuttleActionExecutor: public TLogShuttleActionBase<TDepot> { - private: - TSpinLock Lock; - TVector<TShuttlePtr> AllShuttles; - TVector<TShuttlePtr> Parking; - TRunLogShuttleAction Action; - TDepot* Depot; - - TAtomic MissedTracks = 0; - TAtomic* LastTrackId; + + void SetIgnore(bool ignore); + void Clear(); + + const TTrackLog& GetTrackLog() const { + return TrackLog; + } + }; + + //////////////////////////////////////////////////////////////////////////////// + + template <class TDepot> + class TLogShuttleActionBase: public IExecutor { + private: + const ui64 TraceIdx; + + public: + explicit TLogShuttleActionBase(ui64 traceIdx) + : TraceIdx(traceIdx) + { + } + ui64 GetTraceIdx() const { + return TraceIdx; + } + + static TLogShuttle<TDepot>* Cast(const TShuttlePtr& shuttle); + static TLogShuttle<TDepot>* Cast(IShuttle* shuttle); + }; + + //////////////////////////////////////////////////////////////////////////////// + + template <class TDepot> + class TRunLogShuttleActionExecutor: public TLogShuttleActionBase<TDepot> { + private: + TSpinLock Lock; + TVector<TShuttlePtr> AllShuttles; + TVector<TShuttlePtr> Parking; + TRunLogShuttleAction Action; + TDepot* Depot; + + TAtomic MissedTracks = 0; + TAtomic* LastTrackId; TAtomic* LastSpanId; - - static constexpr int MaxShuttles = 100000; - - public: + + static constexpr int MaxShuttles = 100000; + + public: TRunLogShuttleActionExecutor(ui64 traceIdx, const TRunLogShuttleAction& action, TDepot* depot, TAtomic* lastTrackId, TAtomic* lastSpanId); - ~TRunLogShuttleActionExecutor(); - bool DoExecute(TOrbit& orbit, const TParams& params) override; - void RecordShuttle(TLogShuttle<TDepot>* shuttle); - void ParkShuttle(TLogShuttle<TDepot>* shuttle); + ~TRunLogShuttleActionExecutor(); + bool DoExecute(TOrbit& orbit, const TParams& params) override; + void RecordShuttle(TLogShuttle<TDepot>* shuttle); + void ParkShuttle(TLogShuttle<TDepot>* shuttle); void DiscardShuttle(); TShuttlePtr RentShuttle(); ui64 NewSpanId(); - const TRunLogShuttleAction& GetAction() const { - return Action; - } - }; - - //////////////////////////////////////////////////////////////////////////////// - - template <class TDepot> - class TEditLogShuttleActionExecutor: public TLogShuttleActionBase<TDepot> { - private: - TEditLogShuttleAction Action; - - public: - TEditLogShuttleActionExecutor(ui64 traceIdx, const TEditLogShuttleAction& action); - bool DoExecute(TOrbit& orbit, const TParams& params) override; - }; - - //////////////////////////////////////////////////////////////////////////////// - - template <class TDepot> - class TDropLogShuttleActionExecutor: public TLogShuttleActionBase<TDepot> { - private: - TDropLogShuttleAction Action; - - public: - TDropLogShuttleActionExecutor(ui64 traceIdx, const TDropLogShuttleAction& action); - bool DoExecute(TOrbit& orbit, const TParams& params) override; - }; - - //////////////////////////////////////////////////////////////////////////////// - - template <class TDepot> + const TRunLogShuttleAction& GetAction() const { + return Action; + } + }; + + //////////////////////////////////////////////////////////////////////////////// + + template <class TDepot> + class TEditLogShuttleActionExecutor: public TLogShuttleActionBase<TDepot> { + private: + TEditLogShuttleAction Action; + + public: + TEditLogShuttleActionExecutor(ui64 traceIdx, const TEditLogShuttleAction& action); + bool DoExecute(TOrbit& orbit, const TParams& params) override; + }; + + //////////////////////////////////////////////////////////////////////////////// + + template <class TDepot> + class TDropLogShuttleActionExecutor: public TLogShuttleActionBase<TDepot> { + private: + TDropLogShuttleAction Action; + + public: + TDropLogShuttleActionExecutor(ui64 traceIdx, const TDropLogShuttleAction& action); + bool DoExecute(TOrbit& orbit, const TParams& params) override; + }; + + //////////////////////////////////////////////////////////////////////////////// + + template <class TDepot> bool TLogShuttle<TDepot>::DoAddProbe(TProbe* probe, const TParams& params, ui64 timestamp) { with_lock (Lock) { if (TrackLog.Items.size() >= MaxTrackLength) { @@ -169,41 +169,41 @@ namespace NLWTrace { probe->Event.Signature.CloneParams(item->Params, params); } item->TimestampCycles = timestamp ? timestamp : GetCycleCount(); - } - - return true; - } - - template <class TDepot> - void TLogShuttle<TDepot>::DoEndOfTrack() { - // Record track log if not ignored - if (!Ignore) { + } + + return true; + } + + template <class TDepot> + void TLogShuttle<TDepot>::DoEndOfTrack() { + // Record track log if not ignored + if (!Ignore) { if (AtomicGet(ForkFailed)) { Executor->DiscardShuttle(); } else { Executor->RecordShuttle(this); } - } + } Executor->ParkShuttle(this); - } - - template <class TDepot> - void TLogShuttle<TDepot>::DoDrop() { - // Do not track log results of dropped shuttles + } + + template <class TDepot> + void TLogShuttle<TDepot>::DoDrop() { + // Do not track log results of dropped shuttles Executor->ParkShuttle(this); - } - - template <class TDepot> - void TLogShuttle<TDepot>::SetIgnore(bool ignore) { - Ignore = ignore; - } - - template <class TDepot> - void TLogShuttle<TDepot>::Clear() { - TrackLog.Clear(); - } - - template <class TDepot> + } + + template <class TDepot> + void TLogShuttle<TDepot>::SetIgnore(bool ignore) { + Ignore = ignore; + } + + template <class TDepot> + void TLogShuttle<TDepot>::Clear() { + TrackLog.Clear(); + } + + template <class TDepot> void TLogShuttle<TDepot>::DoSerialize(TShuttleTrace& msg) { with_lock (Lock) @@ -223,137 +223,137 @@ namespace NLWTrace { } template <class TDepot> - TLogShuttle<TDepot>* TLogShuttleActionBase<TDepot>::Cast(const TShuttlePtr& shuttle) { - return static_cast<TLogShuttle<TDepot>*>(shuttle.Get()); - } - - template <class TDepot> - TLogShuttle<TDepot>* TLogShuttleActionBase<TDepot>::Cast(IShuttle* shuttle) { - return static_cast<TLogShuttle<TDepot>*>(shuttle); - } - - //////////////////////////////////////////////////////////////////////////////// - - template <class TDepot> - TRunLogShuttleActionExecutor<TDepot>::TRunLogShuttleActionExecutor( - ui64 traceIdx, - const TRunLogShuttleAction& action, - TDepot* depot, + TLogShuttle<TDepot>* TLogShuttleActionBase<TDepot>::Cast(const TShuttlePtr& shuttle) { + return static_cast<TLogShuttle<TDepot>*>(shuttle.Get()); + } + + template <class TDepot> + TLogShuttle<TDepot>* TLogShuttleActionBase<TDepot>::Cast(IShuttle* shuttle) { + return static_cast<TLogShuttle<TDepot>*>(shuttle); + } + + //////////////////////////////////////////////////////////////////////////////// + + template <class TDepot> + TRunLogShuttleActionExecutor<TDepot>::TRunLogShuttleActionExecutor( + ui64 traceIdx, + const TRunLogShuttleAction& action, + TDepot* depot, TAtomic* lastTrackId, TAtomic* lastSpanId) - : TLogShuttleActionBase<TDepot>(traceIdx) - , Action(action) - , Depot(depot) - , LastTrackId(lastTrackId) + : TLogShuttleActionBase<TDepot>(traceIdx) + , Action(action) + , Depot(depot) + , LastTrackId(lastTrackId) , LastSpanId(lastSpanId) - { + { ui64 size = Min<ui64>(Action.GetShuttlesCount() ? Action.GetShuttlesCount() : 1000, MaxShuttles); // Do not allow to allocate too much memory - AllShuttles.reserve(size); - Parking.reserve(size); - for (ui64 i = 0; i < size; i++) { - TShuttlePtr shuttle(new TLogShuttle<TDepot>(this)); - AllShuttles.emplace_back(shuttle); - Parking.emplace_back(shuttle); - } - } - - template <class TDepot> - TRunLogShuttleActionExecutor<TDepot>::~TRunLogShuttleActionExecutor() { - for (TShuttlePtr& shuttle : AllShuttles) { - shuttle->Kill(); - } - } - - template <class TDepot> - bool TRunLogShuttleActionExecutor<TDepot>::DoExecute(TOrbit& orbit, const TParams& params) { - Y_UNUSED(params); - if (TShuttlePtr shuttle = RentShuttle()) { - this->Cast(shuttle)->SetIgnore(Action.GetIgnore()); - orbit.AddShuttle(shuttle); - } else { - AtomicIncrement(MissedTracks); - } - return true; - } - - template <class TDepot> + AllShuttles.reserve(size); + Parking.reserve(size); + for (ui64 i = 0; i < size; i++) { + TShuttlePtr shuttle(new TLogShuttle<TDepot>(this)); + AllShuttles.emplace_back(shuttle); + Parking.emplace_back(shuttle); + } + } + + template <class TDepot> + TRunLogShuttleActionExecutor<TDepot>::~TRunLogShuttleActionExecutor() { + for (TShuttlePtr& shuttle : AllShuttles) { + shuttle->Kill(); + } + } + + template <class TDepot> + bool TRunLogShuttleActionExecutor<TDepot>::DoExecute(TOrbit& orbit, const TParams& params) { + Y_UNUSED(params); + if (TShuttlePtr shuttle = RentShuttle()) { + this->Cast(shuttle)->SetIgnore(Action.GetIgnore()); + orbit.AddShuttle(shuttle); + } else { + AtomicIncrement(MissedTracks); + } + return true; + } + + template <class TDepot> void TRunLogShuttleActionExecutor<TDepot>::DiscardShuttle() { AtomicIncrement(MissedTracks); } template <class TDepot> - void TRunLogShuttleActionExecutor<TDepot>::RecordShuttle(TLogShuttle<TDepot>* shuttle) { + void TRunLogShuttleActionExecutor<TDepot>::RecordShuttle(TLogShuttle<TDepot>* shuttle) { if (Depot == nullptr) { return; } - typename TDepot::TAccessor a(*Depot); - if (TTrackLog* trackLog = a.Add()) { - *trackLog = shuttle->GetTrackLog(); - trackLog->Id = AtomicIncrement(*LastTrackId); // Track id is assigned at reporting time - } - } - - template <class TDepot> - TShuttlePtr TRunLogShuttleActionExecutor<TDepot>::RentShuttle() { - TGuard<TSpinLock> g(Lock); - if (Parking.empty()) { - return TShuttlePtr(); - } else { - TShuttlePtr shuttle = Parking.back(); - Parking.pop_back(); - return shuttle; - } - } - - template <class TDepot> - void TRunLogShuttleActionExecutor<TDepot>::ParkShuttle(TLogShuttle<TDepot>* shuttle) { - shuttle->Clear(); - TGuard<TSpinLock> g(Lock); - Parking.emplace_back(shuttle); - } - + typename TDepot::TAccessor a(*Depot); + if (TTrackLog* trackLog = a.Add()) { + *trackLog = shuttle->GetTrackLog(); + trackLog->Id = AtomicIncrement(*LastTrackId); // Track id is assigned at reporting time + } + } + + template <class TDepot> + TShuttlePtr TRunLogShuttleActionExecutor<TDepot>::RentShuttle() { + TGuard<TSpinLock> g(Lock); + if (Parking.empty()) { + return TShuttlePtr(); + } else { + TShuttlePtr shuttle = Parking.back(); + Parking.pop_back(); + return shuttle; + } + } + + template <class TDepot> + void TRunLogShuttleActionExecutor<TDepot>::ParkShuttle(TLogShuttle<TDepot>* shuttle) { + shuttle->Clear(); + TGuard<TSpinLock> g(Lock); + Parking.emplace_back(shuttle); + } + template <class TDepot> ui64 TRunLogShuttleActionExecutor<TDepot>::NewSpanId() { return LastSpanId ? AtomicIncrement(*LastSpanId) : 0; } - //////////////////////////////////////////////////////////////////////////////// - - template <class TDepot> - TEditLogShuttleActionExecutor<TDepot>::TEditLogShuttleActionExecutor(ui64 traceIdx, const TEditLogShuttleAction& action) - : TLogShuttleActionBase<TDepot>(traceIdx) - , Action(action) - { - } - - template <class TDepot> - bool TEditLogShuttleActionExecutor<TDepot>::DoExecute(TOrbit& orbit, const TParams& params) { - Y_UNUSED(params); - bool ignore = Action.GetIgnore(); - orbit.ForEachShuttle(this->GetTraceIdx(), [=](IShuttle* shuttle) { - this->Cast(shuttle)->SetIgnore(ignore); - return true; - }); - return true; - } - - //////////////////////////////////////////////////////////////////////////////// - - template <class TDepot> - TDropLogShuttleActionExecutor<TDepot>::TDropLogShuttleActionExecutor(ui64 traceIdx, const TDropLogShuttleAction& action) - : TLogShuttleActionBase<TDepot>(traceIdx) - , Action(action) - { - } - - template <class TDepot> - bool TDropLogShuttleActionExecutor<TDepot>::DoExecute(TOrbit& orbit, const TParams& params) { - Y_UNUSED(params); - orbit.ForEachShuttle(this->GetTraceIdx(), [](IShuttle*) { - return false; // Erase shuttle from orbit - }); - return true; - } - -} + //////////////////////////////////////////////////////////////////////////////// + + template <class TDepot> + TEditLogShuttleActionExecutor<TDepot>::TEditLogShuttleActionExecutor(ui64 traceIdx, const TEditLogShuttleAction& action) + : TLogShuttleActionBase<TDepot>(traceIdx) + , Action(action) + { + } + + template <class TDepot> + bool TEditLogShuttleActionExecutor<TDepot>::DoExecute(TOrbit& orbit, const TParams& params) { + Y_UNUSED(params); + bool ignore = Action.GetIgnore(); + orbit.ForEachShuttle(this->GetTraceIdx(), [=](IShuttle* shuttle) { + this->Cast(shuttle)->SetIgnore(ignore); + return true; + }); + return true; + } + + //////////////////////////////////////////////////////////////////////////////// + + template <class TDepot> + TDropLogShuttleActionExecutor<TDepot>::TDropLogShuttleActionExecutor(ui64 traceIdx, const TDropLogShuttleAction& action) + : TLogShuttleActionBase<TDepot>(traceIdx) + , Action(action) + { + } + + template <class TDepot> + bool TDropLogShuttleActionExecutor<TDepot>::DoExecute(TOrbit& orbit, const TParams& params) { + Y_UNUSED(params); + orbit.ForEachShuttle(this->GetTraceIdx(), [](IShuttle*) { + return false; // Erase shuttle from orbit + }); + return true; + } + +} diff --git a/library/cpp/lwtrace/lwprobe.h b/library/cpp/lwtrace/lwprobe.h index 801fc3861b..9149bb8519 100644 --- a/library/cpp/lwtrace/lwprobe.h +++ b/library/cpp/lwtrace/lwprobe.h @@ -1,110 +1,110 @@ -#pragma once - +#pragma once + #include "control.h" #include "probe.h" -#include <ctype.h> - -namespace NLWTrace { -#ifndef LWTRACE_DISABLE - - // Box that holds dynamically created probe - // NOTE: must be allocated on heap - template <LWTRACE_TEMPLATE_PARAMS> - class TLWProbe: public IBox, public TUserProbe<LWTRACE_TEMPLATE_ARGS> { - private: - // Storage for strings referenced by TEvent - TString Name; - TString Provider; - TVector<TString> Groups; - TVector<TString> Params; - TVector<TProbeRegistry*> Registries; // Note that we assume that registry lives longer than probe - - public: - TLWProbe(const TString& provider, const TString& name, const TVector<TString>& groups, const TVector<TString>& params) - : IBox(true) - , Name(name) - , Provider(provider) - , Groups(groups) - , Params(params) - { - // initialize TProbe - TProbe& probe = this->Probe; - probe.Init(); - - // initialize TEvent +#include <ctype.h> + +namespace NLWTrace { +#ifndef LWTRACE_DISABLE + + // Box that holds dynamically created probe + // NOTE: must be allocated on heap + template <LWTRACE_TEMPLATE_PARAMS> + class TLWProbe: public IBox, public TUserProbe<LWTRACE_TEMPLATE_ARGS> { + private: + // Storage for strings referenced by TEvent + TString Name; + TString Provider; + TVector<TString> Groups; + TVector<TString> Params; + TVector<TProbeRegistry*> Registries; // Note that we assume that registry lives longer than probe + + public: + TLWProbe(const TString& provider, const TString& name, const TVector<TString>& groups, const TVector<TString>& params) + : IBox(true) + , Name(name) + , Provider(provider) + , Groups(groups) + , Params(params) + { + // initialize TProbe + TProbe& probe = this->Probe; + probe.Init(); + + // initialize TEvent Y_VERIFY(IsCppIdentifier(Name), "probe '%s' is not C++ identifier", Name.data()); Y_VERIFY(IsCppIdentifier(Provider), "provider '%s' is not C++ identifier in probe %s", Provider.data(), Name.data()); - probe.Event.Name = Name.c_str(); - Zero(probe.Event.Groups); - probe.Event.Groups[0] = Provider.c_str(); - auto i = Groups.begin(), ie = Groups.end(); + probe.Event.Name = Name.c_str(); + Zero(probe.Event.Groups); + probe.Event.Groups[0] = Provider.c_str(); + auto i = Groups.begin(), ie = Groups.end(); Y_VERIFY(Groups.size() < LWTRACE_MAX_GROUPS, "too many groups in probe %s", Name.data()); - for (size_t n = 1; n < LWTRACE_MAX_GROUPS && i != ie; n++, ++i) { + for (size_t n = 1; n < LWTRACE_MAX_GROUPS && i != ie; n++, ++i) { Y_VERIFY(IsCppIdentifier(*i), "group '%s' is not C++ identifier in probe %s", i->data(), Name.data()); - probe.Event.Groups[n] = i->c_str(); - } - - // initialize TSignature - using TUsrSign = TUserSignature<LWTRACE_TEMPLATE_ARGS>; - Y_VERIFY(TUsrSign::ParamCount == (int)Params.size(), "param count mismatch in probe %s: %d != %d", + probe.Event.Groups[n] = i->c_str(); + } + + // initialize TSignature + using TUsrSign = TUserSignature<LWTRACE_TEMPLATE_ARGS>; + Y_VERIFY(TUsrSign::ParamCount == (int)Params.size(), "param count mismatch in probe %s: %d != %d", Name.data(), int(Params.size()), TUsrSign::ParamCount); - TSignature& signature = probe.Event.Signature; - signature.ParamTypes = TUsrSign::ParamTypes; - Zero(signature.ParamNames); - auto j = Params.begin(), je = Params.end(); - for (size_t n = 0; n < LWTRACE_MAX_PARAMS && j != je; n++, ++j) { + TSignature& signature = probe.Event.Signature; + signature.ParamTypes = TUsrSign::ParamTypes; + Zero(signature.ParamNames); + auto j = Params.begin(), je = Params.end(); + for (size_t n = 0; n < LWTRACE_MAX_PARAMS && j != je; n++, ++j) { Y_VERIFY(IsCppIdentifier(*j), "param '%s' is not C++ identifier in probe %s", j->data(), Name.data()); - signature.ParamNames[n] = j->c_str(); - } - signature.ParamCount = TUsrSign::ParamCount; - signature.SerializeParamsFunc = &TUsrSign::SerializeParams; - signature.CloneParamsFunc = &TUsrSign::CloneParams; - signature.DestroyParamsFunc = &TUsrSign::DestroyParams; + signature.ParamNames[n] = j->c_str(); + } + signature.ParamCount = TUsrSign::ParamCount; + signature.SerializeParamsFunc = &TUsrSign::SerializeParams; + signature.CloneParamsFunc = &TUsrSign::CloneParams; + signature.DestroyParamsFunc = &TUsrSign::DestroyParams; signature.SerializeToPbFunc = &TUsrSign::SerializeToPb; signature.DeserializeFromPbFunc = &TUsrSign::DeserializeFromPb; - - // register probe in global registry - Register(*Singleton<NLWTrace::TProbeRegistry>()); - } - - ~TLWProbe() { - Unregister(); - } - - void Register(TProbeRegistry& reg) { - Registries.push_back(®); - reg.AddProbe(TBoxPtr(this)); // NOTE: implied `this' object is created with new operator - } - - void Unregister() { - // TODO[serxa]: make sure registry never dies before probe it contain - // TODO[serxa]: make sure probe never dies before TSession that uses it - for (TProbeRegistry* reg : Registries) { - reg->RemoveProbe(&this->Probe); - } - } - - TProbe* GetProbe() override { - return &this->Probe; - } - - private: - static bool IsCppIdentifier(const TString& str) { - bool first = true; - for (char c : str) { - if (first) { - first = false; - if (!(isalpha(c) || c == '_')) { - return false; - } - } else if (!(isalnum(c) || c == '_')) { - return false; - } - } - return true; - } - }; - -#endif -} + + // register probe in global registry + Register(*Singleton<NLWTrace::TProbeRegistry>()); + } + + ~TLWProbe() { + Unregister(); + } + + void Register(TProbeRegistry& reg) { + Registries.push_back(®); + reg.AddProbe(TBoxPtr(this)); // NOTE: implied `this' object is created with new operator + } + + void Unregister() { + // TODO[serxa]: make sure registry never dies before probe it contain + // TODO[serxa]: make sure probe never dies before TSession that uses it + for (TProbeRegistry* reg : Registries) { + reg->RemoveProbe(&this->Probe); + } + } + + TProbe* GetProbe() override { + return &this->Probe; + } + + private: + static bool IsCppIdentifier(const TString& str) { + bool first = true; + for (char c : str) { + if (first) { + first = false; + if (!(isalpha(c) || c == '_')) { + return false; + } + } else if (!(isalnum(c) || c == '_')) { + return false; + } + } + return true; + } + }; + +#endif +} diff --git a/library/cpp/lwtrace/mon/analytics/all.h b/library/cpp/lwtrace/mon/analytics/all.h index 02ddfb83f2..93c8b950ca 100644 --- a/library/cpp/lwtrace/mon/analytics/all.h +++ b/library/cpp/lwtrace/mon/analytics/all.h @@ -1,5 +1,5 @@ -#pragma once - +#pragma once + #include "csv_output.h" #include "data.h" #include "html_output.h" diff --git a/library/cpp/lwtrace/mon/analytics/analytics.cpp b/library/cpp/lwtrace/mon/analytics/analytics.cpp index 1b25263386..107c939f15 100644 --- a/library/cpp/lwtrace/mon/analytics/analytics.cpp +++ b/library/cpp/lwtrace/mon/analytics/analytics.cpp @@ -1,5 +1,5 @@ -#include "all.h" - -namespace NAnalytics { - -} +#include "all.h" + +namespace NAnalytics { + +} diff --git a/library/cpp/lwtrace/mon/analytics/csv_output.h b/library/cpp/lwtrace/mon/analytics/csv_output.h index 90ded32f5d..7e441d9e3f 100644 --- a/library/cpp/lwtrace/mon/analytics/csv_output.h +++ b/library/cpp/lwtrace/mon/analytics/csv_output.h @@ -1,52 +1,52 @@ -#pragma once - -#include <util/string/printf.h> -#include <util/stream/str.h> -#include <util/generic/set.h> +#pragma once + +#include <util/string/printf.h> +#include <util/stream/str.h> +#include <util/generic/set.h> #include "data.h" - -namespace NAnalytics { - + +namespace NAnalytics { + inline TString ToCsv(const TTable& in, TString sep = TString("\t"), bool head = true) -{ +{ TSet<TString> cols; - bool hasName = false; - for (const TRow& row : in) { - hasName = hasName || !row.Name.empty(); - for (const auto& kv : row) { - cols.insert(kv.first); - } - } - - TStringStream ss; - if (head) { - bool first = true; - if (hasName) { + bool hasName = false; + for (const TRow& row : in) { + hasName = hasName || !row.Name.empty(); + for (const auto& kv : row) { + cols.insert(kv.first); + } + } + + TStringStream ss; + if (head) { + bool first = true; + if (hasName) { ss << (first? TString(): sep) << "Name"; - first = false; - } + first = false; + } for (const TString& c : cols) { ss << (first? TString(): sep) << c; - first = false; - } - ss << Endl; - } - - for (const TRow& row : in) { - bool first = true; - if (hasName) { + first = false; + } + ss << Endl; + } + + for (const TRow& row : in) { + bool first = true; + if (hasName) { ss << (first? TString(): sep) << row.Name; - first = false; - } + first = false; + } for (const TString& c : cols) { ss << (first? TString(): sep); - first = false; + first = false; TString value; ss << (row.GetAsString(c, value) ? value : TString("-")); - } - ss << Endl; - } - return ss.Str(); -} - -} + } + ss << Endl; + } + return ss.Str(); +} + +} diff --git a/library/cpp/lwtrace/mon/analytics/data.h b/library/cpp/lwtrace/mon/analytics/data.h index 4b643fe20b..7aeedbdd5e 100644 --- a/library/cpp/lwtrace/mon/analytics/data.h +++ b/library/cpp/lwtrace/mon/analytics/data.h @@ -1,15 +1,15 @@ -#pragma once - +#pragma once + #include <util/generic/string.h> -#include <util/generic/hash.h> +#include <util/generic/hash.h> #include <util/generic/vector.h> #include <util/string/builder.h> #include <util/string/cast.h> - + #include <variant> -namespace NAnalytics { - +namespace NAnalytics { + using TRowValue = std::variant<i64, ui64, double, TString>; TString ToString(const TRowValue& val) { @@ -22,7 +22,7 @@ TString ToString(const TRowValue& val) { struct TRow : public THashMap<TString, TRowValue> { TString Name; - + template<typename T> bool Get(const TString& name, T& value) const { if constexpr (std::is_same_v<double, T>) { @@ -30,9 +30,9 @@ struct TRow : public THashMap<TString, TRowValue> { value = 1.0; return true; } - } - auto iter = find(name); - if (iter != end()) { + } + auto iter = find(name); + if (iter != end()) { try { value = std::get<T>(iter->second); return true; @@ -51,58 +51,58 @@ struct TRow : public THashMap<TString, TRowValue> { auto iter = find(name); if (iter != end()) { value = ToString(iter->second); - return true; - } + return true; + } return false; - } -}; - + } +}; + using TAttributes = THashMap<TString, TString>; - + struct TTable : public TVector<TRow> { - TAttributes Attributes; -}; - + TAttributes Attributes; +}; + struct TMatrix : public TVector<double> { - size_t Rows; - size_t Cols; - - explicit TMatrix(size_t rows = 0, size_t cols = 0) + size_t Rows; + size_t Cols; + + explicit TMatrix(size_t rows = 0, size_t cols = 0) : TVector<double>(rows * cols) - , Rows(rows) - , Cols(cols) - {} - - void Reset(size_t rows, size_t cols) - { - Rows = rows; - Cols = cols; - clear(); - resize(rows * cols); - } - - double& Cell(size_t row, size_t col) - { - Y_VERIFY(row < Rows); - Y_VERIFY(col < Cols); - return operator[](row * Cols + col); - } - - double Cell(size_t row, size_t col) const - { - Y_VERIFY(row < Rows); - Y_VERIFY(col < Cols); - return operator[](row * Cols + col); - } - - double CellSum() const - { - double sum = 0.0; - for (double x : *this) { - sum += x; - } - return sum; - } -}; - -} + , Rows(rows) + , Cols(cols) + {} + + void Reset(size_t rows, size_t cols) + { + Rows = rows; + Cols = cols; + clear(); + resize(rows * cols); + } + + double& Cell(size_t row, size_t col) + { + Y_VERIFY(row < Rows); + Y_VERIFY(col < Cols); + return operator[](row * Cols + col); + } + + double Cell(size_t row, size_t col) const + { + Y_VERIFY(row < Rows); + Y_VERIFY(col < Cols); + return operator[](row * Cols + col); + } + + double CellSum() const + { + double sum = 0.0; + for (double x : *this) { + sum += x; + } + return sum; + } +}; + +} diff --git a/library/cpp/lwtrace/mon/analytics/html_output.h b/library/cpp/lwtrace/mon/analytics/html_output.h index f775f216b9..37d9fe3724 100644 --- a/library/cpp/lwtrace/mon/analytics/html_output.h +++ b/library/cpp/lwtrace/mon/analytics/html_output.h @@ -1,86 +1,86 @@ -#pragma once - -#include <util/string/printf.h> -#include <util/stream/str.h> -#include <util/generic/set.h> +#pragma once + +#include <util/string/printf.h> +#include <util/stream/str.h> +#include <util/generic/set.h> #include "data.h" - -namespace NAnalytics { - + +namespace NAnalytics { + inline TString ToHtml(const TTable& in) -{ +{ TSet<TString> cols; - bool hasName = false; - for (const TRow& row : in) { - hasName = hasName || !row.Name.empty(); - for (const auto& kv : row) { - cols.insert(kv.first); - } - } - - TStringStream ss; - ss << "<table>"; - ss << "<thead><tr>"; - if (hasName) { - ss << "<th>Name</th>"; - } + bool hasName = false; + for (const TRow& row : in) { + hasName = hasName || !row.Name.empty(); + for (const auto& kv : row) { + cols.insert(kv.first); + } + } + + TStringStream ss; + ss << "<table>"; + ss << "<thead><tr>"; + if (hasName) { + ss << "<th>Name</th>"; + } for (const TString& c : cols) { - ss << "<th>" << c << "</th>"; - } - ss << "</tr></thead><tbody>"; - - for (const TRow& row : in) { - ss << "<tr>"; - if (hasName) { - ss << "<th>" << row.Name << "</th>"; - } + ss << "<th>" << c << "</th>"; + } + ss << "</tr></thead><tbody>"; + + for (const TRow& row : in) { + ss << "<tr>"; + if (hasName) { + ss << "<th>" << row.Name << "</th>"; + } for (const TString& c : cols) { TString value; ss << "<td>" << (row.GetAsString(c, value) ? value : TString("-")) << "</td>"; - } - ss << "</tr>"; - } - ss << "</tbody></table>"; - - return ss.Str(); -} - + } + ss << "</tr>"; + } + ss << "</tbody></table>"; + + return ss.Str(); +} + inline TString ToTransposedHtml(const TTable& in) -{ +{ TSet<TString> cols; - bool hasName = false; - for (const TRow& row : in) { - hasName = hasName || !row.Name.empty(); - for (const auto& kv : row) { - cols.insert(kv.first); - } - } - - TStringStream ss; - ss << "<table><thead>"; - if (hasName) { - ss << "<tr>"; - ss << "<th>Name</th>"; - for (const TRow& row : in) { - ss << "<th>" << row.Name << "</th>"; - } - ss << "</tr>"; - } - - ss << "</thead><tbody>"; - + bool hasName = false; + for (const TRow& row : in) { + hasName = hasName || !row.Name.empty(); + for (const auto& kv : row) { + cols.insert(kv.first); + } + } + + TStringStream ss; + ss << "<table><thead>"; + if (hasName) { + ss << "<tr>"; + ss << "<th>Name</th>"; + for (const TRow& row : in) { + ss << "<th>" << row.Name << "</th>"; + } + ss << "</tr>"; + } + + ss << "</thead><tbody>"; + for (const TString& c : cols) { - ss << "<tr>"; - ss << "<th>" << c << "</th>"; - for (const TRow& row : in) { + ss << "<tr>"; + ss << "<th>" << c << "</th>"; + for (const TRow& row : in) { TString value; ss << "<td>" << (row.GetAsString(c, value) ? value : TString("-")) << "</td>"; - } - ss << "</tr>"; - } - ss << "</tbody></table>"; - - return ss.Str(); -} - -} + } + ss << "</tr>"; + } + ss << "</tbody></table>"; + + return ss.Str(); +} + +} diff --git a/library/cpp/lwtrace/mon/analytics/json_output.h b/library/cpp/lwtrace/mon/analytics/json_output.h index 189f9802d3..a857ccfa0c 100644 --- a/library/cpp/lwtrace/mon/analytics/json_output.h +++ b/library/cpp/lwtrace/mon/analytics/json_output.h @@ -1,98 +1,98 @@ -#pragma once - -#include <util/string/printf.h> -#include <util/stream/str.h> -#include <util/string/vector.h> -#include <util/generic/set.h> -#include <util/generic/hash_set.h> +#pragma once + +#include <util/string/printf.h> +#include <util/stream/str.h> +#include <util/string/vector.h> +#include <util/generic/set.h> +#include <util/generic/hash_set.h> #include "data.h" #include "util.h" - -namespace NAnalytics { - + +namespace NAnalytics { + inline TString ToJsonFlot(const TTable& in, const TString& xno, const TVector<TString>& ynos, const TString& opts = TString()) -{ - TStringStream ss; - ss << "[ "; - bool first = true; - +{ + TStringStream ss; + ss << "[ "; + bool first = true; + TString xn; THashSet<TString> xopts; - ParseNameAndOpts(xno, xn, xopts); + ParseNameAndOpts(xno, xn, xopts); bool xstack = xopts.contains("stack"); - + for (const TString& yno : ynos) { TString yn; THashSet<TString> yopts; - ParseNameAndOpts(yno, yn, yopts); + ParseNameAndOpts(yno, yn, yopts); bool ystackOpt = yopts.contains("stack"); - - ss << (first? "": ",\n ") << "{ " << opts << (opts? ", ": "") << "\"label\": \"" << yn << "\", \"data\": [ "; - bool first2 = true; + + ss << (first? "": ",\n ") << "{ " << opts << (opts? ", ": "") << "\"label\": \"" << yn << "\", \"data\": [ "; + bool first2 = true; using TPt = std::tuple<double, double, TString>; - std::vector<TPt> pts; - for (const TRow& row : in) { - double x, y; - if (row.Get(xn, x) && row.Get(yn, y)) { - pts.emplace_back(x, y, row.Name); - } - } - - if (xstack) { - std::sort(pts.begin(), pts.end(), [] (const TPt& a, const TPt& b) { - // At first sort by Name, then by x, then by y - return std::make_tuple(std::get<2>(a), std::get<0>(a), std::get<1>(a)) < - std::make_tuple(std::get<2>(b), std::get<0>(b), std::get<1>(b)); - }); - } else { - std::sort(pts.begin(), pts.end()); - } - - double x = 0.0, xsum = 0.0; - double y = 0.0, ysum = 0.0; - for (auto& pt : pts) { - if (xstack) { - x = xsum; - xsum += std::get<0>(pt); - } else { - x = std::get<0>(pt); - } - - if (ystackOpt) { - y = ysum; - ysum += std::get<1>(pt); - } else { - y = std::get<1>(pt); - } - - ss << (first2? "": ", ") << "[" - << Sprintf("%.6lf", Finitize(x)) << ", " // x coordinate - << Sprintf("%.6lf", Finitize(y)) << ", " // y coordinate - << "\"" << std::get<2>(pt) << "\", " // label - << Sprintf("%.6lf", std::get<0>(pt)) << ", " // x label (real value) - << Sprintf("%.6lf", std::get<1>(pt)) // y label (real value) - << "]"; - first2 = false; - } - // Add final point - if (!first2 && (xstack || ystackOpt)) { - if (xstack) - x = xsum; - if (ystackOpt) - y = ysum; - ss << (first2? "": ", ") << "[" - << Sprintf("%.6lf", Finitize(x)) << ", " // x coordinate - << Sprintf("%.6lf", Finitize(y)) << ", " // y coordinate - << "\"\", " - << Sprintf("%.6lf", x) << ", " // x label (real value) - << Sprintf("%.6lf", y) // y label (real value) - << "]"; - } - ss << " ] }"; - first = false; - } - ss << "\n]"; - return ss.Str(); -} - -} + std::vector<TPt> pts; + for (const TRow& row : in) { + double x, y; + if (row.Get(xn, x) && row.Get(yn, y)) { + pts.emplace_back(x, y, row.Name); + } + } + + if (xstack) { + std::sort(pts.begin(), pts.end(), [] (const TPt& a, const TPt& b) { + // At first sort by Name, then by x, then by y + return std::make_tuple(std::get<2>(a), std::get<0>(a), std::get<1>(a)) < + std::make_tuple(std::get<2>(b), std::get<0>(b), std::get<1>(b)); + }); + } else { + std::sort(pts.begin(), pts.end()); + } + + double x = 0.0, xsum = 0.0; + double y = 0.0, ysum = 0.0; + for (auto& pt : pts) { + if (xstack) { + x = xsum; + xsum += std::get<0>(pt); + } else { + x = std::get<0>(pt); + } + + if (ystackOpt) { + y = ysum; + ysum += std::get<1>(pt); + } else { + y = std::get<1>(pt); + } + + ss << (first2? "": ", ") << "[" + << Sprintf("%.6lf", Finitize(x)) << ", " // x coordinate + << Sprintf("%.6lf", Finitize(y)) << ", " // y coordinate + << "\"" << std::get<2>(pt) << "\", " // label + << Sprintf("%.6lf", std::get<0>(pt)) << ", " // x label (real value) + << Sprintf("%.6lf", std::get<1>(pt)) // y label (real value) + << "]"; + first2 = false; + } + // Add final point + if (!first2 && (xstack || ystackOpt)) { + if (xstack) + x = xsum; + if (ystackOpt) + y = ysum; + ss << (first2? "": ", ") << "[" + << Sprintf("%.6lf", Finitize(x)) << ", " // x coordinate + << Sprintf("%.6lf", Finitize(y)) << ", " // y coordinate + << "\"\", " + << Sprintf("%.6lf", x) << ", " // x label (real value) + << Sprintf("%.6lf", y) // y label (real value) + << "]"; + } + ss << " ] }"; + first = false; + } + ss << "\n]"; + return ss.Str(); +} + +} diff --git a/library/cpp/lwtrace/mon/analytics/transform.h b/library/cpp/lwtrace/mon/analytics/transform.h index f7dc9adb5b..bd80d49d35 100644 --- a/library/cpp/lwtrace/mon/analytics/transform.h +++ b/library/cpp/lwtrace/mon/analytics/transform.h @@ -1,204 +1,204 @@ -#pragma once - +#pragma once + #include "data.h" - -namespace NAnalytics { - -template <class TSkip, class TX, class TY> -inline TTable Histogram(const TTable& in, TSkip skip, + +namespace NAnalytics { + +template <class TSkip, class TX, class TY> +inline TTable Histogram(const TTable& in, TSkip skip, const TString& xn_out, TX x_in, const TString& yn_out, TY y_in, - double x1, double x2, double dx) -{ - long buckets = (x2 - x1) / dx; - TTable out; + double x1, double x2, double dx) +{ + long buckets = (x2 - x1) / dx; + TTable out; TString yn_sum = yn_out + "_sum"; TString yn_share = yn_out + "_share"; - double ysum = 0.0; - out.resize(buckets); - for (size_t i = 0; i < out.size(); i++) { - double lb = x1 + dx*i; - double ub = lb + dx; - out[i].Name = "[" + ToString(lb) + ";" + ToString(ub) + (ub==x2? "]": ")"); - out[i][xn_out] = (lb + ub) / 2; - out[i][yn_sum] = 0.0; - } - for (const auto& row : in) { - if (skip(row)) { - continue; - } - double x = x_in(row); - long i = (x - x1) / dx; - if (x == x2) { // Special hack to include right edge - i--; - } - double y = y_in(row); - ysum += y; - if (i >= 0 && i < buckets) { + double ysum = 0.0; + out.resize(buckets); + for (size_t i = 0; i < out.size(); i++) { + double lb = x1 + dx*i; + double ub = lb + dx; + out[i].Name = "[" + ToString(lb) + ";" + ToString(ub) + (ub==x2? "]": ")"); + out[i][xn_out] = (lb + ub) / 2; + out[i][yn_sum] = 0.0; + } + for (const auto& row : in) { + if (skip(row)) { + continue; + } + double x = x_in(row); + long i = (x - x1) / dx; + if (x == x2) { // Special hack to include right edge + i--; + } + double y = y_in(row); + ysum += y; + if (i >= 0 && i < buckets) { out[i][yn_sum] = y + out[i].GetOrDefault(yn_sum, 0.0); - } - } - for (TRow& row : out) { - if (ysum != 0.0) { + } + } + for (TRow& row : out) { + if (ysum != 0.0) { row[yn_share] = row.GetOrDefault(yn_sum, 0.0) / ysum; - } - } - return out; -} - + } + } + return out; +} + inline TTable HistogramAll(const TTable& in, const TString& xn, double x1, double x2, double dx) -{ - long buckets = (dx == 0.0? 1: (x2 - x1) / dx); - TTable out; +{ + long buckets = (dx == 0.0? 1: (x2 - x1) / dx); + TTable out; THashMap<TString, double> colSum; - out.resize(buckets); - + out.resize(buckets); + TSet<TString> cols; - for (auto& row : in) { - for (auto& kv : row) { - cols.insert(kv.first); - } - } - cols.insert("_count"); - cols.erase(xn); - + for (auto& row : in) { + for (auto& kv : row) { + cols.insert(kv.first); + } + } + cols.insert("_count"); + cols.erase(xn); + for (const TString& col : cols) { - colSum[col] = 0.0; - } - - for (size_t i = 0; i < out.size(); i++) { - double lb = x1 + dx*i; - double ub = lb + dx; - TRow& row = out[i]; - row.Name = "[" + ToString(lb) + ";" + ToString(ub) + (ub==x2? "]": ")"); - row[xn] = (lb + ub) / 2; + colSum[col] = 0.0; + } + + for (size_t i = 0; i < out.size(); i++) { + double lb = x1 + dx*i; + double ub = lb + dx; + TRow& row = out[i]; + row.Name = "[" + ToString(lb) + ";" + ToString(ub) + (ub==x2? "]": ")"); + row[xn] = (lb + ub) / 2; for (const TString& col : cols) { - row[col + "_sum"] = 0.0; - } - } - for (const TRow& row_in : in) { - double x; - if (!row_in.Get(xn, x)) { - continue; - } - long i = (dx == 0.0? 0: (x - x1) / dx); - if (x == x2 && dx > 0.0) { // Special hack to include right edge - i--; - } - for (const auto& kv : row_in) { + row[col + "_sum"] = 0.0; + } + } + for (const TRow& row_in : in) { + double x; + if (!row_in.Get(xn, x)) { + continue; + } + long i = (dx == 0.0? 0: (x - x1) / dx); + if (x == x2 && dx > 0.0) { // Special hack to include right edge + i--; + } + for (const auto& kv : row_in) { const TString& yn = kv.first; - if (yn == xn) { - continue; - } + if (yn == xn) { + continue; + } double y; if (!row_in.Get(yn, y)) { continue; } - colSum[yn] += y; - if (i >= 0 && i < buckets) { + colSum[yn] += y; + if (i >= 0 && i < buckets) { out[i][yn + "_cnt"] = out[i].GetOrDefault(yn + "_cnt") + 1; out[i][yn + "_sum"] = out[i].GetOrDefault(yn + "_sum") + y; if (out[i].contains(yn + "_min")) { out[i][yn + "_min"] = Min(y, out[i].GetOrDefault(yn + "_min")); - } else { - out[i][yn + "_min"] = y; - } + } else { + out[i][yn + "_min"] = y; + } if (out[i].contains(yn + "_max")) { out[i][yn + "_max"] = Max(y, out[i].GetOrDefault(yn + "_max")); - } else { - out[i][yn + "_max"] = y; - } - } - } - colSum["_count"]++; - if (i >= 0 && i < buckets) { + } else { + out[i][yn + "_max"] = y; + } + } + } + colSum["_count"]++; + if (i >= 0 && i < buckets) { out[i]["_count_sum"] = out[i].GetOrDefault("_count_sum") + 1; - } - } - for (TRow& row : out) { + } + } + for (TRow& row : out) { for (const TString& col : cols) { - double ysum = colSum[col]; - if (col != "_count") { + double ysum = colSum[col]; + if (col != "_count") { if (row.GetOrDefault(col + "_cnt") != 0.0) { row[col + "_avg"] = row.GetOrDefault(col + "_sum") / row.GetOrDefault(col + "_cnt"); - } - } - if (ysum != 0.0) { + } + } + if (ysum != 0.0) { row[col + "_share"] = row.GetOrDefault(col + "_sum") / ysum; - } - } - } - return out; -} - -inline TMatrix CovarianceMatrix(const TTable& in) -{ + } + } + } + return out; +} + +inline TMatrix CovarianceMatrix(const TTable& in) +{ TSet<TString> cols; - for (auto& row : in) { - for (auto& kv : row) { - cols.insert(kv.first); - } - } - - struct TAggregate { - size_t Idx = 0; - double Sum = 0; - size_t Count = 0; - double Mean = 0; - }; - + for (auto& row : in) { + for (auto& kv : row) { + cols.insert(kv.first); + } + } + + struct TAggregate { + size_t Idx = 0; + double Sum = 0; + size_t Count = 0; + double Mean = 0; + }; + THashMap<TString, TAggregate> colAggr; - - size_t colCount = 0; - for (const TString& col : cols) { - TAggregate& aggr = colAggr[col]; - aggr.Idx = colCount++; - } - - for (const TRow& row : in) { - for (const auto& kv : row) { - const TString& xn = kv.first; + + size_t colCount = 0; + for (const TString& col : cols) { + TAggregate& aggr = colAggr[col]; + aggr.Idx = colCount++; + } + + for (const TRow& row : in) { + for (const auto& kv : row) { + const TString& xn = kv.first; double x; if (!row.Get(xn, x)) { continue; } - TAggregate& aggr = colAggr[xn]; - aggr.Sum += x; - aggr.Count++; - } - } - - for (auto& kv : colAggr) { - TAggregate& aggr = kv.second; - aggr.Mean = aggr.Sum / aggr.Count; - } - - TMatrix covCount(cols.size(), cols.size()); - TMatrix cov(cols.size(), cols.size()); - for (const TRow& row : in) { - for (const auto& kv1 : row) { + TAggregate& aggr = colAggr[xn]; + aggr.Sum += x; + aggr.Count++; + } + } + + for (auto& kv : colAggr) { + TAggregate& aggr = kv.second; + aggr.Mean = aggr.Sum / aggr.Count; + } + + TMatrix covCount(cols.size(), cols.size()); + TMatrix cov(cols.size(), cols.size()); + for (const TRow& row : in) { + for (const auto& kv1 : row) { double x; if (!row.Get(kv1.first, x)) { continue; } - TAggregate& xaggr = colAggr[kv1.first]; - for (const auto& kv2 : row) { + TAggregate& xaggr = colAggr[kv1.first]; + for (const auto& kv2 : row) { double y; if (!row.Get(kv2.first, y)) { continue; } - TAggregate& yaggr = colAggr[kv2.first]; - covCount.Cell(xaggr.Idx, yaggr.Idx)++; - cov.Cell(xaggr.Idx, yaggr.Idx) += (x - xaggr.Mean) * (y - yaggr.Mean); - } - } - } - - for (size_t idx = 0; idx < cov.size(); idx++) { - cov[idx] /= covCount[idx]; - } - - return cov; -} - -} + TAggregate& yaggr = colAggr[kv2.first]; + covCount.Cell(xaggr.Idx, yaggr.Idx)++; + cov.Cell(xaggr.Idx, yaggr.Idx) += (x - xaggr.Mean) * (y - yaggr.Mean); + } + } + } + + for (size_t idx = 0; idx < cov.size(); idx++) { + cov[idx] /= covCount[idx]; + } + + return cov; +} + +} diff --git a/library/cpp/lwtrace/mon/analytics/util.h b/library/cpp/lwtrace/mon/analytics/util.h index e07d06cc43..891ef9ad25 100644 --- a/library/cpp/lwtrace/mon/analytics/util.h +++ b/library/cpp/lwtrace/mon/analytics/util.h @@ -1,122 +1,122 @@ -#pragma once - +#pragma once + #include "data.h" -#include <util/generic/algorithm.h> -#include <util/generic/hash_set.h> -#include <util/string/vector.h> - -namespace NAnalytics { - -// Get rid of NaNs and INFs +#include <util/generic/algorithm.h> +#include <util/generic/hash_set.h> +#include <util/string/vector.h> + +namespace NAnalytics { + +// Get rid of NaNs and INFs inline double Finitize(double x, double notFiniteValue = 0.0) -{ - return isfinite(x)? x: notFiniteValue; -} - +{ + return isfinite(x)? x: notFiniteValue; +} + inline void ParseNameAndOpts(const TString& nameAndOpts, TString& name, THashSet<TString>& opts) -{ - name.clear(); - opts.clear(); - bool first = true; +{ + name.clear(); + opts.clear(); + bool first = true; auto vs = SplitString(nameAndOpts, "-"); - for (const auto& s : vs) { - if (first) { - name = s; - first = false; - } else { - opts.insert(s); - } - } -} - + for (const auto& s : vs) { + if (first) { + name = s; + first = false; + } else { + opts.insert(s); + } + } +} + inline TString ParseName(const TString& nameAndOpts) -{ +{ auto vs = SplitString(nameAndOpts, "-"); - if (vs.empty()) { + if (vs.empty()) { return TString(); - } else { - return vs[0]; - } -} - -template <class R, class T> + } else { + return vs[0]; + } +} + +template <class R, class T> inline R AccumulateIfExist(const TString& name, const TTable& table, R r, T t) -{ - ForEach(table.begin(), table.end(), [=,&r] (const TRow& row) { - double value; - if (row.Get(name, value)) { - r = t(r, value); - } - }); - return r; -} - +{ + ForEach(table.begin(), table.end(), [=,&r] (const TRow& row) { + double value; + if (row.Get(name, value)) { + r = t(r, value); + } + }); + return r; +} + inline double MinValue(const TString& nameAndOpts, const TTable& table) -{ +{ TString name; THashSet<TString> opts; - ParseNameAndOpts(nameAndOpts, name, opts); + ParseNameAndOpts(nameAndOpts, name, opts); bool stack = opts.contains("stack"); - if (stack) { - return 0.0; - } else { + if (stack) { + return 0.0; + } else { auto zero = 0.0; return AccumulateIfExist(name, table, 1.0 / zero /*+inf*/, [] (double x, double y) { - return Min(x, y); - }); - } -} - + return Min(x, y); + }); + } +} + inline double MaxValue(const TString& nameAndOpts, const TTable& table) -{ +{ TString name; THashSet<TString> opts; - ParseNameAndOpts(nameAndOpts, name, opts); + ParseNameAndOpts(nameAndOpts, name, opts); bool stack = opts.contains("stack"); - if (stack) { - return AccumulateIfExist(name, table, 0.0, [] (double x, double y) { - return x + y; - }); - } else { + if (stack) { + return AccumulateIfExist(name, table, 0.0, [] (double x, double y) { + return x + y; + }); + } else { auto zero = 0.0; return AccumulateIfExist(name, table, -1.0 / zero /*-inf*/, [] (double x, double y) { - return Max(x, y); - }); - } -} - -template <class T> + return Max(x, y); + }); + } +} + +template <class T> inline void Map(TTable& table, const TString& rname, T t) -{ - ForEach(table.begin(), table.end(), [=] (TRow& row) { - row[rname] = t(row); - }); -} - +{ + ForEach(table.begin(), table.end(), [=] (TRow& row) { + row[rname] = t(row); + }); +} + inline std::function<bool(const TRow&)> HasNoValueFor(TString name) -{ - return [=] (const TRow& row) -> bool { - double value; - return !row.Get(name, value); - }; -} - - +{ + return [=] (const TRow& row) -> bool { + double value; + return !row.Get(name, value); + }; +} + + inline std::function<double(const TRow&)> GetValueFor(TString name, double defVal = 0.0) -{ - return [=] (const TRow& row) -> double { - double value; - return row.Get(name, value)? value: defVal; - }; -} - -inline std::function<double(const TRow&)> Const(double defVal = 0.0) -{ - return [=] (const TRow&) { - return defVal; - }; -} - -} +{ + return [=] (const TRow& row) -> double { + double value; + return row.Get(name, value)? value: defVal; + }; +} + +inline std::function<double(const TRow&)> Const(double defVal = 0.0) +{ + return [=] (const TRow&) { + return defVal; + }; +} + +} diff --git a/library/cpp/lwtrace/mon/analytics/ya.make b/library/cpp/lwtrace/mon/analytics/ya.make index c18e23c8e1..24a04070b7 100644 --- a/library/cpp/lwtrace/mon/analytics/ya.make +++ b/library/cpp/lwtrace/mon/analytics/ya.make @@ -1,15 +1,15 @@ -LIBRARY() - +LIBRARY() + OWNER(serxa g:kikimr) - + PEERDIR( ) -SRCS( - analytics.cpp -) - -END() - -RECURSE( -) +SRCS( + analytics.cpp +) + +END() + +RECURSE( +) diff --git a/library/cpp/lwtrace/mon/mon_lwtrace.cpp b/library/cpp/lwtrace/mon/mon_lwtrace.cpp index a61ee9ce22..b400103f58 100644 --- a/library/cpp/lwtrace/mon/mon_lwtrace.cpp +++ b/library/cpp/lwtrace/mon/mon_lwtrace.cpp @@ -1,8 +1,8 @@ #include "mon_lwtrace.h" -#include <algorithm> -#include <iterator> - +#include <algorithm> +#include <iterator> + #include <google/protobuf/text_format.h> #include <library/cpp/lwtrace/mon/analytics/all.h> #include <library/cpp/lwtrace/all.h> @@ -12,14 +12,14 @@ #include <library/cpp/resource/resource.h> #include <library/cpp/string_utils/base64/base64.h> #include <library/cpp/html/pcdata/pcdata.h> -#include <util/string/escape.h> -#include <util/system/condvar.h> -#include <util/system/execpath.h> +#include <util/string/escape.h> +#include <util/system/condvar.h> +#include <util/system/execpath.h> #include <util/system/hostname.h> using namespace NMonitoring; -#define WWW_CHECK(cond, ...) \ +#define WWW_CHECK(cond, ...) \ do { \ if (!(cond)) { \ ythrow yexception() << Sprintf(__VA_ARGS__); \ @@ -27,1383 +27,1383 @@ using namespace NMonitoring; } while (false) \ /**/ -#define WWW_HTML_INNER(out) HTML(out) WITH_SCOPED(tmp, TScopedHtmlInner(out)) -#define WWW_HTML(out) out << NMonitoring::HTTPOKHTML; WWW_HTML_INNER(out) - -namespace NLwTraceMonPage { - -struct TTrackLogRefs { - struct TItem { - const TThread::TId ThreadId; - const NLWTrace::TLogItem* Ptr; - - TItem() - : ThreadId(0) - , Ptr(nullptr) - {} - - TItem(TThread::TId tid, const NLWTrace::TLogItem& ref) - : ThreadId(tid) - , Ptr(&ref) - {} - - TItem(const TItem& o) - : ThreadId(o.ThreadId) - , Ptr(o.Ptr) - {} - - operator const NLWTrace::TLogItem&() const { return *Ptr; } - }; - +#define WWW_HTML_INNER(out) HTML(out) WITH_SCOPED(tmp, TScopedHtmlInner(out)) +#define WWW_HTML(out) out << NMonitoring::HTTPOKHTML; WWW_HTML_INNER(out) + +namespace NLwTraceMonPage { + +struct TTrackLogRefs { + struct TItem { + const TThread::TId ThreadId; + const NLWTrace::TLogItem* Ptr; + + TItem() + : ThreadId(0) + , Ptr(nullptr) + {} + + TItem(TThread::TId tid, const NLWTrace::TLogItem& ref) + : ThreadId(tid) + , Ptr(&ref) + {} + + TItem(const TItem& o) + : ThreadId(o.ThreadId) + , Ptr(o.Ptr) + {} + + operator const NLWTrace::TLogItem&() const { return *Ptr; } + }; + using TItems = TVector<TItem>; - TItems Items; - - TTrackLogRefs() {} - - TTrackLogRefs(const TTrackLogRefs& other) - : Items(other.Items) - {} - - void Clear() - { - Items.clear(); - } - - ui64 GetTimestampCycles() const - { - return Items.empty()? 0: Items.front().Ptr->GetTimestampCycles(); - } -}; - -// -// Templates to treat both NLWTrace::TLogItem and NLWTrace::TTrackLog in the same way (e.g. in TLogQuery) -// - -template <class TLog> -struct TLogTraits {}; - -template <> -struct TLogTraits<NLWTrace::TLogItem> { - using TLog = NLWTrace::TLogItem; - using const_iterator = const NLWTrace::TLogItem*; - using const_reverse_iterator = const NLWTrace::TLogItem*; - - static const_iterator begin(const TLog& log) { return &log; } - static const_iterator end(const TLog& log) { return &log + 1; } - static const_reverse_iterator rbegin(const TLog& log) { return &log; } - static const_reverse_iterator rend(const TLog& log) { return &log + 1; } - static bool empty(const TLog&) { return false; } - static const NLWTrace::TLogItem& front(const TLog& log) { return log; } - static const NLWTrace::TLogItem& back(const TLog& log) { return log; } -}; - -template <> -struct TLogTraits<NLWTrace::TTrackLog> { - using TLog = NLWTrace::TTrackLog; - using const_iterator = NLWTrace::TTrackLog::TItems::const_iterator; - using const_reverse_iterator = NLWTrace::TTrackLog::TItems::const_reverse_iterator; - - static const_iterator begin(const TLog& log) { return log.Items.begin(); } - static const_iterator end(const TLog& log) { return log.Items.end(); } - static const_reverse_iterator rbegin(const TLog& log) { return log.Items.rbegin(); } - static const_reverse_iterator rend(const TLog& log) { return log.Items.rend(); } - static bool empty(const TLog& log) { return log.Items.empty(); } - static const NLWTrace::TLogItem& front(const TLog& log) { return log.Items.front(); } - static const NLWTrace::TLogItem& back(const TLog& log) { return log.Items.back(); } -}; - -template <> -struct TLogTraits<TTrackLogRefs> { - using TLog = TTrackLogRefs; - using const_iterator = TTrackLogRefs::TItems::const_iterator; - using const_reverse_iterator = TTrackLogRefs::TItems::const_reverse_iterator; - - static const_iterator begin(const TLog& log) { return log.Items.begin(); } - static const_iterator end(const TLog& log) { return log.Items.end(); } - static const_reverse_iterator rbegin(const TLog& log) { return log.Items.rbegin(); } - static const_reverse_iterator rend(const TLog& log) { return log.Items.rend(); } - static bool empty(const TLog& log) { return log.Items.empty(); } - static const NLWTrace::TLogItem& front(const TLog& log) { return log.Items.front(); } - static const NLWTrace::TLogItem& back(const TLog& log) { return log.Items.back(); } -}; - -/* - * Log Query Language: - * Data expressions: - * 1) myparam[0], myparam[-1] // the first and the last myparam in any probe/provider - * 2) myparam // the first (the same as [0]) - * 3) PROVIDER..myparam // any probe with myparam in PROVIDER - * 4) MyProbe._elapsedMs // Ms since track begin for the first MyProbe event - * 5) PROVIDER.MyProbe._sliceUs // Us since previous event in track for the first PROVIDER.MyProbe event - */ - -struct TLogQuery { -private: - enum ESpecialParam { - NotSpecial = 0, - // The last '*' can be one of: Ms, Us, Ns, Min, Hours, (blank means seconds) - // '*Time' can be one of: RTime (since cut ts for given dataset), NTime (negative time since now), Time (since machine start) - TrackDuration = 1, // _track* - TrackBeginTime = 2, // _begin*Time* - TrackEndTime = 3, // _end*Time* - ElapsedDuration = 4, // _elapsed* - SliceDuration = 5, // _slice* - ThreadTime = 6, // _thr*Time* - }; - - template <class TLog, class TTr = TLogTraits<TLog>> - struct TExecuteQuery; - - template <class TLog, class TTr> - friend struct TExecuteQuery; - - template <class TLog, class TTr> - struct TExecuteQuery { - const TLogQuery& Query; - const TLog* Log = nullptr; - bool Reversed; - - i64 Skip; - const NLWTrace::TLogItem* Item = nullptr; - typename TTr::const_iterator FwdIter; - typename TTr::const_reverse_iterator RevIter; - - NLWTrace::TTypedParam Result; - - explicit TExecuteQuery(const TLogQuery& query, const TLog& log) - : Query(query) - , Log(&log) - , Reversed(Query.Index < 0) - , Skip(Reversed? -Query.Index - 1: Query.Index) - , FwdIter() - , RevIter() - {} - - void ExecuteQuery() - { - if (!Reversed) { - for (auto i = TTr::begin(*Log), e = TTr::end(*Log); i != e; ++i) { - if (FwdIteration(i)) { - return; - } - } - } else { - for (auto i = TTr::rbegin(*Log), e = TTr::rend(*Log); i != e; ++i) { - if (RevIteration(i)) { - return; - } - } - } - } - - bool FwdIteration(typename TTr::const_iterator it) - { - FwdIter = it; - Item = &*it; - return ProcessItem(); - } - - bool RevIteration(typename TTr::const_reverse_iterator it) - { - RevIter = it; - Item = &*it; - return ProcessItem(); - } - - bool ProcessItem() - { - if (Query.Provider && Query.Provider != Item->Probe->Event.GetProvider()) { - return false; - } - if (Query.Probe && Query.Probe != Item->Probe->Event.Name) { - return false; - } - switch (Query.SpecialParam) { - case NotSpecial: - if (Item->Probe->Event.Signature.FindParamIndex(Query.ParamName) != size_t(-1)) { - break; // param found - } else { - return false; // param not found - } - case TrackDuration: Y_FAIL(); - case TrackBeginTime: Y_FAIL(); - case TrackEndTime: Y_FAIL(); - case ElapsedDuration: break; - case SliceDuration: break; - case ThreadTime: break; - } - if (Skip > 0) { - Skip--; - return false; - } - switch (Query.SpecialParam) { - case NotSpecial: - Result = NLWTrace::TTypedParam(Item->GetParam(Query.ParamName)); - return true; - case TrackDuration: Y_FAIL(); - case TrackBeginTime: Y_FAIL(); - case TrackEndTime: Y_FAIL(); - case ElapsedDuration: - Result = NLWTrace::TTypedParam(Query.Duration( - Log->GetTimestampCycles(), - Item->GetTimestampCycles())); - return true; - case SliceDuration: - Result = NLWTrace::TTypedParam(Query.Duration( - PrevOrSame().GetTimestampCycles(), - Item->GetTimestampCycles())); - return true; - case ThreadTime: - Result = NLWTrace::TTypedParam(Query.Instant(Item->GetTimestampCycles())); - return true; - } - return true; - } - - const NLWTrace::TLogItem& PrevOrSame() const - { - if (!Reversed) { - auto i = FwdIter; - if (i != TTr::begin(*Log)) { - i--; - } - return *i; - } else { - auto j = RevIter + 1; - if (j == TTr::rend(*Log)) { - return *RevIter; - } - return *j; - } - } - }; - + TItems Items; + + TTrackLogRefs() {} + + TTrackLogRefs(const TTrackLogRefs& other) + : Items(other.Items) + {} + + void Clear() + { + Items.clear(); + } + + ui64 GetTimestampCycles() const + { + return Items.empty()? 0: Items.front().Ptr->GetTimestampCycles(); + } +}; + +// +// Templates to treat both NLWTrace::TLogItem and NLWTrace::TTrackLog in the same way (e.g. in TLogQuery) +// + +template <class TLog> +struct TLogTraits {}; + +template <> +struct TLogTraits<NLWTrace::TLogItem> { + using TLog = NLWTrace::TLogItem; + using const_iterator = const NLWTrace::TLogItem*; + using const_reverse_iterator = const NLWTrace::TLogItem*; + + static const_iterator begin(const TLog& log) { return &log; } + static const_iterator end(const TLog& log) { return &log + 1; } + static const_reverse_iterator rbegin(const TLog& log) { return &log; } + static const_reverse_iterator rend(const TLog& log) { return &log + 1; } + static bool empty(const TLog&) { return false; } + static const NLWTrace::TLogItem& front(const TLog& log) { return log; } + static const NLWTrace::TLogItem& back(const TLog& log) { return log; } +}; + +template <> +struct TLogTraits<NLWTrace::TTrackLog> { + using TLog = NLWTrace::TTrackLog; + using const_iterator = NLWTrace::TTrackLog::TItems::const_iterator; + using const_reverse_iterator = NLWTrace::TTrackLog::TItems::const_reverse_iterator; + + static const_iterator begin(const TLog& log) { return log.Items.begin(); } + static const_iterator end(const TLog& log) { return log.Items.end(); } + static const_reverse_iterator rbegin(const TLog& log) { return log.Items.rbegin(); } + static const_reverse_iterator rend(const TLog& log) { return log.Items.rend(); } + static bool empty(const TLog& log) { return log.Items.empty(); } + static const NLWTrace::TLogItem& front(const TLog& log) { return log.Items.front(); } + static const NLWTrace::TLogItem& back(const TLog& log) { return log.Items.back(); } +}; + +template <> +struct TLogTraits<TTrackLogRefs> { + using TLog = TTrackLogRefs; + using const_iterator = TTrackLogRefs::TItems::const_iterator; + using const_reverse_iterator = TTrackLogRefs::TItems::const_reverse_iterator; + + static const_iterator begin(const TLog& log) { return log.Items.begin(); } + static const_iterator end(const TLog& log) { return log.Items.end(); } + static const_reverse_iterator rbegin(const TLog& log) { return log.Items.rbegin(); } + static const_reverse_iterator rend(const TLog& log) { return log.Items.rend(); } + static bool empty(const TLog& log) { return log.Items.empty(); } + static const NLWTrace::TLogItem& front(const TLog& log) { return log.Items.front(); } + static const NLWTrace::TLogItem& back(const TLog& log) { return log.Items.back(); } +}; + +/* + * Log Query Language: + * Data expressions: + * 1) myparam[0], myparam[-1] // the first and the last myparam in any probe/provider + * 2) myparam // the first (the same as [0]) + * 3) PROVIDER..myparam // any probe with myparam in PROVIDER + * 4) MyProbe._elapsedMs // Ms since track begin for the first MyProbe event + * 5) PROVIDER.MyProbe._sliceUs // Us since previous event in track for the first PROVIDER.MyProbe event + */ + +struct TLogQuery { +private: + enum ESpecialParam { + NotSpecial = 0, + // The last '*' can be one of: Ms, Us, Ns, Min, Hours, (blank means seconds) + // '*Time' can be one of: RTime (since cut ts for given dataset), NTime (negative time since now), Time (since machine start) + TrackDuration = 1, // _track* + TrackBeginTime = 2, // _begin*Time* + TrackEndTime = 3, // _end*Time* + ElapsedDuration = 4, // _elapsed* + SliceDuration = 5, // _slice* + ThreadTime = 6, // _thr*Time* + }; + + template <class TLog, class TTr = TLogTraits<TLog>> + struct TExecuteQuery; + + template <class TLog, class TTr> + friend struct TExecuteQuery; + + template <class TLog, class TTr> + struct TExecuteQuery { + const TLogQuery& Query; + const TLog* Log = nullptr; + bool Reversed; + + i64 Skip; + const NLWTrace::TLogItem* Item = nullptr; + typename TTr::const_iterator FwdIter; + typename TTr::const_reverse_iterator RevIter; + + NLWTrace::TTypedParam Result; + + explicit TExecuteQuery(const TLogQuery& query, const TLog& log) + : Query(query) + , Log(&log) + , Reversed(Query.Index < 0) + , Skip(Reversed? -Query.Index - 1: Query.Index) + , FwdIter() + , RevIter() + {} + + void ExecuteQuery() + { + if (!Reversed) { + for (auto i = TTr::begin(*Log), e = TTr::end(*Log); i != e; ++i) { + if (FwdIteration(i)) { + return; + } + } + } else { + for (auto i = TTr::rbegin(*Log), e = TTr::rend(*Log); i != e; ++i) { + if (RevIteration(i)) { + return; + } + } + } + } + + bool FwdIteration(typename TTr::const_iterator it) + { + FwdIter = it; + Item = &*it; + return ProcessItem(); + } + + bool RevIteration(typename TTr::const_reverse_iterator it) + { + RevIter = it; + Item = &*it; + return ProcessItem(); + } + + bool ProcessItem() + { + if (Query.Provider && Query.Provider != Item->Probe->Event.GetProvider()) { + return false; + } + if (Query.Probe && Query.Probe != Item->Probe->Event.Name) { + return false; + } + switch (Query.SpecialParam) { + case NotSpecial: + if (Item->Probe->Event.Signature.FindParamIndex(Query.ParamName) != size_t(-1)) { + break; // param found + } else { + return false; // param not found + } + case TrackDuration: Y_FAIL(); + case TrackBeginTime: Y_FAIL(); + case TrackEndTime: Y_FAIL(); + case ElapsedDuration: break; + case SliceDuration: break; + case ThreadTime: break; + } + if (Skip > 0) { + Skip--; + return false; + } + switch (Query.SpecialParam) { + case NotSpecial: + Result = NLWTrace::TTypedParam(Item->GetParam(Query.ParamName)); + return true; + case TrackDuration: Y_FAIL(); + case TrackBeginTime: Y_FAIL(); + case TrackEndTime: Y_FAIL(); + case ElapsedDuration: + Result = NLWTrace::TTypedParam(Query.Duration( + Log->GetTimestampCycles(), + Item->GetTimestampCycles())); + return true; + case SliceDuration: + Result = NLWTrace::TTypedParam(Query.Duration( + PrevOrSame().GetTimestampCycles(), + Item->GetTimestampCycles())); + return true; + case ThreadTime: + Result = NLWTrace::TTypedParam(Query.Instant(Item->GetTimestampCycles())); + return true; + } + return true; + } + + const NLWTrace::TLogItem& PrevOrSame() const + { + if (!Reversed) { + auto i = FwdIter; + if (i != TTr::begin(*Log)) { + i--; + } + return *i; + } else { + auto j = RevIter + 1; + if (j == TTr::rend(*Log)) { + return *RevIter; + } + return *j; + } + } + }; + TString Text; TString Provider; TString Probe; TString ParamName; - ESpecialParam SpecialParam = NotSpecial; - i64 Index = 0; - double TimeUnitSec = 1.0; - i64 ZeroTs = 0; - i64 RTimeZeroTs = 0; - i64 NTimeZeroTs = 0; - -public: - TLogQuery() {} - + ESpecialParam SpecialParam = NotSpecial; + i64 Index = 0; + double TimeUnitSec = 1.0; + i64 ZeroTs = 0; + i64 RTimeZeroTs = 0; + i64 NTimeZeroTs = 0; + +public: + TLogQuery() {} + explicit TLogQuery(const TString& text) - : Text(text) - { - try { - if (!Text.empty()) { - ParseQuery(Text); - } - } catch (...) { - ythrow yexception() - << CurrentExceptionMessage() - << " while parsing track log query: " - << Text; - } - } - - operator bool() const - { - return !Text.empty(); - } - - template <class TLog> - NLWTrace::TTypedParam ExecuteQuery(const TLog& log) const - { - using TTr = TLogTraits<TLog>; - - WWW_CHECK(Text, "execute of empty log query"); - if (TTr::empty(log)) { - return NLWTrace::TTypedParam(); - } - - if (SpecialParam == TrackDuration) { - return Duration( - log.GetTimestampCycles(), - TTr::back(log).GetTimestampCycles()); - } else if (SpecialParam == TrackBeginTime) { - return Instant(log.GetTimestampCycles()); - } else if (SpecialParam == TrackEndTime) { - return Instant(TTr::back(log).GetTimestampCycles()); - } - - TExecuteQuery<TLog, TTr> exec(*this, log); - exec.ExecuteQuery(); - return exec.Result; - } - -private: - NLWTrace::TTypedParam Duration(ui64 ts1, ui64 ts2) const - { - double sec = NHPTimer::GetSeconds(ts1 < ts2? ts2 - ts1: 0); - return NLWTrace::TTypedParam(sec / TimeUnitSec); - } - - NLWTrace::TTypedParam Instant(ui64 ts) const - { - double sec = NHPTimer::GetSeconds(i64(ts) - ZeroTs); - return NLWTrace::TTypedParam(sec / TimeUnitSec); - } - + : Text(text) + { + try { + if (!Text.empty()) { + ParseQuery(Text); + } + } catch (...) { + ythrow yexception() + << CurrentExceptionMessage() + << " while parsing track log query: " + << Text; + } + } + + operator bool() const + { + return !Text.empty(); + } + + template <class TLog> + NLWTrace::TTypedParam ExecuteQuery(const TLog& log) const + { + using TTr = TLogTraits<TLog>; + + WWW_CHECK(Text, "execute of empty log query"); + if (TTr::empty(log)) { + return NLWTrace::TTypedParam(); + } + + if (SpecialParam == TrackDuration) { + return Duration( + log.GetTimestampCycles(), + TTr::back(log).GetTimestampCycles()); + } else if (SpecialParam == TrackBeginTime) { + return Instant(log.GetTimestampCycles()); + } else if (SpecialParam == TrackEndTime) { + return Instant(TTr::back(log).GetTimestampCycles()); + } + + TExecuteQuery<TLog, TTr> exec(*this, log); + exec.ExecuteQuery(); + return exec.Result; + } + +private: + NLWTrace::TTypedParam Duration(ui64 ts1, ui64 ts2) const + { + double sec = NHPTimer::GetSeconds(ts1 < ts2? ts2 - ts1: 0); + return NLWTrace::TTypedParam(sec / TimeUnitSec); + } + + NLWTrace::TTypedParam Instant(ui64 ts) const + { + double sec = NHPTimer::GetSeconds(i64(ts) - ZeroTs); + return NLWTrace::TTypedParam(sec / TimeUnitSec); + } + void ParseQuery(const TString& s) - { + { auto parts = SplitString(s, "."); - WWW_CHECK(parts.size() <= 3, "too many name specifiers"); + WWW_CHECK(parts.size() <= 3, "too many name specifiers"); ParseParamSelector(parts.back()); - if (parts.size() >= 2) { - ParseProbeSelector(parts[parts.size() - 2]); - } - if (parts.size() >= 3) { - ParseProviderSelector(parts[parts.size() - 3]); - } - } - + if (parts.size() >= 2) { + ParseProbeSelector(parts[parts.size() - 2]); + } + if (parts.size() >= 3) { + ParseProviderSelector(parts[parts.size() - 3]); + } + } + void ParseParamSelector(const TString& s) - { - size_t bracket = s.find('['); + { + size_t bracket = s.find('['); if (bracket == TString::npos) { - ParseParamName(s); - Index = 0; - } else { - ParseParamName(s.substr(0, bracket)); - size_t bracket2 = s.find(']', bracket); + ParseParamName(s); + Index = 0; + } else { + ParseParamName(s.substr(0, bracket)); + size_t bracket2 = s.find(']', bracket); WWW_CHECK(bracket2 != TString::npos, "closing braket ']' is missing"); - Index = FromString<i64>(s.substr(bracket + 1, bracket2 - bracket - 1)); - } - } - + Index = FromString<i64>(s.substr(bracket + 1, bracket2 - bracket - 1)); + } + } + void ParseParamName(const TString& s) - { - ParamName = s; + { + ParamName = s; TString paramName = s; - + const static TVector<std::pair<TString, ESpecialParam>> specials = { - { "_track", TrackDuration }, - { "_begin", TrackBeginTime }, - { "_end", TrackEndTime }, - { "_elapsed", ElapsedDuration }, - { "_slice", SliceDuration }, - { "_thr", ThreadTime } - }; - - // Check for special params - SpecialParam = NotSpecial; - for (const auto& p : specials) { - if (paramName.StartsWith(p.first)) { - SpecialParam = p.second; + { "_track", TrackDuration }, + { "_begin", TrackBeginTime }, + { "_end", TrackEndTime }, + { "_elapsed", ElapsedDuration }, + { "_slice", SliceDuration }, + { "_thr", ThreadTime } + }; + + // Check for special params + SpecialParam = NotSpecial; + for (const auto& p : specials) { + if (paramName.StartsWith(p.first)) { + SpecialParam = p.second; paramName.erase(0, p.first.size()); - break; - } - } - - if (SpecialParam == NotSpecial) { - return; - } - + break; + } + } + + if (SpecialParam == NotSpecial) { + return; + } + const static TVector<std::pair<TString, double>> timeUnits = { - { "Ms", 1e-3 }, - { "Us", 1e-6 }, - { "Ns", 1e-9 }, - { "Min", 60.0 }, - { "Hours", 3600.0 } - }; - - // Parse units for special params - TimeUnitSec = 1.0; - for (const auto& p : timeUnits) { - if (paramName.EndsWith(p.first)) { - TimeUnitSec = p.second; + { "Ms", 1e-3 }, + { "Us", 1e-6 }, + { "Ns", 1e-9 }, + { "Min", 60.0 }, + { "Hours", 3600.0 } + }; + + // Parse units for special params + TimeUnitSec = 1.0; + for (const auto& p : timeUnits) { + if (paramName.EndsWith(p.first)) { + TimeUnitSec = p.second; paramName.erase(paramName.size() - p.first.size()); - break; - } - } - - if (SpecialParam == ThreadTime || - SpecialParam == TrackBeginTime || - SpecialParam == TrackEndTime) - { - // Parse time zero for special instant params + break; + } + } + + if (SpecialParam == ThreadTime || + SpecialParam == TrackBeginTime || + SpecialParam == TrackEndTime) + { + // Parse time zero for special instant params const TVector<std::pair<TString, i64>> timeZeros = { - { "RTime", RTimeZeroTs }, - { "NTime", NTimeZeroTs }, - { "Time", 0ll } - }; - ZeroTs = -1; - for (const auto& p : timeZeros) { - if (paramName.EndsWith(p.first)) { - ZeroTs = p.second; + { "RTime", RTimeZeroTs }, + { "NTime", NTimeZeroTs }, + { "Time", 0ll } + }; + ZeroTs = -1; + for (const auto& p : timeZeros) { + if (paramName.EndsWith(p.first)) { + ZeroTs = p.second; paramName.erase(paramName.size() - p.first.size()); - break; - } - } + break; + } + } WWW_CHECK(ZeroTs != -1, "wrong special param name (postfix '*Time' required): %s", s.data()); - } - + } + WWW_CHECK(paramName.empty(), "wrong special param name: %s", s.data()); - } - + } + void ParseProbeSelector(const TString& s) - { - Probe = s; - } - + { + Probe = s; + } + void ParseProviderSelector(const TString& s) - { - Provider = s; - } -}; - + { + Provider = s; + } +}; + using TVariants = TVector<std::pair<TString, TString>>; using TTags = TSet<TString>; - + TString GetProbeName(const NLWTrace::TProbe* probe, const char* sep = ".") -{ +{ return TString(probe->Event.GetProvider()) + sep + probe->Event.Name; -} - -struct TAdHocTraceConfig { - NLWTrace::TQuery Cfg; - - TAdHocTraceConfig() {} // Invalid config - - TAdHocTraceConfig(ui16 logSize, ui64 logDurationUs, bool logShuttle) - { - auto block = Cfg.AddBlocks(); // Create one block to distinguish valid config - if (logSize) { - Cfg.SetPerThreadLogSize(logSize); - } - if (logDurationUs) { - Cfg.SetLogDurationUs(logDurationUs); - } - if (logShuttle) { - block->AddAction()->MutableRunLogShuttleAction(); - } - } - +} + +struct TAdHocTraceConfig { + NLWTrace::TQuery Cfg; + + TAdHocTraceConfig() {} // Invalid config + + TAdHocTraceConfig(ui16 logSize, ui64 logDurationUs, bool logShuttle) + { + auto block = Cfg.AddBlocks(); // Create one block to distinguish valid config + if (logSize) { + Cfg.SetPerThreadLogSize(logSize); + } + if (logDurationUs) { + Cfg.SetLogDurationUs(logDurationUs); + } + if (logShuttle) { + block->AddAction()->MutableRunLogShuttleAction(); + } + } + TAdHocTraceConfig(const TString& provider, const TString& probe, ui16 logSize = 0, ui64 logDurationUs = 0, bool logShuttle = false) - : TAdHocTraceConfig(logSize, logDurationUs, logShuttle) - { - auto block = Cfg.MutableBlocks(0); - auto pdesc = block->MutableProbeDesc(); - pdesc->SetProvider(provider); - pdesc->SetName(probe); - } - + : TAdHocTraceConfig(logSize, logDurationUs, logShuttle) + { + auto block = Cfg.MutableBlocks(0); + auto pdesc = block->MutableProbeDesc(); + pdesc->SetProvider(provider); + pdesc->SetName(probe); + } + explicit TAdHocTraceConfig(const TString& group, ui16 logSize = 0, ui64 logDurationUs = 0, bool logShuttle = false) - : TAdHocTraceConfig(logSize, logDurationUs, logShuttle) - { - auto block = Cfg.MutableBlocks(0); - auto pdesc = block->MutableProbeDesc(); - pdesc->SetGroup(group); - } - + : TAdHocTraceConfig(logSize, logDurationUs, logShuttle) + { + auto block = Cfg.MutableBlocks(0); + auto pdesc = block->MutableProbeDesc(); + pdesc->SetGroup(group); + } + TString Id() const - { - TStringStream ss; - for (size_t blockIdx = 0; blockIdx < Cfg.BlocksSize(); blockIdx++) { - if (!ss.Str().empty()) { - ss << "/"; - } - auto block = Cfg.GetBlocks(blockIdx); - auto pdesc = block.GetProbeDesc(); + { + TStringStream ss; + for (size_t blockIdx = 0; blockIdx < Cfg.BlocksSize(); blockIdx++) { + if (!ss.Str().empty()) { + ss << "/"; + } + auto block = Cfg.GetBlocks(blockIdx); + auto pdesc = block.GetProbeDesc(); if (pdesc.GetProvider()) { - ss << "." << pdesc.GetProvider() << "." << pdesc.GetName(); + ss << "." << pdesc.GetProvider() << "." << pdesc.GetName(); } else if (pdesc.GetGroup()) { - ss << ".Group." << pdesc.GetGroup(); - } - // TODO[serxa]: handle predicate - for (size_t actionIdx = 0; actionIdx < block.ActionSize(); actionIdx++) { - const NLWTrace::TAction& action = block.GetAction(actionIdx); - if (action.HasRunLogShuttleAction()) { - auto ls = action.GetRunLogShuttleAction(); - ss << ".alsr"; - if (ls.GetIgnore()) { - ss << "-i"; - } + ss << ".Group." << pdesc.GetGroup(); + } + // TODO[serxa]: handle predicate + for (size_t actionIdx = 0; actionIdx < block.ActionSize(); actionIdx++) { + const NLWTrace::TAction& action = block.GetAction(actionIdx); + if (action.HasRunLogShuttleAction()) { + auto ls = action.GetRunLogShuttleAction(); + ss << ".alsr"; + if (ls.GetIgnore()) { + ss << "-i"; + } if (ls.GetShuttlesCount()) { - ss << "-s" << ls.GetShuttlesCount(); - } + ss << "-s" << ls.GetShuttlesCount(); + } if (ls.GetMaxTrackLength()) { - ss << "-t" << ls.GetMaxTrackLength(); - } - } else if (action.HasEditLogShuttleAction()) { - auto ls = action.GetEditLogShuttleAction(); - ss << ".alse"; - if (ls.GetIgnore()) { - ss << "-i"; - } - } else if (action.HasDropLogShuttleAction()) { - ss << ".alsd"; - } - } - } + ss << "-t" << ls.GetMaxTrackLength(); + } + } else if (action.HasEditLogShuttleAction()) { + auto ls = action.GetEditLogShuttleAction(); + ss << ".alse"; + if (ls.GetIgnore()) { + ss << "-i"; + } + } else if (action.HasDropLogShuttleAction()) { + ss << ".alsd"; + } + } + } if (Cfg.GetPerThreadLogSize()) { - ss << ".l" << Cfg.GetPerThreadLogSize(); - } + ss << ".l" << Cfg.GetPerThreadLogSize(); + } if (Cfg.GetLogDurationUs()) { - ui64 logDurationUs = Cfg.GetLogDurationUs(); - if (logDurationUs % (60 * 1000 * 1000) == 0) - ss << ".d" << logDurationUs / (60 * 1000 * 1000) << "m"; - if (logDurationUs % (1000 * 1000) == 0) - ss << ".d" << logDurationUs / (1000 * 1000) << "s"; - else if (logDurationUs % 1000 == 0) - ss << ".d" << logDurationUs / 1000 << "ms"; - else - ss << ".d" << logDurationUs << "us"; - } - return ss.Str(); - } - - bool IsValid() const - { - return Cfg.BlocksSize() > 0; - } - - NLWTrace::TQuery Query() const - { - if (!IsValid()) { - ythrow yexception() << "invalid adhoc trace config"; - } - return Cfg; - } - + ui64 logDurationUs = Cfg.GetLogDurationUs(); + if (logDurationUs % (60 * 1000 * 1000) == 0) + ss << ".d" << logDurationUs / (60 * 1000 * 1000) << "m"; + if (logDurationUs % (1000 * 1000) == 0) + ss << ".d" << logDurationUs / (1000 * 1000) << "s"; + else if (logDurationUs % 1000 == 0) + ss << ".d" << logDurationUs / 1000 << "ms"; + else + ss << ".d" << logDurationUs << "us"; + } + return ss.Str(); + } + + bool IsValid() const + { + return Cfg.BlocksSize() > 0; + } + + NLWTrace::TQuery Query() const + { + if (!IsValid()) { + ythrow yexception() << "invalid adhoc trace config"; + } + return Cfg; + } + bool ParseId(const TString& id) - { - if (IsAdHocId(id)) { + { + if (IsAdHocId(id)) { for (const TString& block : SplitString(id, "/")) { - if (block.empty()) { - continue; - } - size_t cutPos = (block[0] == '.'? 1: 0); + if (block.empty()) { + continue; + } + size_t cutPos = (block[0] == '.'? 1: 0); TVector<TString> parts = SplitString(block.substr(cutPos), "."); WWW_CHECK(parts.size() >= 2, "too few parts in adhoc trace id '%s' block '%s'", id.data(), block.data()); - auto blockPb = Cfg.AddBlocks(); - auto pdescPb = blockPb->MutableProbeDesc(); - if (parts[0] == "Group") { - pdescPb->SetGroup(parts[1]); - } else { - pdescPb->SetProvider(parts[0]); - pdescPb->SetName(parts[1]); - } - bool defaultAction = true; - for (auto i = parts.begin() + 2, e = parts.end(); i != e; ++i) { + auto blockPb = Cfg.AddBlocks(); + auto pdescPb = blockPb->MutableProbeDesc(); + if (parts[0] == "Group") { + pdescPb->SetGroup(parts[1]); + } else { + pdescPb->SetProvider(parts[0]); + pdescPb->SetName(parts[1]); + } + bool defaultAction = true; + for (auto i = parts.begin() + 2, e = parts.end(); i != e; ++i) { const TString& part = *i; - if (part.empty()) { - continue; - } - switch (part[0]) { - case 'l': Cfg.SetPerThreadLogSize(FromString<ui16>(part.substr(1))); break; - case 'd': Cfg.SetLogDurationUs(ParseDuration(part.substr(1))); break; - case 's': blockPb->MutablePredicate()->SetSampleRate(1.0 / Max<ui64>(1, FromString<ui64>(part.substr(1)))); break; - case 'p': ParsePredicate(blockPb->MutablePredicate()->AddOperators(), part.substr(1)); break; - case 'a': ParseAction(blockPb->AddAction(), part.substr(1)); defaultAction = false; break; + if (part.empty()) { + continue; + } + switch (part[0]) { + case 'l': Cfg.SetPerThreadLogSize(FromString<ui16>(part.substr(1))); break; + case 'd': Cfg.SetLogDurationUs(ParseDuration(part.substr(1))); break; + case 's': blockPb->MutablePredicate()->SetSampleRate(1.0 / Max<ui64>(1, FromString<ui64>(part.substr(1)))); break; + case 'p': ParsePredicate(blockPb->MutablePredicate()->AddOperators(), part.substr(1)); break; + case 'a': ParseAction(blockPb->AddAction(), part.substr(1)); defaultAction = false; break; default: WWW_CHECK(false, "unknown adhoc trace part type '%s' in '%s'", part.data(), id.data()); - } - } - if (defaultAction) { - blockPb->AddAction()->MutableLogAction(); - } - } - return true; - } - return false; - } -private: + } + } + if (defaultAction) { + blockPb->AddAction()->MutableLogAction(); + } + } + return true; + } + return false; + } +private: static bool IsAdHocId(const TString& id) - { - return !id.empty() && id[0] == '.'; - } - + { + return !id.empty() && id[0] == '.'; + } + void ParsePredicate(NLWTrace::TOperator* op, const TString& p) - { - size_t sign = p.find_first_of("=!><"); + { + size_t sign = p.find_first_of("=!><"); WWW_CHECK(sign != TString::npos, "wrong predicate format in adhoc trace: %s", p.data()); - op->AddArgument()->SetParam(p.substr(0, sign)); - size_t value = sign + 1; - switch (p[sign]) { - case '=': - op->SetType(NLWTrace::OT_EQ); - break; - case '!': { + op->AddArgument()->SetParam(p.substr(0, sign)); + size_t value = sign + 1; + switch (p[sign]) { + case '=': + op->SetType(NLWTrace::OT_EQ); + break; + case '!': { WWW_CHECK(p.size() > sign + 1, "wrong predicate operator format in adhoc trace: %s", p.data()); WWW_CHECK(p[sign + 1] == '=', "wrong predicate operator format in adhoc trace: %s", p.data()); - value++; - op->SetType(NLWTrace::OT_NE); - break; - } - case '<': { + value++; + op->SetType(NLWTrace::OT_NE); + break; + } + case '<': { WWW_CHECK(p.size() > sign + 1, "wrong predicate operator format in adhoc trace: %s", p.data()); - if (p[sign + 1] == '=') { - value++; - op->SetType(NLWTrace::OT_LE); - } else { - op->SetType(NLWTrace::OT_LT); - } - break; - } - case '>': { + if (p[sign + 1] == '=') { + value++; + op->SetType(NLWTrace::OT_LE); + } else { + op->SetType(NLWTrace::OT_LT); + } + break; + } + case '>': { WWW_CHECK(p.size() > sign + 1, "wrong predicate operator format in adhoc trace: %s", p.data()); - if (p[sign + 1] == '=') { - value++; - op->SetType(NLWTrace::OT_GE); - } else { - op->SetType(NLWTrace::OT_GT); - } - break; - } + if (p[sign + 1] == '=') { + value++; + op->SetType(NLWTrace::OT_GE); + } else { + op->SetType(NLWTrace::OT_GT); + } + break; + } default: WWW_CHECK(false, "wrong predicate operator format in adhoc trace: %s", p.data()); - } - op->AddArgument()->SetValue(p.substr(value)); - } - + } + op->AddArgument()->SetValue(p.substr(value)); + } + void ParseAction(NLWTrace::TAction* action, const TString& a) - { - // NOTE: checks for longer action names should go first, your captain. - if (a.substr(0, 3) == "lsr") { - auto pb = action->MutableRunLogShuttleAction(); + { + // NOTE: checks for longer action names should go first, your captain. + if (a.substr(0, 3) == "lsr") { + auto pb = action->MutableRunLogShuttleAction(); for (const TString& opt : SplitString(a.substr(3), "-")) { - if (!opt.empty()) { - switch (opt[0]) { - case 'i': pb->SetIgnore(true); break; - case 's': pb->SetShuttlesCount(FromString<ui64>(opt.substr(1))); break; - case 't': pb->SetMaxTrackLength(FromString<ui64>(opt.substr(1))); break; + if (!opt.empty()) { + switch (opt[0]) { + case 'i': pb->SetIgnore(true); break; + case 's': pb->SetShuttlesCount(FromString<ui64>(opt.substr(1))); break; + case 't': pb->SetMaxTrackLength(FromString<ui64>(opt.substr(1))); break; default: WWW_CHECK(false, "unknown adhoc trace log shuttle opt '%s' in '%s'", opt.data(), a.data()); - } - } - } - } else if (a.substr(0, 3) == "lse") { - auto pb = action->MutableEditLogShuttleAction(); + } + } + } + } else if (a.substr(0, 3) == "lse") { + auto pb = action->MutableEditLogShuttleAction(); for (const TString& opt : SplitString(a.substr(3), "-")) { - if (!opt.empty()) { - switch (opt[0]) { - case 'i': pb->SetIgnore(true); break; + if (!opt.empty()) { + switch (opt[0]) { + case 'i': pb->SetIgnore(true); break; default: WWW_CHECK(false, "unknown adhoc trace log shuttle opt '%s' in '%s'", opt.data(), a.data()); - } - } - } - } else if (a.substr(0, 3) == "lsd") { - action->MutableDropLogShuttleAction(); - } else if (a.substr(0, 1) == "l") { - auto pb = action->MutableLogAction(); + } + } + } + } else if (a.substr(0, 3) == "lsd") { + action->MutableDropLogShuttleAction(); + } else if (a.substr(0, 1) == "l") { + auto pb = action->MutableLogAction(); for (const TString& opt : SplitString(a.substr(1), "-")) { - if (!opt.empty()) { - switch (opt[0]) { - case 't': pb->SetLogTimestamp(true); break; - case 'r': pb->SetMaxRecords(FromString<ui32>(opt.substr(1))); break; + if (!opt.empty()) { + switch (opt[0]) { + case 't': pb->SetLogTimestamp(true); break; + case 'r': pb->SetMaxRecords(FromString<ui32>(opt.substr(1))); break; default: WWW_CHECK(false, "unknown adhoc trace log opt '%s' in '%s'", opt.data(), a.data()); - } - } - } - } else { + } + } + } + } else { WWW_CHECK(false, "wrong action format in adhoc trace: %s", a.data()); - } - } - + } + } + static ui64 ParseDuration(const TString& s) - { - if (s.substr(s.length() - 2) == "us") - return FromString<ui64>(s.substr(0, s.length() - 2)); - if (s.substr(s.length() - 2) == "ms") - return FromString<ui64>(s.substr(0, s.length() - 2)) * 1000; - if (s.substr(s.length() - 1) == "s") - return FromString<ui64>(s.substr(0, s.length() - 1)) * 1000 * 1000; - if (s.substr(s.length() - 1) == "m") - return FromString<ui64>(s.substr(0, s.length() - 1)) * 60 * 1000 * 1000; - else - return FromString<ui64>(s); - } -}; - -// Class that maintains one thread iff there are adhoc traces and cleans'em by deadlines -class TTraceCleaner { -private: - NLWTrace::TManager* TraceMngr; - TAtomic Quit = 0; - - TMutex Mtx; - TCondVar WakeCondVar; + { + if (s.substr(s.length() - 2) == "us") + return FromString<ui64>(s.substr(0, s.length() - 2)); + if (s.substr(s.length() - 2) == "ms") + return FromString<ui64>(s.substr(0, s.length() - 2)) * 1000; + if (s.substr(s.length() - 1) == "s") + return FromString<ui64>(s.substr(0, s.length() - 1)) * 1000 * 1000; + if (s.substr(s.length() - 1) == "m") + return FromString<ui64>(s.substr(0, s.length() - 1)) * 60 * 1000 * 1000; + else + return FromString<ui64>(s); + } +}; + +// Class that maintains one thread iff there are adhoc traces and cleans'em by deadlines +class TTraceCleaner { +private: + NLWTrace::TManager* TraceMngr; + TAtomic Quit = 0; + + TMutex Mtx; + TCondVar WakeCondVar; THashMap<TString, TInstant> Deadlines; - volatile bool ThreadIsRunning = false; - THolder<TThread> Thread; -public: - TTraceCleaner(NLWTrace::TManager* traceMngr) - : TraceMngr(traceMngr) - {} - - ~TTraceCleaner() - { - AtomicSet(Quit, 1); - WakeCondVar.Signal(); - // TThread dtor joins thread - } - - // Returns deadline for specified trace id or zero + volatile bool ThreadIsRunning = false; + THolder<TThread> Thread; +public: + TTraceCleaner(NLWTrace::TManager* traceMngr) + : TraceMngr(traceMngr) + {} + + ~TTraceCleaner() + { + AtomicSet(Quit, 1); + WakeCondVar.Signal(); + // TThread dtor joins thread + } + + // Returns deadline for specified trace id or zero TInstant GetDeadline(const TString& id) const - { - TGuard<TMutex> g(Mtx); - auto iter = Deadlines.find(id); - return iter != Deadlines.end()? iter->second: TInstant::Zero(); - } - - // Postpone deletion of specified trace for specified timeout + { + TGuard<TMutex> g(Mtx); + auto iter = Deadlines.find(id); + return iter != Deadlines.end()? iter->second: TInstant::Zero(); + } + + // Postpone deletion of specified trace for specified timeout void Postpone(const TString& id, TDuration timeout, bool allowLowering) - { - TGuard<TMutex> g(Mtx); - TInstant newDeadline = TInstant::Now() + timeout; - if (Deadlines[id] < newDeadline) { - Deadlines[id] = newDeadline; - } else if (allowLowering) { // Deadline lowering requires wake - Deadlines[id] = newDeadline; - WakeCondVar.Signal(); - } - if (newDeadline != TInstant::Max() && !ThreadIsRunning) { - // Note that dtor joins previous thread if any - Thread.Reset(new TThread(ThreadProc, this)); - Thread->Start(); - ThreadIsRunning = true; - } - } - - // Forget about specified trace deletion + { + TGuard<TMutex> g(Mtx); + TInstant newDeadline = TInstant::Now() + timeout; + if (Deadlines[id] < newDeadline) { + Deadlines[id] = newDeadline; + } else if (allowLowering) { // Deadline lowering requires wake + Deadlines[id] = newDeadline; + WakeCondVar.Signal(); + } + if (newDeadline != TInstant::Max() && !ThreadIsRunning) { + // Note that dtor joins previous thread if any + Thread.Reset(new TThread(ThreadProc, this)); + Thread->Start(); + ThreadIsRunning = true; + } + } + + // Forget about specified trace deletion void Forget(const TString& id) - { - TGuard<TMutex> g(Mtx); - Deadlines.erase(id); - WakeCondVar.Signal(); // in case thread is not required any more - } -private: - void Exec() - { - while (!AtomicGet(Quit)) { - TGuard<TMutex> g(Mtx); - - // Delete all timed out traces - TInstant now = TInstant::Now(); - TInstant nextDeadline = TInstant::Max(); - for (auto i = Deadlines.begin(), e = Deadlines.end(); i != e;) { + { + TGuard<TMutex> g(Mtx); + Deadlines.erase(id); + WakeCondVar.Signal(); // in case thread is not required any more + } +private: + void Exec() + { + while (!AtomicGet(Quit)) { + TGuard<TMutex> g(Mtx); + + // Delete all timed out traces + TInstant now = TInstant::Now(); + TInstant nextDeadline = TInstant::Max(); + for (auto i = Deadlines.begin(), e = Deadlines.end(); i != e;) { const TString& id = i->first; - TInstant deadline = i->second; - if (deadline < now) { - try { - TraceMngr->Delete(id); - } catch (...) { - // already deleted - } - Deadlines.erase(i++); - } else { - nextDeadline = Min(nextDeadline, deadline); - ++i; - } - } - - // Stop thread if there is no more work - if (Deadlines.empty() || nextDeadline == TInstant::Max()) { - ThreadIsRunning = false; - break; - } - - // Wait until next deadline or quit - WakeCondVar.WaitD(Mtx, nextDeadline); - } - } - - static void* ThreadProc(void* _this) - { + TInstant deadline = i->second; + if (deadline < now) { + try { + TraceMngr->Delete(id); + } catch (...) { + // already deleted + } + Deadlines.erase(i++); + } else { + nextDeadline = Min(nextDeadline, deadline); + ++i; + } + } + + // Stop thread if there is no more work + if (Deadlines.empty() || nextDeadline == TInstant::Max()) { + ThreadIsRunning = false; + break; + } + + // Wait until next deadline or quit + WakeCondVar.WaitD(Mtx, nextDeadline); + } + } + + static void* ThreadProc(void* _this) + { TString name = "LWTraceCleaner"; - // Copy-pasted from kikimr/core/util/thread.h -#if defined(_linux_) - TStringStream linuxName; - linuxName << TStringBuf(GetExecPath()).RNextTok('/') << "." << name; + // Copy-pasted from kikimr/core/util/thread.h +#if defined(_linux_) + TStringStream linuxName; + linuxName << TStringBuf(GetExecPath()).RNextTok('/') << "." << name; TThread::SetCurrentThreadName(linuxName.Str().data()); -#else +#else TThread::SetCurrentThreadName(name.data()); -#endif - static_cast<TTraceCleaner*>(_this)->Exec(); - return nullptr; - } -}; - -class TChromeTrace { -private: +#endif + static_cast<TTraceCleaner*>(_this)->Exec(); + return nullptr; + } +}; + +class TChromeTrace { +private: TMultiMap<double, TString> TraceEvents; THashMap<TThread::TId, TString> Tids; -public: +public: void Add(TThread::TId tid, ui64 tsCycles, const TString& ph, const TString& cat, - const NLWTrace::TLogItem* argsItem = nullptr, + const NLWTrace::TLogItem* argsItem = nullptr, const TString& name = TString(), const TString& id = TString()) - { - auto tidIter = Tids.find(tid); - if (tidIter == Tids.end()) { - tidIter = Tids.emplace(tid, ToString(Tids.size() + 1)).first; - } + { + auto tidIter = Tids.find(tid); + if (tidIter == Tids.end()) { + tidIter = Tids.emplace(tid, ToString(Tids.size() + 1)).first; + } const TString& shortId = tidIter->second; - double ts = Timestamp(tsCycles); - TraceEvents.emplace(ts, Event(shortId, ts, ph, cat, argsItem, name, id)); - } - + double ts = Timestamp(tsCycles); + TraceEvents.emplace(ts, Event(shortId, ts, ph, cat, argsItem, name, id)); + } + void Output(IOutputStream& os) - { - os << "{\"traceEvents\":["; - bool first = true; - for (auto kv : TraceEvents) { - if (!first) { - os << ",\n"; - } - os << kv.second; - first = false; - } - os << "]}"; - } - -private: + { + os << "{\"traceEvents\":["; + bool first = true; + for (auto kv : TraceEvents) { + if (!first) { + os << ",\n"; + } + os << kv.second; + first = false; + } + os << "]}"; + } + +private: static TString Event(const TString& tid, double ts, const TString& ph, const TString& cat, - const NLWTrace::TLogItem* argsItem, + const NLWTrace::TLogItem* argsItem, const TString& name, const TString& id) - { - TStringStream ss; - pid_t pid = 1; - ss << "{\"pid\":" << pid - << ",\"tid\":" << tid - << ",\"ts\":" << Sprintf("%lf", ts) - << ",\"ph\":\"" << ph << "\"" - << ",\"cat\":\"" << cat << "\""; - if (name) { - ss << ",\"name\":\"" << name << "\""; - } - if (id) { - ss << ",\"id\":\"" << id << "\""; - } - if (argsItem && argsItem->SavedParamsCount > 0) { - ss << ",\"args\":{"; + { + TStringStream ss; + pid_t pid = 1; + ss << "{\"pid\":" << pid + << ",\"tid\":" << tid + << ",\"ts\":" << Sprintf("%lf", ts) + << ",\"ph\":\"" << ph << "\"" + << ",\"cat\":\"" << cat << "\""; + if (name) { + ss << ",\"name\":\"" << name << "\""; + } + if (id) { + ss << ",\"id\":\"" << id << "\""; + } + if (argsItem && argsItem->SavedParamsCount > 0) { + ss << ",\"args\":{"; TString paramValues[LWTRACE_MAX_PARAMS]; - argsItem->Probe->Event.Signature.SerializeParams(argsItem->Params, paramValues); - bool first = true; - for (size_t pi = 0; pi < argsItem->SavedParamsCount; pi++, first = false) { - if (!first) { - ss << ","; - } + argsItem->Probe->Event.Signature.SerializeParams(argsItem->Params, paramValues); + bool first = true; + for (size_t pi = 0; pi < argsItem->SavedParamsCount; pi++, first = false) { + if (!first) { + ss << ","; + } ss << "\"" << TString(argsItem->Probe->Event.Signature.ParamNames[pi]) << "\":" - "\"" << paramValues[pi] << "\""; - } - ss << "}"; - } - ss << "}"; - return ss.Str(); - } - - static double Timestamp(ui64 cycles) - { - return double(cycles) * 1000000.0 / NHPTimer::GetClockRate(); - } -}; - -TString MakeUrl(const TCgiParameters& e, const THashMap<TString, TString>& values) -{ - TStringStream ss; - bool first = true; - for (const auto& [k, v] : e) { - if (values.find(k) == values.end()) { - ss << (first? "?": "&") << k << "=" << v; - first = false; - } - } - for (const auto& [k, v] : values) { - ss << (first? "?": "&") << k << "=" << v; - first = false; - } - return ss.Str(); -} - + "\"" << paramValues[pi] << "\""; + } + ss << "}"; + } + ss << "}"; + return ss.Str(); + } + + static double Timestamp(ui64 cycles) + { + return double(cycles) * 1000000.0 / NHPTimer::GetClockRate(); + } +}; + +TString MakeUrl(const TCgiParameters& e, const THashMap<TString, TString>& values) +{ + TStringStream ss; + bool first = true; + for (const auto& [k, v] : e) { + if (values.find(k) == values.end()) { + ss << (first? "?": "&") << k << "=" << v; + first = false; + } + } + for (const auto& [k, v] : values) { + ss << (first? "?": "&") << k << "=" << v; + first = false; + } + return ss.Str(); +} + TString MakeUrl(const TCgiParameters& e, const TString& key, const TString& value, bool keep = false) -{ - TStringStream ss; - bool first = true; - for (const auto& kv : e) { - if (keep || kv.first != key) { - ss << (first? "?": "&") << kv.first << "=" << kv.second; - first = false; - } - } - ss << (first? "?": "&") << key << "=" << value; - return ss.Str(); -} - +{ + TStringStream ss; + bool first = true; + for (const auto& kv : e) { + if (keep || kv.first != key) { + ss << (first? "?": "&") << kv.first << "=" << kv.second; + first = false; + } + } + ss << (first? "?": "&") << key << "=" << value; + return ss.Str(); +} + TString MakeUrlAdd(const TCgiParameters& e, const TString& key, const TString& value) -{ - TStringStream ss; - bool first = true; - for (const auto& kv : e) { - ss << (first? "?": "&") << kv.first << "=" << kv.second; - first = false; - } - ss << (first? "?": "&") << key << "=" << value; - return ss.Str(); -} - +{ + TStringStream ss; + bool first = true; + for (const auto& kv : e) { + ss << (first? "?": "&") << kv.first << "=" << kv.second; + first = false; + } + ss << (first? "?": "&") << key << "=" << value; + return ss.Str(); +} + TString MakeUrlReplace(const TCgiParameters& e, const TString& key, const TString& oldValue, const TString& newValue) -{ - TStringStream ss; - bool first = true; - bool inserted = false; - for (const auto& kv : e) { - if (kv.first == key && (kv.second == oldValue || kv.second == newValue)) { - if (!inserted) { - inserted = true; - ss << (first? "?": "&") << key << "=" << newValue; - first = false; - } - } else { - ss << (first? "?": "&") << kv.first << "=" << kv.second; - first = false; - } - } - if (!inserted) { - ss << (first? "?": "&") << key << "=" << newValue; - } - return ss.Str(); -} - +{ + TStringStream ss; + bool first = true; + bool inserted = false; + for (const auto& kv : e) { + if (kv.first == key && (kv.second == oldValue || kv.second == newValue)) { + if (!inserted) { + inserted = true; + ss << (first? "?": "&") << key << "=" << newValue; + first = false; + } + } else { + ss << (first? "?": "&") << kv.first << "=" << kv.second; + first = false; + } + } + if (!inserted) { + ss << (first? "?": "&") << key << "=" << newValue; + } + return ss.Str(); +} + TString MakeUrlErase(const TCgiParameters& e, const TString& key, const TString& value) -{ - TStringStream ss; - bool first = true; - for (const auto& kv : e) { - if (kv.first != key || kv.second != value) { - ss << (first? "?": "&") << kv.first << "=" << kv.second; - first = false; - } - } - return ss.Str(); -} - +{ + TStringStream ss; + bool first = true; + for (const auto& kv : e) { + if (kv.first != key || kv.second != value) { + ss << (first? "?": "&") << kv.first << "=" << kv.second; + first = false; + } + } + return ss.Str(); +} + TString EscapeSubvalue(const TString& s) -{ +{ TString ret; ret.reserve(s.size()); for (size_t i = 0; i < s.size(); i++) { - char c = s[i]; - if (c == ':') { - ret.append("^c"); - } else if (c == '^') { - ret.append("^^"); - } else { - ret.append(c); - } - } - return ret; -} - + char c = s[i]; + if (c == ':') { + ret.append("^c"); + } else if (c == '^') { + ret.append("^^"); + } else { + ret.append(c); + } + } + return ret; +} + TString UnescapeSubvalue(const TString& s) -{ +{ TString ret; ret.reserve(s.size()); for (size_t i = 0; i < s.size(); i++) { - char c = s[i]; + char c = s[i]; if (c == '^' && i + 1 < s.size()) { - char c2 = s[++i]; - if (c2 == 'c') { - ret.append(':'); - } else if (c2 == '^') { - ret.append('^'); - } else { - ret.append(c); - ret.append(c2); - } - } else { - ret.append(c); - } - } - return ret; -} - + char c2 = s[++i]; + if (c2 == 'c') { + ret.append(':'); + } else if (c2 == '^') { + ret.append('^'); + } else { + ret.append(c); + ret.append(c2); + } + } else { + ret.append(c); + } + } + return ret; +} + TVector<TString> Subvalues(const TCgiParameters& e, const TString& key) -{ - if (!e.Has(key)) { +{ + if (!e.Has(key)) { return TVector<TString>(); - } else { + } else { TVector<TString> ret; for (const TString& s : SplitString(e.Get(key), ":", 0, KEEP_EMPTY_TOKENS)) { - ret.push_back(UnescapeSubvalue(s)); - } - if (ret.empty()) { - ret.push_back(""); - } - return ret; - } -} - + ret.push_back(UnescapeSubvalue(s)); + } + if (ret.empty()) { + ret.push_back(""); + } + return ret; + } +} + TString ParseTagsOut(const TString& taggedStr, TTags& tags) -{ +{ auto vec = SplitString(taggedStr, "-"); - if (vec.empty()) { - return ""; - } - auto iter = vec.begin(); + if (vec.empty()) { + return ""; + } + auto iter = vec.begin(); TString value = *iter++; - for (;iter != vec.end(); ++iter) { - tags.insert(*iter); - } - return value; -} - + for (;iter != vec.end(); ++iter) { + tags.insert(*iter); + } + return value; +} + TString JoinTags(TTags tags) { return JoinStrings(TVector<TString>(tags.begin(), tags.end()), "-"); -} - +} + TString MakeValue(const TVector<TString>& subvalues) -{ +{ TVector<TString> subvaluesEsc; for (const TString& s : subvalues) { - subvaluesEsc.push_back(EscapeSubvalue(s)); - } + subvaluesEsc.push_back(EscapeSubvalue(s)); + } return JoinStrings(subvaluesEsc, ":"); -} - +} + TString MakeUrlAddSub(const TCgiParameters& e, const TString& key, const TString& subvalue) -{ +{ const TString& value = e.Get(key); - auto subvalues = Subvalues(e, key); - subvalues.push_back(subvalue); - return MakeUrlReplace(e, key, value, MakeValue(subvalues)); -} - + auto subvalues = Subvalues(e, key); + subvalues.push_back(subvalue); + return MakeUrlReplace(e, key, value, MakeValue(subvalues)); +} + TString MakeUrlReplaceSub(const TCgiParameters& e, const TString& key, const TString& oldSubvalue, const TString& newSubvalue) -{ +{ const TString& value = e.Get(key); - auto subvalues = Subvalues(e, key); - auto iter = std::find(subvalues.begin(), subvalues.end(), oldSubvalue); - if (iter != subvalues.end()) { - *iter = newSubvalue; - } else { - subvalues.push_back(newSubvalue); - } - return MakeUrlReplace(e, key, value, MakeValue(subvalues)); -} - + auto subvalues = Subvalues(e, key); + auto iter = std::find(subvalues.begin(), subvalues.end(), oldSubvalue); + if (iter != subvalues.end()) { + *iter = newSubvalue; + } else { + subvalues.push_back(newSubvalue); + } + return MakeUrlReplace(e, key, value, MakeValue(subvalues)); +} + TString MakeUrlEraseSub(const TCgiParameters& e, const TString& key, const TString& subvalue) -{ +{ const TString& value = e.Get(key); - auto subvalues = Subvalues(e, key); - auto iter = std::find(subvalues.begin(), subvalues.end(), subvalue); - if (iter != subvalues.end()) { - subvalues.erase(iter); - } - if (subvalues.empty()) { - return MakeUrlErase(e, key, value); - } else { - return MakeUrlReplace(e, key, value, MakeValue(subvalues)); - } -} - + auto subvalues = Subvalues(e, key); + auto iter = std::find(subvalues.begin(), subvalues.end(), subvalue); + if (iter != subvalues.end()) { + subvalues.erase(iter); + } + if (subvalues.empty()) { + return MakeUrlErase(e, key, value); + } else { + return MakeUrlReplace(e, key, value, MakeValue(subvalues)); + } +} + template <bool sub> TString UrlAdd(const TCgiParameters& e, const TString& key, const TString& value); template <> TString UrlAdd<false>(const TCgiParameters& e, const TString& key, const TString& value) { - return MakeUrlAdd(e, key, value); -} + return MakeUrlAdd(e, key, value); +} template <> TString UrlAdd<true>(const TCgiParameters& e, const TString& key, const TString& value) { - return MakeUrlAddSub(e, key, value); -} - + return MakeUrlAddSub(e, key, value); +} + template <bool sub> TString UrlReplace(const TCgiParameters& e, const TString& key, const TString& oldValue, const TString& newValue); template <> TString UrlReplace<false>(const TCgiParameters& e, const TString& key, const TString& oldValue, const TString& newValue) { - return MakeUrlReplace(e, key, oldValue, newValue); -} + return MakeUrlReplace(e, key, oldValue, newValue); +} template <> TString UrlReplace<true>(const TCgiParameters& e, const TString& key, const TString& oldValue, const TString& newValue) { - return MakeUrlReplaceSub(e, key, oldValue, newValue); -} - + return MakeUrlReplaceSub(e, key, oldValue, newValue); +} + template <bool sub> TString UrlErase(const TCgiParameters& e, const TString& key, const TString& value); template <> TString UrlErase<false>(const TCgiParameters& e, const TString& key, const TString& value) { - return MakeUrlErase(e, key, value); -} + return MakeUrlErase(e, key, value); +} template <> TString UrlErase<true>(const TCgiParameters& e, const TString& key, const TString& value) { - return MakeUrlEraseSub(e, key, value); -} - + return MakeUrlEraseSub(e, key, value); +} + void OutputCommonHeader(IOutputStream& out) -{ - out << NResource::Find("lwtrace/mon/static/header.html") << Endl; -} - +{ + out << NResource::Find("lwtrace/mon/static/header.html") << Endl; +} + void OutputCommonFooter(IOutputStream& out) -{ - out << NResource::Find("lwtrace/mon/static/footer.html") << Endl; -} - -struct TScopedHtmlInner { +{ + out << NResource::Find("lwtrace/mon/static/footer.html") << Endl; +} + +struct TScopedHtmlInner { explicit TScopedHtmlInner(IOutputStream& str) - : Str(str) - { - Str << "<!DOCTYPE html>\n" - "<html>"; - HTML(str) { - HEAD() { OutputCommonHeader(Str); } - } - Str << "<body>"; - } - - ~TScopedHtmlInner() - { - OutputCommonFooter(Str); - Str << "</body></html>"; - } - - inline operator bool () const noexcept { return true; } - + : Str(str) + { + Str << "<!DOCTYPE html>\n" + "<html>"; + HTML(str) { + HEAD() { OutputCommonHeader(Str); } + } + Str << "<body>"; + } + + ~TScopedHtmlInner() + { + OutputCommonFooter(Str); + Str << "</body></html>"; + } + + inline operator bool () const noexcept { return true; } + IOutputStream &Str; -}; - +}; + TString NavbarHeader() -{ - return "<div class=\"navbar-header\">" - "<a class=\"navbar-brand\" href=\"?mode=\">LWTrace</a>" - "</div>"; -} - -struct TSelectorsContainer { +{ + return "<div class=\"navbar-header\">" + "<a class=\"navbar-brand\" href=\"?mode=\">LWTrace</a>" + "</div>"; +} + +struct TSelectorsContainer { TSelectorsContainer(IOutputStream& str) - : Str(str) - { - Str << "<nav id=\"selectors-container\" class=\"navbar navbar-default\">" - "<div class=\"container-fluid\">" - << NavbarHeader() << - "<div class=\"navbar-text\" style=\"margin-top:12px;margin-bottom:10px\">"; - } - - ~TSelectorsContainer() { - try { - Str << - "</div>" - "<div class=\"container-fluid\">" - "<div class=\"pull-right\">" - "<button id=\"download-btn\"" - " type=\"button\" style=\"display: inline-block;margin:7px\"" - " title=\"Chromium trace (load it in chrome://tracing/)\"" - " class=\"btn btn-default hidden\">" - "<span class=\"glyphicon glyphicon-download-alt\"></span>" - "</button>" - "</div>" - "</div>" - "</div></nav>"; - } catch(...) {} - } - + : Str(str) + { + Str << "<nav id=\"selectors-container\" class=\"navbar navbar-default\">" + "<div class=\"container-fluid\">" + << NavbarHeader() << + "<div class=\"navbar-text\" style=\"margin-top:12px;margin-bottom:10px\">"; + } + + ~TSelectorsContainer() { + try { + Str << + "</div>" + "<div class=\"container-fluid\">" + "<div class=\"pull-right\">" + "<button id=\"download-btn\"" + " type=\"button\" style=\"display: inline-block;margin:7px\"" + " title=\"Chromium trace (load it in chrome://tracing/)\"" + " class=\"btn btn-default hidden\">" + "<span class=\"glyphicon glyphicon-download-alt\"></span>" + "</button>" + "</div>" + "</div>" + "</div></nav>"; + } catch(...) {} + } + IOutputStream& Str; -}; - -struct TNullContainer { +}; + +struct TNullContainer { TNullContainer(IOutputStream&) {} -}; - -class TPageGenBase: public std::exception {}; -template <class TContainer = TNullContainer> -class TPageGen: public TPageGenBase { -private: +}; + +class TPageGenBase: public std::exception {}; +template <class TContainer = TNullContainer> +class TPageGen: public TPageGenBase { +private: TString Content; TString HttpResponse; -public: - void BuildResponse() - { - TStringStream ss; - WWW_HTML(ss) { - TContainer container(ss); - ss << Content; - } - HttpResponse = ss.Str(); - } - +public: + void BuildResponse() + { + TStringStream ss; + WWW_HTML(ss) { + TContainer container(ss); + ss << Content; + } + HttpResponse = ss.Str(); + } + explicit TPageGen(const TString& content = TString()) - : Content(content) - { - BuildResponse(); - } - + : Content(content) + { + BuildResponse(); + } + void Append(const TString& moreContent) - { - Content.append(moreContent); - BuildResponse(); - } - + { + Content.append(moreContent); + BuildResponse(); + } + void Prepend(const TString& moreContent) - { - Content.prepend(moreContent); - BuildResponse(); - } - + { + Content.prepend(moreContent); + BuildResponse(); + } + virtual const char* what() const noexcept { return HttpResponse.data(); } operator bool() const { return !Content.empty(); } -}; - -enum EStyleFlags { - // bit 1 - Link = 0x0, - Button = 0x1, - - // bit 2 - NonErasable = 0x0, - Erasable = 0x2, - - // bit 3-4 - Medium = 0x0, - Large = 0x4, - Small = 0x8, - ExtraSmall = 0xC, - SizeMask = 0xC, - - // bit 5 - NoCaret = 0x0, - Caret = 0x10, - - // bit 6 - SimpleValue = 0x0, - CompositeValue = 0x20 -}; - -template <ui64 flags> +}; + +enum EStyleFlags { + // bit 1 + Link = 0x0, + Button = 0x1, + + // bit 2 + NonErasable = 0x0, + Erasable = 0x2, + + // bit 3-4 + Medium = 0x0, + Large = 0x4, + Small = 0x8, + ExtraSmall = 0xC, + SizeMask = 0xC, + + // bit 5 + NoCaret = 0x0, + Caret = 0x10, + + // bit 6 + SimpleValue = 0x0, + CompositeValue = 0x20 +}; + +template <ui64 flags> TString BtnClass() { - if ((flags & SizeMask) == Large) { - return "btn btn-lg"; - } else if ((flags & SizeMask) == Small) { - return "btn btn-sm"; - } else if ((flags & SizeMask) == ExtraSmall) { - return "btn btn-xs"; - } - return "btn"; -} - + if ((flags & SizeMask) == Large) { + return "btn btn-lg"; + } else if ((flags & SizeMask) == Small) { + return "btn btn-sm"; + } else if ((flags & SizeMask) == ExtraSmall) { + return "btn btn-xs"; + } + return "btn"; +} + void SelectorTitle(IOutputStream& os, const TString& text) -{ - if (!text.empty()) { - os << text; - } -} - -template <ui64 flags> +{ + if (!text.empty()) { + os << text; + } +} + +template <ui64 flags> void BtnHref(IOutputStream& os, const TString& text, const TString& href, bool push = false) -{ - if (flags & Button) { - os << "<button type=\"button\" style=\"display: inline-block;margin:3px\" class=\"" - << BtnClass<flags>() << " " - << (push? "btn-primary": "btn-default") - << "\" onClick=\"window.location.href='" << href << "';\">" - << text - << "</button>"; - } else { - os << "<a href=\"" << href << "\">" - << text - << "</a>"; - } -} - +{ + if (flags & Button) { + os << "<button type=\"button\" style=\"display: inline-block;margin:3px\" class=\"" + << BtnClass<flags>() << " " + << (push? "btn-primary": "btn-default") + << "\" onClick=\"window.location.href='" << href << "';\">" + << text + << "</button>"; + } else { + os << "<a href=\"" << href << "\">" + << text + << "</a>"; + } +} + void DropdownBeginSublist(IOutputStream& os, const TString& text) -{ - os << "<li>" << text << "<ul class=\"dropdown-menu\">"; -} - +{ + os << "<li>" << text << "<ul class=\"dropdown-menu\">"; +} + void DropdownEndSublist(IOutputStream& os) -{ - os << "</ul></li>"; -} - +{ + os << "</ul></li>"; +} + void DropdownItem(IOutputStream& os, const TString& text, const TString& href, bool separated = false) -{ - if (separated) { - os << "<li role=\"separator\" class=\"divider\"></li>"; - } - os << "<li><a href=\"" << href << "\">" << text << "</a></li>"; -} - +{ + if (separated) { + os << "<li role=\"separator\" class=\"divider\"></li>"; + } + os << "<li><a href=\"" << href << "\">" << text << "</a></li>"; +} + TString SuggestSelection() -{ - return "--- "; -} - +{ + return "--- "; +} + TString RemoveSelection() -{ - return "Remove"; -} - +{ + return "Remove"; +} + TString GetDescription(const TString& value, const TVariants& variants) -{ - for (const auto& var : variants) { - if (value == var.first) { - return var.second; - } - } - if (!value) { - return SuggestSelection(); - } - return value; -} - -template <ui64 flags, bool sub = false> +{ + for (const auto& var : variants) { + if (value == var.first) { + return var.second; + } + } + if (!value) { + return SuggestSelection(); + } + return value; +} + +template <ui64 flags, bool sub = false> void DropdownSelector(IOutputStream& os, const TCgiParameters& e, const TString& param, const TString& value, const TString& text, const TVariants& variants, const TString& realValue = TString()) -{ - HTML(os) { - SelectorTitle(os, text); - os << "<div class=\"dropdown\" style=\"display:inline-block;margin:3px\">"; - if (flags & Button) { - os << "<button class=\"" << BtnClass<flags>() << " btn-primary dropdown-toggle\" type=\"button\" data-toggle=\"dropdown\">"; - } else { - os << "<a href=\"#\" data-toggle=\"dropdown\">"; - } - os << GetDescription(flags & CompositeValue? realValue: value, variants); - if (flags & Caret) { - os << "<span class=\"caret\"></span>"; - } - if (flags & Button) { - os <<"</button>"; - } else { - os <<"</a>"; - } - UL_CLASS ("dropdown-menu") { - for (const auto& var : variants) { - DropdownItem(os, var.second, UrlReplace<sub>(e, param, value, var.first)); - } - if (flags & Erasable) { - DropdownItem(os, RemoveSelection(), UrlErase<sub>(e, param, value), true); - } - } - os << "</div>"; - } -} - +{ + HTML(os) { + SelectorTitle(os, text); + os << "<div class=\"dropdown\" style=\"display:inline-block;margin:3px\">"; + if (flags & Button) { + os << "<button class=\"" << BtnClass<flags>() << " btn-primary dropdown-toggle\" type=\"button\" data-toggle=\"dropdown\">"; + } else { + os << "<a href=\"#\" data-toggle=\"dropdown\">"; + } + os << GetDescription(flags & CompositeValue? realValue: value, variants); + if (flags & Caret) { + os << "<span class=\"caret\"></span>"; + } + if (flags & Button) { + os <<"</button>"; + } else { + os <<"</a>"; + } + UL_CLASS ("dropdown-menu") { + for (const auto& var : variants) { + DropdownItem(os, var.second, UrlReplace<sub>(e, param, value, var.first)); + } + if (flags & Erasable) { + DropdownItem(os, RemoveSelection(), UrlErase<sub>(e, param, value), true); + } + } + os << "</div>"; + } +} + void RequireSelection(TStringStream& ss, const TCgiParameters& e, const TString& param, const TString& text, const TVariants& variants) -{ +{ const TString& value = e.Get(param); - DropdownSelector<Link>(ss, e, param, value, text, variants); - if (!value) { - throw TPageGen<TSelectorsContainer>(ss.Str()); - } -} - + DropdownSelector<Link>(ss, e, param, value, text, variants); + if (!value) { + throw TPageGen<TSelectorsContainer>(ss.Str()); + } +} + void RequireMultipleSelection(TStringStream& ss, const TCgiParameters& e, const TString& param, const TString& text, const TVariants& variants) -{ - SelectorTitle(ss, text); +{ + SelectorTitle(ss, text); TSet<TString> selectedValues; for (const TString& subvalue : Subvalues(e, param)) { - selectedValues.insert(subvalue); - } + selectedValues.insert(subvalue); + } for (const TString& subvalue : Subvalues(e, param)) { - DropdownSelector<Erasable, true>(ss, e, param, subvalue, "", variants); - } + DropdownSelector<Erasable, true>(ss, e, param, subvalue, "", variants); + } if (selectedValues.contains("")) { - throw TPageGen<TSelectorsContainer>(ss.Str()); - } else { - BtnHref<Button|ExtraSmall>(ss, "+", MakeUrlAddSub(e, param, "")); - if (selectedValues.empty()) { - throw TPageGen<TSelectorsContainer>(ss.Str()); - } - } -} - + throw TPageGen<TSelectorsContainer>(ss.Str()); + } else { + BtnHref<Button|ExtraSmall>(ss, "+", MakeUrlAddSub(e, param, "")); + if (selectedValues.empty()) { + throw TPageGen<TSelectorsContainer>(ss.Str()); + } + } +} + void OptionalSelection(TStringStream& ss, const TCgiParameters& e, const TString& param, const TString& text, const TVariants& variants) { @@ -1424,251 +1424,251 @@ void OptionalSelection(TStringStream& ss, const TCgiParameters& e, const TString void OptionalMultipleSelection(TStringStream& ss, const TCgiParameters& e, const TString& param, const TString& text, const TVariants& variants) -{ +{ TSet<TString> selectedValues; for (const TString& subvalue : Subvalues(e, param)) { - selectedValues.insert(subvalue); - } - if (!selectedValues.empty()) { - SelectorTitle(ss, text); - } + selectedValues.insert(subvalue); + } + if (!selectedValues.empty()) { + SelectorTitle(ss, text); + } for (const TString& subvalue : Subvalues(e, param)) { - DropdownSelector<Erasable, true>(ss, e, param, subvalue, "", variants); - } + DropdownSelector<Erasable, true>(ss, e, param, subvalue, "", variants); + } if (selectedValues.contains("")) { - throw TPageGen<TSelectorsContainer>(ss.Str()); - } else { - BtnHref<Button|ExtraSmall>(ss, selectedValues.empty()? text: "+", MakeUrlAddSub(e, param, "")); - } -} - -TVariants ListColumns(const NAnalytics::TTable& table) -{ + throw TPageGen<TSelectorsContainer>(ss.Str()); + } else { + BtnHref<Button|ExtraSmall>(ss, selectedValues.empty()? text: "+", MakeUrlAddSub(e, param, "")); + } +} + +TVariants ListColumns(const NAnalytics::TTable& table) +{ TSet<TString> cols; -// bool addSpecialCols = false; -// if (addSpecialCols) { -// cols.insert("_count"); -// } - for (auto& row : table) { - for (auto& kv : row) { - cols.insert(kv.first); - } - } - TVariants result; - for (const auto& s : cols) { - result.emplace_back(s, s); - } - return result; -} - +// bool addSpecialCols = false; +// if (addSpecialCols) { +// cols.insert("_count"); +// } + for (auto& row : table) { + for (auto& kv : row) { + cols.insert(kv.first); + } + } + TVariants result; + for (const auto& s : cols) { + result.emplace_back(s, s); + } + return result; +} + TString TaggedValue(const TString& value, const TString& tag) -{ - if (!tag) { - return value; - } - return value + "-" + tag; -} - +{ + if (!tag) { + return value; + } + return value + "-" + tag; +} + TVariants ValueVars(const TVariants& values, const TString& tag) -{ - TVariants ret; - for (auto& p : values) { - ret.emplace_back(TaggedValue(p.first, tag), p.second); - } - return ret; -} - +{ + TVariants ret; + for (auto& p : values) { + ret.emplace_back(TaggedValue(p.first, tag), p.second); + } + return ret; +} + TVariants TagVars(const TString& value, const TVariants& tags) -{ - TVariants ret; - for (auto& p : tags) { - ret.emplace_back(TaggedValue(value, p.first), p.second); - } - return ret; -} - -TVariants SeriesTags() -{ - TVariants ret; // MSVS2013 doesn't understand complex initializer lists - ret.emplace_back("", "as is"); - ret.emplace_back("stack", "cumulative"); - return ret; -} - -void SeriesSelectors(TStringStream& ss, const TCgiParameters& e, +{ + TVariants ret; + for (auto& p : tags) { + ret.emplace_back(TaggedValue(value, p.first), p.second); + } + return ret; +} + +TVariants SeriesTags() +{ + TVariants ret; // MSVS2013 doesn't understand complex initializer lists + ret.emplace_back("", "as is"); + ret.emplace_back("stack", "cumulative"); + return ret; +} + +void SeriesSelectors(TStringStream& ss, const TCgiParameters& e, const TString& xparam, const TString& yparam, const NAnalytics::TTable& data) -{ - TTags xtags; +{ + TTags xtags; TString xn = ParseTagsOut(e.Get(xparam), xtags); - DropdownSelector<Erasable, true>(ss, e, xparam, e.Get(xparam), "with Ox:", - ValueVars(ListColumns(data), JoinTags(xtags))); - if (xn) { - DropdownSelector<Link, true>(ss, e, xparam, e.Get(xparam), "", - TagVars(xn, SeriesTags())); - } - + DropdownSelector<Erasable, true>(ss, e, xparam, e.Get(xparam), "with Ox:", + ValueVars(ListColumns(data), JoinTags(xtags))); + if (xn) { + DropdownSelector<Link, true>(ss, e, xparam, e.Get(xparam), "", + TagVars(xn, SeriesTags())); + } + TString yns = e.Get(yparam); - SelectorTitle(ss, "and Oy:"); - bool first = true; - bool hasEmpty = false; - for (auto& subvalue : Subvalues(e, yparam)) { - TTags ytags; + SelectorTitle(ss, "and Oy:"); + bool first = true; + bool hasEmpty = false; + for (auto& subvalue : Subvalues(e, yparam)) { + TTags ytags; TString yn = ParseTagsOut(subvalue, ytags); - DropdownSelector<Erasable, true>(ss, e, yparam, subvalue, first? "": ", ", - ValueVars(ListColumns(data), JoinTags(ytags))); - if (yn) { - DropdownSelector<Link, true>(ss, e, yparam, subvalue, "", - TagVars(yn, SeriesTags())); - } - first = false; - if (yn.empty()) { - hasEmpty = true; - } - } - - if (hasEmpty) { - throw TPageGen<TSelectorsContainer>(ss.Str()); - } else { - BtnHref<Button|ExtraSmall>(ss, "+", MakeUrlAddSub(e, yparam, "")); - } - - if (!xn || !yns) { - throw TPageGen<TSelectorsContainer>(ss.Str()); - } -} - + DropdownSelector<Erasable, true>(ss, e, yparam, subvalue, first? "": ", ", + ValueVars(ListColumns(data), JoinTags(ytags))); + if (yn) { + DropdownSelector<Link, true>(ss, e, yparam, subvalue, "", + TagVars(yn, SeriesTags())); + } + first = false; + if (yn.empty()) { + hasEmpty = true; + } + } + + if (hasEmpty) { + throw TPageGen<TSelectorsContainer>(ss.Str()); + } else { + BtnHref<Button|ExtraSmall>(ss, "+", MakeUrlAddSub(e, yparam, "")); + } + + if (!xn || !yns) { + throw TPageGen<TSelectorsContainer>(ss.Str()); + } +} + class TProbesHtmlPrinter { private: TVector<TVector<TString>> TableData; - static constexpr int TimeoutSec = 15 * 60; // default timeout + static constexpr int TimeoutSec = 15 * 60; // default timeout public: void Push(const NLWTrace::TProbe* probe) { TableData.emplace_back(); - auto& row = TableData.back(); - + auto& row = TableData.back(); + row.emplace_back(); TString& groups = row.back(); bool first = true; for (const char* const* i = probe->Event.Groups; *i != nullptr; ++i, first = false) { groups.append(TString(first? "": ", ") + GroupHtml(*i)); } - - row.push_back(ProbeHtml(probe->Event.GetProvider(), probe->Event.Name)); - + + row.push_back(ProbeHtml(probe->Event.GetProvider(), probe->Event.Name)); + row.emplace_back(); TString& params = row.back(); first = true; for (size_t i = 0; i < probe->Event.Signature.ParamCount; i++, first = false) { params.append(TString(first? "": ", ") + probe->Event.Signature.ParamTypes[i] - + " " + probe->Event.Signature.ParamNames[i]); + + " " + probe->Event.Signature.ParamNames[i]); } - - row.emplace_back(ToString(probe->GetExecutorsCount())); + + row.emplace_back(ToString(probe->GetExecutorsCount())); } - + void Output(IOutputStream& os) - { - HTML(os) { - TABLE() { - TABLEHEAD() { - TABLEH() { os << "Groups"; } - TABLEH() { os << "Name"; } - TABLEH() { os << "Params"; } - TABLEH() { os << "ExecCount"; } - } - TABLEBODY() { - for (auto& row : TableData) { - TABLER() { + { + HTML(os) { + TABLE() { + TABLEHEAD() { + TABLEH() { os << "Groups"; } + TABLEH() { os << "Name"; } + TABLEH() { os << "Params"; } + TABLEH() { os << "ExecCount"; } + } + TABLEBODY() { + for (auto& row : TableData) { + TABLER() { for (TString& cell : row) { - TABLED() { os << cell; } - } - } - } - } - } - } - } -private: + TABLED() { os << cell; } + } + } + } + } + } + } + } +private: TString GroupHtml(const TString& group) - { - TStringStream ss; - ss << "<div class=\"dropdown\" style=\"display:inline-block\">" - "<a href=\"#\" data-toggle=\"dropdown\">" << group << "</a>" - "<ul class=\"dropdown-menu\">" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(group).Id() << "'});\">" - "Trace 1000 items</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(group, 10000).Id() << "'});\">" - "Trace 10000 items</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(group, 0, 1000000).Id() << "'});\">" - "Trace 1 second</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(group, 0, 10000000).Id() << "'});\">" - "Trace 10 seconds</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(group, 0, 0, true).Id() << "'});\">" - "Trace 1000 tracks</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(group, 10000, 0, true).Id() << "'});\">" - "Trace 10000 tracks</a></li>" - "</ul>" - "</div>"; - return ss.Str(); - } - + { + TStringStream ss; + ss << "<div class=\"dropdown\" style=\"display:inline-block\">" + "<a href=\"#\" data-toggle=\"dropdown\">" << group << "</a>" + "<ul class=\"dropdown-menu\">" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(group).Id() << "'});\">" + "Trace 1000 items</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(group, 10000).Id() << "'});\">" + "Trace 10000 items</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(group, 0, 1000000).Id() << "'});\">" + "Trace 1 second</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(group, 0, 10000000).Id() << "'});\">" + "Trace 10 seconds</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(group, 0, 0, true).Id() << "'});\">" + "Trace 1000 tracks</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(group, 10000, 0, true).Id() << "'});\">" + "Trace 10000 tracks</a></li>" + "</ul>" + "</div>"; + return ss.Str(); + } + TString ProbeHtml(const TString& provider, const TString& probe) - { - TStringStream ss; - ss << "<div class=\"dropdown\">" - "<a href=\"#\" data-toggle=\"dropdown\">" << probe << "</a>" - "<ul class=\"dropdown-menu\">" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(provider, probe).Id() << "'});\">" - "Trace 1000 items</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(provider, probe, 10000).Id() << "'});\">" - "Trace 10000 items</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(provider, probe, 0, 1000000).Id() << "'});\">" - "Trace 1 second</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(provider, probe, 0, 10000000).Id() << "'});\">" - "Trace 10 seconds</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(provider, probe, 0, 0, true).Id() << "'});\">" - "Trace 1000 tracks</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," - "{id:'" << TAdHocTraceConfig(provider, probe, 10000, 0, true).Id() << "'});\">" - "Trace 10000 tracks</a></li>" - "</ul>" - "</div>"; - return ss.Str(); - } + { + TStringStream ss; + ss << "<div class=\"dropdown\">" + "<a href=\"#\" data-toggle=\"dropdown\">" << probe << "</a>" + "<ul class=\"dropdown-menu\">" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(provider, probe).Id() << "'});\">" + "Trace 1000 items</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(provider, probe, 10000).Id() << "'});\">" + "Trace 10000 items</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(provider, probe, 0, 1000000).Id() << "'});\">" + "Trace 1 second</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(provider, probe, 0, 10000000).Id() << "'});\">" + "Trace 10 seconds</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(provider, probe, 0, 0, true).Id() << "'});\">" + "Trace 1000 tracks</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "'," + "{id:'" << TAdHocTraceConfig(provider, probe, 10000, 0, true).Id() << "'});\">" + "Trace 10000 tracks</a></li>" + "</ul>" + "</div>"; + return ss.Str(); + } }; -void TDashboardRegistry::Register(const NLWTrace::TDashboard& dashboard) { +void TDashboardRegistry::Register(const NLWTrace::TDashboard& dashboard) { TGuard<TMutex> g(Mutex); Dashboards[dashboard.GetName()] = dashboard; } -void TDashboardRegistry::Register(const TVector<NLWTrace::TDashboard>& dashboards) { - for (const auto& dashboard : dashboards) { - Register(dashboard); - } -} - +void TDashboardRegistry::Register(const TVector<NLWTrace::TDashboard>& dashboards) { + for (const auto& dashboard : dashboards) { + Register(dashboard); + } +} + void TDashboardRegistry::Register(const TString& dashText) { - NLWTrace::TDashboard dash; + NLWTrace::TDashboard dash; if (!google::protobuf::TextFormat::ParseFromString(dashText, &dash)) { ythrow yexception() << "Couldn't parse into dashboard"; } Register(dash); } -bool TDashboardRegistry::Get(const TString& name, NLWTrace::TDashboard& dash) { +bool TDashboardRegistry::Get(const TString& name, NLWTrace::TDashboard& dash) { TGuard<TMutex> g(Mutex); if (!Dashboards.contains(name)) { return false; @@ -1698,488 +1698,488 @@ void TDashboardRegistry::Output(TStringStream& ss) { } } -class ILogSource { -public: - virtual ~ILogSource() {} +class ILogSource { +public: + virtual ~ILogSource() {} virtual TString GetId() = 0; - virtual TInstant GetStartTime() = 0; - virtual TDuration GetTimeout(TInstant now) = 0; - virtual ui64 GetEventsCount() = 0; - virtual ui64 GetThreadsCount() = 0; -}; - -class TTraceLogSource : public ILogSource { -private: + virtual TInstant GetStartTime() = 0; + virtual TDuration GetTimeout(TInstant now) = 0; + virtual ui64 GetEventsCount() = 0; + virtual ui64 GetThreadsCount() = 0; +}; + +class TTraceLogSource : public ILogSource { +private: TString Id; - const TTraceCleaner& Cleaner; - const NLWTrace::TSession* Trace; -public: - TTraceLogSource(const TString& id, const NLWTrace::TSession* trace, const TTraceCleaner& cleaner) - : Id(id) - , Cleaner(cleaner) - , Trace(trace) - {} - + const TTraceCleaner& Cleaner; + const NLWTrace::TSession* Trace; +public: + TTraceLogSource(const TString& id, const NLWTrace::TSession* trace, const TTraceCleaner& cleaner) + : Id(id) + , Cleaner(cleaner) + , Trace(trace) + {} + TString GetId() override - { - return Id; - } - - TInstant GetStartTime() override - { - return Trace->GetStartTime(); - } - - TDuration GetTimeout(TInstant now) override - { - TInstant deadline = Cleaner.GetDeadline(Id); - if (deadline < now) { - return TDuration::Zero(); - } else if (deadline == TInstant::Max()) { - return TDuration::Max(); - } else { - return deadline - now; - } - } - - ui64 GetEventsCount() override - { - return Trace->GetEventsCount(); - } - - ui64 GetThreadsCount() override - { - return Trace->GetThreadsCount(); - } -}; - -class TSnapshotLogSource : public ILogSource { -private: + { + return Id; + } + + TInstant GetStartTime() override + { + return Trace->GetStartTime(); + } + + TDuration GetTimeout(TInstant now) override + { + TInstant deadline = Cleaner.GetDeadline(Id); + if (deadline < now) { + return TDuration::Zero(); + } else if (deadline == TInstant::Max()) { + return TDuration::Max(); + } else { + return deadline - now; + } + } + + ui64 GetEventsCount() override + { + return Trace->GetEventsCount(); + } + + ui64 GetThreadsCount() override + { + return Trace->GetThreadsCount(); + } +}; + +class TSnapshotLogSource : public ILogSource { +private: TString Sid; - // Log should be used for read-only purpose, because it can be accessed from multiple threads - // Atomic pointer is used to avoid thread-safety issues with snapshot deletion - // (I hope protobuf const-implementation doesn't use any mutable non-thread-safe stuff inside) - TAtomicSharedPtr<NLWTrace::TLogPb> Log; -public: - // Constructor should be called under SnapshotsMtx lock + // Log should be used for read-only purpose, because it can be accessed from multiple threads + // Atomic pointer is used to avoid thread-safety issues with snapshot deletion + // (I hope protobuf const-implementation doesn't use any mutable non-thread-safe stuff inside) + TAtomicSharedPtr<NLWTrace::TLogPb> Log; +public: + // Constructor should be called under SnapshotsMtx lock TSnapshotLogSource(const TString& sid, const TAtomicSharedPtr<NLWTrace::TLogPb>& log) - : Sid(sid) - , Log(log) - {} - + : Sid(sid) + , Log(log) + {} + TString GetId() override - { - return Sid + "~"; - } - - TInstant GetStartTime() override - { - return TInstant::MicroSeconds(Log->GetCrtTime()); - } - - TDuration GetTimeout(TInstant now) override - { - Y_UNUSED(now); - return TDuration::Max(); - } - - ui64 GetEventsCount() override - { - return Log->GetEventsCount(); - } - - ui64 GetThreadsCount() override - { - return Log->ThreadLogsSize(); - } -}; - -class TLogSources { -private: - TTraceCleaner& Cleaner; - TInstant Now; + { + return Sid + "~"; + } + + TInstant GetStartTime() override + { + return TInstant::MicroSeconds(Log->GetCrtTime()); + } + + TDuration GetTimeout(TInstant now) override + { + Y_UNUSED(now); + return TDuration::Max(); + } + + ui64 GetEventsCount() override + { + return Log->GetEventsCount(); + } + + ui64 GetThreadsCount() override + { + return Log->ThreadLogsSize(); + } +}; + +class TLogSources { +private: + TTraceCleaner& Cleaner; + TInstant Now; using TLogSourcePtr = std::unique_ptr<ILogSource>; TMap<TString, TLogSourcePtr> LogSources; -public: - explicit TLogSources(TTraceCleaner& cleaner, TInstant now = TInstant::Now()) - : Cleaner(cleaner) - , Now(now) - {} - +public: + explicit TLogSources(TTraceCleaner& cleaner, TInstant now = TInstant::Now()) + : Cleaner(cleaner) + , Now(now) + {} + void Push(const TString& sid, const TAtomicSharedPtr<NLWTrace::TLogPb>& log) - { - TLogSourcePtr ls(new TSnapshotLogSource(sid, log)); + { + TLogSourcePtr ls(new TSnapshotLogSource(sid, log)); LogSources.emplace(ls->GetId(), std::move(ls)); - } - - void Push(const TString& id, const NLWTrace::TSession* trace) - { - TLogSourcePtr ls(new TTraceLogSource(id, trace, Cleaner)); + } + + void Push(const TString& id, const NLWTrace::TSession* trace) + { + TLogSourcePtr ls(new TTraceLogSource(id, trace, Cleaner)); LogSources.emplace(ls->GetId(), std::move(ls)); - } - - template <class TFunc> - void ForEach(TFunc& func) - { - for (auto& kv : LogSources) { + } + + template <class TFunc> + void ForEach(TFunc& func) + { + for (auto& kv : LogSources) { func.Push(kv.second.get()); - } - } - - template <class TFunc> - void ForEach(TFunc& func) const - { - for (const auto& kv : LogSources) { + } + } + + template <class TFunc> + void ForEach(TFunc& func) const + { + for (const auto& kv : LogSources) { func.Push(kv.second.get()); - } - } -}; - + } + } +}; + class TTracesHtmlPrinter { private: IOutputStream& Os; - TInstant Now; + TInstant Now; public: explicit TTracesHtmlPrinter(IOutputStream& os) : Os(os) - , Now(TInstant::Now()) + , Now(TInstant::Now()) {} - void Push(ILogSource* src) + void Push(ILogSource* src) { TString id = src->GetId(); Os << "<tr>"; Os << "<td>"; try { - Os << src->GetStartTime().ToStringUpToSeconds(); + Os << src->GetStartTime().ToStringUpToSeconds(); } catch (...) { Os << "error: " << CurrentExceptionMessage(); } Os << "</td>" - << "<td><div class=\"dropdown\">" - "<a href=\"#\" data-toggle=\"dropdown\">" << TimeoutToString(src->GetTimeout(Now)) << "</a>" - "<ul class=\"dropdown-menu\">" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=60', {id:'" << id << "'});\">1 min</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=600', {id:'" << id << "'});\">10 min</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=3600', {id:'" << id << "'});\">1 hour</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=86400', {id:'" << id << "'});\">1 day</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=604800', {id:'" << id << "'});\">1 week</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y', {id:'" << id << "'});\">no timeout</a></li>" - "</ul>" - "</div></td>" + << "<td><div class=\"dropdown\">" + "<a href=\"#\" data-toggle=\"dropdown\">" << TimeoutToString(src->GetTimeout(Now)) << "</a>" + "<ul class=\"dropdown-menu\">" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=60', {id:'" << id << "'});\">1 min</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=600', {id:'" << id << "'});\">10 min</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=3600', {id:'" << id << "'});\">1 hour</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=86400', {id:'" << id << "'});\">1 day</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=604800', {id:'" << id << "'});\">1 week</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y', {id:'" << id << "'});\">no timeout</a></li>" + "</ul>" + "</div></td>" << "<td>" << EncodeHtmlPcdata(id) << "</td>" - << "<td>" << src->GetEventsCount() << "</td>" - << "<td>" << src->GetThreadsCount() << "</td>" + << "<td>" << src->GetEventsCount() << "</td>" + << "<td>" << src->GetThreadsCount() << "</td>" << "<td><a href=\"?mode=log&id=" << id << "\">Text</a></td>" << "<td><a href=\"?mode=log&format=json&id=" << id << "\">Json</a></td>" << "<td><a href=\"?mode=query&id=" << id << "\">Query</a></td>" - << "<td><a href=\"?mode=analytics&id=" << id << "\">Analytics</a></td>" - << "<td><div class=\"dropdown navbar-right\">" // navbar-right is hack to drop left - "<a href=\"#\" data-toggle=\"dropdown\">Modify</a>" - "<ul class=\"dropdown-menu\">" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=make_snapshot&ui=y', {id:'" << id << "'});\">Snapshot</a></li>" - "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=delete&ui=y', {id:'" << id << "'});\">Delete</a></li>" - "</ul>" - "</div></td>" + << "<td><a href=\"?mode=analytics&id=" << id << "\">Analytics</a></td>" + << "<td><div class=\"dropdown navbar-right\">" // navbar-right is hack to drop left + "<a href=\"#\" data-toggle=\"dropdown\">Modify</a>" + "<ul class=\"dropdown-menu\">" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=make_snapshot&ui=y', {id:'" << id << "'});\">Snapshot</a></li>" + "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=delete&ui=y', {id:'" << id << "'});\">Delete</a></li>" + "</ul>" + "</div></td>" << "</tr>\n"; } -private: +private: static TString TimeoutToString(TDuration d) - { - TStringStream ss; - if (d == TDuration::Zero()) { - ss << "0"; - } else if (d == TDuration::Max()) { - ss << "-"; - } else { - ui64 us = d.GetValue(); - ui64 ms = us / 1000; - ui64 sec = ms / 1000; - ui64 min = sec / 60; - ui64 hours = min / 60; - ui64 days = hours / 24; - ui64 weeks = days / 7; - us -= ms * 1000; - ms -= sec * 1000; - sec -= min * 60; - min -= hours * 60; - hours -= days * 24; - days -= weeks * 7; - int terms = 0; - if ((terms > 0 && terms < 2) || ( terms == 0 && weeks)) { ss << (ss.Str()? " ": "") << weeks << "w"; terms++; } - if ((terms > 0 && terms < 2) || ( terms == 0 && days)) { ss << (ss.Str()? " ": "") << days << "d"; terms++; } - if ((terms > 0 && terms < 2) || ( terms == 0 && hours)) { ss << (ss.Str()? " ": "") << hours << "h"; terms++; } - if ((terms > 0 && terms < 2) || ( terms == 0 && min)) { ss << (ss.Str()? " ": "") << min << "m"; terms++; } - if ((terms > 0 && terms < 2) || ( terms == 0 && sec)) { ss << (ss.Str()? " ": "") << sec << "s"; terms++; } - if ((terms > 0 && terms < 2) || ( terms == 0 && ms)) { ss << (ss.Str()? " ": "") << ms << "ms"; terms++; } - if ((terms > 0 && terms < 2) || ( terms == 0 && us)) { ss << (ss.Str()? " ": "") << us << "us"; terms++; } - } - return ss.Str(); - } + { + TStringStream ss; + if (d == TDuration::Zero()) { + ss << "0"; + } else if (d == TDuration::Max()) { + ss << "-"; + } else { + ui64 us = d.GetValue(); + ui64 ms = us / 1000; + ui64 sec = ms / 1000; + ui64 min = sec / 60; + ui64 hours = min / 60; + ui64 days = hours / 24; + ui64 weeks = days / 7; + us -= ms * 1000; + ms -= sec * 1000; + sec -= min * 60; + min -= hours * 60; + hours -= days * 24; + days -= weeks * 7; + int terms = 0; + if ((terms > 0 && terms < 2) || ( terms == 0 && weeks)) { ss << (ss.Str()? " ": "") << weeks << "w"; terms++; } + if ((terms > 0 && terms < 2) || ( terms == 0 && days)) { ss << (ss.Str()? " ": "") << days << "d"; terms++; } + if ((terms > 0 && terms < 2) || ( terms == 0 && hours)) { ss << (ss.Str()? " ": "") << hours << "h"; terms++; } + if ((terms > 0 && terms < 2) || ( terms == 0 && min)) { ss << (ss.Str()? " ": "") << min << "m"; terms++; } + if ((terms > 0 && terms < 2) || ( terms == 0 && sec)) { ss << (ss.Str()? " ": "") << sec << "s"; terms++; } + if ((terms > 0 && terms < 2) || ( terms == 0 && ms)) { ss << (ss.Str()? " ": "") << ms << "ms"; terms++; } + if ((terms > 0 && terms < 2) || ( terms == 0 && us)) { ss << (ss.Str()? " ": "") << us << "us"; terms++; } + } + return ss.Str(); + } }; -class TTracesLister { -private: - TVariants& Variants; -public: - TTracesLister(TVariants& variants) - : Variants(variants) - {} - void Push(ILogSource* src) - { - Variants.emplace_back(src->GetId(), src->GetId()); - } -}; - -TVariants ListTraces(const TLogSources& srcs) -{ - TVariants variants; - TTracesLister lister(variants); - srcs.ForEach(lister); - return variants; -} - -class TTimestampCutter { -private: +class TTracesLister { +private: + TVariants& Variants; +public: + TTracesLister(TVariants& variants) + : Variants(variants) + {} + void Push(ILogSource* src) + { + Variants.emplace_back(src->GetId(), src->GetId()); + } +}; + +TVariants ListTraces(const TLogSources& srcs) +{ + TVariants variants; + TTracesLister lister(variants); + srcs.ForEach(lister); + return variants; +} + +class TTimestampCutter { +private: THashMap<TThread::TId, std::pair<ui64, TInstant>> CutTsForThread; // tid -> time of first item - mutable ui64 CutTsMax = 0; - mutable TInstant CutInstantMax; - bool Enabled; - ui64 NowTs; -public: - explicit TTimestampCutter(bool enabled) - : Enabled(enabled) - , NowTs(GetCycleCount()) - {} - - void Push(TThread::TId tid, const NLWTrace::TLogItem& item) - { - auto it = CutTsForThread.find(tid); - if (it != CutTsForThread.end()) { - ui64& ts = it->second.first; - TInstant& inst = it->second.second; - ts = Min(ts, item.TimestampCycles); - inst = Min(inst, item.Timestamp); - } else { - CutTsForThread[tid] = std::make_pair(item.TimestampCycles, item.Timestamp); - } - } - - // Timestamp from which we are ensured that cyclic log for every thread is not truncated - // NOTE: should NOT be called from Push(tid, item) functions - ui64 StartTimestamp() const - { - if (CutTsMax == 0) { - FindStartTime(); - } - return CutTsMax; - } - - ui64 NowTimestamp() const - { - return NowTs; - } - - TInstant StartInstant() const - { - if (CutInstantMax == TInstant::Zero()) { - FindStartTime(); - } - return CutInstantMax; - } - - // Returns true iff item should be skipped to avoid surprizes - bool Skip(const NLWTrace::TLogItem& item) const - { - return Enabled && item.TimestampCycles < StartTimestamp(); - } - -private: - void FindStartTime() const - { - for (auto& kv : CutTsForThread) { - CutTsMax = Max(CutTsMax, kv.second.first); - CutInstantMax = Max(CutInstantMax, kv.second.second); - } - } -}; - + mutable ui64 CutTsMax = 0; + mutable TInstant CutInstantMax; + bool Enabled; + ui64 NowTs; +public: + explicit TTimestampCutter(bool enabled) + : Enabled(enabled) + , NowTs(GetCycleCount()) + {} + + void Push(TThread::TId tid, const NLWTrace::TLogItem& item) + { + auto it = CutTsForThread.find(tid); + if (it != CutTsForThread.end()) { + ui64& ts = it->second.first; + TInstant& inst = it->second.second; + ts = Min(ts, item.TimestampCycles); + inst = Min(inst, item.Timestamp); + } else { + CutTsForThread[tid] = std::make_pair(item.TimestampCycles, item.Timestamp); + } + } + + // Timestamp from which we are ensured that cyclic log for every thread is not truncated + // NOTE: should NOT be called from Push(tid, item) functions + ui64 StartTimestamp() const + { + if (CutTsMax == 0) { + FindStartTime(); + } + return CutTsMax; + } + + ui64 NowTimestamp() const + { + return NowTs; + } + + TInstant StartInstant() const + { + if (CutInstantMax == TInstant::Zero()) { + FindStartTime(); + } + return CutInstantMax; + } + + // Returns true iff item should be skipped to avoid surprizes + bool Skip(const NLWTrace::TLogItem& item) const + { + return Enabled && item.TimestampCycles < StartTimestamp(); + } + +private: + void FindStartTime() const + { + for (auto& kv : CutTsForThread) { + CutTsMax = Max(CutTsMax, kv.second.first); + CutInstantMax = Max(CutInstantMax, kv.second.second); + } + } +}; + class TLogFilter { private: - struct TFilter { + struct TFilter { TString ParamName; TString ParamValue; - bool Parsed; - - TLogQuery Query; - NLWTrace::TLiteral Value; - + bool Parsed; + + TLogQuery Query; + NLWTrace::TLiteral Value; + explicit TFilter(const TString& text) - { - if (!text) { // Neither ParamName nor ParamValue is selected - ParamName.clear(); - ParamValue.clear(); - Parsed = false; - return; - } - size_t pos = text.find('='); + { + if (!text) { // Neither ParamName nor ParamValue is selected + ParamName.clear(); + ParamValue.clear(); + Parsed = false; + return; + } + size_t pos = text.find('='); if (pos == TString::npos) { // Only ParamName has been selected - ParamName = text; - ParamValue.clear(); - Parsed = false; - return; - } - // Both ParamName and ParamValue have been selected - ParamValue = text.substr(pos + 1); - ParamName = text.substr(0, pos); - Parsed = true; - - Query = TLogQuery(ParamName); - Value = NLWTrace::TLiteral(ParamValue); - } - }; + ParamName = text; + ParamValue.clear(); + Parsed = false; + return; + } + // Both ParamName and ParamValue have been selected + ParamValue = text.substr(pos + 1); + ParamName = text.substr(0, pos); + Parsed = true; + + Query = TLogQuery(ParamName); + Value = NLWTrace::TLiteral(ParamValue); + } + }; TVector<TFilter> Filters; THashSet<const NLWTrace::TSignature*> Signatures; // Just to list param names - TVariants ParamNames; + TVariants ParamNames; THashMap<TString, THashSet<TString>> FilteredParamValues; // paramName -> { paramValue } public: explicit TLogFilter(const TVector<TString>& filters) { for (const TString& subvalue : filters) { - TFilter filter(subvalue); - FilteredParamValues[filter.ParamName]; // just create empty set to gather values later - if (filter.Parsed) { - Filters.push_back(filter); - } + TFilter filter(subvalue); + FilteredParamValues[filter.ParamName]; // just create empty set to gather values later + if (filter.Parsed) { + Filters.push_back(filter); + } } } - virtual ~TLogFilter() {} - - template <class TLog> - bool Filter(const TLog& log) + virtual ~TLogFilter() {} + + template <class TLog> + bool Filter(const TLog& log) { - Gather(log); - for (const TFilter& filter : Filters) { - if (filter.Query.ExecuteQuery(log) != filter.Value) { - return false; + Gather(log); + for (const TFilter& filter : Filters) { + if (filter.Query.ExecuteQuery(log) != filter.Value) { + return false; } } - return true; + return true; } - + void FilterSelectors(TStringStream& ss, const TCgiParameters& e, const TString& fparam) - { - bool first = true; - bool allParsed = true; + { + bool first = true; + bool allParsed = true; for (const TString& subvalue : Subvalues(e, fparam)) { - TFilter filter(subvalue); - allParsed = allParsed && filter.Parsed; - if (first) { - SelectorTitle(ss, "where"); - } - DropdownSelector<Erasable | CompositeValue, true>( - ss, e, fparam, subvalue, first? "": ", ", ListParamNames(), - filter.ParamName - ); - if (filter.ParamName) { - DropdownSelector<Link | CompositeValue, true>( - ss, e, fparam, subvalue, "=", ListParamValues(filter.ParamName), - filter.ParamValue? (filter.ParamName + "=" + filter.ParamValue): "" - ); - } - first = false; - } - - if (!allParsed) { - throw TPageGen<TSelectorsContainer>(ss.Str()); - } else { - BtnHref<Button|ExtraSmall>(ss, first? "where": "+", MakeUrlAddSub(e, fparam, "")); - } - } - - const TVariants& ListParamNames() - { - if (ParamNames.empty()) { + TFilter filter(subvalue); + allParsed = allParsed && filter.Parsed; + if (first) { + SelectorTitle(ss, "where"); + } + DropdownSelector<Erasable | CompositeValue, true>( + ss, e, fparam, subvalue, first? "": ", ", ListParamNames(), + filter.ParamName + ); + if (filter.ParamName) { + DropdownSelector<Link | CompositeValue, true>( + ss, e, fparam, subvalue, "=", ListParamValues(filter.ParamName), + filter.ParamValue? (filter.ParamName + "=" + filter.ParamValue): "" + ); + } + first = false; + } + + if (!allParsed) { + throw TPageGen<TSelectorsContainer>(ss.Str()); + } else { + BtnHref<Button|ExtraSmall>(ss, first? "where": "+", MakeUrlAddSub(e, fparam, "")); + } + } + + const TVariants& ListParamNames() + { + if (ParamNames.empty()) { THashSet<TString> paramNames; - for (const NLWTrace::TSignature* sgn: Signatures) { - for (size_t pi = 0; pi < sgn->ParamCount; pi++) { - paramNames.insert(sgn->ParamNames[pi]); - } - } - for (auto& pn : paramNames) { - ParamNames.emplace_back(pn, pn); - } - } - return ParamNames; - } - + for (const NLWTrace::TSignature* sgn: Signatures) { + for (size_t pi = 0; pi < sgn->ParamCount; pi++) { + paramNames.insert(sgn->ParamNames[pi]); + } + } + for (auto& pn : paramNames) { + ParamNames.emplace_back(pn, pn); + } + } + return ParamNames; + } + bool IsFiltered(const TString& paramName) const - { + { return FilteredParamValues.contains(paramName); - } - -private: - // Gather param names and values for selectors - void Gather(const NLWTrace::TLogItem& item) - { - Signatures.insert(&item.Probe->Event.Signature); - if (!FilteredParamValues.empty() && item.SavedParamsCount > 0) { + } + +private: + // Gather param names and values for selectors + void Gather(const NLWTrace::TLogItem& item) + { + Signatures.insert(&item.Probe->Event.Signature); + if (!FilteredParamValues.empty() && item.SavedParamsCount > 0) { TString paramValues[LWTRACE_MAX_PARAMS]; - item.Probe->Event.Signature.SerializeParams(item.Params, paramValues); - for (size_t pi = 0; pi < item.SavedParamsCount; pi++) { - auto iter = FilteredParamValues.find(item.Probe->Event.Signature.ParamNames[pi]); - if (iter != FilteredParamValues.end()) { - iter->second.insert(paramValues[pi]); - } - } - } - } - - void Gather(const NLWTrace::TTrackLog& tl) - { - for (const NLWTrace::TLogItem& item : tl.Items) { - Gather(item); - } - } - + item.Probe->Event.Signature.SerializeParams(item.Params, paramValues); + for (size_t pi = 0; pi < item.SavedParamsCount; pi++) { + auto iter = FilteredParamValues.find(item.Probe->Event.Signature.ParamNames[pi]); + if (iter != FilteredParamValues.end()) { + iter->second.insert(paramValues[pi]); + } + } + } + } + + void Gather(const NLWTrace::TTrackLog& tl) + { + for (const NLWTrace::TLogItem& item : tl.Items) { + Gather(item); + } + } + TVariants ListParamValues(const TString& paramName) const - { - TVariants result; - auto iter = FilteredParamValues.find(paramName); - if (iter != FilteredParamValues.end()) { + { + TVariants result; + auto iter = FilteredParamValues.find(paramName); + if (iter != FilteredParamValues.end()) { for (const TString& paramValue : iter->second) { - result.emplace_back(paramName + "=" + paramValue, paramValue); - } - } - Sort(result.begin(), result.end()); - return result; - } + result.emplace_back(paramName + "=" + paramValue, paramValue); + } + } + Sort(result.begin(), result.end()); + return result; + } }; -static void EscapeJSONString(IOutputStream& os, const TString& s) -{ - for (TString::const_iterator i = s.begin(), e = s.end(); i != e; ++i) { - char c = *i; - if (c < ' ') { - os << Sprintf("\\u%04x", int(c)); - } else if (c == '"') { - os << "\\\""; - } else if (c == '\\') { - os << "\\\\"; - } else { - os << c; - } - } -} - -static TString EscapeJSONString(const TString& s) -{ - TStringStream ss; - EscapeJSONString(ss, s); - return ss.Str(); -} - +static void EscapeJSONString(IOutputStream& os, const TString& s) +{ + for (TString::const_iterator i = s.begin(), e = s.end(); i != e; ++i) { + char c = *i; + if (c < ' ') { + os << Sprintf("\\u%04x", int(c)); + } else if (c == '"') { + os << "\\\""; + } else if (c == '\\') { + os << "\\\\"; + } else { + os << c; + } + } +} + +static TString EscapeJSONString(const TString& s) +{ + TStringStream ss; + EscapeJSONString(ss, s); + return ss.Str(); +} + class TLogJsonPrinter { private: IOutputStream& Os; @@ -2199,15 +2199,15 @@ public: ; } - void OutputFooter(const NLWTrace::TSession* trace) + void OutputFooter(const NLWTrace::TSession* trace) { Os << "\n\t\t]" "\n\t, \"threads\": [" ; - trace->ReadThreads(*this); + trace->ReadThreads(*this); Os << "]" - "\n\t, \"events_count\": " << trace->GetEventsCount() << - "\n\t, \"threads_count\": " << trace->GetThreadsCount() << + "\n\t, \"events_count\": " << trace->GetEventsCount() << + "\n\t, \"threads_count\": " << trace->GetThreadsCount() << "\n\t, \"timestamp\": " << Now().GetValue() << "\n}" ; @@ -2219,7 +2219,7 @@ public: FirstThread = false; } - void Push(TThread::TId tid, const NLWTrace::TLogItem& item) + void Push(TThread::TId tid, const NLWTrace::TLogItem& item) { Os << "\n\t\t" << (FirstItem? "": ", "); FirstItem = false; @@ -2246,31 +2246,31 @@ public: class TLogTextPrinter : public TLogFilter { private: - TMultiMap<NLWTrace::TTypedParam, std::pair<TThread::TId, NLWTrace::TLogItem> > Items; - TMultiMap<NLWTrace::TTypedParam, NLWTrace::TTrackLog> Depot; - THashMap<NLWTrace::TProbe*, size_t> ProbeId; - TVector<NLWTrace::TProbe*> Probes; - TTimestampCutter CutTs; - TLogQuery Order; - bool ReverseOrder = false; - ui64 Head = 0; - ui64 Tail = 0; - bool ShowTs = false; + TMultiMap<NLWTrace::TTypedParam, std::pair<TThread::TId, NLWTrace::TLogItem> > Items; + TMultiMap<NLWTrace::TTypedParam, NLWTrace::TTrackLog> Depot; + THashMap<NLWTrace::TProbe*, size_t> ProbeId; + TVector<NLWTrace::TProbe*> Probes; + TTimestampCutter CutTs; + TLogQuery Order; + bool ReverseOrder = false; + ui64 Head = 0; + ui64 Tail = 0; + bool ShowTs = false; public: - TLogTextPrinter(const TVector<TString>& filters, ui64 head, ui64 tail, const TString& order, bool reverseOrder, bool cutTs, bool showTs) - : TLogFilter(filters) - , CutTs(cutTs) - , Order(order) - , ReverseOrder(reverseOrder) - , Head(head) - , Tail(tail) - , ShowTs(showTs) - {} - + TLogTextPrinter(const TVector<TString>& filters, ui64 head, ui64 tail, const TString& order, bool reverseOrder, bool cutTs, bool showTs) + : TLogFilter(filters) + , CutTs(cutTs) + , Order(order) + , ReverseOrder(reverseOrder) + , Head(head) + , Tail(tail) + , ShowTs(showTs) + {} + TLogTextPrinter(const TCgiParameters& e) : TLogTextPrinter( - Subvalues(e, "f"), - e.Has("head")? FromString<ui64>(e.Get("head")): 0, + Subvalues(e, "f"), + e.Has("head")? FromString<ui64>(e.Get("head")): 0, e.Has("tail")? FromString<ui64>(e.Get("tail")): 0, e.Get("s"), e.Get("reverse") == "y", @@ -2278,1630 +2278,1630 @@ public: e.Get("showts") == "y") {} - enum EFormat { - Text, - Json - }; - + enum EFormat { + Text, + Json + }; + void Output(IOutputStream& os) const { - OutputItems<Text>(os); - OutputDepot<Text>(os); - } - - void OutputJson(IOutputStream& os) const - { - os << "{\"depot\":[\n"; - OutputItems<Json>(os); - OutputDepot<Json>(os); - os << "],\"probes\":["; - bool first = true; - for (const NLWTrace::TProbe* probe : Probes) { - os << (first? "": ",") << "{\"provider\":\"" << probe->Event.GetProvider() - << "\",\"name\":\"" << probe->Event.Name << "\"}"; - first = false; - } - os << "]}"; - } - - NLWTrace::TTypedParam GetKey(const NLWTrace::TLogItem& item) - { - return Order? Order.ExecuteQuery(item): NLWTrace::TTypedParam(item.GetTimestampCycles()); - } - - NLWTrace::TTypedParam GetKey(const NLWTrace::TTrackLog& tl) - { - return Order? Order.ExecuteQuery(tl): NLWTrace::TTypedParam(tl.GetTimestampCycles()); - } - - void Push(TThread::TId tid, const NLWTrace::TLogItem& item) - { - CutTs.Push(tid, item); + OutputItems<Text>(os); + OutputDepot<Text>(os); + } + + void OutputJson(IOutputStream& os) const + { + os << "{\"depot\":[\n"; + OutputItems<Json>(os); + OutputDepot<Json>(os); + os << "],\"probes\":["; + bool first = true; + for (const NLWTrace::TProbe* probe : Probes) { + os << (first? "": ",") << "{\"provider\":\"" << probe->Event.GetProvider() + << "\",\"name\":\"" << probe->Event.Name << "\"}"; + first = false; + } + os << "]}"; + } + + NLWTrace::TTypedParam GetKey(const NLWTrace::TLogItem& item) + { + return Order? Order.ExecuteQuery(item): NLWTrace::TTypedParam(item.GetTimestampCycles()); + } + + NLWTrace::TTypedParam GetKey(const NLWTrace::TTrackLog& tl) + { + return Order? Order.ExecuteQuery(tl): NLWTrace::TTypedParam(tl.GetTimestampCycles()); + } + + void Push(TThread::TId tid, const NLWTrace::TLogItem& item) + { + CutTs.Push(tid, item); if (Filter(item)) { - AddId(item); - Items.emplace(GetKey(item), std::make_pair(tid, item)); - } - } - - void Push(TThread::TId tid, const NLWTrace::TTrackLog& tl) - { - Y_UNUSED(tid); - if (Filter(tl)) { - AddId(tl); - Depot.emplace(GetKey(tl), tl); - } - } - + AddId(item); + Items.emplace(GetKey(item), std::make_pair(tid, item)); + } + } + + void Push(TThread::TId tid, const NLWTrace::TTrackLog& tl) + { + Y_UNUSED(tid); + if (Filter(tl)) { + AddId(tl); + Depot.emplace(GetKey(tl), tl); + } + } + private: - void AddId(const NLWTrace::TLogItem& item) - { - if (ProbeId.find(item.Probe) == ProbeId.end()) { - size_t id = Probes.size(); - ProbeId[item.Probe] = id; - Probes.emplace_back(item.Probe); - } - } - - void AddId(const NLWTrace::TTrackLog& tl) - { - for (const auto& item : tl.Items) { - AddId(item); - } - } - - bool HeadTailFilter(ui64 idx, ui64 size) const - { - bool headOk = idx < Head; - bool tailOk = size < Tail + idx + 1ull; - if (Head && Tail) { - return headOk || tailOk; - } else if (Head) { - return headOk; - } else if (Tail) { - return tailOk; - } else { - return true; - } - } - - template <EFormat Format> + void AddId(const NLWTrace::TLogItem& item) + { + if (ProbeId.find(item.Probe) == ProbeId.end()) { + size_t id = Probes.size(); + ProbeId[item.Probe] = id; + Probes.emplace_back(item.Probe); + } + } + + void AddId(const NLWTrace::TTrackLog& tl) + { + for (const auto& item : tl.Items) { + AddId(item); + } + } + + bool HeadTailFilter(ui64 idx, ui64 size) const + { + bool headOk = idx < Head; + bool tailOk = size < Tail + idx + 1ull; + if (Head && Tail) { + return headOk || tailOk; + } else if (Head) { + return headOk; + } else if (Tail) { + return tailOk; + } else { + return true; + } + } + + template <EFormat Format> void OutputItems(IOutputStream& os) const - { - ui64 idx = 0; - ui64 size = Items.size(); - ui64 startTs = ShowTs? CutTs.StartTimestamp(): 0; - ui64 prevTs = 0; - bool first = true; - if (!ReverseOrder) { - for (auto i = Items.begin(), e = Items.end(); i != e; ++i, idx++) { - if (HeadTailFilter(idx, size)) { - OutputItem<Format, true>(os, i->second.first, i->second.second, startTs, prevTs, first); - prevTs = startTs? i->second.second.GetTimestampCycles(): 0; - } - } - } else { - for (auto i = Items.rbegin(), e = Items.rend(); i != e; ++i, idx++) { - if (HeadTailFilter(idx, size)) { - OutputItem<Format, true>(os, i->second.first, i->second.second, startTs, prevTs, first); - prevTs = startTs? i->second.second.GetTimestampCycles(): 0; - } - } - } - } - - template <EFormat Format> + { + ui64 idx = 0; + ui64 size = Items.size(); + ui64 startTs = ShowTs? CutTs.StartTimestamp(): 0; + ui64 prevTs = 0; + bool first = true; + if (!ReverseOrder) { + for (auto i = Items.begin(), e = Items.end(); i != e; ++i, idx++) { + if (HeadTailFilter(idx, size)) { + OutputItem<Format, true>(os, i->second.first, i->second.second, startTs, prevTs, first); + prevTs = startTs? i->second.second.GetTimestampCycles(): 0; + } + } + } else { + for (auto i = Items.rbegin(), e = Items.rend(); i != e; ++i, idx++) { + if (HeadTailFilter(idx, size)) { + OutputItem<Format, true>(os, i->second.first, i->second.second, startTs, prevTs, first); + prevTs = startTs? i->second.second.GetTimestampCycles(): 0; + } + } + } + } + + template <EFormat Format> void OutputDepot(IOutputStream& os) const - { - ui64 idx = 0; - ui64 size = Depot.size(); - bool first = true; - if (!ReverseOrder) { - for (auto i = Depot.begin(), e = Depot.end(); i != e; ++i, idx++) { - if (HeadTailFilter(idx, size)) { - OutputTrackLog<Format>(os, i->second, first); - } - } - } else { - for (auto i = Depot.rbegin(), e = Depot.rend(); i != e; ++i, idx++) { - if (HeadTailFilter(idx, size)) { - OutputTrackLog<Format>(os, i->second, first); - } - } - } - } - - template <EFormat Format, bool AsTrack = false> - void OutputItem(IOutputStream& os, TThread::TId tid, const NLWTrace::TLogItem& item, ui64 startTs, ui64 prevTs, bool& first) const - { - if (CutTs.Skip(item)) { - return; - } - if constexpr (Format == Text) { - if (startTs) { - if (!prevTs) { - prevTs = item.GetTimestampCycles(); - } - os << Sprintf("%10.3lf %+10.3lf ms ", - NHPTimer::GetSeconds(item.GetTimestampCycles() - startTs) * 1000.0, - NHPTimer::GetSeconds(item.GetTimestampCycles() - prevTs) * 1000.0); - } - if (tid) { - os << "<" << tid << "> "; - } - if (item.Timestamp != TInstant::Zero()) { - os << "[" << item.Timestamp << "] "; - } else { - os << "[" << item.TimestampCycles << "] "; - } - os << GetProbeName(item.Probe) << "("; - if (item.SavedParamsCount > 0) { - TString ParamValues[LWTRACE_MAX_PARAMS]; - item.Probe->Event.Signature.SerializeParams(item.Params, ParamValues); - bool first = true; - for (size_t i = 0; i < item.SavedParamsCount; i++, first = false) { - os << (first? "": ", ") << item.Probe->Event.Signature.ParamNames[i] << "='" << EscapeC(ParamValues[i]) << "'"; - } - } - os << ")\n"; - } else if constexpr (Format == Json) { - if (auto probeId = ProbeId.find(item.Probe); probeId != ProbeId.end()) { - os << (first? "": ",") << (AsTrack? "[":"") << "[\"" << tid << "\",\""; - if (item.Timestamp != TInstant::Zero()) { - os << item.Timestamp.MicroSeconds(); - } else { - os << Sprintf("%.3lf", NHPTimer::GetSeconds(item.TimestampCycles) * 1e9); - } - os << "\"," << probeId->second << ",{"; - if (item.SavedParamsCount > 0) { - TString ParamValues[LWTRACE_MAX_PARAMS]; - item.Probe->Event.Signature.SerializeParams(item.Params, ParamValues); - bool first = true; - for (size_t i = 0; i < item.SavedParamsCount; i++, first = false) { - os << (first? "": ",") << "\"" << item.Probe->Event.Signature.ParamNames[i] << "\":\""; - EscapeJSONString(os, ParamValues[i]); - os << "\""; - } - } - os << "}]" << (AsTrack? "]":""); - } - } - first = false; - } - - template <EFormat Format> - void OutputTrackLog(IOutputStream& os, const NLWTrace::TTrackLog& tl, bool& first) const - { - if constexpr (Format == Json) { - os << (first? "": ",") << "["; - } - first = false; - ui64 prevTs = tl.GetTimestampCycles(); - bool firstItem = true; - for (const NLWTrace::TTrackLog::TItem& item: tl.Items) { - OutputItem<Format>(os, item.ThreadId, item, tl.GetTimestampCycles(), prevTs, firstItem); - prevTs = item.GetTimestampCycles(); - } - if constexpr (Format == Json) { - os << "]"; - } - os << "\n"; - } + { + ui64 idx = 0; + ui64 size = Depot.size(); + bool first = true; + if (!ReverseOrder) { + for (auto i = Depot.begin(), e = Depot.end(); i != e; ++i, idx++) { + if (HeadTailFilter(idx, size)) { + OutputTrackLog<Format>(os, i->second, first); + } + } + } else { + for (auto i = Depot.rbegin(), e = Depot.rend(); i != e; ++i, idx++) { + if (HeadTailFilter(idx, size)) { + OutputTrackLog<Format>(os, i->second, first); + } + } + } + } + + template <EFormat Format, bool AsTrack = false> + void OutputItem(IOutputStream& os, TThread::TId tid, const NLWTrace::TLogItem& item, ui64 startTs, ui64 prevTs, bool& first) const + { + if (CutTs.Skip(item)) { + return; + } + if constexpr (Format == Text) { + if (startTs) { + if (!prevTs) { + prevTs = item.GetTimestampCycles(); + } + os << Sprintf("%10.3lf %+10.3lf ms ", + NHPTimer::GetSeconds(item.GetTimestampCycles() - startTs) * 1000.0, + NHPTimer::GetSeconds(item.GetTimestampCycles() - prevTs) * 1000.0); + } + if (tid) { + os << "<" << tid << "> "; + } + if (item.Timestamp != TInstant::Zero()) { + os << "[" << item.Timestamp << "] "; + } else { + os << "[" << item.TimestampCycles << "] "; + } + os << GetProbeName(item.Probe) << "("; + if (item.SavedParamsCount > 0) { + TString ParamValues[LWTRACE_MAX_PARAMS]; + item.Probe->Event.Signature.SerializeParams(item.Params, ParamValues); + bool first = true; + for (size_t i = 0; i < item.SavedParamsCount; i++, first = false) { + os << (first? "": ", ") << item.Probe->Event.Signature.ParamNames[i] << "='" << EscapeC(ParamValues[i]) << "'"; + } + } + os << ")\n"; + } else if constexpr (Format == Json) { + if (auto probeId = ProbeId.find(item.Probe); probeId != ProbeId.end()) { + os << (first? "": ",") << (AsTrack? "[":"") << "[\"" << tid << "\",\""; + if (item.Timestamp != TInstant::Zero()) { + os << item.Timestamp.MicroSeconds(); + } else { + os << Sprintf("%.3lf", NHPTimer::GetSeconds(item.TimestampCycles) * 1e9); + } + os << "\"," << probeId->second << ",{"; + if (item.SavedParamsCount > 0) { + TString ParamValues[LWTRACE_MAX_PARAMS]; + item.Probe->Event.Signature.SerializeParams(item.Params, ParamValues); + bool first = true; + for (size_t i = 0; i < item.SavedParamsCount; i++, first = false) { + os << (first? "": ",") << "\"" << item.Probe->Event.Signature.ParamNames[i] << "\":\""; + EscapeJSONString(os, ParamValues[i]); + os << "\""; + } + } + os << "}]" << (AsTrack? "]":""); + } + } + first = false; + } + + template <EFormat Format> + void OutputTrackLog(IOutputStream& os, const NLWTrace::TTrackLog& tl, bool& first) const + { + if constexpr (Format == Json) { + os << (first? "": ",") << "["; + } + first = false; + ui64 prevTs = tl.GetTimestampCycles(); + bool firstItem = true; + for (const NLWTrace::TTrackLog::TItem& item: tl.Items) { + OutputItem<Format>(os, item.ThreadId, item, tl.GetTimestampCycles(), prevTs, firstItem); + prevTs = item.GetTimestampCycles(); + } + if constexpr (Format == Json) { + os << "]"; + } + os << "\n"; + } }; -class TLogAnalyzer: public TLogFilter { -private: +class TLogAnalyzer: public TLogFilter { +private: TMultiMap<ui64, std::pair<TThread::TId, NLWTrace::TLogItem>> Items; TVector<NLWTrace::TTrackLog> Depot; THashMap<TString, TTrackLogRefs> Groups; - NAnalytics::TTable Table; - bool TableCreated = false; + NAnalytics::TTable Table; + bool TableCreated = false; TVector<TString> GroupBy; - TTimestampCutter CutTs; -public: + TTimestampCutter CutTs; +public: TLogAnalyzer(const TVector<TString>& filters, const TVector<TString>& groupBy, bool cutTs) - : TLogFilter(filters) - , CutTs(cutTs) - { + : TLogFilter(filters) + , CutTs(cutTs) + { for (const TString& groupParam : groupBy) { - GroupBy.push_back(groupParam); - } - } - - const NAnalytics::TTable& GetTable() - { - if (!TableCreated) { - TableCreated = true; - if (GroupBy.empty()) { - for (auto i = Items.begin(), e = Items.end(); i != e; ++i) { - ParseItems(i->second.first, i->second.second); - } - ParseDepot(); - } else { - for (auto i = Items.begin(), e = Items.end(); i != e; ++i) { - Map(i->second.first, i->second.second); - } - Reduce(); - } - } - return Table; - } - - void Push(TThread::TId tid, const NLWTrace::TLogItem& item) - { - CutTs.Push(tid, item); - if (Filter(item)) { - Items.emplace(item.TimestampCycles, std::make_pair(tid, item)); - } - } - - void Push(TThread::TId, const NLWTrace::TTrackLog& tl) - { - if (Filter(tl)) { - Depot.emplace_back(tl); - } - } -private: - void FillRow(NAnalytics::TRow& row, const NLWTrace::TLogItem& item) - { - if (item.SavedParamsCount > 0) { + GroupBy.push_back(groupParam); + } + } + + const NAnalytics::TTable& GetTable() + { + if (!TableCreated) { + TableCreated = true; + if (GroupBy.empty()) { + for (auto i = Items.begin(), e = Items.end(); i != e; ++i) { + ParseItems(i->second.first, i->second.second); + } + ParseDepot(); + } else { + for (auto i = Items.begin(), e = Items.end(); i != e; ++i) { + Map(i->second.first, i->second.second); + } + Reduce(); + } + } + return Table; + } + + void Push(TThread::TId tid, const NLWTrace::TLogItem& item) + { + CutTs.Push(tid, item); + if (Filter(item)) { + Items.emplace(item.TimestampCycles, std::make_pair(tid, item)); + } + } + + void Push(TThread::TId, const NLWTrace::TTrackLog& tl) + { + if (Filter(tl)) { + Depot.emplace_back(tl); + } + } +private: + void FillRow(NAnalytics::TRow& row, const NLWTrace::TLogItem& item) + { + if (item.SavedParamsCount > 0) { TString paramValues[LWTRACE_MAX_PARAMS]; - item.Probe->Event.Signature.SerializeParams(item.Params, paramValues); - for (size_t i = 0; i < item.SavedParamsCount; i++) { + item.Probe->Event.Signature.SerializeParams(item.Params, paramValues); + for (size_t i = 0; i < item.SavedParamsCount; i++) { double value = FromString<double>(paramValues[i].data(), paramValues[i].size(), NAN); // If value cannot be cast to double or is inf/nan -- assume it's a string - if (isfinite(value)) { - row[item.Probe->Event.Signature.ParamNames[i]] = value; + if (isfinite(value)) { + row[item.Probe->Event.Signature.ParamNames[i]] = value; } else { row[item.Probe->Event.Signature.ParamNames[i]] = paramValues[i]; - } - } - } - } - + } + } + } + } + TString GetParam(const NLWTrace::TLogItem& item, TString* paramValues, const TString& paramName) - { - for (size_t pi = 0; pi < item.SavedParamsCount; pi++) { - if (paramName == item.Probe->Event.Signature.ParamNames[pi]) { - return paramValues[pi]; - } - } + { + for (size_t pi = 0; pi < item.SavedParamsCount; pi++) { + if (paramName == item.Probe->Event.Signature.ParamNames[pi]) { + return paramValues[pi]; + } + } return TString(); - } - + } + TString GetGroup(const NLWTrace::TLogItem& item, TString* paramValues) - { - TStringStream ss; - bool first = true; + { + TStringStream ss; + bool first = true; for (const TString& groupParam : GroupBy) { - ss << (first? "": "|") << GetParam(item, paramValues, groupParam); - first = false; - } - return ss.Str(); - } - - void ParseItems(TThread::TId tid, const NLWTrace::TLogItem& item) - { - if (CutTs.Skip(item)) { - return; - } + ss << (first? "": "|") << GetParam(item, paramValues, groupParam); + first = false; + } + return ss.Str(); + } + + void ParseItems(TThread::TId tid, const NLWTrace::TLogItem& item) + { + if (CutTs.Skip(item)) { + return; + } Table.emplace_back(); - NAnalytics::TRow& row = Table.back(); - row["_thread"] = tid; - if (item.Timestamp != TInstant::Zero()) { - row["_wallTime"] = item.Timestamp.SecondsFloat(); - row["_wallRTime"] = item.Timestamp.SecondsFloat() - CutTs.StartInstant().SecondsFloat(); - } - row["_cycles"] = item.TimestampCycles; - row["_thrTime"] = CyclesToDuration((ui64)item.TimestampCycles).SecondsFloat(); - row["_thrRTime"] = double(i64(item.TimestampCycles) - i64(CutTs.StartTimestamp())) / NHPTimer::GetCyclesPerSecond(); - row["_thrNTime"] = double(i64(item.TimestampCycles) - i64(CutTs.NowTimestamp())) / NHPTimer::GetCyclesPerSecond(); - row.Name = GetProbeName(item.Probe); - FillRow(row, item); - } - - void Map(TThread::TId tid, const NLWTrace::TLogItem& item) - { - if (item.SavedParamsCount > 0 && !CutTs.Skip(item)) { + NAnalytics::TRow& row = Table.back(); + row["_thread"] = tid; + if (item.Timestamp != TInstant::Zero()) { + row["_wallTime"] = item.Timestamp.SecondsFloat(); + row["_wallRTime"] = item.Timestamp.SecondsFloat() - CutTs.StartInstant().SecondsFloat(); + } + row["_cycles"] = item.TimestampCycles; + row["_thrTime"] = CyclesToDuration((ui64)item.TimestampCycles).SecondsFloat(); + row["_thrRTime"] = double(i64(item.TimestampCycles) - i64(CutTs.StartTimestamp())) / NHPTimer::GetCyclesPerSecond(); + row["_thrNTime"] = double(i64(item.TimestampCycles) - i64(CutTs.NowTimestamp())) / NHPTimer::GetCyclesPerSecond(); + row.Name = GetProbeName(item.Probe); + FillRow(row, item); + } + + void Map(TThread::TId tid, const NLWTrace::TLogItem& item) + { + if (item.SavedParamsCount > 0 && !CutTs.Skip(item)) { TString paramValues[LWTRACE_MAX_PARAMS]; - item.Probe->Event.Signature.SerializeParams(item.Params, paramValues); - TTrackLogRefs& tl = Groups[GetGroup(item, paramValues)]; - tl.Items.emplace_back(tid, item); - } - } - - void Reduce() - { - for (auto& v : Groups) { + item.Probe->Event.Signature.SerializeParams(item.Params, paramValues); + TTrackLogRefs& tl = Groups[GetGroup(item, paramValues)]; + tl.Items.emplace_back(tid, item); + } + } + + void Reduce() + { + for (auto& v : Groups) { const TString& group = v.first; - const TTrackLogRefs& tl = v.second; + const TTrackLogRefs& tl = v.second; Table.emplace_back(); - NAnalytics::TRow& row = Table.back(); - row.Name = group; - for (const NLWTrace::TLogItem& item : tl.Items) { - FillRow(row, item); - } - } - } - - void ParseDepot() - { - for (NLWTrace::TTrackLog& tl : Depot) { - Table.emplace_back(); - NAnalytics::TRow& row = Table.back(); - for (const NLWTrace::TLogItem& item : tl.Items) { - FillRow(row, item); - } - } - } -}; - -struct TSampleOpts { - bool ShowProvider = false; - size_t SizeLimit = 50; -}; - -enum ENodeType { - NT_ROOT, - NT_PROBE, - NT_PARAM -}; - -class TPatternTree; -struct TPatternNode; - -struct TTrack : public TTrackLogRefs { + NAnalytics::TRow& row = Table.back(); + row.Name = group; + for (const NLWTrace::TLogItem& item : tl.Items) { + FillRow(row, item); + } + } + } + + void ParseDepot() + { + for (NLWTrace::TTrackLog& tl : Depot) { + Table.emplace_back(); + NAnalytics::TRow& row = Table.back(); + for (const NLWTrace::TLogItem& item : tl.Items) { + FillRow(row, item); + } + } + } +}; + +struct TSampleOpts { + bool ShowProvider = false; + size_t SizeLimit = 50; +}; + +enum ENodeType { + NT_ROOT, + NT_PROBE, + NT_PARAM +}; + +class TPatternTree; +struct TPatternNode; + +struct TTrack : public TTrackLogRefs { TString TrackId; - TPatternNode* LastNode = nullptr; -}; - -using TTrackTr = TLogTraits<TTrackLogRefs>; -using TTrackIter = TTrackTr::const_iterator; - -// Visitor for tree traversing -class IVisitor { -public: - virtual ~IVisitor() {} - virtual void Visit(TPatternNode* node) = 0; -}; - -// Per-node classifier -class TClassifier { -public: - explicit TClassifier(TPatternNode* node, ENodeType childType, bool keepHead = false) - : Node(node) - , KeepHead(keepHead) - , ChildType(childType) - {} - virtual ~TClassifier() {} - virtual TPatternNode* Classify(TTrackIter cur, const TTrack& track) = 0; - virtual void Accept(IVisitor* visitor) = 0; - virtual bool IsLeaf() = 0; - ENodeType GetChildType() const { return ChildType; } -public: - TPatternNode* Node; - const bool KeepHead; - ENodeType ChildType; -}; - -// Track classification tree node -struct TPatternNode { + TPatternNode* LastNode = nullptr; +}; + +using TTrackTr = TLogTraits<TTrackLogRefs>; +using TTrackIter = TTrackTr::const_iterator; + +// Visitor for tree traversing +class IVisitor { +public: + virtual ~IVisitor() {} + virtual void Visit(TPatternNode* node) = 0; +}; + +// Per-node classifier +class TClassifier { +public: + explicit TClassifier(TPatternNode* node, ENodeType childType, bool keepHead = false) + : Node(node) + , KeepHead(keepHead) + , ChildType(childType) + {} + virtual ~TClassifier() {} + virtual TPatternNode* Classify(TTrackIter cur, const TTrack& track) = 0; + virtual void Accept(IVisitor* visitor) = 0; + virtual bool IsLeaf() = 0; + ENodeType GetChildType() const { return ChildType; } +public: + TPatternNode* Node; + const bool KeepHead; + ENodeType ChildType; +}; + +// Track classification tree node +struct TPatternNode { TString Name; - TPatternNode* Parent = nullptr; - THolder<TClassifier> Classifier; - struct TDesc { - ENodeType Type = NT_ROOT; - // NT_PROBE - const NLWTrace::TProbe* Probe = nullptr; - // NT_PARAM - size_t Rollbacks = 0; + TPatternNode* Parent = nullptr; + THolder<TClassifier> Classifier; + struct TDesc { + ENodeType Type = NT_ROOT; + // NT_PROBE + const NLWTrace::TProbe* Probe = nullptr; + // NT_PARAM + size_t Rollbacks = 0; TString ParamName; TString ParamValue; - } Desc; - - ui64 TrackCount = 0; - struct TTrackEntry { - TTrack* Track; - ui64 ResTotal; - ui64 ResLast; - - TTrackEntry(TTrack* track, ui64 resTotal, ui64 resLast) - : Track(track) - , ResTotal(resTotal) - , ResLast(resLast) - {} - }; - + } Desc; + + ui64 TrackCount = 0; + struct TTrackEntry { + TTrack* Track; + ui64 ResTotal; + ui64 ResLast; + + TTrackEntry(TTrack* track, ui64 resTotal, ui64 resLast) + : Track(track) + , ResTotal(resTotal) + , ResLast(resLast) + {} + }; + TVector<TTrackEntry> Tracks; - - ui64 ResTotalSum = 0; - ui64 ResTotalMax = 0; + + ui64 ResTotalSum = 0; + ui64 ResTotalMax = 0; TVector<ui64> ResTotalAll; - - ui64 ResLastSum = 0; - ui64 ResLastMax = 0; + + ui64 ResLastSum = 0; + ui64 ResLastMax = 0; TVector<ui64> ResLastAll; - + TVector<ui64> TimelineSum; - NAnalytics::TTable Slices; - + NAnalytics::TTable Slices; + TString GetPath() const - { - if (Parent) { - return Parent->GetPath() + Name; - } - return "/"; - } - - NAnalytics::TTable GetTable() const - { - using namespace NAnalytics; - NAnalytics::TTable ret; - for (ui64 x : ResTotalAll) { + { + if (Parent) { + return Parent->GetPath() + Name; + } + return "/"; + } + + NAnalytics::TTable GetTable() const + { + using namespace NAnalytics; + NAnalytics::TTable ret; + for (ui64 x : ResTotalAll) { ret.emplace_back(); - TRow& row = ret.back(); - row["resTotal"] = double(x) * 1000.0 / NHPTimer::GetClockRate(); - } - for (ui64 x : ResLastAll) { + TRow& row = ret.back(); + row["resTotal"] = double(x) * 1000.0 / NHPTimer::GetClockRate(); + } + for (ui64 x : ResLastAll) { ret.emplace_back(); - TRow& row = ret.back(); - row["resLast"] = double(x) * 1000.0 / NHPTimer::GetClockRate(); - } - return ret; - } - + TRow& row = ret.back(); + row["resLast"] = double(x) * 1000.0 / NHPTimer::GetClockRate(); + } + return ret; + } + template <typename TReader> void OutputSample(const TString& bn, double b1, double b2, const TSampleOpts& opts, TReader& reader) const - { - bool filterTotal = false; - if (bn == "resTotal") { - filterTotal = true; - } else { + { + bool filterTotal = false; + if (bn == "resTotal") { + filterTotal = true; + } else { WWW_CHECK(bn == "resLast", "wrong sample filter param: %s", bn.data()); - } - - size_t spaceLeft = opts.SizeLimit; - for (const TTrackEntry& entry : Tracks) { - const TTrack* track = entry.Track; - // Filter out tracks that are not in sample - if (filterTotal) { - double resTotalMs = double(entry.ResTotal) * 1000.0 / NHPTimer::GetClockRate(); - if (resTotalMs < b1 || resTotalMs > b2) { - continue; - } - } else { - double resLastMs = double(entry.ResLast) * 1000.0 / NHPTimer::GetClockRate(); - if (resLastMs < b1 || resLastMs > b2) { - continue; - } - } - + } + + size_t spaceLeft = opts.SizeLimit; + for (const TTrackEntry& entry : Tracks) { + const TTrack* track = entry.Track; + // Filter out tracks that are not in sample + if (filterTotal) { + double resTotalMs = double(entry.ResTotal) * 1000.0 / NHPTimer::GetClockRate(); + if (resTotalMs < b1 || resTotalMs > b2) { + continue; + } + } else { + double resLastMs = double(entry.ResLast) * 1000.0 / NHPTimer::GetClockRate(); + if (resLastMs < b1 || resLastMs > b2) { + continue; + } + } + NLWTrace::TTrackLog tl; for (TTrackIter i = TTrackTr::begin(*track), e = TTrackTr::end(*track); i != e; ++i) { - const NLWTrace::TLogItem& item = *i; + const NLWTrace::TLogItem& item = *i; const auto threadId = i->ThreadId; tl.Items.push_back(NLWTrace::TTrackLog::TItem(threadId, item)); - } + } reader.Push(0, tl); - if (spaceLeft) { - spaceLeft--; - if (!spaceLeft) { - break; - } - } - } - } -}; - -// Track classification tree -class TPatternTree { -public: - // Per-node classifier by probe name - class TClassifyByProbe : public TClassifier { - private: + if (spaceLeft) { + spaceLeft--; + if (!spaceLeft) { + break; + } + } + } + } +}; + +// Track classification tree +class TPatternTree { +public: + // Per-node classifier by probe name + class TClassifyByProbe : public TClassifier { + private: using TChildren = THashMap<NLWTrace::TProbe*, TPatternNode>; - TChildren Children; + TChildren Children; TVector<TChildren::value_type*> SortedChildren; - public: - explicit TClassifyByProbe(TPatternNode* node) - : TClassifier(node, NT_PROBE) - {} - - TPatternNode* Classify(TTrackIter cur, const TTrack& track) override - { - Y_UNUSED(track); - const NLWTrace::TLogItem& item = *cur; - TPatternNode* node = &Children[item.Probe]; - node->Name = "/" + GetProbeName(item.Probe); - node->Desc.Type = NT_PROBE; - node->Desc.Probe = item.Probe; - return node; - } - - void Accept(IVisitor* visitor) override - { - if (SortedChildren.size() != Children.size()) { - SortedChildren.clear(); - SortedChildren.reserve(Children.size()); - for (auto i = Children.begin(), e = Children.end(); i != e; ++i) { - SortedChildren.push_back(&*i); - } - Sort(SortedChildren, [] (TChildren::value_type* lhs, TChildren::value_type* rhs) { - NLWTrace::TProbe* lp = lhs->first; - NLWTrace::TProbe* rp = rhs->first; - if (int cmp = strcmp(lp->Event.GetProvider(), rp->Event.GetProvider())) { - return cmp < 0; - } - return strcmp(lp->Event.Name, rp->Event.Name) < 0; - }); - } - for (auto* kv : SortedChildren) { - visitor->Visit(&kv->second); - } - } - - bool IsLeaf() override { return Children.empty(); } - }; - - // Per-node classifier by probe param value - class TClassifyByParam : public TClassifier { - private: - size_t Rollbacks; // How many items should we look back in track to locate probe + public: + explicit TClassifyByProbe(TPatternNode* node) + : TClassifier(node, NT_PROBE) + {} + + TPatternNode* Classify(TTrackIter cur, const TTrack& track) override + { + Y_UNUSED(track); + const NLWTrace::TLogItem& item = *cur; + TPatternNode* node = &Children[item.Probe]; + node->Name = "/" + GetProbeName(item.Probe); + node->Desc.Type = NT_PROBE; + node->Desc.Probe = item.Probe; + return node; + } + + void Accept(IVisitor* visitor) override + { + if (SortedChildren.size() != Children.size()) { + SortedChildren.clear(); + SortedChildren.reserve(Children.size()); + for (auto i = Children.begin(), e = Children.end(); i != e; ++i) { + SortedChildren.push_back(&*i); + } + Sort(SortedChildren, [] (TChildren::value_type* lhs, TChildren::value_type* rhs) { + NLWTrace::TProbe* lp = lhs->first; + NLWTrace::TProbe* rp = rhs->first; + if (int cmp = strcmp(lp->Event.GetProvider(), rp->Event.GetProvider())) { + return cmp < 0; + } + return strcmp(lp->Event.Name, rp->Event.Name) < 0; + }); + } + for (auto* kv : SortedChildren) { + visitor->Visit(&kv->second); + } + } + + bool IsLeaf() override { return Children.empty(); } + }; + + // Per-node classifier by probe param value + class TClassifyByParam : public TClassifier { + private: + size_t Rollbacks; // How many items should we look back in track to locate probe TString ParamName; using TChildren = THashMap<TString, TPatternNode>; - TChildren Children; + TChildren Children; TVector<TChildren::value_type*> SortedChildren; - public: + public: TClassifyByParam(TPatternNode* node, size_t rollbacks, const TString& paramName) - : TClassifier(node, NT_PARAM, true) - , Rollbacks(rollbacks) - , ParamName(paramName) - {} - - TPatternNode* Classify(TTrackIter cur, const TTrack& track) override - { - WWW_CHECK((i64)Rollbacks >= 0 && std::distance(TTrackTr::begin(track), cur) >= (i64)Rollbacks, "wrong rollbacks in node '%s'", + : TClassifier(node, NT_PARAM, true) + , Rollbacks(rollbacks) + , ParamName(paramName) + {} + + TPatternNode* Classify(TTrackIter cur, const TTrack& track) override + { + WWW_CHECK((i64)Rollbacks >= 0 && std::distance(TTrackTr::begin(track), cur) >= (i64)Rollbacks, "wrong rollbacks in node '%s'", Node->GetPath().data()); - const NLWTrace::TLogItem& item = *(cur - Rollbacks); - WWW_CHECK(item.SavedParamsCount > 0, "classify by params on probe w/o param loggging in node '%s'", + const NLWTrace::TLogItem& item = *(cur - Rollbacks); + WWW_CHECK(item.SavedParamsCount > 0, "classify by params on probe w/o param loggging in node '%s'", Node->GetPath().data()); TString paramValues[LWTRACE_MAX_PARAMS]; TString* paramValue = nullptr; - item.Probe->Event.Signature.SerializeParams(item.Params, paramValues); - for (size_t pi = 0; pi < item.SavedParamsCount; pi++) { - if (item.Probe->Event.Signature.ParamNames[pi] == ParamName) { - paramValue = ¶mValues[pi]; - } - } - WWW_CHECK(paramValue, "param '%s' not found in probe '%s' at path '%s'", + item.Probe->Event.Signature.SerializeParams(item.Params, paramValues); + for (size_t pi = 0; pi < item.SavedParamsCount; pi++) { + if (item.Probe->Event.Signature.ParamNames[pi] == ParamName) { + paramValue = ¶mValues[pi]; + } + } + WWW_CHECK(paramValue, "param '%s' not found in probe '%s' at path '%s'", ParamName.data(), GetProbeName(item.Probe).data(), Node->GetPath().data()); - - TPatternNode* node = &Children[*paramValue]; - // Path example: "//Provider1.Probe1/Provider2.Probe2@1.xxx=123@2.type=harakiri" - node->Name = "@" + ToString(Rollbacks) + "." + ParamName + "=" + *paramValue; - node->Desc.Type = NT_PARAM; - node->Desc.Rollbacks = Rollbacks; - node->Desc.ParamName = ParamName; - node->Desc.ParamValue = *paramValue; - return node; - } - - void Accept(IVisitor* visitor) override - { - if (SortedChildren.size() != Children.size()) { - SortedChildren.clear(); - SortedChildren.reserve(Children.size()); - for (auto i = Children.begin(), e = Children.end(); i != e; ++i) { - SortedChildren.push_back(&*i); - } - Sort(SortedChildren, [] (TChildren::value_type* lhs, TChildren::value_type* rhs) { - return lhs->first < rhs->first; - }); - } - for (auto* kv : SortedChildren) { - visitor->Visit(&kv->second); - } - } - - bool IsLeaf() override { return Children.empty(); } - }; -private: - TPatternNode Root; + + TPatternNode* node = &Children[*paramValue]; + // Path example: "//Provider1.Probe1/Provider2.Probe2@1.xxx=123@2.type=harakiri" + node->Name = "@" + ToString(Rollbacks) + "." + ParamName + "=" + *paramValue; + node->Desc.Type = NT_PARAM; + node->Desc.Rollbacks = Rollbacks; + node->Desc.ParamName = ParamName; + node->Desc.ParamValue = *paramValue; + return node; + } + + void Accept(IVisitor* visitor) override + { + if (SortedChildren.size() != Children.size()) { + SortedChildren.clear(); + SortedChildren.reserve(Children.size()); + for (auto i = Children.begin(), e = Children.end(); i != e; ++i) { + SortedChildren.push_back(&*i); + } + Sort(SortedChildren, [] (TChildren::value_type* lhs, TChildren::value_type* rhs) { + return lhs->first < rhs->first; + }); + } + for (auto* kv : SortedChildren) { + visitor->Visit(&kv->second); + } + } + + bool IsLeaf() override { return Children.empty(); } + }; +private: + TPatternNode Root; THashMap<TString, std::pair<size_t, TString>> ParamClassifiers; // path -> (rollbacks, param) TString SelectedPattern; - TPatternNode* SelectedNode = nullptr; + TPatternNode* SelectedNode = nullptr; TVector<ui64> Timeline; // Just to avoid reallocations -public: - TPatternTree(const TCgiParameters& e) - { +public: + TPatternTree(const TCgiParameters& e) + { for (const TString& cl : Subvalues(e, "classify")) { - size_t at = cl.find_last_of('@'); + size_t at = cl.find_last_of('@'); if (at != TString::npos) { - size_t dot = cl.find('.', at + 1); + size_t dot = cl.find('.', at + 1); if (dot != TString::npos) { - size_t rollbacks = FromString<size_t>(cl.substr(at + 1, dot - at - 1)); - ParamClassifiers[cl.substr(0, at)] = std::make_pair(rollbacks, cl.substr(dot + 1)); - } - } - } - SelectedPattern = e.Get("pattern"); - InitNode(&Root, nullptr); - } - - TPatternNode* GetSelectedNode() - { - return SelectedNode; - } - - NAnalytics::TTable GetSelectedTable() - { - if (SelectedNode) { - return SelectedNode->GetTable(); - } else { - return NAnalytics::TTable(); - } - } - + size_t rollbacks = FromString<size_t>(cl.substr(at + 1, dot - at - 1)); + ParamClassifiers[cl.substr(0, at)] = std::make_pair(rollbacks, cl.substr(dot + 1)); + } + } + } + SelectedPattern = e.Get("pattern"); + InitNode(&Root, nullptr); + } + + TPatternNode* GetSelectedNode() + { + return SelectedNode; + } + + NAnalytics::TTable GetSelectedTable() + { + if (SelectedNode) { + return SelectedNode->GetTable(); + } else { + return NAnalytics::TTable(); + } + } + template <typename TReader> void OutputSelectedSample(const TString& bn, double b1, double b2, const TSampleOpts& opts, TReader& reader) - { - if (SelectedNode) { + { + if (SelectedNode) { SelectedNode->OutputSample(bn, b1, b2, opts, reader); - } - } - - // Register track in given node + } + } + + // Register track in given node void AddTrackToNode(TPatternNode* node, TTrack& track, ui64 resTotal, TVector<ui64>& timeline) - { - if (!SelectedNode) { - if (node->GetPath() == SelectedPattern) { - SelectedNode = node; - } - } - - // Counting - node->TrackCount++; - - // Resource total - node->ResTotalSum += resTotal; - node->ResTotalMax = Max(node->ResTotalMax, resTotal); - node->ResTotalAll.push_back(resTotal); - - // Resource last - ui64 resLast = 0; - resLast = resTotal - (timeline.size() < 2? 0: timeline[timeline.size() - 2]); - node->ResLastSum += resLast; - node->ResLastMax = Max(node->ResLastMax, resLast); - node->ResLastAll.push_back(resLast); - - // Timeline - if (node->TimelineSum.size() < timeline.size()) { - node->TimelineSum.resize(timeline.size()); - } - for (size_t i = 0; i < timeline.size(); i++) { - node->TimelineSum[i] += timeline[i]; - } - - if (node == SelectedNode && !timeline.empty()) { - node->Slices.emplace_back(); - NAnalytics::TRow& row = node->Slices.back(); - ui64 prev = 0; - for (size_t i = 0; i < timeline.size(); i++) { - // Note that col names should go in lexicographical order - // in the same way as slices go in pattern timeline - double sliceMs = double(timeline[i] - prev) * 1000.0 / NHPTimer::GetClockRate(); - row[Sprintf("%09lu", i)] = sliceMs; - prev = timeline[i]; - } - } - - // Interlink node and track - node->Tracks.emplace_back(&track, resTotal, resLast); - track.LastNode = node; - } - - bool CheckPattern(const char*& pi, const char* pe, TStringBuf str) - { - auto si = str.begin(), se = str.end(); - for (;pi != pe && si != se; ++pi, ++si) { - if (*pi != *si) { - return false; - } - } - return si == se; - } - -#define WWW_CHECK_PATTERN(str) if (!CheckPattern(pi, pe, (str))) { return false; } - + { + if (!SelectedNode) { + if (node->GetPath() == SelectedPattern) { + SelectedNode = node; + } + } + + // Counting + node->TrackCount++; + + // Resource total + node->ResTotalSum += resTotal; + node->ResTotalMax = Max(node->ResTotalMax, resTotal); + node->ResTotalAll.push_back(resTotal); + + // Resource last + ui64 resLast = 0; + resLast = resTotal - (timeline.size() < 2? 0: timeline[timeline.size() - 2]); + node->ResLastSum += resLast; + node->ResLastMax = Max(node->ResLastMax, resLast); + node->ResLastAll.push_back(resLast); + + // Timeline + if (node->TimelineSum.size() < timeline.size()) { + node->TimelineSum.resize(timeline.size()); + } + for (size_t i = 0; i < timeline.size(); i++) { + node->TimelineSum[i] += timeline[i]; + } + + if (node == SelectedNode && !timeline.empty()) { + node->Slices.emplace_back(); + NAnalytics::TRow& row = node->Slices.back(); + ui64 prev = 0; + for (size_t i = 0; i < timeline.size(); i++) { + // Note that col names should go in lexicographical order + // in the same way as slices go in pattern timeline + double sliceMs = double(timeline[i] - prev) * 1000.0 / NHPTimer::GetClockRate(); + row[Sprintf("%09lu", i)] = sliceMs; + prev = timeline[i]; + } + } + + // Interlink node and track + node->Tracks.emplace_back(&track, resTotal, resLast); + track.LastNode = node; + } + + bool CheckPattern(const char*& pi, const char* pe, TStringBuf str) + { + auto si = str.begin(), se = str.end(); + for (;pi != pe && si != se; ++pi, ++si) { + if (*pi != *si) { + return false; + } + } + return si == se; + } + +#define WWW_CHECK_PATTERN(str) if (!CheckPattern(pi, pe, (str))) { return false; } + bool MatchTrack(const TTrack& track, const TString& patternStr) - { + { const char* pi = patternStr.data(); const char* pe = pi + patternStr.size(); - WWW_CHECK_PATTERN("/"); - for (TTrackIter i = TTrackTr::begin(track), e = TTrackTr::end(track); i != e; ++i) { - if (pi == pe) { - return true; - } - const NLWTrace::TLogItem& item = *i; - WWW_CHECK_PATTERN("/"); - WWW_CHECK_PATTERN(item.Probe->Event.GetProvider()); - WWW_CHECK_PATTERN("."); - WWW_CHECK_PATTERN(item.Probe->Event.Name); - while (true) { - if (pi == pe) { - return true; - } - char c = *pi; - if (c == '/') { - break; - } else if (c == '@') { - pi++; - // Parse rollbacks - TStringBuf p(pi, pe); - size_t dot = p.find('.'); - if (dot == TStringBuf::npos) { - return false; - } - size_t rollbacks = 0; - try { - rollbacks = FromString<size_t>(p.substr(0, dot)); - } catch (...) { - return false; - } - - // Parse param name - size_t equals = p.find('=', dot + 1); - if (equals == TStringBuf::npos) { - return false; - } - TStringBuf paramName = p.substr(dot + 1, equals - dot - 1); - - pi += equals + 1; // Advance to value - - // Check param value - if ((i64)rollbacks < 0 || std::distance(TTrackTr::begin(track), i) < (i64)rollbacks) { - return false; - } - const NLWTrace::TLogItem& mitem = *(i - rollbacks); - if (mitem.SavedParamsCount == 0) { - return false; - } + WWW_CHECK_PATTERN("/"); + for (TTrackIter i = TTrackTr::begin(track), e = TTrackTr::end(track); i != e; ++i) { + if (pi == pe) { + return true; + } + const NLWTrace::TLogItem& item = *i; + WWW_CHECK_PATTERN("/"); + WWW_CHECK_PATTERN(item.Probe->Event.GetProvider()); + WWW_CHECK_PATTERN("."); + WWW_CHECK_PATTERN(item.Probe->Event.Name); + while (true) { + if (pi == pe) { + return true; + } + char c = *pi; + if (c == '/') { + break; + } else if (c == '@') { + pi++; + // Parse rollbacks + TStringBuf p(pi, pe); + size_t dot = p.find('.'); + if (dot == TStringBuf::npos) { + return false; + } + size_t rollbacks = 0; + try { + rollbacks = FromString<size_t>(p.substr(0, dot)); + } catch (...) { + return false; + } + + // Parse param name + size_t equals = p.find('=', dot + 1); + if (equals == TStringBuf::npos) { + return false; + } + TStringBuf paramName = p.substr(dot + 1, equals - dot - 1); + + pi += equals + 1; // Advance to value + + // Check param value + if ((i64)rollbacks < 0 || std::distance(TTrackTr::begin(track), i) < (i64)rollbacks) { + return false; + } + const NLWTrace::TLogItem& mitem = *(i - rollbacks); + if (mitem.SavedParamsCount == 0) { + return false; + } TString paramValues[LWTRACE_MAX_PARAMS]; TString* paramValue = nullptr; - mitem.Probe->Event.Signature.SerializeParams(mitem.Params, paramValues); - for (size_t pi = 0; pi < mitem.SavedParamsCount; pi++) { - if (mitem.Probe->Event.Signature.ParamNames[pi] == paramName) { - paramValue = ¶mValues[pi]; - } - } - if (!paramValue) { - return false; - } - WWW_CHECK_PATTERN(*paramValue); - } else { - return false; - } - } - } - return true; - } - -#undef WWW_CHECK_PATTERN - - // Push new track through pattern tree - void AddTrack(TTrack& track) - { - // Truncate long tracks - if (track.Items.size() > 50) { - track.Items.resize(50); - } - - if (SelectedPattern) { - if (!MatchTrack(track, SelectedPattern)) { - return; - } - } - - Timeline.clear(); - TPatternNode* node = &Root; - AddTrackToNode(node, track, 0, Timeline); - ui64 trackStart = TTrackTr::front(track).TimestampCycles; - for (TTrackIter i = TTrackTr::begin(track), e = TTrackTr::end(track); i != e;) { - // Get or create child by classification - TPatternNode* parent = node; - node = node->Classifier->Classify(i, track); - if (!node->Classifier) { - InitNode(node, parent); - } - - const NLWTrace::TLogItem& item = *i; - ui64 resTotal = item.TimestampCycles - trackStart; - if (i != TTrackTr::begin(track)) { - Timeline.push_back(resTotal); - } - AddTrackToNode(node, track, resTotal, Timeline); - - // Move through track - if (!node->Classifier->KeepHead) { - ++i; - } - } - } - - // Traverse pattern tree (the only way to extract data from it) - template <class TOnNode, class TOnDescend, class TOnAscend> - void Traverse(TOnNode&& onNode, TOnDescend&& onDescend, TOnAscend&& onAscend) - { - struct TVisitor : public IVisitor { - TOnNode OnNode; - TOnDescend OnDescend; - TOnAscend OnAscend; - TVisitor(TOnNode&& onNode, TOnDescend&& onDescend, TOnAscend&& onAscend) - : OnNode(onNode) - , OnDescend(onDescend) - , OnAscend(onAscend) - {} - virtual void Visit(TPatternNode* node) override - { - OnNode(node); - if (!node->Classifier->IsLeaf()) { - OnDescend(); - node->Classifier->Accept(this); - OnAscend(); - } - } - }; - TVisitor visitor(std::move(onNode), std::move(onDescend), std::move(onAscend)); - visitor.Visit(&Root); - } - - TPatternNode* GetRoot() - { - return &Root; - } - -private: - void InitNode(TPatternNode* node, TPatternNode* parent) - { - node->Parent = parent; - auto iter = ParamClassifiers.find(node->GetPath()); - if (iter != ParamClassifiers.end()) { - node->Classifier.Reset(new TClassifyByParam(node, iter->second.first, iter->second.second)); - } else { - node->Classifier.Reset(new TClassifyByProbe(node)); - } - } -}; - -class TLogTrackExtractor: public TLogFilter { -private: - // Data storage + mitem.Probe->Event.Signature.SerializeParams(mitem.Params, paramValues); + for (size_t pi = 0; pi < mitem.SavedParamsCount; pi++) { + if (mitem.Probe->Event.Signature.ParamNames[pi] == paramName) { + paramValue = ¶mValues[pi]; + } + } + if (!paramValue) { + return false; + } + WWW_CHECK_PATTERN(*paramValue); + } else { + return false; + } + } + } + return true; + } + +#undef WWW_CHECK_PATTERN + + // Push new track through pattern tree + void AddTrack(TTrack& track) + { + // Truncate long tracks + if (track.Items.size() > 50) { + track.Items.resize(50); + } + + if (SelectedPattern) { + if (!MatchTrack(track, SelectedPattern)) { + return; + } + } + + Timeline.clear(); + TPatternNode* node = &Root; + AddTrackToNode(node, track, 0, Timeline); + ui64 trackStart = TTrackTr::front(track).TimestampCycles; + for (TTrackIter i = TTrackTr::begin(track), e = TTrackTr::end(track); i != e;) { + // Get or create child by classification + TPatternNode* parent = node; + node = node->Classifier->Classify(i, track); + if (!node->Classifier) { + InitNode(node, parent); + } + + const NLWTrace::TLogItem& item = *i; + ui64 resTotal = item.TimestampCycles - trackStart; + if (i != TTrackTr::begin(track)) { + Timeline.push_back(resTotal); + } + AddTrackToNode(node, track, resTotal, Timeline); + + // Move through track + if (!node->Classifier->KeepHead) { + ++i; + } + } + } + + // Traverse pattern tree (the only way to extract data from it) + template <class TOnNode, class TOnDescend, class TOnAscend> + void Traverse(TOnNode&& onNode, TOnDescend&& onDescend, TOnAscend&& onAscend) + { + struct TVisitor : public IVisitor { + TOnNode OnNode; + TOnDescend OnDescend; + TOnAscend OnAscend; + TVisitor(TOnNode&& onNode, TOnDescend&& onDescend, TOnAscend&& onAscend) + : OnNode(onNode) + , OnDescend(onDescend) + , OnAscend(onAscend) + {} + virtual void Visit(TPatternNode* node) override + { + OnNode(node); + if (!node->Classifier->IsLeaf()) { + OnDescend(); + node->Classifier->Accept(this); + OnAscend(); + } + } + }; + TVisitor visitor(std::move(onNode), std::move(onDescend), std::move(onAscend)); + visitor.Visit(&Root); + } + + TPatternNode* GetRoot() + { + return &Root; + } + +private: + void InitNode(TPatternNode* node, TPatternNode* parent) + { + node->Parent = parent; + auto iter = ParamClassifiers.find(node->GetPath()); + if (iter != ParamClassifiers.end()) { + node->Classifier.Reset(new TClassifyByParam(node, iter->second.first, iter->second.second)); + } else { + node->Classifier.Reset(new TClassifyByProbe(node)); + } + } +}; + +class TLogTrackExtractor: public TLogFilter { +private: + // Data storage TMultiMap<ui64, std::pair<TThread::TId, NLWTrace::TLogItem>> Items; TVector<NLWTrace::TTrackLog> Depot; - - // Data refs organized in tracks + + // Data refs organized in tracks THashMap<TString, TTrack> Tracks; TVector<TTrack> TracksFromDepot; - - // Analysis + + // Analysis TVector<TString> GroupBy; THashSet<TString> TrackIds; // The same content as in GroupBy - TTimestampCutter CutTs; - TPatternTree Tree; -public: + TTimestampCutter CutTs; + TPatternTree Tree; +public: TLogTrackExtractor(const TCgiParameters& e, const TVector<TString>& filters, const TVector<TString>& groupBy) - : TLogFilter(filters) - , CutTs(true) // Always cut input data for tracks - , Tree(e) - { + : TLogFilter(filters) + , CutTs(true) // Always cut input data for tracks + , Tree(e) + { for (const TString& groupParam : groupBy) { - GroupBy.push_back(groupParam); - TrackIds.insert(groupParam); - } - } - - // For reading lwtrace log (input point for all data) - void Push(TThread::TId tid, const NLWTrace::TLogItem& item) - { - CutTs.Push(tid, item); - if (Filter(item)) { - Items.emplace(item.TimestampCycles, std::make_pair(tid, item)); - } - } - - // For reading lwtrace depot (input point for all data) - void Push(TThread::TId, const NLWTrace::TTrackLog& tl) - { - if (Filter(tl)) { - Depot.emplace_back(tl); - } - } - - // Analyze logs that have been read - void Run() - { - RunImplLog(); - RunImplDepot(); - } - - void RunImplLog() - { - // Create tracks by filling them with lwtrace items in order of occurance time - for (auto& kv : Items) { - AddItemToTrack(kv.second.first, kv.second.second); - } - // Push tracks throught pattern tree - for (auto& kv : Tracks) { - TTrack& track = kv.second; - track.TrackId = kv.first; - Tree.AddTrack(track); - } - } - - void RunImplDepot() - { - // Create tracks from depot - // OPTIMIZE[serxa]: this convertion is not necessary, done just to keep things simple - for (NLWTrace::TTrackLog& tl : Depot) { - TTrack& track = TracksFromDepot.emplace_back(); - track.TrackId = ToString(tl.Id); - for (const NLWTrace::TTrackLog::TItem& i : tl.Items) { - track.Items.emplace_back(i.ThreadId, i); - } - } - for (TTrack& t : TracksFromDepot) { - Tree.AddTrack(t); - } - } - - // Selected node distribution - NAnalytics::TTable Distribution(const TString& bn, const TString& b1Str, const TString& b2Str, const TString& widthStr) - { - using namespace NAnalytics; - - const NAnalytics::TTable& inputTable = Tree.GetSelectedTable(); - double b1 = b1Str? FromString<double>(b1Str): MinValue(bn, inputTable); - double b2 = b2Str? FromString<double>(b2Str): MaxValue(bn, inputTable); - if (isfinite(b1) && isfinite(b2)) { - WWW_CHECK(b1 <= b2, "invalid xrange [%le; %le]", b1, b2); - double width = widthStr? FromString<double>(widthStr): 99; - double dx = (b2 - b1) / width; - if (!(dx > 0)) { - dx = 1.0; - } - return HistogramAll(inputTable, bn, b1, b2, dx); - } else { - // Empty table -- it's ok -- leave data table empty - return NAnalytics::TTable(); - } - } - - // Selected sample + GroupBy.push_back(groupParam); + TrackIds.insert(groupParam); + } + } + + // For reading lwtrace log (input point for all data) + void Push(TThread::TId tid, const NLWTrace::TLogItem& item) + { + CutTs.Push(tid, item); + if (Filter(item)) { + Items.emplace(item.TimestampCycles, std::make_pair(tid, item)); + } + } + + // For reading lwtrace depot (input point for all data) + void Push(TThread::TId, const NLWTrace::TTrackLog& tl) + { + if (Filter(tl)) { + Depot.emplace_back(tl); + } + } + + // Analyze logs that have been read + void Run() + { + RunImplLog(); + RunImplDepot(); + } + + void RunImplLog() + { + // Create tracks by filling them with lwtrace items in order of occurance time + for (auto& kv : Items) { + AddItemToTrack(kv.second.first, kv.second.second); + } + // Push tracks throught pattern tree + for (auto& kv : Tracks) { + TTrack& track = kv.second; + track.TrackId = kv.first; + Tree.AddTrack(track); + } + } + + void RunImplDepot() + { + // Create tracks from depot + // OPTIMIZE[serxa]: this convertion is not necessary, done just to keep things simple + for (NLWTrace::TTrackLog& tl : Depot) { + TTrack& track = TracksFromDepot.emplace_back(); + track.TrackId = ToString(tl.Id); + for (const NLWTrace::TTrackLog::TItem& i : tl.Items) { + track.Items.emplace_back(i.ThreadId, i); + } + } + for (TTrack& t : TracksFromDepot) { + Tree.AddTrack(t); + } + } + + // Selected node distribution + NAnalytics::TTable Distribution(const TString& bn, const TString& b1Str, const TString& b2Str, const TString& widthStr) + { + using namespace NAnalytics; + + const NAnalytics::TTable& inputTable = Tree.GetSelectedTable(); + double b1 = b1Str? FromString<double>(b1Str): MinValue(bn, inputTable); + double b2 = b2Str? FromString<double>(b2Str): MaxValue(bn, inputTable); + if (isfinite(b1) && isfinite(b2)) { + WWW_CHECK(b1 <= b2, "invalid xrange [%le; %le]", b1, b2); + double width = widthStr? FromString<double>(widthStr): 99; + double dx = (b2 - b1) / width; + if (!(dx > 0)) { + dx = 1.0; + } + return HistogramAll(inputTable, bn, b1, b2, dx); + } else { + // Empty table -- it's ok -- leave data table empty + return NAnalytics::TTable(); + } + } + + // Selected sample template <typename TReader> void OutputSample(const TString& bn, double b1, double b2, const TSampleOpts& opts, TReader& reader) - { + { Tree.OutputSelectedSample(bn, b1, b2, opts, reader); - } - - // Tabular representation of tracks data + } + + // Tabular representation of tracks data void OutputTable(IOutputStream& os, const TCgiParameters& e) - { - ui64 tracksTotal = Tree.GetRoot()->TrackCount; - - double maxAvgResTotal = 0; - double maxMaxResTotal = 0; - Tree.Traverse([&] (TPatternNode* node) { - if (node->TrackCount > 0) { - maxAvgResTotal = Max(maxAvgResTotal, double(node->ResTotalSum) / node->TrackCount); - maxMaxResTotal = Max(maxMaxResTotal, double(node->ResTotalMax)); - Sort(node->ResTotalAll); - Sort(node->ResLastAll); - } - }, [&] () { // On descend - }, [&] () { // On ascend - }); - double maxTime = Min(maxMaxResTotal, 1.25 * maxAvgResTotal); - - double percentile = e.Get("ile")? FromString<double>(e.Get("ile")): 90; - WWW_CHECK(percentile >= 0.0 && percentile <= 100.0, "wrong percentile: %lf", percentile); - - ui64 row = 0; + { + ui64 tracksTotal = Tree.GetRoot()->TrackCount; + + double maxAvgResTotal = 0; + double maxMaxResTotal = 0; + Tree.Traverse([&] (TPatternNode* node) { + if (node->TrackCount > 0) { + maxAvgResTotal = Max(maxAvgResTotal, double(node->ResTotalSum) / node->TrackCount); + maxMaxResTotal = Max(maxMaxResTotal, double(node->ResTotalMax)); + Sort(node->ResTotalAll); + Sort(node->ResLastAll); + } + }, [&] () { // On descend + }, [&] () { // On ascend + }); + double maxTime = Min(maxMaxResTotal, 1.25 * maxAvgResTotal); + + double percentile = e.Get("ile")? FromString<double>(e.Get("ile")): 90; + WWW_CHECK(percentile >= 0.0 && percentile <= 100.0, "wrong percentile: %lf", percentile); + + ui64 row = 0; TVector<ui64> chain; - HTML(os) { - TABLE_CLASS("tracks-tree") { - TABLEHEAD() { - os << "<tr>"; - os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">#</td>"; - os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Pattern</td>"; - os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">"; - DIV_CLASS("rotate") { os << "Track Count"; } - os << "</td>"; - os << "<td colspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Share</td>"; - os << "<td colspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Total, ms</td>"; - os << "<td colspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Last, ms</td>"; - os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" class=\"timelinehead\" align=\"center\">Global Timeline</td>"; - os << "</tr><tr>"; - TABLEH() DIV_CLASS("rotate") { os << "Absolute"; } - TABLEH() DIV_CLASS("rotate") { os << "Relative"; } - TABLEH() DIV_CLASS("rotate") { os << "Average"; } - TABLEH() DIV_CLASS("rotate") { os << percentile << "%-ile"; } - TABLEH() DIV_CLASS("rotate") { os << "Average"; } - TABLEH() DIV_CLASS("rotate") { os << percentile << "%-ile"; } - os << "</tr>"; - } - TABLEBODY() { - if (tracksTotal == 0) { - return; - } - Tree.Traverse([&] (TPatternNode* node) { + HTML(os) { + TABLE_CLASS("tracks-tree") { + TABLEHEAD() { + os << "<tr>"; + os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">#</td>"; + os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Pattern</td>"; + os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">"; + DIV_CLASS("rotate") { os << "Track Count"; } + os << "</td>"; + os << "<td colspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Share</td>"; + os << "<td colspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Total, ms</td>"; + os << "<td colspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Last, ms</td>"; + os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" class=\"timelinehead\" align=\"center\">Global Timeline</td>"; + os << "</tr><tr>"; + TABLEH() DIV_CLASS("rotate") { os << "Absolute"; } + TABLEH() DIV_CLASS("rotate") { os << "Relative"; } + TABLEH() DIV_CLASS("rotate") { os << "Average"; } + TABLEH() DIV_CLASS("rotate") { os << percentile << "%-ile"; } + TABLEH() DIV_CLASS("rotate") { os << "Average"; } + TABLEH() DIV_CLASS("rotate") { os << percentile << "%-ile"; } + os << "</tr>"; + } + TABLEBODY() { + if (tracksTotal == 0) { + return; + } + Tree.Traverse([&] (TPatternNode* node) { TString parentClass; - if (!chain.empty()) { - parentClass = " treegrid-parent-" + ToString(chain.back()); - } + if (!chain.empty()) { + parentClass = " treegrid-parent-" + ToString(chain.back()); + } TString selectedClass; - if (e.Get("pattern") == node->GetPath()) { - selectedClass = " danger"; - } - TABLER_CLASS("treegrid-" + ToString(++row) + parentClass + selectedClass) { - // Counting - ui64 tracksParent = node->Parent? node->Parent->TrackCount: tracksTotal; - double absShare = double(node->TrackCount) * 100 / tracksTotal; - double relShare = double(node->TrackCount) * 100 / tracksParent; - - // Resource total - double avgResTotal = double(node->ResTotalSum) / node->TrackCount; - size_t ileResTotalIdx = node->ResTotalAll.size() * percentile / 100; - if (ileResTotalIdx > 0) { - ileResTotalIdx--; - } - double ileResTotal = double(ileResTotalIdx >= node->ResTotalAll.size()? 0: node->ResTotalAll[ileResTotalIdx]); - double avgResTotalMs = avgResTotal * 1000.0 / NHPTimer::GetClockRate(); - double ileResTotalMs = ileResTotal * 1000.0 / NHPTimer::GetClockRate(); - - // Resource last - double avgResLast = double(node->ResLastSum) / node->TrackCount; - size_t ileResLastIdx = node->ResLastAll.size() * percentile / 100; - if (ileResLastIdx > 0) { - ileResLastIdx--; - } - double ileResLast = double(ileResLastIdx >= node->ResLastAll.size()? 0: node->ResLastAll[ileResLastIdx]); - double avgResLastMs = avgResLast * 1000.0 / NHPTimer::GetClockRate(); - double ileResLastMs = ileResLast * 1000.0 / NHPTimer::GetClockRate(); - - // Output - TABLED() { os << row; } - TABLED_CLASS("treegrid-element") { OutputPattern(os, e, node); } - TABLED() { os << node->TrackCount; } - TABLED() { OutputShare(os, absShare); } - TABLED() { OutputShare(os, relShare); } - TABLED() { os << FormatFloat(avgResTotalMs); } - TABLED() { os << FormatFloat(ileResTotalMs); } - TABLED() { os << FormatFloat(avgResLastMs); } - TABLED() { os << FormatFloat(ileResLastMs); } - TABLED() { OutputTimeline(os, MakeTimeline(node), maxTime); } - } - }, [&] () { // On descend - chain.push_back(row); - }, [&] () { // On ascend - chain.pop_back(); - }); - } - } - } - } - - // Chromium-compatible trace representation of tracks data + if (e.Get("pattern") == node->GetPath()) { + selectedClass = " danger"; + } + TABLER_CLASS("treegrid-" + ToString(++row) + parentClass + selectedClass) { + // Counting + ui64 tracksParent = node->Parent? node->Parent->TrackCount: tracksTotal; + double absShare = double(node->TrackCount) * 100 / tracksTotal; + double relShare = double(node->TrackCount) * 100 / tracksParent; + + // Resource total + double avgResTotal = double(node->ResTotalSum) / node->TrackCount; + size_t ileResTotalIdx = node->ResTotalAll.size() * percentile / 100; + if (ileResTotalIdx > 0) { + ileResTotalIdx--; + } + double ileResTotal = double(ileResTotalIdx >= node->ResTotalAll.size()? 0: node->ResTotalAll[ileResTotalIdx]); + double avgResTotalMs = avgResTotal * 1000.0 / NHPTimer::GetClockRate(); + double ileResTotalMs = ileResTotal * 1000.0 / NHPTimer::GetClockRate(); + + // Resource last + double avgResLast = double(node->ResLastSum) / node->TrackCount; + size_t ileResLastIdx = node->ResLastAll.size() * percentile / 100; + if (ileResLastIdx > 0) { + ileResLastIdx--; + } + double ileResLast = double(ileResLastIdx >= node->ResLastAll.size()? 0: node->ResLastAll[ileResLastIdx]); + double avgResLastMs = avgResLast * 1000.0 / NHPTimer::GetClockRate(); + double ileResLastMs = ileResLast * 1000.0 / NHPTimer::GetClockRate(); + + // Output + TABLED() { os << row; } + TABLED_CLASS("treegrid-element") { OutputPattern(os, e, node); } + TABLED() { os << node->TrackCount; } + TABLED() { OutputShare(os, absShare); } + TABLED() { OutputShare(os, relShare); } + TABLED() { os << FormatFloat(avgResTotalMs); } + TABLED() { os << FormatFloat(ileResTotalMs); } + TABLED() { os << FormatFloat(avgResLastMs); } + TABLED() { os << FormatFloat(ileResLastMs); } + TABLED() { OutputTimeline(os, MakeTimeline(node), maxTime); } + } + }, [&] () { // On descend + chain.push_back(row); + }, [&] () { // On ascend + chain.pop_back(); + }); + } + } + } + } + + // Chromium-compatible trace representation of tracks data void OutputChromeTrace(IOutputStream& os, const TCgiParameters& e) - { - Y_UNUSED(e); - TChromeTrace tr; - for (TPatternNode::TTrackEntry& entry: Tree.GetRoot()->Tracks) { - TTrack* track = entry.Track; - auto first = TTrackTr::begin(*track); - auto last = TTrackTr::rbegin(*track); - + { + Y_UNUSED(e); + TChromeTrace tr; + for (TPatternNode::TTrackEntry& entry: Tree.GetRoot()->Tracks) { + TTrack* track = entry.Track; + auto first = TTrackTr::begin(*track); + auto last = TTrackTr::rbegin(*track); + TString name = track->LastNode->GetPath(); - - const NLWTrace::TLogItem& firstItem = *first; - TThread::TId firstTid = first->ThreadId; - tr.Add(firstTid, firstItem.TimestampCycles, "b", "track", nullptr, name, track->TrackId); - - for (auto cur = TTrackTr::begin(*track), end = TTrackTr::end(*track); cur != end; ++cur) { - const NLWTrace::TLogItem& item = *cur; - - tr.Add(cur->ThreadId, item.TimestampCycles, "i", "event", &item, GetProbeName(item.Probe)); - + + const NLWTrace::TLogItem& firstItem = *first; + TThread::TId firstTid = first->ThreadId; + tr.Add(firstTid, firstItem.TimestampCycles, "b", "track", nullptr, name, track->TrackId); + + for (auto cur = TTrackTr::begin(*track), end = TTrackTr::end(*track); cur != end; ++cur) { + const NLWTrace::TLogItem& item = *cur; + + tr.Add(cur->ThreadId, item.TimestampCycles, "i", "event", &item, GetProbeName(item.Probe)); + TString sliceName = GetProbeName(item.Probe); - - auto next = cur + 1; - if (next != end) { - const NLWTrace::TLogItem& nextItem = *next; - tr.Add(cur->ThreadId, item.TimestampCycles, "b", "track", &item, sliceName, track->TrackId); - tr.Add(next->ThreadId, nextItem.TimestampCycles, "e", "track", &nextItem, sliceName, track->TrackId); - } else { - tr.Add(cur->ThreadId, item.TimestampCycles, "n", "track", &item, sliceName, track->TrackId); - } - } - - const NLWTrace::TLogItem& lastItem = *last; - tr.Add(last->ThreadId, lastItem.TimestampCycles, "e", "track", nullptr, name, track->TrackId); - } - tr.Output(os); - } - + + auto next = cur + 1; + if (next != end) { + const NLWTrace::TLogItem& nextItem = *next; + tr.Add(cur->ThreadId, item.TimestampCycles, "b", "track", &item, sliceName, track->TrackId); + tr.Add(next->ThreadId, nextItem.TimestampCycles, "e", "track", &nextItem, sliceName, track->TrackId); + } else { + tr.Add(cur->ThreadId, item.TimestampCycles, "n", "track", &item, sliceName, track->TrackId); + } + } + + const NLWTrace::TLogItem& lastItem = *last; + tr.Add(last->ThreadId, lastItem.TimestampCycles, "e", "track", nullptr, name, track->TrackId); + } + tr.Output(os); + } + void OutputSliceCovarianceMatrix(IOutputStream& os, const TCgiParameters& e) - { - Y_UNUSED(e); - TPatternNode* node = Tree.GetSelectedNode(); - if (!node) { - return; - } - - NAnalytics::TMatrix covMatrix = NAnalytics::CovarianceMatrix(node->Slices); - double var = covMatrix.CellSum(); - - double covMax = 0.0; - for (double x : covMatrix) { - if (covMax < x) { - covMax = x; - } - } - double dangerCov = covMax * 0.9 * 0.9; - double warnCov = covMax * 0.5 * 0.5; - - HTML(os) { - TABLE() { - TTimeline timeline = MakeTimeline(node); - TABLEHEAD() TABLER() { - TABLED(); - for (auto& e : timeline) TABLED() { - TPatternNode* subnode = e.first; - os << subnode->Name; - } - } - - auto tl = timeline.begin(); - TABLEBODY() for (size_t row = 0; row < covMatrix.Rows; row++) TABLER() { - TABLEH() { - if (tl != timeline.end()) { - TPatternNode* subnode = tl->first; - os << subnode->Name; - ++tl; - } - } - - for (size_t col = 0; col < covMatrix.Cols; col++) { - double cov = covMatrix.Cell(row, col); - TString tdClass = (cov >= dangerCov? "danger": (cov >= warnCov? "warning": "")); - TABLED_CLASS(tdClass) { - double sigmaX = (covMatrix.Cell(row, row) > 0? sqrt(covMatrix.Cell(row, row)): 0); - double sigmaY = (covMatrix.Cell(col, col) > 0? sqrt(covMatrix.Cell(col, col)): 0); - os << Sprintf("cov=%.3lf ms<sup>2</sup> (%.3lf ms) corr=%.1lf%% var_share=%.1lf%%", - cov, sqrt(abs(cov)), cov * 100.0 / sigmaX / sigmaY, cov * 100.0 / var); - } - } - } - } - } - } - -private: - TPatternNode* RollbackFind(TPatternNode* node) - { - for (;node != nullptr; node = node->Parent) { - if (node->Desc.Type == NT_PROBE) { - return node; - } - } - return nullptr; - } - + { + Y_UNUSED(e); + TPatternNode* node = Tree.GetSelectedNode(); + if (!node) { + return; + } + + NAnalytics::TMatrix covMatrix = NAnalytics::CovarianceMatrix(node->Slices); + double var = covMatrix.CellSum(); + + double covMax = 0.0; + for (double x : covMatrix) { + if (covMax < x) { + covMax = x; + } + } + double dangerCov = covMax * 0.9 * 0.9; + double warnCov = covMax * 0.5 * 0.5; + + HTML(os) { + TABLE() { + TTimeline timeline = MakeTimeline(node); + TABLEHEAD() TABLER() { + TABLED(); + for (auto& e : timeline) TABLED() { + TPatternNode* subnode = e.first; + os << subnode->Name; + } + } + + auto tl = timeline.begin(); + TABLEBODY() for (size_t row = 0; row < covMatrix.Rows; row++) TABLER() { + TABLEH() { + if (tl != timeline.end()) { + TPatternNode* subnode = tl->first; + os << subnode->Name; + ++tl; + } + } + + for (size_t col = 0; col < covMatrix.Cols; col++) { + double cov = covMatrix.Cell(row, col); + TString tdClass = (cov >= dangerCov? "danger": (cov >= warnCov? "warning": "")); + TABLED_CLASS(tdClass) { + double sigmaX = (covMatrix.Cell(row, row) > 0? sqrt(covMatrix.Cell(row, row)): 0); + double sigmaY = (covMatrix.Cell(col, col) > 0? sqrt(covMatrix.Cell(col, col)): 0); + os << Sprintf("cov=%.3lf ms<sup>2</sup> (%.3lf ms) corr=%.1lf%% var_share=%.1lf%%", + cov, sqrt(abs(cov)), cov * 100.0 / sigmaX / sigmaY, cov * 100.0 / var); + } + } + } + } + } + } + +private: + TPatternNode* RollbackFind(TPatternNode* node) + { + for (;node != nullptr; node = node->Parent) { + if (node->Desc.Type == NT_PROBE) { + return node; + } + } + return nullptr; + } + void OutputPattern(IOutputStream& os, const TCgiParameters& e, TPatternNode* node) - { - // Fill pattern name + { + // Fill pattern name TString patternName; TString patternTitle; - switch (node->Desc.Type) { - case NT_ROOT: - patternName = "All Tracks"; - break; - case NT_PROBE: - patternTitle = GetProbeName(node->Desc.Probe); - patternName = node->Desc.Probe->Event.Name; - break; - case NT_PARAM: - patternName.append(node->Desc.ParamName + " = " + node->Desc.ParamValue); - break; - } - - os << "<a href=\"" << MakeUrl(e, { - {"pattern", node->GetPath()}, - {"ptrn_anlz", e.Get("ptrn_anlz") ? e.Get("ptrn_anlz") : "resTotal"}, - {"linesfill", "y"}, - {"linessteps", "y"}, - {"pointsshow", "n"}, - {"sel_x1", e.Get("sel_x1") ? e.Get("sel_x1") : "0"}, - {"sel_x2", e.Get("sel_x2") ? e.Get("sel_x2") : "inf"}}) << "\"" - " title=\"" + patternTitle + "\">" << patternName << "</a>"; - - // Add/remove node menu - if (node->Desc.Type != NT_ROOT) { - os << "<div class=\"dropdown pull-right\" style=\"display:inline-block\">"; - if (node->Desc.Type == NT_PARAM) { - os<< "<button class=\"btn btn-xs btn-default\" type=\"button\"" - << "\" onClick=\"window.location.href='" - << MakeUrlEraseSub(e, "classify", node->Parent->GetPath() + "@" - + ToString(node->Desc.Rollbacks) + "." + node->Desc.ParamName) - << "';\">" - "<span class=\"glyphicon glyphicon-minus\"></span>" - "</button>"; - } - if (node->Classifier->GetChildType() != NT_PARAM) { - os << "<button class=\"btn btn-xs btn-default dropdown-toggle\" type=\"button\"" - " data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"true\">" - "<span class=\"glyphicon glyphicon-plus\"></span>" - "</button>" - "<ul class=\"dropdown-menu\">" - "<li class=\"dropdown-header\">Classify by param:</li>"; - int rollbacks = 0; - TPatternNode* probeNode = node; - while (probeNode = RollbackFind(probeNode)) { - const NLWTrace::TProbe* probe = probeNode->Desc.Probe; - os << "<li class=\"dropdown-header\">" << GetProbeName(probe) << "</li>"; - const NLWTrace::TSignature* sgn = &probe->Event.Signature; - for (size_t pi = 0; pi < sgn->ParamCount; pi++) { + switch (node->Desc.Type) { + case NT_ROOT: + patternName = "All Tracks"; + break; + case NT_PROBE: + patternTitle = GetProbeName(node->Desc.Probe); + patternName = node->Desc.Probe->Event.Name; + break; + case NT_PARAM: + patternName.append(node->Desc.ParamName + " = " + node->Desc.ParamValue); + break; + } + + os << "<a href=\"" << MakeUrl(e, { + {"pattern", node->GetPath()}, + {"ptrn_anlz", e.Get("ptrn_anlz") ? e.Get("ptrn_anlz") : "resTotal"}, + {"linesfill", "y"}, + {"linessteps", "y"}, + {"pointsshow", "n"}, + {"sel_x1", e.Get("sel_x1") ? e.Get("sel_x1") : "0"}, + {"sel_x2", e.Get("sel_x2") ? e.Get("sel_x2") : "inf"}}) << "\"" + " title=\"" + patternTitle + "\">" << patternName << "</a>"; + + // Add/remove node menu + if (node->Desc.Type != NT_ROOT) { + os << "<div class=\"dropdown pull-right\" style=\"display:inline-block\">"; + if (node->Desc.Type == NT_PARAM) { + os<< "<button class=\"btn btn-xs btn-default\" type=\"button\"" + << "\" onClick=\"window.location.href='" + << MakeUrlEraseSub(e, "classify", node->Parent->GetPath() + "@" + + ToString(node->Desc.Rollbacks) + "." + node->Desc.ParamName) + << "';\">" + "<span class=\"glyphicon glyphicon-minus\"></span>" + "</button>"; + } + if (node->Classifier->GetChildType() != NT_PARAM) { + os << "<button class=\"btn btn-xs btn-default dropdown-toggle\" type=\"button\"" + " data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"true\">" + "<span class=\"glyphicon glyphicon-plus\"></span>" + "</button>" + "<ul class=\"dropdown-menu\">" + "<li class=\"dropdown-header\">Classify by param:</li>"; + int rollbacks = 0; + TPatternNode* probeNode = node; + while (probeNode = RollbackFind(probeNode)) { + const NLWTrace::TProbe* probe = probeNode->Desc.Probe; + os << "<li class=\"dropdown-header\">" << GetProbeName(probe) << "</li>"; + const NLWTrace::TSignature* sgn = &probe->Event.Signature; + for (size_t pi = 0; pi < sgn->ParamCount; pi++) { TString param = sgn->ParamNames[pi]; if (TrackIds.contains(param) || IsFiltered(param)) { - continue; - } - os << "<li><a href=\"" - << MakeUrlAddSub(e, "classify", node->GetPath() + "@" + ToString(rollbacks) + "." + param) - << "\">" << param << "</a></li>"; - } - rollbacks++; - probeNode = probeNode->Parent; - } - os << "</ul>"; - } - os << "</div>"; - } - } - + continue; + } + os << "<li><a href=\"" + << MakeUrlAddSub(e, "classify", node->GetPath() + "@" + ToString(rollbacks) + "." + param) + << "\">" << param << "</a></li>"; + } + rollbacks++; + probeNode = probeNode->Parent; + } + os << "</ul>"; + } + os << "</div>"; + } + } + void OutputShare(IOutputStream& os, double share) - { - double lshare = share; - double rshare = 100 - lshare; - os << "<div class=\"progress\" style=\"margin-bottom:0px;position:relative\">" - "<div class=\"progress-bar progress-bar-success\" role=\"progressbar\"" - " aria-valuenow=\"" << lshare << "\"" - " aria-valuemin=\"0\"" - " aria-valuemax=\"100\"" - " style=\"width: " << lshare << "%;\">" - "</div>" - "<div class=\"progress-bar progress-bar-danger\" role=\"progressbar\"" - " aria-valuenow=\"" << rshare << "\"" - " aria-valuemin=\"0\"" - " aria-valuemax=\"100\"" - " style=\"width: " << rshare << "%;\">" - "</div>" - "<span style=\"position:absolute;left:0;width:100%;text-align:center;z-index:2;color:white\">" - << (share == 100? "100%": Sprintf("%2.1lf%%", share)) << - "</span>" - "</div>"; - } - + { + double lshare = share; + double rshare = 100 - lshare; + os << "<div class=\"progress\" style=\"margin-bottom:0px;position:relative\">" + "<div class=\"progress-bar progress-bar-success\" role=\"progressbar\"" + " aria-valuenow=\"" << lshare << "\"" + " aria-valuemin=\"0\"" + " aria-valuemax=\"100\"" + " style=\"width: " << lshare << "%;\">" + "</div>" + "<div class=\"progress-bar progress-bar-danger\" role=\"progressbar\"" + " aria-valuenow=\"" << rshare << "\"" + " aria-valuemin=\"0\"" + " aria-valuemax=\"100\"" + " style=\"width: " << rshare << "%;\">" + "</div>" + "<span style=\"position:absolute;left:0;width:100%;text-align:center;z-index:2;color:white\">" + << (share == 100? "100%": Sprintf("%2.1lf%%", share)) << + "</span>" + "</div>"; + } + using TTimeline = TVector<std::pair<TPatternNode*, double>>; - - TTimeline MakeTimeline(TPatternNode* node) - { - TTimeline ret; - if (node->TrackCount == 0) { - return ret; - } - ret.reserve(node->TimelineSum.size()); - for (double time : node->TimelineSum) { - ret.emplace_back(nullptr, double(time) / node->TrackCount); - } - TPatternNode* n = node; - for (auto i = ret.rbegin(), e = ret.rend(); i != e; ++i) { + + TTimeline MakeTimeline(TPatternNode* node) + { + TTimeline ret; + if (node->TrackCount == 0) { + return ret; + } + ret.reserve(node->TimelineSum.size()); + for (double time : node->TimelineSum) { + ret.emplace_back(nullptr, double(time) / node->TrackCount); + } + TPatternNode* n = node; + for (auto i = ret.rbegin(), e = ret.rend(); i != e; ++i) { WWW_CHECK(n, "internal bug: wrong timeline length at pattern node '%s'", node->GetPath().data()); - i->first = n; - n = n->Parent; - } - return ret; - } - + i->first = n; + n = n->Parent; + } + return ret; + } + void OutputTimeline(IOutputStream& os, const TTimeline& timeline, double maxTime) - { - static const char *barClass[] = { - "progress-bar-info", - "progress-bar-warning" - }; - if (timeline.empty()) { - return; - } - os << "<div class=\"progress\" style=\"margin-bottom:0px;color:black\">"; - double prevPos = 0.0; - double prevTime = 0.0; - size_t i = 0; - for (auto& e : timeline) { - TPatternNode* node = e.first; - double time = e.second; - double pos = time * 100 / maxTime; - if (pos > 100) { - pos = 100; - } - double width = pos - prevPos; - os << "<div class=\"progress-bar " << barClass[i % 2] << "\" role=\"progressbar\"" - " aria-valuenow=\"" << width << "\"" - " aria-valuemin=\"0\"" - " aria-valuemax=\"100\"" - " style=\"width:" << width << "%;color:black\"" - " title=\"" << FormatTimelineTooltip(time, prevTime, node) << "\">"; - if (width > 20) { // To ensure text will fit the bar - os << FormatCycles(time - prevTime); - } - os << "</div>"; - prevPos = pos; - prevTime = time; - i++; - } - os << "</div>"; - } - + { + static const char *barClass[] = { + "progress-bar-info", + "progress-bar-warning" + }; + if (timeline.empty()) { + return; + } + os << "<div class=\"progress\" style=\"margin-bottom:0px;color:black\">"; + double prevPos = 0.0; + double prevTime = 0.0; + size_t i = 0; + for (auto& e : timeline) { + TPatternNode* node = e.first; + double time = e.second; + double pos = time * 100 / maxTime; + if (pos > 100) { + pos = 100; + } + double width = pos - prevPos; + os << "<div class=\"progress-bar " << barClass[i % 2] << "\" role=\"progressbar\"" + " aria-valuenow=\"" << width << "\"" + " aria-valuemin=\"0\"" + " aria-valuemax=\"100\"" + " style=\"width:" << width << "%;color:black\"" + " title=\"" << FormatTimelineTooltip(time, prevTime, node) << "\">"; + if (width > 20) { // To ensure text will fit the bar + os << FormatCycles(time - prevTime); + } + os << "</div>"; + prevPos = pos; + prevTime = time; + i++; + } + os << "</div>"; + } + TString FormatTimelineTooltip(double time, double prevTime, TPatternNode* node) - { - return FormatCycles(time - prevTime) + ": " - + FormatCycles(prevTime) + " -> " + FormatCycles(time) - + "(" + node->Name + ")"; - } - + { + return FormatCycles(time - prevTime) + ": " + + FormatCycles(prevTime) + " -> " + FormatCycles(time) + + "(" + node->Name + ")"; + } + TString FormatFloat(double value) - { - if (value == 0.0) { - return "0"; - } - if (value > 1.0) { - if (value > 100.0) { - return Sprintf("%.0lf", value); - } - if (value > 10.0) { - return Sprintf("%.1lf", value); - } - return Sprintf("%.2lf", value); - } else if (value > 1e-3) { - if (value > 1e-1) { - return Sprintf("%.3lf", value); - } - if (value > 1e-2) { - return Sprintf("%.4lf", value); - } - return Sprintf("%.5lf", value); - } else if (value > 1e-6) { - if (value > 1e-4) { - return Sprintf("%.6lf", value); - } - if (value > 1e-5) { - return Sprintf("%.7lf", value); - } - return Sprintf("%.8lfus", value); - } else { - if (value > 1e-7) { - return Sprintf("%.9lfns", value); - } - if (value > 1e-8) { - return Sprintf("%.10lfns", value); - } - return Sprintf("%.2le", value); - } - } - + { + if (value == 0.0) { + return "0"; + } + if (value > 1.0) { + if (value > 100.0) { + return Sprintf("%.0lf", value); + } + if (value > 10.0) { + return Sprintf("%.1lf", value); + } + return Sprintf("%.2lf", value); + } else if (value > 1e-3) { + if (value > 1e-1) { + return Sprintf("%.3lf", value); + } + if (value > 1e-2) { + return Sprintf("%.4lf", value); + } + return Sprintf("%.5lf", value); + } else if (value > 1e-6) { + if (value > 1e-4) { + return Sprintf("%.6lf", value); + } + if (value > 1e-5) { + return Sprintf("%.7lf", value); + } + return Sprintf("%.8lfus", value); + } else { + if (value > 1e-7) { + return Sprintf("%.9lfns", value); + } + if (value > 1e-8) { + return Sprintf("%.10lfns", value); + } + return Sprintf("%.2le", value); + } + } + TString FormatCycles(double timeCycles) - { - double timeSec = timeCycles / NHPTimer::GetClockRate(); - if (timeSec > 1.0) { - if (timeSec > 100.0) { - return Sprintf("%.0lfs", timeSec); - } - if (timeSec > 10.0) { - return Sprintf("%.1lfs", timeSec); - } - return Sprintf("%.2lfs", timeSec); - } else if (timeSec > 1e-3) { - if (timeSec > 1e-1) { - return Sprintf("%.0lfms", timeSec * 1e3); - } - if (timeSec > 1e-2) { - return Sprintf("%.1lfms", timeSec * 1e3); - } - return Sprintf("%.2lfms", timeSec * 1e3); - } else if (timeSec > 1e-6) { - if (timeSec > 1e-4) { - return Sprintf("%.0lfus", timeSec * 1e6); - } - if (timeSec > 1e-5) { - return Sprintf("%.1lfus", timeSec * 1e6); - } - return Sprintf("%.2lfus", timeSec * 1e6); - } else { - if (timeSec > 1e-7) { - return Sprintf("%.0lfns", timeSec * 1e9); - } - if (timeSec > 1e-8) { - return Sprintf("%.1lfns", timeSec * 1e9); - } - return Sprintf("%.2lfns", timeSec * 1e9); - } - } - + { + double timeSec = timeCycles / NHPTimer::GetClockRate(); + if (timeSec > 1.0) { + if (timeSec > 100.0) { + return Sprintf("%.0lfs", timeSec); + } + if (timeSec > 10.0) { + return Sprintf("%.1lfs", timeSec); + } + return Sprintf("%.2lfs", timeSec); + } else if (timeSec > 1e-3) { + if (timeSec > 1e-1) { + return Sprintf("%.0lfms", timeSec * 1e3); + } + if (timeSec > 1e-2) { + return Sprintf("%.1lfms", timeSec * 1e3); + } + return Sprintf("%.2lfms", timeSec * 1e3); + } else if (timeSec > 1e-6) { + if (timeSec > 1e-4) { + return Sprintf("%.0lfus", timeSec * 1e6); + } + if (timeSec > 1e-5) { + return Sprintf("%.1lfus", timeSec * 1e6); + } + return Sprintf("%.2lfus", timeSec * 1e6); + } else { + if (timeSec > 1e-7) { + return Sprintf("%.0lfns", timeSec * 1e9); + } + if (timeSec > 1e-8) { + return Sprintf("%.1lfns", timeSec * 1e9); + } + return Sprintf("%.2lfns", timeSec * 1e9); + } + } + TString GetParam(const NLWTrace::TLogItem& item, TString* paramValues, const TString& paramName) - { - for (size_t pi = 0; pi < item.SavedParamsCount; pi++) { - if (paramName == item.Probe->Event.Signature.ParamNames[pi]) { - return paramValues[pi]; - } - } + { + for (size_t pi = 0; pi < item.SavedParamsCount; pi++) { + if (paramName == item.Probe->Event.Signature.ParamNames[pi]) { + return paramValues[pi]; + } + } return TString(); - } - + } + TString GetGroup(const NLWTrace::TLogItem& item, TString* paramValues) - { - TStringStream ss; - bool first = true; + { + TStringStream ss; + bool first = true; for (const TString& groupParam : GroupBy) { - ss << (first? "": "|") << GetParam(item, paramValues, groupParam); - first = false; - } - return ss.Str(); - } - - void AddItemToTrack(TThread::TId tid, const NLWTrace::TLogItem& item) - { - // Ensure cyclic per thread lwtrace logs wont drop *inner* items of a track - // (note that some *starting* items can be dropped) - if (item.SavedParamsCount > 0 && !CutTs.Skip(item)) { + ss << (first? "": "|") << GetParam(item, paramValues, groupParam); + first = false; + } + return ss.Str(); + } + + void AddItemToTrack(TThread::TId tid, const NLWTrace::TLogItem& item) + { + // Ensure cyclic per thread lwtrace logs wont drop *inner* items of a track + // (note that some *starting* items can be dropped) + if (item.SavedParamsCount > 0 && !CutTs.Skip(item)) { TString paramValues[LWTRACE_MAX_PARAMS]; - item.Probe->Event.Signature.SerializeParams(item.Params, paramValues); - Tracks[GetGroup(item, paramValues)].Items.emplace_back(tid, item); - } - } -}; - -NLWTrace::TProbeRegistry g_Probes; + item.Probe->Event.Signature.SerializeParams(item.Params, paramValues); + Tracks[GetGroup(item, paramValues)].Items.emplace_back(tid, item); + } + } +}; + +NLWTrace::TProbeRegistry g_Probes; TString g_sanitizerTest("TString g_sanitizerTest"); -NLWTrace::TManager g_SafeManager(g_Probes, false); -NLWTrace::TManager g_UnsafeManager(g_Probes, true); +NLWTrace::TManager g_SafeManager(g_Probes, false); +NLWTrace::TManager g_UnsafeManager(g_Probes, true); TDashboardRegistry g_DashboardRegistry; - -class TLWTraceMonPage : public NMonitoring::IMonPage { + +class TLWTraceMonPage : public NMonitoring::IMonPage { private: - NLWTrace::TManager* TraceMngr; + NLWTrace::TManager* TraceMngr; TString StartTime; - TTraceCleaner Cleaner; - TMutex SnapshotsMtx; + TTraceCleaner Cleaner; + TMutex SnapshotsMtx; THashMap<TString, TAtomicSharedPtr<NLWTrace::TLogPb>> Snapshots; public: - explicit TLWTraceMonPage(bool allowUnsafe = false) + explicit TLWTraceMonPage(bool allowUnsafe = false) : NMonitoring::IMonPage("trace", "Tracing") - , TraceMngr(&TraceManager(allowUnsafe)) - , Cleaner(TraceMngr) - { - time_t stime = TInstant::Now().TimeT(); - StartTime = CTimeR(&stime); - } + , TraceMngr(&TraceManager(allowUnsafe)) + , Cleaner(TraceMngr) + { + time_t stime = TInstant::Now().TimeT(); + StartTime = CTimeR(&stime); + } virtual void Output(NMonitoring::IMonHttpRequest& request) { - TStringStream out; + TStringStream out; try { - if (request.GetParams().Get("mode") == "") { - OutputTracesAndSnapshots(request, out); + if (request.GetParams().Get("mode") == "") { + OutputTracesAndSnapshots(request, out); } else if (request.GetParams().Get("mode") == "probes") { - OutputProbes(request, out); + OutputProbes(request, out); } else if (request.GetParams().Get("mode") == "dashboards") { OutputDashboards(request, out); } else if (request.GetParams().Get("mode") == "dashboard") { OutputDashboard(request, out); } else if (request.GetParams().Get("mode") == "log") { - OutputLog(request, out); + OutputLog(request, out); } else if (request.GetParams().Get("mode") == "query") { - OutputQuery(request, out); - } else if (request.GetParams().Get("mode") == "builder") { - OutputBuilder(request, out); - } else if (request.GetParams().Get("mode") == "analytics") { - OutputAnalytics(request, out); + OutputQuery(request, out); + } else if (request.GetParams().Get("mode") == "builder") { + OutputBuilder(request, out); + } else if (request.GetParams().Get("mode") == "analytics") { + OutputAnalytics(request, out); } else if (request.GetParams().Get("mode") == "new") { - PostNew(request, out); + PostNew(request, out); } else if (request.GetParams().Get("mode") == "delete") { - PostDelete(request, out); - } else if (request.GetParams().Get("mode") == "make_snapshot") { - PostSnapshot(request, out); - } else if (request.GetParams().Get("mode") == "settimeout") { - PostSetTimeout(request, out); + PostDelete(request, out); + } else if (request.GetParams().Get("mode") == "make_snapshot") { + PostSnapshot(request, out); + } else if (request.GetParams().Get("mode") == "settimeout") { + PostSetTimeout(request, out); } else { ythrow yexception() << "Bad request"; } - } catch (TPageGenBase& gen) { - out.Clear(); - out << gen.what(); - } catch (...) { - out.Clear(); - if (request.GetParams().Get("error") == "text") { - // Text error reply is helpful for ajax requests - out << NMonitoring::HTTPOKTEXT; - out << CurrentExceptionMessage(); - } else { - WWW_HTML(out) { - out << "<h2>Error</h2><pre>" - << CurrentExceptionMessage() - << Endl; - } - } - } + } catch (TPageGenBase& gen) { + out.Clear(); + out << gen.what(); + } catch (...) { + out.Clear(); + if (request.GetParams().Get("error") == "text") { + // Text error reply is helpful for ajax requests + out << NMonitoring::HTTPOKTEXT; + out << CurrentExceptionMessage(); + } else { + WWW_HTML(out) { + out << "<h2>Error</h2><pre>" + << CurrentExceptionMessage() + << Endl; + } + } + } request.Output() << out.Str(); - } - -private: + } + +private: void OutputNavbar(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) - { + { TString active = " class=\"active\""; - out << - "<nav class=\"navbar navbar-default\"><div class=\"container-fluid\">" - << NavbarHeader() << - "<ul class=\"nav navbar-nav\">" - "<li" << (request.GetParams().Get("mode") == ""? active: "") << "><a href=\"?mode=\">Traces</a></li>" - "<li" << (request.GetParams().Get("mode") == "probes"? active: "") << "><a href=\"?mode=probes\">Probes</a></li>" + out << + "<nav class=\"navbar navbar-default\"><div class=\"container-fluid\">" + << NavbarHeader() << + "<ul class=\"nav navbar-nav\">" + "<li" << (request.GetParams().Get("mode") == ""? active: "") << "><a href=\"?mode=\">Traces</a></li>" + "<li" << (request.GetParams().Get("mode") == "probes"? active: "") << "><a href=\"?mode=probes\">Probes</a></li>" "<li" << (request.GetParams().Get("mode") == "dashboards"? active: "") << "><a href=\"?mode=dashboards\">Dashboard</a></li>" - "<li" << (request.GetParams().Get("mode") == "builder"? active: "") << "><a href=\"?mode=builder\">Builder</a></li>" - "<li" << (request.GetParams().Get("mode") == "analytics"? active: "") << "><a href=\"?mode=analytics&id=\">Analytics</a></li>" + "<li" << (request.GetParams().Get("mode") == "builder"? active: "") << "><a href=\"?mode=builder\">Builder</a></li>" + "<li" << (request.GetParams().Get("mode") == "analytics"? active: "") << "><a href=\"?mode=analytics&id=\">Analytics</a></li>" "<li><a href=\"https://wiki.yandex-team.ru/development/poisk/arcadia/library/cpp/lwtrace/\" target=\"_blank\">Documentation</a></li>" - "</ul>" - "</div></nav>" - ; - } - - template <class TReader> - void ReadSnapshots(TReader& reader) const - { - TGuard<TMutex> g(SnapshotsMtx); - for (const auto& kv : Snapshots) { - reader.Push(kv.first, kv.second); - } - } - + "</ul>" + "</div></nav>" + ; + } + + template <class TReader> + void ReadSnapshots(TReader& reader) const + { + TGuard<TMutex> g(SnapshotsMtx); + for (const auto& kv : Snapshots) { + reader.Push(kv.first, kv.second); + } + } + void OutputTracesAndSnapshots(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) - { - TLogSources logSources(Cleaner); - TraceMngr->ReadTraces(logSources); - ReadSnapshots(logSources); - - TStringStream ss; - TTracesHtmlPrinter printer(ss); - logSources.ForEach(printer); - WWW_HTML(out) { - OutputNavbar(request, out); - out << - "<table class=\"table table-striped\">" - "<tr><th>Start Time</th><th>Timeout</th><th>Name</th><th>Events</th><th>Threads</th><th></th><th></th><th></th><th></th><th></th></tr>" - << ss.Str() << - "</table>" - ; - out << "<hr/><p><strong>Start time:</strong> " << StartTime; - out << "<br/><strong>Build date:</strong> "; - out << __DATE__ << " " << __TIME__ << "</p>" << Endl; - } - } - + { + TLogSources logSources(Cleaner); + TraceMngr->ReadTraces(logSources); + ReadSnapshots(logSources); + + TStringStream ss; + TTracesHtmlPrinter printer(ss); + logSources.ForEach(printer); + WWW_HTML(out) { + OutputNavbar(request, out); + out << + "<table class=\"table table-striped\">" + "<tr><th>Start Time</th><th>Timeout</th><th>Name</th><th>Events</th><th>Threads</th><th></th><th></th><th></th><th></th><th></th></tr>" + << ss.Str() << + "</table>" + ; + out << "<hr/><p><strong>Start time:</strong> " << StartTime; + out << "<br/><strong>Build date:</strong> "; + out << __DATE__ << " " << __TIME__ << "</p>" << Endl; + } + } + void OutputProbes(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) - { - TStringStream ss; - TProbesHtmlPrinter printer; - TraceMngr->ReadProbes(printer); - printer.Output(ss); - WWW_HTML(out) { - OutputNavbar(request, out); - out << ss.Str(); - } - } - + { + TStringStream ss; + TProbesHtmlPrinter printer; + TraceMngr->ReadProbes(printer); + printer.Output(ss); + WWW_HTML(out) { + OutputNavbar(request, out); + out << ss.Str(); + } + } + void OutputDashboards(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) { TStringStream ss; @@ -3910,7 +3910,7 @@ private: WWW_HTML(out) { OutputNavbar(request, out); out << ss.Str(); - } + } } void OutputDashboard(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) { @@ -3918,97 +3918,97 @@ private: ythrow yexception() << "Cgi-parameter 'name' is not specified"; } else { auto name = request.GetParams().Get("name"); - NLWTrace::TDashboard dash; + NLWTrace::TDashboard dash; if (!g_DashboardRegistry.Get(name, dash)) { ythrow yexception() << "Dashboard doesn't exist"; } WWW_HTML(out) { OutputNavbar(request, out); - out << "<style type='text/css'>html, body { height: 100%; }</style>"; - out << "<h2>" << dash.GetName() << "</h2>"; - if (dash.GetDescription()) { - out << "<h3>" << dash.GetDescription() << "</h3>"; - } - int height = 85; // % - int minHeight = 100; // px - out << "<table height='" << height << "%' width='100%' cellpadding='4'><tbody height='100%' width='100%'>"; - ui32 rows = 0; - auto maxRowSpan = [](const auto& row) { - ui32 rowSpan = 1; - for (const auto& cell : row.GetCells()) { - rowSpan = Max(rowSpan, cell.GetRowSpan()); - } - return rowSpan; - }; - for (const auto& row : dash.GetRows()) { - rows += maxRowSpan(row); - } - for (const auto& row : dash.GetRows()) { - int rowSpan = maxRowSpan(row); - out << "<tr align='left' valign='top' style='height:" << (height * rowSpan / rows) << "%; min-height:" << (minHeight * rowSpan)<< "px'>"; - for (const auto& cell : row.GetCells()) { - TString url = cell.GetUrl(); - TString title = cell.GetTitle(); - TString text = cell.GetText(); - auto rowSpan = Max<ui64>(1, cell.GetRowSpan()); - auto colSpan = Max<ui64>(1, cell.GetColSpan()); - if (url) { - if (title) { - out << "<td rowspan='" << rowSpan << "' colSpan='1'><a href=" << url << ">" << title << "</a><br>"; - } - out << "<iframe scrolling='no' width='" << 100 * colSpan << "%' height='" << height << "%' style='border: 0' src=" << url << "></iframe></td>"; - // Add fake cells to fix html table - for (ui32 left = 1; left < colSpan; ++left) { - out << "<td height='100%' rowspan='" << rowSpan << "' colSpan='1'>" - << "<iframe scrolling='no' width='100%' height='100%' style='border: 0' src=" << "" << "></iframe></td>"; + out << "<style type='text/css'>html, body { height: 100%; }</style>"; + out << "<h2>" << dash.GetName() << "</h2>"; + if (dash.GetDescription()) { + out << "<h3>" << dash.GetDescription() << "</h3>"; + } + int height = 85; // % + int minHeight = 100; // px + out << "<table height='" << height << "%' width='100%' cellpadding='4'><tbody height='100%' width='100%'>"; + ui32 rows = 0; + auto maxRowSpan = [](const auto& row) { + ui32 rowSpan = 1; + for (const auto& cell : row.GetCells()) { + rowSpan = Max(rowSpan, cell.GetRowSpan()); + } + return rowSpan; + }; + for (const auto& row : dash.GetRows()) { + rows += maxRowSpan(row); + } + for (const auto& row : dash.GetRows()) { + int rowSpan = maxRowSpan(row); + out << "<tr align='left' valign='top' style='height:" << (height * rowSpan / rows) << "%; min-height:" << (minHeight * rowSpan)<< "px'>"; + for (const auto& cell : row.GetCells()) { + TString url = cell.GetUrl(); + TString title = cell.GetTitle(); + TString text = cell.GetText(); + auto rowSpan = Max<ui64>(1, cell.GetRowSpan()); + auto colSpan = Max<ui64>(1, cell.GetColSpan()); + if (url) { + if (title) { + out << "<td rowspan='" << rowSpan << "' colSpan='1'><a href=" << url << ">" << title << "</a><br>"; } - } else { - out << "<td style='font-size: 25px' align='left' rowspan='" << rowSpan << "' colSpan='" << colSpan << "'>" << text << "</td>"; + out << "<iframe scrolling='no' width='" << 100 * colSpan << "%' height='" << height << "%' style='border: 0' src=" << url << "></iframe></td>"; + // Add fake cells to fix html table + for (ui32 left = 1; left < colSpan; ++left) { + out << "<td height='100%' rowspan='" << rowSpan << "' colSpan='1'>" + << "<iframe scrolling='no' width='100%' height='100%' style='border: 0' src=" << "" << "></iframe></td>"; + } + } else { + out << "<td style='font-size: 25px' align='left' rowspan='" << rowSpan << "' colSpan='" << colSpan << "'>" << text << "</td>"; } } - } + } out << "</tbody></table>"; } } } - static double ParseDouble(const TString& s) - { - if (s == "inf") { - return std::numeric_limits<double>::infinity(); - } else if (s == "-inf") { - return -std::numeric_limits<double>::infinity(); - } else { - return FromString<double>(s); - } - } - + static double ParseDouble(const TString& s) + { + if (s == "inf") { + return std::numeric_limits<double>::infinity(); + } else if (s == "-inf") { + return -std::numeric_limits<double>::infinity(); + } else { + return FromString<double>(s); + } + } + void OutputLog(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) - { - if (request.GetParams().NumOfValues("id") == 0) { - ythrow yexception() << "Cgi-parameter 'id' is not specified"; - } else { + { + if (request.GetParams().NumOfValues("id") == 0) { + ythrow yexception() << "Cgi-parameter 'id' is not specified"; + } else { const TCgiParameters& e = request.GetParams(); - TStringStream ss; - if (e.Get("format") == "json") { - TLogJsonPrinter printer(ss); - printer.OutputHeader(); - TString id = e.Get("id"); - CheckAdHocTrace(id, TDuration::Minutes(1)); - TraceMngr->ReadLog(id, printer); - printer.OutputFooter(TraceMngr->GetTrace(id)); - out << HTTPOKJSON; - out << ss.Str(); - } if (e.Get("format") == "json2") { - TLogTextPrinter printer(e); - for (const TString& id : Subvalues(e, "id")) { - CheckAdHocTrace(id, TDuration::Minutes(1)); - TraceMngr->ReadLog(id, printer); - TraceMngr->ReadDepot(id, printer); - } - printer.OutputJson(ss); - out << HTTPOKJSON; - out << ss.Str(); + TStringStream ss; + if (e.Get("format") == "json") { + TLogJsonPrinter printer(ss); + printer.OutputHeader(); + TString id = e.Get("id"); + CheckAdHocTrace(id, TDuration::Minutes(1)); + TraceMngr->ReadLog(id, printer); + printer.OutputFooter(TraceMngr->GetTrace(id)); + out << HTTPOKJSON; + out << ss.Str(); + } if (e.Get("format") == "json2") { + TLogTextPrinter printer(e); + for (const TString& id : Subvalues(e, "id")) { + CheckAdHocTrace(id, TDuration::Minutes(1)); + TraceMngr->ReadLog(id, printer); + TraceMngr->ReadDepot(id, printer); + } + printer.OutputJson(ss); + out << HTTPOKJSON; + out << ss.Str(); } else if (e.Get("format") == "analytics" && e.Get("aggr") == "tracks") { TLogTrackExtractor logTrackExtractor(e, Subvalues(e, "f"), @@ -4027,8 +4027,8 @@ private: TLogTextPrinter printer(e); const TString& distBy = patternAnalyzer; - double sel_x1 = e.Get("sel_x1")? ParseDouble(e.Get("sel_x1")): NAN; - double sel_x2 = e.Get("sel_x2")? ParseDouble(e.Get("sel_x2")): NAN; + double sel_x1 = e.Get("sel_x1")? ParseDouble(e.Get("sel_x1")): NAN; + double sel_x2 = e.Get("sel_x2")? ParseDouble(e.Get("sel_x2")): NAN; TSampleOpts opts; opts.ShowProvider = (e.Get("show_provider") == "y"); if (e.Get("size_limit")) { @@ -4038,101 +4038,101 @@ private: printer.Output(ss); out << HTTPOKTEXT; out << ss.Str(); - } else { + } else { TLogTextPrinter printer(e); for (const TString& id : Subvalues(e, "id")) { - CheckAdHocTrace(id, TDuration::Minutes(1)); - TraceMngr->ReadLog(id, printer); - TraceMngr->ReadDepot(id, printer); - } - printer.Output(ss); - out << HTTPOKTEXT; - out << ss.Str(); - } - } - } - + CheckAdHocTrace(id, TDuration::Minutes(1)); + TraceMngr->ReadLog(id, printer); + TraceMngr->ReadDepot(id, printer); + } + printer.Output(ss); + out << HTTPOKTEXT; + out << ss.Str(); + } + } + } + void OutputQuery(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) - { - if (request.GetParams().NumOfValues("id") == 0) { - ythrow yexception() << "Cgi-parameter 'id' is not specified"; - } else { + { + if (request.GetParams().NumOfValues("id") == 0) { + ythrow yexception() << "Cgi-parameter 'id' is not specified"; + } else { TString id = request.GetParams().Get("id"); - const NLWTrace::TQuery& query = TraceMngr->GetTrace(id)->GetQuery(); + const NLWTrace::TQuery& query = TraceMngr->GetTrace(id)->GetQuery(); TString queryStr = query.DebugString(); - WWW_HTML(out) { - out << "<h2>Trace Query: " << id << "</h2><pre>" << queryStr; - } + WWW_HTML(out) { + out << "<h2>Trace Query: " << id << "</h2><pre>" << queryStr; + } } } - + void OutputBuilder(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) - { - Y_UNUSED(request); - WWW_HTML(out) { - OutputNavbar(request, out); - out << "<form class=\"form-horizontal\" action=\"?mode=new&ui=y\" method=\"POST\">"; - DIV_CLASS("form-group") { - LABEL_CLASS_FOR("col-sm-1 control-label", "inputId") { out << "Name"; } - DIV_CLASS("col-sm-11") { - out << "<input class=\"form-control\" id=\"inputId\" name=\"id\" placeholder=\"mytrace\">"; - } - } - DIV_CLASS("form-group") { - LABEL_CLASS_FOR("col-sm-1 control-label", "textareaQuery") { out << "Query"; } - DIV_CLASS("col-sm-11") { - out << "<textarea class=\"form-control\" id=\"textareaQuery\" name=\"query\" rows=\"10\"></textarea>"; - } - } - DIV_CLASS("form-group") { - DIV_CLASS("col-sm-offset-1 col-sm-11") { - out << "<button type=\"submit\" class=\"btn btn-default\">Trace</button>"; - } - } - out << "</form>"; - } - } - + { + Y_UNUSED(request); + WWW_HTML(out) { + OutputNavbar(request, out); + out << "<form class=\"form-horizontal\" action=\"?mode=new&ui=y\" method=\"POST\">"; + DIV_CLASS("form-group") { + LABEL_CLASS_FOR("col-sm-1 control-label", "inputId") { out << "Name"; } + DIV_CLASS("col-sm-11") { + out << "<input class=\"form-control\" id=\"inputId\" name=\"id\" placeholder=\"mytrace\">"; + } + } + DIV_CLASS("form-group") { + LABEL_CLASS_FOR("col-sm-1 control-label", "textareaQuery") { out << "Query"; } + DIV_CLASS("col-sm-11") { + out << "<textarea class=\"form-control\" id=\"textareaQuery\" name=\"query\" rows=\"10\"></textarea>"; + } + } + DIV_CLASS("form-group") { + DIV_CLASS("col-sm-offset-1 col-sm-11") { + out << "<button type=\"submit\" class=\"btn btn-default\">Trace</button>"; + } + } + out << "</form>"; + } + } + void OutputAnalytics(const NMonitoring::IMonHttpRequest& request, TStringStream& out) - { - using namespace NAnalytics; - const TCgiParameters& e = request.GetParams(); - - TLogSources logSources(Cleaner); - TraceMngr->ReadTraces(logSources); - ReadSnapshots(logSources); - - RequireMultipleSelection(out, e, "id", "Analyze ", ListTraces(logSources)); - - THolder<TLogFilter> logFilter; - TLogAnalyzer* logAnalyzer = nullptr; - TLogTrackExtractor* logTracks = nullptr; - if (request.GetParams().Get("aggr") == "tracks") { - logFilter.Reset(logTracks = new TLogTrackExtractor(e, - Subvalues(request.GetParams(), "f"), - Subvalues(request.GetParams(), "g") - )); + { + using namespace NAnalytics; + const TCgiParameters& e = request.GetParams(); + + TLogSources logSources(Cleaner); + TraceMngr->ReadTraces(logSources); + ReadSnapshots(logSources); + + RequireMultipleSelection(out, e, "id", "Analyze ", ListTraces(logSources)); + + THolder<TLogFilter> logFilter; + TLogAnalyzer* logAnalyzer = nullptr; + TLogTrackExtractor* logTracks = nullptr; + if (request.GetParams().Get("aggr") == "tracks") { + logFilter.Reset(logTracks = new TLogTrackExtractor(e, + Subvalues(request.GetParams(), "f"), + Subvalues(request.GetParams(), "g") + )); for (const TString& id : Subvalues(request.GetParams(), "id")) { - CheckAdHocTrace(id, TDuration::Minutes(1)); - TraceMngr->ReadLog(id, *logTracks); - TraceMngr->ReadDepot(id, *logTracks); - } - } else { - logFilter.Reset(logAnalyzer = new TLogAnalyzer( - Subvalues(request.GetParams(), "f"), - Subvalues(request.GetParams(), "g"), - request.GetParams().Get("cutts") == "y" - )); + CheckAdHocTrace(id, TDuration::Minutes(1)); + TraceMngr->ReadLog(id, *logTracks); + TraceMngr->ReadDepot(id, *logTracks); + } + } else { + logFilter.Reset(logAnalyzer = new TLogAnalyzer( + Subvalues(request.GetParams(), "f"), + Subvalues(request.GetParams(), "g"), + request.GetParams().Get("cutts") == "y" + )); for (const TString& id : Subvalues(request.GetParams(), "id")) { - CheckAdHocTrace(id, TDuration::Minutes(1)); - TraceMngr->ReadLog(id, *logAnalyzer); - TraceMngr->ReadDepot(id, *logAnalyzer); - } - } - - logFilter->FilterSelectors(out, e, "f"); - - OptionalMultipleSelection(out, e, "g", "group by", logFilter->ListParamNames()); + CheckAdHocTrace(id, TDuration::Minutes(1)); + TraceMngr->ReadLog(id, *logAnalyzer); + TraceMngr->ReadDepot(id, *logAnalyzer); + } + } + + logFilter->FilterSelectors(out, e, "f"); + + OptionalMultipleSelection(out, e, "g", "group by", logFilter->ListParamNames()); { auto paramNamesList = logFilter->ListParamNames(); if (e.Get("aggr") == "tracks") { @@ -4140,7 +4140,7 @@ private: } OptionalSelection(out, e, "s", "order by", paramNamesList); } - + if (e.Get("s")) { TVariants variants; variants.emplace_back("", "asc"); @@ -4149,130 +4149,130 @@ private: } TString aggr = e.Get("aggr"); - TVariants variants1; // MSVS2013 doesn't understand complex initializer lists - variants1.emplace_back("", "without aggregation"); - variants1.emplace_back("hist", "as histogram"); - variants1.emplace_back("tracks", "tracks"); - DropdownSelector<Link>(out, e, "aggr", e.Get("aggr"), "", variants1); - - unsigned refresh = e.Get("refresh")? - FromString<unsigned>(e.Get("refresh")): - 1000; - - if (aggr == "tracks") { - TVariants ileVars; - ileVars.emplace_back("0", "0"); - ileVars.emplace_back("25", "25"); - ileVars.emplace_back("50", "50"); - ileVars.emplace_back("75", "75"); - ileVars.emplace_back("", "90"); - ileVars.emplace_back("95", "95"); - ileVars.emplace_back("99", "99"); - ileVars.emplace_back("99.9", "99.9"); - ileVars.emplace_back("100", "100"); - DropdownSelector<Link>(out, e, "ile", e.Get("ile"), "and show", ileVars); - out << "%-ile. "; - TString patternAnalyzer; + TVariants variants1; // MSVS2013 doesn't understand complex initializer lists + variants1.emplace_back("", "without aggregation"); + variants1.emplace_back("hist", "as histogram"); + variants1.emplace_back("tracks", "tracks"); + DropdownSelector<Link>(out, e, "aggr", e.Get("aggr"), "", variants1); + + unsigned refresh = e.Get("refresh")? + FromString<unsigned>(e.Get("refresh")): + 1000; + + if (aggr == "tracks") { + TVariants ileVars; + ileVars.emplace_back("0", "0"); + ileVars.emplace_back("25", "25"); + ileVars.emplace_back("50", "50"); + ileVars.emplace_back("75", "75"); + ileVars.emplace_back("", "90"); + ileVars.emplace_back("95", "95"); + ileVars.emplace_back("99", "99"); + ileVars.emplace_back("99.9", "99.9"); + ileVars.emplace_back("100", "100"); + DropdownSelector<Link>(out, e, "ile", e.Get("ile"), "and show", ileVars); + out << "%-ile. "; + TString patternAnalyzer; TString distBy; TString distType; - if (e.Get("pattern")) { - TVariants analyzePatternVars; - analyzePatternVars.emplace_back("resTotal", "distribution by total"); - analyzePatternVars.emplace_back("resLast", "distribution by last"); - analyzePatternVars.emplace_back("covMatrix", "covariance matrix"); - DropdownSelector<Link>( - out, e, "ptrn_anlz", e.Get("ptrn_anlz"), - "Pattern", analyzePatternVars - ); - patternAnalyzer = e.Get("ptrn_anlz"); - - TVariants distTypeVars; - distTypeVars.emplace_back("", "as is"); - distTypeVars.emplace_back("-stack", "cumulative"); - DropdownSelector<Link>(out, e, "dist_type", e.Get("dist_type"), "", distTypeVars); - distType = e.Get("dist_type"); - } else { - out << "<i>Select pattern for more options</i>"; - } - logTracks->Run(); - - if (e.Get("download") == "y") { - out.Clear(); - out << - "HTTP/1.1 200 Ok\r\n" - "Content-Type: application/force-download\r\n" - "Content-Transfer-Encoding: binary\r\n" - "Content-Disposition: attachment; filename=\"trace_chrome.json\"\r\n" - "\r\n" - ; - logTracks->OutputChromeTrace(out, e); - return; - } - - NAnalytics::TTable distData; - bool showSample = false; + if (e.Get("pattern")) { + TVariants analyzePatternVars; + analyzePatternVars.emplace_back("resTotal", "distribution by total"); + analyzePatternVars.emplace_back("resLast", "distribution by last"); + analyzePatternVars.emplace_back("covMatrix", "covariance matrix"); + DropdownSelector<Link>( + out, e, "ptrn_anlz", e.Get("ptrn_anlz"), + "Pattern", analyzePatternVars + ); + patternAnalyzer = e.Get("ptrn_anlz"); + + TVariants distTypeVars; + distTypeVars.emplace_back("", "as is"); + distTypeVars.emplace_back("-stack", "cumulative"); + DropdownSelector<Link>(out, e, "dist_type", e.Get("dist_type"), "", distTypeVars); + distType = e.Get("dist_type"); + } else { + out << "<i>Select pattern for more options</i>"; + } + logTracks->Run(); + + if (e.Get("download") == "y") { + out.Clear(); + out << + "HTTP/1.1 200 Ok\r\n" + "Content-Type: application/force-download\r\n" + "Content-Transfer-Encoding: binary\r\n" + "Content-Disposition: attachment; filename=\"trace_chrome.json\"\r\n" + "\r\n" + ; + logTracks->OutputChromeTrace(out, e); + return; + } + + NAnalytics::TTable distData; + bool showSample = false; TLogTextPrinter printer(e); - - if (patternAnalyzer == "resTotal" || patternAnalyzer == "resLast") { - distBy = patternAnalyzer; - distData = logTracks->Distribution(distBy, "", "", e.Get("width")); - double sel_x1 = e.Get("sel_x1")? ParseDouble(e.Get("sel_x1")): NAN; - double sel_x2 = e.Get("sel_x2")? ParseDouble(e.Get("sel_x2")): NAN; - if (!isnan(sel_x1) && !isnan(sel_x2)) { - showSample = true; - TSampleOpts opts; - opts.ShowProvider = (e.Get("show_provider") == "y"); - if (e.Get("size_limit")) { - opts.SizeLimit = FromString<size_t>(e.Get("size_limit")); - } + + if (patternAnalyzer == "resTotal" || patternAnalyzer == "resLast") { + distBy = patternAnalyzer; + distData = logTracks->Distribution(distBy, "", "", e.Get("width")); + double sel_x1 = e.Get("sel_x1")? ParseDouble(e.Get("sel_x1")): NAN; + double sel_x2 = e.Get("sel_x2")? ParseDouble(e.Get("sel_x2")): NAN; + if (!isnan(sel_x1) && !isnan(sel_x2)) { + showSample = true; + TSampleOpts opts; + opts.ShowProvider = (e.Get("show_provider") == "y"); + if (e.Get("size_limit")) { + opts.SizeLimit = FromString<size_t>(e.Get("size_limit")); + } logTracks->OutputSample(distBy, sel_x1, sel_x2, opts, printer); - } - } - + } + } + TString selectors = out.Str(); - out.Clear(); - out << NMonitoring::HTTPOKHTML; - out << "<!DOCTYPE html>" << Endl; - HTML(out) { - HTML_TAG() { - HEAD() { - out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl; - if (distBy) { - out << - "<script type=\"text/javascript\">\n" - "$(function() {\n" - " var dataurl = null;\n" - " var datajson = " << ToJsonFlot(distData, distBy, {"_count_sum" + distType}) << ";\n" - " var refreshPeriod = 0;\n" - " var xn = \"" << distBy << "\";\n" - " var navigate = false;\n" - << NResource::Find("lwtrace/mon/static/analytics.js") << - " embededMode();" - " enableSelection();" - "});\n" - "</script>\n"; - } - // Show download button - out << - "<script type=\"text/javascript\">" - "$(function() {" - " $(\"#download-btn\").click(function(){window.location.href='" - << MakeUrlAdd(e, "download", "y") << - "';});" - " $(\"#download-btn\").removeClass(\"hidden\");" - "});" - "</script>\n"; - } - BODY() { - // Wrap selectors with navbar - { TSelectorsContainer sc(out); - out << selectors; - } - - logTracks->OutputTable(out, e); - if (distBy) { - out << NResource::Find("lwtrace/mon/static/analytics.flot.html") << Endl; - if (showSample) { + out.Clear(); + out << NMonitoring::HTTPOKHTML; + out << "<!DOCTYPE html>" << Endl; + HTML(out) { + HTML_TAG() { + HEAD() { + out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl; + if (distBy) { + out << + "<script type=\"text/javascript\">\n" + "$(function() {\n" + " var dataurl = null;\n" + " var datajson = " << ToJsonFlot(distData, distBy, {"_count_sum" + distType}) << ";\n" + " var refreshPeriod = 0;\n" + " var xn = \"" << distBy << "\";\n" + " var navigate = false;\n" + << NResource::Find("lwtrace/mon/static/analytics.js") << + " embededMode();" + " enableSelection();" + "});\n" + "</script>\n"; + } + // Show download button + out << + "<script type=\"text/javascript\">" + "$(function() {" + " $(\"#download-btn\").click(function(){window.location.href='" + << MakeUrlAdd(e, "download", "y") << + "';});" + " $(\"#download-btn\").removeClass(\"hidden\");" + "});" + "</script>\n"; + } + BODY() { + // Wrap selectors with navbar + { TSelectorsContainer sc(out); + out << selectors; + } + + logTracks->OutputTable(out, e); + if (distBy) { + out << NResource::Find("lwtrace/mon/static/analytics.flot.html") << Endl; + if (showSample) { static const THashSet<TString> keepParams = { "f", "g", @@ -4302,134 +4302,134 @@ private: out << "<pre>\n"; printer.Output(out); out << "</pre>\n"; - } - } - - if (patternAnalyzer == "covMatrix") { - logTracks->OutputSliceCovarianceMatrix(out, e); - } - } - } - } - } else { - double width = e.Get("width")? FromString<double>(e.Get("width")): 99; - - NAnalytics::TTable data; - if (aggr == "") { - data = logAnalyzer->GetTable(); - } else if (aggr == "hist") { - RequireSelection(out, e, "bn", "by", logFilter->ListParamNames()); - const NAnalytics::TTable& inputTable = logAnalyzer->GetTable(); + } + } + + if (patternAnalyzer == "covMatrix") { + logTracks->OutputSliceCovarianceMatrix(out, e); + } + } + } + } + } else { + double width = e.Get("width")? FromString<double>(e.Get("width")): 99; + + NAnalytics::TTable data; + if (aggr == "") { + data = logAnalyzer->GetTable(); + } else if (aggr == "hist") { + RequireSelection(out, e, "bn", "by", logFilter->ListParamNames()); + const NAnalytics::TTable& inputTable = logAnalyzer->GetTable(); TString bn = e.Get("bn"); - double b1 = e.Get("b1")? FromString<double>(e.Get("b1")): MinValue(bn, inputTable); - double b2 = e.Get("b2")? FromString<double>(e.Get("b2")): MaxValue(bn, inputTable); - if (isfinite(b1) && isfinite(b2)) { - WWW_CHECK(b1 <= b2, "invalid xrange [%le; %le]", b1, b2); - double dx = e.Get("dx")? FromString<double>(e.Get("dx")): (b2-b1)/width; - data = HistogramAll(inputTable, e.Get("bn"), b1, b2, dx); - } else { - // Empty table -- it's ok -- leave data table empty - } - } - + double b1 = e.Get("b1")? FromString<double>(e.Get("b1")): MinValue(bn, inputTable); + double b2 = e.Get("b2")? FromString<double>(e.Get("b2")): MaxValue(bn, inputTable); + if (isfinite(b1) && isfinite(b2)) { + WWW_CHECK(b1 <= b2, "invalid xrange [%le; %le]", b1, b2); + double dx = e.Get("dx")? FromString<double>(e.Get("dx")): (b2-b1)/width; + data = HistogramAll(inputTable, e.Get("bn"), b1, b2, dx); + } else { + // Empty table -- it's ok -- leave data table empty + } + } + TString xn = e.Get("xn"); - + TString outFormat = e.Get("out"); - TVariants variants2; - variants2.emplace_back("html", "table"); - variants2.emplace_back("flot", "chart"); - variants2.emplace_back("gantt", "gantt"); - variants2.emplace_back("text", "text"); - variants2.emplace_back("csv", "CSV"); - variants2.emplace_back("json_flot", "JSON"); - - RequireSelection(out, e, "out", "and show", variants2); - if (outFormat == "csv") { + TVariants variants2; + variants2.emplace_back("html", "table"); + variants2.emplace_back("flot", "chart"); + variants2.emplace_back("gantt", "gantt"); + variants2.emplace_back("text", "text"); + variants2.emplace_back("csv", "CSV"); + variants2.emplace_back("json_flot", "JSON"); + + RequireSelection(out, e, "out", "and show", variants2); + if (outFormat == "csv") { TString sep = e.Get("sep")? e.Get("sep"): TString("\t"); - out.Clear(); - out << NMonitoring::HTTPOKTEXT; - out << ToCsv(data, sep, e.Get("head") != "n"); - } else if (outFormat == "html") { + out.Clear(); + out << NMonitoring::HTTPOKTEXT; + out << ToCsv(data, sep, e.Get("head") != "n"); + } else if (outFormat == "html") { TString selectors = out.Str(); - out.Clear(); - WWW_HTML(out) { - // Wrap selectors with navbar - { TSelectorsContainer sc(out); - out << selectors; - } - out << ToHtml(data); - } - } else if (outFormat == "json_flot") { - SeriesSelectors(out, e, "xn", "yns", data); - out.Clear(); - out << NMonitoring::HTTPOKJSON; + out.Clear(); + WWW_HTML(out) { + // Wrap selectors with navbar + { TSelectorsContainer sc(out); + out << selectors; + } + out << ToHtml(data); + } + } else if (outFormat == "json_flot") { + SeriesSelectors(out, e, "xn", "yns", data); + out.Clear(); + out << NMonitoring::HTTPOKJSON; out << ToJsonFlot(data, xn, SplitString(e.Get("yns"), ":")); - } else if (outFormat == "flot") { - SeriesSelectors(out, e, "xn", "yns", data); + } else if (outFormat == "flot") { + SeriesSelectors(out, e, "xn", "yns", data); TString selectors = out.Str(); - + TVector<TString> ynos = SplitString(e.Get("yns"), ":"); - out.Clear(); - out << NMonitoring::HTTPOKHTML; - out << "<!DOCTYPE html>" << Endl; - HTML(out) { - HTML_TAG() { - HEAD() { - out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl; - out << - "<script type=\"text/javascript\">\n" - "$(function() {\n" - " var dataurl = \"" << EscapeJSONString(MakeUrl(e, "out", "json_flot")) << "\";\n" - " var refreshPeriod = " << refresh << ";\n" - " var xn = \"" << ParseName(xn) << "\";\n" - " var navigate = true;\n" - << NResource::Find("lwtrace/mon/static/analytics.js") << - "});\n" - "</script>\n" - ; - } - BODY() { - // Wrap selectors with navbar - { TSelectorsContainer sc(out); - out << selectors; - } - out << NResource::Find("lwtrace/mon/static/analytics.flot.html") << Endl; - } - } - } - } else if (outFormat == "gantt") { - TString selectors = out.Str(); - out.Clear(); - out << NMonitoring::HTTPOKHTML; - out << "<!DOCTYPE html>" << Endl; - HTML(out) { - HTML_TAG() { - HEAD() { - out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl; - out << - "<script type=\"text/javascript\">\n" - "$(function() {\n" - " var dataurl = \"" << EscapeJSONString(MakeUrl(e, {{"mode", "log"}, {"format", "json2"}, {"gantt",""}})) << "\";\n" - " var refreshPeriod = " << refresh << ";\n" - " var xn = \"" << ParseName(xn) << "\";\n" - " var navigate = true;\n" - << NResource::Find("lwtrace/mon/static/analytics.js") << - "});\n" - "</script>\n" - ; - } - BODY() { - // Wrap selectors with navbar - { TSelectorsContainer sc(out); - out << selectors; - } - out << NResource::Find("lwtrace/mon/static/analytics.gantt.html") << Endl; - } - } - } + out.Clear(); + out << NMonitoring::HTTPOKHTML; + out << "<!DOCTYPE html>" << Endl; + HTML(out) { + HTML_TAG() { + HEAD() { + out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl; + out << + "<script type=\"text/javascript\">\n" + "$(function() {\n" + " var dataurl = \"" << EscapeJSONString(MakeUrl(e, "out", "json_flot")) << "\";\n" + " var refreshPeriod = " << refresh << ";\n" + " var xn = \"" << ParseName(xn) << "\";\n" + " var navigate = true;\n" + << NResource::Find("lwtrace/mon/static/analytics.js") << + "});\n" + "</script>\n" + ; + } + BODY() { + // Wrap selectors with navbar + { TSelectorsContainer sc(out); + out << selectors; + } + out << NResource::Find("lwtrace/mon/static/analytics.flot.html") << Endl; + } + } + } + } else if (outFormat == "gantt") { + TString selectors = out.Str(); + out.Clear(); + out << NMonitoring::HTTPOKHTML; + out << "<!DOCTYPE html>" << Endl; + HTML(out) { + HTML_TAG() { + HEAD() { + out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl; + out << + "<script type=\"text/javascript\">\n" + "$(function() {\n" + " var dataurl = \"" << EscapeJSONString(MakeUrl(e, {{"mode", "log"}, {"format", "json2"}, {"gantt",""}})) << "\";\n" + " var refreshPeriod = " << refresh << ";\n" + " var xn = \"" << ParseName(xn) << "\";\n" + " var navigate = true;\n" + << NResource::Find("lwtrace/mon/static/analytics.js") << + "});\n" + "</script>\n" + ; + } + BODY() { + // Wrap selectors with navbar + { TSelectorsContainer sc(out); + out << selectors; + } + out << NResource::Find("lwtrace/mon/static/analytics.gantt.html") << Endl; + } + } + } } else if (outFormat = "text") { - out << " <input type='text' id='logsLimit' size='2' placeholder='Limit'>" << Endl; - out << + out << " <input type='text' id='logsLimit' size='2' placeholder='Limit'>" << Endl; + out << R"END(<script> { var url = new URL(window.location.href); @@ -4468,7 +4468,7 @@ private: HTML(out) { HTML_TAG() { HEAD() { - out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl; + out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl; } BODY() { // Wrap selectors with navbar @@ -4511,213 +4511,213 @@ private: } } } - } - } - } - + } + } + } + TDuration GetGetTimeout(const NMonitoring::IMonHttpRequest& request) - { - return (request.GetParams().Has("timeout")? - TDuration::Seconds(FromString<double>(request.GetParams().Get("timeout"))): - TDuration::Max()); - } - + { + return (request.GetParams().Has("timeout")? + TDuration::Seconds(FromString<double>(request.GetParams().Get("timeout"))): + TDuration::Max()); + } + void PostNew(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) - { - WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified"); + { + WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified"); const TString& id = request.GetPostParams().Get("id"); - bool ui = (request.GetParams().Get("ui") == "y"); - TDuration timeout = GetGetTimeout(request); - if (!CheckAdHocTrace(id, timeout)) { - NLWTrace::TQuery query; + bool ui = (request.GetParams().Get("ui") == "y"); + TDuration timeout = GetGetTimeout(request); + if (!CheckAdHocTrace(id, timeout)) { + NLWTrace::TQuery query; TString queryStr = request.GetPostParams().Get("query"); - if (!ui) { - queryStr = Base64Decode(queryStr); // Needed for trace.sh (historically) - } - WWW_CHECK(queryStr, "Empty trace query"); - bool parsed = NProtoBuf::TextFormat::ParseFromString(queryStr, &query); - WWW_CHECK(parsed, "Trace query text protobuf parse failed"); // TODO[serxa]: report error line/col and message - TraceMngr->New(id, query); - Cleaner.Postpone(id, timeout, false); - } else { + if (!ui) { + queryStr = Base64Decode(queryStr); // Needed for trace.sh (historically) + } + WWW_CHECK(queryStr, "Empty trace query"); + bool parsed = NProtoBuf::TextFormat::ParseFromString(queryStr, &query); + WWW_CHECK(parsed, "Trace query text protobuf parse failed"); // TODO[serxa]: report error line/col and message + TraceMngr->New(id, query); + Cleaner.Postpone(id, timeout, false); + } else { WWW_CHECK(!request.GetPostParams().Has("query"), "trace id '%s' is reserved for ad-hoc traces", id.data()); - } - if (ui) { - WWW_HTML(out) { - out << - "<div class=\"jumbotron alert-success\">" - "<h2>Trace created successfully</h2>" - "</div>" - "<script type=\"text/javascript\">\n" - "$(function() {\n" - " setTimeout(function() {" - " window.location.replace('?');" - " }, 1000);" - "});\n" - "</script>\n"; - } - } else { - out << HTTPOKTEXT; - out << "OK\n"; - } - } - + } + if (ui) { + WWW_HTML(out) { + out << + "<div class=\"jumbotron alert-success\">" + "<h2>Trace created successfully</h2>" + "</div>" + "<script type=\"text/javascript\">\n" + "$(function() {\n" + " setTimeout(function() {" + " window.location.replace('?');" + " }, 1000);" + "});\n" + "</script>\n"; + } + } else { + out << HTTPOKTEXT; + out << "OK\n"; + } + } + void PostDelete(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) - { - WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified"); + { + WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified"); const TString& id = request.GetPostParams().Get("id"); - bool ui = (request.GetParams().Get("ui") == "y"); - TraceMngr->Delete(id); - Cleaner.Forget(id); - if (ui) { - WWW_HTML(out) { - out << - "<div class=\"jumbotron alert-success\">" - "<h2>Trace deleted successfully</h2>" - "</div>" - "<script type=\"text/javascript\">\n" - "$(function() {\n" - " setTimeout(function() {" - " window.location.replace('?');" - " }, 1000);" - "});\n" - "</script>\n"; - } - } else { - out << HTTPOKTEXT; - out << "OK\n"; - } - } - + bool ui = (request.GetParams().Get("ui") == "y"); + TraceMngr->Delete(id); + Cleaner.Forget(id); + if (ui) { + WWW_HTML(out) { + out << + "<div class=\"jumbotron alert-success\">" + "<h2>Trace deleted successfully</h2>" + "</div>" + "<script type=\"text/javascript\">\n" + "$(function() {\n" + " setTimeout(function() {" + " window.location.replace('?');" + " }, 1000);" + "});\n" + "</script>\n"; + } + } else { + out << HTTPOKTEXT; + out << "OK\n"; + } + } + void PostSnapshot(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) - { - WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified"); + { + WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified"); const TString& id = request.GetPostParams().Get("id"); - bool ui = (request.GetParams().Get("ui") == "y"); - TInstant now = TInstant::Now(); - - TGuard<TMutex> g(SnapshotsMtx); - const NLWTrace::TSession* trace = TraceMngr->GetTrace(id); - struct tm tm0; + bool ui = (request.GetParams().Get("ui") == "y"); + TInstant now = TInstant::Now(); + + TGuard<TMutex> g(SnapshotsMtx); + const NLWTrace::TSession* trace = TraceMngr->GetTrace(id); + struct tm tm0; TString sid = id + Strftime("_%Y%m%d-%H%M%S", now.GmTime(&tm0)); - TAtomicSharedPtr<NLWTrace::TLogPb>& pbPtr = Snapshots[sid]; - pbPtr.Reset(new NLWTrace::TLogPb()); - trace->ToProtobuf(*pbPtr); - pbPtr->SetName(sid); - if (ui) { - WWW_HTML(out) { - out << - "<div class=\"jumbotron alert-success\">" - "<h2>Snapshot created successfully</h2>" - "</div>" - "<script type=\"text/javascript\">\n" - "$(function() {\n" - " setTimeout(function() {" - " window.location.replace('?');" - " }, 1000);" - "});\n" - "</script>\n"; - } - } else { - out << HTTPOKTEXT; - out << "OK\n"; - } - } - + TAtomicSharedPtr<NLWTrace::TLogPb>& pbPtr = Snapshots[sid]; + pbPtr.Reset(new NLWTrace::TLogPb()); + trace->ToProtobuf(*pbPtr); + pbPtr->SetName(sid); + if (ui) { + WWW_HTML(out) { + out << + "<div class=\"jumbotron alert-success\">" + "<h2>Snapshot created successfully</h2>" + "</div>" + "<script type=\"text/javascript\">\n" + "$(function() {\n" + " setTimeout(function() {" + " window.location.replace('?');" + " }, 1000);" + "});\n" + "</script>\n"; + } + } else { + out << HTTPOKTEXT; + out << "OK\n"; + } + } + void PostSetTimeout(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) - { - WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified"); + { + WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified"); const TString& id = request.GetPostParams().Get("id"); - TDuration timeout = GetGetTimeout(request); - bool ui = (request.GetParams().Get("ui") == "y"); - Cleaner.Postpone(id, timeout, true); - if (ui) { - WWW_HTML(out) { - out << - "<div class=\"jumbotron alert-success\">" - "<h2>Timeout changed successfully</h2>" - "</div>" - "<script type=\"text/javascript\">\n" - "$(function() {\n" - " setTimeout(function() {" - " window.location.replace('?');" - " }, 1000);" - "});\n" - "</script>\n"; - } - } else { - out << HTTPOKTEXT; - out << "OK\n"; - } - } + TDuration timeout = GetGetTimeout(request); + bool ui = (request.GetParams().Get("ui") == "y"); + Cleaner.Postpone(id, timeout, true); + if (ui) { + WWW_HTML(out) { + out << + "<div class=\"jumbotron alert-success\">" + "<h2>Timeout changed successfully</h2>" + "</div>" + "<script type=\"text/javascript\">\n" + "$(function() {\n" + " setTimeout(function() {" + " window.location.replace('?');" + " }, 1000);" + "});\n" + "</script>\n"; + } + } else { + out << HTTPOKTEXT; + out << "OK\n"; + } + } void RegisterDashboard(const TString& dashConfig) { g_DashboardRegistry.Register(dashConfig); } -private: - // Returns true iff trace is ad-hoc and ensures trace is created +private: + // Returns true iff trace is ad-hoc and ensures trace is created bool CheckAdHocTrace(const TString& id, TDuration timeout) - { - TAdHocTraceConfig cfg; - if (cfg.ParseId(id)) { - if (!TraceMngr->HasTrace(id)) { - TraceMngr->New(id, cfg.Query()); - } - Cleaner.Postpone(id, timeout, false); - return true; - } - return false; - } + { + TAdHocTraceConfig cfg; + if (cfg.ParseId(id)) { + if (!TraceMngr->HasTrace(id)) { + TraceMngr->New(id, cfg.Query()); + } + Cleaner.Postpone(id, timeout, false); + return true; + } + return false; + } }; -void RegisterPages(NMonitoring::TMonService2* mon, bool allowUnsafe) { +void RegisterPages(NMonitoring::TMonService2* mon, bool allowUnsafe) { THolder<NLwTraceMonPage::TLWTraceMonPage> p = MakeHolder<NLwTraceMonPage::TLWTraceMonPage>(allowUnsafe); - mon->Register(p.Release()); - -#define WWW_STATIC_FILE(file, type) \ - mon->Register(new TResourceMonPage(file, file, NMonitoring::TResourceMonPage::type)); - WWW_STATIC_FILE("lwtrace/mon/static/common.css", CSS); - WWW_STATIC_FILE("lwtrace/mon/static/common.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/css/bootstrap.min.css", CSS); - WWW_STATIC_FILE("lwtrace/mon/static/css/d3-gantt.css", CSS); - WWW_STATIC_FILE("lwtrace/mon/static/css/jquery.treegrid.css", CSS); - WWW_STATIC_FILE("lwtrace/mon/static/analytics.css", CSS); - WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot", FONT_EOT); - WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg", SVG); - WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf", FONT_TTF); - WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2", FONT_WOFF2); - WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff", FONT_WOFF); - WWW_STATIC_FILE("lwtrace/mon/static/img/collapse.png", PNG); - WWW_STATIC_FILE("lwtrace/mon/static/img/expand.png", PNG); - WWW_STATIC_FILE("lwtrace/mon/static/img/file.png", PNG); - WWW_STATIC_FILE("lwtrace/mon/static/img/folder.png", PNG); - WWW_STATIC_FILE("lwtrace/mon/static/js/bootstrap.min.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/d3.v4.min.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/d3-gantt.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/filesaver.min.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.extents.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.min.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.navigate.min.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.selection.min.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.min.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.treegrid.min.js", JAVASCRIPT); - WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.url.min.js", JAVASCRIPT); -#undef WWW_STATIC_FILE + mon->Register(p.Release()); + +#define WWW_STATIC_FILE(file, type) \ + mon->Register(new TResourceMonPage(file, file, NMonitoring::TResourceMonPage::type)); + WWW_STATIC_FILE("lwtrace/mon/static/common.css", CSS); + WWW_STATIC_FILE("lwtrace/mon/static/common.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/css/bootstrap.min.css", CSS); + WWW_STATIC_FILE("lwtrace/mon/static/css/d3-gantt.css", CSS); + WWW_STATIC_FILE("lwtrace/mon/static/css/jquery.treegrid.css", CSS); + WWW_STATIC_FILE("lwtrace/mon/static/analytics.css", CSS); + WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot", FONT_EOT); + WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg", SVG); + WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf", FONT_TTF); + WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2", FONT_WOFF2); + WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff", FONT_WOFF); + WWW_STATIC_FILE("lwtrace/mon/static/img/collapse.png", PNG); + WWW_STATIC_FILE("lwtrace/mon/static/img/expand.png", PNG); + WWW_STATIC_FILE("lwtrace/mon/static/img/file.png", PNG); + WWW_STATIC_FILE("lwtrace/mon/static/img/folder.png", PNG); + WWW_STATIC_FILE("lwtrace/mon/static/js/bootstrap.min.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/d3.v4.min.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/d3-gantt.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/filesaver.min.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.extents.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.min.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.navigate.min.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.selection.min.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.min.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.treegrid.min.js", JAVASCRIPT); + WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.url.min.js", JAVASCRIPT); +#undef WWW_STATIC_FILE } - -NLWTrace::TProbeRegistry& ProbeRegistry() { - return g_Probes; -} - -NLWTrace::TManager& TraceManager(bool allowUnsafe) { - return allowUnsafe? g_UnsafeManager: g_SafeManager; -} - + +NLWTrace::TProbeRegistry& ProbeRegistry() { + return g_Probes; +} + +NLWTrace::TManager& TraceManager(bool allowUnsafe) { + return allowUnsafe? g_UnsafeManager: g_SafeManager; +} + TDashboardRegistry& DashboardRegistry() { return g_DashboardRegistry; } -} // namespace NLwTraceMonPage +} // namespace NLwTraceMonPage diff --git a/library/cpp/lwtrace/mon/mon_lwtrace.h b/library/cpp/lwtrace/mon/mon_lwtrace.h index 8030f6ea61..3c239d478c 100644 --- a/library/cpp/lwtrace/mon/mon_lwtrace.h +++ b/library/cpp/lwtrace/mon/mon_lwtrace.h @@ -1,27 +1,27 @@ #pragma once - -#include <library/cpp/lwtrace/protos/lwtrace.pb.h> + +#include <library/cpp/lwtrace/protos/lwtrace.pb.h> #include <library/cpp/monlib/service/monservice.h> #include <library/cpp/lwtrace/control.h> -#include <util/generic/vector.h> - -namespace NLwTraceMonPage { - +#include <util/generic/vector.h> + +namespace NLwTraceMonPage { + class TDashboardRegistry { - THashMap<TString, NLWTrace::TDashboard> Dashboards; + THashMap<TString, NLWTrace::TDashboard> Dashboards; TMutex Mutex; public: - void Register(const NLWTrace::TDashboard& dashboard); - void Register(const TVector<NLWTrace::TDashboard>& dashboards); + void Register(const NLWTrace::TDashboard& dashboard); + void Register(const TVector<NLWTrace::TDashboard>& dashboards); void Register(const TString& dashText); - bool Get(const TString& name, NLWTrace::TDashboard& dash); + bool Get(const TString& name, NLWTrace::TDashboard& dash); void Output(TStringStream& ss); }; -void RegisterPages(NMonitoring::TMonService2* mon, bool allowUnsafe = false); -NLWTrace::TProbeRegistry& ProbeRegistry(); // This is not safe to use this function before main() -NLWTrace::TManager& TraceManager(bool allowUnsafe = false); +void RegisterPages(NMonitoring::TMonService2* mon, bool allowUnsafe = false); +NLWTrace::TProbeRegistry& ProbeRegistry(); // This is not safe to use this function before main() +NLWTrace::TManager& TraceManager(bool allowUnsafe = false); TDashboardRegistry& DashboardRegistry(); - -} // namespace NLwTraceMonPage + +} // namespace NLwTraceMonPage diff --git a/library/cpp/lwtrace/mon/static/analytics.css b/library/cpp/lwtrace/mon/static/analytics.css index 1b0c268e43..916fb9136e 100644 --- a/library/cpp/lwtrace/mon/static/analytics.css +++ b/library/cpp/lwtrace/mon/static/analytics.css @@ -1,68 +1,68 @@ -#header { - position: relative; - width: 900px; - margin: auto; -} - -#header h2 { - margin-left: 10px; - vertical-align: middle; - font-size: 42px; - font-weight: bold; - text-decoration: none; - color: #000; -} - -#errmsg { - width: 95vw; - margin: 0 auto; - padding: 10px; -} - -#footer { - margin-top: 25px; - margin-bottom: 10px; - text-align: center; - font-size: 12px; - color: #999; -} - -.chart-container { - box-sizing: border-box; - width: 90vw; - height: 70vh; - padding: 10px 0px 0px 0px; - margin: 15px auto 30px auto; -} - -#playback div { display: inline-block; } -#playback input { display: inline-block; } - -.chart-placeholder { - width: 100%; - height: 100%; - font-size: 14px; - line-height: 1.2em; -} - -.legend table { - border-spacing: 5px; -} - -.body-fullscreen { - width: 100%; - height: 100%; - padding: 0; - margin: 0; -} - -.container-fullscreen { - width: 100vw; - height: 100vh; - margin: 0; -} - -.toolbar-fullscreen { - display:none; - margin: 0; -} +#header { + position: relative; + width: 900px; + margin: auto; +} + +#header h2 { + margin-left: 10px; + vertical-align: middle; + font-size: 42px; + font-weight: bold; + text-decoration: none; + color: #000; +} + +#errmsg { + width: 95vw; + margin: 0 auto; + padding: 10px; +} + +#footer { + margin-top: 25px; + margin-bottom: 10px; + text-align: center; + font-size: 12px; + color: #999; +} + +.chart-container { + box-sizing: border-box; + width: 90vw; + height: 70vh; + padding: 10px 0px 0px 0px; + margin: 15px auto 30px auto; +} + +#playback div { display: inline-block; } +#playback input { display: inline-block; } + +.chart-placeholder { + width: 100%; + height: 100%; + font-size: 14px; + line-height: 1.2em; +} + +.legend table { + border-spacing: 5px; +} + +.body-fullscreen { + width: 100%; + height: 100%; + padding: 0; + margin: 0; +} + +.container-fullscreen { + width: 100vw; + height: 100vh; + margin: 0; +} + +.toolbar-fullscreen { + display:none; + margin: 0; +} diff --git a/library/cpp/lwtrace/mon/static/analytics.flot.html b/library/cpp/lwtrace/mon/static/analytics.flot.html index ea0a2880a5..9f2a2264fd 100644 --- a/library/cpp/lwtrace/mon/static/analytics.flot.html +++ b/library/cpp/lwtrace/mon/static/analytics.flot.html @@ -1,49 +1,49 @@ -<div class="container-fluid" id="toolbar" style="margin:10px;width:92vw"> - <div class="pull-right" id="playback"> - <div class="btn-group" style="margin-right:40px"> - <button type="button" class="btn btn-default" id="pb-linesfill">linesfill</button> - <button type="button" class="btn btn-default" id="pb-linessteps">linessteps</button> - <button type="button" class="btn btn-default" id="pb-linesshow">linesshow</button> - <button type="button" class="btn btn-default" id="pb-pointsshow">pointsshow</button> - </div> - <div class="btn-group" style="margin-right:40px"> - <button type="button" class="btn btn-default" id="pb-export">Export</button> - <button type="button" class="btn btn-default" id="pb-import" data-toggle="modal" data-target="#importModal">Import</button> - </div> - <button type="button" class="btn btn-default hidden" id="pb-unselect">unselect</button> - <button type="button" class="btn" id="pb-fullscreen">Fullscreen</button> - <button type="button" class="btn" id="pb-autoscale" title="Enforce axis min/max value to be equal to min/max value of data points">Autoscale</button> - <button type="button" class="btn" id="pb-legendshow">Legend</button> - <button type="button" class="btn" id="pb-cutts" title="Cuts old items in every trace log to make them start from the same instant">Cut Tails</button> - <button type="button" class="btn btn-default" id="pb-pause"><strong>||</strong></button> - </div> - - <div style="display:inline-block"> - <div style="display: inline-block"> - <span id="errmsg2" style="display:none"></span> - </div> - </div> -</div> - -<div class="chart-container" id="container"> - <div id="placeholder" class="chart-placeholder"></div> -</div> - -<div class="modal fade" id="importModal" tabindex="-1" role="dialog" aria-labelledby="importModalLabel"> - <div class="modal-dialog" role="document"> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span - aria-hidden="true">×</span></button> - <h4 class="modal-title" id="importModalLabel">Import chart Data</h4> - </div> - <div class="modal-body"> - <input type="file" id="importFiles" value="Import" /><br /> - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> - <button type="button" class="btn btn-primary" id="btnDoImport">Import</button> - </div> - </div> - </div> -</div> +<div class="container-fluid" id="toolbar" style="margin:10px;width:92vw"> + <div class="pull-right" id="playback"> + <div class="btn-group" style="margin-right:40px"> + <button type="button" class="btn btn-default" id="pb-linesfill">linesfill</button> + <button type="button" class="btn btn-default" id="pb-linessteps">linessteps</button> + <button type="button" class="btn btn-default" id="pb-linesshow">linesshow</button> + <button type="button" class="btn btn-default" id="pb-pointsshow">pointsshow</button> + </div> + <div class="btn-group" style="margin-right:40px"> + <button type="button" class="btn btn-default" id="pb-export">Export</button> + <button type="button" class="btn btn-default" id="pb-import" data-toggle="modal" data-target="#importModal">Import</button> + </div> + <button type="button" class="btn btn-default hidden" id="pb-unselect">unselect</button> + <button type="button" class="btn" id="pb-fullscreen">Fullscreen</button> + <button type="button" class="btn" id="pb-autoscale" title="Enforce axis min/max value to be equal to min/max value of data points">Autoscale</button> + <button type="button" class="btn" id="pb-legendshow">Legend</button> + <button type="button" class="btn" id="pb-cutts" title="Cuts old items in every trace log to make them start from the same instant">Cut Tails</button> + <button type="button" class="btn btn-default" id="pb-pause"><strong>||</strong></button> + </div> + + <div style="display:inline-block"> + <div style="display: inline-block"> + <span id="errmsg2" style="display:none"></span> + </div> + </div> +</div> + +<div class="chart-container" id="container"> + <div id="placeholder" class="chart-placeholder"></div> +</div> + +<div class="modal fade" id="importModal" tabindex="-1" role="dialog" aria-labelledby="importModalLabel"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span + aria-hidden="true">×</span></button> + <h4 class="modal-title" id="importModalLabel">Import chart Data</h4> + </div> + <div class="modal-body"> + <input type="file" id="importFiles" value="Import" /><br /> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" id="btnDoImport">Import</button> + </div> + </div> + </div> +</div> diff --git a/library/cpp/lwtrace/mon/static/analytics.gantt.html b/library/cpp/lwtrace/mon/static/analytics.gantt.html index cf41008900..9b846510c9 100644 --- a/library/cpp/lwtrace/mon/static/analytics.gantt.html +++ b/library/cpp/lwtrace/mon/static/analytics.gantt.html @@ -1,26 +1,26 @@ -<div id="placeholder" class="chart-placeholder"></div> - -<div class="form-group"><label class="col-sm-1 control-label" for="textareaGantt">Config</label> - <div class="col-sm-11"> - <textarea class="form-control" id="textareaGantt" name="gantt" rows="5"> -{ - "bands": [ - { - "t1": "_thrRTime[0]", - "t2": "_thrRTime[-1]", - "band": "_thread", - "color": "1", - "colorScale": "colors1" - } - ], - "scales": { - "colors1": "linear().domain([-1,0,1]).range(['red','black','green'])", - "colors2": "ordinal().domain(['VALUE1','VALUE2']).range(['blue','yellow'])" - } -} - </textarea> - </div> -</div> -<div class="form-group"> - <div class="col-sm-offset-1 col-sm-11"><button class="btn btn-default" id="gantt-apply">Apply</button></div> -</div> +<div id="placeholder" class="chart-placeholder"></div> + +<div class="form-group"><label class="col-sm-1 control-label" for="textareaGantt">Config</label> + <div class="col-sm-11"> + <textarea class="form-control" id="textareaGantt" name="gantt" rows="5"> +{ + "bands": [ + { + "t1": "_thrRTime[0]", + "t2": "_thrRTime[-1]", + "band": "_thread", + "color": "1", + "colorScale": "colors1" + } + ], + "scales": { + "colors1": "linear().domain([-1,0,1]).range(['red','black','green'])", + "colors2": "ordinal().domain(['VALUE1','VALUE2']).range(['blue','yellow'])" + } +} + </textarea> + </div> +</div> +<div class="form-group"> + <div class="col-sm-offset-1 col-sm-11"><button class="btn btn-default" id="gantt-apply">Apply</button></div> +</div> diff --git a/library/cpp/lwtrace/mon/static/analytics.header.html b/library/cpp/lwtrace/mon/static/analytics.header.html index 0a6790e232..53d080f41f 100644 --- a/library/cpp/lwtrace/mon/static/analytics.header.html +++ b/library/cpp/lwtrace/mon/static/analytics.header.html @@ -1,21 +1,21 @@ -<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> -<link rel="stylesheet" href="lwtrace/mon/static/analytics.css" type="text/css"> -<link rel="stylesheet" href="lwtrace/mon/static/css/d3-gantt.css" type="text/css"> -<link rel="stylesheet" href="lwtrace/mon/static/css/bootstrap.min.css"> -<link rel="stylesheet" href="lwtrace/mon/static/css/jquery.treegrid.css"> -<link rel="stylesheet" href="lwtrace/mon/static/common.css"> - -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.url.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.navigate.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.extents.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.selection.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/bootstrap.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/filesaver.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/d3.v4.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/d3-gantt.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/common.js"></script> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<link rel="stylesheet" href="lwtrace/mon/static/analytics.css" type="text/css"> +<link rel="stylesheet" href="lwtrace/mon/static/css/d3-gantt.css" type="text/css"> +<link rel="stylesheet" href="lwtrace/mon/static/css/bootstrap.min.css"> +<link rel="stylesheet" href="lwtrace/mon/static/css/jquery.treegrid.css"> +<link rel="stylesheet" href="lwtrace/mon/static/common.css"> + +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.url.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.navigate.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.extents.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.selection.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/bootstrap.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/filesaver.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/d3.v4.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/d3-gantt.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/common.js"></script> diff --git a/library/cpp/lwtrace/mon/static/analytics.js b/library/cpp/lwtrace/mon/static/analytics.js index 7b66cca4c0..85b869869b 100644 --- a/library/cpp/lwtrace/mon/static/analytics.js +++ b/library/cpp/lwtrace/mon/static/analytics.js @@ -1,561 +1,561 @@ -/* - * This code is executed from document ready function - * Also note that some variable are set from C++ code - */ - -var x1 = $.url("?x1"); -var x2 = $.url("?x2"); -var y1 = $.url("?y1"); -var y2 = $.url("?y2"); - -var gantt = $.url("?gantt"); -var out = $.url("?out"); - -var linesfill = $.url("?linesfill") == "y"; -var linessteps = $.url("?linessteps") == "y"; -var linesshow = $.url("?linesshow") != "n"; -var pointsshow = $.url("?pointsshow") != "n"; -var autoscale = $.url("?autoscale") == "y"; -var legendshow = $.url("?legendshow") != "n"; -var cutts = $.url("?cutts") == "y"; -var fullscreen = $.url("?fullscreen") == "y"; -var realnames = $.url("?realnames") == "y"; -var xzoomoff = $.url("?xzoomoff") == "y"; -var yzoomoff = $.url("?yzoomoff") == "y"; - -function inIframe() { try { return window.self !== window.top; } catch (e) { return true; } } -function inDashboard() { return fullscreen && inIframe(); } - -// URL management -function makeUrl(url, queryFunc, hashFunc) { - var query = $.url("?", url); - var hash = $.url("#", url); - if (paused) { - query.paused = "y"; - } - - if (queryFunc) { queryFunc(query); } - if (hashFunc) { hashFunc(hash); } - var queryStr = ""; - var first = true; - for (var k in query) { - queryStr += (first? "?": "&") + k + "=" + encodeURIComponent(query[k]); - first = false; - } - var hashStr = ""; - first = true; - for (k in hash) { - hashStr += (first? "#": "&") + k + "=" + encodeURIComponent(hash[k]); - first = false; - } - return queryStr + hashStr; -} - -function dataUrl() { - return makeUrl(dataurl, function(query) { - query.error = "text"; - }); -} - -// Error message popup -$("<div id='errmsg'></div>").css({ - position: "absolute", - display: "none", - border: "1px solid #faa", - padding: "2px", - "background-color": "#fcc", - opacity: 0.80 -}).appendTo("body"); - -if (out == "gantt") { - $("#gantt-apply").click(function() { - try { - let val = $("#textareaGantt").val().replace(/\s/g, ""); - JSON.parse(val); - window.location.replace(makeUrl($.url(), function(query) { - query.gantt = val; - })); - } catch(e) { - $("#errmsg").text("Not valid JSON: " + e) - .css({bottom: "5px", left: "25%", width: "50%"}) - .fadeIn(200); - } - }); - - if (gantt) { - // Data fetching and auto-refreshing - var fetchCounter = 0; - function fetchData() { - function onDataReceived(json, textStatus, xhr) { - $("#errmsg").hide(); - logs = json; - chart(config, logs, true); - } - - function onDataError(xhr, error) { - console.log(arguments); - $("#errmsg").text("Fetch data error: " + error + (xhr.status == 200? xhr.responseText: "")) - .css({bottom: "5px", left: "25%", width: "50%"}) - .fadeIn(200); - } - - if (dataurl) { - $.ajax({ - url: dataUrl(), - type: "GET", - dataType: "json", - success: function (json, textStatus, xhr) { onDataReceived(json, textStatus, xhr); }, - error: onDataError - }); - } else { - onDataReceived(datajson, "textStatus", "xhr"); - } - - // if (fetchPeriod > 0) { - // if (fetchCounter == 0) { - // fetchCounter++; - // setTimeout(function() { - // fetchCounter--; - // if (!paused) { - // fetchData(); - // } - // }, $("#errmsg").is(":visible")? errorPeriod: fetchPeriod); - // } - // } - } - - try { - var config = JSON.parse(gantt); - $("#textareaGantt").val(JSON.stringify(config, "\n", " ")); - let formHeight = 220; - var chart = d3.gantt() - .height(window.innerHeight - $("#placeholder")[0].getBoundingClientRect().y - window.scrollY - formHeight) - .selector("#placeholder"); - var logs = null; - fetchData(); - } catch(e) { - $("#textareaGantt").val(gantt); - alert("Not valid JSON: " + e); - } - } -} else { // flot - // Special options adjustment for fullscreen charts in iframe (solomon dashboards) - if (fullscreen) { - navigate = false; // Disable navigation to avoid scrolling problems - legendshow = false; // Show legend only on hover - } - - // Adjust zooming options - var xZoomRange = null; - var yZoomRange = null; - if (xzoomoff) { - xZoomRange = false; - } - if (yzoomoff) { - yZoomRange = false; - } - - var placeholder = $("#placeholder"); - var playback = $("#playback"); - - var data = null; - var loaded_data = []; - var imported_data = []; - var fetchPeriod = refreshPeriod; - var errorPeriod = 5000; - var playbackPeriod = 500; - var abstimestep = 1.0; - - var paused = $.url("?paused") == "y"; - var timestep = abstimestep; - - var seriesDescription = { - _time: "time", - _thread: "thread" - } - - function seriesDesc(name) { - if (seriesDescription.hasOwnProperty(name)) { - return (realnames? "[" + name + "] ": "") + seriesDescription[name]; - } else { - return name; - } - } - - playback.show(); - - var options = { - series: { - lines: { show: linesshow, fill: linesfill, steps: linessteps}, - points: { show: pointsshow }, - shadowSize: 0 - }, - xaxis: { zoomRange: xZoomRange }, - yaxis: { zoomRange: yZoomRange }, - grid: { clickable: true, hoverable: true }, - zoom: { interactive: navigate }, - pan: { interactive: navigate }, - legend: { - show: legendshow, - labelFormatter: function(label, series) { return seriesDesc(label) + '(' + seriesDesc(xn) + ')'; } - } - }; - - if (fullscreen) { - $("body").attr("class","body-fullscreen"); - $("#container").attr("class","container-fullscreen"); - $("#toolbar").attr("class","toolbar-fullscreen"); - $("#selectors-container").attr("class","toolbar-fullscreen"); - options.grid.margin = 0; - } - - if (x1) { options.xaxis.min = x1; } - if (x2) { options.xaxis.max = x2; } - if (y1) { options.yaxis.min = y1; } - if (y2) { options.yaxis.max = y2; } - - $("<div id='tooltip'></div>").css({ - position: "absolute", - display: "none", - border: "1px solid #fdd", - padding: "2px", - "background-color": "#fee", - opacity: 0.80 - }).appendTo("body"); - - // Helper to hide tooltip - var lastShow = new Date(); - var hideCounter = 0; - function hideTooltip() { - if (hideCounter == 0) { - hideCounter++; - setTimeout(function() { - hideCounter--; - if (new Date().getTime() - lastShow.getTime() > 1000) { - $("#tooltip").fadeOut(200); - } else if ($("#tooltip").is(":visible")) { - hideTooltip(); - } - }, 200); - } - } - - // Helper to hide legend - var legendLastShow = new Date(); - var legendHideCounter = 0; - function hideLegend() { - if (legendHideCounter == 0) { - legendHideCounter++; - setTimeout(function() { - legendHideCounter--; - if (new Date().getTime() - legendLastShow.getTime() > 1000) { - options.legend.show = false; - $.plot(placeholder, data, options); - } else { - hideLegend(); - } - }, 200); - } - } - - function onPlotClick(event, pos, item) { - // Leave fullscreen on click - var nonFullscreenUrl = makeUrl($.url(), function(query) { - delete query.fullscreen; - }); - if (inDashboard()) { - window.open(nonFullscreenUrl, "_blank"); - } else if (fullscreen) { - window.location.href = nonFullscreenUrl; - } - } - - function onPlotHover(event, pos, item) { - var redraw = false; - // Show legend on hover - if (fullscreen) { - legendLastShow = new Date(); - if (!options.legend.show) { - redraw = true; - } - options.legend.show = true; - hideLegend(); - } - - // Show names on hover - var left = placeholder.position().left; - var top = placeholder.position().top; - var ttmargin = 10; - var ttwidth = $("#tooltip").width(); - var ttheight = $("#tooltip").height(); - if (linessteps) { - var pts = data[0].data; - var idx = 0; - for (var i = 0; i < pts.length - 1; i++) { - var x1 = pts[i][0]; - var x2 = pts[i+1][0]; - if (pos.x >= x1 && (x2 == null || pos.x < x2)) { - idx = i; - } - } - var n = pts[idx][2]; - var html = (n? "<u><b><center>" + n + "</center></b></u>": "") + "<table><tr><td align=\"right\">" + seriesDesc(xn) + "</td><td>: </td><td>" + pts[idx][3] + "</td></tr>"; - for (var sid = 0; sid < data.length; sid++) { - var series = data[sid]; - var y = series.data[idx][4]; - html += "<tr><td align=\"right\">" + seriesDesc(series.label) + "</td><td>: </td><td>" + y + "</td></tr>"; - } - html += "</table>"; - - lastShow = new Date(); - if (pos.pageX < left + placeholder.width() && pos.pageX > left && - pos.pageY < top + placeholder.height() && pos.pageY > top) { - $("#tooltip").html(html) - .css({top: Math.max(top + ttmargin + 10, pos.pageY - ttheight - 20), - left: Math.max(left + ttmargin + 10, pos.pageX - ttwidth - 20)}) - .fadeIn(200, "swing", hideTooltip()); - } - } else { - if (item) { - var idx = item.dataIndex; - var n = item.series.data[idx][2]; - var x = item.series.data[idx][3]; //item.datapoint[0]; - var y = item.series.data[idx][4]; //item.datapoint[1]; - $("#tooltip").html((n? n + ": ": "") + seriesDesc(item.series.label) + " = " + y + ", " + seriesDesc(xn) + " = " + x) - .css({top: Math.max(top + ttmargin + 10, item.pageY - ttheight - 20), - left: Math.max(left + ttmargin + 10, item.pageX - ttwidth - 20)}) - .fadeIn(200); - } else { - $("#tooltip").hide(); - } - } - - // Redraw if required - if (redraw) { - $.plot(placeholder, data, options); - } - } - - // Add some more interactivity - function onZoomOrPan(event, plot) { - var axes = plot.getAxes(); - options.xaxis.min = axes.xaxis.min; - options.xaxis.max = axes.xaxis.max; - options.yaxis.min = axes.yaxis.min; - options.yaxis.max = axes.yaxis.max; - } - - // Bind to events - placeholder.bind("plotclick", onPlotClick); - placeholder.bind("plothover", onPlotHover); - placeholder.bind("plotpan", onZoomOrPan); - placeholder.bind("plotzoom", onZoomOrPan); - - // Data fetching and auto-refreshing - var fetchCounter = 0; - function fetchData() { - function onDataReceived(json, textStatus, xhr) { - $("#errmsg").hide(); - if (paused && logs) { - return; - } - - // Plot fetched data - loaded_data = json; - data = loaded_data.concat(imported_data); - - if (autoscale) { - var xmin = null; - var xmax = null; - var ymin = null; - var ymax = null; - for (var sid = 0; sid < data.length; sid++) { - var pts = data[sid].data; - for (var i = 0; i < pts.length; i++) { - var x = pts[i][0]; - var y = pts[i][1]; - if (x != null && y != null) { - if (xmin == null || x < xmin) { xmin = x; } - if (xmax == null || x > xmax) { xmax = x; } - if (ymin == null || y < ymin) { ymin = y; } - if (ymax == null || y > ymax) { ymax = y; } - } - } - } - if (xmin != null) { options.xaxis.min = xmin; } - if (xmax != null) { options.xaxis.max = xmax; } - if (ymin != null) { options.yaxis.min = ymin; } - if (ymax != null) { options.yaxis.max = ymax; } - } - $.plot(placeholder, data, options); - } - - function onDataError(xhr, error) { - console.log(arguments); - $("#errmsg").text("Fetch data error: " + error + (xhr.status == 200? xhr.responseText: "")) - .css({bottom: "5px", left: "25%", width: "50%"}) - .fadeIn(200); - } - - if (dataurl) { - $.ajax({ - url: dataUrl(), - type: "GET", - dataType: "json", - success: function (json, textStatus, xhr) { onDataReceived(json, textStatus, xhr); }, - error: onDataError - }); - } else { - onDataReceived(datajson, "textStatus", "xhr"); - } - - if (fetchPeriod > 0) { - if (fetchCounter == 0) { - fetchCounter++; - setTimeout(function() { - fetchCounter--; - if (!paused) { - fetchData(); - } - }, $("#errmsg").is(":visible")? errorPeriod: fetchPeriod); - } - } - } - - // Playback control - var pb_pause = $("#pb-pause"); - - function setActive(btn, active) { - if (active) { - btn.addClass("btn-primary"); - btn.removeClass("btn-default"); - } else { - btn.addClass("btn-default"); - btn.removeClass("btn-primary"); - } - } - - function onPlaybackControl() { - setActive(pb_pause, paused); - fetchPeriod = refreshPeriod; - fetchData(); - } - - function clickPause(val) { - paused = val; - onPlaybackControl(); - } - - pb_pause.click(function() { clickPause(!paused); }); - - function addOptionButton(opt, btn, defOn) { - setActive(btn, defOn ? $.url("?" + opt) != "n" : $.url("?" + opt) == "y"); - btn.click(function() { - window.location.replace(makeUrl($.url(), function(query) { - if (defOn) { - if ($.url("?" + opt) != "n") { - query[opt] = "n"; - } else { - delete query[opt]; - } - } else { - if ($.url("?" + opt) == "y") { - delete query[opt]; - } else { - query[opt] = "y"; - } - } - })); - }); - } - - // Options - addOptionButton("linesfill", $("#pb-linesfill"), false); - addOptionButton("linessteps", $("#pb-linessteps"), false); - addOptionButton("linesshow", $("#pb-linesshow"), true); - addOptionButton("pointsshow", $("#pb-pointsshow"), true); - addOptionButton("legendshow", $("#pb-legendshow"), true); - addOptionButton("cutts", $("#pb-cutts"), false); - addOptionButton("autoscale", $("#pb-autoscale"), false); - - var pb_fullscreen = $("#pb-fullscreen"); - setActive(pb_fullscreen, fullscreen); - pb_fullscreen.click(function(){ - window.location.href = makeUrl($.url(), function(query) { - if (fullscreen) { - delete query.fullscreen; - } else { - query.fullscreen = "y"; - } - }); - }); - - // Embeded mode (in case there is other stuff on page) - function embededMode() { - $("#pb-fullscreen").hide(); - $("#pb-autoscale").hide(); - $("#pb-legendshow").hide(); - $("#pb-pause").hide(); - } - - function enableSelection() { - // Redraw chart with selection enabled - options.selection = {mode: "x"}; - var plot = $.plot(placeholder, data, options); - if ($.url("?sel_x1") && $.url("?sel_x2")) { - plot.setSelection({ - xaxis: { - from: $.url("?sel_x1") , - to: $.url("?sel_x2") - } - }); - } - - // Create selection hooks - placeholder.bind("plotselected", function (event, ranges) { - window.location.replace(makeUrl($.url(), function(query) { - query.sel_x1 = ranges.xaxis.from; - query.sel_x2 = ranges.xaxis.to; - })); - }); - placeholder.bind("plotunselected", function (event) { - window.location.replace(makeUrl($.url(), function(query) { - delete query.sel_x1; - delete query.sel_x2; - })); - }); - - // Init and show unselect button - $("#pb-unselect").click(function () { - plot.clearSelection(); - }); - $("#pb-unselect").removeClass("hidden"); - } - - // Export data - var pb_export = $("#pb-export"); - pb_export.click(function(){ - var blob = new Blob([JSON.stringify(data)], {type: "application/json;charset=utf-8"}); - saveAs(blob, "exported.json"); - }); - - // Import data - $("#btnDoImport").click(function(){ - var files = document.getElementById('importFiles').files; - if (files.length <= 0) { - return false; - } - - var fr = new FileReader(); - fr.onload = function(e) { - imported_data = imported_data.concat(JSON.parse(e.target.result)); - data = loaded_data.concat(imported_data); - $.plot(placeholder, data, options); - $('#importModal').modal('hide'); - } - fr.readAsText(files.item(0)); - }); - - // Initialize stuff and fetch data - onPlaybackControl(); -} +/* + * This code is executed from document ready function + * Also note that some variable are set from C++ code + */ + +var x1 = $.url("?x1"); +var x2 = $.url("?x2"); +var y1 = $.url("?y1"); +var y2 = $.url("?y2"); + +var gantt = $.url("?gantt"); +var out = $.url("?out"); + +var linesfill = $.url("?linesfill") == "y"; +var linessteps = $.url("?linessteps") == "y"; +var linesshow = $.url("?linesshow") != "n"; +var pointsshow = $.url("?pointsshow") != "n"; +var autoscale = $.url("?autoscale") == "y"; +var legendshow = $.url("?legendshow") != "n"; +var cutts = $.url("?cutts") == "y"; +var fullscreen = $.url("?fullscreen") == "y"; +var realnames = $.url("?realnames") == "y"; +var xzoomoff = $.url("?xzoomoff") == "y"; +var yzoomoff = $.url("?yzoomoff") == "y"; + +function inIframe() { try { return window.self !== window.top; } catch (e) { return true; } } +function inDashboard() { return fullscreen && inIframe(); } + +// URL management +function makeUrl(url, queryFunc, hashFunc) { + var query = $.url("?", url); + var hash = $.url("#", url); + if (paused) { + query.paused = "y"; + } + + if (queryFunc) { queryFunc(query); } + if (hashFunc) { hashFunc(hash); } + var queryStr = ""; + var first = true; + for (var k in query) { + queryStr += (first? "?": "&") + k + "=" + encodeURIComponent(query[k]); + first = false; + } + var hashStr = ""; + first = true; + for (k in hash) { + hashStr += (first? "#": "&") + k + "=" + encodeURIComponent(hash[k]); + first = false; + } + return queryStr + hashStr; +} + +function dataUrl() { + return makeUrl(dataurl, function(query) { + query.error = "text"; + }); +} + +// Error message popup +$("<div id='errmsg'></div>").css({ + position: "absolute", + display: "none", + border: "1px solid #faa", + padding: "2px", + "background-color": "#fcc", + opacity: 0.80 +}).appendTo("body"); + +if (out == "gantt") { + $("#gantt-apply").click(function() { + try { + let val = $("#textareaGantt").val().replace(/\s/g, ""); + JSON.parse(val); + window.location.replace(makeUrl($.url(), function(query) { + query.gantt = val; + })); + } catch(e) { + $("#errmsg").text("Not valid JSON: " + e) + .css({bottom: "5px", left: "25%", width: "50%"}) + .fadeIn(200); + } + }); + + if (gantt) { + // Data fetching and auto-refreshing + var fetchCounter = 0; + function fetchData() { + function onDataReceived(json, textStatus, xhr) { + $("#errmsg").hide(); + logs = json; + chart(config, logs, true); + } + + function onDataError(xhr, error) { + console.log(arguments); + $("#errmsg").text("Fetch data error: " + error + (xhr.status == 200? xhr.responseText: "")) + .css({bottom: "5px", left: "25%", width: "50%"}) + .fadeIn(200); + } + + if (dataurl) { + $.ajax({ + url: dataUrl(), + type: "GET", + dataType: "json", + success: function (json, textStatus, xhr) { onDataReceived(json, textStatus, xhr); }, + error: onDataError + }); + } else { + onDataReceived(datajson, "textStatus", "xhr"); + } + + // if (fetchPeriod > 0) { + // if (fetchCounter == 0) { + // fetchCounter++; + // setTimeout(function() { + // fetchCounter--; + // if (!paused) { + // fetchData(); + // } + // }, $("#errmsg").is(":visible")? errorPeriod: fetchPeriod); + // } + // } + } + + try { + var config = JSON.parse(gantt); + $("#textareaGantt").val(JSON.stringify(config, "\n", " ")); + let formHeight = 220; + var chart = d3.gantt() + .height(window.innerHeight - $("#placeholder")[0].getBoundingClientRect().y - window.scrollY - formHeight) + .selector("#placeholder"); + var logs = null; + fetchData(); + } catch(e) { + $("#textareaGantt").val(gantt); + alert("Not valid JSON: " + e); + } + } +} else { // flot + // Special options adjustment for fullscreen charts in iframe (solomon dashboards) + if (fullscreen) { + navigate = false; // Disable navigation to avoid scrolling problems + legendshow = false; // Show legend only on hover + } + + // Adjust zooming options + var xZoomRange = null; + var yZoomRange = null; + if (xzoomoff) { + xZoomRange = false; + } + if (yzoomoff) { + yZoomRange = false; + } + + var placeholder = $("#placeholder"); + var playback = $("#playback"); + + var data = null; + var loaded_data = []; + var imported_data = []; + var fetchPeriod = refreshPeriod; + var errorPeriod = 5000; + var playbackPeriod = 500; + var abstimestep = 1.0; + + var paused = $.url("?paused") == "y"; + var timestep = abstimestep; + + var seriesDescription = { + _time: "time", + _thread: "thread" + } + + function seriesDesc(name) { + if (seriesDescription.hasOwnProperty(name)) { + return (realnames? "[" + name + "] ": "") + seriesDescription[name]; + } else { + return name; + } + } + + playback.show(); + + var options = { + series: { + lines: { show: linesshow, fill: linesfill, steps: linessteps}, + points: { show: pointsshow }, + shadowSize: 0 + }, + xaxis: { zoomRange: xZoomRange }, + yaxis: { zoomRange: yZoomRange }, + grid: { clickable: true, hoverable: true }, + zoom: { interactive: navigate }, + pan: { interactive: navigate }, + legend: { + show: legendshow, + labelFormatter: function(label, series) { return seriesDesc(label) + '(' + seriesDesc(xn) + ')'; } + } + }; + + if (fullscreen) { + $("body").attr("class","body-fullscreen"); + $("#container").attr("class","container-fullscreen"); + $("#toolbar").attr("class","toolbar-fullscreen"); + $("#selectors-container").attr("class","toolbar-fullscreen"); + options.grid.margin = 0; + } + + if (x1) { options.xaxis.min = x1; } + if (x2) { options.xaxis.max = x2; } + if (y1) { options.yaxis.min = y1; } + if (y2) { options.yaxis.max = y2; } + + $("<div id='tooltip'></div>").css({ + position: "absolute", + display: "none", + border: "1px solid #fdd", + padding: "2px", + "background-color": "#fee", + opacity: 0.80 + }).appendTo("body"); + + // Helper to hide tooltip + var lastShow = new Date(); + var hideCounter = 0; + function hideTooltip() { + if (hideCounter == 0) { + hideCounter++; + setTimeout(function() { + hideCounter--; + if (new Date().getTime() - lastShow.getTime() > 1000) { + $("#tooltip").fadeOut(200); + } else if ($("#tooltip").is(":visible")) { + hideTooltip(); + } + }, 200); + } + } + + // Helper to hide legend + var legendLastShow = new Date(); + var legendHideCounter = 0; + function hideLegend() { + if (legendHideCounter == 0) { + legendHideCounter++; + setTimeout(function() { + legendHideCounter--; + if (new Date().getTime() - legendLastShow.getTime() > 1000) { + options.legend.show = false; + $.plot(placeholder, data, options); + } else { + hideLegend(); + } + }, 200); + } + } + + function onPlotClick(event, pos, item) { + // Leave fullscreen on click + var nonFullscreenUrl = makeUrl($.url(), function(query) { + delete query.fullscreen; + }); + if (inDashboard()) { + window.open(nonFullscreenUrl, "_blank"); + } else if (fullscreen) { + window.location.href = nonFullscreenUrl; + } + } + + function onPlotHover(event, pos, item) { + var redraw = false; + // Show legend on hover + if (fullscreen) { + legendLastShow = new Date(); + if (!options.legend.show) { + redraw = true; + } + options.legend.show = true; + hideLegend(); + } + + // Show names on hover + var left = placeholder.position().left; + var top = placeholder.position().top; + var ttmargin = 10; + var ttwidth = $("#tooltip").width(); + var ttheight = $("#tooltip").height(); + if (linessteps) { + var pts = data[0].data; + var idx = 0; + for (var i = 0; i < pts.length - 1; i++) { + var x1 = pts[i][0]; + var x2 = pts[i+1][0]; + if (pos.x >= x1 && (x2 == null || pos.x < x2)) { + idx = i; + } + } + var n = pts[idx][2]; + var html = (n? "<u><b><center>" + n + "</center></b></u>": "") + "<table><tr><td align=\"right\">" + seriesDesc(xn) + "</td><td>: </td><td>" + pts[idx][3] + "</td></tr>"; + for (var sid = 0; sid < data.length; sid++) { + var series = data[sid]; + var y = series.data[idx][4]; + html += "<tr><td align=\"right\">" + seriesDesc(series.label) + "</td><td>: </td><td>" + y + "</td></tr>"; + } + html += "</table>"; + + lastShow = new Date(); + if (pos.pageX < left + placeholder.width() && pos.pageX > left && + pos.pageY < top + placeholder.height() && pos.pageY > top) { + $("#tooltip").html(html) + .css({top: Math.max(top + ttmargin + 10, pos.pageY - ttheight - 20), + left: Math.max(left + ttmargin + 10, pos.pageX - ttwidth - 20)}) + .fadeIn(200, "swing", hideTooltip()); + } + } else { + if (item) { + var idx = item.dataIndex; + var n = item.series.data[idx][2]; + var x = item.series.data[idx][3]; //item.datapoint[0]; + var y = item.series.data[idx][4]; //item.datapoint[1]; + $("#tooltip").html((n? n + ": ": "") + seriesDesc(item.series.label) + " = " + y + ", " + seriesDesc(xn) + " = " + x) + .css({top: Math.max(top + ttmargin + 10, item.pageY - ttheight - 20), + left: Math.max(left + ttmargin + 10, item.pageX - ttwidth - 20)}) + .fadeIn(200); + } else { + $("#tooltip").hide(); + } + } + + // Redraw if required + if (redraw) { + $.plot(placeholder, data, options); + } + } + + // Add some more interactivity + function onZoomOrPan(event, plot) { + var axes = plot.getAxes(); + options.xaxis.min = axes.xaxis.min; + options.xaxis.max = axes.xaxis.max; + options.yaxis.min = axes.yaxis.min; + options.yaxis.max = axes.yaxis.max; + } + + // Bind to events + placeholder.bind("plotclick", onPlotClick); + placeholder.bind("plothover", onPlotHover); + placeholder.bind("plotpan", onZoomOrPan); + placeholder.bind("plotzoom", onZoomOrPan); + + // Data fetching and auto-refreshing + var fetchCounter = 0; + function fetchData() { + function onDataReceived(json, textStatus, xhr) { + $("#errmsg").hide(); + if (paused && logs) { + return; + } + + // Plot fetched data + loaded_data = json; + data = loaded_data.concat(imported_data); + + if (autoscale) { + var xmin = null; + var xmax = null; + var ymin = null; + var ymax = null; + for (var sid = 0; sid < data.length; sid++) { + var pts = data[sid].data; + for (var i = 0; i < pts.length; i++) { + var x = pts[i][0]; + var y = pts[i][1]; + if (x != null && y != null) { + if (xmin == null || x < xmin) { xmin = x; } + if (xmax == null || x > xmax) { xmax = x; } + if (ymin == null || y < ymin) { ymin = y; } + if (ymax == null || y > ymax) { ymax = y; } + } + } + } + if (xmin != null) { options.xaxis.min = xmin; } + if (xmax != null) { options.xaxis.max = xmax; } + if (ymin != null) { options.yaxis.min = ymin; } + if (ymax != null) { options.yaxis.max = ymax; } + } + $.plot(placeholder, data, options); + } + + function onDataError(xhr, error) { + console.log(arguments); + $("#errmsg").text("Fetch data error: " + error + (xhr.status == 200? xhr.responseText: "")) + .css({bottom: "5px", left: "25%", width: "50%"}) + .fadeIn(200); + } + + if (dataurl) { + $.ajax({ + url: dataUrl(), + type: "GET", + dataType: "json", + success: function (json, textStatus, xhr) { onDataReceived(json, textStatus, xhr); }, + error: onDataError + }); + } else { + onDataReceived(datajson, "textStatus", "xhr"); + } + + if (fetchPeriod > 0) { + if (fetchCounter == 0) { + fetchCounter++; + setTimeout(function() { + fetchCounter--; + if (!paused) { + fetchData(); + } + }, $("#errmsg").is(":visible")? errorPeriod: fetchPeriod); + } + } + } + + // Playback control + var pb_pause = $("#pb-pause"); + + function setActive(btn, active) { + if (active) { + btn.addClass("btn-primary"); + btn.removeClass("btn-default"); + } else { + btn.addClass("btn-default"); + btn.removeClass("btn-primary"); + } + } + + function onPlaybackControl() { + setActive(pb_pause, paused); + fetchPeriod = refreshPeriod; + fetchData(); + } + + function clickPause(val) { + paused = val; + onPlaybackControl(); + } + + pb_pause.click(function() { clickPause(!paused); }); + + function addOptionButton(opt, btn, defOn) { + setActive(btn, defOn ? $.url("?" + opt) != "n" : $.url("?" + opt) == "y"); + btn.click(function() { + window.location.replace(makeUrl($.url(), function(query) { + if (defOn) { + if ($.url("?" + opt) != "n") { + query[opt] = "n"; + } else { + delete query[opt]; + } + } else { + if ($.url("?" + opt) == "y") { + delete query[opt]; + } else { + query[opt] = "y"; + } + } + })); + }); + } + + // Options + addOptionButton("linesfill", $("#pb-linesfill"), false); + addOptionButton("linessteps", $("#pb-linessteps"), false); + addOptionButton("linesshow", $("#pb-linesshow"), true); + addOptionButton("pointsshow", $("#pb-pointsshow"), true); + addOptionButton("legendshow", $("#pb-legendshow"), true); + addOptionButton("cutts", $("#pb-cutts"), false); + addOptionButton("autoscale", $("#pb-autoscale"), false); + + var pb_fullscreen = $("#pb-fullscreen"); + setActive(pb_fullscreen, fullscreen); + pb_fullscreen.click(function(){ + window.location.href = makeUrl($.url(), function(query) { + if (fullscreen) { + delete query.fullscreen; + } else { + query.fullscreen = "y"; + } + }); + }); + + // Embeded mode (in case there is other stuff on page) + function embededMode() { + $("#pb-fullscreen").hide(); + $("#pb-autoscale").hide(); + $("#pb-legendshow").hide(); + $("#pb-pause").hide(); + } + + function enableSelection() { + // Redraw chart with selection enabled + options.selection = {mode: "x"}; + var plot = $.plot(placeholder, data, options); + if ($.url("?sel_x1") && $.url("?sel_x2")) { + plot.setSelection({ + xaxis: { + from: $.url("?sel_x1") , + to: $.url("?sel_x2") + } + }); + } + + // Create selection hooks + placeholder.bind("plotselected", function (event, ranges) { + window.location.replace(makeUrl($.url(), function(query) { + query.sel_x1 = ranges.xaxis.from; + query.sel_x2 = ranges.xaxis.to; + })); + }); + placeholder.bind("plotunselected", function (event) { + window.location.replace(makeUrl($.url(), function(query) { + delete query.sel_x1; + delete query.sel_x2; + })); + }); + + // Init and show unselect button + $("#pb-unselect").click(function () { + plot.clearSelection(); + }); + $("#pb-unselect").removeClass("hidden"); + } + + // Export data + var pb_export = $("#pb-export"); + pb_export.click(function(){ + var blob = new Blob([JSON.stringify(data)], {type: "application/json;charset=utf-8"}); + saveAs(blob, "exported.json"); + }); + + // Import data + $("#btnDoImport").click(function(){ + var files = document.getElementById('importFiles').files; + if (files.length <= 0) { + return false; + } + + var fr = new FileReader(); + fr.onload = function(e) { + imported_data = imported_data.concat(JSON.parse(e.target.result)); + data = loaded_data.concat(imported_data); + $.plot(placeholder, data, options); + $('#importModal').modal('hide'); + } + fr.readAsText(files.item(0)); + }); + + // Initialize stuff and fetch data + onPlaybackControl(); +} diff --git a/library/cpp/lwtrace/mon/static/common.js b/library/cpp/lwtrace/mon/static/common.js index 42b93a6836..38ca5e464c 100644 --- a/library/cpp/lwtrace/mon/static/common.js +++ b/library/cpp/lwtrace/mon/static/common.js @@ -1,17 +1,17 @@ /* jquery.tablesorter.min.js 2.18.4 */ !function(h){h.extend({tablesorter:new function(){function d(){var b=arguments[0],a=1<arguments.length?Array.prototype.slice.call(arguments):b;if("undefined"!==typeof console&&"undefined"!==typeof console.log)console[/error/i.test(b)?"error":/warn/i.test(b)?"warn":"log"](a);else alert(a)}function r(b,a){d(b+" ("+((new Date).getTime()-a.getTime())+"ms)")}function k(b){for(var a in b)return!1;return!0}function v(b,a,c){if(!a)return"";var f,e=b.config,m=e.textExtraction||"",d="",d="basic"===m?h(a).attr(e.textAttribute)|| a.textContent||a.innerText||h(a).text()||"":"function"===typeof m?m(a,b,c):"function"===typeof(f=g.getColumnData(b,m,c))?f(a,b,c):a.textContent||a.innerText||h(a).text()||"";return h.trim(d)}function p(b){var a,c,f=b.config,e=f.$tbodies=f.$table.children("tbody:not(."+f.cssInfoBlock+")"),m,x,l,n,w,u,k,q,t,D=0,A="",y=e.length;if(0===y)return f.debug?d("Warning: *Empty table!* Not building a parser cache"):"";f.debug&&(t=new Date,d("Detecting parsers for each column"));a=[];for(c=[];D<y;){m=e[D].rows; if(m[D])for(x=f.columns,l=0;l<x;l++){n=f.$headers.filter('[data-column="'+l+'"]:last');w=g.getColumnData(b,f.headers,l);q=g.getParserById(g.getData(n,w,"extractor"));k=g.getParserById(g.getData(n,w,"sorter"));u="false"===g.getData(n,w,"parser");f.empties[l]=(g.getData(n,w,"empty")||f.emptyTo||(f.emptyToBottom?"bottom":"top")).toLowerCase();f.strings[l]=(g.getData(n,w,"string")||f.stringTo||"max").toLowerCase();u&&(k=g.getParserById("no-parser"));q||(q=!1);if(!k)a:{n=b;w=m;u=-1;k=l;for(var C=void 0, L=void 0,M=g.parsers.length,z=!1,B="",C=!0;""===B&&C;)u++,w[u]?(z=w[u].cells[k],B=v(n,z,k),L=h(z),n.config.debug&&d("Checking if value was empty on row "+u+", column: "+k+': "'+B+'"')):C=!1;for(;0<=--M;)if((C=g.parsers[M])&&"text"!==C.id&&C.is&&C.is(B,n,z,L)){k=C;break a}k=g.getParserById("text")}f.debug&&(A+="column:"+l+"; extractor:"+q.id+"; parser:"+k.id+"; string:"+f.strings[l]+"; empty: "+f.empties[l]+"\n");c[l]=k;a[l]=q}D+=c.length?y:1}f.debug&&(d(A?A:"No parsers detected"),r("Completed detecting parsers", t));f.parsers=c;f.extractors=a}function y(b){var a,c,f,e,m,x,l,n,w,u,k,q=b.config,t=q.$table.children("tbody"),p=q.extractors,A=q.parsers;q.cache={};q.totalRows=0;if(!A)return q.debug?d("Warning: *Empty table!* Not building a cache"):"";q.debug&&(n=new Date);q.showProcessing&&g.isProcessing(b,!0);for(m=0;m<t.length;m++)if(k=[],a=q.cache[m]={normalized:[]},!t.eq(m).hasClass(q.cssInfoBlock)){w=t[m]&&t[m].rows.length||0;for(f=0;f<w;++f)if(u={child:[]},x=h(t[m].rows[f]),l=[],x.hasClass(q.cssChildRow)&& 0!==f)c=a.normalized.length-1,a.normalized[c][q.columns].$row=a.normalized[c][q.columns].$row.add(x),x.prev().hasClass(q.cssChildRow)||x.prev().addClass(g.css.cssHasChild),u.child[c]=h.trim(x[0].textContent||x[0].innerText||x.text()||"");else{u.$row=x;u.order=f;for(e=0;e<q.columns;++e)"undefined"===typeof A[e]?q.debug&&d("No parser found for cell:",x[0].cells[e],"does it have a header?"):(c=v(b,x[0].cells[e],e),c="undefined"===typeof p[e].id?c:p[e].format(c,b,x[0].cells[e],e),c="no-parser"===A[e].id? "":A[e].format(c,b,x[0].cells[e],e),l.push(q.ignoreCase&&"string"===typeof c?c.toLowerCase():c),"numeric"===(A[e].type||"").toLowerCase()&&(k[e]=Math.max(Math.abs(c)||0,k[e]||0)));l[q.columns]=u;a.normalized.push(l)}a.colMax=k;q.totalRows+=a.normalized.length}q.showProcessing&&g.isProcessing(b);q.debug&&r("Building cache for "+w+" rows",n)}function B(b,a){var c=b.config,f=c.widgetOptions,e=b.tBodies,m=[],d=c.cache,l,n,w,u,p,q;if(k(d))return c.appender?c.appender(b,m):b.isUpdating?c.$table.trigger("updateComplete", b):"";c.debug&&(q=new Date);for(p=0;p<e.length;p++)if(l=h(e[p]),l.length&&!l.hasClass(c.cssInfoBlock)){w=g.processTbody(b,l,!0);l=d[p].normalized;n=l.length;for(u=0;u<n;u++)m.push(l[u][c.columns].$row),c.appender&&(!c.pager||c.pager.removeRows&&f.pager_removeRows||c.pager.ajax)||w.append(l[u][c.columns].$row);g.processTbody(b,w,!1)}c.appender&&c.appender(b,m);c.debug&&r("Rebuilt table",q);a||c.appender||g.applyWidget(b);b.isUpdating&&c.$table.trigger("updateComplete",b)}function F(b){return/^d/i.test(b)|| 1===b}function E(b){var a,c,f,e,m,x,l,n=b.config;n.headerList=[];n.headerContent=[];n.debug&&(l=new Date);n.columns=g.computeColumnIndex(n.$table.children("thead, tfoot").children("tr"));e=n.cssIcon?'<i class="'+(n.cssIcon===g.css.icon?g.css.icon:n.cssIcon+" "+g.css.icon)+'"></i>':"";n.$headers=h(h.map(h(b).find(n.selectorHeaders),function(l,d){c=h(l);if(!c.parent().hasClass(n.cssIgnoreRow))return a=g.getColumnData(b,n.headers,d,!0),n.headerContent[d]=c.html(),""!==n.headerTemplate&&(m=n.headerTemplate.replace(/\{content\}/g, c.html()).replace(/\{icon\}/g,e),n.onRenderTemplate&&(f=n.onRenderTemplate.apply(c,[d,m]))&&"string"===typeof f&&(m=f),c.html('<div class="'+g.css.headerIn+'">'+m+"</div>")),n.onRenderHeader&&n.onRenderHeader.apply(c,[d,n,n.$table]),l.column=parseInt(c.attr("data-column"),10),l.order=F(g.getData(c,a,"sortInitialOrder")||n.sortInitialOrder)?[1,0,2]:[0,1,2],l.count=-1,l.lockedOrder=!1,x=g.getData(c,a,"lockedOrder")||!1,"undefined"!==typeof x&&!1!==x&&(l.order=l.lockedOrder=F(x)?[1,1,1]:[0,0,0]),c.addClass(g.css.header+ " "+n.cssHeader),n.headerList[d]=l,c.parent().addClass(g.css.headerRow+" "+n.cssHeaderRow).attr("role","row"),n.tabIndex&&c.attr("tabindex",0),l}));h(b).find(n.selectorHeaders).attr({scope:"col",role:"columnheader"});H(b);n.debug&&(r("Built headers:",l),d(n.$headers))}function I(b,a,c){var f=b.config;f.$table.find(f.selectorRemove).remove();p(b);y(b);J(f.$table,a,c)}function H(b){var a,c,f,e=b.config;e.$headers.each(function(m,d){c=h(d);f=g.getColumnData(b,e.headers,m,!0);a="false"===g.getData(d, f,"sorter")||"false"===g.getData(d,f,"parser");d.sortDisabled=a;c[a?"addClass":"removeClass"]("sorter-false").attr("aria-disabled",""+a);b.id&&(a?c.removeAttr("aria-controls"):c.attr("aria-controls",b.id))})}function G(b){var a,c,f=b.config,e=f.sortList,m=e.length,d=g.css.sortNone+" "+f.cssNone,l=[g.css.sortAsc+" "+f.cssAsc,g.css.sortDesc+" "+f.cssDesc],n=[f.cssIconAsc,f.cssIconDesc,f.cssIconNone],w=["ascending","descending"],k=h(b).find("tfoot tr").children().add(f.$extraHeaders).removeClass(l.join(" ")); f.$headers.removeClass(l.join(" ")).addClass(d).attr("aria-sort","none").find("."+f.cssIcon).removeClass(n.join(" ")).addClass(n[2]);for(a=0;a<m;a++)if(2!==e[a][1]&&(b=f.$headers.not(".sorter-false").filter('[data-column="'+e[a][0]+'"]'+(1===m?":last":"")),b.length)){for(c=0;c<b.length;c++)b[c].sortDisabled||b.eq(c).removeClass(d).addClass(l[e[a][1]]).attr("aria-sort",w[e[a][1]]).find("."+f.cssIcon).removeClass(n[2]).addClass(n[e[a][1]]);k.length&&k.filter('[data-column="'+e[a][0]+'"]').removeClass(d).addClass(l[e[a][1]])}f.$headers.not(".sorter-false").each(function(){var b= h(this),a=this.order[(this.count+1)%(f.sortReset?3:2)],a=b.text()+": "+g.language[b.hasClass(g.css.sortAsc)?"sortAsc":b.hasClass(g.css.sortDesc)?"sortDesc":"sortNone"]+g.language[0===a?"nextAsc":1===a?"nextDesc":"nextNone"];b.attr("aria-label",a)})}function Q(b){var a,c,f=b.config;f.widthFixed&&0===f.$table.children("colgroup").length&&(a=h("<colgroup>"),c=h(b).width(),h(b.tBodies).not("."+f.cssInfoBlock).find("tr:first").children(":visible").each(function(){a.append(h("<col>").css("width",parseInt(h(this).width()/ c*1E3,10)/10+"%"))}),f.$table.prepend(a))}function R(b,a){var c,f,e,m,g,l=b.config,d=a||l.sortList;l.sortList=[];h.each(d,function(b,a){m=parseInt(a[0],10);if(e=l.$headers.filter('[data-column="'+m+'"]:last')[0]){f=(f=(""+a[1]).match(/^(1|d|s|o|n)/))?f[0]:"";switch(f){case "1":case "d":f=1;break;case "s":f=g||0;break;case "o":c=e.order[(g||0)%(l.sortReset?3:2)];f=0===c?1:1===c?0:2;break;case "n":e.count+=1;f=e.order[e.count%(l.sortReset?3:2)];break;default:f=0}g=0===b?f:g;c=[m,parseInt(f,10)||0]; l.sortList.push(c);f=h.inArray(c[1],e.order);e.count=0<=f?f:c[1]%(l.sortReset?3:2)}})}function S(b,a){return b&&b[a]?b[a].type||"":""}function N(b,a,c){if(b.isUpdating)return setTimeout(function(){N(b,a,c)},50);var f,e,m,d,l=b.config,n=!c[l.sortMultiSortKey],w=l.$table;w.trigger("sortStart",b);a.count=c[l.sortResetKey]?2:(a.count+1)%(l.sortReset?3:2);l.sortRestart&&(e=a,l.$headers.each(function(){this===e||!n&&h(this).is("."+g.css.sortDesc+",."+g.css.sortAsc)||(this.count=-1)}));e=parseInt(h(a).attr("data-column"), 10);if(n){l.sortList=[];if(null!==l.sortForce)for(f=l.sortForce,m=0;m<f.length;m++)f[m][0]!==e&&l.sortList.push(f[m]);f=a.order[a.count];if(2>f&&(l.sortList.push([e,f]),1<a.colSpan))for(m=1;m<a.colSpan;m++)l.sortList.push([e+m,f])}else{if(l.sortAppend&&1<l.sortList.length)for(m=0;m<l.sortAppend.length;m++)d=g.isValueInArray(l.sortAppend[m][0],l.sortList),0<=d&&l.sortList.splice(d,1);if(0<=g.isValueInArray(e,l.sortList))for(m=0;m<l.sortList.length;m++)d=l.sortList[m],f=l.$headers.filter('[data-column="'+ d[0]+'"]:last')[0],d[0]===e&&(d[1]=f.order[a.count],2===d[1]&&(l.sortList.splice(m,1),f.count=-1));else if(f=a.order[a.count],2>f&&(l.sortList.push([e,f]),1<a.colSpan))for(m=1;m<a.colSpan;m++)l.sortList.push([e+m,f])}if(null!==l.sortAppend)for(f=l.sortAppend,m=0;m<f.length;m++)f[m][0]!==e&&l.sortList.push(f[m]);w.trigger("sortBegin",b);setTimeout(function(){G(b);K(b);B(b);w.trigger("sortEnd",b)},1)}function K(b){var a,c,f,e,m,d,l,n,h,u,p,q=0,t=b.config,v=t.textSorter||"",A=t.sortList,z=A.length,y= b.tBodies.length;if(!t.serverSideSorting&&!k(t.cache)){t.debug&&(m=new Date);for(c=0;c<y;c++)d=t.cache[c].colMax,l=t.cache[c].normalized,l.sort(function(c,m){for(a=0;a<z;a++){e=A[a][0];n=A[a][1];q=0===n;if(t.sortStable&&c[e]===m[e]&&1===z)break;(f=/n/i.test(S(t.parsers,e)))&&t.strings[e]?(f="boolean"===typeof t.string[t.strings[e]]?(q?1:-1)*(t.string[t.strings[e]]?-1:1):t.strings[e]?t.string[t.strings[e]]||0:0,h=t.numberSorter?t.numberSorter(c[e],m[e],q,d[e],b):g["sortNumeric"+(q?"Asc":"Desc")](c[e], m[e],f,d[e],e,b)):(u=q?c:m,p=q?m:c,h="function"===typeof v?v(u[e],p[e],q,e,b):"object"===typeof v&&v.hasOwnProperty(e)?v[e](u[e],p[e],q,e,b):g["sortNatural"+(q?"Asc":"Desc")](c[e],m[e],e,b,t));if(h)return h}return c[t.columns].order-m[t.columns].order});t.debug&&r("Sorting on "+A.toString()+" and dir "+n+" time",m)}}function O(b,a){var c=b[0];c.isUpdating&&b.trigger("updateComplete",c);h.isFunction(a)&&a(b[0])}function J(b,a,c){var f=b[0].config.sortList;!1!==a&&!b[0].isProcessing&&f.length?b.trigger("sorton", [f,function(){O(b,c)},!0]):(O(b,c),g.applyWidget(b[0],!1))}function P(b){var a=b.config,c=a.$table;c.unbind("sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(a.namespace+" ")).bind("sortReset"+a.namespace,function(c,e){c.stopPropagation();a.sortList=[];G(b);K(b);B(b);h.isFunction(e)&&e(b)}).bind("updateAll"+a.namespace,function(c,e,m){c.stopPropagation();b.isUpdating= !0;g.refreshWidgets(b,!0,!0);g.restoreHeaders(b);E(b);g.bindEvents(b,a.$headers,!0);P(b);I(b,e,m)}).bind("update"+a.namespace+" updateRows"+a.namespace,function(a,c,m){a.stopPropagation();b.isUpdating=!0;H(b);I(b,c,m)}).bind("updateCell"+a.namespace,function(f,e,m,g){f.stopPropagation();b.isUpdating=!0;c.find(a.selectorRemove).remove();var l,d,k;d=c.find("tbody");k=h(e);f=d.index(h.fn.closest?k.closest("tbody"):k.parents("tbody").filter(":first"));l=h.fn.closest?k.closest("tr"):k.parents("tr").filter(":first"); e=k[0];d.length&&0<=f&&(d=d.eq(f).find("tr").index(l),k=k.index(),a.cache[f].normalized[d][a.columns].$row=l,l="undefined"===typeof a.extractors[k].id?v(b,e,k):a.extractors[k].format(v(b,e,k),b,e,k),e="no-parser"===a.parsers[k].id?"":a.parsers[k].format(l,b,e,k),a.cache[f].normalized[d][k]=a.ignoreCase&&"string"===typeof e?e.toLowerCase():e,"numeric"===(a.parsers[k].type||"").toLowerCase()&&(a.cache[f].colMax[k]=Math.max(Math.abs(e)||0,a.cache[f].colMax[k]||0)),J(c,m,g))}).bind("addRows"+a.namespace, function(f,e,m,g){f.stopPropagation();b.isUpdating=!0;if(k(a.cache))H(b),I(b,m,g);else{e=h(e).attr("role","row");var d,n,r,u,y,q=e.filter("tr").length,t=c.find("tbody").index(e.parents("tbody").filter(":first"));a.parsers&&a.parsers.length||p(b);for(f=0;f<q;f++){n=e[f].cells.length;y=[];u={child:[],$row:e.eq(f),order:a.cache[t].normalized.length};for(d=0;d<n;d++)r="undefined"===typeof a.extractors[d].id?v(b,e[f].cells[d],d):a.extractors[d].format(v(b,e[f].cells[d],d),b,e[f].cells[d],d),r="no-parser"=== a.parsers[d].id?"":a.parsers[d].format(r,b,e[f].cells[d],d),y[d]=a.ignoreCase&&"string"===typeof r?r.toLowerCase():r,"numeric"===(a.parsers[d].type||"").toLowerCase()&&(a.cache[t].colMax[d]=Math.max(Math.abs(y[d])||0,a.cache[t].colMax[d]||0));y.push(u);a.cache[t].normalized.push(y)}J(c,m,g)}}).bind("updateComplete"+a.namespace,function(){b.isUpdating=!1}).bind("sorton"+a.namespace,function(a,e,m,d){var l=b.config;a.stopPropagation();c.trigger("sortStart",this);R(b,e);G(b);l.delayInit&&k(l.cache)&& y(b);c.trigger("sortBegin",this);K(b);B(b,d);c.trigger("sortEnd",this);g.applyWidget(b);h.isFunction(m)&&m(b)}).bind("appendCache"+a.namespace,function(a,c,d){a.stopPropagation();B(b,d);h.isFunction(c)&&c(b)}).bind("updateCache"+a.namespace,function(c,e){a.parsers&&a.parsers.length||p(b);y(b);h.isFunction(e)&&e(b)}).bind("applyWidgetId"+a.namespace,function(c,e){c.stopPropagation();g.getWidgetById(e).format(b,a,a.widgetOptions)}).bind("applyWidgets"+a.namespace,function(a,c){a.stopPropagation();g.applyWidget(b, c)}).bind("refreshWidgets"+a.namespace,function(a,c,d){a.stopPropagation();g.refreshWidgets(b,c,d)}).bind("destroy"+a.namespace,function(a,c,d){a.stopPropagation();g.destroy(b,c,d)}).bind("resetToLoadState"+a.namespace,function(){g.refreshWidgets(b,!0,!0);a=h.extend(!0,g.defaults,a.originalSettings);b.hasInitialized=!1;g.setup(b,a)})}var g=this;g.version="2.18.4";g.parsers=[];g.widgets=[];g.defaults={theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null, onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1,sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,widgets:[],widgetOptions:{zebra:["even","odd"]},initWidgets:!0, widgetClass:"widget-{name}",initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",cssInfoBlock:"tablesorter-infoOnly",cssAllowClicks:"tablesorter-allowClicks",cssIgnoreRow:"tablesorter-ignoreRow",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[]}; g.css={table:"tablesorter",cssHasChild:"tablesorter-hasChildRow",childRow:"tablesorter-childRow",header:"tablesorter-header",headerRow:"tablesorter-headerRow",headerIn:"tablesorter-header-inner",icon:"tablesorter-icon",info:"tablesorter-infoOnly",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc",sortNone:"tablesorter-headerUnSorted"};g.language={sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ", nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"};g.log=d;g.benchmark=r;g.construct=function(b){return this.each(function(){var a=h.extend(!0,{},g.defaults,b);a.originalSettings=b;!this.hasInitialized&&g.buildTable&&"TABLE"!==this.tagName?g.buildTable(this,a):g.setup(this,a)})};g.setup=function(b,a){if(!b||!b.tHead||0===b.tBodies.length||!0===b.hasInitialized)return a.debug?d("ERROR: stopping initialization! No table, thead, tbody or tablesorter has already been initialized"): "";var c="",f=h(b),e=h.metadata;b.hasInitialized=!1;b.isProcessing=!0;b.config=a;h.data(b,"tablesorter",a);a.debug&&h.data(b,"startoveralltimer",new Date);a.supportsDataObject=function(a){a[0]=parseInt(a[0],10);return 1<a[0]||1===a[0]&&4<=parseInt(a[1],10)}(h.fn.jquery.split("."));a.string={max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1};a.emptyTo=a.emptyTo.toLowerCase();a.stringTo=a.stringTo.toLowerCase();/tablesorter\-/.test(f.attr("class"))||(c=""!==a.theme?" tablesorter-"+ a.theme:"");a.table=b;a.$table=f.addClass(g.css.table+" "+a.tableClass+c).attr("role","grid");a.$headers=f.find(a.selectorHeaders);a.namespace=a.namespace?"."+a.namespace.replace(/\W/g,""):".tablesorter"+Math.random().toString(16).slice(2);a.$table.children().children("tr").attr("role","row");a.$tbodies=f.children("tbody:not(."+a.cssInfoBlock+")").attr({"aria-live":"polite","aria-relevant":"all"});a.$table.children("caption").length&&(c=a.$table.children("caption")[0],c.id||(c.id=a.namespace.slice(1)+ "caption"),a.$table.attr("aria-labelledby",c.id));a.widgetInit={};a.textExtraction=a.$table.attr("data-text-extraction")||a.textExtraction||"basic";E(b);Q(b);p(b);a.totalRows=0;a.delayInit||y(b);g.bindEvents(b,a.$headers,!0);P(b);a.supportsDataObject&&"undefined"!==typeof f.data().sortlist?a.sortList=f.data().sortlist:e&&f.metadata()&&f.metadata().sortlist&&(a.sortList=f.metadata().sortlist);g.applyWidget(b,!0);0<a.sortList.length?f.trigger("sorton",[a.sortList,{},!a.initWidgets,!0]):(G(b),a.initWidgets&& g.applyWidget(b,!1));a.showProcessing&&f.unbind("sortBegin"+a.namespace+" sortEnd"+a.namespace).bind("sortBegin"+a.namespace+" sortEnd"+a.namespace,function(c){clearTimeout(a.processTimer);g.isProcessing(b);"sortBegin"===c.type&&(a.processTimer=setTimeout(function(){g.isProcessing(b,!0)},500))});b.hasInitialized=!0;b.isProcessing=!1;a.debug&&g.benchmark("Overall initialization time",h.data(b,"startoveralltimer"));f.trigger("tablesorter-initialized",b);"function"===typeof a.initialized&&a.initialized(b)}; g.getColumnData=function(b,a,c,f,e){if("undefined"!==typeof a&&null!==a){b=h(b)[0];var d;b=b.config;e=e||b.$headers;if(a[c])return f?a[c]:a[e.index(e.filter('[data-column="'+c+'"]:last'))];for(d in a)if("string"===typeof d&&(f=e.filter('[data-column="'+c+'"]:last').filter(d).add(e.filter('[data-column="'+c+'"]:last').find(d)),f.length))return a[d]}};g.computeColumnIndex=function(b){var a=[],c=0,f,e,d,g,l,k,r,u,p,q;for(f=0;f<b.length;f++)for(l=b[f].cells,e=0;e<l.length;e++){d=l[e];g=h(d);k=d.parentNode.rowIndex; g.index();r=d.rowSpan||1;u=d.colSpan||1;"undefined"===typeof a[k]&&(a[k]=[]);for(d=0;d<a[k].length+1;d++)if("undefined"===typeof a[k][d]){p=d;break}c=Math.max(p,c);g.attr({"data-column":p});for(d=k;d<k+r;d++)for("undefined"===typeof a[d]&&(a[d]=[]),q=a[d],g=p;g<p+u;g++)q[g]="x"}return c+1};g.isProcessing=function(b,a,c){b=h(b);var f=b[0].config,e=c||b.find("."+g.css.header);a?("undefined"!==typeof c&&0<f.sortList.length&&(e=e.filter(function(){return this.sortDisabled?!1:0<=g.isValueInArray(parseFloat(h(this).attr("data-column")), f.sortList)})),b.add(e).addClass(g.css.processing+" "+f.cssProcessing)):b.add(e).removeClass(g.css.processing+" "+f.cssProcessing)};g.processTbody=function(b,a,c){b=h(b)[0];if(c)return b.isProcessing=!0,a.before('<span class="tablesorter-savemyplace"/>'),c=h.fn.detach?a.detach():a.remove();c=h(b).find("span.tablesorter-savemyplace");a.insertAfter(c);c.remove();b.isProcessing=!1};g.clearTableBody=function(b){h(b)[0].config.$tbodies.children().detach()};g.bindEvents=function(b,a,c){b=h(b)[0];var f, e=b.config;!0!==c&&(e.$extraHeaders=e.$extraHeaders?e.$extraHeaders.add(a):a);a.find(e.selectorSort).add(a.filter(e.selectorSort)).unbind(["mousedown","mouseup","sort","keyup",""].join(e.namespace+" ")).bind(["mousedown","mouseup","sort","keyup",""].join(e.namespace+" "),function(c,d){var g;g=c.type;if(!(1!==(c.which||c.button)&&!/sort|keyup/.test(g)||"keyup"===g&&13!==c.which||"mouseup"===g&&!0!==d&&250<(new Date).getTime()-f)){if("mousedown"===g)return f=(new Date).getTime(),/(input|select|button|textarea)/i.test(c.target.tagName)|| h(c.target).closest("td,th").hasClass(e.cssAllowClicks)?"":!e.cancelSelection;e.delayInit&&k(e.cache)&&y(b);g=h.fn.closest?h(this).closest("th, td")[0]:/TH|TD/.test(this.tagName)?this:h(this).parents("th, td")[0];g=e.$headers[a.index(g)];g.sortDisabled||N(b,g,c)}});e.cancelSelection&&a.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})};g.restoreHeaders=function(b){var a=h(b)[0].config;a.$table.find(a.selectorHeaders).each(function(b){h(this).find("."+ g.css.headerIn).length&&h(this).html(a.headerContent[b])})};g.destroy=function(b,a,c){b=h(b)[0];if(b.hasInitialized){g.refreshWidgets(b,!0,!0);var f=h(b),e=b.config,d=f.find("thead:first"),k=d.find("tr."+g.css.headerRow).removeClass(g.css.headerRow+" "+e.cssHeaderRow),l=f.find("tfoot:first > tr").children("th, td");!1===a&&0<=h.inArray("uitheme",e.widgets)&&(f.trigger("applyWidgetId",["uitheme"]),f.trigger("applyWidgetId",["zebra"]));d.find("tr").not(k).remove();f.removeData("tablesorter").unbind("sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState ".split(" ").join(e.namespace+ " "));e.$headers.add(l).removeClass([g.css.header,e.cssHeader,e.cssAsc,e.cssDesc,g.css.sortAsc,g.css.sortDesc,g.css.sortNone].join(" ")).removeAttr("data-column").removeAttr("aria-label").attr("aria-disabled","true");k.find(e.selectorSort).unbind(["mousedown","mouseup","keypress",""].join(e.namespace+" "));g.restoreHeaders(b);f.toggleClass(g.css.table+" "+e.tableClass+" tablesorter-"+e.theme,!1===a);b.hasInitialized=!1;delete b.config.cache;"function"===typeof c&&c(b)}};g.regex={chunk:/(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i};g.sortNatural=function(b,a){if(b===a)return 0;var c,f,e,d,k,l;f=g.regex;if(f.hex.test(a)){c=parseInt(b.match(f.hex),16);e=parseInt(a.match(f.hex),16);if(c<e)return-1;if(c>e)return 1}c=b.replace(f.chunk,"\\0$1\\0").replace(f.chunks,"").split("\\0");f=a.replace(f.chunk,"\\0$1\\0").replace(f.chunks,"").split("\\0");l=Math.max(c.length,f.length);for(k=0;k<l;k++){e=isNaN(c[k])?c[k]||0:parseFloat(c[k])||0;d=isNaN(f[k])?f[k]||0:parseFloat(f[k])||0;if(isNaN(e)!== isNaN(d))return isNaN(e)?1:-1;typeof e!==typeof d&&(e+="",d+="");if(e<d)return-1;if(e>d)return 1}return 0};g.sortNaturalAsc=function(b,a,c,f,e){if(b===a)return 0;c=e.string[e.empties[c]||e.emptyTo];return""===b&&0!==c?"boolean"===typeof c?c?-1:1:-c||-1:""===a&&0!==c?"boolean"===typeof c?c?1:-1:c||1:g.sortNatural(b,a)};g.sortNaturalDesc=function(b,a,c,f,e){if(b===a)return 0;c=e.string[e.empties[c]||e.emptyTo];return""===b&&0!==c?"boolean"===typeof c?c?-1:1:c||1:""===a&&0!==c?"boolean"===typeof c?c? 1:-1:-c||-1:g.sortNatural(a,b)};g.sortText=function(b,a){return b>a?1:b<a?-1:0};g.getTextValue=function(b,a,c){if(c){var f=b?b.length:0,e=c+a;for(c=0;c<f;c++)e+=b.charCodeAt(c);return a*e}return 0};g.sortNumericAsc=function(b,a,c,f,e,d){if(b===a)return 0;d=d.config;e=d.string[d.empties[e]||d.emptyTo];if(""===b&&0!==e)return"boolean"===typeof e?e?-1:1:-e||-1;if(""===a&&0!==e)return"boolean"===typeof e?e?1:-1:e||1;isNaN(b)&&(b=g.getTextValue(b,c,f));isNaN(a)&&(a=g.getTextValue(a,c,f));return b-a};g.sortNumericDesc= function(b,a,c,f,e,d){if(b===a)return 0;d=d.config;e=d.string[d.empties[e]||d.emptyTo];if(""===b&&0!==e)return"boolean"===typeof e?e?-1:1:e||1;if(""===a&&0!==e)return"boolean"===typeof e?e?1:-1:-e||-1;isNaN(b)&&(b=g.getTextValue(b,c,f));isNaN(a)&&(a=g.getTextValue(a,c,f));return a-b};g.sortNumeric=function(b,a){return b-a};g.characterEquivalents={a:"\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5",A:"\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5",c:"\u00e7\u0107\u010d",C:"\u00c7\u0106\u010c",e:"\u00e9\u00e8\u00ea\u00eb\u011b\u0119", E:"\u00c9\u00c8\u00ca\u00cb\u011a\u0118",i:"\u00ed\u00ec\u0130\u00ee\u00ef\u0131",I:"\u00cd\u00cc\u0130\u00ce\u00cf",o:"\u00f3\u00f2\u00f4\u00f5\u00f6",O:"\u00d3\u00d2\u00d4\u00d5\u00d6",ss:"\u00df",SS:"\u1e9e",u:"\u00fa\u00f9\u00fb\u00fc\u016f",U:"\u00da\u00d9\u00db\u00dc\u016e"};g.replaceAccents=function(b){var a,c="[",f=g.characterEquivalents;if(!g.characterRegex){g.characterRegexArray={};for(a in f)"string"===typeof a&&(c+=f[a],g.characterRegexArray[a]=new RegExp("["+f[a]+"]","g"));g.characterRegex= new RegExp(c+"]")}if(g.characterRegex.test(b))for(a in f)"string"===typeof a&&(b=b.replace(g.characterRegexArray[a],a));return b};g.isValueInArray=function(b,a){var c,f=a.length;for(c=0;c<f;c++)if(a[c][0]===b)return c;return-1};g.addParser=function(b){var a,c=g.parsers.length,f=!0;for(a=0;a<c;a++)g.parsers[a].id.toLowerCase()===b.id.toLowerCase()&&(f=!1);f&&g.parsers.push(b)};g.getParserById=function(b){if("false"==b)return!1;var a,c=g.parsers.length;for(a=0;a<c;a++)if(g.parsers[a].id.toLowerCase()=== b.toString().toLowerCase())return g.parsers[a];return!1};g.addWidget=function(b){g.widgets.push(b)};g.hasWidget=function(b,a){b=h(b);return b.length&&b[0].config&&b[0].config.widgetInit[a]||!1};g.getWidgetById=function(b){var a,c,f=g.widgets.length;for(a=0;a<f;a++)if((c=g.widgets[a])&&c.hasOwnProperty("id")&&c.id.toLowerCase()===b.toLowerCase())return c};g.applyWidget=function(b,a){b=h(b)[0];var c=b.config,f=c.widgetOptions,e=" "+c.table.className+" ",d=[],k,l,n;!1!==a&&b.hasInitialized&&(b.isApplyingWidgets|| b.isUpdating)||(c.debug&&(k=new Date),n=new RegExp("\\s"+c.widgetClass.replace(/\{name\}/i,"([\\w-]+)")+"\\s","g"),e.match(n)&&(e=e.match(n))&&h.each(e,function(a,b){c.widgets.push(b.replace(n,"$1"))}),c.widgets.length&&(b.isApplyingWidgets=!0,c.widgets=h.grep(c.widgets,function(a,b){return h.inArray(a,c.widgets)===b}),h.each(c.widgets||[],function(a,b){(n=g.getWidgetById(b))&&n.id&&(n.priority||(n.priority=10),d[a]=n)}),d.sort(function(a,b){return a.priority<b.priority?-1:a.priority===b.priority? 0:1}),h.each(d,function(e,d){if(d){if(a||!c.widgetInit[d.id])c.widgetInit[d.id]=!0,d.hasOwnProperty("options")&&(f=b.config.widgetOptions=h.extend(!0,{},d.options,f)),d.hasOwnProperty("init")&&(c.debug&&(l=new Date),d.init(b,d,c,f),c.debug&&g.benchmark("Initializing "+d.id+" widget",l));!a&&d.hasOwnProperty("format")&&(c.debug&&(l=new Date),d.format(b,c,f,!1),c.debug&&g.benchmark((a?"Initializing ":"Applying ")+d.id+" widget",l))}})),setTimeout(function(){b.isApplyingWidgets=!1;h.data(b,"lastWidgetApplication", new Date)},0),c.debug&&(e=c.widgets.length,r("Completed "+(!0===a?"initializing ":"applying ")+e+" widget"+(1!==e?"s":""),k)))};g.refreshWidgets=function(b,a,c){b=h(b)[0];var f,e=b.config,k=e.widgets,r=g.widgets,l=r.length;for(f=0;f<l;f++)r[f]&&r[f].id&&(a||0>h.inArray(r[f].id,k))&&(e.debug&&d('Refeshing widgets: Removing "'+r[f].id+'"'),r[f].hasOwnProperty("remove")&&e.widgetInit[r[f].id]&&(r[f].remove(b,e,e.widgetOptions),e.widgetInit[r[f].id]=!1));!0!==c&&g.applyWidget(b,a)};g.getData=function(b, a,c){var d="";b=h(b);var e,g;if(!b.length)return"";e=h.metadata?b.metadata():!1;g=" "+(b.attr("class")||"");"undefined"!==typeof b.data(c)||"undefined"!==typeof b.data(c.toLowerCase())?d+=b.data(c)||b.data(c.toLowerCase()):e&&"undefined"!==typeof e[c]?d+=e[c]:a&&"undefined"!==typeof a[c]?d+=a[c]:" "!==g&&g.match(" "+c+"-")&&(d=g.match(new RegExp("\\s"+c+"-([\\w-]+)"))[1]||"");return h.trim(d)};g.formatFloat=function(b,a){if("string"!==typeof b||""===b)return b;var c;b=(a&&a.config?!1!==a.config.usNumberFormat: "undefined"!==typeof a?a:1)?b.replace(/,/g,""):b.replace(/[\s|\.]/g,"").replace(/,/g,".");/^\s*\([.\d]+\)/.test(b)&&(b=b.replace(/^\s*\(([.\d]+)\)/,"-$1"));c=parseFloat(b);return isNaN(c)?h.trim(b):c};g.isDigit=function(b){return isNaN(b)?/^[\-+(]?\d+[)]?$/.test(b.toString().replace(/[,.'"\s]/g,"")):!0}}});var p=h.tablesorter;h.fn.extend({tablesorter:p.construct});p.addParser({id:"no-parser",is:function(){return!1},format:function(){return""},type:"text"});p.addParser({id:"text",is:function(){return!0}, format:function(d,r){var k=r.config;d&&(d=h.trim(k.ignoreCase?d.toLocaleLowerCase():d),d=k.sortLocaleCompare?p.replaceAccents(d):d);return d},type:"text"});p.addParser({id:"digit",is:function(d){return p.isDigit(d)},format:function(d,r){var k=p.formatFloat((d||"").replace(/[^\w,. \-()]/g,""),r);return d&&"number"===typeof k?k:d?h.trim(d&&r.config.ignoreCase?d.toLocaleLowerCase():d):d},type:"numeric"});p.addParser({id:"currency",is:function(d){return/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/.test((d|| "").replace(/[+\-,. ]/g,""))},format:function(d,r){var k=p.formatFloat((d||"").replace(/[^\w,. \-()]/g,""),r);return d&&"number"===typeof k?k:d?h.trim(d&&r.config.ignoreCase?d.toLocaleLowerCase():d):d},type:"numeric"});p.addParser({id:"url",is:function(d){return/^(https?|ftp|file):\/\//.test(d)},format:function(d){return d?h.trim(d.replace(/(https?|ftp|file):\/\//,"")):d},parsed:!0,type:"text"});p.addParser({id:"isoDate",is:function(d){return/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/.test(d)},format:function(d, h){var k=d?new Date(d.replace(/-/g,"/")):d;return k instanceof Date&&isFinite(k)?k.getTime():d},type:"numeric"});p.addParser({id:"percent",is:function(d){return/(\d\s*?%|%\s*?\d)/.test(d)&&15>d.length},format:function(d,h){return d?p.formatFloat(d.replace(/%/g,""),h):d},type:"numeric"});p.addParser({id:"image",is:function(d,h,k,p){return 0<p.find("img").length},format:function(d,r,k){return h(k).find("img").attr(r.config.imgAttr||"alt")||d},parsed:!0,type:"text"});p.addParser({id:"usLongDate",is:function(d){return/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i.test(d)|| /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i.test(d)},format:function(d,h){var k=d?new Date(d.replace(/(\S)([AP]M)$/i,"$1 $2")):d;return k instanceof Date&&isFinite(k)?k.getTime():d},type:"numeric"});p.addParser({id:"shortDate",is:function(d){return/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/.test((d||"").replace(/\s+/g," ").replace(/[\-.,]/g,"/"))},format:function(d,h,k,v){if(d){k=h.config;var z=k.$headers.filter("[data-column="+v+"]:last");v=z.length&&z[0].dateFormat||p.getData(z, p.getColumnData(h,k.headers,v),"dateFormat")||k.dateFormat;h=d.replace(/\s+/g," ").replace(/[\-.,]/g,"/");"mmddyyyy"===v?h=h.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$1/$2"):"ddmmyyyy"===v?h=h.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$2/$1"):"yyyymmdd"===v&&(h=h.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,"$1/$2/$3"));h=new Date(h);return h instanceof Date&&isFinite(h)?h.getTime():d}return d},type:"numeric"});p.addParser({id:"time",is:function(d){return/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i.test(d)}, format:function(d,h){var k=d?new Date("2000/01/01 "+d.replace(/(\S)([AP]M)$/i,"$1 $2")):d;return k instanceof Date&&isFinite(k)?k.getTime():d},type:"numeric"});p.addParser({id:"metadata",is:function(){return!1},format:function(d,p,k){d=p.config;d=d.parserMetadataName?d.parserMetadataName:"sortValue";return h(k).metadata()[d]},type:"numeric"});p.addWidget({id:"zebra",priority:90,format:function(d,p,k){var v,z,y,B,F=new RegExp(p.cssChildRow,"i"),E=p.$tbodies;for(d=0;d<E.length;d++)y=0,v=E.eq(d),v=v.children("tr:visible").not(p.selectorRemove), v.each(function(){z=h(this);F.test(this.className)||y++;B=0===y%2;z.removeClass(k.zebra[B?1:0]).addClass(k.zebra[B?0:1])})},remove:function(d,h,k){var v;h=h.$tbodies;var z=(k.zebra||["even","odd"]).join(" ");for(k=0;k<h.length;k++)v=p.processTbody(d,h.eq(k),!0),v.children().removeClass(z),p.processTbody(d,v,!1)}})}(jQuery); /* jquery.tablesorter.widgets.min.js 2.18.4 */ ;(function(k,A){ var e=k.tablesorter=k.tablesorter||{}; e.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",footerRow:"",footerCells:"",icons:"",sortNone:"bootstrap-icon-unsorted",sortAsc:"icon-chevron-up glyphicon glyphicon-chevron-up",sortDesc:"icon-chevron-down glyphicon glyphicon-chevron-down",active:"",hover:"",filterRow:"",even:"",odd:""},jui:{table:"ui-widget ui-widget-content ui-corner-all",caption:"ui-widget-content",header:"ui-widget-header ui-corner-all ui-state-default", footerRow:"",footerCells:"",icons:"ui-icon",sortNone:"ui-icon-carat-2-n-s",sortAsc:"ui-icon-carat-1-n",sortDesc:"ui-icon-carat-1-s",active:"ui-state-active",hover:"ui-state-hover",filterRow:"",even:"ui-widget-content",odd:"ui-state-default"}};k.extend(e.css,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",wrapper:"tablesorter-wrapper",resizer:"tablesorter-resizer",sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyWrap:"tablesorter-sticky-wrapper"}); e.storage= function(c,a,b,d){c=k(c)[0];var e,h,g=!1;e={};h=c.config;var m=k(c);c=d&&d.id||m.attr(d&&d.group||"data-table-group")||c.id||k(".tablesorter").index(m);d=d&&d.url||m.attr(d&&d.page||"data-table-page")||h&&h.fixedUrl||A.location.pathname;if("localStorage"in A)try{A.localStorage.setItem("_tmptest","temp"),g=!0,A.localStorage.removeItem("_tmptest")}catch(n){}k.parseJSON&&(g?e=k.parseJSON(localStorage[a]||"{}"):(h=document.cookie.split(/[;\s|=]/),e=k.inArray(a,h)+1,e=0!==e?k.parseJSON(h[e]||"{}"):{})); if((b||""===b)&&A.JSON&&JSON.hasOwnProperty("stringify"))e[d]||(e[d]={}),e[d][c]=b,g?localStorage[a]=JSON.stringify(e):(b=new Date,b.setTime(b.getTime()+31536E6),document.cookie=a+"="+JSON.stringify(e).replace(/\"/g,'"')+"; expires="+b.toGMTString()+"; path=/");else return e&&e[d]?e[d][c]:""}; e.addHeaderResizeEvent=function(c,a,b){c=k(c)[0];var d;b=k.extend({},{timer:250},b);var e=c.config,h=e.widgetOptions,g=function(a){h.resize_flag=!0;d=[];e.$headers.each(function(){var a=k(this),b=a.data("savedSizes")|| [0,0],c=this.offsetWidth,e=this.offsetHeight;if(c!==b[0]||e!==b[1])a.data("savedSizes",[c,e]),d.push(this)});d.length&&!1!==a&&e.$table.trigger("resize",[d]);h.resize_flag=!1};g(!1);clearInterval(h.resize_timer);if(a)return h.resize_flag=!1;h.resize_timer=setInterval(function(){h.resize_flag||g()},b.timer)}; e.addWidget({id:"uitheme",priority:10,format:function(c,a,b){var d,f,h,g=e.themes;d=a.$table;var m=a.$headers,n=a.theme||"jui",p=g[n]||g.jui,g=[p.sortNone,p.sortDesc,p.sortAsc,p.active].join(" "); a.debug&&(f=new Date);d.hasClass("tablesorter-"+n)&&a.theme===a.appliedTheme&&c.hasInitialized||(h=(c=p[a.appliedTheme]||{},[c.sortNone,c.sortDesc,c.sortAsc,c.active].join(" ")),c&&(b.zebra[0]=b.zebra[0].replace(" "+c.even,""),b.zebra[1]=b.zebra[1].replace(" "+c.odd,"")),""!==p.even&&(b.zebra[0]+=" "+p.even),""!==p.odd&&(b.zebra[1]+=" "+p.odd),d.children("caption").removeClass(c.caption).addClass(p.caption),b=d.removeClass(a.appliedTheme?"tablesorter-"+(a.appliedTheme||""):"").addClass("tablesorter-"+ n+" "+p.table).children("tfoot"),b.length&&b.children("tr").removeClass(c.footerRow||"").addClass(p.footerRow).children("th, td").removeClass(c.footerCells||"").addClass(p.footerCells),m.add(a.$extraHeaders).removeClass(c.header+" "+c.hover+" "+h).addClass(p.header).not(".sorter-false").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(a){k(this)["mouseenter"===a.type?"addClass":"removeClass"](p.hover)}),m.find("."+e.css.wrapper).length||m.wrapInner('<div class="'+e.css.wrapper+'" style="position:relative;height:100%;width:100%"></div>'), a.cssIcon&&m.find("."+e.css.icon).removeClass(c.icons+" "+h).addClass(p.icons),d.hasClass("hasFilters")&&d.children("thead").children("."+e.css.filterRow).removeClass(c.filterRow).addClass(p.filterRow),a.appliedTheme=a.theme);for(d=0;d<a.columns;d++)b=a.$headers.add(a.$extraHeaders).not(".sorter-false").filter('[data-column="'+d+'"]'),c=e.css.icon?b.find("."+e.css.icon):b,h=m.not(".sorter-false").filter('[data-column="'+d+'"]:last'),h.length&&(h[0].sortDisabled?(b.removeClass(g),c.removeClass(g+" "+ p.icons)):(h=b.hasClass(e.css.sortAsc)?p.sortAsc:b.hasClass(e.css.sortDesc)?p.sortDesc:b.hasClass(e.css.header)?p.sortNone:"",b[h===p.sortNone?"removeClass":"addClass"](p.active),c.removeClass(g).addClass(h)));a.debug&&e.benchmark("Applying "+n+" theme",f)},remove:function(c,a){var b=a.$table,d=a.theme||"jui",f=e.themes[d]||e.themes.jui,h=b.children("thead").children(),g=f.sortNone+" "+f.sortDesc+" "+f.sortAsc;b.removeClass("tablesorter-"+d+" "+f.table).find(e.css.header).removeClass(f.header);h.unbind("mouseenter.tsuitheme mouseleave.tsuitheme").removeClass(f.hover+ " "+g+" "+f.active).find("."+e.css.filterRow).removeClass(f.filterRow);h.find("."+e.css.icon).removeClass(f.icons)}}); e.addWidget({id:"columns",priority:30,options:{columns:["primary","secondary","tertiary"]},format:function(c,a,b){var d,f,h,g,m,n,p=a.$table,r=a.$tbodies,w=a.sortList,x=w.length,t=b&&b.columns||["primary","secondary","tertiary"],u=t.length-1;m=t.join(" ");for(d=0;d<r.length;d++)a=e.processTbody(c,r.eq(d),!0),f=a.children("tr"),f.each(function(){h=k(this);if("none"!==this.style.display&& (g=h.children().removeClass(m),w&&w[0]&&(g.eq(w[0][0]).addClass(t[0]),1<x)))for(n=1;n<x;n++)g.eq(w[n][0]).addClass(t[n]||t[u])}),e.processTbody(c,a,!1);c=!1!==b.columns_thead?["thead tr"]:[];!1!==b.columns_tfoot&&c.push("tfoot tr");if(c.length&&(f=p.find(c.join(",")).children().removeClass(m),x))for(n=0;n<x;n++)f.filter('[data-column="'+w[n][0]+'"]').addClass(t[n]||t[u])},remove:function(c,a,b){var d=a.$tbodies,f=(b.columns||["primary","secondary","tertiary"]).join(" ");a.$headers.removeClass(f); a.$table.children("tfoot").children("tr").children("th, td").removeClass(f);for(a=0;a<d.length;a++)b=e.processTbody(c,d.eq(a),!0),b.children("tr").each(function(){k(this).children().removeClass(f)}),e.processTbody(c,b,!1)}}); e.addWidget({id:"filter",priority:50,options:{filter_childRows:!1,filter_columnFilters:!0,filter_cellFilter:"",filter_cssFilter:"",filter_defaultFilter:{},filter_excludeFilter:{},filter_external:"",filter_filteredRow:"filtered",filter_formatter:null,filter_functions:null,filter_hideEmpty:!0, filter_hideFilters:!1,filter_ignoreCase:!0,filter_liveSearch:!0,filter_onlyAvail:"filter-onlyAvail",filter_placeholder:{search:"",select:""},filter_reset:null,filter_saveFilters:!1,filter_searchDelay:300,filter_searchFiltered:!0,filter_selectSource:null,filter_startsWith:!1,filter_useParsedData:!1,filter_serversideFiltering:!1,filter_defaultAttrib:"data-value",filter_selectSourceSeparator:"|"},format:function(c,a,b){a.$table.hasClass("hasFilters")||e.filter.init(c,a,b)},remove:function(c,a,b){var d, f=a.$tbodies;a.$table.removeClass("hasFilters").unbind("addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(a.namespace+"filter ")).find("."+e.css.filterRow).remove();for(a=0;a<f.length;a++)d=e.processTbody(c,f.eq(a),!0),d.children().removeClass(b.filter_filteredRow).show(),e.processTbody(c,d,!1);b.filter_reset&&k(document).undelegate(b.filter_reset,"click.tsfilter")}}); e.filter={regex:{regex:/^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/,child:/tablesorter-childRow/, filtered:/filtered/,type:/undefined|number/,exact:/(^[\"\'=]+)|([\"\'=]+$)/g,nondigit:/[^\w,. \-()]/g,operators:/[<>=]/g,query:"(q|query)"},types:{regex:function(c,a){if(e.filter.regex.regex.test(a.iFilter)){var b,d=e.filter.regex.regex.exec(a.iFilter);try{b=(new RegExp(d[1],d[2])).test(a.iExact)}catch(f){b=!1}return b}return null},operators:function(c,a){if(/^[<>]=?/.test(a.iFilter)){var b,d;b=c.table;var f=a.index,h=a.parsed[f],g=e.formatFloat(a.iFilter.replace(e.filter.regex.operators,""),b),m= c.parsers[f],n=g;if(h||"numeric"===m.type)d=e.filter.parseFilter(c,k.trim(""+a.iFilter.replace(e.filter.regex.operators,"")),f,h,!0),g="number"!==typeof d||""===d||isNaN(d)?g:d;b=!h&&"numeric"!==m.type||isNaN(g)||"undefined"===typeof a.cache?isNaN(a.iExact)?e.formatFloat(a.iExact.replace(e.filter.regex.nondigit,""),b):e.formatFloat(a.iExact,b):a.cache;/>/.test(a.iFilter)&&(d=/>=/.test(a.iFilter)?b>=g:b>g);/</.test(a.iFilter)&&(d=/<=/.test(a.iFilter)?b<=g:b<g);d||""!==n||(d=!0);return d}return null}, notMatch:function(c,a){if(/^\!/.test(a.iFilter)){var b,d=e.filter.parseFilter(c,a.iFilter.replace("!",""),a.index,a.parsed[a.index]);if(e.filter.regex.exact.test(d))return d=d.replace(e.filter.regex.exact,""),""===d?!0:k.trim(d)!==a.iExact;b=a.iExact.search(k.trim(d));return""===d?!0:!(c.widgetOptions.filter_startsWith?0===b:0<=b)}return null},exact:function(c,a){if(e.filter.regex.exact.test(a.iFilter)){var b=e.filter.parseFilter(c,a.iFilter.replace(e.filter.regex.exact,""),a.index,a.parsed[a.index]); return a.anyMatch?0<=k.inArray(b,a.rowArray):b==a.iExact}return null},and:function(c,a){if(e.filter.regex.andTest.test(a.filter)){for(var b=a.index,d=a.parsed[b],f=a.iFilter.split(e.filter.regex.andSplit),h=0<=a.iExact.search(k.trim(e.filter.parseFilter(c,f[0],b,d))),g=f.length-1;h&&g;)h=h&&0<=a.iExact.search(k.trim(e.filter.parseFilter(c,f[g],b,d))),g--;return h}return null},range:function(c,a){if(e.filter.regex.toTest.test(a.iFilter)){var b,d;d=c.table;var f=a.index,h=a.parsed[f],g=a.iFilter.split(e.filter.regex.toSplit), k=e.formatFloat(e.filter.parseFilter(c,g[0].replace(e.filter.regex.nondigit,""),f,h),d),n=e.formatFloat(e.filter.parseFilter(c,g[1].replace(e.filter.regex.nondigit,""),f,h),d);if(h||"numeric"===c.parsers[f].type)b=c.parsers[f].format(""+g[0],d,c.$headers.eq(f),f),k=""===b||isNaN(b)?k:b,b=c.parsers[f].format(""+g[1],d,c.$headers.eq(f),f),n=""===b||isNaN(b)?n:b;b=!h&&"numeric"!==c.parsers[f].type||isNaN(k)||isNaN(n)?isNaN(a.iExact)?e.formatFloat(a.iExact.replace(e.filter.regex.nondigit,""),d):e.formatFloat(a.iExact, d):a.cache;k>n&&(d=k,k=n,n=d);return b>=k&&b<=n||""===k||""===n}return null},wild:function(c,a){if(/[\?\*\|]/.test(a.iFilter)||e.filter.regex.orReplace.test(a.filter)){var b=a.index,d=a.parsed[b],d=e.filter.parseFilter(c,a.iFilter.replace(e.filter.regex.orReplace,"|"),b,d);!c.$headers.filter('[data-column="'+b+'"]:last').hasClass("filter-match")&&/\|/.test(d)&&("|"===d[d.length-1]&&(d+="*"),d=a.anyMatch&&k.isArray(a.rowArray)?"("+d+")":"^("+d+")$");return(new RegExp(d.replace(/\?/g,"\\S{1}").replace(/\*/g, "\\S*"))).test(a.iExact)}return null},fuzzy:function(c,a){if(/^~/.test(a.iFilter)){var b,d=0,f=a.iExact.length,h=e.filter.parseFilter(c,a.iFilter.slice(1),a.index,a.parsed[a.index]);for(b=0;b<f;b++)a.iExact[b]===h[d]&&(d+=1);return d===h.length?!0:!1}return null}},init:function(c,a,b){e.language=k.extend(!0,{},{to:"to",or:"or",and:"and"},e.language);var d,f,h,g,m,n,p;d=e.filter.regex;a.$table.addClass("hasFilters");b.searchTimer=null;b.filter_initTimer=null;b.filter_formatterCount=0;b.filter_formatterInit= [];b.filter_anyColumnSelector='[data-column="all"],[data-column="any"]';b.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]';h="\\{"+e.filter.regex.query+"\\}";k.extend(d,{child:new RegExp(a.cssChildRow),filtered:new RegExp(b.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+e.language.or+"|-|"+e.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+e.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+e.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+e.language.and+ "|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+e.language.and+"|&&)\\s+)","gi"),orReplace:new RegExp("\\s+("+e.language.or+")\\s+","gi"),iQuery:new RegExp(h,"i"),igQuery:new RegExp(h,"ig")});!1!==b.filter_columnFilters&&a.$headers.filter(".filter-false, .parser-false").length!==a.$headers.length&&e.filter.buildRow(c,a,b);a.$table.bind("addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(a.namespace+"filter "),function(d,f){a.$table.find("."+ e.css.filterRow).toggle(!(b.filter_hideEmpty&&k.isEmptyObject(a.cache)&&(!a.delayInit||"appendCache"!==d.type)));/(search|filter)/.test(d.type)||(d.stopPropagation(),e.filter.buildDefault(c,!0));"filterReset"===d.type?(a.$table.find("."+e.css.filter).add(b.filter_$externalFilters).val(""),e.filter.searching(c,[])):"filterEnd"===d.type?e.filter.buildDefault(c,!0):(f="search"===d.type?f:"updateComplete"===d.type?a.$table.data("lastSearch"):"",/(update|add)/.test(d.type)&&"updateComplete"!==d.type&& (a.lastCombinedFilter=null,a.lastSearch=[]),e.filter.searching(c,f,!0));return!1});b.filter_reset&&(b.filter_reset instanceof k?b.filter_reset.click(function(){a.$table.trigger("filterReset")}):k(b.filter_reset).length&&k(document).undelegate(b.filter_reset,"click.tsfilter").delegate(b.filter_reset,"click.tsfilter",function(){a.$table.trigger("filterReset")}));if(b.filter_functions)for(m=0;m<a.columns;m++)if(h=e.getColumnData(c,b.filter_functions,m))if(g=a.$headers.filter('[data-column="'+m+'"]:last').removeClass("filter-select"), p=!(g.hasClass("filter-false")||g.hasClass("parser-false")),d="",!0===h&&p)e.filter.buildSelect(c,m);else if("object"===typeof h&&p){for(f in h)"string"===typeof f&&(d+=""===d?'<option value="">'+(g.data("placeholder")||g.attr("data-placeholder")||b.filter_placeholder.select||"")+"</option>":"",h=p=f,0<=f.indexOf(b.filter_selectSourceSeparator)&&(p=f.split(b.filter_selectSourceSeparator),h=p[1],p=p[0]),d+="<option "+(h===p?"":'data-function-name="'+f+'" ')+'value="'+p+'">'+h+"</option>");a.$table.find("thead").find("select."+ e.css.filter+'[data-column="'+m+'"]').append(d)}e.filter.buildDefault(c,!0);e.filter.bindSearch(c,a.$table.find("."+e.css.filter),!0);b.filter_external&&e.filter.bindSearch(c,b.filter_external);b.filter_hideFilters&&e.filter.hideFilters(c,a);a.showProcessing&&a.$table.bind("filterStart"+a.namespace+"filter filterEnd"+a.namespace+"filter",function(b,d){g=d?a.$table.find("."+e.css.header).filter("[data-column]").filter(function(){return""!==d[k(this).data("column")]}):"";e.isProcessing(c,"filterStart"=== b.type,d?g:"")});a.filteredRows=a.totalRows;a.$table.bind("tablesorter-initialized pagerBeforeInitialized",function(){var b=this.config.widgetOptions;n=e.filter.setDefaults(c,a,b)||[];n.length&&(a.delayInit&&""===n.join("")||e.setFilters(c,n,!0));a.$table.trigger("filterFomatterUpdate");setTimeout(function(){b.filter_initialized||e.filter.filterInitComplete(a)},100)});a.pager&&a.pager.initialized&&!b.filter_initialized&&(a.$table.trigger("filterFomatterUpdate"),setTimeout(function(){e.filter.filterInitComplete(a)}, 100))},formatterUpdated:function(c,a){var b=c.closest("table")[0].config.widgetOptions;b.filter_initialized||(b.filter_formatterInit[a]=1)},filterInitComplete:function(c){var a=c.widgetOptions,b=0,d=function(){a.filter_initialized=!0;c.$table.trigger("filterInit",c);e.filter.findRows(c.table,c.$table.data("lastSearch")||[])};k.isEmptyObject(a.filter_formatter)?d():(k.each(a.filter_formatterInit,function(a,c){1===c&&b++}),clearTimeout(a.filter_initTimer),a.filter_initialized||b!==a.filter_formatterCount)? a.filter_initialized||(a.filter_initTimer=setTimeout(function(){d()},500)):d()},setDefaults:function(c,a,b){var d,f=e.getFilters(c)||[];b.filter_saveFilters&&e.storage&&(d=e.storage(c,"tablesorter-filters")||[],(c=k.isArray(d))&&""===d.join("")||!c||(f=d));if(""===f.join(""))for(c=0;c<a.columns;c++)f[c]=a.$headers.filter('[data-column="'+c+'"]:last').attr(b.filter_defaultAttrib)||f[c];a.$table.data("lastSearch",f);return f},parseFilter:function(c,a,b,d,e){return e||d?c.parsers[b].format(a,c.table, [],b):a},buildRow:function(c,a,b){var d,f,h,g,m=a.columns;h=k.isArray(b.filter_cellFilter);g='<tr role="row" class="'+e.css.filterRow+'">';for(f=0;f<m;f++)g=h?g+("<td"+(b.filter_cellFilter[f]?' class="'+b.filter_cellFilter[f]+'"':"")+"></td>"):g+("<td"+(""!==b.filter_cellFilter?' class="'+b.filter_cellFilter+'"':"")+"></td>");a.$filters=k(g+"</tr>").appendTo(a.$table.children("thead").eq(0)).find("td");for(f=0;f<m;f++)h=a.$headers.filter('[data-column="'+f+'"]:last'),g=e.getColumnData(c,b.filter_functions, f),g=b.filter_functions&&g&&"function"!==typeof g||h.hasClass("filter-select"),d=e.getColumnData(c,a.headers,f),d="false"===e.getData(h[0],d,"filter")||"false"===e.getData(h[0],d,"parser"),g?g=k("<select>").appendTo(a.$filters.eq(f)):((g=e.getColumnData(c,b.filter_formatter,f))?(b.filter_formatterCount++,(g=g(a.$filters.eq(f),f))&&0===g.length&&(g=a.$filters.eq(f).children("input")),g&&(0===g.parent().length||g.parent().length&&g.parent()[0]!==a.$filters[f])&&a.$filters.eq(f).append(g)):g=k('<input type="search">').appendTo(a.$filters.eq(f)), g&&g.attr("placeholder",h.data("placeholder")||h.attr("data-placeholder")||b.filter_placeholder.search||"")),g&&(h=(k.isArray(b.filter_cssFilter)?"undefined"!==typeof b.filter_cssFilter[f]?b.filter_cssFilter[f]||"":"":b.filter_cssFilter)||"",g.addClass(e.css.filter+" "+h).attr("data-column",f),d&&(g.attr("placeholder","").addClass("disabled")[0].disabled=!0))},bindSearch:function(c,a,b){c=k(c)[0];a=k(a);if(a.length){var d=c.config,f=d.widgetOptions,h=f.filter_$externalFilters;!0!==b&&(f.filter_$anyMatch= a.filter(f.filter_anyColumnSelector+","+f.filter_multipleColumnSelector),f.filter_$externalFilters=h&&h.length?f.filter_$externalFilters.add(a):a,e.setFilters(c,d.$table.data("lastSearch")||[],!1===b));a.attr("data-lastSearchTime",(new Date).getTime()).unbind(["keypress","keyup","search","change",""].join(d.namespace+"filter ")).bind("keyup"+d.namespace+"filter",function(a){k(this).attr("data-lastSearchTime",(new Date).getTime());if(27===a.which)this.value="";else if(!1===f.filter_liveSearch||""!== this.value&&("number"===typeof f.filter_liveSearch&&this.value.length<f.filter_liveSearch||13!==a.which&&8!==a.which&&(32>a.which||37<=a.which&&40>=a.which)))return;e.filter.searching(c,!0,!0)}).bind(["search","change","keypress",""].join(d.namespace+"filter "),function(a){var b=k(this).data("column");if(13===a.which||"search"===a.type||"change"===a.type&&this.value!==d.lastSearch[b])a.preventDefault(),k(this).attr("data-lastSearchTime",(new Date).getTime()),e.filter.searching(c,!1,!0)})}},searching:function(c, a,b){var d=c.config.widgetOptions;clearTimeout(d.searchTimer);"undefined"===typeof a||!0===a?d.searchTimer=setTimeout(function(){e.filter.checkFilters(c,a,b)},d.filter_liveSearch?d.filter_searchDelay:10):e.filter.checkFilters(c,a,b)},checkFilters:function(c,a,b){var d=c.config,f=d.widgetOptions,h=k.isArray(a),g=h?a:e.getFilters(c,!0),m=(g||[]).join("");if(k.isEmptyObject(d.cache))d.delayInit&&d.pager&&d.pager.initialized&&d.$table.trigger("updateCache",[function(){e.filter.checkFilters(c,!1,b)}]); else if(h&&(e.setFilters(c,g,!1,!0!==b),f.filter_initialized||(d.lastCombinedFilter="")),f.filter_hideFilters&&d.$table.find("."+e.css.filterRow).trigger(""===m?"mouseleave":"mouseenter"),d.lastCombinedFilter!==m||!1===a)if(!1===a&&(d.lastCombinedFilter=null,d.lastSearch=[]),f.filter_initialized&&d.$table.trigger("filterStart",[g]),d.showProcessing)setTimeout(function(){e.filter.findRows(c,g,m);return!1},30);else return e.filter.findRows(c,g,m),!1},hideFilters:function(c,a){var b,d,f;k(c).find("."+ e.css.filterRow).addClass("hideme").bind("mouseenter mouseleave",function(c){b=k(this);clearTimeout(f);f=setTimeout(function(){/enter|over/.test(c.type)?b.removeClass("hideme"):k(document.activeElement).closest("tr")[0]!==b[0]&&""===a.lastCombinedFilter&&b.addClass("hideme")},200)}).find("input, select").bind("focus blur",function(b){d=k(this).closest("tr");clearTimeout(f);f=setTimeout(function(){if(""===e.getFilters(a.$table).join(""))d["focus"===b.type?"removeClass":"addClass"]("hideme")},200)})}, defaultFilter:function(c,a){if(""===c)return c;var b=e.filter.regex.iQuery,d=a.match(e.filter.regex.igQuery).length,f=1<d?k.trim(c).split(/\s/):[k.trim(c)],h=f.length-1,g=0,m=a;for(1>h&&1<d&&(f[1]=f[0]);b.test(m);)m=m.replace(b,f[g++]||""),b.test(m)&&g<h&&""!==(f[g]||"")&&(m=a.replace(b,m));return m},getLatestSearch:function(c){return c.sort(function(a,b){return k(b).attr("data-lastSearchTime")-k(a).attr("data-lastSearchTime")})},multipleColumns:function(c,a){var b,d;b=c.widgetOptions;var f=b.filter_initialized|| !a.filter(b.filter_anyColumnSelector).length,h=[],g=k.trim(e.filter.getLatestSearch(a).attr("data-column"));f&&/-/.test(g)&&(b=g.match(/(\d+)\s*-\s*(\d+)/g),k.each(b,function(a,b){var d;d=b.split(/\s*-\s*/);var e=parseInt(d[0],10)||0,f=parseInt(d[1],10)||c.columns-1;e>f&&(d=e,e=f,f=d);for(f>=c.columns&&(f=c.columns-1);e<=f;e++)h.push(e);g=g.replace(b,"")}));f&&/,/.test(g)&&(b=g.split(/\s*,\s*/),k.each(b,function(a,b){""!==b&&(d=parseInt(b,10),d<c.columns&&h.push(d))}));if(!h.length)for(d=0;d<c.columns;d++)h.push(d); return h},findRows:function(c,a,b){if(c.config.lastCombinedFilter!==b&&c.config.widgetOptions.filter_initialized){var d,f,h,g,m,n,p,r,w,x,t,u,y,A,z,B,C,G,D,H,F=e.filter.regex,q=c.config,v=q.widgetOptions,I=q.$table.children("tbody"),l={anyMatch:!1},J=["range","notMatch","operators"];l.parsed=q.$headers.map(function(a){return q.parsers&&q.parsers[a]&&q.parsers[a].parsed||e.getData&&"parsed"===e.getData(q.$headers.filter('[data-column="'+a+'"]:last'),e.getColumnData(c,q.headers,a),"filter")||k(this).hasClass("filter-parsed")}).get(); q.debug&&(e.log("Starting filter widget search",a),A=new Date);q.filteredRows=0;q.totalRows=0;b=(a||[]).join("");for(g=0;g<I.length;g++)if(!I.eq(g).hasClass(q.cssInfoBlock||e.css.info)){m=e.processTbody(c,I.eq(g),!0);r=q.columns;f=k(k.map(q.cache[g].normalized,function(a){return a[r].$row.get()}));if(""===b||v.filter_serversideFiltering)f.removeClass(v.filter_filteredRow).not("."+q.cssChildRow).show();else{f=f.not("."+q.cssChildRow);d=f.length;B=v.filter_searchFiltered;h=q.lastSearch||q.$table.data("lastSearch")|| [];if(B)for(n=0;n<r+1;n++)z=a[n]||"",B||(n=r),B=B&&h.length&&0===z.indexOf(h[n]||"")&&!F.alreadyFiltered.test(z)&&!/[=\"\|!]/.test(z)&&!(/(>=?\s*-\d)/.test(z)||/(<=?\s*\d)/.test(z))&&!(""!==z&&q.$filters&&q.$filters.eq(n).find("select").length&&!q.$headers.filter('[data-column="'+n+'"]:last').hasClass("filter-match"));z=f.not("."+v.filter_filteredRow).length;B&&0===z&&(B=!1);q.debug&&e.log("Searching through "+(B&&z<d?z:"all")+" rows");if(v.filter_$anyMatch&&v.filter_$anyMatch.length||a[q.columns])l.anyMatchFlag= !0,l.anyMatchFilter=v.filter_$anyMatch&&e.filter.getLatestSearch(v.filter_$anyMatch).val()||a[q.columns]||"",q.sortLocaleCompare&&(l.anyMatchFilter=e.replaceAccents(l.anyMatchFilter)),v.filter_defaultFilter&&F.iQuery.test(e.getColumnData(c,v.filter_defaultFilter,q.columns,!0)||"")&&(l.anyMatchFilter=e.filter.defaultFilter(l.anyMatchFilter,e.getColumnData(c,v.filter_defaultFilter,q.columns,!0)),B=!1),l.iAnyMatchFilter=v.filter_ignoreCase&&q.ignoreCase?l.anyMatchFilter.toLocaleLowerCase():l.anyMatchFilter; for(h=0;h<d;h++)if(l.cacheArray=q.cache[g].normalized[h],w=f[h].className,!(F.child.test(w)||B&&F.filtered.test(w))){y=!0;w=f.eq(h).nextUntil("tr:not(."+q.cssChildRow+")");l.childRowText=w.length&&v.filter_childRows?w.text():"";l.childRowText=v.filter_ignoreCase?l.childRowText.toLocaleLowerCase():l.childRowText;n=f.eq(h).children();if(l.anyMatchFlag){r=e.filter.multipleColumns(q,v.filter_$anyMatch);l.anyMatch=!0;l.rowArray=n.map(function(a){if(-1<k.inArray(a,r))return l.parsed[a]?a=l.cacheArray[a]: (a=v.filter_ignoreCase?k(this).text().toLowerCase():k(this).text(),q.sortLocaleCompare&&(a=e.replaceAccents(a))),a}).get();l.filter=l.anyMatchFilter;l.iFilter=l.iAnyMatchFilter;l.exact=l.rowArray.join(" ");l.iExact=v.filter_ignoreCase?l.exact.toLowerCase():l.exact;l.cache=l.cacheArray.slice(0,-1).join(" ");C=null;k.each(e.filter.types,function(a,b){if(0>k.inArray(a,J)&&(t=b(q,l),null!==t))return C=t,!1});if(null!==C)y=C;else if(v.filter_startsWith)for(y=!1,r=q.columns;!y&&0<r;)r--,y=y||0===l.rowArray[r].indexOf(l.iFilter); else y=0<=(l.iExact+l.childRowText).indexOf(l.iFilter);l.anyMatch=!1}for(r=0;r<q.columns;r++)l.filter=a[r],l.index=r,G=(e.getColumnData(c,v.filter_excludeFilter,r,!0)||"").split(/\s+/),l.filter&&(l.cache=l.cacheArray[r],v.filter_useParsedData||l.parsed[r]?l.exact=l.cache:(l.exact=k.trim(n.eq(r).text()),l.exact=q.sortLocaleCompare?e.replaceAccents(l.exact):l.exact),l.iExact=!F.type.test(typeof l.exact)&&v.filter_ignoreCase?l.exact.toLocaleLowerCase():l.exact,u=y,H=v.filter_columnFilters?q.$filters.add(q.$externalFilters).filter('[data-column="'+ r+'"]').find("select option:selected").attr("data-function-name")||"":"",l.filter=q.sortLocaleCompare?e.replaceAccents(l.filter):l.filter,z=!0,v.filter_defaultFilter&&F.iQuery.test(e.getColumnData(c,v.filter_defaultFilter,r)||"")&&(l.filter=e.filter.defaultFilter(l.filter,e.getColumnData(c,v.filter_defaultFilter,r)),z=!1),l.iFilter=v.filter_ignoreCase?(l.filter||"").toLocaleLowerCase():l.filter,D=e.getColumnData(c,v.filter_functions,r),p=q.$headers.filter('[data-column="'+r+'"]:last'),x=p.hasClass("filter-select"), D||x&&z?!0===D||x?u=p.hasClass("filter-match")?0<=l.iExact.search(l.iFilter):l.filter===l.exact:"function"===typeof D?u=D(l.exact,l.cache,l.filter,r,f.eq(h)):"function"===typeof D[H||l.filter]&&(u=D[H||l.filter](l.exact,l.cache,l.filter,r,f.eq(h))):(C=null,k.each(e.filter.types,function(a,b){if(0>k.inArray(a,G)&&(t=b(q,l),null!==t))return C=t,!1}),null!==C?u=C:(l.exact=(l.iExact+l.childRowText).indexOf(e.filter.parseFilter(q,l.iFilter,r,l.parsed[r])),u=!v.filter_startsWith&&0<=l.exact||v.filter_startsWith&& 0===l.exact)),y=u?y:!1);f.eq(h).toggle(y).toggleClass(v.filter_filteredRow,!y);w.length&&w.toggleClass(v.filter_filteredRow,!y)}}q.filteredRows+=f.not("."+v.filter_filteredRow).length;q.totalRows+=f.length;e.processTbody(c,m,!1)}q.lastCombinedFilter=b;q.lastSearch=a;q.$table.data("lastSearch",a);v.filter_saveFilters&&e.storage&&e.storage(c,"tablesorter-filters",a);q.debug&&e.benchmark("Completed filter widget search",A);v.filter_initialized&&q.$table.trigger("filterEnd",q);setTimeout(function(){q.$table.trigger("applyWidgets")}, 0)}},getOptionSource:function(c,a,b){var d,f=c.config,h=[],g=!1,m=f.widgetOptions.filter_selectSource,n=f.$table.data("lastSearch")||[],p=k.isFunction(m)?!0:e.getColumnData(c,m,a);b&&""!==n[a]&&(b=!1);if(!0===p)g=m(c,a,b);else{if(p instanceof k||"string"===k.type(p)&&0<=p.indexOf("</option>"))return p;k.isArray(p)?g=p:"object"===k.type(m)&&p&&(g=p(c,a,b))}!1===g&&(g=e.filter.getOptions(c,a,b));g=k.grep(g,function(a,b){return k.inArray(a,g)===b});f.$headers.filter('[data-column="'+a+'"]:last').hasClass("filter-select-nosort")|| (k.each(g,function(b,d){h.push({t:d,p:f.parsers&&f.parsers[a].format(d,c,[],a)})}),d=f.textSorter||"",h.sort(function(b,f){var g=b.p.toString(),h=f.p.toString();return k.isFunction(d)?d(g,h,!0,a,c):"object"===typeof d&&d.hasOwnProperty(a)?d[a](g,h,!0,a,c):e.sortNatural?e.sortNatural(g,h):!0}),g=[],k.each(h,function(a,b){g.push(b.t)}));return g},getOptions:function(c,a,b){var d,e,h,g,m=c.config,n=m.widgetOptions,p=m.$table.children("tbody"),r=[];for(d=0;d<p.length;d++)if(!p.eq(d).hasClass(m.cssInfoBlock))for(g= m.cache[d],e=m.cache[d].normalized.length,c=0;c<e;c++)h=g.row?g.row[c]:g.normalized[c][m.columns].$row[0],b&&h.className.match(n.filter_filteredRow)||(n.filter_useParsedData||m.parsers[a].parsed||m.$headers.filter('[data-column="'+a+'"]:last').hasClass("filter-parsed")?r.push(""+g.normalized[c][a]):(h=h.cells[a])&&r.push(k.trim(h.textContent||h.innerText||k(h).text())));return r},buildSelect:function(c,a,b,d,f){c=k(c)[0];a=parseInt(a,10);if(c.config.cache&&!k.isEmptyObject(c.config.cache)){var h, g;g=c.config;var m=g.widgetOptions,n=g.$headers.filter('[data-column="'+a+'"]:last'),n='<option value="">'+(n.data("placeholder")||n.attr("data-placeholder")||m.filter_placeholder.select||"")+"</option>",p=g.$table.find("thead").find("select."+e.css.filter+'[data-column="'+a+'"]').val();if("undefined"===typeof b||""===b)b=e.filter.getOptionSource(c,a,f);if(k.isArray(b)){for(c=0;c<b.length;c++)f=h=b[c]=(""+b[c]).replace(/\"/g,"""),0<=h.indexOf(m.filter_selectSourceSeparator)&&(h=h.split(m.filter_selectSourceSeparator), f=h[0],h=h[1]),n+=""!==b[c]?"<option "+(f===h?"":'data-function-name="'+b[c]+'" ')+'value="'+f+'">'+h+"</option>":"";b=[]}g=(g.$filters?g.$filters:g.$table.children("thead")).find("."+e.css.filter);m.filter_$externalFilters&&(g=g&&g.length?g.add(m.filter_$externalFilters):m.filter_$externalFilters);a=g.filter('select[data-column="'+a+'"]');a.length&&(a[d?"html":"append"](n),k.isArray(b)||a.append(b).val(p),a.val(p))}},buildDefault:function(c,a){var b,d,f,h=c.config,g=h.widgetOptions,k=h.columns;for(b= 0;b<k;b++)d=h.$headers.filter('[data-column="'+b+'"]:last'),f=!(d.hasClass("filter-false")||d.hasClass("parser-false")),(d.hasClass("filter-select")||!0===e.getColumnData(c,g.filter_functions,b))&&f&&e.filter.buildSelect(c,b,"",a,d.hasClass(g.filter_onlyAvail))}}; e.getFilters=function(c,a,b,d){var f,h,g=!1,m=c?k(c)[0].config:"",n=m?m.widgetOptions:"";if(!0!==a&&n&&!n.filter_columnFilters)return k(c).data("lastSearch");if(m&&(m.$filters&&(f=m.$filters.find("."+e.css.filter)),n.filter_$externalFilters&& (f=f&&f.length?f.add(n.filter_$externalFilters):n.filter_$externalFilters),f&&f.length))for(g=b||[],c=0;c<m.columns+1;c++)h=c===m.columns?n.filter_anyColumnSelector+","+n.filter_multipleColumnSelector:'[data-column="'+c+'"]',a=f.filter(h),a.length&&(a=e.filter.getLatestSearch(a),k.isArray(b)?(d&&a.slice(1),c===m.columns&&(h=a.filter(n.filter_anyColumnSelector),a=h.length?h:a),a.val(b[c]).trigger("change.tsfilter")):(g[c]=a.val()||"",c===m.columns?a.slice(1).filter('[data-column*="'+a.attr("data-column")+ '"]').val(g[c]):a.slice(1).val(g[c])),c===m.columns&&a.length&&(n.filter_$anyMatch=a));0===g.length&&(g=!1);return g}; e.setFilters=function(c,a,b,d){var f=c?k(c)[0].config:"";c=e.getFilters(c,!0,a,d);f&&b&&(f.lastCombinedFilter=null,f.lastSearch=[],e.filter.searching(f.$table[0],a,d),f.$table.trigger("filterFomatterUpdate"));return!!c}; e.addWidget({id:"stickyHeaders",priority:60,options:{stickyHeaders:"",stickyHeaders_attachTo:null,stickyHeaders_xScroll:null,stickyHeaders_yScroll:null,stickyHeaders_offset:0, stickyHeaders_filteredToTop:!0,stickyHeaders_cloneId:"-sticky",stickyHeaders_addResizeEvent:!0,stickyHeaders_includeCaption:!0,stickyHeaders_zIndex:2},format:function(c,a,b){if(!(a.$table.hasClass("hasStickyHeaders")||0<=k.inArray("filter",a.widgets)&&!a.$table.hasClass("hasFilters"))){var d=a.$table,f=k(b.stickyHeaders_attachTo),h=a.namespace+"stickyheaders ",g=k(b.stickyHeaders_yScroll||b.stickyHeaders_attachTo||A),m=k(b.stickyHeaders_xScroll||b.stickyHeaders_attachTo||A),n=d.children("thead:first").children("tr").not(".sticky-false").children(), p=d.children("tfoot"),r=isNaN(b.stickyHeaders_offset)?k(b.stickyHeaders_offset):"",w=f.length?0:r.length?r.height()||0:parseInt(b.stickyHeaders_offset,10)||0,x=d.parent().closest("."+e.css.table).hasClass("hasStickyHeaders")?d.parent().closest("table.tablesorter")[0].config.widgetOptions.$sticky.parent():[],t=x.length?x.height():0,u=b.$sticky=d.clone().addClass("containsStickyHeaders "+e.css.sticky+" "+b.stickyHeaders).wrap('<div class="'+e.css.stickyWrap+'">'),y=u.parent().css({position:f.length? "absolute":"fixed",padding:parseInt(u.parent().parent().css("padding-left"),10),top:w+t,left:0,visibility:"hidden",zIndex:b.stickyHeaders_zIndex||2}),E=u.children("thead:first"),z,B="",C=0,G=function(a,b){a.filter(":visible").each(function(a){var d;a=b.filter(":visible").eq(a);var c=k(this);"border-box"===c.css("box-sizing")?d=c.outerWidth():"collapse"===a.css("border-collapse")?A.getComputedStyle?d=parseFloat(A.getComputedStyle(this,null).width):(d=parseFloat(c.css("border-width")),d=c.outerWidth()- parseFloat(c.css("padding-left"))-parseFloat(c.css("padding-right"))-d):d=c.width();a.css({"min-width":d,"max-width":d})})},D=function(){w=r.length?r.height()||0:parseInt(b.stickyHeaders_offset,10)||0;C=0;y.css({left:f.length?parseInt(f.css("padding-left"),10)||0:d.offset().left-parseInt(d.css("margin-left"),10)-m.scrollLeft()-C,width:d.outerWidth()});G(d,u);G(n,z)};u.attr("id")&&(u[0].id+=b.stickyHeaders_cloneId);u.find("thead:gt(0), tr.sticky-false").hide();u.find("tbody, tfoot").remove();u.find("caption").toggle(b.stickyHeaders_includeCaption); z=E.children().children();u.css({height:0,width:0,margin:0});z.find("."+e.css.resizer).remove();d.addClass("hasStickyHeaders").bind("pagerComplete"+h,function(){D()});e.bindEvents(c,E.children().children(".tablesorter-header"));d.after(y);a.onRenderHeader&&E.children("tr").children().each(function(b){a.onRenderHeader.apply(k(this),[b,a,u])});m.add(g).unbind(["scroll","resize",""].join(h)).bind(["scroll","resize",""].join(h),function(a){if(d.is(":visible")){t=x.length?x.offset().top-g.scrollTop()+ x.height():0;var b=d.offset(),c=k.isWindow(g[0]),e=k.isWindow(m[0]),h=(f.length?c?g.scrollTop():g.offset().top:g.scrollTop())+w+t,l=d.height()-(y.height()+(p.height()||0)),b=h>b.top&&h<b.top+l?"visible":"hidden",l={visibility:b};f.length&&(l.top=c?h:f.scrollTop());e&&(l.left=d.offset().left-parseInt(d.css("margin-left"),10)-m.scrollLeft()-C);x.length&&(l.top=(l.top||0)+w+t);y.removeClass("tablesorter-sticky-visible tablesorter-sticky-hidden").addClass("tablesorter-sticky-"+b).css(l);if(b!==B||"resize"=== a.type)D(),B=b}});b.stickyHeaders_addResizeEvent&&e.addHeaderResizeEvent(c);d.hasClass("hasFilters")&&b.filter_columnFilters&&(d.bind("filterEnd"+h,function(){var c=k(document.activeElement).closest("td"),c=c.parent().children().index(c);y.hasClass(e.css.stickyVis)&&b.stickyHeaders_filteredToTop&&(A.scrollTo(0,d.position().top),0<=c&&a.$filters&&a.$filters.eq(c).find("a, select, input").filter(":visible").focus())}),e.filter.bindSearch(d,z.find("."+e.css.filter)),b.filter_hideFilters&&e.filter.hideFilters(u, a));d.trigger("stickyHeadersInit")}},remove:function(c,a,b){var d=a.namespace+"stickyheaders ";a.$table.removeClass("hasStickyHeaders").unbind(["pagerComplete","filterEnd",""].join(d)).next("."+e.css.stickyWrap).remove();b.$sticky&&b.$sticky.length&&b.$sticky.remove();k(".hasStickyHeaders").length||k(A).add(b.stickyHeaders_xScroll).add(b.stickyHeaders_yScroll).add(b.stickyHeaders_attachTo).unbind(["scroll","resize",""].join(d));e.addHeaderResizeEvent(c,!1)}}); e.addWidget({id:"resizable",priority:40, options:{resizable:!0,resizable_addLastColumn:!1,resizable_widths:[],resizable_throttle:!1},format:function(c,a,b){if(!a.$table.hasClass("hasResizable")){a.$table.addClass("hasResizable");e.resizableReset(c,!0);var d,f,h,g,m,n={},p=a.$table,r=p.parent(),w="auto"===p.parent().css("overflow"),x=0,t=null,u=null,y=20>Math.abs(p.parent().width()-p.width()),E=function(a){if(0!==x&&t){var b=a.pageX-x,c=t.width();t.width(c+b);t.width()!==c&&y?u.width(u.width()-b):w&&(p.width(function(a,c){return c+b}),u.length|| (r[0].scrollLeft=p.width()));x=a.pageX}},z=function(){e.storage&&t&&u&&(n={},n[t.index()]=t.width(),n[u.index()]=u.width(),t.width(n[t.index()]),u.width(n[u.index()]),!1!==b.resizable&&e.storage(c,"tablesorter-resizable",a.$headers.map(function(){return k(this).width()}).get()));x=0;t=u=null;k(A).trigger("resize")};if(n=e.storage&&!1!==b.resizable?e.storage(c,"tablesorter-resizable"):{})for(g in n)!isNaN(g)&&g<a.$headers.length&&a.$headers.eq(g).width(n[g]);d=p.children("thead:first").children("tr"); d.children().each(function(){var b;b=k(this);g=b.attr("data-column");b="false"===e.getData(b,e.getColumnData(c,a.headers,g),"resizable");d.children().filter('[data-column="'+g+'"]')[b?"addClass":"removeClass"]("resizable-false")});d.each(function(){h=k(this).children().not(".resizable-false");k(this).find("."+e.css.wrapper).length||h.wrapInner('<div class="'+e.css.wrapper+'" style="position:relative;height:100%;width:100%"></div>');b.resizable_addLastColumn||(h=h.slice(0,-1));f=f?f.add(h):h});f.each(function(){var a= k(this),b=parseInt(a.css("padding-right"),10)+10;a.find("."+e.css.wrapper).append('<div class="'+e.css.resizer+'" style="cursor:w-resize;position:absolute;z-index:1;right:-'+b+'px;top:0;height:100%;width:20px;"></div>')}).find("."+e.css.resizer).bind("mousedown",function(b){t=k(b.target).closest("th");var c=a.$headers.filter('[data-column="'+t.attr("data-column")+'"]');1<c.length&&(t=t.add(c));u=b.shiftKey?t.parent().find("th").not(".resizable-false").filter(":last"):t.nextAll(":not(.resizable-false)").eq(0); x=b.pageX});k(document).bind("mousemove.tsresize",function(a){0!==x&&t&&(b.resizable_throttle?(clearTimeout(m),m=setTimeout(function(){E(a)},isNaN(b.resizable_throttle)?5:b.resizable_throttle)):E(a))}).bind("mouseup.tsresize",function(){z()});p.find("thead:first").bind("contextmenu.tsresize",function(){e.resizableReset(c);var a=k.isEmptyObject?k.isEmptyObject(n):!0;n={};return a})}},remove:function(c,a){a.$table.removeClass("hasResizable").children("thead").unbind("mouseup.tsresize mouseleave.tsresize contextmenu.tsresize").children("tr").children().unbind("mousemove.tsresize mouseup.tsresize").find("."+ e.css.resizer).remove();e.resizableReset(c)}}); e.resizableReset=function(c,a){k(c).each(function(){var b,d=this.config,f=d&&d.widgetOptions;c&&d&&(d.$headers.each(function(a){b=k(this);f.resizable_widths[a]?b.css("width",f.resizable_widths[a]):b.hasClass("resizable-false")||b.css("width","")}),e.storage&&!a&&e.storage(this,"tablesorter-resizable",{}))})}; e.addWidget({id:"saveSort",priority:20,options:{saveSort:!0},init:function(c,a,b,d){a.format(c,b,d,!0)},format:function(c,a,b,d){var f,h=a.$table; b=!1!==b.saveSort;var g={sortList:a.sortList};a.debug&&(f=new Date);h.hasClass("hasSaveSort")?b&&c.hasInitialized&&e.storage&&(e.storage(c,"tablesorter-savesort",g),a.debug&&e.benchmark("saveSort widget: Saving last sort: "+a.sortList,f)):(h.addClass("hasSaveSort"),g="",e.storage&&(g=(b=e.storage(c,"tablesorter-savesort"))&&b.hasOwnProperty("sortList")&&k.isArray(b.sortList)?b.sortList:"",a.debug&&e.benchmark('saveSort: Last sort loaded: "'+g+'"',f),h.bind("saveSortReset",function(a){a.stopPropagation(); e.storage(c,"tablesorter-savesort","")})),d&&g&&0<g.length?a.sortList=g:c.hasInitialized&&g&&0<g.length&&h.trigger("sorton",[g]))},remove:function(c){e.storage&&e.storage(c,"tablesorter-savesort","")}}) })(jQuery,window); -/* tablesorter */ $(document).ready(function(){$('table').tablesorter({theme:'bootstrap',widgets:['uitheme','zebra','filter'],headerTemplate:'{content} {icon}',widthFixed:true,ignoreCase:true,widgetOptions:{filter_columnFilters:true,zebra:['even','odd'],filter_reset:'.reset'}});}); -/* treegrid */ $(document).ready(function(){$('.tracks-tree').treegrid({'treeColumn':1});}); - -/* redirectPost */ -$.extend( -{ - redirectPost: function(location, args) - { - var form = ''; - $.each(args, function(key, value) { - form += '<input type="hidden" name="' + key + '" value="' + value + '">'; - }); - $('<form action="' + location + '" method="POST">' + form + '</form>').appendTo('body').submit(); - } -}); +/* tablesorter */ $(document).ready(function(){$('table').tablesorter({theme:'bootstrap',widgets:['uitheme','zebra','filter'],headerTemplate:'{content} {icon}',widthFixed:true,ignoreCase:true,widgetOptions:{filter_columnFilters:true,zebra:['even','odd'],filter_reset:'.reset'}});}); +/* treegrid */ $(document).ready(function(){$('.tracks-tree').treegrid({'treeColumn':1});}); + +/* redirectPost */ +$.extend( +{ + redirectPost: function(location, args) + { + var form = ''; + $.each(args, function(key, value) { + form += '<input type="hidden" name="' + key + '" value="' + value + '">'; + }); + $('<form action="' + location + '" method="POST">' + form + '</form>').appendTo('body').submit(); + } +}); diff --git a/library/cpp/lwtrace/mon/static/css/bootstrap.min.css b/library/cpp/lwtrace/mon/static/css/bootstrap.min.css index f602cacbf8..361830c990 100644 --- a/library/cpp/lwtrace/mon/static/css/bootstrap.min.css +++ b/library/cpp/lwtrace/mon/static/css/bootstrap.min.css @@ -1,9 +1,9 @@ -/*! - * Bootstrap v3.0.2 by @fat and @mdo - * Copyright 2013 Twitter, Inc. - * Licensed under http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world by @mdo and @fat. - */ - -/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#c09853}.text-warning:hover{color:#a47e3c}.text-danger{color:#b94a48}.text-danger:hover{color:#953b39}.text-success{color:#468847}.text-success:hover{color:#356635}.text-info{color:#3a87ad}.text-info:hover{color:#2d6987}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.container{width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.container{width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.container{width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .open>a .caret,.nav .open>a:hover .caret,.nav .open>a:focus .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-pills>li.active>a .caret,.nav-pills>li.active>a:hover .caret,.nav-pills>li.active>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:auto}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image: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)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-heading>.dropdown .caret{border-color:#333 transparent}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-heading>.dropdown .caret{border-color:#fff transparent}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading>.dropdown .caret{border-color:#468847 transparent}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading>.dropdown .caret{border-color:#c09853 transparent}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading>.dropdown .caret{border-color:#b94a48 transparent}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading>.dropdown .caret{border-color:#3a87ad transparent}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} +/*! + * Bootstrap v3.0.2 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#c09853}.text-warning:hover{color:#a47e3c}.text-danger{color:#b94a48}.text-danger:hover{color:#953b39}.text-success{color:#468847}.text-success:hover{color:#356635}.text-info{color:#3a87ad}.text-info:hover{color:#2d6987}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.container{width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.container{width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.container{width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .open>a .caret,.nav .open>a:hover .caret,.nav .open>a:focus .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-pills>li.active>a .caret,.nav-pills>li.active>a:hover .caret,.nav-pills>li.active>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:auto}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image: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)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-heading>.dropdown .caret{border-color:#333 transparent}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-heading>.dropdown .caret{border-color:#fff transparent}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading>.dropdown .caret{border-color:#468847 transparent}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading>.dropdown .caret{border-color:#c09853 transparent}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading>.dropdown .caret{border-color:#b94a48 transparent}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading>.dropdown .caret{border-color:#3a87ad transparent}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} diff --git a/library/cpp/lwtrace/mon/static/css/d3-gantt.css b/library/cpp/lwtrace/mon/static/css/d3-gantt.css index 25ba8fae6e..d6aeeb1a54 100644 --- a/library/cpp/lwtrace/mon/static/css/d3-gantt.css +++ b/library/cpp/lwtrace/mon/static/css/d3-gantt.css @@ -1,68 +1,68 @@ -.chart { - font-family: Arial, sans-serif; - font-size: 12px; -} - -rect.zoom-panel { - /*cursor: ew-resize;*/ - fill: none; - pointer-events: all; -} - -.axis path,.axis line { - fill: none; - stroke: #000; - shape-rendering: crispEdges; -} - -.axis.y { - font-size: 16px; - cursor: ns-resize; -} - -.axis.x { - font-size: 16px; -} - -#ruler { - text-anchor: middle; - alignment-baseline: before-edge; - font-size: 16px; - font-family: sans-serif; - pointer-events: none; -} - -.d3-tip { - line-height: 1; - font-weight: bold; - padding: 12px; - background: rgba(0, 0, 0, 0.8); - color: #fff; - border-radius: 2px; -} - -.d3-tip pre { - font-weight: bold; - padding: 12px; - background: rgba(0, 0, 0, 0); - color: #fff; - border: 0px; -} - -/* Style northward tooltips differently */ -.d3-tip.n:after { - margin: -1px 0 0 0; - top: 100%; - left: 0; -} - -/* for arrowhead marker */ -#arrow { - stroke-width:1; - stroke-dasharray:0; -} - -.bar:hover { - stroke-width: 1px; - stroke: black; -}
\ No newline at end of file +.chart { + font-family: Arial, sans-serif; + font-size: 12px; +} + +rect.zoom-panel { + /*cursor: ew-resize;*/ + fill: none; + pointer-events: all; +} + +.axis path,.axis line { + fill: none; + stroke: #000; + shape-rendering: crispEdges; +} + +.axis.y { + font-size: 16px; + cursor: ns-resize; +} + +.axis.x { + font-size: 16px; +} + +#ruler { + text-anchor: middle; + alignment-baseline: before-edge; + font-size: 16px; + font-family: sans-serif; + pointer-events: none; +} + +.d3-tip { + line-height: 1; + font-weight: bold; + padding: 12px; + background: rgba(0, 0, 0, 0.8); + color: #fff; + border-radius: 2px; +} + +.d3-tip pre { + font-weight: bold; + padding: 12px; + background: rgba(0, 0, 0, 0); + color: #fff; + border: 0px; +} + +/* Style northward tooltips differently */ +.d3-tip.n:after { + margin: -1px 0 0 0; + top: 100%; + left: 0; +} + +/* for arrowhead marker */ +#arrow { + stroke-width:1; + stroke-dasharray:0; +} + +.bar:hover { + stroke-width: 1px; + stroke: black; +}
\ No newline at end of file diff --git a/library/cpp/lwtrace/mon/static/css/jquery.treegrid.css b/library/cpp/lwtrace/mon/static/css/jquery.treegrid.css index 3980272607..068cfdc134 100644 --- a/library/cpp/lwtrace/mon/static/css/jquery.treegrid.css +++ b/library/cpp/lwtrace/mon/static/css/jquery.treegrid.css @@ -1,8 +1,8 @@ -.treegrid-indent {width:16px; height: 16px; display: inline-block; position: relative;} -.treegrid-expander {width:16px; height: 16px; display: inline-block; position: relative; cursor: pointer;} -.treegrid-expander-expanded{background-image: url(../img/collapse.png); } -.treegrid-expander-collapsed{background-image: url(../img/expand.png);} - -.treegrid-element {white-space: unset;} - -.timelinehead {width:30vw;} +.treegrid-indent {width:16px; height: 16px; display: inline-block; position: relative;} +.treegrid-expander {width:16px; height: 16px; display: inline-block; position: relative; cursor: pointer;} +.treegrid-expander-expanded{background-image: url(../img/collapse.png); } +.treegrid-expander-collapsed{background-image: url(../img/expand.png);} + +.treegrid-element {white-space: unset;} + +.timelinehead {width:30vw;} diff --git a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg index 94fb5490a2..02ec85726c 100644 --- a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg +++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg @@ -1,288 +1,288 @@ -<?xml version="1.0" standalone="no"?> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > -<svg xmlns="http://www.w3.org/2000/svg"> -<metadata></metadata> -<defs> -<font id="glyphicons_halflingsregular" horiz-adv-x="1200" > -<font-face units-per-em="1200" ascent="960" descent="-240" /> -<missing-glyph horiz-adv-x="500" /> -<glyph horiz-adv-x="0" /> -<glyph horiz-adv-x="400" /> -<glyph unicode=" " /> -<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" /> -<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode=" " /> -<glyph unicode="¥" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" /> -<glyph unicode=" " horiz-adv-x="650" /> -<glyph unicode=" " horiz-adv-x="1300" /> -<glyph unicode=" " horiz-adv-x="650" /> -<glyph unicode=" " horiz-adv-x="1300" /> -<glyph unicode=" " horiz-adv-x="433" /> -<glyph unicode=" " horiz-adv-x="325" /> -<glyph unicode=" " horiz-adv-x="216" /> -<glyph unicode=" " horiz-adv-x="216" /> -<glyph unicode=" " horiz-adv-x="162" /> -<glyph unicode=" " horiz-adv-x="260" /> -<glyph unicode=" " horiz-adv-x="72" /> -<glyph unicode=" " horiz-adv-x="260" /> -<glyph unicode=" " horiz-adv-x="325" /> -<glyph unicode="€" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" /> -<glyph unicode="₽" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" /> -<glyph unicode="−" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="⌛" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" /> -<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" /> -<glyph unicode="☁" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" /> -<glyph unicode="⛺" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " /> -<glyph unicode="✉" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" /> -<glyph unicode="✏" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" /> -<glyph unicode="" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" /> -<glyph unicode="" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" /> -<glyph unicode="" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" /> -<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" /> -<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" /> -<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" /> -<glyph unicode="" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" /> -<glyph unicode="" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" /> -<glyph unicode="" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" /> -<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" /> -<glyph unicode="" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" /> -<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" /> -<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" /> -<glyph unicode="" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" /> -<glyph unicode="" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" /> -<glyph unicode="" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" /> -<glyph unicode="" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" /> -<glyph unicode="" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" /> -<glyph unicode="" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" /> -<glyph unicode="" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" /> -<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" /> -<glyph unicode="" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" /> -<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" /> -<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" /> -<glyph unicode="" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" /> -<glyph unicode="" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" /> -<glyph unicode="" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" /> -<glyph unicode="" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" /> -<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" /> -<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" /> -<glyph unicode="" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" /> -<glyph unicode="" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" /> -<glyph unicode="" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" /> -<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" /> -<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" /> -<glyph unicode="" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" /> -<glyph unicode="" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" /> -<glyph unicode="" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" /> -<glyph unicode="" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" /> -<glyph unicode="" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" /> -<glyph unicode="" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" /> -<glyph unicode="" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" /> -<glyph unicode="" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" /> -<glyph unicode="" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" /> -<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" /> -<glyph unicode="" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" /> -<glyph unicode="" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" /> -<glyph unicode="" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" /> -<glyph unicode="" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" /> -<glyph unicode="" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" /> -<glyph unicode="" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" /> -<glyph unicode="" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" /> -<glyph unicode="" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" /> -<glyph unicode="" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" /> -<glyph unicode="" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" /> -<glyph unicode="" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" /> -<glyph unicode="" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" /> -<glyph unicode="" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" /> -<glyph unicode="" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" /> -<glyph unicode="" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" /> -<glyph unicode="" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" /> -<glyph unicode="" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" /> -<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" /> -<glyph unicode="" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" /> -<glyph unicode="" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" /> -<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" /> -<glyph unicode="" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" /> -<glyph unicode="" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" /> -<glyph unicode="" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" /> -<glyph unicode="" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" /> -<glyph unicode="" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" /> -<glyph unicode="" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" /> -<glyph unicode="" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" /> -<glyph unicode="" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" /> -<glyph unicode="" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" /> -<glyph unicode="" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" /> -<glyph unicode="" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" /> -<glyph unicode="" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" /> -<glyph unicode="" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" /> -<glyph unicode="" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" /> -<glyph unicode="" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" /> -<glyph unicode="" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" /> -<glyph unicode="" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" /> -<glyph unicode="" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" /> -<glyph unicode="" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" /> -<glyph unicode="" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" /> -<glyph unicode="" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" /> -<glyph unicode="" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" /> -<glyph unicode="" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" /> -<glyph unicode="" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" /> -<glyph unicode="" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" /> -<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" /> -<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" /> -<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" /> -<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" /> -<glyph unicode="" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" /> -<glyph unicode="" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" /> -<glyph unicode="" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " /> -<glyph unicode="" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" /> -<glyph unicode="" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" /> -<glyph unicode="" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" /> -<glyph unicode="" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" /> -<glyph unicode="" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" /> -<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" /> -<glyph unicode="" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" /> -<glyph unicode="" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" /> -<glyph unicode="" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" /> -<glyph unicode="" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" /> -<glyph unicode="" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" /> -<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" /> -<glyph unicode="" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " /> -<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " /> -<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" /> -<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" /> -<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" /> -<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" /> -<glyph unicode="" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" /> -<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" /> -<glyph unicode="" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" /> -<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" /> -<glyph unicode="" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" /> -<glyph unicode="" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" /> -<glyph unicode="" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" /> -<glyph unicode="" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" /> -<glyph unicode="" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" /> -<glyph unicode="" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" /> -<glyph unicode="" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" /> -<glyph unicode="" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" /> -<glyph unicode="" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" /> -<glyph unicode="" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" /> -<glyph unicode="" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" /> -<glyph unicode="" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" /> -<glyph unicode="" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" /> -<glyph unicode="" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" /> -<glyph unicode="" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" /> -<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" /> -<glyph unicode="" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" /> -<glyph unicode="" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" /> -<glyph unicode="" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" /> -<glyph unicode="" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" /> -<glyph unicode="" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" /> -<glyph unicode="" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" /> -<glyph unicode="" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " /> -<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" /> -<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" /> -<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" /> -<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" /> -<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" /> -<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" /> -<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" /> -<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" /> -<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" /> -<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" /> -<glyph unicode="" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" /> -<glyph unicode="" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" /> -<glyph unicode="" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" /> -<glyph unicode="" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" /> -<glyph unicode="" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" /> -<glyph unicode="" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" /> -<glyph unicode="" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" /> -<glyph unicode="" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" /> -<glyph unicode="" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" /> -<glyph unicode="" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" /> -<glyph unicode="" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" /> -<glyph unicode="" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" /> -<glyph unicode="" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" /> -<glyph unicode="" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" /> -<glyph unicode="" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" /> -<glyph unicode="" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" /> -<glyph unicode="" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " /> -<glyph unicode="" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" /> -<glyph unicode="" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" /> -<glyph unicode="" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" /> -<glyph unicode="" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" /> -<glyph unicode="" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" /> -<glyph unicode="" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" /> -<glyph unicode="" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" /> -<glyph unicode="" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" /> -<glyph unicode="" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" /> -<glyph unicode="" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" /> -<glyph unicode="" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" /> -<glyph unicode="" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" /> -<glyph unicode="" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" /> -<glyph unicode="" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" /> -<glyph unicode="" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" /> -<glyph unicode="" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" /> -<glyph unicode="" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" /> -<glyph unicode="" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" /> -<glyph unicode="" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" /> -<glyph unicode="" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" /> -<glyph unicode="" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" /> -<glyph unicode="" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" /> -<glyph unicode="" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" /> -<glyph unicode="" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" /> -<glyph unicode="" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" /> -<glyph unicode="" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" /> -<glyph unicode="" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" /> -<glyph unicode="" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" /> -<glyph unicode="" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" /> -<glyph unicode="" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" /> -<glyph unicode="" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" /> -<glyph unicode="" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" /> -<glyph unicode="" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" /> -<glyph unicode="🔑" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" /> -<glyph unicode="🚪" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" /> -</font> -</defs></svg>
\ No newline at end of file +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="glyphicons_halflingsregular" horiz-adv-x="1200" > +<font-face units-per-em="1200" ascent="960" descent="-240" /> +<missing-glyph horiz-adv-x="500" /> +<glyph horiz-adv-x="0" /> +<glyph horiz-adv-x="400" /> +<glyph unicode=" " /> +<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" /> +<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode=" " /> +<glyph unicode="¥" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" /> +<glyph unicode=" " horiz-adv-x="650" /> +<glyph unicode=" " horiz-adv-x="1300" /> +<glyph unicode=" " horiz-adv-x="650" /> +<glyph unicode=" " horiz-adv-x="1300" /> +<glyph unicode=" " horiz-adv-x="433" /> +<glyph unicode=" " horiz-adv-x="325" /> +<glyph unicode=" " horiz-adv-x="216" /> +<glyph unicode=" " horiz-adv-x="216" /> +<glyph unicode=" " horiz-adv-x="162" /> +<glyph unicode=" " horiz-adv-x="260" /> +<glyph unicode=" " horiz-adv-x="72" /> +<glyph unicode=" " horiz-adv-x="260" /> +<glyph unicode=" " horiz-adv-x="325" /> +<glyph unicode="€" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" /> +<glyph unicode="₽" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" /> +<glyph unicode="−" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="⌛" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" /> +<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" /> +<glyph unicode="☁" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" /> +<glyph unicode="⛺" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " /> +<glyph unicode="✉" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" /> +<glyph unicode="✏" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" /> +<glyph unicode="" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" /> +<glyph unicode="" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" /> +<glyph unicode="" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" /> +<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" /> +<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" /> +<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" /> +<glyph unicode="" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" /> +<glyph unicode="" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" /> +<glyph unicode="" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" /> +<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" /> +<glyph unicode="" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" /> +<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" /> +<glyph unicode="" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" /> +<glyph unicode="" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" /> +<glyph unicode="" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" /> +<glyph unicode="" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" /> +<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" /> +<glyph unicode="" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" /> +<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" /> +<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" /> +<glyph unicode="" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" /> +<glyph unicode="" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" /> +<glyph unicode="" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" /> +<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" /> +<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" /> +<glyph unicode="" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" /> +<glyph unicode="" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" /> +<glyph unicode="" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" /> +<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" /> +<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" /> +<glyph unicode="" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" /> +<glyph unicode="" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" /> +<glyph unicode="" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" /> +<glyph unicode="" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" /> +<glyph unicode="" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" /> +<glyph unicode="" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" /> +<glyph unicode="" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" /> +<glyph unicode="" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" /> +<glyph unicode="" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" /> +<glyph unicode="" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" /> +<glyph unicode="" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" /> +<glyph unicode="" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" /> +<glyph unicode="" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" /> +<glyph unicode="" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" /> +<glyph unicode="" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" /> +<glyph unicode="" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" /> +<glyph unicode="" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" /> +<glyph unicode="" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" /> +<glyph unicode="" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" /> +<glyph unicode="" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" /> +<glyph unicode="" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" /> +<glyph unicode="" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" /> +<glyph unicode="" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" /> +<glyph unicode="" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" /> +<glyph unicode="" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" /> +<glyph unicode="" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" /> +<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" /> +<glyph unicode="" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" /> +<glyph unicode="" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" /> +<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" /> +<glyph unicode="" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" /> +<glyph unicode="" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" /> +<glyph unicode="" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" /> +<glyph unicode="" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" /> +<glyph unicode="" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" /> +<glyph unicode="" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" /> +<glyph unicode="" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" /> +<glyph unicode="" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" /> +<glyph unicode="" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" /> +<glyph unicode="" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" /> +<glyph unicode="" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" /> +<glyph unicode="" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" /> +<glyph unicode="" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" /> +<glyph unicode="" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" /> +<glyph unicode="" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" /> +<glyph unicode="" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" /> +<glyph unicode="" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" /> +<glyph unicode="" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" /> +<glyph unicode="" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" /> +<glyph unicode="" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" /> +<glyph unicode="" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" /> +<glyph unicode="" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" /> +<glyph unicode="" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" /> +<glyph unicode="" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" /> +<glyph unicode="" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" /> +<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" /> +<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" /> +<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" /> +<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" /> +<glyph unicode="" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" /> +<glyph unicode="" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" /> +<glyph unicode="" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " /> +<glyph unicode="" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" /> +<glyph unicode="" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" /> +<glyph unicode="" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" /> +<glyph unicode="" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" /> +<glyph unicode="" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" /> +<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" /> +<glyph unicode="" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" /> +<glyph unicode="" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" /> +<glyph unicode="" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" /> +<glyph unicode="" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" /> +<glyph unicode="" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" /> +<glyph unicode="" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" /> +<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" /> +<glyph unicode="" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" /> +<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" /> +<glyph unicode="" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" /> +<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" /> +<glyph unicode="" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" /> +<glyph unicode="" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" /> +<glyph unicode="" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" /> +<glyph unicode="" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" /> +<glyph unicode="" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" /> +<glyph unicode="" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" /> +<glyph unicode="" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" /> +<glyph unicode="" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" /> +<glyph unicode="" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" /> +<glyph unicode="" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" /> +<glyph unicode="" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" /> +<glyph unicode="" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" /> +<glyph unicode="" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" /> +<glyph unicode="" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" /> +<glyph unicode="" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" /> +<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" /> +<glyph unicode="" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" /> +<glyph unicode="" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" /> +<glyph unicode="" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" /> +<glyph unicode="" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" /> +<glyph unicode="" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" /> +<glyph unicode="" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" /> +<glyph unicode="" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" /> +<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" /> +<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" /> +<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" /> +<glyph unicode="" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" /> +<glyph unicode="" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" /> +<glyph unicode="" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" /> +<glyph unicode="" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" /> +<glyph unicode="" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" /> +<glyph unicode="" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" /> +<glyph unicode="" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" /> +<glyph unicode="" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" /> +<glyph unicode="" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" /> +<glyph unicode="" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" /> +<glyph unicode="" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" /> +<glyph unicode="" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" /> +<glyph unicode="" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" /> +<glyph unicode="" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" /> +<glyph unicode="" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " /> +<glyph unicode="" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" /> +<glyph unicode="" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" /> +<glyph unicode="" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" /> +<glyph unicode="" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" /> +<glyph unicode="" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" /> +<glyph unicode="" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" /> +<glyph unicode="" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" /> +<glyph unicode="" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" /> +<glyph unicode="" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" /> +<glyph unicode="" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" /> +<glyph unicode="" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" /> +<glyph unicode="" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" /> +<glyph unicode="" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" /> +<glyph unicode="" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" /> +<glyph unicode="" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" /> +<glyph unicode="" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" /> +<glyph unicode="" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" /> +<glyph unicode="" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" /> +<glyph unicode="" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" /> +<glyph unicode="" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" /> +<glyph unicode="" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" /> +<glyph unicode="" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" /> +<glyph unicode="" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" /> +<glyph unicode="" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" /> +<glyph unicode="" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" /> +<glyph unicode="" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" /> +<glyph unicode="" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" /> +<glyph unicode="" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" /> +<glyph unicode="" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" /> +<glyph unicode="" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" /> +<glyph unicode="" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" /> +<glyph unicode="" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" /> +<glyph unicode="" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" /> +<glyph unicode="🔑" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" /> +<glyph unicode="🚪" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" /> +</font> +</defs></svg>
\ No newline at end of file diff --git a/library/cpp/lwtrace/mon/static/header.html b/library/cpp/lwtrace/mon/static/header.html index 9a263673d3..52352eced8 100644 --- a/library/cpp/lwtrace/mon/static/header.html +++ b/library/cpp/lwtrace/mon/static/header.html @@ -1,11 +1,11 @@ -<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - -<link rel="stylesheet" href="lwtrace/mon/static/css/bootstrap.min.css"> -<link rel="stylesheet" href="lwtrace/mon/static/css/jquery.treegrid.css"> -<link rel="stylesheet" href="lwtrace/mon/static/common.css"> - -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/bootstrap.min.js"></script> -<script language="javascript" type="text/javascript" src="lwtrace/mon/static/common.js"></script> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + +<link rel="stylesheet" href="lwtrace/mon/static/css/bootstrap.min.css"> +<link rel="stylesheet" href="lwtrace/mon/static/css/jquery.treegrid.css"> +<link rel="stylesheet" href="lwtrace/mon/static/common.css"> + +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/bootstrap.min.js"></script> +<script language="javascript" type="text/javascript" src="lwtrace/mon/static/common.js"></script> diff --git a/library/cpp/lwtrace/mon/static/js/bootstrap.min.js b/library/cpp/lwtrace/mon/static/js/bootstrap.min.js index 80e40418f2..175d50353d 100644 --- a/library/cpp/lwtrace/mon/static/js/bootstrap.min.js +++ b/library/cpp/lwtrace/mon/static/js/bootstrap.min.js @@ -1,9 +1,9 @@ -/*! - * Bootstrap v3.0.2 by @fat and @mdo - * Copyright 2013 Twitter, Inc. - * Licensed under http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world by @mdo and @fat. - */ - -if("undefined"==typeof jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]}}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(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 c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d)};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.is("input")?"val":"html",e=c.data();a+="Text",e.resetText||c.data("resetText",c[d]()),c[d](e[a]||this.options[a]),setTimeout(function(){"loadingText"==a?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons"]');if(a.length){var b=this.$element.find("input").prop("checked",!this.$element.hasClass("active")).trigger("change");"radio"===b.prop("type")&&a.find(".active").removeClass("active")}this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}this.sliding=!0,f&&this.pause();var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});if(!e.hasClass("active")){if(this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(j),j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.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)}).emulateTransitionEnd(600)}else{if(this.$element.trigger(j),j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?(this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350),void 0):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(jQuery),+function(a){"use strict";function b(){a(d).remove(),a(e).each(function(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b),f.trigger(d=a.Event("show.bs.dropdown")),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown"),e.focus()}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).focus(),d.click();var h=a("[role=menu] li:not(.divider):visible a",f);if(h.length){var i=h.index(h.filter(":focus"));38==b.keyCode&&i>0&&i--,40==b.keyCode&&i<h.length-1&&i++,~i||(i=0),h.eq(i).focus()}}}};var g=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var c=a(this),d=c.data("dropdown");d||c.data("dropdown",d=new f(this)),"string"==typeof b&&d[b].call(c)})},a.fn.dropdown.Constructor=f,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=g,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",e,f.prototype.toggle).on("keydown.bs.dropdown.data-api",e+", [role=menu]",f.prototype.keydown)}(jQuery),+function(a){"use strict";var b=function(b,c){this.options=c,this.$element=a(b),this.$backdrop=this.isShown=null,this.options.remote&&this.$element.load(this.options.remote)};b.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},b.prototype.toggle=function(a){return this[this.isShown?"hide":"show"](a)},b.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.$element.on("click.dismiss.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(document.body),c.$element.show(),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one(a.support.transition.end,function(){c.$element.focus().trigger(e)}).emulateTransitionEnd(300):c.$element.focus().trigger(e)}))},b.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one(a.support.transition.end,a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},b.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.focus()},this))},b.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},b.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden.bs.modal")})},b.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},b.prototype.backdrop=function(b){var c=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var d=a.support.transition&&c;if(this.$backdrop=a('<div class="modal-backdrop '+c+'" />').appendTo(document.body),this.$element.on("click.dismiss.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),d&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;d?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()):b&&b()};var c=a.fn.modal;a.fn.modal=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},b.DEFAULTS,e.data(),"object"==typeof c&&c);f||e.data("bs.modal",f=new b(this,g)),"string"==typeof c?f[c](d):g.show&&f.show(d)})},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f,this).one("hide",function(){c.is(":visible")&&c.focus()})}),a(document).on("show.bs.modal",".modal",function(){a(document.body).addClass("modal-open")}).on("hidden.bs.modal",".modal",function(){a(document.body).removeClass("modal-open")})}(jQuery),+function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focus",i="hover"==g?"mouseleave":"blur";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show),void 0):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide),void 0):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this.tip();this.setContent(),this.options.animation&&c.addClass("fade");var d="function"==typeof this.options.placement?this.options.placement.call(this,c[0],this.$element[0]):this.options.placement,e=/\s?auto?\s?/i,f=e.test(d);f&&(d=d.replace(e,"")||"top"),c.detach().css({top:0,left:0,display:"block"}).addClass(d),this.options.container?c.appendTo(this.options.container):c.insertAfter(this.$element);var g=this.getPosition(),h=c[0].offsetWidth,i=c[0].offsetHeight;if(f){var j=this.$element.parent(),k=d,l=document.documentElement.scrollTop||document.body.scrollTop,m="body"==this.options.container?window.innerWidth:j.outerWidth(),n="body"==this.options.container?window.innerHeight:j.outerHeight(),o="body"==this.options.container?0:j.offset().left;d="bottom"==d&&g.top+g.height+i-l>n?"top":"top"==d&&g.top-l-i<0?"bottom":"right"==d&&g.right+h>m?"left":"left"==d&&g.left-h<o?"right":d,c.removeClass(k).addClass(d)}var p=this.getCalculatedOffset(d,g,h,i);this.applyPlacement(p,d),this.$element.trigger("shown.bs."+this.type)}},b.prototype.applyPlacement=function(a,b){var c,d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),a.top=a.top+g,a.left=a.left+h,d.offset(a).addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;if("top"==b&&j!=f&&(c=!0,a.top=a.top+f-j),/bottom|top/.test(b)){var k=0;a.left<0&&(k=-2*a.left,a.left=0,d.offset(a),i=d[0].offsetWidth,j=d[0].offsetHeight),this.replaceArrow(k-e+i,i,"left")}else this.replaceArrow(j-f,j,"top");c&&d.offset(a)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach()}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.$element.trigger("hidden.bs."+this.type),this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(jQuery),+function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");b.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(c).is("body")?a(window):a(c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#\w/.test(e)&&a(e);return f&&f.length&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parents(".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top()),"function"==typeof h&&(h=f.bottom());var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;this.affixed!==i&&(this.unpin&&this.$element.css("top",""),this.affixed=i,this.unpin="bottom"==i?e.top-d:null,this.$element.removeClass(b.RESET).addClass("affix"+(i?"-"+i:"")),"bottom"==i&&this.$element.offset({top:document.body.offsetHeight-h-this.$element.height()}))}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(jQuery); +/*! + * Bootstrap v3.0.2 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +if("undefined"==typeof jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]}}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(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 c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d)};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.is("input")?"val":"html",e=c.data();a+="Text",e.resetText||c.data("resetText",c[d]()),c[d](e[a]||this.options[a]),setTimeout(function(){"loadingText"==a?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons"]');if(a.length){var b=this.$element.find("input").prop("checked",!this.$element.hasClass("active")).trigger("change");"radio"===b.prop("type")&&a.find(".active").removeClass("active")}this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}this.sliding=!0,f&&this.pause();var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});if(!e.hasClass("active")){if(this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(j),j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.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)}).emulateTransitionEnd(600)}else{if(this.$element.trigger(j),j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?(this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350),void 0):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(jQuery),+function(a){"use strict";function b(){a(d).remove(),a(e).each(function(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b),f.trigger(d=a.Event("show.bs.dropdown")),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown"),e.focus()}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).focus(),d.click();var h=a("[role=menu] li:not(.divider):visible a",f);if(h.length){var i=h.index(h.filter(":focus"));38==b.keyCode&&i>0&&i--,40==b.keyCode&&i<h.length-1&&i++,~i||(i=0),h.eq(i).focus()}}}};var g=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var c=a(this),d=c.data("dropdown");d||c.data("dropdown",d=new f(this)),"string"==typeof b&&d[b].call(c)})},a.fn.dropdown.Constructor=f,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=g,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",e,f.prototype.toggle).on("keydown.bs.dropdown.data-api",e+", [role=menu]",f.prototype.keydown)}(jQuery),+function(a){"use strict";var b=function(b,c){this.options=c,this.$element=a(b),this.$backdrop=this.isShown=null,this.options.remote&&this.$element.load(this.options.remote)};b.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},b.prototype.toggle=function(a){return this[this.isShown?"hide":"show"](a)},b.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.$element.on("click.dismiss.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(document.body),c.$element.show(),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one(a.support.transition.end,function(){c.$element.focus().trigger(e)}).emulateTransitionEnd(300):c.$element.focus().trigger(e)}))},b.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one(a.support.transition.end,a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},b.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.focus()},this))},b.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},b.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden.bs.modal")})},b.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},b.prototype.backdrop=function(b){var c=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var d=a.support.transition&&c;if(this.$backdrop=a('<div class="modal-backdrop '+c+'" />').appendTo(document.body),this.$element.on("click.dismiss.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),d&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;d?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()):b&&b()};var c=a.fn.modal;a.fn.modal=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},b.DEFAULTS,e.data(),"object"==typeof c&&c);f||e.data("bs.modal",f=new b(this,g)),"string"==typeof c?f[c](d):g.show&&f.show(d)})},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f,this).one("hide",function(){c.is(":visible")&&c.focus()})}),a(document).on("show.bs.modal",".modal",function(){a(document.body).addClass("modal-open")}).on("hidden.bs.modal",".modal",function(){a(document.body).removeClass("modal-open")})}(jQuery),+function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focus",i="hover"==g?"mouseleave":"blur";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show),void 0):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide),void 0):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this.tip();this.setContent(),this.options.animation&&c.addClass("fade");var d="function"==typeof this.options.placement?this.options.placement.call(this,c[0],this.$element[0]):this.options.placement,e=/\s?auto?\s?/i,f=e.test(d);f&&(d=d.replace(e,"")||"top"),c.detach().css({top:0,left:0,display:"block"}).addClass(d),this.options.container?c.appendTo(this.options.container):c.insertAfter(this.$element);var g=this.getPosition(),h=c[0].offsetWidth,i=c[0].offsetHeight;if(f){var j=this.$element.parent(),k=d,l=document.documentElement.scrollTop||document.body.scrollTop,m="body"==this.options.container?window.innerWidth:j.outerWidth(),n="body"==this.options.container?window.innerHeight:j.outerHeight(),o="body"==this.options.container?0:j.offset().left;d="bottom"==d&&g.top+g.height+i-l>n?"top":"top"==d&&g.top-l-i<0?"bottom":"right"==d&&g.right+h>m?"left":"left"==d&&g.left-h<o?"right":d,c.removeClass(k).addClass(d)}var p=this.getCalculatedOffset(d,g,h,i);this.applyPlacement(p,d),this.$element.trigger("shown.bs."+this.type)}},b.prototype.applyPlacement=function(a,b){var c,d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),a.top=a.top+g,a.left=a.left+h,d.offset(a).addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;if("top"==b&&j!=f&&(c=!0,a.top=a.top+f-j),/bottom|top/.test(b)){var k=0;a.left<0&&(k=-2*a.left,a.left=0,d.offset(a),i=d[0].offsetWidth,j=d[0].offsetHeight),this.replaceArrow(k-e+i,i,"left")}else this.replaceArrow(j-f,j,"top");c&&d.offset(a)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach()}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.$element.trigger("hidden.bs."+this.type),this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(jQuery),+function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");b.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(c).is("body")?a(window):a(c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#\w/.test(e)&&a(e);return f&&f.length&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parents(".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top()),"function"==typeof h&&(h=f.bottom());var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;this.affixed!==i&&(this.unpin&&this.$element.css("top",""),this.affixed=i,this.unpin="bottom"==i?e.top-d:null,this.$element.removeClass(b.RESET).addClass("affix"+(i?"-"+i:"")),"bottom"==i&&this.$element.offset({top:document.body.offsetHeight-h-this.$element.height()}))}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(jQuery); diff --git a/library/cpp/lwtrace/mon/static/js/d3-gantt.js b/library/cpp/lwtrace/mon/static/js/d3-gantt.js index 54ec38ae57..4e95ad347a 100644 --- a/library/cpp/lwtrace/mon/static/js/d3-gantt.js +++ b/library/cpp/lwtrace/mon/static/js/d3-gantt.js @@ -1,759 +1,759 @@ -d3.gantt = function() { - function gantt(config, logs, autoscale) { - parseLogs(config, logs); - - if (autoscale) { - gantt.timeDomain([minT, maxT]); - } - - initAxis(); - - // create svg element - svg = d3.select(selector) - .append("svg") - .attr("class", "chart") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - ; - - // create arrowhead marker - defs = svg.append("defs"); - defs.append("marker") - .attr("id", "arrow") - .attr("viewBox", "0 -5 10 10") - .attr("refX", 5) - .attr("refY", 0) - .attr("markerWidth", 4) - .attr("markerHeight", 4) - .attr("orient", "auto") - .append("path") - .attr("d", "M0,-5L10,0L0,5") - .attr("class","arrowHead") - ; - - zoom = d3.zoom() - .scaleExtent([0.1, 1000]) - //.translateExtent([0, 0], [1000,0]) - .on("zoom", function() { - if (tipShown != null) { - tip.hide(tipShown); - } - var tr = d3.event.transform; - xZoomed = tr.rescaleX(x); - svg.select("g.x.axis").call(xAxis.scale(xZoomed)); - - var dy = d3.event.sourceEvent.screenY - zoom.startScreenY; - var newScrollTop = documentBodyScrollTop() - dy; - window.scrollTo(documentBodyScrollLeft(), newScrollTop); - documentBodyScrollTop(newScrollTop); - zoom.startScreenY = d3.event.sourceEvent.screenY; - - zoomContainer1.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); - zoomContainer2.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); - - render(); - }) - .on("start", function() { - zoom.startScreenY = d3.event.sourceEvent.screenY; - }) - .on("end", function() { - }) - ; - - svgChartContainer = svg.append('g') - .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") - ; - svgChart = svgChartContainer.append("svg") - .attr("top", 0) - .attr("left", 0) - .attr("width", width) - .attr("height", height) - .attr("viewBox", "0 0 " + width + " " + height) - ; - - zoomContainer1 = svgChart.append("g"); - - zoomPanel = svgChart.append("rect") - .attr("class", "zoom-panel") - .attr("width", width) - .attr("height", height) - .call(zoom) - ; - - zoomContainer2 = svgChart.append("g"); - bandsSvg = zoomContainer2.append("g"); - - // tooltips for bands - var maxTipHeight = 130; - const tipDirection = d => y(d.band) - maxTipHeight < documentBodyScrollTop()? 's': 'n'; - tip = d3.tip() - .attr("class", "d3-tip") - .offset(function(d) { - // compute x to return tip in chart region - var t0 = (d.t1 + d.t2) / 2; - var t1 = Math.min(Math.max(t0, xZoomed.invert(0)), xZoomed.invert(width)); - var dir = tipDirection(d); - return [dir === 'n'? -10 : 10, xZoomed(t1) - xZoomed(t0)]; - }) - .direction(tipDirection) - .html(function(d) { - let text = ''; - for (let item of d.record) { - text += probes[item[PROBEID]].provider + "." + probes[item[PROBEID]].name + "("; - let first = true; - for (let [param, value] of Object.entries(item[PARAMS])) { - text += (first? "": ", ") + param + "='" + value + "'"; - first = false; - } - text += ")\n"; - } - return "<pre>" + text + "</pre>"; - }) - ; - - bandsSvg.call(tip); - - render(); - - // container for non-zoomable elements - fixedContainer = svg.append("g") - .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") - ; - - // create x axis - fixedContainer.append("g") - .attr("class", "x axis") - .attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")") - .transition() - .call(xAxis) - ; - - // create y axis - fixedContainer.append("g") - .attr("class", "y axis") - .transition() - .call(yAxis) - ; - - // make y axis ticks draggable - var ytickdrag = d3.drag() - .on("drag", function(d) { - var ypos = d3.event.y - margin.top; - var index = Math.floor((ypos / y.step())); - index = Math.min(Math.max(index, 0), this.initDomain.length - 1); - if (index != this.curIndex) { - var newDomain = []; - for (var i = 0; i < this.initDomain.length; ++i) { - newDomain.push(this.initDomain[i]); - } - newDomain.splice(this.initIndex, 1); - newDomain.splice(index, 0, this.initDomain[this.initIndex]); - - this.curIndex = index; - this.curDomain = newDomain; - y.domain(newDomain); - - // rearange y scale and axis - svg.select("g.y.axis").transition().call(yAxis); - - // rearange other stuff - render(-1, true); - } - }) - .on("start", function(d) { - var ypos = d3.event.y - margin.top; - this.initIndex = Math.floor((ypos / y.step())); - this.initDomain = y.domain(); - }) - .on("end", function(d) { - svg.select("g.y.axis").call(yAxis); - }) - ; - svg.selectAll("g.y.axis .tick") - .call(ytickdrag) - ; - - // right margin - var rmargin = fixedContainer.append("g") - .attr("id", "right-margin") - .attr("transform", "translate(" + width + ", 0)") - ; - rmargin.append("rect") - .attr("x", 0) - .attr("y", 0) - .attr("width", 1) - .attr("height", height - margin.top - margin.bottom) - ; - - // top margin - var tmargin = fixedContainer.append("g") - .attr("id", "top-margin") - .attr("transform", "translate(0, 0)") - ; - tmargin.append("rect") - .attr("x", 0) - .attr("y", 0) - .attr("width", width) - .attr("height", 1) - ; - - // ruler - ruler = fixedContainer.append("g") - .attr("id", "ruler") - .attr("transform", "translate(0, 0)") - ; - ruler.append("rect") - .attr("id", "ruler-line") - .attr("x", 0) - .attr("y", 0) - .attr("width", "1") - .attr("height", height - margin.top - margin.bottom + 8) - ; - ruler.append("rect") - .attr("id", "bgrect") - .attr("x", 0) - .attr("y", 0) - .attr("width", 0) - .attr("height", 0) - .style("fill", "white") - ; - ruler.append("text") - .attr("x", 0) - .attr("y", height - margin.top - margin.bottom + 16) - .attr("dy", "0.71em") - .text("0") - ; - - svg.on('mousemove', function() { - positionRuler(d3.event.pageX); - }); - - // scroll handling - window.onscroll = function myFunction() { - documentBodyScrollLeft(document.body.scrollLeft); - documentBodyScrollTop(document.body.scrollTop); - var scroll = scrollParams(); - - svgChartContainer - .attr("transform", "translate(" + margin.left - + ", " + (margin.top + scroll.y1) + ")"); - svgChart - .attr("viewBox", "0 " + scroll.y1 + " " + width + " " + scroll.h) - .attr("height", scroll.h); - tmargin - .attr("transform", "translate(0," + scroll.y1 + ")"); - fixedContainer.select(".x.axis") - .attr("transform", "translate(0," + scroll.y2 + ")"); - rmargin.select("rect") - .attr("y", scroll.y1) - .attr("height", scroll.h); - ruler.select("#ruler-line") - .attr("y", scroll.y1) - .attr("height", scroll.h); - - positionRuler(); - } - - // render axis - svg.select("g.x.axis").call(xAxis); - svg.select("g.y.axis").call(yAxis); - - // update to initiale state - window.onscroll(0); - - return gantt; - } - -// private: - - var keyFunction = function(d) { - return d.t1.toString() + d.t2.toString() + d.band.toString(); - } - - var bandTransform = function(d) { - return "translate(" + x(d.t1) + "," + y(d.band) + ")"; - } - - var xPixel = function(d) { - return xZoomed.invert(1) - xZoomed.invert(0); - } - - var render = function(t0, smooth) { - // Save/restore last t0 value - if (!arguments.length || t0 == -1) { - t0 = render.t0; - } - render.t0 = t0; - smooth = smooth || false; - - // Create rectangles for bands - bands = bandsSvg.selectAll("rect.bar") - .data(data, keyFunction); - bands.exit().remove(); - bands.enter().append("rect") - .attr("class", "bar") - .attr("vector-effect", "non-scaling-stroke") - .style("fill", d => d.color) - .on('click', function(d) { - if (tipShown != d) { - tipShown = d; - tip.show(d); - } else { - tipShown = null; - tip.hide(d); - } - }) - .merge(bands) - .transition().duration(smooth? 250: 0) - .attr("y", 0) - .attr("transform", bandTransform) - .attr("height", y.bandwidth()) - .attr("width", d => Math.max(1*xPixel(), x(d.t2) - x(d.t1))) - ; - - var emptyMarker = bandsSvg.selectAll("text") - .data(data.length == 0? ["no data to show"]: []); - emptyMarker.exit().remove(); - emptyMarker.enter().append("text") - .text(d => d) - ; - } - - function initAxis() { - x = d3.scaleLinear() - .domain([timeDomainStart, timeDomainEnd]) - .range([0, width]) - //.clamp(true); // dosn't work with zoom/pan - xZoomed = x; - y = d3.scaleBand() - .domain(Object.values(data).map(d => d.band).sort()) - .rangeRound([0, height - margin.top - margin.bottom]) - .padding(0.5); - xAxis = d3.axisBottom() - .scale(x) - //.tickSubdivide(true) - .tickSize(8) - .tickPadding(8); - yAxis = d3.axisLeft() - .scale(y) - .tickSize(0); - } - - // slow function wrapper - var documentBodyScrollLeft = function(value) { - if (!arguments.length) { - if (documentBodyScrollLeft.value === undefined) { - documentBodyScrollLeft.value = document.body.scrollLeft; - } - return documentBodyScrollLeft.value; - } else { - documentBodyScrollLeft.value = value; - } - } - - // slow function wrapper - var documentBodyScrollTop = function(value) { - if (!arguments.length) { - if (!documentBodyScrollTop.value === undefined) { - documentBodyScrollTop.value = document.body.scrollTop; - } - return documentBodyScrollTop.value; - } else { - documentBodyScrollTop.value = value; - } - } - - var scrollParams = function() { - var y1 = documentBodyScrollTop(); - var y2 = y1 + window.innerHeight - margin.footer; - y2 = Math.min(y2, height - margin.top - margin.bottom); - var h = y2 - y1; - return { - y1: y1, - y2: y2, - h: h - }; - } - - var posTextFormat = d3.format(".1f"); - - var positionRuler = function(pageX) { - if (!arguments.length) { - pageX = positionRuler.pageX || 0; - } else { - positionRuler.pageX = pageX; - } - - // x-coordinate - if (!positionRuler.svgLeft) { - positionRuler.svgLeft = svg.node().getBoundingClientRect().x; - } - - var xpos = pageX - margin.left + 1 - positionRuler.svgLeft; - var tpos = xZoomed.invert(xpos); - tpos = Math.min(Math.max(tpos, xZoomed.invert(0)), xZoomed.invert(width)); - ruler.attr("transform", "translate(" + xZoomed(tpos) + ", 0)"); - var posText = posTextFormat(tpos); - - // scroll-related - var scroll = scrollParams(); - - var text = ruler.select("text") - .attr("y", scroll.y2 + 16) - ; - - // getBBox() is very slow, so compute symbol width once - var xpadding = 5; - var ypadding = 5; - if (!positionRuler.bbox) { - positionRuler.bbox = text.node().getBBox(); - } - - text.text(posText); - var textWidth = 10 * posText.length; - ruler.select("#bgrect") - .attr("x", -textWidth/2 - xpadding) - .attr("y", positionRuler.bbox.y - ypadding) - .attr("width", textWidth + (xpadding*2)) - .attr("height", positionRuler.bbox.height + (ypadding*2)) - ; - - render(tpos); - } - - /* - * Log Query Language: - * Data expressions: - * 1) myparam[0], myparam[-1] // the first and the last myparam in any probe/provider - * 2) myparam // the first (the same as [0]) - * 3) PROVIDER..myparam // any probe with myparam in PROVIDER - * 4) MyProbe._elapsedMs // Ms since track begin for the first MyProbe event - * 5) PROVIDER.MyProbe._sliceUs // Us since previous event in track for the first PROVIDER.MyProbe event - */ - function compile(query) { - query = query.replace(/\s/g, ""); - let [compiled, rest] = sum(query); - if (rest.length != 0) { - throw "parse error: unexpected expression starting at: '" + query + "'"; - } - return record => { - try { - return compiled(record); - } catch (e) { - return null; - } - }; - - function sum(query) { - let term0; - if (query[0] == '-') { - let [term, rest] = product(query.substr(1)); - query = rest; - term0 = x => -term(x); - } else { - let [term, rest] = product(query); - query = rest; - term0 = term; - } - let terms = []; - while (query.length > 0) { - let negate; - if (query[0] == '+') { - negate = false; - } else if (query[0] == '-') { - negate = true; - } else { - break; - } - let [term, rest] = product(query.substr(1)); - query = rest; - terms.push(negate? x => -term(x): term); - } - const cast = x => (isNaN(+x)? x: +x); - return [terms.reduce((a, f) => x => cast(a(x)) + cast(f(x)), term0), query]; - } - - function product(query) { - let [factor0, rest] = parentheses(query); - query = rest; - let factors = []; - while (query.length > 0) { - let invert; - if (query[0] == '*') { - invert = false; - } else if (query[0] == '/') { - invert = true; - } else { - break; - } - let [factor, rest] = parentheses(query.substr(1)); - query = rest; - factors.push(invert? x => 1 / factor(x): factor); - } - return [factors.reduce((a, f) => x => a(x) * f(x), factor0), query]; - } - - function parentheses(query) { - if (query[0] == "(") { - let [expr, rest] = sum(query.substr(1)); - if (rest[0] != ")") { - throw "parse error: missing ')' before '" + rest + "'"; - } - return [expr, rest.substr(1)]; - } else { - return atom(query); - } - } - - function atom(query) { - specialParam = { - _thrNTime: item => (item[US] - thrNTimeZero) * 1e-6, - _thrRTime: item => (item[US] - thrRTimeZero) * 1e-6, - _thrTime: item => item[US] * 1e-6, - _thrNTimeMs: item => (item[US] - thrNTimeZero) * 1e-3, - _thrRTimeMs: item => (item[US] - thrRTimeZero) * 1e-3, - _thrTimeMs: item => item[US] * 1e-3, - _thrNTimeUs: item => item[US] - thrNTimeZero, - _thrRTimeUs: item => item[US] - thrRTimeZero, - _thrTimeUs: item => item[US], - _thrNTimeNs: item => (item[US] - thrNTimeZero) * 1e+3, - _thrRTimeNs: item => (item[US] - thrRTimeZero) * 1e+3, - _thrTimeNs: item => item[US] * 1e+3, - _thread: item => item[THREAD], - }; - var match; - if (match = query.match(/^\d+(\.\d+)?/)) { // number literals - let literal = match[0]; - return [record => literal, query.substr(match[0].length)]; - } else if (match = query.match(/^#[0-9a-fA-F]+/)) { // color literals - let literal = match[0]; - return [record => literal, query.substr(match[0].length)]; - } else if (match = query.match(/^'(.*)'/)) { // string literal - let literal = match[1].replace(/\\'/, "'").replace(/\\\\/, "\\"); - return [record => literal, query.substr(match[0].length)]; - } else if (match = query.match(/^(?:(?:(\w+)\.)?(\w*)\.)?(\w+)(?:\[(-?\d+)\])?/)) { - let provider = match[1] || ""; - let probe = match[2] || ""; - let param = match[3]; - let index = +(match[4] || 0); - let probeId = new Set(); - for (let id = 0; id < probes.length; id++) { - if ((!probe || probes[id].name == probe) && - (!provider || probes[id].provider == provider)) - { - probeId.add(id); - } - } - let isSpecial = specialParam.hasOwnProperty(param); - return [record => { - let end = index >= 0? record.length: -1; - let step = index >= 0? 1: -1; - let skip = index >= 0? index: -index - 1; - for (let i = index >= 0? 0: record.length - 1; i != end; i += step) { - let item = record[i]; - if (probeId.has(item[PROBEID]) && (isSpecial || item[PARAMS].hasOwnProperty(param))) { - if (skip == 0) { - return isSpecial? specialParam[param](item): item[PARAMS][param]; - } else { - skip--; - } - } - } - throw "no data"; - }, query.substr(match[0].length)]; - } else { - throw "parse error: invalid expression starting at '" + query + "'"; - } - } - } - - // ex1: "linear().domain([-1, 0, 1]).range(['red', 'white', 'green'])", - // ex2: "ordinal().domain(['a1', 'a2']).range(['blue', 'yellow'])" - function parseScale(query) { - query = query.replaceAll("'","\""); - var match, scale; - if (match = query.match(/^linear\(\)/)) { - scale = d3.scaleLinear(); - } else if (match = query.match(/^pow\(\)/)) { - scale = d3.scalePow(); - } else if (match = query.match(/^log\(\)/)) { - scale = d3.scaleLog(); - } else if (match = query.match(/^identity\(\)/)) { - scale = d3.scaleIdentity(); - } else if (match = query.match(/^time\(\)/)) { - scale = d3.scaleTime(); - } else if (match = query.match(/^threshold\(\)/)) { - scale = d3.scaleThreshold(); - } else if (match = query.match(/^ordinal\(\)/)) { - scale = d3.scaleOrdinal(); - } else { - throw "Unable to parse scale: " + query; - } - if (match = query.match(/\.domain\(([^\)]+)\)/)) { - scale.domain(JSON.parse(match[1])); - } - if (match = query.match(/\.range\(([^\)]+)\)/)) { - scale.range(JSON.parse(match[1])); - } - if (match = query.match(/\.unknown\(([^\)]+)\)/)) { - scale.unknown(JSON.parse(match[1])); - } - return scale; - } - - function parseLogs(config, logs) { - data = []; - probes = logs.probes; - if (config.hasOwnProperty('scales')) - for (let [name, text] of Object.entries(config.scales)) { - scales[name] = parseScale(text); - } - // Compute aggregates - let minUs = new Map(); - for (record of logs.depot) { - if (record.length > 0) { - let item = record[0]; - let us = item[US]; - let thread = item[US]; - if (!minUs.has(thread)) { - minUs.set(thread, us); - } else { - minUs.set(thread, Math.min(us, minUs.get(thread))); - } - } - } - thrNTimeZero = Number.MAX_VALUE; - thrRTimeZero = 0; - for (let [thread, us] of minUs) { - thrNTimeZero = Math.min(thrNTimeZero, us); - thrRTimeZero = Math.max(thrRTimeZero, us); - } - // Comple data for bands - for (let bandCfg of config.bands) { - function applyScale(func, scaleName) { - if (scaleName) { - let scale = scales[scaleName]; - return (record) => { - let value = func(record); - if (value != null) { - value = scale(value); - } - return value; - }; - } else { - return func; - } - } - let t1f = applyScale(compile(bandCfg.t1), bandCfg.t1Scale); - let t2f = applyScale(compile(bandCfg.t2), bandCfg.t2Scale); - let bandf = applyScale(compile(bandCfg.band), bandCfg.bandScale); - let colorf = applyScale(compile(bandCfg.color), bandCfg.colorScale); - let minTime = Number.MAX_VALUE; - let maxTime = -Number.MAX_VALUE; - for (record of logs.depot) { - let t1 = t1f(record), - t2 = t2f(record), - band = bandf(record), - color = colorf(record) - ; - if (t1 != null && t2 != null && band != null && color != null) { - data.push({t1, t2, band, color, record}); - minTime = Math.min(minTime, t1); - maxTime = Math.max(maxTime, t2); - } - } - if (minTime != Number.MAX_VALUE) { - minT = minTime; - maxT = maxTime; - } - } - } - -// public: - - gantt.width = function(value) { - if (!arguments.length) - return width; - width = +value; - return gantt; - } - - gantt.height = function(value) { - if (!arguments.length) - return height; - height = +value; - return gantt; - } - - gantt.selector = function(value) { - if (!arguments.length) - return selector; - selector = value; - return gantt; - } - - gantt.timeDomain = function(value) { - if (!arguments.length) - return [timeDomainStart, timeDomainEnd]; - timeDomainStart = value[0]; - timeDomainEnd = value[1]; - return gantt; - } - - gantt.data = function() { - return data; - } - - // constructor - - // Log Format - const - THREAD = 0, - US = 1, - PROBEID = 2, - PARAMS = 3 - ; - - // Config - var margin = { top: 20, right: 40, bottom: 20, left: 100, footer: 100 }, - height = document.body.clientHeight - margin.top - margin.bottom - 5, - width = document.body.clientWidth - margin.right - margin.left - 5, - selector = 'body', - timeDomainStart = 0, - timeDomainEnd = 1000, - scales = {}; - ; - - // View - var x = null, - xZoomed = null, - y = null, - xAxis = null, - yAxis = null, - svg = null, - defs = null, - svgChartContainer = null, - svgChart = null, - zoomPanel = null, - zoomContainer1 = null, - zoomContainer2 = null, - fixedContainer = null, - zoom = null, - bandsSvg = null, - bands = null, - tip = null, - tipShown = null, - ruler = null - ; - - // Model - var data = null, - probes = null, - thrRTimeZero = 0, - thrNTimeZero = 0, - minT, - maxT - ; - - return gantt; -}
\ No newline at end of file +d3.gantt = function() { + function gantt(config, logs, autoscale) { + parseLogs(config, logs); + + if (autoscale) { + gantt.timeDomain([minT, maxT]); + } + + initAxis(); + + // create svg element + svg = d3.select(selector) + .append("svg") + .attr("class", "chart") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + ; + + // create arrowhead marker + defs = svg.append("defs"); + defs.append("marker") + .attr("id", "arrow") + .attr("viewBox", "0 -5 10 10") + .attr("refX", 5) + .attr("refY", 0) + .attr("markerWidth", 4) + .attr("markerHeight", 4) + .attr("orient", "auto") + .append("path") + .attr("d", "M0,-5L10,0L0,5") + .attr("class","arrowHead") + ; + + zoom = d3.zoom() + .scaleExtent([0.1, 1000]) + //.translateExtent([0, 0], [1000,0]) + .on("zoom", function() { + if (tipShown != null) { + tip.hide(tipShown); + } + var tr = d3.event.transform; + xZoomed = tr.rescaleX(x); + svg.select("g.x.axis").call(xAxis.scale(xZoomed)); + + var dy = d3.event.sourceEvent.screenY - zoom.startScreenY; + var newScrollTop = documentBodyScrollTop() - dy; + window.scrollTo(documentBodyScrollLeft(), newScrollTop); + documentBodyScrollTop(newScrollTop); + zoom.startScreenY = d3.event.sourceEvent.screenY; + + zoomContainer1.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); + zoomContainer2.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); + + render(); + }) + .on("start", function() { + zoom.startScreenY = d3.event.sourceEvent.screenY; + }) + .on("end", function() { + }) + ; + + svgChartContainer = svg.append('g') + .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") + ; + svgChart = svgChartContainer.append("svg") + .attr("top", 0) + .attr("left", 0) + .attr("width", width) + .attr("height", height) + .attr("viewBox", "0 0 " + width + " " + height) + ; + + zoomContainer1 = svgChart.append("g"); + + zoomPanel = svgChart.append("rect") + .attr("class", "zoom-panel") + .attr("width", width) + .attr("height", height) + .call(zoom) + ; + + zoomContainer2 = svgChart.append("g"); + bandsSvg = zoomContainer2.append("g"); + + // tooltips for bands + var maxTipHeight = 130; + const tipDirection = d => y(d.band) - maxTipHeight < documentBodyScrollTop()? 's': 'n'; + tip = d3.tip() + .attr("class", "d3-tip") + .offset(function(d) { + // compute x to return tip in chart region + var t0 = (d.t1 + d.t2) / 2; + var t1 = Math.min(Math.max(t0, xZoomed.invert(0)), xZoomed.invert(width)); + var dir = tipDirection(d); + return [dir === 'n'? -10 : 10, xZoomed(t1) - xZoomed(t0)]; + }) + .direction(tipDirection) + .html(function(d) { + let text = ''; + for (let item of d.record) { + text += probes[item[PROBEID]].provider + "." + probes[item[PROBEID]].name + "("; + let first = true; + for (let [param, value] of Object.entries(item[PARAMS])) { + text += (first? "": ", ") + param + "='" + value + "'"; + first = false; + } + text += ")\n"; + } + return "<pre>" + text + "</pre>"; + }) + ; + + bandsSvg.call(tip); + + render(); + + // container for non-zoomable elements + fixedContainer = svg.append("g") + .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") + ; + + // create x axis + fixedContainer.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")") + .transition() + .call(xAxis) + ; + + // create y axis + fixedContainer.append("g") + .attr("class", "y axis") + .transition() + .call(yAxis) + ; + + // make y axis ticks draggable + var ytickdrag = d3.drag() + .on("drag", function(d) { + var ypos = d3.event.y - margin.top; + var index = Math.floor((ypos / y.step())); + index = Math.min(Math.max(index, 0), this.initDomain.length - 1); + if (index != this.curIndex) { + var newDomain = []; + for (var i = 0; i < this.initDomain.length; ++i) { + newDomain.push(this.initDomain[i]); + } + newDomain.splice(this.initIndex, 1); + newDomain.splice(index, 0, this.initDomain[this.initIndex]); + + this.curIndex = index; + this.curDomain = newDomain; + y.domain(newDomain); + + // rearange y scale and axis + svg.select("g.y.axis").transition().call(yAxis); + + // rearange other stuff + render(-1, true); + } + }) + .on("start", function(d) { + var ypos = d3.event.y - margin.top; + this.initIndex = Math.floor((ypos / y.step())); + this.initDomain = y.domain(); + }) + .on("end", function(d) { + svg.select("g.y.axis").call(yAxis); + }) + ; + svg.selectAll("g.y.axis .tick") + .call(ytickdrag) + ; + + // right margin + var rmargin = fixedContainer.append("g") + .attr("id", "right-margin") + .attr("transform", "translate(" + width + ", 0)") + ; + rmargin.append("rect") + .attr("x", 0) + .attr("y", 0) + .attr("width", 1) + .attr("height", height - margin.top - margin.bottom) + ; + + // top margin + var tmargin = fixedContainer.append("g") + .attr("id", "top-margin") + .attr("transform", "translate(0, 0)") + ; + tmargin.append("rect") + .attr("x", 0) + .attr("y", 0) + .attr("width", width) + .attr("height", 1) + ; + + // ruler + ruler = fixedContainer.append("g") + .attr("id", "ruler") + .attr("transform", "translate(0, 0)") + ; + ruler.append("rect") + .attr("id", "ruler-line") + .attr("x", 0) + .attr("y", 0) + .attr("width", "1") + .attr("height", height - margin.top - margin.bottom + 8) + ; + ruler.append("rect") + .attr("id", "bgrect") + .attr("x", 0) + .attr("y", 0) + .attr("width", 0) + .attr("height", 0) + .style("fill", "white") + ; + ruler.append("text") + .attr("x", 0) + .attr("y", height - margin.top - margin.bottom + 16) + .attr("dy", "0.71em") + .text("0") + ; + + svg.on('mousemove', function() { + positionRuler(d3.event.pageX); + }); + + // scroll handling + window.onscroll = function myFunction() { + documentBodyScrollLeft(document.body.scrollLeft); + documentBodyScrollTop(document.body.scrollTop); + var scroll = scrollParams(); + + svgChartContainer + .attr("transform", "translate(" + margin.left + + ", " + (margin.top + scroll.y1) + ")"); + svgChart + .attr("viewBox", "0 " + scroll.y1 + " " + width + " " + scroll.h) + .attr("height", scroll.h); + tmargin + .attr("transform", "translate(0," + scroll.y1 + ")"); + fixedContainer.select(".x.axis") + .attr("transform", "translate(0," + scroll.y2 + ")"); + rmargin.select("rect") + .attr("y", scroll.y1) + .attr("height", scroll.h); + ruler.select("#ruler-line") + .attr("y", scroll.y1) + .attr("height", scroll.h); + + positionRuler(); + } + + // render axis + svg.select("g.x.axis").call(xAxis); + svg.select("g.y.axis").call(yAxis); + + // update to initiale state + window.onscroll(0); + + return gantt; + } + +// private: + + var keyFunction = function(d) { + return d.t1.toString() + d.t2.toString() + d.band.toString(); + } + + var bandTransform = function(d) { + return "translate(" + x(d.t1) + "," + y(d.band) + ")"; + } + + var xPixel = function(d) { + return xZoomed.invert(1) - xZoomed.invert(0); + } + + var render = function(t0, smooth) { + // Save/restore last t0 value + if (!arguments.length || t0 == -1) { + t0 = render.t0; + } + render.t0 = t0; + smooth = smooth || false; + + // Create rectangles for bands + bands = bandsSvg.selectAll("rect.bar") + .data(data, keyFunction); + bands.exit().remove(); + bands.enter().append("rect") + .attr("class", "bar") + .attr("vector-effect", "non-scaling-stroke") + .style("fill", d => d.color) + .on('click', function(d) { + if (tipShown != d) { + tipShown = d; + tip.show(d); + } else { + tipShown = null; + tip.hide(d); + } + }) + .merge(bands) + .transition().duration(smooth? 250: 0) + .attr("y", 0) + .attr("transform", bandTransform) + .attr("height", y.bandwidth()) + .attr("width", d => Math.max(1*xPixel(), x(d.t2) - x(d.t1))) + ; + + var emptyMarker = bandsSvg.selectAll("text") + .data(data.length == 0? ["no data to show"]: []); + emptyMarker.exit().remove(); + emptyMarker.enter().append("text") + .text(d => d) + ; + } + + function initAxis() { + x = d3.scaleLinear() + .domain([timeDomainStart, timeDomainEnd]) + .range([0, width]) + //.clamp(true); // dosn't work with zoom/pan + xZoomed = x; + y = d3.scaleBand() + .domain(Object.values(data).map(d => d.band).sort()) + .rangeRound([0, height - margin.top - margin.bottom]) + .padding(0.5); + xAxis = d3.axisBottom() + .scale(x) + //.tickSubdivide(true) + .tickSize(8) + .tickPadding(8); + yAxis = d3.axisLeft() + .scale(y) + .tickSize(0); + } + + // slow function wrapper + var documentBodyScrollLeft = function(value) { + if (!arguments.length) { + if (documentBodyScrollLeft.value === undefined) { + documentBodyScrollLeft.value = document.body.scrollLeft; + } + return documentBodyScrollLeft.value; + } else { + documentBodyScrollLeft.value = value; + } + } + + // slow function wrapper + var documentBodyScrollTop = function(value) { + if (!arguments.length) { + if (!documentBodyScrollTop.value === undefined) { + documentBodyScrollTop.value = document.body.scrollTop; + } + return documentBodyScrollTop.value; + } else { + documentBodyScrollTop.value = value; + } + } + + var scrollParams = function() { + var y1 = documentBodyScrollTop(); + var y2 = y1 + window.innerHeight - margin.footer; + y2 = Math.min(y2, height - margin.top - margin.bottom); + var h = y2 - y1; + return { + y1: y1, + y2: y2, + h: h + }; + } + + var posTextFormat = d3.format(".1f"); + + var positionRuler = function(pageX) { + if (!arguments.length) { + pageX = positionRuler.pageX || 0; + } else { + positionRuler.pageX = pageX; + } + + // x-coordinate + if (!positionRuler.svgLeft) { + positionRuler.svgLeft = svg.node().getBoundingClientRect().x; + } + + var xpos = pageX - margin.left + 1 - positionRuler.svgLeft; + var tpos = xZoomed.invert(xpos); + tpos = Math.min(Math.max(tpos, xZoomed.invert(0)), xZoomed.invert(width)); + ruler.attr("transform", "translate(" + xZoomed(tpos) + ", 0)"); + var posText = posTextFormat(tpos); + + // scroll-related + var scroll = scrollParams(); + + var text = ruler.select("text") + .attr("y", scroll.y2 + 16) + ; + + // getBBox() is very slow, so compute symbol width once + var xpadding = 5; + var ypadding = 5; + if (!positionRuler.bbox) { + positionRuler.bbox = text.node().getBBox(); + } + + text.text(posText); + var textWidth = 10 * posText.length; + ruler.select("#bgrect") + .attr("x", -textWidth/2 - xpadding) + .attr("y", positionRuler.bbox.y - ypadding) + .attr("width", textWidth + (xpadding*2)) + .attr("height", positionRuler.bbox.height + (ypadding*2)) + ; + + render(tpos); + } + + /* + * Log Query Language: + * Data expressions: + * 1) myparam[0], myparam[-1] // the first and the last myparam in any probe/provider + * 2) myparam // the first (the same as [0]) + * 3) PROVIDER..myparam // any probe with myparam in PROVIDER + * 4) MyProbe._elapsedMs // Ms since track begin for the first MyProbe event + * 5) PROVIDER.MyProbe._sliceUs // Us since previous event in track for the first PROVIDER.MyProbe event + */ + function compile(query) { + query = query.replace(/\s/g, ""); + let [compiled, rest] = sum(query); + if (rest.length != 0) { + throw "parse error: unexpected expression starting at: '" + query + "'"; + } + return record => { + try { + return compiled(record); + } catch (e) { + return null; + } + }; + + function sum(query) { + let term0; + if (query[0] == '-') { + let [term, rest] = product(query.substr(1)); + query = rest; + term0 = x => -term(x); + } else { + let [term, rest] = product(query); + query = rest; + term0 = term; + } + let terms = []; + while (query.length > 0) { + let negate; + if (query[0] == '+') { + negate = false; + } else if (query[0] == '-') { + negate = true; + } else { + break; + } + let [term, rest] = product(query.substr(1)); + query = rest; + terms.push(negate? x => -term(x): term); + } + const cast = x => (isNaN(+x)? x: +x); + return [terms.reduce((a, f) => x => cast(a(x)) + cast(f(x)), term0), query]; + } + + function product(query) { + let [factor0, rest] = parentheses(query); + query = rest; + let factors = []; + while (query.length > 0) { + let invert; + if (query[0] == '*') { + invert = false; + } else if (query[0] == '/') { + invert = true; + } else { + break; + } + let [factor, rest] = parentheses(query.substr(1)); + query = rest; + factors.push(invert? x => 1 / factor(x): factor); + } + return [factors.reduce((a, f) => x => a(x) * f(x), factor0), query]; + } + + function parentheses(query) { + if (query[0] == "(") { + let [expr, rest] = sum(query.substr(1)); + if (rest[0] != ")") { + throw "parse error: missing ')' before '" + rest + "'"; + } + return [expr, rest.substr(1)]; + } else { + return atom(query); + } + } + + function atom(query) { + specialParam = { + _thrNTime: item => (item[US] - thrNTimeZero) * 1e-6, + _thrRTime: item => (item[US] - thrRTimeZero) * 1e-6, + _thrTime: item => item[US] * 1e-6, + _thrNTimeMs: item => (item[US] - thrNTimeZero) * 1e-3, + _thrRTimeMs: item => (item[US] - thrRTimeZero) * 1e-3, + _thrTimeMs: item => item[US] * 1e-3, + _thrNTimeUs: item => item[US] - thrNTimeZero, + _thrRTimeUs: item => item[US] - thrRTimeZero, + _thrTimeUs: item => item[US], + _thrNTimeNs: item => (item[US] - thrNTimeZero) * 1e+3, + _thrRTimeNs: item => (item[US] - thrRTimeZero) * 1e+3, + _thrTimeNs: item => item[US] * 1e+3, + _thread: item => item[THREAD], + }; + var match; + if (match = query.match(/^\d+(\.\d+)?/)) { // number literals + let literal = match[0]; + return [record => literal, query.substr(match[0].length)]; + } else if (match = query.match(/^#[0-9a-fA-F]+/)) { // color literals + let literal = match[0]; + return [record => literal, query.substr(match[0].length)]; + } else if (match = query.match(/^'(.*)'/)) { // string literal + let literal = match[1].replace(/\\'/, "'").replace(/\\\\/, "\\"); + return [record => literal, query.substr(match[0].length)]; + } else if (match = query.match(/^(?:(?:(\w+)\.)?(\w*)\.)?(\w+)(?:\[(-?\d+)\])?/)) { + let provider = match[1] || ""; + let probe = match[2] || ""; + let param = match[3]; + let index = +(match[4] || 0); + let probeId = new Set(); + for (let id = 0; id < probes.length; id++) { + if ((!probe || probes[id].name == probe) && + (!provider || probes[id].provider == provider)) + { + probeId.add(id); + } + } + let isSpecial = specialParam.hasOwnProperty(param); + return [record => { + let end = index >= 0? record.length: -1; + let step = index >= 0? 1: -1; + let skip = index >= 0? index: -index - 1; + for (let i = index >= 0? 0: record.length - 1; i != end; i += step) { + let item = record[i]; + if (probeId.has(item[PROBEID]) && (isSpecial || item[PARAMS].hasOwnProperty(param))) { + if (skip == 0) { + return isSpecial? specialParam[param](item): item[PARAMS][param]; + } else { + skip--; + } + } + } + throw "no data"; + }, query.substr(match[0].length)]; + } else { + throw "parse error: invalid expression starting at '" + query + "'"; + } + } + } + + // ex1: "linear().domain([-1, 0, 1]).range(['red', 'white', 'green'])", + // ex2: "ordinal().domain(['a1', 'a2']).range(['blue', 'yellow'])" + function parseScale(query) { + query = query.replaceAll("'","\""); + var match, scale; + if (match = query.match(/^linear\(\)/)) { + scale = d3.scaleLinear(); + } else if (match = query.match(/^pow\(\)/)) { + scale = d3.scalePow(); + } else if (match = query.match(/^log\(\)/)) { + scale = d3.scaleLog(); + } else if (match = query.match(/^identity\(\)/)) { + scale = d3.scaleIdentity(); + } else if (match = query.match(/^time\(\)/)) { + scale = d3.scaleTime(); + } else if (match = query.match(/^threshold\(\)/)) { + scale = d3.scaleThreshold(); + } else if (match = query.match(/^ordinal\(\)/)) { + scale = d3.scaleOrdinal(); + } else { + throw "Unable to parse scale: " + query; + } + if (match = query.match(/\.domain\(([^\)]+)\)/)) { + scale.domain(JSON.parse(match[1])); + } + if (match = query.match(/\.range\(([^\)]+)\)/)) { + scale.range(JSON.parse(match[1])); + } + if (match = query.match(/\.unknown\(([^\)]+)\)/)) { + scale.unknown(JSON.parse(match[1])); + } + return scale; + } + + function parseLogs(config, logs) { + data = []; + probes = logs.probes; + if (config.hasOwnProperty('scales')) + for (let [name, text] of Object.entries(config.scales)) { + scales[name] = parseScale(text); + } + // Compute aggregates + let minUs = new Map(); + for (record of logs.depot) { + if (record.length > 0) { + let item = record[0]; + let us = item[US]; + let thread = item[US]; + if (!minUs.has(thread)) { + minUs.set(thread, us); + } else { + minUs.set(thread, Math.min(us, minUs.get(thread))); + } + } + } + thrNTimeZero = Number.MAX_VALUE; + thrRTimeZero = 0; + for (let [thread, us] of minUs) { + thrNTimeZero = Math.min(thrNTimeZero, us); + thrRTimeZero = Math.max(thrRTimeZero, us); + } + // Comple data for bands + for (let bandCfg of config.bands) { + function applyScale(func, scaleName) { + if (scaleName) { + let scale = scales[scaleName]; + return (record) => { + let value = func(record); + if (value != null) { + value = scale(value); + } + return value; + }; + } else { + return func; + } + } + let t1f = applyScale(compile(bandCfg.t1), bandCfg.t1Scale); + let t2f = applyScale(compile(bandCfg.t2), bandCfg.t2Scale); + let bandf = applyScale(compile(bandCfg.band), bandCfg.bandScale); + let colorf = applyScale(compile(bandCfg.color), bandCfg.colorScale); + let minTime = Number.MAX_VALUE; + let maxTime = -Number.MAX_VALUE; + for (record of logs.depot) { + let t1 = t1f(record), + t2 = t2f(record), + band = bandf(record), + color = colorf(record) + ; + if (t1 != null && t2 != null && band != null && color != null) { + data.push({t1, t2, band, color, record}); + minTime = Math.min(minTime, t1); + maxTime = Math.max(maxTime, t2); + } + } + if (minTime != Number.MAX_VALUE) { + minT = minTime; + maxT = maxTime; + } + } + } + +// public: + + gantt.width = function(value) { + if (!arguments.length) + return width; + width = +value; + return gantt; + } + + gantt.height = function(value) { + if (!arguments.length) + return height; + height = +value; + return gantt; + } + + gantt.selector = function(value) { + if (!arguments.length) + return selector; + selector = value; + return gantt; + } + + gantt.timeDomain = function(value) { + if (!arguments.length) + return [timeDomainStart, timeDomainEnd]; + timeDomainStart = value[0]; + timeDomainEnd = value[1]; + return gantt; + } + + gantt.data = function() { + return data; + } + + // constructor + + // Log Format + const + THREAD = 0, + US = 1, + PROBEID = 2, + PARAMS = 3 + ; + + // Config + var margin = { top: 20, right: 40, bottom: 20, left: 100, footer: 100 }, + height = document.body.clientHeight - margin.top - margin.bottom - 5, + width = document.body.clientWidth - margin.right - margin.left - 5, + selector = 'body', + timeDomainStart = 0, + timeDomainEnd = 1000, + scales = {}; + ; + + // View + var x = null, + xZoomed = null, + y = null, + xAxis = null, + yAxis = null, + svg = null, + defs = null, + svgChartContainer = null, + svgChart = null, + zoomPanel = null, + zoomContainer1 = null, + zoomContainer2 = null, + fixedContainer = null, + zoom = null, + bandsSvg = null, + bands = null, + tip = null, + tipShown = null, + ruler = null + ; + + // Model + var data = null, + probes = null, + thrRTimeZero = 0, + thrNTimeZero = 0, + minT, + maxT + ; + + return gantt; +}
\ No newline at end of file diff --git a/library/cpp/lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js b/library/cpp/lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js index ad3a6c0d19..2b2e61ad4c 100644 --- a/library/cpp/lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js +++ b/library/cpp/lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js @@ -1,352 +1,352 @@ -/** - * d3.tip - * Copyright (c) 2013 Justin Palmer - * - * Tooltips for d3.js SVG visualizations - */ -// eslint-disable-next-line no-extra-semi -;(function(root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module with d3 as a dependency. - define([ - 'd3-collection', - 'd3-selection' - ], factory) - } else if (typeof module === 'object' && module.exports) { - /* eslint-disable global-require */ - // CommonJS - var d3Collection = require('d3-collection'), - d3Selection = require('d3-selection') - module.exports = factory(d3Collection, d3Selection) - /* eslint-enable global-require */ - } else { - // Browser global. - var d3 = root.d3 - // eslint-disable-next-line no-param-reassign - root.d3.tip = factory(d3, d3) - } -}(this, function(d3Collection, d3Selection) { - // Public - contructs a new tooltip - // - // Returns a tip - return function() { - var direction = d3TipDirection, - offset = d3TipOffset, - html = d3TipHTML, - rootElement = document.body, - node = initNode(), - svg = null, - point = null, - target = null - - function tip(vis) { - svg = getSVGNode(vis) - if (!svg) return - point = svg.createSVGPoint() - rootElement.appendChild(node) - } - - // Public - show the tooltip on the screen - // - // Returns a tip - tip.show = function() { - var args = Array.prototype.slice.call(arguments) - if (args[args.length - 1] instanceof SVGElement) target = args.pop() - - var content = html.apply(this, args), - poffset = offset.apply(this, args), - dir = direction.apply(this, args), - nodel = getNodeEl(), - i = directions.length, - coords, - scrollTop = document.documentElement.scrollTop || - rootElement.scrollTop, - scrollLeft = document.documentElement.scrollLeft || - rootElement.scrollLeft - - nodel.html(content) - .style('opacity', 1).style('pointer-events', 'all') - - while (i--) nodel.classed(directions[i], false) - coords = directionCallbacks.get(dir).apply(this) - nodel.classed(dir, true) - .style('top', (coords.top + poffset[0]) + scrollTop + 'px') - .style('left', (coords.left + poffset[1]) + scrollLeft + 'px') - - return tip - } - - // Public - hide the tooltip - // - // Returns a tip - tip.hide = function() { - var nodel = getNodeEl() - nodel.style('opacity', 0).style('pointer-events', 'none') - return tip - } - - // Public: Proxy attr calls to the d3 tip container. - // Sets or gets attribute value. - // - // n - name of the attribute - // v - value of the attribute - // - // Returns tip or attribute value - // eslint-disable-next-line no-unused-vars - tip.attr = function(n, v) { - if (arguments.length < 2 && typeof n === 'string') { - return getNodeEl().attr(n) - } - - var args = Array.prototype.slice.call(arguments) - d3Selection.selection.prototype.attr.apply(getNodeEl(), args) - return tip - } - - // Public: Proxy style calls to the d3 tip container. - // Sets or gets a style value. - // - // n - name of the property - // v - value of the property - // - // Returns tip or style property value - // eslint-disable-next-line no-unused-vars - tip.style = function(n, v) { - if (arguments.length < 2 && typeof n === 'string') { - return getNodeEl().style(n) - } - - var args = Array.prototype.slice.call(arguments) - d3Selection.selection.prototype.style.apply(getNodeEl(), args) - return tip - } - - // Public: Set or get the direction of the tooltip - // - // v - One of n(north), s(south), e(east), or w(west), nw(northwest), - // sw(southwest), ne(northeast) or se(southeast) - // - // Returns tip or direction - tip.direction = function(v) { - if (!arguments.length) return direction - direction = v == null ? v : functor(v) - - return tip - } - - // Public: Sets or gets the offset of the tip - // - // v - Array of [x, y] offset - // - // Returns offset or - tip.offset = function(v) { - if (!arguments.length) return offset - offset = v == null ? v : functor(v) - - return tip - } - - // Public: sets or gets the html value of the tooltip - // - // v - String value of the tip - // - // Returns html value or tip - tip.html = function(v) { - if (!arguments.length) return html - html = v == null ? v : functor(v) - - return tip - } - - // Public: sets or gets the root element anchor of the tooltip - // - // v - root element of the tooltip - // - // Returns root node of tip - tip.rootElement = function(v) { - if (!arguments.length) return rootElement - rootElement = v == null ? v : functor(v) - - return tip - } - - // Public: destroys the tooltip and removes it from the DOM - // - // Returns a tip - tip.destroy = function() { - if (node) { - getNodeEl().remove() - node = null - } - return tip - } - - function d3TipDirection() { return 'n' } - function d3TipOffset() { return [0, 0] } - function d3TipHTML() { return ' ' } - - var directionCallbacks = d3Collection.map({ - n: directionNorth, - s: directionSouth, - e: directionEast, - w: directionWest, - nw: directionNorthWest, - ne: directionNorthEast, - sw: directionSouthWest, - se: directionSouthEast - }), - directions = directionCallbacks.keys() - - function directionNorth() { - var bbox = getScreenBBox() - return { - top: bbox.n.y - node.offsetHeight, - left: bbox.n.x - node.offsetWidth / 2 - } - } - - function directionSouth() { - var bbox = getScreenBBox() - return { - top: bbox.s.y, - left: bbox.s.x - node.offsetWidth / 2 - } - } - - function directionEast() { - var bbox = getScreenBBox() - return { - top: bbox.e.y - node.offsetHeight / 2, - left: bbox.e.x - } - } - - function directionWest() { - var bbox = getScreenBBox() - return { - top: bbox.w.y - node.offsetHeight / 2, - left: bbox.w.x - node.offsetWidth - } - } - - function directionNorthWest() { - var bbox = getScreenBBox() - return { - top: bbox.nw.y - node.offsetHeight, - left: bbox.nw.x - node.offsetWidth - } - } - - function directionNorthEast() { - var bbox = getScreenBBox() - return { - top: bbox.ne.y - node.offsetHeight, - left: bbox.ne.x - } - } - - function directionSouthWest() { - var bbox = getScreenBBox() - return { - top: bbox.sw.y, - left: bbox.sw.x - node.offsetWidth - } - } - - function directionSouthEast() { - var bbox = getScreenBBox() - return { - top: bbox.se.y, - left: bbox.se.x - } - } - - function initNode() { - var div = d3Selection.select(document.createElement('div')) - div - .style('position', 'absolute') - .style('top', 0) - .style('opacity', 0) - .style('pointer-events', 'none') - .style('box-sizing', 'border-box') - - return div.node() - } - - function getSVGNode(element) { - var svgNode = element.node() - if (!svgNode) return null - if (svgNode.tagName.toLowerCase() === 'svg') return svgNode - return svgNode.ownerSVGElement - } - - function getNodeEl() { - if (node == null) { - node = initNode() - // re-add node to DOM - rootElement.appendChild(node) - } - return d3Selection.select(node) - } - - // Private - gets the screen coordinates of a shape - // - // Given a shape on the screen, will return an SVGPoint for the directions - // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), - // nw(northwest), sw(southwest). - // - // +-+-+ - // | | - // + + - // | | - // +-+-+ - // - // Returns an Object {n, s, e, w, nw, sw, ne, se} - function getScreenBBox() { - var targetel = target || d3Selection.event.target - - while (targetel.getScreenCTM == null && targetel.parentNode == null) { - targetel = targetel.parentNode - } - - var bbox = {}, - matrix = targetel.getScreenCTM(), - tbbox = targetel.getBBox(), - width = tbbox.width, - height = tbbox.height, - x = tbbox.x, - y = tbbox.y - - point.x = x - point.y = y - bbox.nw = point.matrixTransform(matrix) - point.x += width - bbox.ne = point.matrixTransform(matrix) - point.y += height - bbox.se = point.matrixTransform(matrix) - point.x -= width - bbox.sw = point.matrixTransform(matrix) - point.y -= height / 2 - bbox.w = point.matrixTransform(matrix) - point.x += width - bbox.e = point.matrixTransform(matrix) - point.x -= width / 2 - point.y -= height / 2 - bbox.n = point.matrixTransform(matrix) - point.y += height - bbox.s = point.matrixTransform(matrix) - - return bbox - } - - // Private - replace D3JS 3.X d3.functor() function - function functor(v) { - return typeof v === 'function' ? v : function() { - return v - } - } - - return tip - } -// eslint-disable-next-line semi -})); +/** + * d3.tip + * Copyright (c) 2013 Justin Palmer + * + * Tooltips for d3.js SVG visualizations + */ +// eslint-disable-next-line no-extra-semi +;(function(root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module with d3 as a dependency. + define([ + 'd3-collection', + 'd3-selection' + ], factory) + } else if (typeof module === 'object' && module.exports) { + /* eslint-disable global-require */ + // CommonJS + var d3Collection = require('d3-collection'), + d3Selection = require('d3-selection') + module.exports = factory(d3Collection, d3Selection) + /* eslint-enable global-require */ + } else { + // Browser global. + var d3 = root.d3 + // eslint-disable-next-line no-param-reassign + root.d3.tip = factory(d3, d3) + } +}(this, function(d3Collection, d3Selection) { + // Public - contructs a new tooltip + // + // Returns a tip + return function() { + var direction = d3TipDirection, + offset = d3TipOffset, + html = d3TipHTML, + rootElement = document.body, + node = initNode(), + svg = null, + point = null, + target = null + + function tip(vis) { + svg = getSVGNode(vis) + if (!svg) return + point = svg.createSVGPoint() + rootElement.appendChild(node) + } + + // Public - show the tooltip on the screen + // + // Returns a tip + tip.show = function() { + var args = Array.prototype.slice.call(arguments) + if (args[args.length - 1] instanceof SVGElement) target = args.pop() + + var content = html.apply(this, args), + poffset = offset.apply(this, args), + dir = direction.apply(this, args), + nodel = getNodeEl(), + i = directions.length, + coords, + scrollTop = document.documentElement.scrollTop || + rootElement.scrollTop, + scrollLeft = document.documentElement.scrollLeft || + rootElement.scrollLeft + + nodel.html(content) + .style('opacity', 1).style('pointer-events', 'all') + + while (i--) nodel.classed(directions[i], false) + coords = directionCallbacks.get(dir).apply(this) + nodel.classed(dir, true) + .style('top', (coords.top + poffset[0]) + scrollTop + 'px') + .style('left', (coords.left + poffset[1]) + scrollLeft + 'px') + + return tip + } + + // Public - hide the tooltip + // + // Returns a tip + tip.hide = function() { + var nodel = getNodeEl() + nodel.style('opacity', 0).style('pointer-events', 'none') + return tip + } + + // Public: Proxy attr calls to the d3 tip container. + // Sets or gets attribute value. + // + // n - name of the attribute + // v - value of the attribute + // + // Returns tip or attribute value + // eslint-disable-next-line no-unused-vars + tip.attr = function(n, v) { + if (arguments.length < 2 && typeof n === 'string') { + return getNodeEl().attr(n) + } + + var args = Array.prototype.slice.call(arguments) + d3Selection.selection.prototype.attr.apply(getNodeEl(), args) + return tip + } + + // Public: Proxy style calls to the d3 tip container. + // Sets or gets a style value. + // + // n - name of the property + // v - value of the property + // + // Returns tip or style property value + // eslint-disable-next-line no-unused-vars + tip.style = function(n, v) { + if (arguments.length < 2 && typeof n === 'string') { + return getNodeEl().style(n) + } + + var args = Array.prototype.slice.call(arguments) + d3Selection.selection.prototype.style.apply(getNodeEl(), args) + return tip + } + + // Public: Set or get the direction of the tooltip + // + // v - One of n(north), s(south), e(east), or w(west), nw(northwest), + // sw(southwest), ne(northeast) or se(southeast) + // + // Returns tip or direction + tip.direction = function(v) { + if (!arguments.length) return direction + direction = v == null ? v : functor(v) + + return tip + } + + // Public: Sets or gets the offset of the tip + // + // v - Array of [x, y] offset + // + // Returns offset or + tip.offset = function(v) { + if (!arguments.length) return offset + offset = v == null ? v : functor(v) + + return tip + } + + // Public: sets or gets the html value of the tooltip + // + // v - String value of the tip + // + // Returns html value or tip + tip.html = function(v) { + if (!arguments.length) return html + html = v == null ? v : functor(v) + + return tip + } + + // Public: sets or gets the root element anchor of the tooltip + // + // v - root element of the tooltip + // + // Returns root node of tip + tip.rootElement = function(v) { + if (!arguments.length) return rootElement + rootElement = v == null ? v : functor(v) + + return tip + } + + // Public: destroys the tooltip and removes it from the DOM + // + // Returns a tip + tip.destroy = function() { + if (node) { + getNodeEl().remove() + node = null + } + return tip + } + + function d3TipDirection() { return 'n' } + function d3TipOffset() { return [0, 0] } + function d3TipHTML() { return ' ' } + + var directionCallbacks = d3Collection.map({ + n: directionNorth, + s: directionSouth, + e: directionEast, + w: directionWest, + nw: directionNorthWest, + ne: directionNorthEast, + sw: directionSouthWest, + se: directionSouthEast + }), + directions = directionCallbacks.keys() + + function directionNorth() { + var bbox = getScreenBBox() + return { + top: bbox.n.y - node.offsetHeight, + left: bbox.n.x - node.offsetWidth / 2 + } + } + + function directionSouth() { + var bbox = getScreenBBox() + return { + top: bbox.s.y, + left: bbox.s.x - node.offsetWidth / 2 + } + } + + function directionEast() { + var bbox = getScreenBBox() + return { + top: bbox.e.y - node.offsetHeight / 2, + left: bbox.e.x + } + } + + function directionWest() { + var bbox = getScreenBBox() + return { + top: bbox.w.y - node.offsetHeight / 2, + left: bbox.w.x - node.offsetWidth + } + } + + function directionNorthWest() { + var bbox = getScreenBBox() + return { + top: bbox.nw.y - node.offsetHeight, + left: bbox.nw.x - node.offsetWidth + } + } + + function directionNorthEast() { + var bbox = getScreenBBox() + return { + top: bbox.ne.y - node.offsetHeight, + left: bbox.ne.x + } + } + + function directionSouthWest() { + var bbox = getScreenBBox() + return { + top: bbox.sw.y, + left: bbox.sw.x - node.offsetWidth + } + } + + function directionSouthEast() { + var bbox = getScreenBBox() + return { + top: bbox.se.y, + left: bbox.se.x + } + } + + function initNode() { + var div = d3Selection.select(document.createElement('div')) + div + .style('position', 'absolute') + .style('top', 0) + .style('opacity', 0) + .style('pointer-events', 'none') + .style('box-sizing', 'border-box') + + return div.node() + } + + function getSVGNode(element) { + var svgNode = element.node() + if (!svgNode) return null + if (svgNode.tagName.toLowerCase() === 'svg') return svgNode + return svgNode.ownerSVGElement + } + + function getNodeEl() { + if (node == null) { + node = initNode() + // re-add node to DOM + rootElement.appendChild(node) + } + return d3Selection.select(node) + } + + // Private - gets the screen coordinates of a shape + // + // Given a shape on the screen, will return an SVGPoint for the directions + // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), + // nw(northwest), sw(southwest). + // + // +-+-+ + // | | + // + + + // | | + // +-+-+ + // + // Returns an Object {n, s, e, w, nw, sw, ne, se} + function getScreenBBox() { + var targetel = target || d3Selection.event.target + + while (targetel.getScreenCTM == null && targetel.parentNode == null) { + targetel = targetel.parentNode + } + + var bbox = {}, + matrix = targetel.getScreenCTM(), + tbbox = targetel.getBBox(), + width = tbbox.width, + height = tbbox.height, + x = tbbox.x, + y = tbbox.y + + point.x = x + point.y = y + bbox.nw = point.matrixTransform(matrix) + point.x += width + bbox.ne = point.matrixTransform(matrix) + point.y += height + bbox.se = point.matrixTransform(matrix) + point.x -= width + bbox.sw = point.matrixTransform(matrix) + point.y -= height / 2 + bbox.w = point.matrixTransform(matrix) + point.x += width + bbox.e = point.matrixTransform(matrix) + point.x -= width / 2 + point.y -= height / 2 + bbox.n = point.matrixTransform(matrix) + point.y += height + bbox.s = point.matrixTransform(matrix) + + return bbox + } + + // Private - replace D3JS 3.X d3.functor() function + function functor(v) { + return typeof v === 'function' ? v : function() { + return v + } + } + + return tip + } +// eslint-disable-next-line semi +})); diff --git a/library/cpp/lwtrace/mon/static/js/d3.v4.min.js b/library/cpp/lwtrace/mon/static/js/d3.v4.min.js index 6a2705865c..544c4eb8cd 100644 --- a/library/cpp/lwtrace/mon/static/js/d3.v4.min.js +++ b/library/cpp/lwtrace/mon/static/js/d3.v4.min.js @@ -1,2 +1,2 @@ -// https://d3js.org Version 4.10.0. Copyright 2017 Mike Bostock. -(function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})})(this,function(t){"use strict";function n(t){return function(n,e){return ss(t(n),e)}}function e(t,n){return[t,n]}function r(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=Ts?10:o>=ks?5:o>=Ns?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=Ts?10:o>=ks?5:o>=Ns?2:1)}function i(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=Ts?i*=10:o>=ks?i*=5:o>=Ns&&(i*=2),n<t?-i:i}function o(t){return t.length}function u(t){return"translate("+(t+.5)+",0)"}function a(t){return"translate(0,"+(t+.5)+")"}function c(t){return function(n){return+t(n)}}function s(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}function f(){return!this.__axis}function l(t,n){function e(e){var u=null==i?n.ticks?n.ticks.apply(n,r):n.domain():i,a=null==o?n.tickFormat?n.tickFormat.apply(n,r):Ls:o,y=Math.max(l,0)+p,g=n.range(),m=+g[0]+.5,x=+g[g.length-1]+.5,b=(n.bandwidth?s:c)(n.copy()),w=e.selection?e.selection():e,M=w.selectAll(".domain").data([null]),T=w.selectAll(".tick").data(u,n).order(),k=T.exit(),N=T.enter().append("g").attr("class","tick"),S=T.select("line"),E=T.select("text");M=M.merge(M.enter().insert("path",".tick").attr("class","domain").attr("stroke","#000")),T=T.merge(N),S=S.merge(N.append("line").attr("stroke","#000").attr(v+"2",d*l)),E=E.merge(N.append("text").attr("fill","#000").attr(v,d*y).attr("dy",t===qs?"0em":t===Ds?"0.71em":"0.32em")),e!==w&&(M=M.transition(e),T=T.transition(e),S=S.transition(e),E=E.transition(e),k=k.transition(e).attr("opacity",Fs).attr("transform",function(t){return isFinite(t=b(t))?_(t):this.getAttribute("transform")}),N.attr("opacity",Fs).attr("transform",function(t){var n=this.parentNode.__axis;return _(n&&isFinite(n=n(t))?n:b(t))})),k.remove(),M.attr("d",t===Os||t==Us?"M"+d*h+","+m+"H0.5V"+x+"H"+d*h:"M"+m+","+d*h+"V0.5H"+x+"V"+d*h),T.attr("opacity",1).attr("transform",function(t){return _(b(t))}),S.attr(v+"2",d*l),E.attr(v,d*y).text(a),w.filter(f).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===Us?"start":t===Os?"end":"middle"),w.each(function(){this.__axis=b})}var r=[],i=null,o=null,l=6,h=6,p=3,d=t===qs||t===Os?-1:1,v=t===Os||t===Us?"x":"y",_=t===qs||t===Ds?u:a;return e.scale=function(t){return arguments.length?(n=t,e):n},e.ticks=function(){return r=Rs.call(arguments),e},e.tickArguments=function(t){return arguments.length?(r=null==t?[]:Rs.call(t),e):r.slice()},e.tickValues=function(t){return arguments.length?(i=null==t?null:Rs.call(t),e):i&&i.slice()},e.tickFormat=function(t){return arguments.length?(o=t,e):o},e.tickSize=function(t){return arguments.length?(l=h=+t,e):l},e.tickSizeInner=function(t){return arguments.length?(l=+t,e):l},e.tickSizeOuter=function(t){return arguments.length?(h=+t,e):h},e.tickPadding=function(t){return arguments.length?(p=+t,e):p},e}function h(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r)throw new Error("illegal type: "+t);r[t]=[]}return new p(r)}function p(t){this._=t}function d(t,n){return t.trim().split(/^|\s+/).map(function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}function v(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function _(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=Is,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}function y(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===Ys&&n.documentElement.namespaceURI===Ys?n.createElement(t):n.createElementNS(e,t)}}function g(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function m(){return new x}function x(){this._="@"+(++Xs).toString(36)}function b(t,n,e){return t=w(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function w(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function M(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}function T(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function k(t,n,e){var r=Gs.hasOwnProperty(t.type)?b:w;return function(i,o,u){var a,c=this.__on,s=r(n,o,u);if(c)for(var f=0,l=c.length;f<l;++f)if((a=c[f]).type===t.type&&a.name===t.name)return this.removeEventListener(a.type,a.listener,a.capture),this.addEventListener(a.type,a.listener=s,a.capture=e),void(a.value=n);this.addEventListener(t.type,s,e),a={type:t.type,name:t.name,value:n,listener:s,capture:e},c?c.push(a):this.__on=[a]}}function N(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function S(){}function E(){return[]}function A(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function C(t,n,e,r,i,o){for(var u,a=0,c=n.length,s=o.length;a<s;++a)(u=n[a])?(u.__data__=o[a],r[a]=u):e[a]=new A(t,o[a]);for(;a<c;++a)(u=n[a])&&(i[a]=u)}function z(t,n,e,r,i,o,u){var a,c,s,f={},l=n.length,h=o.length,p=new Array(l);for(a=0;a<l;++a)(c=n[a])&&(p[a]=s=of+u.call(c,c.__data__,a,n),s in f?i[a]=c:f[s]=c);for(a=0;a<h;++a)(c=f[s=of+u.call(t,o[a],a,o)])?(r[a]=c,c.__data__=o[a],f[s]=null):e[a]=new A(t,o[a]);for(a=0;a<l;++a)(c=n[a])&&f[p[a]]===c&&(i[a]=c)}function P(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function R(t){return function(){this.removeAttribute(t)}}function L(t){return function(){this.removeAttributeNS(t.space,t.local)}}function q(t,n){return function(){this.setAttribute(t,n)}}function U(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function D(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function O(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function F(t){return function(){this.style.removeProperty(t)}}function I(t,n,e){return function(){this.style.setProperty(t,n,e)}}function Y(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function B(t,n){return t.style.getPropertyValue(n)||uf(t).getComputedStyle(t,null).getPropertyValue(n)}function j(t){return function(){delete this[t]}}function H(t,n){return function(){this[t]=n}}function X(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function $(t){return t.trim().split(/^|\s+/)}function V(t){return t.classList||new W(t)}function W(t){this._node=t,this._names=$(t.getAttribute("class")||"")}function Z(t,n){for(var e=V(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function G(t,n){for(var e=V(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function J(t){return function(){Z(this,t)}}function Q(t){return function(){G(this,t)}}function K(t,n){return function(){(n.apply(this,arguments)?Z:G)(this,t)}}function tt(){this.textContent=""}function nt(t){return function(){this.textContent=t}}function et(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}function rt(){this.innerHTML=""}function it(t){return function(){this.innerHTML=t}}function ot(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}function ut(){this.nextSibling&&this.parentNode.appendChild(this)}function at(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function ct(){return null}function st(){var t=this.parentNode;t&&t.removeChild(this)}function ft(t,n,e){var r=uf(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function lt(t,n){return function(){return ft(this,t,n)}}function ht(t,n){return function(){return ft(this,t,n.apply(this,arguments))}}function pt(t,n){this._groups=t,this._parents=n}function dt(){return new pt([[document.documentElement]],af)}function vt(){t.event.stopImmediatePropagation()}function _t(t,n){var e=t.document.documentElement,r=cf(t).on("dragstart.drag",null);n&&(r.on("click.drag",ff,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function yt(t,n,e,r,i,o,u,a,c,s){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=u,this.dx=a,this.dy=c,this._=s}function gt(){return!t.event.button}function mt(){return this.parentNode}function xt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function bt(){return"ontouchstart"in this}function wt(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Mt(){}function Tt(t){var n;return t=(t+"").trim().toLowerCase(),(n=yf.exec(t))?(n=parseInt(n[1],16),new At(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1)):(n=gf.exec(t))?kt(parseInt(n[1],16)):(n=mf.exec(t))?new At(n[1],n[2],n[3],1):(n=xf.exec(t))?new At(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=bf.exec(t))?Nt(n[1],n[2],n[3],n[4]):(n=wf.exec(t))?Nt(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Mf.exec(t))?Ct(n[1],n[2]/100,n[3]/100,1):(n=Tf.exec(t))?Ct(n[1],n[2]/100,n[3]/100,n[4]):kf.hasOwnProperty(t)?kt(kf[t]):"transparent"===t?new At(NaN,NaN,NaN,0):null}function kt(t){return new At(t>>16&255,t>>8&255,255&t,1)}function Nt(t,n,e,r){return r<=0&&(t=n=e=NaN),new At(t,n,e,r)}function St(t){return t instanceof Mt||(t=Tt(t)),t?(t=t.rgb(),new At(t.r,t.g,t.b,t.opacity)):new At}function Et(t,n,e,r){return 1===arguments.length?St(t):new At(t,n,e,null==r?1:r)}function At(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ct(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Rt(t,n,e,r)}function zt(t){if(t instanceof Rt)return new Rt(t.h,t.s,t.l,t.opacity);if(t instanceof Mt||(t=Tt(t)),!t)return new Rt;if(t instanceof Rt)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e<r):e===o?(r-n)/a+2:(n-e)/a+4,a/=c<.5?o+i:2-o-i,u*=60):a=c>0&&c<1?0:u,new Rt(u,a,c,t.opacity)}function Pt(t,n,e,r){return 1===arguments.length?zt(t):new Rt(t,n,e,null==r?1:r)}function Rt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Lt(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function qt(t){if(t instanceof Dt)return new Dt(t.l,t.a,t.b,t.opacity);if(t instanceof Ht){var n=t.h*Nf;return new Dt(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof At||(t=St(t));var e=Yt(t.r),r=Yt(t.g),i=Yt(t.b),o=Ot((.4124564*e+.3575761*r+.1804375*i)/Ef),u=Ot((.2126729*e+.7151522*r+.072175*i)/Af);return new Dt(116*u-16,500*(o-u),200*(u-Ot((.0193339*e+.119192*r+.9503041*i)/Cf)),t.opacity)}function Ut(t,n,e,r){return 1===arguments.length?qt(t):new Dt(t,n,e,null==r?1:r)}function Dt(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Ot(t){return t>Lf?Math.pow(t,1/3):t/Rf+zf}function Ft(t){return t>Pf?t*t*t:Rf*(t-zf)}function It(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Yt(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Bt(t){if(t instanceof Ht)return new Ht(t.h,t.c,t.l,t.opacity);t instanceof Dt||(t=qt(t));var n=Math.atan2(t.b,t.a)*Sf;return new Ht(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function jt(t,n,e,r){return 1===arguments.length?Bt(t):new Ht(t,n,e,null==r?1:r)}function Ht(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function Xt(t){if(t instanceof Vt)return new Vt(t.h,t.s,t.l,t.opacity);t instanceof At||(t=St(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Bf*r+If*n-Yf*e)/(Bf+If-Yf),o=r-i,u=(Ff*(e-i)-Df*o)/Of,a=Math.sqrt(u*u+o*o)/(Ff*i*(1-i)),c=a?Math.atan2(u,o)*Sf-120:NaN;return new Vt(c<0?c+360:c,a,i,t.opacity)}function $t(t,n,e,r){return 1===arguments.length?Xt(t):new Vt(t,n,e,null==r?1:r)}function Vt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Wt(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}function Zt(t,n){return function(e){return t+e*n}}function Gt(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}function Jt(t,n){var e=n-t;return e?Zt(t,e>180||e<-180?e-360*Math.round(e/360):e):Jf(isNaN(t)?n:t)}function Qt(t){return 1==(t=+t)?Kt:function(n,e){return e-n?Gt(n,e,t):Jf(isNaN(n)?e:n)}}function Kt(t,n){var e=n-t;return e?Zt(t,e):Jf(isNaN(t)?n:t)}function tn(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e<i;++e)r=Et(n[e]),o[e]=r.r||0,u[e]=r.g||0,a[e]=r.b||0;return o=t(o),u=t(u),a=t(a),r.opacity=1,function(t){return r.r=o(t),r.g=u(t),r.b=a(t),r+""}}}function nn(t){return function(){return t}}function en(t){return function(n){return t(n)+""}}function rn(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}function o(t,r,i,o,u,a){if(t!==i||r!==o){var c=u.push("translate(",null,n,null,e);a.push({i:c-4,x:rl(t,i)},{i:c-2,x:rl(r,o)})}else(i||o)&&u.push("translate("+i+n+o+e)}function u(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:rl(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}function a(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:rl(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}function c(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:rl(t,e)},{i:a-2,x:rl(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}return function(n,e){var r=[],i=[];return n=t(n),e=t(e),o(n.translateX,n.translateY,e.translateX,e.translateY,r,i),u(n.rotate,e.rotate,r,i),a(n.skewX,e.skewX,r,i),c(n.scaleX,n.scaleY,e.scaleX,e.scaleY,r,i),n=e=null,function(t){for(var n,e=-1,o=i.length;++e<o;)r[(n=i[e]).i]=n.x(t);return r.join("")}}}function on(t){return((t=Math.exp(t))+1/t)/2}function un(t){return((t=Math.exp(t))-1/t)/2}function an(t){return((t=Math.exp(2*t))-1)/(t+1)}function cn(t){return function(n,e){var r=t((n=Pt(n)).h,(e=Pt(e)).h),i=Kt(n.s,e.s),o=Kt(n.l,e.l),u=Kt(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function sn(t){return function(n,e){var r=t((n=jt(n)).h,(e=jt(e)).h),i=Kt(n.c,e.c),o=Kt(n.l,e.l),u=Kt(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function fn(t){return function n(e){function r(n,r){var i=t((n=$t(n)).h,(r=$t(r)).h),o=Kt(n.s,r.s),u=Kt(n.l,r.l),a=Kt(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=u(Math.pow(t,e)),n.opacity=a(t),n+""}}return e=+e,r.gamma=n,r}(1)}function ln(){return El||(zl(hn),El=Cl.now()+Al)}function hn(){El=0}function pn(){this._call=this._time=this._next=null}function dn(t,n,e){var r=new pn;return r.restart(t,n,e),r}function vn(){ln(),++Ml;for(var t,n=Vf;n;)(t=El-n._time)>=0&&n._call.call(null,t),n=n._next;--Ml}function _n(){El=(Sl=Cl.now())+Al,Ml=Tl=0;try{vn()}finally{Ml=0,gn(),El=0}}function yn(){var t=Cl.now(),n=t-Sl;n>Nl&&(Al-=n,Sl=t)}function gn(){for(var t,n,e=Vf,r=1/0;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Vf=n);Wf=t,mn(r)}function mn(t){if(!Ml){Tl&&(Tl=clearTimeout(Tl));var n=t-El;n>24?(t<1/0&&(Tl=setTimeout(_n,n)),kl&&(kl=clearInterval(kl))):(kl||(Sl=El,kl=setInterval(yn,Nl)),Ml=1,zl(_n))}}function xn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>ql)throw new Error("too late");return e}function bn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>Dl)throw new Error("too late");return e}function wn(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("too late");return e}function Mn(t,n,e){function r(c){var s,f,l,h;if(e.state!==Ul)return o();for(s in a)if((h=a[s]).name===e.name){if(h.state===Ol)return Pl(r);h.state===Fl?(h.state=Yl,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete a[s]):+s<n&&(h.state=Yl,h.timer.stop(),delete a[s])}if(Pl(function(){e.state===Ol&&(e.state=Fl,e.timer.restart(i,e.delay,e.time),i(c))}),e.state=Dl,e.on.call("start",t,t.__data__,e.index,e.group),e.state===Dl){for(e.state=Ol,u=new Array(l=e.tween.length),s=0,f=-1;s<l;++s)(h=e.tween[s].value.call(t,t.__data__,e.index,e.group))&&(u[++f]=h);u.length=f+1}}function i(n){for(var r=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(o),e.state=Il,1),i=-1,a=u.length;++i<a;)u[i].call(null,r);e.state===Il&&(e.on.call("end",t,t.__data__,e.index,e.group),o())}function o(){e.state=Yl,e.timer.stop(),delete a[n];for(var r in a)return;delete t.__transition}var u,a=t.__transition;a[n]=e,e.timer=dn(function(t){e.state=Ul,e.timer.restart(r,e.delay,e.time),e.delay<=t&&r(t-e.delay)},0,e.time)}function Tn(t,n){var e,r;return function(){var i=bn(this,t),o=i.tween;if(o!==e)for(var u=0,a=(r=e=o).length;u<a;++u)if(r[u].name===n){(r=r.slice()).splice(u,1);break}i.tween=r}}function kn(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=bn(this,t),u=o.tween;if(u!==r){i=(r=u).slice();for(var a={name:n,value:e},c=0,s=i.length;c<s;++c)if(i[c].name===n){i[c]=a;break}c===s&&i.push(a)}o.tween=i}}function Nn(t,n,e){var r=t._id;return t.each(function(){var t=bn(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return wn(t,r).value[n]}}function Sn(t){return function(){this.removeAttribute(t)}}function En(t){return function(){this.removeAttributeNS(t.space,t.local)}}function An(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}}function Cn(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}function zn(t,n,e){var r,i,o;return function(){var u,a=e(this);{if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}}}function Pn(t,n,e){var r,i,o;return function(){var u,a=e(this);{if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}}function Rn(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}function Ln(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e}function qn(t,n){return function(){xn(this,t).delay=+n.apply(this,arguments)}}function Un(t,n){return n=+n,function(){xn(this,t).delay=n}}function Dn(t,n){return function(){bn(this,t).duration=+n.apply(this,arguments)}}function On(t,n){return n=+n,function(){bn(this,t).duration=n}}function Fn(t,n){if("function"!=typeof n)throw new Error;return function(){bn(this,t).ease=n}}function In(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}function Yn(t,n,e){var r,i,o=In(n)?xn:bn;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}function Bn(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}function jn(t,n){var e,r,i;return function(){var o=B(this,t),u=(this.style.removeProperty(t),B(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}function Hn(t){return function(){this.style.removeProperty(t)}}function Xn(t,n,e){var r,i;return function(){var o=B(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}function $n(t,n,e){var r,i,o;return function(){var u=B(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=B(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}function Vn(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}function Wn(t){return function(){this.textContent=t}}function Zn(t){return function(){var n=t(this);this.textContent=null==n?"":n}}function Gn(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function Jn(t){return dt().transition(t)}function Qn(){return++$l}function Kn(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function te(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}function ne(t){return(1-Math.cos(Jl*t))/2}function ee(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function re(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}function ie(t){return(t=+t)<Kl?ch*t*t:t<nh?ch*(t-=th)*t+eh:t<ih?ch*(t-=rh)*t+oh:ch*(t-=uh)*t+ah}function oe(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return _h.time=ln(),_h;return e}function ue(){t.event.stopImmediatePropagation()}function ae(t){return{type:t}}function ce(){return!t.event.button}function se(){var t=this.ownerSVGElement||this;return[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function fe(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function le(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function he(n){function e(t){var e=t.property("__brush",a).selectAll(".overlay").data([ae("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",Eh.overlay).merge(e).each(function(){var t=fe(this).extent;cf(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([ae("selection")]).enter().append("rect").attr("class","selection").attr("cursor",Eh.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var i=t.selectAll(".handle").data(n.handles,function(t){return t.type});i.exit().remove(),i.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return Eh[t.type]}),t.each(r).attr("fill","none").attr("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush touchstart.brush",u)}function r(){var t=cf(this),n=fe(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-p/2:n[0][0]-p/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-p/2:n[0][1]-p/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+p:p}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+p:p})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function i(t,n){return t.__brush.emitter||new o(t,n)}function o(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function u(){function e(){var t=Ks(w);!L||x||b||(Math.abs(t[0]-U[0])>Math.abs(t[1]-U[1])?b=!0:x=!0),U=t,m=!0,xh(),o()}function o(){var t;switch(y=U[0]-q[0],g=U[1]-q[1],T){case wh:case bh:k&&(y=Math.max(C-a,Math.min(P-p,y)),s=a+y,d=p+y),N&&(g=Math.max(z-l,Math.min(R-v,g)),h=l+g,_=v+g);break;case Mh:k<0?(y=Math.max(C-a,Math.min(P-a,y)),s=a+y,d=p):k>0&&(y=Math.max(C-p,Math.min(P-p,y)),s=a,d=p+y),N<0?(g=Math.max(z-l,Math.min(R-l,g)),h=l+g,_=v):N>0&&(g=Math.max(z-v,Math.min(R-v,g)),h=l,_=v+g);break;case Th:k&&(s=Math.max(C,Math.min(P,a-y*k)),d=Math.max(C,Math.min(P,p+y*k))),N&&(h=Math.max(z,Math.min(R,l-g*N)),_=Math.max(z,Math.min(R,v+g*N)))}d<s&&(k*=-1,t=a,a=p,p=t,t=s,s=d,d=t,M in Ah&&F.attr("cursor",Eh[M=Ah[M]])),_<h&&(N*=-1,t=l,l=v,v=t,t=h,h=_,_=t,M in Ch&&F.attr("cursor",Eh[M=Ch[M]])),S.selection&&(A=S.selection),x&&(s=A[0][0],d=A[1][0]),b&&(h=A[0][1],_=A[1][1]),A[0][0]===s&&A[0][1]===h&&A[1][0]===d&&A[1][1]===_||(S.selection=[[s,h],[d,_]],r.call(w),D.brush())}function u(){if(ue(),t.event.touches){if(t.event.touches.length)return;c&&clearTimeout(c),c=setTimeout(function(){c=null},500),O.on("touchmove.brush touchend.brush touchcancel.brush",null)}else _t(t.event.view,m),I.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);O.attr("pointer-events","all"),F.attr("cursor",Eh.overlay),S.selection&&(A=S.selection),le(A)&&(S.selection=null,r.call(w)),D.end()}if(t.event.touches){if(t.event.changedTouches.length<t.event.touches.length)return xh()}else if(c)return;if(f.apply(this,arguments)){var a,s,l,h,p,d,v,_,y,g,m,x,b,w=this,M=t.event.target.__data__.type,T="selection"===(t.event.metaKey?M="overlay":M)?bh:t.event.altKey?Th:Mh,k=n===Nh?null:zh[M],N=n===kh?null:Ph[M],S=fe(w),E=S.extent,A=S.selection,C=E[0][0],z=E[0][1],P=E[1][0],R=E[1][1],L=k&&N&&t.event.shiftKey,q=Ks(w),U=q,D=i(w,arguments).beforestart();"overlay"===M?S.selection=A=[[a=n===Nh?C:q[0],l=n===kh?z:q[1]],[p=n===Nh?P:a,v=n===kh?R:l]]:(a=A[0][0],l=A[0][1],p=A[1][0],v=A[1][1]),s=a,h=l,d=p,_=v;var O=cf(w).attr("pointer-events","none"),F=O.selectAll(".overlay").attr("cursor",Eh[M]);if(t.event.touches)O.on("touchmove.brush",e,!0).on("touchend.brush touchcancel.brush",u,!0);else{var I=cf(t.event.view).on("keydown.brush",function(){switch(t.event.keyCode){case 16:L=k&&N;break;case 18:T===Mh&&(k&&(p=d-y*k,a=s+y*k),N&&(v=_-g*N,l=h+g*N),T=Th,o());break;case 32:T!==Mh&&T!==Th||(k<0?p=d-y:k>0&&(a=s-y),N<0?v=_-g:N>0&&(l=h-g),T=wh,F.attr("cursor",Eh.selection),o());break;default:return}xh()},!0).on("keyup.brush",function(){switch(t.event.keyCode){case 16:L&&(x=b=L=!1,o());break;case 18:T===Th&&(k<0?p=d:k>0&&(a=s),N<0?v=_:N>0&&(l=h),T=Mh,o());break;case 32:T===wh&&(t.event.altKey?(k&&(p=d-y*k,a=s+y*k),N&&(v=_-g*N,l=h+g*N),T=Th):(k<0?p=d:k>0&&(a=s),N<0?v=_:N>0&&(l=h),T=Mh),F.attr("cursor",Eh[M]),o());break;default:return}xh()},!0).on("mousemove.brush",e,!0).on("mouseup.brush",u,!0);lf(t.event.view)}ue(),jl(w),r.call(w),D.start()}}function a(){var t=this.__brush||{selection:null};return t.extent=s.apply(this,arguments),t.dim=n,t}var c,s=se,f=ce,l=h(e,"start","brush","end"),p=6;return e.move=function(t,e){t.selection?t.on("start.brush",function(){i(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){i(this,arguments).end()}).tween("brush",function(){function t(t){u.selection=1===t&&le(s)?null:f(t),r.call(o),a.brush()}var o=this,u=o.__brush,a=i(o,arguments),c=u.selection,s=n.input("function"==typeof e?e.apply(this,arguments):e,u.extent),f=cl(c,s);return c&&s?t:t(1)}):t.each(function(){var t=this,o=arguments,u=t.__brush,a=n.input("function"==typeof e?e.apply(t,o):e,u.extent),c=i(t,o).beforestart();jl(t),u.selection=null==a||le(a)?null:a,r.call(t),c.start().brush().end()})},o.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting&&(this.starting=!1,this.emit("start")),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){N(new mh(e,t,n.output(this.state.selection)),l.apply,l,[t,this.that,this.args])}},e.extent=function(t){return arguments.length?(s="function"==typeof t?t:gh([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),e):s},e.filter=function(t){return arguments.length?(f="function"==typeof t?t:gh(!!t),e):f},e.handleSize=function(t){return arguments.length?(p=+t,e):p},e.on=function(){var t=l.on.apply(l,arguments);return t===l?e:t},e}function pe(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}function de(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function ve(){return new de}function _e(t){return t.source}function ye(t){return t.target}function ge(t){return t.radius}function me(t){return t.startAngle}function xe(t){return t.endAngle}function be(){}function we(t,n){var e=new be;if(t instanceof be)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var u in t)e.set(u,t[u]);return e}function Me(){return{}}function Te(t,n,e){t[n]=e}function ke(){return we()}function Ne(t,n,e){t.set(n,e)}function Se(){}function Ee(t,n){var e=new Se;if(t instanceof Se)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}function Ae(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}")}function Ce(t,n){var e=Ae(t);return function(r,i){return n(e(r),i,t)}}function ze(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function Pe(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,u,a,c,s,f,l,h,p=t._root,d={data:r},v=t._x0,_=t._y0,y=t._x1,g=t._y1;if(!p)return t._root=d,t;for(;p.length;)if((s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u,i=p,!(p=p[l=f<<1|s]))return i[l]=d,t;if(a=+t._x.call(null,p.data),c=+t._y.call(null,p.data),n===a&&e===c)return d.next=p,i?i[l]=d:t._root=d,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u}while((l=f<<1|s)==(h=(c>=u)<<1|a>=o));return i[h]=p,i[l]=d,t}function Re(t){return t[0]}function Le(t){return t[1]}function qe(t,n,e){var r=new Ue(null==n?Re:n,null==e?Le:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ue(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function De(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}function Oe(t){return t.x+t.vx}function Fe(t){return t.y+t.vy}function Ie(t){return t.index}function Ye(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function Be(t){return t.x}function je(t){return t.y}function He(t){return new Xe(t)}function Xe(t){if(!(n=vp.exec(t)))throw new Error("invalid format: "+t);var n,e=n[1]||" ",r=n[2]||">",i=n[3]||"-",o=n[4]||"",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],s=n[8]&&+n[8].slice(1),f=n[9]||"";"n"===f?(c=!0,f="g"):dp[f]||(f=""),(u||"0"===e&&"="===r)&&(u=!0,e="0",r="="),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=s,this.type=f}function $e(n){return _p=mp(n),t.format=_p.format,t.formatPrefix=_p.formatPrefix,_p}function Ve(){this.reset()}function We(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}function Ze(t){return t>1?0:t<-1?rd:Math.acos(t)}function Ge(t){return t>1?id:t<-1?-id:Math.asin(t)}function Je(t){return(t=yd(t/2))*t}function Qe(){}function Ke(t,n){t&&wd.hasOwnProperty(t.type)&&wd[t.type](t,n)}function tr(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function nr(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)tr(t[e],n,1);n.polygonEnd()}function er(){Nd.point=ir}function rr(){or(Tp,kp)}function ir(t,n){Nd.point=or,Tp=t,kp=n,Np=t*=cd,Sp=hd(n=(n*=cd)/2+od),Ep=yd(n)}function or(t,n){n=(n*=cd)/2+od;var e=(t*=cd)-Np,r=e>=0?1:-1,i=r*e,o=hd(n),u=yd(n),a=Ep*u,c=Sp*o+a*hd(i),s=a*r*yd(i);Td.add(ld(s,c)),Np=t,Sp=o,Ep=u}function ur(t){return[ld(t[1],t[0]),Ge(t[2])]}function ar(t){var n=t[0],e=t[1],r=hd(e);return[r*hd(n),r*yd(n),yd(e)]}function cr(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function sr(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function fr(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function lr(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function hr(t){var n=md(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}function pr(t,n){Dp.push(Op=[Ap=t,zp=t]),n<Cp&&(Cp=n),n>Pp&&(Pp=n)}function dr(t,n){var e=ar([t*cd,n*cd]);if(Up){var r=sr(Up,e),i=sr([r[1],-r[0],0],r);hr(i),i=ur(i);var o,u=t-Rp,a=u>0?1:-1,c=i[0]*ad*a,s=sd(u)>180;s^(a*Rp<c&&c<a*t)?(o=i[1]*ad)>Pp&&(Pp=o):(c=(c+360)%360-180,s^(a*Rp<c&&c<a*t)?(o=-i[1]*ad)<Cp&&(Cp=o):(n<Cp&&(Cp=n),n>Pp&&(Pp=n))),s?t<Rp?xr(Ap,t)>xr(Ap,zp)&&(zp=t):xr(t,zp)>xr(Ap,zp)&&(Ap=t):zp>=Ap?(t<Ap&&(Ap=t),t>zp&&(zp=t)):t>Rp?xr(Ap,t)>xr(Ap,zp)&&(zp=t):xr(t,zp)>xr(Ap,zp)&&(Ap=t)}else Dp.push(Op=[Ap=t,zp=t]);n<Cp&&(Cp=n),n>Pp&&(Pp=n),Up=e,Rp=t}function vr(){Ed.point=dr}function _r(){Op[0]=Ap,Op[1]=zp,Ed.point=pr,Up=null}function yr(t,n){if(Up){var e=t-Rp;Sd.add(sd(e)>180?e+(e>0?360:-360):e)}else Lp=t,qp=n;Nd.point(t,n),dr(t,n)}function gr(){Nd.lineStart()}function mr(){yr(Lp,qp),Nd.lineEnd(),sd(Sd)>ed&&(Ap=-(zp=180)),Op[0]=Ap,Op[1]=zp,Up=null}function xr(t,n){return(n-=t)<0?n+360:n}function br(t,n){return t[0]-n[0]}function wr(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}function Mr(t,n){t*=cd;var e=hd(n*=cd);Tr(e*hd(t),e*yd(t),yd(n))}function Tr(t,n,e){Yp+=(t-Yp)/++Fp,Bp+=(n-Bp)/Fp,jp+=(e-jp)/Fp}function kr(){Ad.point=Nr}function Nr(t,n){t*=cd;var e=hd(n*=cd);Qp=e*hd(t),Kp=e*yd(t),td=yd(n),Ad.point=Sr,Tr(Qp,Kp,td)}function Sr(t,n){t*=cd;var e=hd(n*=cd),r=e*hd(t),i=e*yd(t),o=yd(n),u=ld(md((u=Kp*o-td*i)*u+(u=td*r-Qp*o)*u+(u=Qp*i-Kp*r)*u),Qp*r+Kp*i+td*o);Ip+=u,Hp+=u*(Qp+(Qp=r)),Xp+=u*(Kp+(Kp=i)),$p+=u*(td+(td=o)),Tr(Qp,Kp,td)}function Er(){Ad.point=Mr}function Ar(){Ad.point=zr}function Cr(){Pr(Gp,Jp),Ad.point=Mr}function zr(t,n){Gp=t,Jp=n,t*=cd,n*=cd,Ad.point=Pr;var e=hd(n);Qp=e*hd(t),Kp=e*yd(t),td=yd(n),Tr(Qp,Kp,td)}function Pr(t,n){t*=cd;var e=hd(n*=cd),r=e*hd(t),i=e*yd(t),o=yd(n),u=Kp*o-td*i,a=td*r-Qp*o,c=Qp*i-Kp*r,s=md(u*u+a*a+c*c),f=Ge(s),l=s&&-f/s;Vp+=l*u,Wp+=l*a,Zp+=l*c,Ip+=f,Hp+=f*(Qp+(Qp=r)),Xp+=f*(Kp+(Kp=i)),$p+=f*(td+(td=o)),Tr(Qp,Kp,td)}function Rr(t,n){return[t>rd?t-ud:t<-rd?t+ud:t,n]}function Lr(t,n,e){return(t%=ud)?n||e?zd(Ur(t),Dr(n,e)):Ur(t):n||e?Dr(n,e):Rr}function qr(t){return function(n,e){return n+=t,[n>rd?n-ud:n<-rd?n+ud:n,e]}}function Ur(t){var n=qr(t);return n.invert=qr(-t),n}function Dr(t,n){function e(t,n){var e=hd(n),a=hd(t)*e,c=yd(t)*e,s=yd(n),f=s*r+a*i;return[ld(c*o-f*u,a*r-s*i),Ge(f*o+c*u)]}var r=hd(t),i=yd(t),o=hd(n),u=yd(n);return e.invert=function(t,n){var e=hd(n),a=hd(t)*e,c=yd(t)*e,s=yd(n),f=s*o-c*u;return[ld(c*o+s*u,a*r+f*i),Ge(f*r-a*i)]},e}function Or(t,n,e,r,i,o){if(e){var u=hd(n),a=yd(n),c=r*e;null==i?(i=n+r*ud,o=n-c/2):(i=Fr(u,i),o=Fr(u,o),(r>0?i<o:i>o)&&(i+=r*ud));for(var s,f=i;r>0?f>o:f<o;f-=c)s=ur([u,-a*hd(f),-a*yd(f)]),t.point(s[0],s[1])}}function Fr(t,n){(n=ar(n))[0]-=t,hr(n);var e=Ze(-n[1]);return((-n[2]<0?-e:e)+ud-ed)%ud}function Ir(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Yr(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function Br(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,a,s){var f=0,l=0;if(null==i||(f=u(i,a))!==(l=u(o,a))||c(i,o)<0^a>0)do{s.point(0===f||3===f?t:e,f>1?r:n)}while((f=(f+a+4)%4)!==l);else s.point(o[0],o[1])}function u(r,i){return sd(r[0]-t)<ed?i>0?0:3:sd(r[0]-e)<ed?i>0?2:1:sd(r[1]-n)<ed?i>0?1:0:i>0?3:2}function a(t,n){return c(t.x,n.x)}function c(t,n){var e=u(t,1),r=u(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){function c(t,n){i(t,n)&&w.point(t,n)}function s(){for(var n=0,e=0,i=h.length;e<i;++e)for(var o,u,a=h[e],c=1,s=a.length,f=a[0],l=f[0],p=f[1];c<s;++c)o=l,u=p,l=(f=a[c])[0],p=f[1],u<=r?p>r&&(l-o)*(r-u)>(p-u)*(t-o)&&++n:p<=r&&(l-o)*(r-u)<(p-u)*(t-o)&&--n;return n}function f(o,u){var a=i(o,u);if(h&&p.push([o,u]),x)d=o,v=u,_=a,x=!1,a&&(w.lineStart(),w.point(o,u));else if(a&&m)w.point(o,u);else{var c=[y=Math.max(Zd,Math.min(Wd,y)),g=Math.max(Zd,Math.min(Wd,g))],s=[o=Math.max(Zd,Math.min(Wd,o)),u=Math.max(Zd,Math.min(Wd,u))];Xd(c,s,t,n,e,r)?(m||(w.lineStart(),w.point(c[0],c[1])),w.point(s[0],s[1]),a||w.lineEnd(),b=!1):a&&(w.lineStart(),w.point(o,u),b=!1)}y=o,g=u,m=a}var l,h,p,d,v,_,y,g,m,x,b,w=u,M=Hd(),T={point:c,lineStart:function(){T.point=f,h&&h.push(p=[]),x=!0,m=!1,y=g=NaN},lineEnd:function(){l&&(f(d,v),_&&m&&M.rejoin(),l.push(M.result())),T.point=c,m&&w.lineEnd()},polygonStart:function(){w=M,l=[],h=[],b=!0},polygonEnd:function(){var t=s(),n=b&&t,e=(l=Cs(l)).length;(n||e)&&(u.polygonStart(),n&&(u.lineStart(),o(null,null,1,u),u.lineEnd()),e&&Vd(l,a,t,o,u),u.polygonEnd()),w=u,l=h=p=null}};return T}}function jr(){Kd.point=Kd.lineEnd=Qe}function Hr(t,n){Pd=t*=cd,Rd=yd(n*=cd),Ld=hd(n),Kd.point=Xr}function Xr(t,n){t*=cd;var e=yd(n*=cd),r=hd(n),i=sd(t-Pd),o=hd(i),u=r*yd(i),a=Ld*e-Rd*r*o,c=Rd*e+Ld*r*o;Qd.add(ld(md(u*u+a*a),c)),Pd=t,Rd=e,Ld=r}function $r(t,n){return!(!t||!ov.hasOwnProperty(t.type))&&ov[t.type](t,n)}function Vr(t,n){return 0===rv(t,n)}function Wr(t,n){var e=rv(t[0],t[1]);return rv(t[0],n)+rv(n,t[1])<=e+ed}function Zr(t,n){return!!Jd(t.map(Gr),Jr(n))}function Gr(t){return(t=t.map(Jr)).pop(),t}function Jr(t){return[t[0]*cd,t[1]*cd]}function Qr(t,n,e){var r=Ms(t,n-ed,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function Kr(t,n,e){var r=Ms(t,n-ed,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function ti(){function t(){return{type:"MultiLineString",coordinates:n()}}function n(){return Ms(pd(o/_)*_,i,_).map(h).concat(Ms(pd(s/y)*y,c,y).map(p)).concat(Ms(pd(r/d)*d,e,d).filter(function(t){return sd(t%_)>ed}).map(f)).concat(Ms(pd(a/v)*v,u,v).filter(function(t){return sd(t%y)>ed}).map(l))}var e,r,i,o,u,a,c,s,f,l,h,p,d=10,v=d,_=90,y=360,g=2.5;return t.lines=function(){return n().map(function(t){return{type:"LineString",coordinates:t}})},t.outline=function(){return{type:"Polygon",coordinates:[h(o).concat(p(c).slice(1),h(i).reverse().slice(1),p(s).reverse().slice(1))]}},t.extent=function(n){return arguments.length?t.extentMajor(n).extentMinor(n):t.extentMinor()},t.extentMajor=function(n){return arguments.length?(o=+n[0][0],i=+n[1][0],s=+n[0][1],c=+n[1][1],o>i&&(n=o,o=i,i=n),s>c&&(n=s,s=c,c=n),t.precision(g)):[[o,s],[i,c]]},t.extentMinor=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],a=+n[0][1],u=+n[1][1],r>e&&(n=r,r=e,e=n),a>u&&(n=a,a=u,u=n),t.precision(g)):[[r,a],[e,u]]},t.step=function(n){return arguments.length?t.stepMajor(n).stepMinor(n):t.stepMinor()},t.stepMajor=function(n){return arguments.length?(_=+n[0],y=+n[1],t):[_,y]},t.stepMinor=function(n){return arguments.length?(d=+n[0],v=+n[1],t):[d,v]},t.precision=function(n){return arguments.length?(g=+n,f=Qr(a,u,90),l=Kr(r,e,g),h=Qr(s,c,90),p=Kr(o,i,g),t):g},t.extentMajor([[-180,-90+ed],[180,90-ed]]).extentMinor([[-180,-80-ed],[180,80+ed]])}function ni(){sv.point=ei}function ei(t,n){sv.point=ri,qd=Dd=t,Ud=Od=n}function ri(t,n){cv.add(Od*t-Dd*n),Dd=t,Od=n}function ii(){ri(qd,Ud)}function oi(t,n){vv+=t,_v+=n,++yv}function ui(){Tv.point=ai}function ai(t,n){Tv.point=ci,oi(Yd=t,Bd=n)}function ci(t,n){var e=t-Yd,r=n-Bd,i=md(e*e+r*r);gv+=i*(Yd+t)/2,mv+=i*(Bd+n)/2,xv+=i,oi(Yd=t,Bd=n)}function si(){Tv.point=oi}function fi(){Tv.point=hi}function li(){pi(Fd,Id)}function hi(t,n){Tv.point=pi,oi(Fd=Yd=t,Id=Bd=n)}function pi(t,n){var e=t-Yd,r=n-Bd,i=md(e*e+r*r);gv+=i*(Yd+t)/2,mv+=i*(Bd+n)/2,xv+=i,bv+=(i=Bd*t-Yd*n)*(Yd+t),wv+=i*(Bd+n),Mv+=3*i,oi(Yd=t,Bd=n)}function di(t){this._context=t}function vi(t,n){zv.point=_i,Nv=Ev=t,Sv=Av=n}function _i(t,n){Ev-=t,Av-=n,Cv.add(md(Ev*Ev+Av*Av)),Ev=t,Av=n}function yi(){this._string=[]}function gi(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function mi(t){return t.length>1}function xi(t,n){return((t=t.x)[0]<0?t[1]-id-ed:id-t[1])-((n=n.x)[0]<0?n[1]-id-ed:id-n[1])}function bi(t,n,e,r){var i,o,u=yd(t-e);return sd(u)>ed?fd((yd(n)*(o=hd(r))*yd(e)-yd(r)*(i=hd(n))*yd(t))/(i*o*u)):(n+r)/2}function wi(t){return function(n){var e=new Mi;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Mi(){}function Ti(t,n,e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=t.clipExtent&&t.clipExtent();t.scale(150).translate([0,0]),null!=o&&t.clipExtent(null),Md(e,t.stream(dv));var u=dv.result(),a=Math.min(r/(u[1][0]-u[0][0]),i/(u[1][1]-u[0][1])),c=+n[0][0]+(r-a*(u[1][0]+u[0][0]))/2,s=+n[0][1]+(i-a*(u[1][1]+u[0][1]))/2;return null!=o&&t.clipExtent(o),t.scale(150*a).translate([c,s])}function ki(t,n,e){return Ti(t,[[0,0],n],e)}function Ni(t){return wi({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}function Si(t,n){function e(r,i,o,u,a,c,s,f,l,h,p,d,v,_){var y=s-r,g=f-i,m=y*y+g*g;if(m>4*n&&v--){var x=u+h,b=a+p,w=c+d,M=md(x*x+b*b+w*w),T=Ge(w/=M),k=sd(sd(w)-1)<ed||sd(o-l)<ed?(o+l)/2:ld(b,x),N=t(k,T),S=N[0],E=N[1],A=S-r,C=E-i,z=g*A-y*C;(z*z/m>n||sd((y*A+g*C)/m-.5)>.3||u*h+a*p+c*d<Uv)&&(e(r,i,o,u,a,c,S,E,k,x/=M,b/=M,w,v,_),_.point(S,E),e(S,E,k,x,b,w,s,f,l,h,p,d,v,_))}}return function(n){function r(e,r){e=t(e,r),n.point(e[0],e[1])}function i(){y=NaN,w.point=o,n.lineStart()}function o(r,i){var o=ar([r,i]),u=t(r,i);e(y,g,_,m,x,b,y=u[0],g=u[1],_=r,m=o[0],x=o[1],b=o[2],qv,n),n.point(y,g)}function u(){w.point=r,n.lineEnd()}function a(){i(),w.point=c,w.lineEnd=s}function c(t,n){o(f=t,n),l=y,h=g,p=m,d=x,v=b,w.point=o}function s(){e(y,g,_,m,x,b,l,h,f,p,d,v,qv,n),w.lineEnd=u,u()}var f,l,h,p,d,v,_,y,g,m,x,b,w={point:r,lineStart:i,lineEnd:u,polygonStart:function(){n.polygonStart(),w.lineStart=a},polygonEnd:function(){n.polygonEnd(),w.lineStart=i}};return w}}function Ei(t){return Ai(function(){return t})()}function Ai(t){function n(t){return t=f(t[0]*cd,t[1]*cd),[t[0]*_+a,c-t[1]*_]}function e(t){return(t=f.invert((t[0]-a)/_,(c-t[1])/_))&&[t[0]*ad,t[1]*ad]}function r(t,n){return t=u(t,n),[t[0]*_+a,c-t[1]*_]}function i(){f=zd(s=Lr(b,w,M),u);var t=u(m,x);return a=y-t[0]*_,c=g+t[1]*_,o()}function o(){return d=v=null,n}var u,a,c,s,f,l,h,p,d,v,_=150,y=480,g=250,m=0,x=0,b=0,w=0,M=0,T=null,k=Rv,N=null,S=uv,E=.5,A=Dv(r,E);return n.stream=function(t){return d&&v===t?d:d=Ov(k(s,A(S(v=t))))},n.clipAngle=function(t){return arguments.length?(k=+t?Lv(T=t*cd,6*cd):(T=null,Rv),o()):T*ad},n.clipExtent=function(t){return arguments.length?(S=null==t?(N=l=h=p=null,uv):Br(N=+t[0][0],l=+t[0][1],h=+t[1][0],p=+t[1][1]),o()):null==N?null:[[N,l],[h,p]]},n.scale=function(t){return arguments.length?(_=+t,i()):_},n.translate=function(t){return arguments.length?(y=+t[0],g=+t[1],i()):[y,g]},n.center=function(t){return arguments.length?(m=t[0]%360*cd,x=t[1]%360*cd,i()):[m*ad,x*ad]},n.rotate=function(t){return arguments.length?(b=t[0]%360*cd,w=t[1]%360*cd,M=t.length>2?t[2]%360*cd:0,i()):[b*ad,w*ad,M*ad]},n.precision=function(t){return arguments.length?(A=Dv(r,E=t*t),o()):md(E)},n.fitExtent=function(t,e){return Ti(n,t,e)},n.fitSize=function(t,e){return ki(n,t,e)},function(){return u=t.apply(this,arguments),n.invert=u.invert&&e,i()}}function Ci(t){var n=0,e=rd/3,r=Ai(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*cd,e=t[1]*cd):[n*ad,e*ad]},i}function zi(t){function n(t,n){return[t*e,yd(n)/e]}var e=hd(t);return n.invert=function(t,n){return[t/e,Ge(n*e)]},n}function Pi(t,n){function e(t,n){var e=md(o-2*i*yd(n))/i;return[e*yd(t*=i),u-e*hd(t)]}var r=yd(t),i=(r+yd(n))/2;if(sd(i)<ed)return zi(t);var o=1+r*(2*i-r),u=md(o)/i;return e.invert=function(t,n){var e=u-n;return[ld(t,sd(e))/i*gd(e),Ge((o-(t*t+e*e)*i*i)/(2*i))]},e}function Ri(t){var n=t.length;return{point:function(e,r){for(var i=-1;++i<n;)t[i].point(e,r)},sphere:function(){for(var e=-1;++e<n;)t[e].sphere()},lineStart:function(){for(var e=-1;++e<n;)t[e].lineStart()},lineEnd:function(){for(var e=-1;++e<n;)t[e].lineEnd()},polygonStart:function(){for(var e=-1;++e<n;)t[e].polygonStart()},polygonEnd:function(){for(var e=-1;++e<n;)t[e].polygonEnd()}}}function Li(t){return function(n,e){var r=hd(n),i=hd(e),o=t(r*i);return[o*i*yd(n),o*yd(e)]}}function qi(t){return function(n,e){var r=md(n*n+e*e),i=t(r),o=yd(i),u=hd(i);return[ld(n*o,r*u),Ge(r&&e*o/r)]}}function Ui(t,n){return[t,vd(xd((id+n)/2))]}function Di(t){function n(){var n=rd*a(),u=o(jd(o.rotate()).invert([0,0]));return s(null==f?[[u[0]-n,u[1]-n],[u[0]+n,u[1]+n]]:t===Ui?[[Math.max(u[0]-n,f),e],[Math.min(u[0]+n,r),i]]:[[f,Math.max(u[1]-n,e)],[r,Math.min(u[1]+n,i)]])}var e,r,i,o=Ei(t),u=o.center,a=o.scale,c=o.translate,s=o.clipExtent,f=null;return o.scale=function(t){return arguments.length?(a(t),n()):a()},o.translate=function(t){return arguments.length?(c(t),n()):c()},o.center=function(t){return arguments.length?(u(t),n()):u()},o.clipExtent=function(t){return arguments.length?(null==t?f=e=r=i=null:(f=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),n()):null==f?null:[[f,e],[r,i]]},n()}function Oi(t){return xd((id+t)/2)}function Fi(t,n){function e(t,n){o>0?n<-id+ed&&(n=-id+ed):n>id-ed&&(n=id-ed);var e=o/_d(Oi(n),i);return[e*yd(i*t),o-e*hd(i*t)]}var r=hd(t),i=t===n?yd(t):vd(r/hd(n))/vd(Oi(n)/Oi(t)),o=r*_d(Oi(t),i)/i;return i?(e.invert=function(t,n){var e=o-n,r=gd(i)*md(t*t+e*e);return[ld(t,sd(e))/i*gd(e),2*fd(_d(o/r,1/i))-id]},e):Ui}function Ii(t,n){return[t,n]}function Yi(t,n){function e(t,n){var e=o-n,r=i*t;return[e*yd(r),o-e*hd(r)]}var r=hd(t),i=t===n?yd(t):(r-hd(n))/(n-t),o=r/i+t;return sd(i)<ed?Ii:(e.invert=function(t,n){var e=o-n;return[ld(t,sd(e))/i*gd(e),o-gd(i)*md(t*t+e*e)]},e)}function Bi(t,n){var e=hd(n),r=hd(t)*e;return[e*yd(t)/r,yd(n)/r]}function ji(t,n,e,r){return 1===t&&1===n&&0===e&&0===r?uv:wi({point:function(i,o){this.stream.point(i*t+e,o*n+r)}})}function Hi(t,n){return[hd(n)*yd(t),yd(n)]}function Xi(t,n){var e=hd(n),r=1+hd(t)*e;return[e*yd(t)/r,yd(n)/r]}function $i(t,n){return[vd(xd((id+n)/2)),-t]}function Vi(t,n){return t.parent===n.parent?1:2}function Wi(t){return t.reduce(Zi,0)/t.length}function Zi(t,n){return t+n.x}function Gi(t){return 1+t.reduce(Ji,0)}function Ji(t,n){return Math.max(t,n.y)}function Qi(t){for(var n;n=t.children;)t=n[0];return t}function Ki(t){for(var n;n=t.children;)t=n[n.length-1];return t}function to(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function no(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}function eo(t,n){var e,r,i,o,u,a=new uo(t),c=+t.value&&(a.value=t.value),s=[a];for(null==n&&(n=ro);e=s.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(u=i.length))for(e.children=new Array(u),o=u-1;o>=0;--o)s.push(r=e.children[o]=new uo(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(oo)}function ro(t){return t.children}function io(t){t.data=t.data.data}function oo(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function uo(t){this.data=t,this.depth=this.height=0,this.parent=null}function ao(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}function co(t,n){var e,r;if(lo(n,t))return[n];for(e=0;e<t.length;++e)if(so(n,t[e])&&lo(vo(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(so(vo(t[e],t[r]),n)&&so(vo(t[e],n),t[r])&&so(vo(t[r],n),t[e])&&lo(_o(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function so(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function fo(t,n){var e=t.r-n.r+1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function lo(t,n){for(var e=0;e<n.length;++e)if(!fo(t,n[e]))return!1;return!0}function ho(t){switch(t.length){case 1:return po(t[0]);case 2:return vo(t[0],t[1]);case 3:return _o(t[0],t[1],t[2])}}function po(t){return{x:t.x,y:t.y,r:t.r}}function vo(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,u=n.y,a=n.r,c=o-e,s=u-r,f=a-i,l=Math.sqrt(c*c+s*s);return{x:(e+o+c/l*f)/2,y:(r+u+s/l*f)/2,r:(l+i+a)/2}}function _o(t,n,e){var r=t.x,i=t.y,o=t.r,u=n.x,a=n.y,c=n.r,s=e.x,f=e.y,l=e.r,h=r-u,p=r-s,d=i-a,v=i-f,_=c-o,y=l-o,g=r*r+i*i-o*o,m=g-u*u-a*a+c*c,x=g-s*s-f*f+l*l,b=p*d-h*v,w=(d*x-v*m)/(2*b)-r,M=(v*_-d*y)/b,T=(p*m-h*x)/(2*b)-i,k=(h*y-p*_)/b,N=M*M+k*k-1,S=2*(o+w*M+T*k),E=w*w+T*T-o*o,A=-(N?(S+Math.sqrt(S*S-4*N*E))/(2*N):E/S);return{x:r+w+M*A,y:i+T+k*A,r:A}}function yo(t,n,e){var r=t.x,i=t.y,o=n.r+e.r,u=t.r+e.r,a=n.x-r,c=n.y-i,s=a*a+c*c;if(s){var f=.5+((u*=u)-(o*=o))/(2*s),l=Math.sqrt(Math.max(0,2*o*(u+s)-(u-=s)*u-o*o))/(2*s);e.x=r+f*a+l*c,e.y=i+f*c-l*a}else e.x=r+u,e.y=i}function go(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return i*i-1e-6>e*e+r*r}function mo(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function xo(t){this._=t,this.next=null,this.previous=null}function bo(t){if(!(i=t.length))return 0;var n,e,r,i,o,u,a,c,s,f,l;if(n=t[0],n.x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;yo(e,n,r=t[2]),n=new xo(n),e=new xo(e),r=new xo(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(a=3;a<i;++a){yo(n._,e._,r=t[a]),r=new xo(r),c=e.next,s=n.previous,f=e._.r,l=n._.r;do{if(f<=l){if(go(c._,r._)){e=c,n.next=e,e.previous=n,--a;continue t}f+=c._.r,c=c.next}else{if(go(s._,r._)){(n=s).next=e,e.previous=n,--a;continue t}l+=s._.r,s=s.previous}}while(c!==s.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=mo(n);(r=r.next)!==e;)(u=mo(r))<o&&(n=r,o=u);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Hv(n),a=0;a<i;++a)n=t[a],n.x-=r.x,n.y-=r.y;return r.r}function wo(t){return null==t?null:Mo(t)}function Mo(t){if("function"!=typeof t)throw new Error;return t}function To(){return 0}function ko(t){return Math.sqrt(t.value)}function No(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function So(t,n){return function(e){if(r=e.children){var r,i,o,u=r.length,a=t(e)*n||0;if(a)for(i=0;i<u;++i)r[i].r+=a;if(o=bo(r),a)for(i=0;i<u;++i)r[i].r-=a;e.r=o+a}}}function Eo(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Ao(t){return t.id}function Co(t){return t.parentId}function zo(t,n){return t.parent===n.parent?1:2}function Po(t){var n=t.children;return n?n[0]:t.t}function Ro(t){var n=t.children;return n?n[n.length-1]:t.t}function Lo(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function qo(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}function Uo(t,n,e){return t.a.parent===n.parent?t.a:e}function Do(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Oo(t){for(var n,e,r,i,o,u=new Do(t,0),a=[u];n=a.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)a.push(e=n.children[i]=new Do(r[i],i)),e.parent=n;return(u.parent=new Do(null,0)).children=[u],u}function Fo(t,n,e,r,i,o){for(var u,a,c,s,f,l,h,p,d,v,_,y=[],g=n.children,m=0,x=0,b=g.length,w=n.value;m<b;){c=i-e,s=o-r;do{f=g[x++].value}while(!f&&x<b);for(l=h=f,_=f*f*(v=Math.max(s/c,c/s)/(w*t)),d=Math.max(h/_,_/l);x<b;++x){if(f+=a=g[x].value,a<l&&(l=a),a>h&&(h=a),_=f*f*v,(p=Math.max(h/_,_/l))>d){f-=a;break}d=p}y.push(u={value:f,dice:c<s,children:g.slice(m,x)}),u.dice?Vv(u,e,r,i,w?r+=s*f/w:o):Jv(u,e,r,w?e+=c*f/w:i,o),w-=f,m=x}return y}function Io(t,n){return t[0]-n[0]||t[1]-n[1]}function Yo(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&n_(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function Bo(t){this._size=t,this._call=this._error=null,this._tasks=[],this._data=[],this._waiting=this._active=this._ended=this._start=0}function jo(t){if(!t._start)try{Ho(t)}catch(n){if(t._tasks[t._ended+t._active-1])$o(t,n);else if(!t._data)throw n}}function Ho(t){for(;t._start=t._waiting&&t._active<t._size;){var n=t._ended+t._active,e=t._tasks[n],r=e.length-1,i=e[r];e[r]=Xo(t,n),--t._waiting,++t._active,e=i.apply(null,e),t._tasks[n]&&(t._tasks[n]=e||r_)}}function Xo(t,n){return function(e,r){t._tasks[n]&&(--t._active,++t._ended,t._tasks[n]=null,null==t._error&&(null!=e?$o(t,e):(t._data[n]=r,t._waiting?jo(t):Vo(t))))}}function $o(t,n){var e,r=t._tasks.length;for(t._error=n,t._data=void 0,t._waiting=NaN;--r>=0;)if((e=t._tasks[r])&&(t._tasks[r]=null,e.abort))try{e.abort()}catch(n){}t._active=NaN,Vo(t)}function Vo(t){if(!t._active&&t._call){var n=t._data;t._data=void 0,t._call(t._error,n)}}function Wo(t){if(null==t)t=1/0;else if(!((t=+t)>=1))throw new Error("invalid concurrency");return new Bo(t)}function Zo(t){return function(n,e){t(null==n?e:null)}}function Go(t){var n=t.responseType;return n&&"text"!==n?t.response:t.responseText}function Jo(t,n){return function(e){return t(e.responseText,n)}}function Qo(t){function n(n){var o=n+"",u=e.get(o);if(!u){if(i!==M_)return i;e.set(o,u=r.push(n))}return t[(u-1)%t.length]}var e=we(),r=[],i=M_;return t=null==t?[]:w_.call(t),n.domain=function(t){if(!arguments.length)return r.slice();r=[],e=we();for(var i,o,u=-1,a=t.length;++u<a;)e.has(o=(i=t[u])+"")||e.set(o,r.push(i));return n},n.range=function(e){return arguments.length?(t=w_.call(e),n):t.slice()},n.unknown=function(t){return arguments.length?(i=t,n):i},n.copy=function(){return Qo().domain(r).range(t).unknown(i)},n}function Ko(){function t(){var t=i().length,r=u[1]<u[0],l=u[r-0],h=u[1-r];n=(h-l)/Math.max(1,t-c+2*s),a&&(n=Math.floor(n)),l+=(h-l-n*(t-c))*f,e=n*(1-c),a&&(l=Math.round(l),e=Math.round(e));var p=Ms(t).map(function(t){return l+n*t});return o(r?p.reverse():p)}var n,e,r=Qo().unknown(void 0),i=r.domain,o=r.range,u=[0,1],a=!1,c=0,s=0,f=.5;return delete r.unknown,r.domain=function(n){return arguments.length?(i(n),t()):i()},r.range=function(n){return arguments.length?(u=[+n[0],+n[1]],t()):u.slice()},r.rangeRound=function(n){return u=[+n[0],+n[1]],a=!0,t()},r.bandwidth=function(){return e},r.step=function(){return n},r.round=function(n){return arguments.length?(a=!!n,t()):a},r.padding=function(n){return arguments.length?(c=s=Math.max(0,Math.min(1,n)),t()):c},r.paddingInner=function(n){return arguments.length?(c=Math.max(0,Math.min(1,n)),t()):c},r.paddingOuter=function(n){return arguments.length?(s=Math.max(0,Math.min(1,n)),t()):s},r.align=function(n){return arguments.length?(f=Math.max(0,Math.min(1,n)),t()):f},r.copy=function(){return Ko().domain(i()).range(u).round(a).paddingInner(c).paddingOuter(s).align(f)},t()}function tu(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return tu(n())},t}function nu(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:T_(n)}function eu(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}function ru(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}function iu(t,n,e,r){var i=t[0],o=t[1],u=n[0],a=n[1];return o<i?(i=e(o,i),u=r(a,u)):(i=e(i,o),u=r(u,a)),function(t){return u(i(t))}}function ou(t,n,e,r){var i=Math.min(t.length,n.length)-1,o=new Array(i),u=new Array(i),a=-1;for(t[i]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<i;)o[a]=e(t[a],t[a+1]),u[a]=r(n[a],n[a+1]);return function(n){var e=hs(t,n,1,i)-1;return u[e](o[e](n))}}function uu(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp())}function au(t,n){function e(){return i=Math.min(a.length,c.length)>2?ou:iu,o=u=null,r}function r(n){return(o||(o=i(a,c,f?eu(t):t,s)))(+n)}var i,o,u,a=N_,c=N_,s=cl,f=!1;return r.invert=function(t){return(u||(u=i(c,a,nu,f?ru(n):n)))(+t)},r.domain=function(t){return arguments.length?(a=b_.call(t,k_),e()):a.slice()},r.range=function(t){return arguments.length?(c=w_.call(t),e()):c.slice()},r.rangeRound=function(t){return c=w_.call(t),s=sl,e()},r.clamp=function(t){return arguments.length?(f=!!t,e()):f},r.interpolate=function(t){return arguments.length?(s=t,e()):s},e()}function cu(t){var n=t.domain;return t.ticks=function(t){var e=n();return Ss(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){return S_(n(),t,e)},t.nice=function(e){null==e&&(e=10);var i,o=n(),u=0,a=o.length-1,c=o[u],s=o[a];return s<c&&(i=c,c=s,s=i,i=u,u=a,a=i),(i=r(c,s,e))>0?i=r(c=Math.floor(c/i)*i,s=Math.ceil(s/i)*i,e):i<0&&(i=r(c=Math.ceil(c*i)/i,s=Math.floor(s*i)/i,e)),i>0?(o[u]=Math.floor(c/i)*i,o[a]=Math.ceil(s/i)*i,n(o)):i<0&&(o[u]=Math.ceil(c*i)/i,o[a]=Math.floor(s*i)/i,n(o)),t},t}function su(){var t=au(nu,rl);return t.copy=function(){return uu(t,su())},cu(t)}function fu(){function t(t){return+t}var n=[0,1];return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=b_.call(e,k_),t):n.slice()},t.copy=function(){return fu().domain(n)},cu(t)}function lu(t,n){return(n=Math.log(n/t))?function(e){return Math.log(e/t)/n}:T_(n)}function hu(t,n){return t<0?function(e){return-Math.pow(-n,e)*Math.pow(-t,1-e)}:function(e){return Math.pow(n,e)*Math.pow(t,1-e)}}function pu(t){return isFinite(t)?+("1e"+t):t<0?0:t}function du(t){return 10===t?pu:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}function vu(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}function _u(t){return function(n){return-t(-n)}}function yu(){function n(){return o=vu(i),u=du(i),r()[0]<0&&(o=_u(o),u=_u(u)),e}var e=au(lu,hu).domain([1,10]),r=e.domain,i=10,o=vu(10),u=du(10);return e.base=function(t){return arguments.length?(i=+t,n()):i},e.domain=function(t){return arguments.length?(r(t),n()):r()},e.ticks=function(t){var n,e=r(),a=e[0],c=e[e.length-1];(n=c<a)&&(h=a,a=c,c=h);var s,f,l,h=o(a),p=o(c),d=null==t?10:+t,v=[];if(!(i%1)&&p-h<d){if(h=Math.round(h)-1,p=Math.round(p)+1,a>0){for(;h<p;++h)for(f=1,s=u(h);f<i;++f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else for(;h<p;++h)for(f=i-1,s=u(h);f>=1;--f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else v=Ss(h,p,Math.min(p-h,d)).map(u);return n?v.reverse():v},e.tickFormat=function(n,r){if(null==r&&(r=10===i?".0e":","),"function"!=typeof r&&(r=t.format(r)),n===1/0)return r;null==n&&(n=10);var a=Math.max(1,i*n/e.ticks().length);return function(t){var n=t/u(Math.round(o(t)));return n*i<i-.5&&(n*=i),n<=a?r(t):""}},e.nice=function(){return r(E_(r(),{floor:function(t){return u(Math.floor(o(t)))},ceil:function(t){return u(Math.ceil(o(t)))}}))},e.copy=function(){return uu(e,yu().base(i))},e}function gu(t,n){return t<0?-Math.pow(-t,n):Math.pow(t,n)}function mu(){var t=1,n=au(function(n,e){return(e=gu(e,t)-(n=gu(n,t)))?function(r){return(gu(r,t)-n)/e}:T_(e)},function(n,e){return e=gu(e,t)-(n=gu(n,t)),function(r){return gu(n+e*r,1/t)}}),e=n.domain;return n.exponent=function(n){return arguments.length?(t=+n,e(e())):t},n.copy=function(){return uu(n,mu().exponent(t))},cu(n)}function xu(){function t(){var t=0,o=Math.max(1,r.length);for(i=new Array(o-1);++t<o;)i[t-1]=As(e,t/o);return n}function n(t){if(!isNaN(t=+t))return r[hs(i,t)]}var e=[],r=[],i=[];return n.invertExtent=function(t){var n=r.indexOf(t);return n<0?[NaN,NaN]:[n>0?i[n-1]:e[0],n<i.length?i[n]:e[e.length-1]]},n.domain=function(n){if(!arguments.length)return e.slice();e=[];for(var r,i=0,o=n.length;i<o;++i)null==(r=n[i])||isNaN(r=+r)||e.push(r);return e.sort(ss),t()},n.range=function(n){return arguments.length?(r=w_.call(n),t()):r.slice()},n.quantiles=function(){return i.slice()},n.copy=function(){return xu().domain(e).range(r)},n}function bu(){function t(t){if(t<=t)return u[hs(o,t,0,i)]}function n(){var n=-1;for(o=new Array(i);++n<i;)o[n]=((n+1)*r-(n-i)*e)/(i+1);return t}var e=0,r=1,i=1,o=[.5],u=[0,1];return t.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n()):[e,r]},t.range=function(t){return arguments.length?(i=(u=w_.call(t)).length-1,n()):u.slice()},t.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},t.copy=function(){return bu().domain([e,r]).range(u)},cu(t)}function wu(){function t(t){if(t<=t)return e[hs(n,t,0,r)]}var n=[.5],e=[0,1],r=1;return t.domain=function(i){return arguments.length?(n=w_.call(i),r=Math.min(n.length,e.length-1),t):n.slice()},t.range=function(i){return arguments.length?(e=w_.call(i),r=Math.min(n.length,e.length-1),t):e.slice()},t.invertExtent=function(t){var r=e.indexOf(t);return[n[r-1],n[r]]},t.copy=function(){return wu().domain(n).range(e)},t}function Mu(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(new Date(+e))}while(n(e,o),t(e),e<r);return u},i.filter=function(e){return Mu(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return A_.setTime(+n),C_.setTime(+r),t(A_),t(C_),Math.floor(e(A_,C_))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}function Tu(t){return Mu(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*R_)/L_})}function ku(t){return Mu(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/L_})}function Nu(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Su(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Eu(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function Au(t){function n(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,s=t.length;for(e instanceof Date||(e=new Date(+e));++a<s;)37===t.charCodeAt(a)&&(u.push(t.slice(c,a)),null!=(i=Py[r=t.charAt(++a)])?r=t.charAt(++a):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),u.push(r),c=a+1);return u.push(t.slice(c,a)),u.join("")}}function e(t,n){return function(e){var i=Eu(1900);if(r(i,t,e+="",0)!=e.length)return null;if("p"in i&&(i.H=i.H%12+12*i.p),"W"in i||"U"in i){"w"in i||(i.w="W"in i?1:0);var o="Z"in i?Su(Eu(i.y)).getUTCDay():n(Eu(i.y)).getDay();i.m=0,i.d="W"in i?(i.w+6)%7+7*i.W-(o+5)%7:i.w+7*i.U-(o+6)%7}return"Z"in i?(i.H+=i.Z/100|0,i.M+=i.Z%100,Su(i)):n(i)}}function r(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u<a;){if(r>=c)return-1;if(37===(i=n.charCodeAt(u++))){if(i=n.charAt(u++),!(o=T[i in Py?n.charAt(u++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}var i=t.dateTime,o=t.date,u=t.time,a=t.periods,c=t.days,s=t.shortDays,f=t.months,l=t.shortMonths,h=Pu(a),p=Ru(a),d=Pu(c),v=Ru(c),_=Pu(s),y=Ru(s),g=Pu(f),m=Ru(f),x=Pu(l),b=Ru(l),w={a:function(t){return s[t.getDay()]},A:function(t){return c[t.getDay()]},b:function(t){return l[t.getMonth()]},B:function(t){return f[t.getMonth()]},c:null,d:Wu,e:Wu,H:Zu,I:Gu,j:Ju,L:Qu,m:Ku,M:ta,p:function(t){return a[+(t.getHours()>=12)]},S:na,U:ea,w:ra,W:ia,x:null,X:null,y:oa,Y:ua,Z:aa,"%":wa},M={a:function(t){return s[t.getUTCDay()]},A:function(t){return c[t.getUTCDay()]},b:function(t){return l[t.getUTCMonth()]},B:function(t){return f[t.getUTCMonth()]},c:null,d:ca,e:ca,H:sa,I:fa,j:la,L:ha,m:pa,M:da,p:function(t){return a[+(t.getUTCHours()>=12)]},S:va,U:_a,w:ya,W:ga,x:null,X:null,y:ma,Y:xa,Z:ba,"%":wa},T={a:function(t,n,e){var r=_.exec(n.slice(e));return r?(t.w=y[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=v[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=x.exec(n.slice(e));return r?(t.m=b[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=m[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,n,e){return r(t,i,n,e)},d:Yu,e:Yu,H:ju,I:ju,j:Bu,L:$u,m:Iu,M:Hu,p:function(t,n,e){var r=h.exec(n.slice(e));return r?(t.p=p[r[0].toLowerCase()],e+r[0].length):-1},S:Xu,U:qu,w:Lu,W:Uu,x:function(t,n,e){return r(t,o,n,e)},X:function(t,n,e){return r(t,u,n,e)},y:Ou,Y:Du,Z:Fu,"%":Vu};return w.x=n(o,w),w.X=n(u,w),w.c=n(i,w),M.x=n(o,M),M.X=n(u,M),M.c=n(i,M),{format:function(t){var e=n(t+="",w);return e.toString=function(){return t},e},parse:function(t){var n=e(t+="",Nu);return n.toString=function(){return t},n},utcFormat:function(t){var e=n(t+="",M);return e.toString=function(){return t},e},utcParse:function(t){var n=e(t,Su);return n.toString=function(){return t},n}}}function Cu(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function zu(t){return t.replace(qy,"\\$&")}function Pu(t){return new RegExp("^(?:"+t.map(zu).join("|")+")","i")}function Ru(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function Lu(t,n,e){var r=Ry.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function qu(t,n,e){var r=Ry.exec(n.slice(e));return r?(t.U=+r[0],e+r[0].length):-1}function Uu(t,n,e){var r=Ry.exec(n.slice(e));return r?(t.W=+r[0],e+r[0].length):-1}function Du(t,n,e){var r=Ry.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function Ou(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function Fu(t,n,e){var r=/^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Iu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function Yu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function Bu(t,n,e){var r=Ry.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function ju(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Hu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Xu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function $u(t,n,e){var r=Ry.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Vu(t,n,e){var r=Ly.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Wu(t,n){return Cu(t.getDate(),n,2)}function Zu(t,n){return Cu(t.getHours(),n,2)}function Gu(t,n){return Cu(t.getHours()%12||12,n,2)}function Ju(t,n){return Cu(1+Y_.count(oy(t),t),n,3)}function Qu(t,n){return Cu(t.getMilliseconds(),n,3)}function Ku(t,n){return Cu(t.getMonth()+1,n,2)}function ta(t,n){return Cu(t.getMinutes(),n,2)}function na(t,n){return Cu(t.getSeconds(),n,2)}function ea(t,n){return Cu(j_.count(oy(t),t),n,2)}function ra(t){return t.getDay()}function ia(t,n){return Cu(H_.count(oy(t),t),n,2)}function oa(t,n){return Cu(t.getFullYear()%100,n,2)}function ua(t,n){return Cu(t.getFullYear()%1e4,n,4)}function aa(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Cu(n/60|0,"0",2)+Cu(n%60,"0",2)}function ca(t,n){return Cu(t.getUTCDate(),n,2)}function sa(t,n){return Cu(t.getUTCHours(),n,2)}function fa(t,n){return Cu(t.getUTCHours()%12||12,n,2)}function la(t,n){return Cu(1+ly.count(Ay(t),t),n,3)}function ha(t,n){return Cu(t.getUTCMilliseconds(),n,3)}function pa(t,n){return Cu(t.getUTCMonth()+1,n,2)}function da(t,n){return Cu(t.getUTCMinutes(),n,2)}function va(t,n){return Cu(t.getUTCSeconds(),n,2)}function _a(t,n){return Cu(py.count(Ay(t),t),n,2)}function ya(t){return t.getUTCDay()}function ga(t,n){return Cu(dy.count(Ay(t),t),n,2)}function ma(t,n){return Cu(t.getUTCFullYear()%100,n,2)}function xa(t,n){return Cu(t.getUTCFullYear()%1e4,n,4)}function ba(){return"+0000"}function wa(){return"%"}function Ma(n){return Cy=Au(n),t.timeFormat=Cy.format,t.timeParse=Cy.parse,t.utcFormat=Cy.utcFormat,t.utcParse=Cy.utcParse,Cy}function Ta(t){return new Date(t)}function ka(t){return t instanceof Date?+t:+new Date(+t)}function Na(t,n,e,r,o,u,a,c,s){function f(i){return(a(i)<i?v:u(i)<i?_:o(i)<i?y:r(i)<i?g:n(i)<i?e(i)<i?m:x:t(i)<i?b:w)(i)}function l(n,e,r,o){if(null==n&&(n=10),"number"==typeof n){var u=Math.abs(r-e)/n,a=fs(function(t){return t[2]}).right(M,u);a===M.length?(o=i(e/Hy,r/Hy,n),n=t):a?(o=(a=M[u/M[a-1][2]<M[a][2]/u?a-1:a])[1],n=a[0]):(o=i(e,r,n),n=c)}return null==o?n:n.every(o)}var h=au(nu,rl),p=h.invert,d=h.domain,v=s(".%L"),_=s(":%S"),y=s("%I:%M"),g=s("%I %p"),m=s("%a %d"),x=s("%b %d"),b=s("%B"),w=s("%Y"),M=[[a,1,Oy],[a,5,5*Oy],[a,15,15*Oy],[a,30,30*Oy],[u,1,Fy],[u,5,5*Fy],[u,15,15*Fy],[u,30,30*Fy],[o,1,Iy],[o,3,3*Iy],[o,6,6*Iy],[o,12,12*Iy],[r,1,Yy],[r,2,2*Yy],[e,1,By],[n,1,jy],[n,3,3*jy],[t,1,Hy]];return h.invert=function(t){return new Date(p(t))},h.domain=function(t){return arguments.length?d(b_.call(t,ka)):d().map(Ta)},h.ticks=function(t,n){var e,r=d(),i=r[0],o=r[r.length-1],u=o<i;return u&&(e=i,i=o,o=e),e=l(t,i,o,n),e=e?e.range(i,o+1):[],u?e.reverse():e},h.tickFormat=function(t,n){return null==n?f:s(n)},h.nice=function(t,n){var e=d();return(t=l(t,e[0],e[e.length-1],n))?d(E_(e,t)):h},h.copy=function(){return uu(h,Na(t,n,e,r,o,u,a,c,s))},h}function Sa(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}function Ea(t){function n(n){var o=(n-e)/(r-e);return t(i?Math.max(0,Math.min(1,o)):o)}var e=0,r=1,i=!1;return n.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n):[e,r]},n.clamp=function(t){return arguments.length?(i=!!t,n):i},n.interpolator=function(e){return arguments.length?(t=e,n):t},n.copy=function(){return Ea(t).domain([e,r]).clamp(i)},cu(n)}function Aa(t){return t>1?0:t<-1?pg:Math.acos(t)}function Ca(t){return t>=1?dg:t<=-1?-dg:Math.asin(t)}function za(t){return t.innerRadius}function Pa(t){return t.outerRadius}function Ra(t){return t.startAngle}function La(t){return t.endAngle}function qa(t){return t&&t.padAngle}function Ua(t,n,e,r,i,o,u,a){var c=e-t,s=r-n,f=u-i,l=a-o,h=(f*(n-o)-l*(t-i))/(l*c-f*s);return[t+h*c,n+h*s]}function Da(t,n,e,r,i,o,u){var a=t-e,c=n-r,s=(u?o:-o)/lg(a*a+c*c),f=s*c,l=-s*a,h=t+f,p=n+l,d=e+f,v=r+l,_=(h+d)/2,y=(p+v)/2,g=d-h,m=v-p,x=g*g+m*m,b=i-o,w=h*v-d*p,M=(m<0?-1:1)*lg(cg(0,b*b*x-w*w)),T=(w*m-g*M)/x,k=(-w*g-m*M)/x,N=(w*m+g*M)/x,S=(-w*g+m*M)/x,E=T-_,A=k-y,C=N-_,z=S-y;return E*E+A*A>C*C+z*z&&(T=N,k=S),{cx:T,cy:k,x01:-f,y01:-l,x11:T*(i/b-1),y11:k*(i/b-1)}}function Oa(t){this._context=t}function Fa(t){return t[0]}function Ia(t){return t[1]}function Ya(t){this._curve=t}function Ba(t){function n(n){return new Ya(t(n))}return n._curve=t,n}function ja(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Ba(t)):n()._curve},t}function Ha(t){return t.source}function Xa(t){return t.target}function $a(t){function n(){var n,a=kg.call(arguments),c=e.apply(this,a),s=r.apply(this,a);if(u||(u=n=ve()),t(u,+i.apply(this,(a[0]=c,a)),+o.apply(this,a),+i.apply(this,(a[0]=s,a)),+o.apply(this,a)),n)return u=null,n+""||null}var e=Ha,r=Xa,i=Fa,o=Ia,u=null;return n.source=function(t){return arguments.length?(e=t,n):e},n.target=function(t){return arguments.length?(r=t,n):r},n.x=function(t){return arguments.length?(i="function"==typeof t?t:ig(+t),n):i},n.y=function(t){return arguments.length?(o="function"==typeof t?t:ig(+t),n):o},n.context=function(t){return arguments.length?(u=null==t?null:t,n):u},n}function Va(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function Wa(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function Za(t,n,e,r,i){var o=Tg(n,e),u=Tg(n,e=(e+i)/2),a=Tg(r,e),c=Tg(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(u[0],u[1],a[0],a[1],c[0],c[1])}function Ga(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Ja(t){this._context=t}function Qa(t){this._context=t}function Ka(t){this._context=t}function tc(t,n){this._basis=new Ja(t),this._beta=n}function nc(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function ec(t,n){this._context=t,this._k=(1-n)/6}function rc(t,n){this._context=t,this._k=(1-n)/6}function ic(t,n){this._context=t,this._k=(1-n)/6}function oc(t,n,e){var r=t._x1,i=t._y1,o=t._x2,u=t._y2;if(t._l01_a>hg){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>hg){var s=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*s+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*s+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function uc(t,n){this._context=t,this._alpha=n}function ac(t,n){this._context=t,this._alpha=n}function cc(t,n){this._context=t,this._alpha=n}function sc(t){this._context=t}function fc(t){return t<0?-1:1}function lc(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(fc(o)+fc(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function hc(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function pc(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function dc(t){this._context=t}function vc(t){this._context=new _c(t)}function _c(t){this._context=t}function yc(t){this._context=t}function gc(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(i[0]=0,o[0]=2,u[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,u[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,u[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,u[n]-=e*u[n-1];for(i[r-1]=u[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(u[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function mc(t,n){this._context=t,this._t=n}function xc(t,n){return t[n]}function bc(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function wc(t){return t[0]}function Mc(t){return t[1]}function Tc(){this._=null}function kc(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function Nc(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Sc(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function Ec(t){for(;t.L;)t=t.L;return t}function Ac(t,n,e,r){var i=[null,null],o=um.push(i)-1;return i.left=t,i.right=n,e&&zc(i,t,n,e),r&&zc(i,n,t,r),im[t.index].halfedges.push(o),im[n.index].halfedges.push(o),i}function Cc(t,n,e){var r=[n,e];return r.left=t,r}function zc(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function Pc(t,n,e,r,i){var o,u=t[0],a=t[1],c=u[0],s=u[1],f=0,l=1,h=a[0]-c,p=a[1]-s;if(o=n-c,h||!(o>0)){if(o/=h,h<0){if(o<f)return;o<l&&(l=o)}else if(h>0){if(o>l)return;o>f&&(f=o)}if(o=r-c,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>f&&(f=o)}else if(h>0){if(o<f)return;o<l&&(l=o)}if(o=e-s,p||!(o>0)){if(o/=p,p<0){if(o<f)return;o<l&&(l=o)}else if(p>0){if(o>l)return;o>f&&(f=o)}if(o=i-s,p||!(o<0)){if(o/=p,p<0){if(o>l)return;o>f&&(f=o)}else if(p>0){if(o<f)return;o<l&&(l=o)}return!(f>0||l<1)||(f>0&&(t[0]=[c+f*h,s+f*p]),l<1&&(t[1]=[c+l*h,s+l*p]),!0)}}}}}function Rc(t,n,e,r,i){var o=t[1];if(o)return!0;var u,a,c=t[0],s=t.left,f=t.right,l=s[0],h=s[1],p=f[0],d=f[1],v=(l+p)/2,_=(h+d)/2;if(d===h){if(v<n||v>=r)return;if(l>p){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=(l-p)/(d-h),a=_-u*v,u<-1||u>1)if(l>p){if(c){if(c[1]>=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]<e)return}else c=[(i-a)/u,i];o=[(e-a)/u,e]}else if(h<d){if(c){if(c[0]>=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]<n)return}else c=[r,u*r+a];o=[n,u*n+a]}return t[0]=c,t[1]=o,!0}function Lc(t,n,e,r){for(var i,o=um.length;o--;)Rc(i=um[o],t,n,e,r)&&Pc(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>sm||Math.abs(i[0][1]-i[1][1])>sm)||delete um[o]}function qc(t){return im[t.index]={site:t,halfedges:[]}}function Uc(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function Dc(t,n){return n[+(n.left!==t.site)]}function Oc(t,n){return n[+(n.left===t.site)]}function Fc(){for(var t,n,e,r,i=0,o=im.length;i<o;++i)if((t=im[i])&&(r=(n=t.halfedges).length)){var u=new Array(r),a=new Array(r);for(e=0;e<r;++e)u[e]=e,a[e]=Uc(t,um[n[e]]);for(u.sort(function(t,n){return a[n]-a[t]}),e=0;e<r;++e)a[e]=n[u[e]];for(e=0;e<r;++e)n[e]=a[e]}}function Ic(t,n,e,r){var i,o,u,a,c,s,f,l,h,p,d,v,_=im.length,y=!0;for(i=0;i<_;++i)if(o=im[i]){for(u=o.site,a=(c=o.halfedges).length;a--;)um[c[a]]||c.splice(a,1);for(a=0,s=c.length;a<s;)d=(p=Oc(o,um[c[a]]))[0],v=p[1],l=(f=Dc(o,um[c[++a%s]]))[0],h=f[1],(Math.abs(d-l)>sm||Math.abs(v-h)>sm)&&(c.splice(a,0,um.push(Cc(u,p,Math.abs(d-t)<sm&&r-v>sm?[t,Math.abs(l-t)<sm?h:r]:Math.abs(v-r)<sm&&e-d>sm?[Math.abs(h-r)<sm?l:e,r]:Math.abs(d-e)<sm&&v-n>sm?[e,Math.abs(l-e)<sm?h:n]:Math.abs(v-n)<sm&&d-t>sm?[Math.abs(h-n)<sm?l:t,n]:null))-1),++s);s&&(y=!1)}if(y){var g,m,x,b=1/0;for(i=0,y=null;i<_;++i)(o=im[i])&&(x=(g=(u=o.site)[0]-t)*g+(m=u[1]-n)*m)<b&&(b=x,y=o);if(y){var w=[t,n],M=[t,r],T=[e,r],k=[e,n];y.halfedges.push(um.push(Cc(u=y.site,w,M))-1,um.push(Cc(u,M,T))-1,um.push(Cc(u,T,k))-1,um.push(Cc(u,k,w))-1)}}for(i=0;i<_;++i)(o=im[i])&&(o.halfedges.length||delete im[i])}function Yc(){kc(this),this.x=this.y=this.arc=this.site=this.cy=null}function Bc(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var u=i[0],a=i[1],c=r[0]-u,s=r[1]-a,f=o[0]-u,l=o[1]-a,h=2*(c*l-s*f);if(!(h>=-fm)){var p=c*c+s*s,d=f*f+l*l,v=(l*p-s*d)/h,_=(c*d-f*p)/h,y=am.pop()||new Yc;y.arc=t,y.site=i,y.x=v+u,y.y=(y.cy=_+a)+Math.sqrt(v*v+_*_),t.circle=y;for(var g=null,m=om._;m;)if(y.y<m.y||y.y===m.y&&y.x<=m.x){if(!m.L){g=m.P;break}m=m.L}else{if(!m.R){g=m;break}m=m.R}om.insert(g,y),g||(em=y)}}}}function jc(t){var n=t.circle;n&&(n.P||(em=n.N),om.remove(n),am.push(n),kc(n),t.circle=null)}function Hc(){kc(this),this.edge=this.site=this.circle=null}function Xc(t){var n=cm.pop()||new Hc;return n.site=t,n}function $c(t){jc(t),rm.remove(t),cm.push(t),kc(t)}function Vc(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,u=t.N,a=[t];$c(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<sm&&Math.abs(r-c.circle.cy)<sm;)o=c.P,a.unshift(c),$c(c),c=o;a.unshift(c),jc(c);for(var s=u;s.circle&&Math.abs(e-s.circle.x)<sm&&Math.abs(r-s.circle.cy)<sm;)u=s.N,a.push(s),$c(s),s=u;a.push(s),jc(s);var f,l=a.length;for(f=1;f<l;++f)s=a[f],c=a[f-1],zc(s.edge,c.site,s.site,i);c=a[0],(s=a[l-1]).edge=Ac(c.site,s.site,null,i),Bc(c),Bc(s)}function Wc(t){for(var n,e,r,i,o=t[0],u=t[1],a=rm._;a;)if((r=Zc(a,u)-o)>sm)a=a.L;else{if(!((i=o-Gc(a,u))>sm)){r>-sm?(n=a.P,e=a):i>-sm?(n=a,e=a.N):n=e=a;break}if(!a.R){n=a;break}a=a.R}qc(t);var c=Xc(t);if(rm.insert(n,c),n||e){if(n===e)return jc(n),e=Xc(n.site),rm.insert(c,e),c.edge=e.edge=Ac(n.site,c.site),Bc(n),void Bc(e);if(e){jc(n),jc(e);var s=n.site,f=s[0],l=s[1],h=t[0]-f,p=t[1]-l,d=e.site,v=d[0]-f,_=d[1]-l,y=2*(h*_-p*v),g=h*h+p*p,m=v*v+_*_,x=[(_*g-p*m)/y+f,(h*m-v*g)/y+l];zc(e.edge,s,d,x),c.edge=Ac(s,t,null,x),e.edge=Ac(t,d,null,x),Bc(n),Bc(e)}else c.edge=Ac(n.site,c.site)}}function Zc(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var u=t.P;if(!u)return-1/0;var a=(e=u.site)[0],c=e[1],s=c-n;if(!s)return a;var f=a-r,l=1/o-1/s,h=f/s;return l?(-h+Math.sqrt(h*h-2*l*(f*f/(-2*s)-c+s/2+i-o/2)))/l+r:(r+a)/2}function Gc(t,n){var e=t.N;if(e)return Zc(e,n);var r=t.site;return r[1]===n?r[0]:1/0}function Jc(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function Qc(t,n){return n[1]-t[1]||n[0]-t[0]}function Kc(t,n){var e,r,i,o=t.sort(Qc).pop();for(um=[],im=new Array(t.length),rm=new Tc,om=new Tc;;)if(i=em,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(Wc(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;Vc(i.arc)}if(Fc(),n){var u=+n[0][0],a=+n[0][1],c=+n[1][0],s=+n[1][1];Lc(u,a,c,s),Ic(u,a,c,s)}this.edges=um,this.cells=im,rm=om=um=im=null}function ts(t,n,e){this.target=t,this.type=n,this.transform=e}function ns(t,n,e){this.k=t,this.x=n,this.y=e}function es(t){return t.__zoom||hm}function rs(){t.event.stopImmediatePropagation()}function is(){return!t.event.button}function os(){var t,n,e=this;return e instanceof SVGElement?(t=(e=e.ownerSVGElement||e).width.baseVal.value,n=e.height.baseVal.value):(t=e.clientWidth,n=e.clientHeight),[[0,0],[t,n]]}function us(){return this.__zoom||hm}function as(){return-t.event.deltaY*(t.event.deltaMode?120:1)/500}function cs(){return"ontouchstart"in this}var ss=function(t,n){return t<n?-1:t>n?1:t>=n?0:NaN},fs=function(t){return 1===t.length&&(t=n(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}},ls=fs(ss),hs=ls.right,ps=ls.left,ds=function(t){return null===t?NaN:+t},vs=function(t,n){var e,r,i=t.length,o=0,u=-1,a=0,c=0;if(null==n)for(;++u<i;)isNaN(e=ds(t[u]))||(c+=(r=e-a)*(e-(a+=r/++o)));else for(;++u<i;)isNaN(e=ds(n(t[u],u,t)))||(c+=(r=e-a)*(e-(a+=r/++o)));if(o>1)return c/(o-1)},_s=function(t,n){var e=vs(t,n);return e?Math.sqrt(e):e},ys=function(t,n){var e,r,i,o=t.length,u=-1;if(null==n){for(;++u<o;)if(null!=(e=t[u])&&e>=e)for(r=i=e;++u<o;)null!=(e=t[u])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++u<o;)if(null!=(e=n(t[u],u,t))&&e>=e)for(r=i=e;++u<o;)null!=(e=n(t[u],u,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]},gs=Array.prototype,ms=gs.slice,xs=gs.map,bs=function(t){return function(){return t}},ws=function(t){return t},Ms=function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o},Ts=Math.sqrt(50),ks=Math.sqrt(10),Ns=Math.sqrt(2),Ss=function(t,n,e){var i,o,u,a=n<t,c=-1;if(a&&(i=t,t=n,n=i),0===(u=r(t,n,e))||!isFinite(u))return[];if(u>0)for(t=Math.ceil(t/u),n=Math.floor(n/u),o=new Array(i=Math.ceil(n-t+1));++c<i;)o[c]=(t+c)*u;else for(t=Math.floor(t*u),n=Math.ceil(n*u),o=new Array(i=Math.ceil(t-n+1));++c<i;)o[c]=(t-c)/u;return a&&o.reverse(),o},Es=function(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1},As=function(t,n,e){if(null==e&&(e=ds),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t);return u+(+e(t[o+1],o+1,t)-u)*(i-o)}},Cs=function(t){for(var n,e,r,i=t.length,o=-1,u=0;++o<i;)u+=t[o].length;for(e=new Array(u);--i>=0;)for(n=(r=t[i]).length;--n>=0;)e[--u]=r[n];return e},zs=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r},Ps=function(t){if(!(i=t.length))return[];for(var n=-1,e=zs(t,o),r=new Array(e);++n<e;)for(var i,u=-1,a=r[n]=new Array(i);++u<i;)a[u]=t[u][n];return r},Rs=Array.prototype.slice,Ls=function(t){return t},qs=1,Us=2,Ds=3,Os=4,Fs=1e-6,Is={value:function(){}};p.prototype=h.prototype={constructor:p,on:function(t,n){var e,r=this._,i=d(t+"",r),o=-1,u=i.length;{if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<u;)if(e=(t=i[o]).type)r[e]=_(r[e],t.name,n);else if(null==n)for(e in r)r[e]=_(r[e],t.name,null);return this}for(;++o<u;)if((e=(t=i[o]).type)&&(e=v(r[e],t.name)))return e}},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new p(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var Ys="http://www.w3.org/1999/xhtml",Bs={svg:"http://www.w3.org/2000/svg",xhtml:Ys,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},js=function(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Bs.hasOwnProperty(n)?{space:Bs[n],local:t}:t},Hs=function(t){var n=js(t);return(n.local?g:y)(n)},Xs=0;x.prototype=m.prototype={constructor:x,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};var $s=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var Vs=document.documentElement;if(!Vs.matches){var Ws=Vs.webkitMatchesSelector||Vs.msMatchesSelector||Vs.mozMatchesSelector||Vs.oMatchesSelector;$s=function(t){return function(){return Ws.call(this,t)}}}}var Zs=$s,Gs={};t.event=null,"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(Gs={mouseenter:"mouseover",mouseleave:"mouseout"}));var Js=function(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e},Qs=function(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,r=r.matrixTransform(t.getScreenCTM().inverse()),[r.x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]},Ks=function(t){var n=Js();return n.changedTouches&&(n=n.changedTouches[0]),Qs(t,n)},tf=function(t){return null==t?S:function(){return this.querySelector(t)}},nf=function(t){return null==t?E:function(){return this.querySelectorAll(t)}},ef=function(t){return new Array(t.length)};A.prototype={constructor:A,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var rf=function(t){return function(){return t}},of="$",uf=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};W.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var af=[null];pt.prototype=dt.prototype={constructor:pt,select:function(t){"function"!=typeof t&&(t=tf(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u,a=n[i],c=a.length,s=r[i]=new Array(c),f=0;f<c;++f)(o=a[f])&&(u=t.call(o,o.__data__,f,a))&&("__data__"in o&&(u.__data__=o.__data__),s[f]=u);return new pt(r,this._parents)},selectAll:function(t){"function"!=typeof t&&(t=nf(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var u,a=n[o],c=a.length,s=0;s<c;++s)(u=a[s])&&(r.push(t.call(u,u.__data__,s,a)),i.push(u));return new pt(r,i)},filter:function(t){"function"!=typeof t&&(t=Zs(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new pt(r,this._parents)},data:function(t,n){if(!t)return p=new Array(this.size()),s=-1,this.each(function(t){p[++s]=t}),p;var e=n?z:C,r=this._parents,i=this._groups;"function"!=typeof t&&(t=rf(t));for(var o=i.length,u=new Array(o),a=new Array(o),c=new Array(o),s=0;s<o;++s){var f=r[s],l=i[s],h=l.length,p=t.call(f,f&&f.__data__,s,r),d=p.length,v=a[s]=new Array(d),_=u[s]=new Array(d);e(f,l,v,_,c[s]=new Array(h),p,n);for(var y,g,m=0,x=0;m<d;++m)if(y=v[m]){for(m>=x&&(x=m+1);!(g=_[x])&&++x<d;);y._next=g||null}}return u=new pt(u,r),u._enter=a,u._exit=c,u},enter:function(){return new pt(this._enter||this._groups.map(ef),this._parents)},exit:function(){return new pt(this._exit||this._groups.map(ef),this._parents)},merge:function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new pt(u,this._parents)},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,u=i[o];--o>=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){t||(t=P);for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i){for(var o,u=n[i],a=u.length,c=r[i]=new Array(a),s=0;s<a;++s)(o=u[s])&&(c[s]=o);c.sort(function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e})}return new pt(r,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var u=r[i];if(u)return u}return null},size:function(){var t=0;return this.each(function(){++t}),t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],u=0,a=o.length;u<a;++u)(i=o[u])&&t.call(i,i.__data__,u,o);return this},attr:function(t,n){var e=js(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?L:R:"function"==typeof n?e.local?O:D:e.local?U:q)(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?F:"function"==typeof n?Y:I)(t,n,null==e?"":e)):B(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?j:"function"==typeof n?X:H)(t,n)):this.node()[t]},classed:function(t,n){var e=$(t+"");if(arguments.length<2){for(var r=V(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?K:n?J:Q)(e,n))},text:function(t){return arguments.length?this.each(null==t?tt:("function"==typeof t?et:nt)(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?rt:("function"==typeof t?ot:it)(t)):this.node().innerHTML},raise:function(){return this.each(ut)},lower:function(){return this.each(at)},append:function(t){var n="function"==typeof t?t:Hs(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},insert:function(t,n){var e="function"==typeof t?t:Hs(t),r=null==n?ct:"function"==typeof n?n:tf(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},remove:function(){return this.each(st)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=M(t+""),u=o.length;{if(!(arguments.length<2)){for(a=n?k:T,null==e&&(e=!1),r=0;r<u;++r)this.each(a(o[r],n,e));return this}var a=this.node().__on;if(a)for(var c,s=0,f=a.length;s<f;++s)for(r=0,c=a[s];r<u;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value}},dispatch:function(t,n){return this.each(("function"==typeof n?ht:lt)(t,n))}};var cf=function(t){return"string"==typeof t?new pt([[document.querySelector(t)]],[document.documentElement]):new pt([[t]],af)},sf=function(t,n,e){arguments.length<3&&(e=n,n=Js().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Qs(t,r);return null},ff=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},lf=function(t){var n=t.document.documentElement,e=cf(t).on("dragstart.drag",ff,!0);"onselectstart"in n?e.on("selectstart.drag",ff,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")},hf=function(t){return function(){return t}};yt.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var pf=function(t,n,e){t.prototype=n.prototype=e,e.constructor=t},df="\\s*([+-]?\\d+)\\s*",vf="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",_f="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",yf=/^#([0-9a-f]{3})$/,gf=/^#([0-9a-f]{6})$/,mf=new RegExp("^rgb\\("+[df,df,df]+"\\)$"),xf=new RegExp("^rgb\\("+[_f,_f,_f]+"\\)$"),bf=new RegExp("^rgba\\("+[df,df,df,vf]+"\\)$"),wf=new RegExp("^rgba\\("+[_f,_f,_f,vf]+"\\)$"),Mf=new RegExp("^hsl\\("+[vf,_f,_f]+"\\)$"),Tf=new RegExp("^hsla\\("+[vf,_f,_f,vf]+"\\)$"),kf={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};pf(Mt,Tt,{displayable:function(){return this.rgb().displayable()},toString:function(){return this.rgb()+""}}),pf(At,Et,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new At(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new At(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),pf(Rt,Pt,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new At(Lt(t>=240?t-240:t+120,i,r),Lt(t,i,r),Lt(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Nf=Math.PI/180,Sf=180/Math.PI,Ef=.95047,Af=1,Cf=1.08883,zf=4/29,Pf=6/29,Rf=3*Pf*Pf,Lf=Pf*Pf*Pf;pf(Dt,Ut,wt(Mt,{brighter:function(t){return new Dt(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Dt(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=Af*Ft(t),n=Ef*Ft(n),e=Cf*Ft(e),new At(It(3.2404542*n-1.5371385*t-.4985314*e),It(-.969266*n+1.8760108*t+.041556*e),It(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),pf(Ht,jt,wt(Mt,{brighter:function(t){return new Ht(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Ht(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return qt(this).rgb()}}));var qf=-.14861,Uf=1.78277,Df=-.29227,Of=-.90649,Ff=1.97294,If=Ff*Of,Yf=Ff*Uf,Bf=Uf*Df-Of*qf;pf(Vt,$t,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Vt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Vt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Nf,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new At(255*(n+e*(qf*r+Uf*i)),255*(n+e*(Df*r+Of*i)),255*(n+e*(Ff*r)),this.opacity)}}));var jf,Hf,Xf,$f,Vf,Wf,Zf=function(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=r<n-1?t[r+2]:2*o-i;return Wt((e-r/n)*n,u,i,o,a)}},Gf=function(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],u=t[(r+1)%n],a=t[(r+2)%n];return Wt((e-r/n)*n,i,o,u,a)}},Jf=function(t){return function(){return t}},Qf=function t(n){function e(t,n){var e=r((t=Et(t)).r,(n=Et(n)).r),i=r(t.g,n.g),o=r(t.b,n.b),u=Kt(t.opacity,n.opacity);return function(n){return t.r=e(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}var r=Qt(n);return e.gamma=t,e}(1),Kf=tn(Zf),tl=tn(Gf),nl=function(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(r),u=new Array(r);for(e=0;e<i;++e)o[e]=cl(t[e],n[e]);for(;e<r;++e)u[e]=n[e];return function(t){for(e=0;e<i;++e)u[e]=o[e](t);return u}},el=function(t,n){var e=new Date;return t=+t,n-=t,function(r){return e.setTime(t+n*r),e}},rl=function(t,n){return t=+t,n-=t,function(e){return t+n*e}},il=function(t,n){var e,r={},i={};null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={});for(e in n)e in t?r[e]=cl(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}},ol=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ul=new RegExp(ol.source,"g"),al=function(t,n){var e,r,i,o=ol.lastIndex=ul.lastIndex=0,u=-1,a=[],c=[];for(t+="",n+="";(e=ol.exec(t))&&(r=ul.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:rl(e,r)})),o=ul.lastIndex;return o<n.length&&(i=n.slice(o),a[u]?a[u]+=i:a[++u]=i),a.length<2?c[0]?en(c[0].x):nn(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)a[(e=c[r]).i]=e.x(t);return a.join("")})},cl=function(t,n){var e,r=typeof n;return null==n||"boolean"===r?Jf(n):("number"===r?rl:"string"===r?(e=Tt(n))?(n=e,Qf):al:n instanceof Tt?Qf:n instanceof Date?el:Array.isArray(n)?nl:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?il:rl)(t,n)},sl=function(t,n){return t=+t,n-=t,function(e){return Math.round(t+n*e)}},fl=180/Math.PI,ll={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1},hl=function(t,n,e,r,i,o){var u,a,c;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,c/=a),t*r<n*e&&(t=-t,n=-n,c=-c,u=-u),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*fl,skewX:Math.atan(c)*fl,scaleX:u,scaleY:a}},pl=rn(function(t){return"none"===t?ll:(jf||(jf=document.createElement("DIV"),Hf=document.documentElement,Xf=document.defaultView),jf.style.transform=t,t=Xf.getComputedStyle(Hf.appendChild(jf),null).getPropertyValue("transform"),Hf.removeChild(jf),t=t.slice(7,-1).split(","),hl(+t[0],+t[1],+t[2],+t[3],+t[4],+t[5]))},"px, ","px)","deg)"),dl=rn(function(t){return null==t?ll:($f||($f=document.createElementNS("http://www.w3.org/2000/svg","g")),$f.setAttribute("transform",t),(t=$f.transform.baseVal.consolidate())?(t=t.matrix,hl(t.a,t.b,t.c,t.d,t.e,t.f)):ll)},", ",")",")"),vl=Math.SQRT2,_l=function(t,n){var e,r,i=t[0],o=t[1],u=t[2],a=n[0],c=n[1],s=n[2],f=a-i,l=c-o,h=f*f+l*l;if(h<1e-12)r=Math.log(s/u)/vl,e=function(t){return[i+t*f,o+t*l,u*Math.exp(vl*t*r)]};else{var p=Math.sqrt(h),d=(s*s-u*u+4*h)/(2*u*2*p),v=(s*s-u*u-4*h)/(2*s*2*p),_=Math.log(Math.sqrt(d*d+1)-d),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-_)/vl,e=function(t){var n=t*r,e=on(_),a=u/(2*p)*(e*an(vl*n+_)-un(_));return[i+a*f,o+a*l,u*e/on(vl*n+_)]}}return e.duration=1e3*r,e},yl=cn(Jt),gl=cn(Kt),ml=sn(Jt),xl=sn(Kt),bl=fn(Jt),wl=fn(Kt),Ml=0,Tl=0,kl=0,Nl=1e3,Sl=0,El=0,Al=0,Cl="object"==typeof performance&&performance.now?performance:Date,zl="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};pn.prototype=dn.prototype={constructor:pn,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?ln():+e)+(null==n?0:+n),this._next||Wf===this||(Wf?Wf._next=this:Vf=this,Wf=this),this._call=t,this._time=e,mn()},stop:function(){this._call&&(this._call=null,this._time=1/0,mn())}};var Pl=function(t,n,e){var r=new pn;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},Rl=h("start","end","interrupt"),Ll=[],ql=0,Ul=1,Dl=2,Ol=3,Fl=4,Il=5,Yl=6,Bl=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};Mn(t,e,{name:n,index:r,group:i,on:Rl,tween:Ll,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:ql})},jl=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){n=null==n?null:n+"";for(i in o)(e=o[i]).name===n?(r=e.state>Dl&&e.state<Il,e.state=Yl,e.timer.stop(),r&&e.on.call("interrupt",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}},Hl=function(t,n){var e;return("number"==typeof n?rl:n instanceof Tt?Qf:(e=Tt(n))?(n=e,Qf):al)(t,n)},Xl=dt.prototype.constructor,$l=0,Vl=dt.prototype;Gn.prototype=Jn.prototype={constructor:Gn,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=tf(t));for(var r=this._groups,i=r.length,o=new Array(i),u=0;u<i;++u)for(var a,c,s=r[u],f=s.length,l=o[u]=new Array(f),h=0;h<f;++h)(a=s[h])&&(c=t.call(a,a.__data__,h,s))&&("__data__"in a&&(c.__data__=a.__data__),l[h]=c,Bl(l[h],n,e,h,l,wn(a,e)));return new Gn(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=nf(t));for(var r=this._groups,i=r.length,o=[],u=[],a=0;a<i;++a)for(var c,s=r[a],f=s.length,l=0;l<f;++l)if(c=s[l]){for(var h,p=t.call(c,c.__data__,l,s),d=wn(c,e),v=0,_=p.length;v<_;++v)(h=p[v])&&Bl(h,n,e,v,p,d);o.push(p),u.push(c)}return new Gn(o,u,n,e)},filter:function(t){"function"!=typeof t&&(t=Zs(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new Gn(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new Gn(u,this._parents,this._name,this._id)},selection:function(){return new Xl(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Qn(),r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)if(u=a[s]){var f=wn(u,n);Bl(u,t,e,s,a,{time:f.time+f.delay+f.duration,delay:0,duration:f.duration,ease:f.ease})}return new Gn(r,this._parents,t,e)},call:Vl.call,nodes:Vl.nodes,node:Vl.node,size:Vl.size,empty:Vl.empty,each:Vl.each,on:function(t,n){var e=this._id;return arguments.length<2?wn(this.node(),e).on.on(t):this.each(Yn(e,t,n))},attr:function(t,n){var e=js(t),r="transform"===e?dl:Hl;return this.attrTween(t,"function"==typeof n?(e.local?Pn:zn)(e,r,Nn(this,"attr."+t,n)):null==n?(e.local?En:Sn)(e):(e.local?Cn:An)(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=js(t);return this.tween(e,(r.local?Rn:Ln)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?pl:Hl;return null==n?this.styleTween(t,jn(t,r)).on("end.style."+t,Hn(t)):this.styleTween(t,"function"==typeof n?$n(t,r,Nn(this,"style."+t,n)):Xn(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,Vn(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?Zn(Nn(this,"text",t)):Wn(null==t?"":t+""))},remove:function(){return this.on("end.remove",Bn(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=wn(this.node(),e).tween,o=0,u=i.length;o<u;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?Tn:kn)(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?qn:Un)(n,t)):wn(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?Dn:On)(n,t)):wn(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(Fn(n,t)):wn(this.node(),n).ease}};var Wl=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),Zl=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Gl=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Jl=Math.PI,Ql=Jl/2,Kl=4/11,th=6/11,nh=8/11,eh=.75,rh=9/11,ih=10/11,oh=.9375,uh=21/22,ah=63/64,ch=1/Kl/Kl,sh=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),fh=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),lh=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),hh=2*Math.PI,ph=function t(n,e){function r(t){return n*Math.pow(2,10*--t)*Math.sin((i-t)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),dh=function t(n,e){function r(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+i)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),vh=function t(n,e){function r(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((i-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((i+t)/e))/2}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),_h={time:null,delay:0,duration:250,ease:te};dt.prototype.interrupt=function(t){return this.each(function(){jl(this,t)})},dt.prototype.transition=function(t){var n,e;t instanceof Gn?(n=t._id,t=t._name):(n=Qn(),(e=_h).time=ln(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)(u=a[s])&&Bl(u,t,n,s,a,e||oe(u,n));return new Gn(r,this._parents,t,n)};var yh=[null],gh=function(t){return function(){return t}},mh=function(t,n,e){this.target=t,this.type=n,this.selection=e},xh=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},bh={name:"drag"},wh={name:"space"},Mh={name:"handle"},Th={name:"center"},kh={name:"x",handles:["e","w"].map(ae),input:function(t,n){return t&&[[t[0],n[0][1]],[t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Nh={name:"y",handles:["n","s"].map(ae),input:function(t,n){return t&&[[n[0][0],t[0]],[n[1][0],t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Sh={name:"xy",handles:["n","e","s","w","nw","ne","se","sw"].map(ae),input:function(t){return t},output:function(t){return t}},Eh={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ah={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ch={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},zh={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Ph={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1},Rh=Math.cos,Lh=Math.sin,qh=Math.PI,Uh=qh/2,Dh=2*qh,Oh=Math.max,Fh=Array.prototype.slice,Ih=function(t){return function(){return t}},Yh=Math.PI,Bh=2*Yh,jh=Bh-1e-6;de.prototype=ve.prototype={constructor:de,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,u=this._y1,a=e-t,c=r-n,s=o-t,f=u-n,l=s*s+f*f;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(f*a-c*s)>1e-6&&i){var h=e-o,p=r-u,d=a*a+c*c,v=h*h+p*p,_=Math.sqrt(d),y=Math.sqrt(l),g=i*Math.tan((Yh-Math.acos((d+l-v)/(2*_*y)))/2),m=g/y,x=g/_;Math.abs(m-1)>1e-6&&(this._+="L"+(t+m*s)+","+(n+m*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>s*p)+","+(this._x1=t+x*a)+","+(this._y1=n+x*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,s=n+a,f=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+s:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-s)>1e-6)&&(this._+="L"+c+","+s),e&&(l<0&&(l=l%Bh+Bh),l>jh?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=s):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Yh)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};be.prototype=we.prototype={constructor:be,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var Hh=we.prototype;Se.prototype=Ee.prototype={constructor:Se,has:Hh.has,add:function(t){return t+="",this["$"+t]=t,this},remove:Hh.remove,clear:Hh.clear,values:Hh.keys,size:Hh.size,empty:Hh.empty,each:Hh.each};var Xh=function(t){function n(t,n){function e(){if(f>=s)return a;if(i)return i=!1,u;var n,e=f;if(34===t.charCodeAt(e)){for(var r=e;r++<s;)if(34===t.charCodeAt(r)){if(34!==t.charCodeAt(r+1))break;++r}return f=r+2,13===(n=t.charCodeAt(r+1))?(i=!0,10===t.charCodeAt(r+2)&&++f):10===n&&(i=!0),t.slice(e+1,r).replace(/""/g,'"')}for(;f<s;){var c=1;if(10===(n=t.charCodeAt(f++)))i=!0;else if(13===n)i=!0,10===t.charCodeAt(f)&&(++f,++c);else if(n!==o)continue;return t.slice(e,f-c)}return t.slice(e)}for(var r,i,u={},a={},c=[],s=t.length,f=0,l=0;(r=e())!==a;){for(var h=[];r!==u&&r!==a;)h.push(r),r=e();n&&null==(h=n(h,l++))||c.push(h)}return c}function e(n){return n.map(r).join(t)}function r(t){return null==t?"":i.test(t+="")?'"'+t.replace(/\"/g,'""')+'"':t}var i=new RegExp('["'+t+"\n\r]"),o=t.charCodeAt(0);return{parse:function(t,e){var r,i,o=n(t,function(t,n){if(r)return r(t,n-1);i=t,r=e?Ce(t,e):Ae(t)});return o.columns=i,o},parseRows:n,format:function(n,e){return null==e&&(e=ze(n)),[e.map(r).join(t)].concat(n.map(function(n){return e.map(function(t){return r(n[t])}).join(t)})).join("\n")},formatRows:function(t){return t.map(e).join("\n")}}},$h=Xh(","),Vh=$h.parse,Wh=$h.parseRows,Zh=$h.format,Gh=$h.formatRows,Jh=Xh("\t"),Qh=Jh.parse,Kh=Jh.parseRows,tp=Jh.format,np=Jh.formatRows,ep=function(t){return function(){return t}},rp=function(){return 1e-6*(Math.random()-.5)},ip=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i},op=qe.prototype=Ue.prototype;op.copy=function(){var t,n,e=new Ue(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=De(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=De(n));return e},op.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return Pe(this.cover(n,e),n,e,t)},op.addAll=function(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,s=1/0,f=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(u[e]=r,a[e]=i,r<c&&(c=r),r>f&&(f=r),i<s&&(s=i),i>l&&(l=i));for(f<c&&(c=this._x0,f=this._x1),l<s&&(s=this._y0,l=this._y1),this.cover(c,s).cover(f,l),e=0;e<o;++e)Pe(this,u[e],a[e],t[e]);return this},op.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{if(!(e>t||t>i||r>n||n>o))return this;var u,a,c=i-e,s=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,o=r+c,t>i||n>o);break;case 1:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,o=r+c,e>t||n>o);break;case 2:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,r=o-c,t>i||r>n);break;case 3:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,r=o-c,e>t||r>n)}this._root&&this._root.length&&(this._root=s)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},op.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},op.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},op.find=function(t,n,e){var r,i,o,u,a,c,s,f=this._x0,l=this._y0,h=this._x1,p=this._y1,d=[],v=this._root;for(v&&d.push(new ip(v,f,l,h,p)),null==e?e=1/0:(f=t-e,l=n-e,h=t+e,p=n+e,e*=e);c=d.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>p||(u=c.x1)<f||(a=c.y1)<l))if(v.length){var _=(i+u)/2,y=(o+a)/2;d.push(new ip(v[3],_,y,u,a),new ip(v[2],i,y,_,a),new ip(v[1],_,o,u,y),new ip(v[0],i,o,_,y)),(s=(n>=y)<<1|t>=_)&&(c=d[d.length-1],d[d.length-1]=d[d.length-1-s],d[d.length-1-s]=c)}else{var g=t-+this._x.call(null,v.data),m=n-+this._y.call(null,v.data),x=g*g+m*m;if(x<e){var b=Math.sqrt(e=x);f=t-b,l=n-b,h=t+b,p=n+b,r=v.data}}return r},op.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(u=+this._y.call(null,t)))return this;var n,e,r,i,o,u,a,c,s,f,l,h,p=this._root,d=this._x0,v=this._y0,_=this._x1,y=this._y1;if(!p)return this;if(p.length)for(;;){if((s=o>=(a=(d+_)/2))?d=a:_=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=p,!(p=p[l=f<<1|s]))return this;if(!p.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;p.data!==t;)if(r=p,!(p=p.next))return this;return(i=p.next)&&delete p.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(p=n[0]||n[1]||n[2]||n[3])&&p===(n[3]||n[2]||n[1]||n[0])&&!p.length&&(e?e[h]=p:this._root=p),this):(this._root=i,this)},op.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},op.root=function(){return this._root},op.size=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},op.visit=function(t){var n,e,r,i,o,u,a=[],c=this._root;for(c&&a.push(new ip(c,this._x0,this._y0,this._x1,this._y1));n=a.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,u=n.y1)&&c.length){var s=(r+o)/2,f=(i+u)/2;(e=c[3])&&a.push(new ip(e,s,f,o,u)),(e=c[2])&&a.push(new ip(e,r,f,s,u)),(e=c[1])&&a.push(new ip(e,s,i,o,f)),(e=c[0])&&a.push(new ip(e,r,i,s,f))}return this},op.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new ip(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,u=n.x0,a=n.y0,c=n.x1,s=n.y1,f=(u+c)/2,l=(a+s)/2;(o=i[0])&&e.push(new ip(o,u,a,f,l)),(o=i[1])&&e.push(new ip(o,f,a,c,l)),(o=i[2])&&e.push(new ip(o,u,l,f,s)),(o=i[3])&&e.push(new ip(o,f,l,c,s))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},op.x=function(t){return arguments.length?(this._x=t,this):this._x},op.y=function(t){return arguments.length?(this._y=t,this):this._y};var up,ap=10,cp=Math.PI*(3-Math.sqrt(5)),sp=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},fp=function(t){return(t=sp(Math.abs(t)))?t[1]:NaN},lp=function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}},hp=function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}},pp=function(t,n){var e=sp(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},dp={"":function(t,n){t:for(var e,r=(t=t.toPrecision(n)).length,i=1,o=-1;i<r;++i)switch(t[i]){case".":o=e=i;break;case"0":0===o&&(o=i),e=i;break;case"e":break t;default:o>0&&(o=0)}return o>0?t.slice(0,o)+t.slice(e+1):t},"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return pp(100*t,n)},r:pp,s:function(t,n){var e=sp(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(up=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+sp(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},vp=/^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;He.prototype=Xe.prototype,Xe.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var _p,yp=function(t){return t},gp=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],mp=function(t){function n(t){function n(t){var n,r,u,f=_,x=y;if("c"===v)x=g(t)+x,t="";else{var b=(t=+t)<0;if(t=g(Math.abs(t),d),b&&0==+t&&(b=!1),f=(b?"("===s?s:"-":"-"===s||"("===s?"":s)+f,x=x+("s"===v?gp[8+up/3]:"")+(b&&"("===s?")":""),m)for(n=-1,r=t.length;++n<r;)if(48>(u=t.charCodeAt(n))||u>57){x=(46===u?i+t.slice(n+1):t.slice(n))+x,t=t.slice(0,n);break}}p&&!l&&(t=e(t,1/0));var w=f.length+t.length+x.length,M=w<h?new Array(h-w+1).join(a):"";switch(p&&l&&(t=e(M+t,M.length?h-x.length:1/0),M=""),c){case"<":t=f+t+x+M;break;case"=":t=f+M+t+x;break;case"^":t=M.slice(0,w=M.length>>1)+f+t+x+M.slice(w);break;default:t=M+f+t+x}return o(t)}var a=(t=He(t)).fill,c=t.align,s=t.sign,f=t.symbol,l=t.zero,h=t.width,p=t.comma,d=t.precision,v=t.type,_="$"===f?r[0]:"#"===f&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",y="$"===f?r[1]:/[%p]/.test(v)?u:"",g=dp[v],m=!v||/[defgprs%]/.test(v);return d=null==d?v?6:12:/[gprs]/.test(v)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),n.toString=function(){return t+""},n}var e=t.grouping&&t.thousands?lp(t.grouping,t.thousands):yp,r=t.currency,i=t.decimal,o=t.numerals?hp(t.numerals):yp,u=t.percent||"%";return{format:n,formatPrefix:function(t,e){var r=n((t=He(t),t.type="f",t)),i=3*Math.max(-8,Math.min(8,Math.floor(fp(e)/3))),o=Math.pow(10,-i),u=gp[8+i/3];return function(t){return r(o*t)+u}}}};$e({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var xp=function(t){return Math.max(0,-fp(Math.abs(t)))},bp=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(fp(n)/3)))-fp(Math.abs(t)))},wp=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,fp(n)-fp(t))+1},Mp=function(){return new Ve};Ve.prototype={constructor:Ve,reset:function(){this.s=this.t=0},add:function(t){We(nd,t,this.t),We(this,nd.s,this.s),this.s?this.t+=nd.t:this.s=nd.t},valueOf:function(){return this.s}};var Tp,kp,Np,Sp,Ep,Ap,Cp,zp,Pp,Rp,Lp,qp,Up,Dp,Op,Fp,Ip,Yp,Bp,jp,Hp,Xp,$p,Vp,Wp,Zp,Gp,Jp,Qp,Kp,td,nd=new Ve,ed=1e-6,rd=Math.PI,id=rd/2,od=rd/4,ud=2*rd,ad=180/rd,cd=rd/180,sd=Math.abs,fd=Math.atan,ld=Math.atan2,hd=Math.cos,pd=Math.ceil,dd=Math.exp,vd=Math.log,_d=Math.pow,yd=Math.sin,gd=Math.sign||function(t){return t>0?1:t<0?-1:0},md=Math.sqrt,xd=Math.tan,bd={Feature:function(t,n){Ke(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)Ke(e[r].geometry,n)}},wd={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){tr(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)tr(e[r],n,0)},Polygon:function(t,n){nr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)nr(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)Ke(e[r],n)}},Md=function(t,n){t&&bd.hasOwnProperty(t.type)?bd[t.type](t,n):Ke(t,n)},Td=Mp(),kd=Mp(),Nd={point:Qe,lineStart:Qe,lineEnd:Qe,polygonStart:function(){Td.reset(),Nd.lineStart=er,Nd.lineEnd=rr},polygonEnd:function(){var t=+Td;kd.add(t<0?ud+t:t),this.lineStart=this.lineEnd=this.point=Qe},sphere:function(){kd.add(ud)}},Sd=Mp(),Ed={point:pr,lineStart:vr,lineEnd:_r,polygonStart:function(){Ed.point=yr,Ed.lineStart=gr,Ed.lineEnd=mr,Sd.reset(),Nd.polygonStart()},polygonEnd:function(){Nd.polygonEnd(),Ed.point=pr,Ed.lineStart=vr,Ed.lineEnd=_r,Td<0?(Ap=-(zp=180),Cp=-(Pp=90)):Sd>ed?Pp=90:Sd<-ed&&(Cp=-90),Op[0]=Ap,Op[1]=zp}},Ad={sphere:Qe,point:Mr,lineStart:kr,lineEnd:Er,polygonStart:function(){Ad.lineStart=Ar,Ad.lineEnd=Cr},polygonEnd:function(){Ad.lineStart=kr,Ad.lineEnd=Er}},Cd=function(t){return function(){return t}},zd=function(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e};Rr.invert=Rr;var Pd,Rd,Ld,qd,Ud,Dd,Od,Fd,Id,Yd,Bd,jd=function(t){function n(n){return n=t(n[0]*cd,n[1]*cd),n[0]*=ad,n[1]*=ad,n}return t=Lr(t[0]*cd,t[1]*cd,t.length>2?t[2]*cd:0),n.invert=function(n){return n=t.invert(n[0]*cd,n[1]*cd),n[0]*=ad,n[1]*=ad,n},n},Hd=function(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:Qe,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}},Xd=function(t,n,e,r,i,o){var u,a=t[0],c=t[1],s=0,f=1,l=n[0]-a,h=n[1]-c;if(u=e-a,l||!(u>0)){if(u/=l,l<0){if(u<s)return;u<f&&(f=u)}else if(l>0){if(u>f)return;u>s&&(s=u)}if(u=i-a,l||!(u<0)){if(u/=l,l<0){if(u>f)return;u>s&&(s=u)}else if(l>0){if(u<s)return;u<f&&(f=u)}if(u=r-c,h||!(u>0)){if(u/=h,h<0){if(u<s)return;u<f&&(f=u)}else if(h>0){if(u>f)return;u>s&&(s=u)}if(u=o-c,h||!(u<0)){if(u/=h,h<0){if(u>f)return;u>s&&(s=u)}else if(h>0){if(u<s)return;u<f&&(f=u)}return s>0&&(t[0]=a+s*l,t[1]=c+s*h),f<1&&(n[0]=a+f*l,n[1]=c+f*h),!0}}}}},$d=function(t,n){return sd(t[0]-n[0])<ed&&sd(t[1]-n[1])<ed},Vd=function(t,n,e,r,i){var o,u,a=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],u=t[n];if($d(r,u)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);i.lineEnd()}else a.push(e=new Ir(r,t,null,!0)),c.push(e.o=new Ir(r,null,e,!1)),a.push(e=new Ir(u,t,null,!1)),c.push(e.o=new Ir(u,null,e,!0))}}),a.length){for(c.sort(n),Yr(a),Yr(c),o=0,u=c.length;o<u;++o)c[o].e=e=!e;for(var s,f,l=a[0];;){for(var h=l,p=!0;h.v;)if((h=h.n)===l)return;s=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(p)for(o=0,u=s.length;o<u;++o)i.point((f=s[o])[0],f[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(p)for(s=h.p.z,o=s.length-1;o>=0;--o)i.point((f=s[o])[0],f[1]);else r(h.x,h.p.x,-1,i);h=h.p}s=(h=h.o).z,p=!p}while(!h.v);i.lineEnd()}}},Wd=1e9,Zd=-Wd,Gd=Mp(),Jd=function(t,n){var e=n[0],r=n[1],i=[yd(e),-hd(e),0],o=0,u=0;Gd.reset();for(var a=0,c=t.length;a<c;++a)if(f=(s=t[a]).length)for(var s,f,l=s[f-1],h=l[0],p=l[1]/2+od,d=yd(p),v=hd(p),_=0;_<f;++_,h=g,d=x,v=b,l=y){var y=s[_],g=y[0],m=y[1]/2+od,x=yd(m),b=hd(m),w=g-h,M=w>=0?1:-1,T=M*w,k=T>rd,N=d*x;if(Gd.add(ld(N*M*yd(T),v*b+N*hd(T))),o+=k?w+M*ud:w,k^h>=e^g>=e){var S=sr(ar(l),ar(y));hr(S);var E=sr(i,S);hr(E);var A=(k^w>=0?-1:1)*Ge(E[2]);(r>A||r===A&&(S[0]||S[1]))&&(u+=k^w>=0?1:-1)}}return(o<-ed||o<ed&&Gd<-ed)^1&u},Qd=Mp(),Kd={sphere:Qe,point:Qe,lineStart:function(){Kd.point=Hr,Kd.lineEnd=jr},lineEnd:Qe,polygonStart:Qe,polygonEnd:Qe},tv=function(t){return Qd.reset(),Md(t,Kd),+Qd},nv=[null,null],ev={type:"LineString",coordinates:nv},rv=function(t,n){return nv[0]=t,nv[1]=n,tv(ev)},iv={Feature:function(t,n){return $r(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if($r(e[r].geometry,n))return!0;return!1}},ov={Sphere:function(){return!0},Point:function(t,n){return Vr(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Vr(e[r],n))return!0;return!1},LineString:function(t,n){return Wr(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Wr(e[r],n))return!0;return!1},Polygon:function(t,n){return Zr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Zr(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if($r(e[r],n))return!0;return!1}},uv=function(t){return t},av=Mp(),cv=Mp(),sv={point:Qe,lineStart:Qe,lineEnd:Qe,polygonStart:function(){sv.lineStart=ni,sv.lineEnd=ii},polygonEnd:function(){sv.lineStart=sv.lineEnd=sv.point=Qe,av.add(sd(cv)),cv.reset()},result:function(){var t=av/2;return av.reset(),t}},fv=1/0,lv=fv,hv=-fv,pv=hv,dv={point:function(t,n){t<fv&&(fv=t),t>hv&&(hv=t),n<lv&&(lv=n),n>pv&&(pv=n)},lineStart:Qe,lineEnd:Qe,polygonStart:Qe,polygonEnd:Qe,result:function(){var t=[[fv,lv],[hv,pv]];return hv=pv=-(lv=fv=1/0),t}},vv=0,_v=0,yv=0,gv=0,mv=0,xv=0,bv=0,wv=0,Mv=0,Tv={point:oi,lineStart:ui,lineEnd:si,polygonStart:function(){Tv.lineStart=fi,Tv.lineEnd=li},polygonEnd:function(){Tv.point=oi,Tv.lineStart=ui,Tv.lineEnd=si},result:function(){var t=Mv?[bv/Mv,wv/Mv]:xv?[gv/xv,mv/xv]:yv?[vv/yv,_v/yv]:[NaN,NaN];return vv=_v=yv=gv=mv=xv=bv=wv=Mv=0,t}};di.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,ud)}},result:Qe};var kv,Nv,Sv,Ev,Av,Cv=Mp(),zv={point:Qe,lineStart:function(){zv.point=vi},lineEnd:function(){kv&&_i(Nv,Sv),zv.point=Qe},polygonStart:function(){kv=!0},polygonEnd:function(){kv=null},result:function(){var t=+Cv;return Cv.reset(),t}};yi.prototype={_radius:4.5,_circle:gi(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=gi(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}};var Pv=function(t,n,e,r){return function(i,o){function u(n,e){var r=i(n,e);t(n=r[0],e=r[1])&&o.point(n,e)}function a(t,n){var e=i(t,n);_.point(e[0],e[1])}function c(){b.point=a,_.lineStart()}function s(){b.point=u,_.lineEnd()}function f(t,n){v.push([t,n]);var e=i(t,n);m.point(e[0],e[1])}function l(){m.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),m.lineEnd();var t,n,e,r,i=m.clean(),u=g.result(),a=u.length;if(v.pop(),p.push(v),v=null,a)if(1&i){if(e=u[0],(n=e.length-1)>0){for(x||(o.polygonStart(),x=!0),o.lineStart(),t=0;t<n;++t)o.point((r=e[t])[0],r[1]);o.lineEnd()}}else a>1&&2&i&&u.push(u.pop().concat(u.shift())),d.push(u.filter(mi))}var p,d,v,_=n(o),y=i.invert(r[0],r[1]),g=Hd(),m=n(g),x=!1,b={point:u,lineStart:c,lineEnd:s,polygonStart:function(){b.point=f,b.lineStart=l,b.lineEnd=h,d=[],p=[]},polygonEnd:function(){b.point=u,b.lineStart=c,b.lineEnd=s,d=Cs(d);var t=Jd(p,y);d.length?(x||(o.polygonStart(),x=!0),Vd(d,xi,t,e,o)):t&&(x||(o.polygonStart(),x=!0),o.lineStart(),e(null,null,1,o),o.lineEnd()),x&&(o.polygonEnd(),x=!1),d=p=null},sphere:function(){o.polygonStart(),o.lineStart(),e(null,null,1,o),o.lineEnd(),o.polygonEnd()}};return b}},Rv=Pv(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,u){var a=o>0?rd:-rd,c=sd(o-e);sd(c-rd)<ed?(t.point(e,r=(r+u)/2>0?id:-id),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),t.point(o,r),n=0):i!==a&&c>=rd&&(sd(e-i)<ed&&(e-=i*ed),sd(o-a)<ed&&(o-=a*ed),r=bi(e,r,o,u),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),n=0),t.point(e=o,r=u),i=a},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*id,r.point(-rd,i),r.point(0,i),r.point(rd,i),r.point(rd,0),r.point(rd,-i),r.point(0,-i),r.point(-rd,-i),r.point(-rd,0),r.point(-rd,i);else if(sd(t[0]-n[0])>ed){var o=t[0]<n[0]?rd:-rd;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])},[-rd,-id]),Lv=function(t,n){function e(t,n){return hd(t)*hd(n)>o}function r(t,n,e){var r=[1,0,0],i=sr(ar(t),ar(n)),u=cr(i,i),a=i[0],c=u-a*a;if(!c)return!e&&t;var s=o*u/c,f=-o*a/c,l=sr(r,i),h=lr(r,s);fr(h,lr(i,f));var p=l,d=cr(h,p),v=cr(p,p),_=d*d-v*(cr(h,h)-1);if(!(_<0)){var y=md(_),g=lr(p,(-d-y)/v);if(fr(g,h),g=ur(g),!e)return g;var m,x=t[0],b=n[0],w=t[1],M=n[1];b<x&&(m=x,x=b,b=m);var T=b-x,k=sd(T-rd)<ed,N=k||T<ed;if(!k&&M<w&&(m=w,w=M,M=m),N?k?w+M>0^g[1]<(sd(g[0]-x)<ed?w:M):w<=g[1]&&g[1]<=M:T>rd^(x<=g[0]&&g[0]<=b)){var S=lr(p,(-d+y)/v);return fr(S,h),[g,ur(S)]}}}function i(n,e){var r=u?t:rd-t,i=0;return n<-r?i|=1:n>r&&(i|=2),e<-r?i|=4:e>r&&(i|=8),i}var o=hd(t),u=o>0,a=sd(o)>ed;return Pv(e,function(t){var n,o,c,s,f;return{lineStart:function(){s=c=!1,f=1},point:function(l,h){var p,d=[l,h],v=e(l,h),_=u?v?0:i(l,h):v?i(l+(l<0?rd:-rd),h):0;if(!n&&(s=c=v)&&t.lineStart(),v!==c&&(!(p=r(n,d))||$d(n,p)||$d(d,p))&&(d[0]+=ed,d[1]+=ed,v=e(d[0],d[1])),v!==c)f=0,v?(t.lineStart(),p=r(d,n),t.point(p[0],p[1])):(p=r(n,d),t.point(p[0],p[1]),t.lineEnd()),n=p;else if(a&&n&&u^v){var y;_&o||!(y=r(d,n,!0))||(f=0,u?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&$d(n,d)||t.point(d[0],d[1]),n=d,c=v,o=_},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return f|(s&&c)<<1}}},function(e,r,i,o){Or(o,t,n,i,e,r)},u?[0,-t]:[-rd,t-rd])};Mi.prototype={constructor:Mi,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var qv=16,Uv=hd(30*cd),Dv=function(t,n){return+n?Si(t,n):Ni(t)},Ov=wi({point:function(t,n){this.stream.point(t*cd,n*cd)}}),Fv=function(){return Ci(Pi).scale(155.424).center([0,33.6442])},Iv=function(){return Fv().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])},Yv=Li(function(t){return md(2/(1+t))});Yv.invert=qi(function(t){return 2*Ge(t/2)});var Bv=Li(function(t){return(t=Ze(t))&&t/yd(t)});Bv.invert=qi(function(t){return t});Ui.invert=function(t,n){return[t,2*fd(dd(n))-id]};Ii.invert=Ii;Bi.invert=qi(fd);Hi.invert=qi(Ge);Xi.invert=qi(function(t){return 2*fd(t)});$i.invert=function(t,n){return[-n,2*fd(dd(t))-id]};uo.prototype=eo.prototype={constructor:uo,count:function(){return this.eachAfter(to)},each:function(t){var n,e,r,i,o=this,u=[o];do{for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)u.push(e[r])}while(u.length);return this},eachAfter:function(t){for(var n,e,r,i=this,o=[i],u=[];i=o.pop();)if(u.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=u.pop();)t(i);return this},eachBefore:function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=no(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return eo(this).eachBefore(io)}};var jv=Array.prototype.slice,Hv=function(t){for(var n,e,r=0,i=(t=ao(jv.call(t))).length,o=[];r<i;)n=t[r],e&&fo(e,n)?++r:(e=ho(o=co(o,n)),r=0);return e},Xv=function(t){return function(){return t}},$v=function(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)},Vv=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(r-n)/t.value;++a<c;)(o=u[a]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*s},Wv="$",Zv={depth:-1},Gv={};Do.prototype=Object.create(uo.prototype);var Jv=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(i-e)/t.value;++a<c;)(o=u[a]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*s},Qv=(1+Math.sqrt(5))/2,Kv=function t(n){function e(t,e,r,i,o){Fo(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Qv),t_=function t(n){function e(t,e,r,i,o){if((u=t._squarify)&&u.ratio===n)for(var u,a,c,s,f,l=-1,h=u.length,p=t.value;++l<h;){for(c=(a=u[l]).children,s=a.value=0,f=c.length;s<f;++s)a.value+=c[s].value;a.dice?Vv(a,e,r,i,r+=(o-r)*a.value/p):Jv(a,e,r,e+=(i-e)*a.value/p,o),p-=a.value}else t._squarify=u=Fo(n,t,e,r,i,o),u.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Qv),n_=function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])},e_=[].slice,r_={};Bo.prototype=Wo.prototype={constructor:Bo,defer:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("defer after await");if(null!=this._error)return this;var n=e_.call(arguments,1);return n.push(t),++this._waiting,this._tasks.push(n),jo(this),this},abort:function(){return null==this._error&&$o(this,new Error("abort")),this},await:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=function(n,e){t.apply(null,[n].concat(e))},Vo(this),this},awaitAll:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=t,Vo(this),this}};var i_=function(){return Math.random()},o_=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(i_),u_=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(i_),a_=function t(n){function e(){var t=u_.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(i_),c_=function t(n){function e(t){return function(){for(var e=0,r=0;r<t;++r)e+=n();return e}}return e.source=t,e}(i_),s_=function t(n){function e(t){var e=c_.source(n)(t);return function(){return e()/t}}return e.source=t,e}(i_),f_=function t(n){function e(t){return function(){return-Math.log(1-n())/t}}return e.source=t,e}(i_),l_=function(t,n){function e(t){var n,e=s.status;if(!e&&Go(s)||e>=200&&e<300||304===e){if(o)try{n=o.call(r,s)}catch(t){return void a.call("error",r,t)}else n=s;a.call("load",r,n)}else a.call("error",r,t)}var r,i,o,u,a=h("beforesend","progress","load","error"),c=we(),s=new XMLHttpRequest,f=null,l=null,p=0;if("undefined"==typeof XDomainRequest||"withCredentials"in s||!/^(http(s)?:)?\/\//.test(t)||(s=new XDomainRequest),"onload"in s?s.onload=s.onerror=s.ontimeout=e:s.onreadystatechange=function(t){s.readyState>3&&e(t)},s.onprogress=function(t){a.call("progress",r,t)},r={header:function(t,n){return t=(t+"").toLowerCase(),arguments.length<2?c.get(t):(null==n?c.remove(t):c.set(t,n+""),r)},mimeType:function(t){return arguments.length?(i=null==t?null:t+"",r):i},responseType:function(t){return arguments.length?(u=t,r):u},timeout:function(t){return arguments.length?(p=+t,r):p},user:function(t){return arguments.length<1?f:(f=null==t?null:t+"",r)},password:function(t){return arguments.length<1?l:(l=null==t?null:t+"",r)},response:function(t){return o=t,r},get:function(t,n){return r.send("GET",t,n)},post:function(t,n){return r.send("POST",t,n)},send:function(n,e,o){return s.open(n,t,!0,f,l),null==i||c.has("accept")||c.set("accept",i+",*/*"),s.setRequestHeader&&c.each(function(t,n){s.setRequestHeader(n,t)}),null!=i&&s.overrideMimeType&&s.overrideMimeType(i),null!=u&&(s.responseType=u),p>0&&(s.timeout=p),null==o&&"function"==typeof e&&(o=e,e=null),null!=o&&1===o.length&&(o=Zo(o)),null!=o&&r.on("error",o).on("load",function(t){o(null,t)}),a.call("beforesend",r,s),s.send(null==e?null:e),r},abort:function(){return s.abort(),r},on:function(){var t=a.on.apply(a,arguments);return t===a?r:t}},null!=n){if("function"!=typeof n)throw new Error("invalid callback: "+n);return r.get(n)}return r},h_=function(t,n){return function(e,r){var i=l_(e).mimeType(t).response(n);if(null!=r){if("function"!=typeof r)throw new Error("invalid callback: "+r);return i.get(r)}return i}},p_=h_("text/html",function(t){return document.createRange().createContextualFragment(t.responseText)}),d_=h_("application/json",function(t){return JSON.parse(t.responseText)}),v_=h_("text/plain",function(t){return t.responseText}),__=h_("application/xml",function(t){var n=t.responseXML;if(!n)throw new Error("parse error");return n}),y_=function(t,n){return function(e,r,i){arguments.length<3&&(i=r,r=null);var o=l_(e).mimeType(t);return o.row=function(t){return arguments.length?o.response(Jo(n,r=t)):r},o.row(r),i?o.get(i):o}},g_=y_("text/csv",Vh),m_=y_("text/tab-separated-values",Qh),x_=Array.prototype,b_=x_.map,w_=x_.slice,M_={name:"implicit"},T_=function(t){return function(){return t}},k_=function(t){return+t},N_=[0,1],S_=function(n,e,r){var o,u=n[0],a=n[n.length-1],c=i(u,a,null==e?10:e);switch((r=He(null==r?",f":r)).type){case"s":var s=Math.max(Math.abs(u),Math.abs(a));return null!=r.precision||isNaN(o=bp(c,s))||(r.precision=o),t.formatPrefix(r,s);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(o=wp(c,Math.max(Math.abs(u),Math.abs(a))))||(r.precision=o-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(o=xp(c))||(r.precision=o-2*("%"===r.type))}return t.format(r)},E_=function(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],u=t[i];return u<o&&(e=r,r=i,i=e,e=o,o=u,u=e),t[r]=n.floor(o),t[i]=n.ceil(u),t},A_=new Date,C_=new Date,z_=Mu(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});z_.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Mu(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):z_:null};var P_=z_.range,R_=6e4,L_=6048e5,q_=Mu(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),U_=q_.range,D_=Mu(function(t){t.setTime(Math.floor(t/R_)*R_)},function(t,n){t.setTime(+t+n*R_)},function(t,n){return(n-t)/R_},function(t){return t.getMinutes()}),O_=D_.range,F_=Mu(function(t){var n=t.getTimezoneOffset()*R_%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),I_=F_.range,Y_=Mu(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*R_)/864e5},function(t){return t.getDate()-1}),B_=Y_.range,j_=Tu(0),H_=Tu(1),X_=Tu(2),$_=Tu(3),V_=Tu(4),W_=Tu(5),Z_=Tu(6),G_=j_.range,J_=H_.range,Q_=X_.range,K_=$_.range,ty=V_.range,ny=W_.range,ey=Z_.range,ry=Mu(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),iy=ry.range,oy=Mu(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});oy.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Mu(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var uy=oy.range,ay=Mu(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*R_)},function(t,n){return(n-t)/R_},function(t){return t.getUTCMinutes()}),cy=ay.range,sy=Mu(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),fy=sy.range,ly=Mu(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),hy=ly.range,py=ku(0),dy=ku(1),vy=ku(2),_y=ku(3),yy=ku(4),gy=ku(5),my=ku(6),xy=py.range,by=dy.range,wy=vy.range,My=_y.range,Ty=yy.range,ky=gy.range,Ny=my.range,Sy=Mu(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),Ey=Sy.range,Ay=Mu(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});Ay.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Mu(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Cy,zy=Ay.range,Py={"-":"",_:" ",0:"0"},Ry=/^\s*\d+/,Ly=/^%/,qy=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;Ma({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Uy=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ"),Dy=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),Oy=1e3,Fy=60*Oy,Iy=60*Fy,Yy=24*Iy,By=7*Yy,jy=30*Yy,Hy=365*Yy,Xy=function(t){return t.match(/.{6}/g).map(function(t){return"#"+t})},$y=Xy("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),Vy=Xy("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6"),Wy=Xy("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9"),Zy=Xy("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5"),Gy=wl($t(300,.5,0),$t(-240,.5,1)),Jy=wl($t(-100,.75,.35),$t(80,1.5,.8)),Qy=wl($t(260,.75,.35),$t(80,1.5,.8)),Ky=$t(),tg=Sa(Xy("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),ng=Sa(Xy("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),eg=Sa(Xy("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),rg=Sa(Xy("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921")),ig=function(t){return function(){return t}},og=Math.abs,ug=Math.atan2,ag=Math.cos,cg=Math.max,sg=Math.min,fg=Math.sin,lg=Math.sqrt,hg=1e-12,pg=Math.PI,dg=pg/2,vg=2*pg;Oa.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var _g=function(t){return new Oa(t)},yg=function(){function t(t){var a,c,s,f=t.length,l=!1;for(null==i&&(u=o(s=ve())),a=0;a<=f;++a)!(a<f&&r(c=t[a],a,t))===l&&((l=!l)?u.lineStart():u.lineEnd()),l&&u.point(+n(c,a,t),+e(c,a,t));if(s)return u=null,s+""||null}var n=Fa,e=Ia,r=ig(!0),i=null,o=_g,u=null;return t.x=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.defined=function(n){return arguments.length?(r="function"==typeof n?n:ig(!!n),t):r},t.curve=function(n){return arguments.length?(o=n,null!=i&&(u=o(i)),t):o},t.context=function(n){return arguments.length?(null==n?i=u=null:u=o(i=n),t):i},t},gg=function(){function t(t){var n,f,l,h,p,d=t.length,v=!1,_=new Array(d),y=new Array(d);for(null==a&&(s=c(p=ve())),n=0;n<=d;++n){if(!(n<d&&u(h=t[n],n,t))===v)if(v=!v)f=n,s.areaStart(),s.lineStart();else{for(s.lineEnd(),s.lineStart(),l=n-1;l>=f;--l)s.point(_[l],y[l]);s.lineEnd(),s.areaEnd()}v&&(_[n]=+e(h,n,t),y[n]=+i(h,n,t),s.point(r?+r(h,n,t):_[n],o?+o(h,n,t):y[n]))}if(p)return s=null,p+""||null}function n(){return yg().defined(u).curve(c).context(a)}var e=Fa,r=null,i=ig(0),o=Ia,u=ig(!0),a=null,c=_g,s=null;return t.x=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),r=null,t):e},t.x0=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.x1=function(n){return arguments.length?(r=null==n?null:"function"==typeof n?n:ig(+n),t):r},t.y=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),o=null,t):i},t.y0=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.y1=function(n){return arguments.length?(o=null==n?null:"function"==typeof n?n:ig(+n),t):o},t.lineX0=t.lineY0=function(){return n().x(e).y(i)},t.lineY1=function(){return n().x(e).y(o)},t.lineX1=function(){return n().x(r).y(i)},t.defined=function(n){return arguments.length?(u="function"==typeof n?n:ig(!!n),t):u},t.curve=function(n){return arguments.length?(c=n,null!=a&&(s=c(a)),t):c},t.context=function(n){return arguments.length?(null==n?a=s=null:s=c(a=n),t):a},t},mg=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},xg=function(t){return t},bg=Ba(_g);Ya.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var wg=function(){return ja(yg().curve(bg))},Mg=function(){var t=gg().curve(bg),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return ja(e())},delete t.lineX0,t.lineEndAngle=function(){return ja(r())},delete t.lineX1,t.lineInnerRadius=function(){return ja(i())},delete t.lineY0,t.lineOuterRadius=function(){return ja(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Ba(t)):n()._curve},t},Tg=function(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]},kg=Array.prototype.slice,Ng={draw:function(t,n){var e=Math.sqrt(n/pg);t.moveTo(e,0),t.arc(0,0,e,0,vg)}},Sg={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},Eg=Math.sqrt(1/3),Ag=2*Eg,Cg={draw:function(t,n){var e=Math.sqrt(n/Ag),r=e*Eg;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},zg=Math.sin(pg/10)/Math.sin(7*pg/10),Pg=Math.sin(vg/10)*zg,Rg=-Math.cos(vg/10)*zg,Lg={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=Pg*e,i=Rg*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var u=vg*o/5,a=Math.cos(u),c=Math.sin(u);t.lineTo(c*e,-a*e),t.lineTo(a*r-c*i,c*r+a*i)}t.closePath()}},qg={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},Ug=Math.sqrt(3),Dg={draw:function(t,n){var e=-Math.sqrt(n/(3*Ug));t.moveTo(0,2*e),t.lineTo(-Ug*e,-e),t.lineTo(Ug*e,-e),t.closePath()}},Og=-.5,Fg=Math.sqrt(3)/2,Ig=1/Math.sqrt(12),Yg=3*(Ig/2+1),Bg={draw:function(t,n){var e=Math.sqrt(n/Yg),r=e/2,i=e*Ig,o=r,u=e*Ig+e,a=-o,c=u;t.moveTo(r,i),t.lineTo(o,u),t.lineTo(a,c),t.lineTo(Og*r-Fg*i,Fg*r+Og*i),t.lineTo(Og*o-Fg*u,Fg*o+Og*u),t.lineTo(Og*a-Fg*c,Fg*a+Og*c),t.lineTo(Og*r+Fg*i,Og*i-Fg*r),t.lineTo(Og*o+Fg*u,Og*u-Fg*o),t.lineTo(Og*a+Fg*c,Og*c-Fg*a),t.closePath()}},jg=[Ng,Sg,Cg,qg,Lg,Dg,Bg],Hg=function(){};Ja.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Ga(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};Qa.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};Ka.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};tc.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],u=t[e]-i,a=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*u),this._beta*n[c]+(1-this._beta)*(o+r*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Xg=function t(n){function e(t){return 1===n?new Ja(t):new tc(t,n)}return e.beta=function(n){return t(+n)},e}(.85);ec.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:nc(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var $g=function t(n){function e(t){return new ec(t,n)}return e.tension=function(n){return t(+n)},e}(0);rc.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Vg=function t(n){function e(t){return new rc(t,n)}return e.tension=function(n){return t(+n)},e}(0);ic.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Wg=function t(n){function e(t){return new ic(t,n)}return e.tension=function(n){return t(+n)},e}(0);uc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Zg=function t(n){function e(t){return n?new uc(t,n):new ec(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);ac.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Gg=function t(n){function e(t){return n?new ac(t,n):new rc(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);cc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Jg=function t(n){function e(t){return n?new cc(t,n):new ic(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);sc.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}};dc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:pc(this,this._t0,hc(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(t=+t,n=+n,t!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,pc(this,hc(this,e=lc(this,t,n)),e);break;default:pc(this,this._t0,e=lc(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(vc.prototype=Object.create(dc.prototype)).point=function(t,n){dc.prototype.point.call(this,n,t)},_c.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},yc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=gc(t),i=gc(n),o=0,u=1;u<e;++o,++u)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[u],n[u]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}};mc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var Qg=function(t,n){if((i=t.length)>1)for(var e,r,i,o=1,u=t[n[0]],a=u.length;o<i;++o)for(r=u,u=t[n[o]],e=0;e<a;++e)u[e][1]+=u[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]},Kg=function(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e},tm=function(t){var n=t.map(bc);return Kg(t).sort(function(t,e){return n[t]-n[e]})},nm=function(t){return function(){return t}};Tc.prototype={constructor:Tc,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=Ec(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(Nc(this,e),e=(t=e).U),e.C=!1,r.C=!0,Sc(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(Sc(this,e),e=(t=e).U),e.C=!1,r.C=!0,Nc(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,u=t.R;if(e=o?u?Ec(u):o:u,i?i.L===t?i.L=e:i.R=e:this._=e,o&&u?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==u?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=u,u.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,Nc(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,Sc(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,Nc(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,Sc(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,Nc(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,Sc(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var em,rm,im,om,um,am=[],cm=[],sm=1e-6,fm=1e-12;Kc.prototype={constructor:Kc,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return Dc(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,u,a=e.site,c=-1,s=n[i[o-1]],f=s.left===a?s.right:s.left;++c<o;)u=f,f=(s=n[i[c]]).left===a?s.right:s.left,u&&f&&r<u.index&&r<f.index&&Jc(a,u,f)<0&&t.push([a.data,u.data,f.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,u=o._found||0,a=o.cells.length;!(i=o.cells[u]);)if(++u>=a)return null;var c=t-i.site[0],s=n-i.site[1],f=c*c+s*s;do{i=o.cells[r=u],u=null,i.halfedges.forEach(function(e){var r=o.edges[e],a=r.left;if(a!==i.site&&a||(a=r.right)){var c=t-a[0],s=n-a[1],l=c*c+s*s;l<f&&(f=l,u=a.index)}})}while(null!==u);return o._found=r,null==e||f<=e*e?i.site:null}};var lm=function(t){return function(){return t}};ns.prototype={constructor:ns,scale:function(t){return 1===t?this:new ns(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ns(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var hm=new ns(1,0,0);es.prototype=ns.prototype;var pm=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()};t.version="4.10.0",t.bisect=hs,t.bisectRight=hs,t.bisectLeft=ps,t.ascending=ss,t.bisector=fs,t.cross=function(t,n,r){var i,o,u,a,c=t.length,s=n.length,f=new Array(c*s);for(null==r&&(r=e),i=u=0;i<c;++i)for(a=t[i],o=0;o<s;++o,++u)f[u]=r(a,n[o]);return f},t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=_s,t.extent=ys,t.histogram=function(){function t(t){var o,u,a=t.length,c=new Array(a);for(o=0;o<a;++o)c[o]=n(t[o],o,t);var s=e(c),f=s[0],l=s[1],h=r(c,f,l);Array.isArray(h)||(h=i(f,l,h),h=Ms(Math.ceil(f/h)*h,Math.floor(l/h)*h,h));for(var p=h.length;h[0]<=f;)h.shift(),--p;for(;h[p-1]>l;)h.pop(),--p;var d,v=new Array(p+1);for(o=0;o<=p;++o)(d=v[o]=[]).x0=o>0?h[o-1]:f,d.x1=o<p?h[o]:l;for(o=0;o<a;++o)f<=(u=c[o])&&u<=l&&v[hs(h,u,0,p)].push(t[o]);return v}var n=ws,e=ys,r=Es;return t.value=function(e){return arguments.length?(n="function"==typeof e?e:bs(e),t):n},t.domain=function(n){return arguments.length?(e="function"==typeof n?n:bs([n[0],n[1]]),t):e},t.thresholds=function(n){return arguments.length?(r="function"==typeof n?n:bs(Array.isArray(n)?ms.call(n):n),t):r},t},t.thresholdFreedmanDiaconis=function(t,n,e){return t=xs.call(t,ds).sort(ss),Math.ceil((e-n)/(2*(As(t,.75)-As(t,.25))*Math.pow(t.length,-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*_s(t)*Math.pow(t.length,-1/3)))},t.thresholdSturges=Es,t.max=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r},t.mean=function(t,n){var e,r=t.length,i=r,o=-1,u=0;if(null==n)for(;++o<r;)isNaN(e=ds(t[o]))?--i:u+=e;else for(;++o<r;)isNaN(e=ds(n(t[o],o,t)))?--i:u+=e;if(i)return u/i},t.median=function(t,n){var e,r=t.length,i=-1,o=[];if(null==n)for(;++i<r;)isNaN(e=ds(t[i]))||o.push(e);else for(;++i<r;)isNaN(e=ds(n(t[i],i,t)))||o.push(e);return As(o.sort(ss),.5)},t.merge=Cs,t.min=zs,t.pairs=function(t,n){null==n&&(n=e);for(var r=0,i=t.length-1,o=t[0],u=new Array(i<0?0:i);r<i;)u[r]=n(o,o=t[++r]);return u},t.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},t.quantile=As,t.range=Ms,t.scan=function(t,n){if(e=t.length){var e,r,i=0,o=0,u=t[o];for(null==n&&(n=ss);++i<e;)(n(r=t[i],u)<0||0!==n(u,u))&&(u=r,o=i);return 0===n(u,u)?o:void 0}},t.shuffle=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},t.sum=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},t.ticks=Ss,t.tickIncrement=r,t.tickStep=i,t.transpose=Ps,t.variance=vs,t.zip=function(){return Ps(arguments)},t.axisTop=function(t){return l(qs,t)},t.axisRight=function(t){return l(Us,t)},t.axisBottom=function(t){return l(Ds,t)},t.axisLeft=function(t){return l(Os,t)},t.brush=function(){return he(Sh)},t.brushX=function(){return he(kh)},t.brushY=function(){return he(Nh)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.chord=function(){function t(t){var o,u,a,c,s,f,l=t.length,h=[],p=Ms(l),d=[],v=[],_=v.groups=new Array(l),y=new Array(l*l);for(o=0,s=-1;++s<l;){for(u=0,f=-1;++f<l;)u+=t[s][f];h.push(u),d.push(Ms(l)),o+=u}for(e&&p.sort(function(t,n){return e(h[t],h[n])}),r&&d.forEach(function(n,e){n.sort(function(n,i){return r(t[e][n],t[e][i])})}),c=(o=Oh(0,Dh-n*l)/o)?n:Dh/l,u=0,s=-1;++s<l;){for(a=u,f=-1;++f<l;){var g=p[s],m=d[g][f],x=t[g][m],b=u,w=u+=x*o;y[m*l+g]={index:g,subindex:m,startAngle:b,endAngle:w,value:x}}_[g]={index:g,startAngle:a,endAngle:u,value:h[g]},u+=c}for(s=-1;++s<l;)for(f=s-1;++f<l;){var M=y[f*l+s],T=y[s*l+f];(M.value||T.value)&&v.push(M.value<T.value?{source:T,target:M}:{source:M,target:T})}return i?v.sort(i):v}var n=0,e=null,r=null,i=null;return t.padAngle=function(e){return arguments.length?(n=Oh(0,e),t):n},t.sortGroups=function(n){return arguments.length?(e=n,t):e},t.sortSubgroups=function(n){return arguments.length?(r=n,t):r},t.sortChords=function(n){return arguments.length?(null==n?i=null:(i=pe(n))._=n,t):i&&i._},t},t.ribbon=function(){function t(){var t,a=Fh.call(arguments),c=n.apply(this,a),s=e.apply(this,a),f=+r.apply(this,(a[0]=c,a)),l=i.apply(this,a)-Uh,h=o.apply(this,a)-Uh,p=f*Rh(l),d=f*Lh(l),v=+r.apply(this,(a[0]=s,a)),_=i.apply(this,a)-Uh,y=o.apply(this,a)-Uh;if(u||(u=t=ve()),u.moveTo(p,d),u.arc(0,0,f,l,h),l===_&&h===y||(u.quadraticCurveTo(0,0,v*Rh(_),v*Lh(_)),u.arc(0,0,v,_,y)),u.quadraticCurveTo(0,0,p,d),u.closePath(),t)return u=null,t+""||null}var n=_e,e=ye,r=ge,i=me,o=xe,u=null;return t.radius=function(n){return arguments.length?(r="function"==typeof n?n:Ih(+n),t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:Ih(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:Ih(+n),t):o},t.source=function(e){return arguments.length?(n=e,t):n},t.target=function(n){return arguments.length?(e=n,t):e},t.context=function(n){return arguments.length?(u=null==n?null:n,t):u},t},t.nest=function(){function t(n,i,u,a){if(i>=o.length)return null!=e&&n.sort(e),null!=r?r(n):n;for(var c,s,f,l=-1,h=n.length,p=o[i++],d=we(),v=u();++l<h;)(f=d.get(c=p(s=n[l])+""))?f.push(s):d.set(c,[s]);return d.each(function(n,e){a(v,e,t(n,i,u,a))}),v}function n(t,e){if(++e>o.length)return t;var i,a=u[e-1];return null!=r&&e>=o.length?i=t.entries():(i=[],t.each(function(t,r){i.push({key:r,values:n(t,e)})})),null!=a?i.sort(function(t,n){return a(t.key,n.key)}):i}var e,r,i,o=[],u=[];return i={object:function(n){return t(n,0,Me,Te)},map:function(n){return t(n,0,ke,Ne)},entries:function(e){return n(t(e,0,ke,Ne),0)},key:function(t){return o.push(t),i},sortKeys:function(t){return u[o.length-1]=t,i},sortValues:function(t){return e=t,i},rollup:function(t){return r=t,i}}},t.set=Ee,t.map=we,t.keys=function(t){var n=[];for(var e in t)n.push(e);return n},t.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},t.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},t.color=Tt,t.rgb=Et,t.hsl=Pt,t.lab=Ut,t.hcl=jt,t.cubehelix=$t,t.dispatch=h,t.drag=function(){function n(t){t.on("mousedown.drag",e).filter(bt).on("touchstart.drag",o).on("touchmove.drag",u).on("touchend.drag touchcancel.drag",a).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(){if(!p&&d.apply(this,arguments)){var n=c("mouse",v.apply(this,arguments),Ks,this,arguments);n&&(cf(t.event.view).on("mousemove.drag",r,!0).on("mouseup.drag",i,!0),lf(t.event.view),vt(),l=!1,s=t.event.clientX,f=t.event.clientY,n("start"))}}function r(){if(ff(),!l){var n=t.event.clientX-s,e=t.event.clientY-f;l=n*n+e*e>x}y.mouse("drag")}function i(){cf(t.event.view).on("mousemove.drag mouseup.drag",null),_t(t.event.view,l),ff(),y.mouse("end")}function o(){if(d.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=v.apply(this,arguments),o=r.length;for(n=0;n<o;++n)(e=c(r[n].identifier,i,sf,this,arguments))&&(vt(),e("start"))}}function u(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=y[r[n].identifier])&&(ff(),e("drag"))}function a(){var n,e,r=t.event.changedTouches,i=r.length;for(p&&clearTimeout(p),p=setTimeout(function(){p=null},500),n=0;n<i;++n)(e=y[r[n].identifier])&&(vt(),e("end"))}function c(e,r,i,o,u){var a,c,s,f=i(r,e),l=g.copy();if(N(new yt(n,"beforestart",a,e,m,f[0],f[1],0,0,l),function(){return null!=(t.event.subject=a=_.apply(o,u))&&(c=a.x-f[0]||0,s=a.y-f[1]||0,!0)}))return function t(h){var p,d=f;switch(h){case"start":y[e]=t,p=m++;break;case"end":delete y[e],--m;case"drag":f=i(r,e),p=m}N(new yt(n,h,a,e,p,f[0]+c,f[1]+s,f[0]-d[0],f[1]-d[1],l),l.apply,l,[h,o,u])}}var s,f,l,p,d=gt,v=mt,_=xt,y={},g=h("start","drag","end"),m=0,x=0;return n.filter=function(t){return arguments.length?(d="function"==typeof t?t:hf(!!t),n):d},n.container=function(t){return arguments.length?(v="function"==typeof t?t:hf(t),n):v},n.subject=function(t){return arguments.length?(_="function"==typeof t?t:hf(t),n):_},n.on=function(){var t=g.on.apply(g,arguments);return t===g?n:t},n.clickDistance=function(t){return arguments.length?(x=(t=+t)*t,n):Math.sqrt(x)},n},t.dragDisable=lf,t.dragEnable=_t,t.dsvFormat=Xh,t.csvParse=Vh,t.csvParseRows=Wh,t.csvFormat=Zh,t.csvFormatRows=Gh,t.tsvParse=Qh,t.tsvParseRows=Kh,t.tsvFormat=tp,t.tsvFormatRows=np,t.easeLinear=function(t){return+t},t.easeQuad=Kn,t.easeQuadIn=function(t){return t*t},t.easeQuadOut=function(t){return t*(2-t)},t.easeQuadInOut=Kn,t.easeCubic=te,t.easeCubicIn=function(t){return t*t*t},t.easeCubicOut=function(t){return--t*t*t+1},t.easeCubicInOut=te,t.easePoly=Gl,t.easePolyIn=Wl,t.easePolyOut=Zl,t.easePolyInOut=Gl,t.easeSin=ne,t.easeSinIn=function(t){return 1-Math.cos(t*Ql)},t.easeSinOut=function(t){return Math.sin(t*Ql)},t.easeSinInOut=ne,t.easeExp=ee,t.easeExpIn=function(t){return Math.pow(2,10*t-10)},t.easeExpOut=function(t){return 1-Math.pow(2,-10*t)},t.easeExpInOut=ee,t.easeCircle=re,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCircleInOut=re,t.easeBounce=ie,t.easeBounceIn=function(t){return 1-ie(1-t)},t.easeBounceOut=ie,t.easeBounceInOut=function(t){return((t*=2)<=1?1-ie(1-t):ie(t-1)+1)/2},t.easeBack=lh,t.easeBackIn=sh,t.easeBackOut=fh,t.easeBackInOut=lh,t.easeElastic=dh,t.easeElasticIn=ph,t.easeElasticOut=dh,t.easeElasticInOut=vh,t.forceCenter=function(t,n){function e(){var e,i,o=r.length,u=0,a=0;for(e=0;e<o;++e)u+=(i=r[e]).x,a+=i.y;for(u=u/o-t,a=a/o-n,e=0;e<o;++e)(i=r[e]).x-=u,i.y-=a}var r;return null==t&&(t=0),null==n&&(n=0),e.initialize=function(t){r=t},e.x=function(n){return arguments.length?(t=+n,e):t},e.y=function(t){return arguments.length?(n=+t,e):n},e},t.forceCollide=function(t){function n(){for(var t,n,r,c,s,f,l,h=i.length,p=0;p<a;++p)for(n=qe(i,Oe,Fe).visitAfter(e),t=0;t<h;++t)r=i[t],f=o[r.index],l=f*f,c=r.x+r.vx,s=r.y+r.vy,n.visit(function(t,n,e,i,o){var a=t.data,h=t.r,p=f+h;if(!a)return n>c+p||i<c-p||e>s+p||o<s-p;if(a.index>r.index){var d=c-a.x-a.vx,v=s-a.y-a.vy,_=d*d+v*v;_<p*p&&(0===d&&(d=rp(),_+=d*d),0===v&&(v=rp(),_+=v*v),_=(p-(_=Math.sqrt(_)))/_*u,r.vx+=(d*=_)*(p=(h*=h)/(l+h)),r.vy+=(v*=_)*p,a.vx-=d*(p=1-p),a.vy-=v*p)}})}function e(t){if(t.data)return t.r=o[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function r(){if(i){var n,e,r=i.length;for(o=new Array(r),n=0;n<r;++n)e=i[n],o[e.index]=+t(e,n,i)}}var i,o,u=1,a=1;return"function"!=typeof t&&(t=ep(null==t?1:+t)),n.initialize=function(t){i=t,r()},n.iterations=function(t){return arguments.length?(a=+t,n):a},n.strength=function(t){return arguments.length?(u=+t,n):u},n.radius=function(e){return arguments.length?(t="function"==typeof e?e:ep(+e),r(),n):t},n},t.forceLink=function(t){function n(n){for(var e=0,r=t.length;e<p;++e)for(var i,a,c,f,l,h,d,v=0;v<r;++v)a=(i=t[v]).source,f=(c=i.target).x+c.vx-a.x-a.vx||rp(),l=c.y+c.vy-a.y-a.vy||rp(),f*=h=((h=Math.sqrt(f*f+l*l))-u[v])/h*n*o[v],l*=h,c.vx-=f*(d=s[v]),c.vy-=l*d,a.vx+=f*(d=1-d),a.vy+=l*d}function e(){if(a){var n,e,l=a.length,h=t.length,p=we(a,f);for(n=0,c=new Array(l);n<h;++n)(e=t[n]).index=n,"object"!=typeof e.source&&(e.source=Ye(p,e.source)),"object"!=typeof e.target&&(e.target=Ye(p,e.target)),c[e.source.index]=(c[e.source.index]||0)+1,c[e.target.index]=(c[e.target.index]||0)+1;for(n=0,s=new Array(h);n<h;++n)e=t[n],s[n]=c[e.source.index]/(c[e.source.index]+c[e.target.index]);o=new Array(h),r(),u=new Array(h),i()}}function r(){if(a)for(var n=0,e=t.length;n<e;++n)o[n]=+l(t[n],n,t)}function i(){if(a)for(var n=0,e=t.length;n<e;++n)u[n]=+h(t[n],n,t)}var o,u,a,c,s,f=Ie,l=function(t){return 1/Math.min(c[t.source.index],c[t.target.index])},h=ep(30),p=1;return null==t&&(t=[]),n.initialize=function(t){a=t,e()},n.links=function(r){return arguments.length?(t=r,e(),n):t},n.id=function(t){return arguments.length?(f=t,n):f},n.iterations=function(t){return arguments.length?(p=+t,n):p},n.strength=function(t){return arguments.length?(l="function"==typeof t?t:ep(+t),r(),n):l},n.distance=function(t){return arguments.length?(h="function"==typeof t?t:ep(+t),i(),n):h},n},t.forceManyBody=function(){function t(t){var n,a=i.length,c=qe(i,Be,je).visitAfter(e);for(u=t,n=0;n<a;++n)o=i[n],c.visit(r)}function n(){if(i){var t,n,e=i.length;for(a=new Array(e),t=0;t<e;++t)n=i[t],a[n.index]=+c(n,t,i)}}function e(t){var n,e,r,i,o,u=0;if(t.length){for(r=i=o=0;o<4;++o)(n=t[o])&&(e=n.value)&&(u+=e,r+=e*n.x,i+=e*n.y);t.x=r/u,t.y=i/u}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=a[n.data.index]}while(n=n.next)}t.value=u}function r(t,n,e,r){if(!t.value)return!0;var i=t.x-o.x,c=t.y-o.y,h=r-n,p=i*i+c*c;if(h*h/l<p)return p<f&&(0===i&&(i=rp(),p+=i*i),0===c&&(c=rp(),p+=c*c),p<s&&(p=Math.sqrt(s*p)),o.vx+=i*t.value*u/p,o.vy+=c*t.value*u/p),!0;if(!(t.length||p>=f)){(t.data!==o||t.next)&&(0===i&&(i=rp(),p+=i*i),0===c&&(c=rp(),p+=c*c),p<s&&(p=Math.sqrt(s*p)));do{t.data!==o&&(h=a[t.data.index]*u/p,o.vx+=i*h,o.vy+=c*h)}while(t=t.next)}}var i,o,u,a,c=ep(-30),s=1,f=1/0,l=.81;return t.initialize=function(t){i=t,n()},t.strength=function(e){return arguments.length?(c="function"==typeof e?e:ep(+e),n(),t):c},t.distanceMin=function(n){return arguments.length?(s=n*n,t):Math.sqrt(s)},t.distanceMax=function(n){return arguments.length?(f=n*n,t):Math.sqrt(f)},t.theta=function(n){return arguments.length?(l=n*n,t):Math.sqrt(l)},t},t.forceSimulation=function(t){function n(){e(),d.call("tick",o),u<a&&(p.stop(),d.call("end",o))}function e(){var n,e,r=t.length;for(u+=(s-u)*c,l.each(function(t){t(u)}),n=0;n<r;++n)null==(e=t[n]).fx?e.x+=e.vx*=f:(e.x=e.fx,e.vx=0),null==e.fy?e.y+=e.vy*=f:(e.y=e.fy,e.vy=0)}function r(){for(var n,e=0,r=t.length;e<r;++e){if(n=t[e],n.index=e,isNaN(n.x)||isNaN(n.y)){var i=ap*Math.sqrt(e),o=e*cp;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function i(n){return n.initialize&&n.initialize(t),n}var o,u=1,a=.001,c=1-Math.pow(a,1/300),s=0,f=.6,l=we(),p=dn(n),d=h("tick","end");return null==t&&(t=[]),r(),o={tick:e,restart:function(){return p.restart(n),o},stop:function(){return p.stop(),o},nodes:function(n){return arguments.length?(t=n,r(),l.each(i),o):t},alpha:function(t){return arguments.length?(u=+t,o):u},alphaMin:function(t){return arguments.length?(a=+t,o):a},alphaDecay:function(t){return arguments.length?(c=+t,o):+c},alphaTarget:function(t){return arguments.length?(s=+t,o):s},velocityDecay:function(t){return arguments.length?(f=1-t,o):1-f},force:function(t,n){return arguments.length>1?(null==n?l.remove(t):l.set(t,i(n)),o):l.get(t)},find:function(n,e,r){var i,o,u,a,c,s=0,f=t.length;for(null==r?r=1/0:r*=r,s=0;s<f;++s)(u=(i=n-(a=t[s]).x)*i+(o=e-a.y)*o)<r&&(c=a,r=u);return c},on:function(t,n){return arguments.length>1?(d.on(t,n),o):d.on(t)}}},t.forceX=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)(n=r[e]).vx+=(o[e]-n.x)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=ep(.1);return"function"!=typeof t&&(t=ep(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),e(),n):u},n.x=function(r){return arguments.length?(t="function"==typeof r?r:ep(+r),e(),n):t},n},t.forceY=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)(n=r[e]).vy+=(o[e]-n.y)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=ep(.1);return"function"!=typeof t&&(t=ep(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),e(),n):u},n.y=function(r){return arguments.length?(t="function"==typeof r?r:ep(+r),e(),n):t},n},t.formatDefaultLocale=$e,t.formatLocale=mp,t.formatSpecifier=He,t.precisionFixed=xp,t.precisionPrefix=bp,t.precisionRound=wp,t.geoArea=function(t){return kd.reset(),Md(t,Nd),2*kd},t.geoBounds=function(t){var n,e,r,i,o,u,a;if(Pp=zp=-(Ap=Cp=1/0),Dp=[],Md(t,Ed),e=Dp.length){for(Dp.sort(br),n=1,o=[r=Dp[0]];n<e;++n)wr(r,(i=Dp[n])[0])||wr(r,i[1])?(xr(r[0],i[1])>xr(r[0],r[1])&&(r[1]=i[1]),xr(i[0],r[1])>xr(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(a=xr(r[1],i[0]))>u&&(u=a,Ap=i[0],zp=r[1])}return Dp=Op=null,Ap===1/0||Cp===1/0?[[NaN,NaN],[NaN,NaN]]:[[Ap,Cp],[zp,Pp]]},t.geoCentroid=function(t){Fp=Ip=Yp=Bp=jp=Hp=Xp=$p=Vp=Wp=Zp=0,Md(t,Ad);var n=Vp,e=Wp,r=Zp,i=n*n+e*e+r*r;return i<1e-12&&(n=Hp,e=Xp,r=$p,Ip<ed&&(n=Yp,e=Bp,r=jp),(i=n*n+e*e+r*r)<1e-12)?[NaN,NaN]:[ld(e,n)*ad,Ge(r/md(i))*ad]},t.geoCircle=function(){function t(){var t=r.apply(this,arguments),a=i.apply(this,arguments)*cd,c=o.apply(this,arguments)*cd;return n=[],e=Lr(-t[0]*cd,-t[1]*cd,0).invert,Or(u,a,c,1),t={type:"Polygon",coordinates:[n]},n=e=null,t}var n,e,r=Cd([0,0]),i=Cd(90),o=Cd(6),u={point:function(t,r){n.push(t=e(t,r)),t[0]*=ad,t[1]*=ad}};return t.center=function(n){return arguments.length?(r="function"==typeof n?n:Cd([+n[0],+n[1]]),t):r},t.radius=function(n){return arguments.length?(i="function"==typeof n?n:Cd(+n),t):i},t.precision=function(n){return arguments.length?(o="function"==typeof n?n:Cd(+n),t):o},t},t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,u=500;return e={stream:function(e){return t&&n===e?t:t=Br(r,i,o,u)(n=e)},extent:function(a){return arguments.length?(r=+a[0][0],i=+a[0][1],o=+a[1][0],u=+a[1][1],t=n=null,e):[[r,i],[o,u]]}}},t.geoContains=function(t,n){return(t&&iv.hasOwnProperty(t.type)?iv[t.type]:$r)(t,n)},t.geoDistance=rv,t.geoGraticule=ti,t.geoGraticule10=function(){return ti()()},t.geoInterpolate=function(t,n){var e=t[0]*cd,r=t[1]*cd,i=n[0]*cd,o=n[1]*cd,u=hd(r),a=yd(r),c=hd(o),s=yd(o),f=u*hd(e),l=u*yd(e),h=c*hd(i),p=c*yd(i),d=2*Ge(md(Je(o-r)+u*c*Je(i-e))),v=yd(d),_=d?function(t){var n=yd(t*=d)/v,e=yd(d-t)/v,r=e*f+n*h,i=e*l+n*p,o=e*a+n*s;return[ld(i,r)*ad,ld(o,md(r*r+i*i))*ad]}:function(){return[e*ad,r*ad]};return _.distance=d,_},t.geoLength=tv,t.geoPath=function(t,n){function e(t){return t&&("function"==typeof o&&i.pointRadius(+o.apply(this,arguments)),Md(t,r(i))),i.result()}var r,i,o=4.5;return e.area=function(t){return Md(t,r(sv)),sv.result()},e.measure=function(t){return Md(t,r(zv)),zv.result()},e.bounds=function(t){return Md(t,r(dv)),dv.result()},e.centroid=function(t){return Md(t,r(Tv)),Tv.result()},e.projection=function(n){return arguments.length?(r=null==n?(t=null,uv):(t=n).stream,e):t},e.context=function(t){return arguments.length?(i=null==t?(n=null,new yi):new di(n=t),"function"!=typeof o&&i.pointRadius(o),e):n},e.pointRadius=function(t){return arguments.length?(o="function"==typeof t?t:(i.pointRadius(+t),+t),e):o},e.projection(t).context(n)},t.geoAlbers=Iv,t.geoAlbersUsa=function(){function t(t){var n=t[0],e=t[1];return a=null,i.point(n,e),a||(o.point(n,e),a)||(u.point(n,e),a)}function n(){return e=r=null,t}var e,r,i,o,u,a,c=Iv(),s=Fv().rotate([154,0]).center([-2,58.5]).parallels([55,65]),f=Fv().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(t,n){a=[t,n]}};return t.invert=function(t){var n=c.scale(),e=c.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?f:c).invert(t)},t.stream=function(t){return e&&r===t?e:e=Ri([c.stream(r=t),s.stream(t),f.stream(t)])},t.precision=function(t){return arguments.length?(c.precision(t),s.precision(t),f.precision(t),n()):c.precision()},t.scale=function(n){return arguments.length?(c.scale(n),s.scale(.35*n),f.scale(n),t.translate(c.translate())):c.scale()},t.translate=function(t){if(!arguments.length)return c.translate();var e=c.scale(),r=+t[0],a=+t[1];return i=c.translate(t).clipExtent([[r-.455*e,a-.238*e],[r+.455*e,a+.238*e]]).stream(l),o=s.translate([r-.307*e,a+.201*e]).clipExtent([[r-.425*e+ed,a+.12*e+ed],[r-.214*e-ed,a+.234*e-ed]]).stream(l),u=f.translate([r-.205*e,a+.212*e]).clipExtent([[r-.214*e+ed,a+.166*e+ed],[r-.115*e-ed,a+.234*e-ed]]).stream(l),n()},t.fitExtent=function(n,e){return Ti(t,n,e)},t.fitSize=function(n,e){return ki(t,n,e)},t.scale(1070)},t.geoAzimuthalEqualArea=function(){return Ei(Yv).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Yv,t.geoAzimuthalEquidistant=function(){return Ei(Bv).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=Bv,t.geoConicConformal=function(){return Ci(Fi).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=Fi,t.geoConicEqualArea=Fv,t.geoConicEqualAreaRaw=Pi,t.geoConicEquidistant=function(){return Ci(Yi).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=Yi,t.geoEquirectangular=function(){return Ei(Ii).scale(152.63)},t.geoEquirectangularRaw=Ii,t.geoGnomonic=function(){return Ei(Bi).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=Bi,t.geoIdentity=function(){function t(){return i=o=null,u}var n,e,r,i,o,u,a=1,c=0,s=0,f=1,l=1,h=uv,p=null,d=uv;return u={stream:function(t){return i&&o===t?i:i=h(d(o=t))},clipExtent:function(i){return arguments.length?(d=null==i?(p=n=e=r=null,uv):Br(p=+i[0][0],n=+i[0][1],e=+i[1][0],r=+i[1][1]),t()):null==p?null:[[p,n],[e,r]]},scale:function(n){return arguments.length?(h=ji((a=+n)*f,a*l,c,s),t()):a},translate:function(n){return arguments.length?(h=ji(a*f,a*l,c=+n[0],s=+n[1]),t()):[c,s]},reflectX:function(n){return arguments.length?(h=ji(a*(f=n?-1:1),a*l,c,s),t()):f<0},reflectY:function(n){return arguments.length?(h=ji(a*f,a*(l=n?-1:1),c,s),t()):l<0},fitExtent:function(t,n){return Ti(u,t,n)},fitSize:function(t,n){return ki(u,t,n)}}},t.geoProjection=Ei,t.geoProjectionMutator=Ai,t.geoMercator=function(){return Di(Ui).scale(961/ud)},t.geoMercatorRaw=Ui,t.geoOrthographic=function(){return Ei(Hi).scale(249.5).clipAngle(90+ed)},t.geoOrthographicRaw=Hi,t.geoStereographic=function(){return Ei(Xi).scale(250).clipAngle(142)},t.geoStereographicRaw=Xi,t.geoTransverseMercator=function(){var t=Di($i),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):(t=n(),[t[1],-t[0]])},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):(t=e(),[t[0],t[1],t[2]-90])},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=$i,t.geoRotation=jd,t.geoStream=Md,t.geoTransform=function(t){return{stream:wi(t)}},t.cluster=function(){function t(t){var o,u=0;t.eachAfter(function(t){var e=t.children;e?(t.x=Wi(e),t.y=Gi(e)):(t.x=o?u+=n(t,o):0,t.y=0,o=t)});var a=Qi(t),c=Ki(t),s=a.x-n(a,c)/2,f=c.x+n(c,a)/2;return t.eachAfter(i?function(n){n.x=(n.x-t.x)*e,n.y=(t.y-n.y)*r}:function(n){n.x=(n.x-s)/(f-s)*e,n.y=(1-(t.y?n.y/t.y:1))*r})}var n=Vi,e=1,r=1,i=!1;return t.separation=function(e){return arguments.length?(n=e,t):n},t.size=function(n){return arguments.length?(i=!1,e=+n[0],r=+n[1],t):i?null:[e,r]},t.nodeSize=function(n){return arguments.length?(i=!0,e=+n[0],r=+n[1],t):i?[e,r]:null},t},t.hierarchy=eo,t.pack=function(){function t(t){return t.x=e/2,t.y=r/2,n?t.eachBefore(No(n)).eachAfter(So(i,.5)).eachBefore(Eo(1)):t.eachBefore(No(ko)).eachAfter(So(To,1)).eachAfter(So(i,t.r/Math.min(e,r))).eachBefore(Eo(Math.min(e,r)/(2*t.r))),t}var n=null,e=1,r=1,i=To;return t.radius=function(e){return arguments.length?(n=wo(e),t):n},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i="function"==typeof n?n:Xv(+n),t):i},t},t.packSiblings=function(t){return bo(t),t},t.packEnclose=Hv,t.partition=function(){function t(t){var u=t.height+1;return t.x0=t.y0=i,t.x1=e,t.y1=r/u,t.eachBefore(n(r,u)),o&&t.eachBefore($v),t}function n(t,n){return function(e){e.children&&Vv(e,e.x0,t*(e.depth+1)/n,e.x1,t*(e.depth+2)/n);var r=e.x0,o=e.y0,u=e.x1-i,a=e.y1-i;u<r&&(r=u=(r+u)/2),a<o&&(o=a=(o+a)/2),e.x0=r,e.y0=o,e.x1=u,e.y1=a}}var e=1,r=1,i=0,o=!1;return t.round=function(n){return arguments.length?(o=!!n,t):o},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i=+n,t):i},t},t.stratify=function(){function t(t){var r,i,o,u,a,c,s,f=t.length,l=new Array(f),h={};for(i=0;i<f;++i)r=t[i],a=l[i]=new uo(r),null!=(c=n(r,i,t))&&(c+="")&&(h[s=Wv+(a.id=c)]=s in h?Gv:a);for(i=0;i<f;++i)if(a=l[i],null!=(c=e(t[i],i,t))&&(c+="")){if(!(u=h[Wv+c]))throw new Error("missing: "+c);if(u===Gv)throw new Error("ambiguous: "+c);u.children?u.children.push(a):u.children=[a],a.parent=u}else{if(o)throw new Error("multiple roots");o=a}if(!o)throw new Error("no root");if(o.parent=Zv,o.eachBefore(function(t){t.depth=t.parent.depth+1,--f}).eachBefore(oo),o.parent=null,f>0)throw new Error("cycle");return o}var n=Ao,e=Co;return t.id=function(e){return arguments.length?(n=Mo(e),t):n},t.parentId=function(n){return arguments.length?(e=Mo(n),t):e},t},t.tree=function(){function t(t){var r=Oo(t);if(r.eachAfter(n),r.parent.m=-r.z,r.eachBefore(e),c)t.eachBefore(i);else{var s=t,f=t,l=t;t.eachBefore(function(t){t.x<s.x&&(s=t),t.x>f.x&&(f=t),t.depth>l.depth&&(l=t)});var h=s===f?1:o(s,f)/2,p=h-s.x,d=u/(f.x+h+p),v=a/(l.depth||1);t.eachBefore(function(t){t.x=(t.x+p)*d,t.y=t.depth*v})}return t}function n(t){var n=t.children,e=t.parent.children,i=t.i?e[t.i-1]:null;if(n){qo(t);var u=(n[0].z+n[n.length-1].z)/2;i?(t.z=i.z+o(t._,i._),t.m=t.z-u):t.z=u}else i&&(t.z=i.z+o(t._,i._));t.parent.A=r(t,i,t.parent.A||e[0])}function e(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function r(t,n,e){if(n){for(var r,i=t,u=t,a=n,c=i.parent.children[0],s=i.m,f=u.m,l=a.m,h=c.m;a=Ro(a),i=Po(i),a&&i;)c=Po(c),(u=Ro(u)).a=t,(r=a.z+l-i.z-s+o(a._,i._))>0&&(Lo(Uo(a,t,e),t,r),s+=r,f+=r),l+=a.m,s+=i.m,h+=c.m,f+=u.m;a&&!Ro(u)&&(u.t=a,u.m+=l-f),i&&!Po(c)&&(c.t=i,c.m+=s-h,e=t)}return e}function i(t){t.x*=u,t.y=t.depth*a}var o=zo,u=1,a=1,c=null;return t.separation=function(n){return arguments.length?(o=n,t):o},t.size=function(n){return arguments.length?(c=!1,u=+n[0],a=+n[1],t):c?null:[u,a]},t.nodeSize=function(n){return arguments.length?(c=!0,u=+n[0],a=+n[1],t):c?[u,a]:null},t},t.treemap=function(){function t(t){return t.x0=t.y0=0,t.x1=i,t.y1=o,t.eachBefore(n),u=[0],r&&t.eachBefore($v),t}function n(t){var n=u[t.depth],r=t.x0+n,i=t.y0+n,o=t.x1-n,h=t.y1-n;o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),t.x0=r,t.y0=i,t.x1=o,t.y1=h,t.children&&(n=u[t.depth+1]=a(t)/2,r+=l(t)-n,i+=c(t)-n,o-=s(t)-n,h-=f(t)-n,o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),e(t,r,i,o,h))}var e=Kv,r=!1,i=1,o=1,u=[0],a=To,c=To,s=To,f=To,l=To;return t.round=function(n){return arguments.length?(r=!!n,t):r},t.size=function(n){return arguments.length?(i=+n[0],o=+n[1],t):[i,o]},t.tile=function(n){return arguments.length?(e=Mo(n),t):e},t.padding=function(n){return arguments.length?t.paddingInner(n).paddingOuter(n):t.paddingInner()},t.paddingInner=function(n){return arguments.length?(a="function"==typeof n?n:Xv(+n),t):a},t.paddingOuter=function(n){return arguments.length?t.paddingTop(n).paddingRight(n).paddingBottom(n).paddingLeft(n):t.paddingTop()},t.paddingTop=function(n){return arguments.length?(c="function"==typeof n?n:Xv(+n),t):c},t.paddingRight=function(n){return arguments.length?(s="function"==typeof n?n:Xv(+n),t):s},t.paddingBottom=function(n){return arguments.length?(f="function"==typeof n?n:Xv(+n),t):f},t.paddingLeft=function(n){return arguments.length?(l="function"==typeof n?n:Xv(+n),t):l},t},t.treemapBinary=function(t,n,e,r,i){function o(t,n,e,r,i,u,a){if(t>=n-1){var s=c[t];return s.x0=r,s.y0=i,s.x1=u,void(s.y1=a)}for(var l=f[t],h=e/2+l,p=t+1,d=n-1;p<d;){var v=p+d>>>1;f[v]<h?p=v+1:d=v}h-f[p-1]<f[p]-h&&t+1<p&&--p;var _=f[p]-l,y=e-_;if(u-r>a-i){var g=(r*y+u*_)/e;o(t,p,_,r,i,g,a),o(p,n,y,g,i,u,a)}else{var m=(i*y+a*_)/e;o(t,p,_,r,i,u,m),o(p,n,y,r,m,u,a)}}var u,a,c=t.children,s=c.length,f=new Array(s+1);for(f[0]=a=u=0;u<s;++u)f[u+1]=a+=c[u].value;o(0,s,t.value,n,e,r,i)},t.treemapDice=Vv,t.treemapSlice=Jv,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Jv:Vv)(t,n,e,r,i)},t.treemapSquarify=Kv,t.treemapResquarify=t_,t.interpolate=cl,t.interpolateArray=nl,t.interpolateBasis=Zf,t.interpolateBasisClosed=Gf,t.interpolateDate=el,t.interpolateNumber=rl,t.interpolateObject=il,t.interpolateRound=sl,t.interpolateString=al,t.interpolateTransformCss=pl,t.interpolateTransformSvg=dl,t.interpolateZoom=_l,t.interpolateRgb=Qf,t.interpolateRgbBasis=Kf,t.interpolateRgbBasisClosed=tl,t.interpolateHsl=yl,t.interpolateHslLong=gl,t.interpolateLab=function(t,n){var e=Kt((t=Ut(t)).l,(n=Ut(n)).l),r=Kt(t.a,n.a),i=Kt(t.b,n.b),o=Kt(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateHcl=ml,t.interpolateHclLong=xl,t.interpolateCubehelix=bl,t.interpolateCubehelixLong=wl,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.path=ve,t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,u=0,a=t[i-1],c=0;++r<i;)n=a,a=t[r],c+=e=n[0]*a[1]-a[0]*n[1],o+=(n[0]+a[0])*e,u+=(n[1]+a[1])*e;return c*=3,[o/c,u/c]},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(Io),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=Yo(r),u=Yo(i),a=u[0]===o[0],c=u[u.length-1]===o[o.length-1],s=[];for(n=o.length-1;n>=0;--n)s.push(t[r[o[n]][2]]);for(n=+a;n<u.length-c;++n)s.push(t[r[u[n]][2]]);return s},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],u=n[0],a=n[1],c=o[0],s=o[1],f=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>a!=s>a&&u<(c-e)*(a-r)/(s-r)+e&&(f=!f),c=e,s=r;return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],u=o[0],a=o[1],c=0;++r<i;)n=u,e=a,n-=u=(o=t[r])[0],e-=a=o[1],c+=Math.sqrt(n*n+e*e);return c},t.quadtree=qe,t.queue=Wo,t.randomUniform=o_,t.randomNormal=u_,t.randomLogNormal=a_,t.randomBates=s_,t.randomIrwinHall=c_,t.randomExponential=f_,t.request=l_,t.html=p_,t.json=d_,t.text=v_,t.xml=__,t.csv=g_,t.tsv=m_,t.scaleBand=Ko,t.scalePoint=function(){return tu(Ko().paddingInner(1))},t.scaleIdentity=fu,t.scaleLinear=su,t.scaleLog=yu,t.scaleOrdinal=Qo,t.scaleImplicit=M_,t.scalePow=mu,t.scaleSqrt=function(){return mu().exponent(.5)},t.scaleQuantile=xu,t.scaleQuantize=bu,t.scaleThreshold=wu,t.scaleTime=function(){return Na(oy,ry,j_,Y_,F_,D_,q_,z_,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)])},t.scaleUtc=function(){return Na(Ay,Sy,py,ly,sy,ay,q_,z_,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)])},t.schemeCategory10=$y,t.schemeCategory20b=Vy,t.schemeCategory20c=Wy,t.schemeCategory20=Zy,t.interpolateCubehelixDefault=Gy,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return Ky.h=360*t-100,Ky.s=1.5-1.5*n,Ky.l=.8-.9*n,Ky+""},t.interpolateWarm=Jy,t.interpolateCool=Qy,t.interpolateViridis=tg,t.interpolateMagma=ng,t.interpolateInferno=eg,t.interpolatePlasma=rg,t.scaleSequential=Ea,t.creator=Hs,t.local=m,t.matcher=Zs,t.mouse=Ks,t.namespace=js,t.namespaces=Bs,t.select=cf,t.selectAll=function(t){return"string"==typeof t?new pt([document.querySelectorAll(t)],[document.documentElement]):new pt([null==t?[]:t],af)},t.selection=dt,t.selector=tf,t.selectorAll=nf,t.style=B,t.touch=sf,t.touches=function(t,n){null==n&&(n=Js().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Qs(t,n[e]);return i},t.window=uf,t.customEvent=N,t.arc=function(){function t(){var t,s,f=+n.apply(this,arguments),l=+e.apply(this,arguments),h=o.apply(this,arguments)-dg,p=u.apply(this,arguments)-dg,d=og(p-h),v=p>h;if(c||(c=t=ve()),l<f&&(s=l,l=f,f=s),l>hg)if(d>vg-hg)c.moveTo(l*ag(h),l*fg(h)),c.arc(0,0,l,h,p,!v),f>hg&&(c.moveTo(f*ag(p),f*fg(p)),c.arc(0,0,f,p,h,v));else{var _,y,g=h,m=p,x=h,b=p,w=d,M=d,T=a.apply(this,arguments)/2,k=T>hg&&(i?+i.apply(this,arguments):lg(f*f+l*l)),N=sg(og(l-f)/2,+r.apply(this,arguments)),S=N,E=N;if(k>hg){var A=Ca(k/f*fg(T)),C=Ca(k/l*fg(T));(w-=2*A)>hg?(A*=v?1:-1,x+=A,b-=A):(w=0,x=b=(h+p)/2),(M-=2*C)>hg?(C*=v?1:-1,g+=C,m-=C):(M=0,g=m=(h+p)/2)}var z=l*ag(g),P=l*fg(g),R=f*ag(b),L=f*fg(b);if(N>hg){var q=l*ag(m),U=l*fg(m),D=f*ag(x),O=f*fg(x);if(d<pg){var F=w>hg?Ua(z,P,D,O,q,U,R,L):[R,L],I=z-F[0],Y=P-F[1],B=q-F[0],j=U-F[1],H=1/fg(Aa((I*B+Y*j)/(lg(I*I+Y*Y)*lg(B*B+j*j)))/2),X=lg(F[0]*F[0]+F[1]*F[1]);S=sg(N,(f-X)/(H-1)),E=sg(N,(l-X)/(H+1))}}M>hg?E>hg?(_=Da(D,O,z,P,l,E,v),y=Da(q,U,R,L,l,E,v),c.moveTo(_.cx+_.x01,_.cy+_.y01),E<N?c.arc(_.cx,_.cy,E,ug(_.y01,_.x01),ug(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,E,ug(_.y01,_.x01),ug(_.y11,_.x11),!v),c.arc(0,0,l,ug(_.cy+_.y11,_.cx+_.x11),ug(y.cy+y.y11,y.cx+y.x11),!v),c.arc(y.cx,y.cy,E,ug(y.y11,y.x11),ug(y.y01,y.x01),!v))):(c.moveTo(z,P),c.arc(0,0,l,g,m,!v)):c.moveTo(z,P),f>hg&&w>hg?S>hg?(_=Da(R,L,q,U,f,-S,v),y=Da(z,P,D,O,f,-S,v),c.lineTo(_.cx+_.x01,_.cy+_.y01),S<N?c.arc(_.cx,_.cy,S,ug(_.y01,_.x01),ug(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,S,ug(_.y01,_.x01),ug(_.y11,_.x11),!v),c.arc(0,0,f,ug(_.cy+_.y11,_.cx+_.x11),ug(y.cy+y.y11,y.cx+y.x11),v),c.arc(y.cx,y.cy,S,ug(y.y11,y.x11),ug(y.y01,y.x01),!v))):c.arc(0,0,f,b,x,v):c.lineTo(R,L)}else c.moveTo(0,0);if(c.closePath(),t)return c=null,t+""||null}var n=za,e=Pa,r=ig(0),i=null,o=Ra,u=La,a=qa,c=null;return t.centroid=function(){var t=(+n.apply(this,arguments)+ +e.apply(this,arguments))/2,r=(+o.apply(this,arguments)+ +u.apply(this,arguments))/2-pg/2;return[ag(r)*t,fg(r)*t]},t.innerRadius=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.outerRadius=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.cornerRadius=function(n){return arguments.length?(r="function"==typeof n?n:ig(+n),t):r},t.padRadius=function(n){return arguments.length?(i=null==n?null:"function"==typeof n?n:ig(+n),t):i},t.startAngle=function(n){return arguments.length?(o="function"==typeof n?n:ig(+n),t):o},t.endAngle=function(n){return arguments.length?(u="function"==typeof n?n:ig(+n),t):u},t.padAngle=function(n){return arguments.length?(a="function"==typeof n?n:ig(+n),t):a},t.context=function(n){return arguments.length?(c=null==n?null:n,t):c},t},t.area=gg,t.line=yg,t.pie=function(){function t(t){var a,c,s,f,l,h=t.length,p=0,d=new Array(h),v=new Array(h),_=+i.apply(this,arguments),y=Math.min(vg,Math.max(-vg,o.apply(this,arguments)-_)),g=Math.min(Math.abs(y)/h,u.apply(this,arguments)),m=g*(y<0?-1:1);for(a=0;a<h;++a)(l=v[d[a]=a]=+n(t[a],a,t))>0&&(p+=l);for(null!=e?d.sort(function(t,n){return e(v[t],v[n])}):null!=r&&d.sort(function(n,e){return r(t[n],t[e])}),a=0,s=p?(y-h*m)/p:0;a<h;++a,_=f)c=d[a],f=_+((l=v[c])>0?l*s:0)+m,v[c]={data:t[c],index:a,value:l,startAngle:_,endAngle:f,padAngle:g};return v}var n=xg,e=mg,r=null,i=ig(0),o=ig(vg),u=ig(0);return t.value=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.sortValues=function(n){return arguments.length?(e=n,r=null,t):e},t.sort=function(n){return arguments.length?(r=n,e=null,t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:ig(+n),t):o},t.padAngle=function(n){return arguments.length?(u="function"==typeof n?n:ig(+n),t):u},t},t.areaRadial=Mg,t.radialArea=Mg,t.lineRadial=wg,t.radialLine=wg,t.pointRadial=Tg,t.linkHorizontal=function(){return $a(Va)},t.linkVertical=function(){return $a(Wa)},t.linkRadial=function(){var t=$a(Za);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.symbol=function(){function t(){var t;if(r||(r=t=ve()),n.apply(this,arguments).draw(r,+e.apply(this,arguments)),t)return r=null,t+""||null}var n=ig(Ng),e=ig(64),r=null;return t.type=function(e){return arguments.length?(n="function"==typeof e?e:ig(e),t):n},t.size=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.context=function(n){return arguments.length?(r=null==n?null:n,t):r},t},t.symbols=jg,t.symbolCircle=Ng,t.symbolCross=Sg,t.symbolDiamond=Cg,t.symbolSquare=qg,t.symbolStar=Lg,t.symbolTriangle=Dg,t.symbolWye=Bg,t.curveBasisClosed=function(t){return new Qa(t)},t.curveBasisOpen=function(t){return new Ka(t)},t.curveBasis=function(t){return new Ja(t)},t.curveBundle=Xg,t.curveCardinalClosed=Vg,t.curveCardinalOpen=Wg,t.curveCardinal=$g,t.curveCatmullRomClosed=Gg,t.curveCatmullRomOpen=Jg,t.curveCatmullRom=Zg,t.curveLinearClosed=function(t){return new sc(t)},t.curveLinear=_g,t.curveMonotoneX=function(t){return new dc(t)},t.curveMonotoneY=function(t){return new vc(t)},t.curveNatural=function(t){return new yc(t)},t.curveStep=function(t){return new mc(t,.5)},t.curveStepAfter=function(t){return new mc(t,1)},t.curveStepBefore=function(t){return new mc(t,0)},t.stack=function(){function t(t){var o,u,a=n.apply(this,arguments),c=t.length,s=a.length,f=new Array(s);for(o=0;o<s;++o){for(var l,h=a[o],p=f[o]=new Array(c),d=0;d<c;++d)p[d]=l=[0,+i(t[d],h,d,t)],l.data=t[d];p.key=h}for(o=0,u=e(f);o<s;++o)f[u[o]].index=o;return r(f,u),f}var n=ig([]),e=Kg,r=Qg,i=xc;return t.keys=function(e){return arguments.length?(n="function"==typeof e?e:ig(kg.call(e)),t):n},t.value=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.order=function(n){return arguments.length?(e=null==n?Kg:"function"==typeof n?n:ig(kg.call(n)),t):e},t.offset=function(n){return arguments.length?(r=null==n?Qg:n,t):r},t},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,u=t[0].length;o<u;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}Qg(t,n)}},t.stackOffsetDiverging=function(t,n){if((a=t.length)>1)for(var e,r,i,o,u,a,c=0,s=t[n[0]].length;c<s;++c)for(o=u=0,e=0;e<a;++e)(i=(r=t[n[e]][c])[1]-r[0])>=0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=u,r[0]=u+=i):r[0]=o},t.stackOffsetNone=Qg,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var u=0,a=0;u<e;++u)a+=t[u][r][1]||0;i[r][1]+=i[r][0]=-a/2}Qg(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,u=1;u<r;++u){for(var a=0,c=0,s=0;a<i;++a){for(var f=t[n[a]],l=f[u][1]||0,h=(l-(f[u-1][1]||0))/2,p=0;p<a;++p){var d=t[n[p]];h+=(d[u][1]||0)-(d[u-1][1]||0)}c+=l,s+=h*l}e[u-1][1]+=e[u-1][0]=o,c&&(o-=s/c)}e[u-1][1]+=e[u-1][0]=o,Qg(t,n)}},t.stackOrderAscending=tm,t.stackOrderDescending=function(t){return tm(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(bc),o=Kg(t).sort(function(t,n){return i[n]-i[t]}),u=0,a=0,c=[],s=[];for(n=0;n<r;++n)e=o[n],u<a?(u+=i[e],c.push(e)):(a+=i[e],s.push(e));return s.reverse().concat(c)},t.stackOrderNone=Kg,t.stackOrderReverse=function(t){return Kg(t).reverse()},t.timeInterval=Mu,t.timeMillisecond=z_,t.timeMilliseconds=P_,t.utcMillisecond=z_,t.utcMilliseconds=P_,t.timeSecond=q_,t.timeSeconds=U_,t.utcSecond=q_,t.utcSeconds=U_,t.timeMinute=D_,t.timeMinutes=O_,t.timeHour=F_,t.timeHours=I_,t.timeDay=Y_,t.timeDays=B_,t.timeWeek=j_,t.timeWeeks=G_,t.timeSunday=j_,t.timeSundays=G_,t.timeMonday=H_,t.timeMondays=J_,t.timeTuesday=X_,t.timeTuesdays=Q_,t.timeWednesday=$_,t.timeWednesdays=K_,t.timeThursday=V_,t.timeThursdays=ty,t.timeFriday=W_,t.timeFridays=ny,t.timeSaturday=Z_,t.timeSaturdays=ey,t.timeMonth=ry,t.timeMonths=iy,t.timeYear=oy,t.timeYears=uy,t.utcMinute=ay,t.utcMinutes=cy,t.utcHour=sy,t.utcHours=fy,t.utcDay=ly,t.utcDays=hy,t.utcWeek=py,t.utcWeeks=xy,t.utcSunday=py,t.utcSundays=xy,t.utcMonday=dy,t.utcMondays=by,t.utcTuesday=vy,t.utcTuesdays=wy,t.utcWednesday=_y,t.utcWednesdays=My,t.utcThursday=yy,t.utcThursdays=Ty,t.utcFriday=gy,t.utcFridays=ky,t.utcSaturday=my,t.utcSaturdays=Ny,t.utcMonth=Sy,t.utcMonths=Ey,t.utcYear=Ay,t.utcYears=zy,t.timeFormatDefaultLocale=Ma,t.timeFormatLocale=Au,t.isoFormat=Uy,t.isoParse=Dy,t.now=ln,t.timer=dn,t.timerFlush=vn,t.timeout=Pl,t.interval=function(t,n,e){var r=new pn,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?ln():+e,r.restart(function o(u){u+=i,r.restart(o,i+=n,e),t(u)},n,e),r)},t.transition=Jn,t.active=function(t,n){var e,r,i=t.__transition;if(i){n=null==n?null:n+"";for(r in i)if((e=i[r]).state>Ul&&e.name===n)return new Gn([[t]],yh,n,+r)}return null},t.interrupt=jl,t.voronoi=function(){function t(t){return new Kc(t.map(function(r,i){var o=[Math.round(n(r,i,t)/sm)*sm,Math.round(e(r,i,t)/sm)*sm];return o.index=i,o.data=r,o}),r)}var n=wc,e=Mc,r=null;return t.polygons=function(n){return t(n).polygons()},t.links=function(n){return t(n).links()},t.triangles=function(n){return t(n).triangles()},t.x=function(e){return arguments.length?(n="function"==typeof e?e:nm(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:nm(+n),t):e},t.extent=function(n){return arguments.length?(r=null==n?null:[[+n[0][0],+n[0][1]],[+n[1][0],+n[1][1]]],t):r&&[[r[0][0],r[0][1]],[r[1][0],r[1][1]]]},t.size=function(n){return arguments.length?(r=null==n?null:[[0,0],[+n[0],+n[1]]],t):r&&[r[1][0]-r[0][0],r[1][1]-r[0][1]]},t},t.zoom=function(){function n(t){t.property("__zoom",us).on("wheel.zoom",s).on("mousedown.zoom",f).on("dblclick.zoom",l).filter(cs).on("touchstart.zoom",p).on("touchmove.zoom",d).on("touchend.zoom touchcancel.zoom",v).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(t,n){return(n=Math.max(b,Math.min(w,n)))===t.k?t:new ns(n,t.x,t.y)}function r(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ns(t.k,r,i)}function i(t,n){var e=t.invertX(n[0][0])-M,r=t.invertX(n[1][0])-T,i=t.invertY(n[0][1])-k,o=t.invertY(n[1][1])-S;return t.translate(r>e?(e+r)/2:Math.min(0,e)||Math.max(0,r),o>i?(i+o)/2:Math.min(0,i)||Math.max(0,o))}function o(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function u(t,n,e){t.on("start.zoom",function(){a(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){a(this,arguments).end()}).tween("zoom",function(){var t=this,r=arguments,i=a(t,r),u=m.apply(t,r),c=e||o(u),s=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),f=t.__zoom,l="function"==typeof n?n.apply(t,r):n,h=A(f.invert(c).concat(s/f.k),l.invert(c).concat(s/l.k));return function(t){if(1===t)t=l;else{var n=h(t),e=s/n[2];t=new ns(e,c[0]-n[0]*e,c[1]-n[1]*e)}i.zoom(null,t)}})}function a(t,n){for(var e,r=0,i=C.length;r<i;++r)if((e=C[r]).that===t)return e;return new c(t,n)}function c(t,n){this.that=t,this.args=n,this.index=-1,this.active=0,this.extent=m.apply(t,n)}function s(){if(g.apply(this,arguments)){var t=a(this,arguments),n=this.__zoom,o=Math.max(b,Math.min(w,n.k*Math.pow(2,x.apply(this,arguments)))),u=Ks(this);if(t.wheel)t.mouse[0][0]===u[0]&&t.mouse[0][1]===u[1]||(t.mouse[1]=n.invert(t.mouse[0]=u)),clearTimeout(t.wheel);else{if(n.k===o)return;t.mouse=[u,n.invert(u)],jl(this),t.start()}pm(),t.wheel=setTimeout(function(){t.wheel=null,t.end()},R),t.zoom("mouse",i(r(e(n,o),t.mouse[0],t.mouse[1]),t.extent))}}function f(){if(!y&&g.apply(this,arguments)){var n=a(this,arguments),e=cf(t.event.view).on("mousemove.zoom",function(){if(pm(),!n.moved){var e=t.event.clientX-u,o=t.event.clientY-c;n.moved=e*e+o*o>L}n.zoom("mouse",i(r(n.that.__zoom,n.mouse[0]=Ks(n.that),n.mouse[1]),n.extent))},!0).on("mouseup.zoom",function(){e.on("mousemove.zoom mouseup.zoom",null),_t(t.event.view,n.moved),pm(),n.end()},!0),o=Ks(this),u=t.event.clientX,c=t.event.clientY;lf(t.event.view),rs(),n.mouse=[o,this.__zoom.invert(o)],jl(this),n.start()}}function l(){if(g.apply(this,arguments)){var o=this.__zoom,a=Ks(this),c=o.invert(a),s=i(r(e(o,o.k*(t.event.shiftKey?.5:2)),a,c),m.apply(this,arguments));pm(),E>0?cf(this).transition().duration(E).call(u,s,a):cf(this).call(n.transform,s)}}function p(){if(g.apply(this,arguments)){var n,e,r,i,o=a(this,arguments),u=t.event.changedTouches,c=u.length;for(rs(),e=0;e<c;++e)r=u[e],i=[i=sf(this,u,r.identifier),this.__zoom.invert(i),r.identifier],o.touch0?o.touch1||(o.touch1=i):(o.touch0=i,n=!0);if(_&&(_=clearTimeout(_),!o.touch1))return o.end(),void((i=cf(this).on("dblclick.zoom"))&&i.apply(this,arguments));n&&(_=setTimeout(function(){_=null},P),jl(this),o.start())}}function d(){var n,o,u,c,s=a(this,arguments),f=t.event.changedTouches,l=f.length;for(pm(),_&&(_=clearTimeout(_)),n=0;n<l;++n)o=f[n],u=sf(this,f,o.identifier),s.touch0&&s.touch0[2]===o.identifier?s.touch0[0]=u:s.touch1&&s.touch1[2]===o.identifier&&(s.touch1[0]=u);if(o=s.that.__zoom,s.touch1){var h=s.touch0[0],p=s.touch0[1],d=s.touch1[0],v=s.touch1[1],y=(y=d[0]-h[0])*y+(y=d[1]-h[1])*y,g=(g=v[0]-p[0])*g+(g=v[1]-p[1])*g;o=e(o,Math.sqrt(y/g)),u=[(h[0]+d[0])/2,(h[1]+d[1])/2],c=[(p[0]+v[0])/2,(p[1]+v[1])/2]}else{if(!s.touch0)return;u=s.touch0[0],c=s.touch0[1]}s.zoom("touch",i(r(o,u,c),s.extent))}function v(){var n,e,r=a(this,arguments),i=t.event.changedTouches,o=i.length;for(rs(),y&&clearTimeout(y),y=setTimeout(function(){y=null},P),n=0;n<o;++n)e=i[n],r.touch0&&r.touch0[2]===e.identifier?delete r.touch0:r.touch1&&r.touch1[2]===e.identifier&&delete r.touch1;r.touch1&&!r.touch0&&(r.touch0=r.touch1,delete r.touch1),r.touch0?r.touch0[1]=this.__zoom.invert(r.touch0[0]):r.end()}var _,y,g=is,m=os,x=as,b=0,w=1/0,M=-w,T=w,k=M,S=T,E=250,A=_l,C=[],z=h("start","zoom","end"),P=500,R=150,L=0;return n.transform=function(t,n){var e=t.selection?t.selection():t;e.property("__zoom",us),t!==e?u(t,n):e.interrupt().each(function(){a(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},n.scaleBy=function(t,e){n.scaleTo(t,function(){return this.__zoom.k*("function"==typeof e?e.apply(this,arguments):e)})},n.scaleTo=function(t,u){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,a=o(t),c=n.invert(a);return i(r(e(n,"function"==typeof u?u.apply(this,arguments):u),a,c),t)})},n.translateBy=function(t,e,r){n.transform(t,function(){return i(this.__zoom.translate("function"==typeof e?e.apply(this,arguments):e,"function"==typeof r?r.apply(this,arguments):r),m.apply(this,arguments))})},n.translateTo=function(t,e,r){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,u=o(t);return i(hm.translate(u[0],u[1]).scale(n.k).translate("function"==typeof e?-e.apply(this,arguments):-e,"function"==typeof r?-r.apply(this,arguments):-r),t)})},c.prototype={start:function(){return 1==++this.active&&(this.index=C.push(this)-1,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(C.splice(this.index,1),this.index=-1,this.emit("end")),this},emit:function(t){N(new ts(n,t,this.that.__zoom),z.apply,z,[t,this.that,this.args])}},n.wheelDelta=function(t){return arguments.length?(x="function"==typeof t?t:lm(+t),n):x},n.filter=function(t){return arguments.length?(g="function"==typeof t?t:lm(!!t),n):g},n.extent=function(t){return arguments.length?(m="function"==typeof t?t:lm([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),n):m},n.scaleExtent=function(t){return arguments.length?(b=+t[0],w=+t[1],n):[b,w]},n.translateExtent=function(t){return arguments.length?(M=+t[0][0],T=+t[1][0],k=+t[0][1],S=+t[1][1],n):[[M,k],[T,S]]},n.duration=function(t){return arguments.length?(E=+t,n):E},n.interpolate=function(t){return arguments.length?(A=t,n):A},n.on=function(){var t=z.on.apply(z,arguments);return t===z?n:t},n.clickDistance=function(t){return arguments.length?(L=(t=+t)*t,n):Math.sqrt(L)},n},t.zoomTransform=es,t.zoomIdentity=hm,Object.defineProperty(t,"__esModule",{value:!0})});
\ No newline at end of file +// https://d3js.org Version 4.10.0. Copyright 2017 Mike Bostock. +(function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})})(this,function(t){"use strict";function n(t){return function(n,e){return ss(t(n),e)}}function e(t,n){return[t,n]}function r(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=Ts?10:o>=ks?5:o>=Ns?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=Ts?10:o>=ks?5:o>=Ns?2:1)}function i(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=Ts?i*=10:o>=ks?i*=5:o>=Ns&&(i*=2),n<t?-i:i}function o(t){return t.length}function u(t){return"translate("+(t+.5)+",0)"}function a(t){return"translate(0,"+(t+.5)+")"}function c(t){return function(n){return+t(n)}}function s(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}function f(){return!this.__axis}function l(t,n){function e(e){var u=null==i?n.ticks?n.ticks.apply(n,r):n.domain():i,a=null==o?n.tickFormat?n.tickFormat.apply(n,r):Ls:o,y=Math.max(l,0)+p,g=n.range(),m=+g[0]+.5,x=+g[g.length-1]+.5,b=(n.bandwidth?s:c)(n.copy()),w=e.selection?e.selection():e,M=w.selectAll(".domain").data([null]),T=w.selectAll(".tick").data(u,n).order(),k=T.exit(),N=T.enter().append("g").attr("class","tick"),S=T.select("line"),E=T.select("text");M=M.merge(M.enter().insert("path",".tick").attr("class","domain").attr("stroke","#000")),T=T.merge(N),S=S.merge(N.append("line").attr("stroke","#000").attr(v+"2",d*l)),E=E.merge(N.append("text").attr("fill","#000").attr(v,d*y).attr("dy",t===qs?"0em":t===Ds?"0.71em":"0.32em")),e!==w&&(M=M.transition(e),T=T.transition(e),S=S.transition(e),E=E.transition(e),k=k.transition(e).attr("opacity",Fs).attr("transform",function(t){return isFinite(t=b(t))?_(t):this.getAttribute("transform")}),N.attr("opacity",Fs).attr("transform",function(t){var n=this.parentNode.__axis;return _(n&&isFinite(n=n(t))?n:b(t))})),k.remove(),M.attr("d",t===Os||t==Us?"M"+d*h+","+m+"H0.5V"+x+"H"+d*h:"M"+m+","+d*h+"V0.5H"+x+"V"+d*h),T.attr("opacity",1).attr("transform",function(t){return _(b(t))}),S.attr(v+"2",d*l),E.attr(v,d*y).text(a),w.filter(f).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===Us?"start":t===Os?"end":"middle"),w.each(function(){this.__axis=b})}var r=[],i=null,o=null,l=6,h=6,p=3,d=t===qs||t===Os?-1:1,v=t===Os||t===Us?"x":"y",_=t===qs||t===Ds?u:a;return e.scale=function(t){return arguments.length?(n=t,e):n},e.ticks=function(){return r=Rs.call(arguments),e},e.tickArguments=function(t){return arguments.length?(r=null==t?[]:Rs.call(t),e):r.slice()},e.tickValues=function(t){return arguments.length?(i=null==t?null:Rs.call(t),e):i&&i.slice()},e.tickFormat=function(t){return arguments.length?(o=t,e):o},e.tickSize=function(t){return arguments.length?(l=h=+t,e):l},e.tickSizeInner=function(t){return arguments.length?(l=+t,e):l},e.tickSizeOuter=function(t){return arguments.length?(h=+t,e):h},e.tickPadding=function(t){return arguments.length?(p=+t,e):p},e}function h(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r)throw new Error("illegal type: "+t);r[t]=[]}return new p(r)}function p(t){this._=t}function d(t,n){return t.trim().split(/^|\s+/).map(function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}function v(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function _(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=Is,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}function y(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===Ys&&n.documentElement.namespaceURI===Ys?n.createElement(t):n.createElementNS(e,t)}}function g(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function m(){return new x}function x(){this._="@"+(++Xs).toString(36)}function b(t,n,e){return t=w(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function w(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function M(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}function T(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function k(t,n,e){var r=Gs.hasOwnProperty(t.type)?b:w;return function(i,o,u){var a,c=this.__on,s=r(n,o,u);if(c)for(var f=0,l=c.length;f<l;++f)if((a=c[f]).type===t.type&&a.name===t.name)return this.removeEventListener(a.type,a.listener,a.capture),this.addEventListener(a.type,a.listener=s,a.capture=e),void(a.value=n);this.addEventListener(t.type,s,e),a={type:t.type,name:t.name,value:n,listener:s,capture:e},c?c.push(a):this.__on=[a]}}function N(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function S(){}function E(){return[]}function A(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function C(t,n,e,r,i,o){for(var u,a=0,c=n.length,s=o.length;a<s;++a)(u=n[a])?(u.__data__=o[a],r[a]=u):e[a]=new A(t,o[a]);for(;a<c;++a)(u=n[a])&&(i[a]=u)}function z(t,n,e,r,i,o,u){var a,c,s,f={},l=n.length,h=o.length,p=new Array(l);for(a=0;a<l;++a)(c=n[a])&&(p[a]=s=of+u.call(c,c.__data__,a,n),s in f?i[a]=c:f[s]=c);for(a=0;a<h;++a)(c=f[s=of+u.call(t,o[a],a,o)])?(r[a]=c,c.__data__=o[a],f[s]=null):e[a]=new A(t,o[a]);for(a=0;a<l;++a)(c=n[a])&&f[p[a]]===c&&(i[a]=c)}function P(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function R(t){return function(){this.removeAttribute(t)}}function L(t){return function(){this.removeAttributeNS(t.space,t.local)}}function q(t,n){return function(){this.setAttribute(t,n)}}function U(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function D(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function O(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function F(t){return function(){this.style.removeProperty(t)}}function I(t,n,e){return function(){this.style.setProperty(t,n,e)}}function Y(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function B(t,n){return t.style.getPropertyValue(n)||uf(t).getComputedStyle(t,null).getPropertyValue(n)}function j(t){return function(){delete this[t]}}function H(t,n){return function(){this[t]=n}}function X(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function $(t){return t.trim().split(/^|\s+/)}function V(t){return t.classList||new W(t)}function W(t){this._node=t,this._names=$(t.getAttribute("class")||"")}function Z(t,n){for(var e=V(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function G(t,n){for(var e=V(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function J(t){return function(){Z(this,t)}}function Q(t){return function(){G(this,t)}}function K(t,n){return function(){(n.apply(this,arguments)?Z:G)(this,t)}}function tt(){this.textContent=""}function nt(t){return function(){this.textContent=t}}function et(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}function rt(){this.innerHTML=""}function it(t){return function(){this.innerHTML=t}}function ot(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}function ut(){this.nextSibling&&this.parentNode.appendChild(this)}function at(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function ct(){return null}function st(){var t=this.parentNode;t&&t.removeChild(this)}function ft(t,n,e){var r=uf(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function lt(t,n){return function(){return ft(this,t,n)}}function ht(t,n){return function(){return ft(this,t,n.apply(this,arguments))}}function pt(t,n){this._groups=t,this._parents=n}function dt(){return new pt([[document.documentElement]],af)}function vt(){t.event.stopImmediatePropagation()}function _t(t,n){var e=t.document.documentElement,r=cf(t).on("dragstart.drag",null);n&&(r.on("click.drag",ff,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function yt(t,n,e,r,i,o,u,a,c,s){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=u,this.dx=a,this.dy=c,this._=s}function gt(){return!t.event.button}function mt(){return this.parentNode}function xt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function bt(){return"ontouchstart"in this}function wt(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Mt(){}function Tt(t){var n;return t=(t+"").trim().toLowerCase(),(n=yf.exec(t))?(n=parseInt(n[1],16),new At(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1)):(n=gf.exec(t))?kt(parseInt(n[1],16)):(n=mf.exec(t))?new At(n[1],n[2],n[3],1):(n=xf.exec(t))?new At(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=bf.exec(t))?Nt(n[1],n[2],n[3],n[4]):(n=wf.exec(t))?Nt(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Mf.exec(t))?Ct(n[1],n[2]/100,n[3]/100,1):(n=Tf.exec(t))?Ct(n[1],n[2]/100,n[3]/100,n[4]):kf.hasOwnProperty(t)?kt(kf[t]):"transparent"===t?new At(NaN,NaN,NaN,0):null}function kt(t){return new At(t>>16&255,t>>8&255,255&t,1)}function Nt(t,n,e,r){return r<=0&&(t=n=e=NaN),new At(t,n,e,r)}function St(t){return t instanceof Mt||(t=Tt(t)),t?(t=t.rgb(),new At(t.r,t.g,t.b,t.opacity)):new At}function Et(t,n,e,r){return 1===arguments.length?St(t):new At(t,n,e,null==r?1:r)}function At(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ct(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Rt(t,n,e,r)}function zt(t){if(t instanceof Rt)return new Rt(t.h,t.s,t.l,t.opacity);if(t instanceof Mt||(t=Tt(t)),!t)return new Rt;if(t instanceof Rt)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e<r):e===o?(r-n)/a+2:(n-e)/a+4,a/=c<.5?o+i:2-o-i,u*=60):a=c>0&&c<1?0:u,new Rt(u,a,c,t.opacity)}function Pt(t,n,e,r){return 1===arguments.length?zt(t):new Rt(t,n,e,null==r?1:r)}function Rt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Lt(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function qt(t){if(t instanceof Dt)return new Dt(t.l,t.a,t.b,t.opacity);if(t instanceof Ht){var n=t.h*Nf;return new Dt(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof At||(t=St(t));var e=Yt(t.r),r=Yt(t.g),i=Yt(t.b),o=Ot((.4124564*e+.3575761*r+.1804375*i)/Ef),u=Ot((.2126729*e+.7151522*r+.072175*i)/Af);return new Dt(116*u-16,500*(o-u),200*(u-Ot((.0193339*e+.119192*r+.9503041*i)/Cf)),t.opacity)}function Ut(t,n,e,r){return 1===arguments.length?qt(t):new Dt(t,n,e,null==r?1:r)}function Dt(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Ot(t){return t>Lf?Math.pow(t,1/3):t/Rf+zf}function Ft(t){return t>Pf?t*t*t:Rf*(t-zf)}function It(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Yt(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Bt(t){if(t instanceof Ht)return new Ht(t.h,t.c,t.l,t.opacity);t instanceof Dt||(t=qt(t));var n=Math.atan2(t.b,t.a)*Sf;return new Ht(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function jt(t,n,e,r){return 1===arguments.length?Bt(t):new Ht(t,n,e,null==r?1:r)}function Ht(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function Xt(t){if(t instanceof Vt)return new Vt(t.h,t.s,t.l,t.opacity);t instanceof At||(t=St(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Bf*r+If*n-Yf*e)/(Bf+If-Yf),o=r-i,u=(Ff*(e-i)-Df*o)/Of,a=Math.sqrt(u*u+o*o)/(Ff*i*(1-i)),c=a?Math.atan2(u,o)*Sf-120:NaN;return new Vt(c<0?c+360:c,a,i,t.opacity)}function $t(t,n,e,r){return 1===arguments.length?Xt(t):new Vt(t,n,e,null==r?1:r)}function Vt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Wt(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}function Zt(t,n){return function(e){return t+e*n}}function Gt(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}function Jt(t,n){var e=n-t;return e?Zt(t,e>180||e<-180?e-360*Math.round(e/360):e):Jf(isNaN(t)?n:t)}function Qt(t){return 1==(t=+t)?Kt:function(n,e){return e-n?Gt(n,e,t):Jf(isNaN(n)?e:n)}}function Kt(t,n){var e=n-t;return e?Zt(t,e):Jf(isNaN(t)?n:t)}function tn(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e<i;++e)r=Et(n[e]),o[e]=r.r||0,u[e]=r.g||0,a[e]=r.b||0;return o=t(o),u=t(u),a=t(a),r.opacity=1,function(t){return r.r=o(t),r.g=u(t),r.b=a(t),r+""}}}function nn(t){return function(){return t}}function en(t){return function(n){return t(n)+""}}function rn(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}function o(t,r,i,o,u,a){if(t!==i||r!==o){var c=u.push("translate(",null,n,null,e);a.push({i:c-4,x:rl(t,i)},{i:c-2,x:rl(r,o)})}else(i||o)&&u.push("translate("+i+n+o+e)}function u(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:rl(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}function a(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:rl(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}function c(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:rl(t,e)},{i:a-2,x:rl(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}return function(n,e){var r=[],i=[];return n=t(n),e=t(e),o(n.translateX,n.translateY,e.translateX,e.translateY,r,i),u(n.rotate,e.rotate,r,i),a(n.skewX,e.skewX,r,i),c(n.scaleX,n.scaleY,e.scaleX,e.scaleY,r,i),n=e=null,function(t){for(var n,e=-1,o=i.length;++e<o;)r[(n=i[e]).i]=n.x(t);return r.join("")}}}function on(t){return((t=Math.exp(t))+1/t)/2}function un(t){return((t=Math.exp(t))-1/t)/2}function an(t){return((t=Math.exp(2*t))-1)/(t+1)}function cn(t){return function(n,e){var r=t((n=Pt(n)).h,(e=Pt(e)).h),i=Kt(n.s,e.s),o=Kt(n.l,e.l),u=Kt(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function sn(t){return function(n,e){var r=t((n=jt(n)).h,(e=jt(e)).h),i=Kt(n.c,e.c),o=Kt(n.l,e.l),u=Kt(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function fn(t){return function n(e){function r(n,r){var i=t((n=$t(n)).h,(r=$t(r)).h),o=Kt(n.s,r.s),u=Kt(n.l,r.l),a=Kt(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=u(Math.pow(t,e)),n.opacity=a(t),n+""}}return e=+e,r.gamma=n,r}(1)}function ln(){return El||(zl(hn),El=Cl.now()+Al)}function hn(){El=0}function pn(){this._call=this._time=this._next=null}function dn(t,n,e){var r=new pn;return r.restart(t,n,e),r}function vn(){ln(),++Ml;for(var t,n=Vf;n;)(t=El-n._time)>=0&&n._call.call(null,t),n=n._next;--Ml}function _n(){El=(Sl=Cl.now())+Al,Ml=Tl=0;try{vn()}finally{Ml=0,gn(),El=0}}function yn(){var t=Cl.now(),n=t-Sl;n>Nl&&(Al-=n,Sl=t)}function gn(){for(var t,n,e=Vf,r=1/0;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Vf=n);Wf=t,mn(r)}function mn(t){if(!Ml){Tl&&(Tl=clearTimeout(Tl));var n=t-El;n>24?(t<1/0&&(Tl=setTimeout(_n,n)),kl&&(kl=clearInterval(kl))):(kl||(Sl=El,kl=setInterval(yn,Nl)),Ml=1,zl(_n))}}function xn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>ql)throw new Error("too late");return e}function bn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>Dl)throw new Error("too late");return e}function wn(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("too late");return e}function Mn(t,n,e){function r(c){var s,f,l,h;if(e.state!==Ul)return o();for(s in a)if((h=a[s]).name===e.name){if(h.state===Ol)return Pl(r);h.state===Fl?(h.state=Yl,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete a[s]):+s<n&&(h.state=Yl,h.timer.stop(),delete a[s])}if(Pl(function(){e.state===Ol&&(e.state=Fl,e.timer.restart(i,e.delay,e.time),i(c))}),e.state=Dl,e.on.call("start",t,t.__data__,e.index,e.group),e.state===Dl){for(e.state=Ol,u=new Array(l=e.tween.length),s=0,f=-1;s<l;++s)(h=e.tween[s].value.call(t,t.__data__,e.index,e.group))&&(u[++f]=h);u.length=f+1}}function i(n){for(var r=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(o),e.state=Il,1),i=-1,a=u.length;++i<a;)u[i].call(null,r);e.state===Il&&(e.on.call("end",t,t.__data__,e.index,e.group),o())}function o(){e.state=Yl,e.timer.stop(),delete a[n];for(var r in a)return;delete t.__transition}var u,a=t.__transition;a[n]=e,e.timer=dn(function(t){e.state=Ul,e.timer.restart(r,e.delay,e.time),e.delay<=t&&r(t-e.delay)},0,e.time)}function Tn(t,n){var e,r;return function(){var i=bn(this,t),o=i.tween;if(o!==e)for(var u=0,a=(r=e=o).length;u<a;++u)if(r[u].name===n){(r=r.slice()).splice(u,1);break}i.tween=r}}function kn(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=bn(this,t),u=o.tween;if(u!==r){i=(r=u).slice();for(var a={name:n,value:e},c=0,s=i.length;c<s;++c)if(i[c].name===n){i[c]=a;break}c===s&&i.push(a)}o.tween=i}}function Nn(t,n,e){var r=t._id;return t.each(function(){var t=bn(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return wn(t,r).value[n]}}function Sn(t){return function(){this.removeAttribute(t)}}function En(t){return function(){this.removeAttributeNS(t.space,t.local)}}function An(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}}function Cn(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}function zn(t,n,e){var r,i,o;return function(){var u,a=e(this);{if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}}}function Pn(t,n,e){var r,i,o;return function(){var u,a=e(this);{if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}}function Rn(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}function Ln(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e}function qn(t,n){return function(){xn(this,t).delay=+n.apply(this,arguments)}}function Un(t,n){return n=+n,function(){xn(this,t).delay=n}}function Dn(t,n){return function(){bn(this,t).duration=+n.apply(this,arguments)}}function On(t,n){return n=+n,function(){bn(this,t).duration=n}}function Fn(t,n){if("function"!=typeof n)throw new Error;return function(){bn(this,t).ease=n}}function In(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}function Yn(t,n,e){var r,i,o=In(n)?xn:bn;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}function Bn(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}function jn(t,n){var e,r,i;return function(){var o=B(this,t),u=(this.style.removeProperty(t),B(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}function Hn(t){return function(){this.style.removeProperty(t)}}function Xn(t,n,e){var r,i;return function(){var o=B(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}function $n(t,n,e){var r,i,o;return function(){var u=B(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=B(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}function Vn(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}function Wn(t){return function(){this.textContent=t}}function Zn(t){return function(){var n=t(this);this.textContent=null==n?"":n}}function Gn(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function Jn(t){return dt().transition(t)}function Qn(){return++$l}function Kn(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function te(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}function ne(t){return(1-Math.cos(Jl*t))/2}function ee(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function re(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}function ie(t){return(t=+t)<Kl?ch*t*t:t<nh?ch*(t-=th)*t+eh:t<ih?ch*(t-=rh)*t+oh:ch*(t-=uh)*t+ah}function oe(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return _h.time=ln(),_h;return e}function ue(){t.event.stopImmediatePropagation()}function ae(t){return{type:t}}function ce(){return!t.event.button}function se(){var t=this.ownerSVGElement||this;return[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function fe(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function le(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function he(n){function e(t){var e=t.property("__brush",a).selectAll(".overlay").data([ae("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",Eh.overlay).merge(e).each(function(){var t=fe(this).extent;cf(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([ae("selection")]).enter().append("rect").attr("class","selection").attr("cursor",Eh.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var i=t.selectAll(".handle").data(n.handles,function(t){return t.type});i.exit().remove(),i.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return Eh[t.type]}),t.each(r).attr("fill","none").attr("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush touchstart.brush",u)}function r(){var t=cf(this),n=fe(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-p/2:n[0][0]-p/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-p/2:n[0][1]-p/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+p:p}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+p:p})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function i(t,n){return t.__brush.emitter||new o(t,n)}function o(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function u(){function e(){var t=Ks(w);!L||x||b||(Math.abs(t[0]-U[0])>Math.abs(t[1]-U[1])?b=!0:x=!0),U=t,m=!0,xh(),o()}function o(){var t;switch(y=U[0]-q[0],g=U[1]-q[1],T){case wh:case bh:k&&(y=Math.max(C-a,Math.min(P-p,y)),s=a+y,d=p+y),N&&(g=Math.max(z-l,Math.min(R-v,g)),h=l+g,_=v+g);break;case Mh:k<0?(y=Math.max(C-a,Math.min(P-a,y)),s=a+y,d=p):k>0&&(y=Math.max(C-p,Math.min(P-p,y)),s=a,d=p+y),N<0?(g=Math.max(z-l,Math.min(R-l,g)),h=l+g,_=v):N>0&&(g=Math.max(z-v,Math.min(R-v,g)),h=l,_=v+g);break;case Th:k&&(s=Math.max(C,Math.min(P,a-y*k)),d=Math.max(C,Math.min(P,p+y*k))),N&&(h=Math.max(z,Math.min(R,l-g*N)),_=Math.max(z,Math.min(R,v+g*N)))}d<s&&(k*=-1,t=a,a=p,p=t,t=s,s=d,d=t,M in Ah&&F.attr("cursor",Eh[M=Ah[M]])),_<h&&(N*=-1,t=l,l=v,v=t,t=h,h=_,_=t,M in Ch&&F.attr("cursor",Eh[M=Ch[M]])),S.selection&&(A=S.selection),x&&(s=A[0][0],d=A[1][0]),b&&(h=A[0][1],_=A[1][1]),A[0][0]===s&&A[0][1]===h&&A[1][0]===d&&A[1][1]===_||(S.selection=[[s,h],[d,_]],r.call(w),D.brush())}function u(){if(ue(),t.event.touches){if(t.event.touches.length)return;c&&clearTimeout(c),c=setTimeout(function(){c=null},500),O.on("touchmove.brush touchend.brush touchcancel.brush",null)}else _t(t.event.view,m),I.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);O.attr("pointer-events","all"),F.attr("cursor",Eh.overlay),S.selection&&(A=S.selection),le(A)&&(S.selection=null,r.call(w)),D.end()}if(t.event.touches){if(t.event.changedTouches.length<t.event.touches.length)return xh()}else if(c)return;if(f.apply(this,arguments)){var a,s,l,h,p,d,v,_,y,g,m,x,b,w=this,M=t.event.target.__data__.type,T="selection"===(t.event.metaKey?M="overlay":M)?bh:t.event.altKey?Th:Mh,k=n===Nh?null:zh[M],N=n===kh?null:Ph[M],S=fe(w),E=S.extent,A=S.selection,C=E[0][0],z=E[0][1],P=E[1][0],R=E[1][1],L=k&&N&&t.event.shiftKey,q=Ks(w),U=q,D=i(w,arguments).beforestart();"overlay"===M?S.selection=A=[[a=n===Nh?C:q[0],l=n===kh?z:q[1]],[p=n===Nh?P:a,v=n===kh?R:l]]:(a=A[0][0],l=A[0][1],p=A[1][0],v=A[1][1]),s=a,h=l,d=p,_=v;var O=cf(w).attr("pointer-events","none"),F=O.selectAll(".overlay").attr("cursor",Eh[M]);if(t.event.touches)O.on("touchmove.brush",e,!0).on("touchend.brush touchcancel.brush",u,!0);else{var I=cf(t.event.view).on("keydown.brush",function(){switch(t.event.keyCode){case 16:L=k&&N;break;case 18:T===Mh&&(k&&(p=d-y*k,a=s+y*k),N&&(v=_-g*N,l=h+g*N),T=Th,o());break;case 32:T!==Mh&&T!==Th||(k<0?p=d-y:k>0&&(a=s-y),N<0?v=_-g:N>0&&(l=h-g),T=wh,F.attr("cursor",Eh.selection),o());break;default:return}xh()},!0).on("keyup.brush",function(){switch(t.event.keyCode){case 16:L&&(x=b=L=!1,o());break;case 18:T===Th&&(k<0?p=d:k>0&&(a=s),N<0?v=_:N>0&&(l=h),T=Mh,o());break;case 32:T===wh&&(t.event.altKey?(k&&(p=d-y*k,a=s+y*k),N&&(v=_-g*N,l=h+g*N),T=Th):(k<0?p=d:k>0&&(a=s),N<0?v=_:N>0&&(l=h),T=Mh),F.attr("cursor",Eh[M]),o());break;default:return}xh()},!0).on("mousemove.brush",e,!0).on("mouseup.brush",u,!0);lf(t.event.view)}ue(),jl(w),r.call(w),D.start()}}function a(){var t=this.__brush||{selection:null};return t.extent=s.apply(this,arguments),t.dim=n,t}var c,s=se,f=ce,l=h(e,"start","brush","end"),p=6;return e.move=function(t,e){t.selection?t.on("start.brush",function(){i(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){i(this,arguments).end()}).tween("brush",function(){function t(t){u.selection=1===t&&le(s)?null:f(t),r.call(o),a.brush()}var o=this,u=o.__brush,a=i(o,arguments),c=u.selection,s=n.input("function"==typeof e?e.apply(this,arguments):e,u.extent),f=cl(c,s);return c&&s?t:t(1)}):t.each(function(){var t=this,o=arguments,u=t.__brush,a=n.input("function"==typeof e?e.apply(t,o):e,u.extent),c=i(t,o).beforestart();jl(t),u.selection=null==a||le(a)?null:a,r.call(t),c.start().brush().end()})},o.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting&&(this.starting=!1,this.emit("start")),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){N(new mh(e,t,n.output(this.state.selection)),l.apply,l,[t,this.that,this.args])}},e.extent=function(t){return arguments.length?(s="function"==typeof t?t:gh([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),e):s},e.filter=function(t){return arguments.length?(f="function"==typeof t?t:gh(!!t),e):f},e.handleSize=function(t){return arguments.length?(p=+t,e):p},e.on=function(){var t=l.on.apply(l,arguments);return t===l?e:t},e}function pe(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}function de(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function ve(){return new de}function _e(t){return t.source}function ye(t){return t.target}function ge(t){return t.radius}function me(t){return t.startAngle}function xe(t){return t.endAngle}function be(){}function we(t,n){var e=new be;if(t instanceof be)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var u in t)e.set(u,t[u]);return e}function Me(){return{}}function Te(t,n,e){t[n]=e}function ke(){return we()}function Ne(t,n,e){t.set(n,e)}function Se(){}function Ee(t,n){var e=new Se;if(t instanceof Se)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}function Ae(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}")}function Ce(t,n){var e=Ae(t);return function(r,i){return n(e(r),i,t)}}function ze(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function Pe(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,u,a,c,s,f,l,h,p=t._root,d={data:r},v=t._x0,_=t._y0,y=t._x1,g=t._y1;if(!p)return t._root=d,t;for(;p.length;)if((s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u,i=p,!(p=p[l=f<<1|s]))return i[l]=d,t;if(a=+t._x.call(null,p.data),c=+t._y.call(null,p.data),n===a&&e===c)return d.next=p,i?i[l]=d:t._root=d,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u}while((l=f<<1|s)==(h=(c>=u)<<1|a>=o));return i[h]=p,i[l]=d,t}function Re(t){return t[0]}function Le(t){return t[1]}function qe(t,n,e){var r=new Ue(null==n?Re:n,null==e?Le:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ue(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function De(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}function Oe(t){return t.x+t.vx}function Fe(t){return t.y+t.vy}function Ie(t){return t.index}function Ye(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function Be(t){return t.x}function je(t){return t.y}function He(t){return new Xe(t)}function Xe(t){if(!(n=vp.exec(t)))throw new Error("invalid format: "+t);var n,e=n[1]||" ",r=n[2]||">",i=n[3]||"-",o=n[4]||"",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],s=n[8]&&+n[8].slice(1),f=n[9]||"";"n"===f?(c=!0,f="g"):dp[f]||(f=""),(u||"0"===e&&"="===r)&&(u=!0,e="0",r="="),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=s,this.type=f}function $e(n){return _p=mp(n),t.format=_p.format,t.formatPrefix=_p.formatPrefix,_p}function Ve(){this.reset()}function We(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}function Ze(t){return t>1?0:t<-1?rd:Math.acos(t)}function Ge(t){return t>1?id:t<-1?-id:Math.asin(t)}function Je(t){return(t=yd(t/2))*t}function Qe(){}function Ke(t,n){t&&wd.hasOwnProperty(t.type)&&wd[t.type](t,n)}function tr(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function nr(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)tr(t[e],n,1);n.polygonEnd()}function er(){Nd.point=ir}function rr(){or(Tp,kp)}function ir(t,n){Nd.point=or,Tp=t,kp=n,Np=t*=cd,Sp=hd(n=(n*=cd)/2+od),Ep=yd(n)}function or(t,n){n=(n*=cd)/2+od;var e=(t*=cd)-Np,r=e>=0?1:-1,i=r*e,o=hd(n),u=yd(n),a=Ep*u,c=Sp*o+a*hd(i),s=a*r*yd(i);Td.add(ld(s,c)),Np=t,Sp=o,Ep=u}function ur(t){return[ld(t[1],t[0]),Ge(t[2])]}function ar(t){var n=t[0],e=t[1],r=hd(e);return[r*hd(n),r*yd(n),yd(e)]}function cr(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function sr(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function fr(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function lr(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function hr(t){var n=md(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}function pr(t,n){Dp.push(Op=[Ap=t,zp=t]),n<Cp&&(Cp=n),n>Pp&&(Pp=n)}function dr(t,n){var e=ar([t*cd,n*cd]);if(Up){var r=sr(Up,e),i=sr([r[1],-r[0],0],r);hr(i),i=ur(i);var o,u=t-Rp,a=u>0?1:-1,c=i[0]*ad*a,s=sd(u)>180;s^(a*Rp<c&&c<a*t)?(o=i[1]*ad)>Pp&&(Pp=o):(c=(c+360)%360-180,s^(a*Rp<c&&c<a*t)?(o=-i[1]*ad)<Cp&&(Cp=o):(n<Cp&&(Cp=n),n>Pp&&(Pp=n))),s?t<Rp?xr(Ap,t)>xr(Ap,zp)&&(zp=t):xr(t,zp)>xr(Ap,zp)&&(Ap=t):zp>=Ap?(t<Ap&&(Ap=t),t>zp&&(zp=t)):t>Rp?xr(Ap,t)>xr(Ap,zp)&&(zp=t):xr(t,zp)>xr(Ap,zp)&&(Ap=t)}else Dp.push(Op=[Ap=t,zp=t]);n<Cp&&(Cp=n),n>Pp&&(Pp=n),Up=e,Rp=t}function vr(){Ed.point=dr}function _r(){Op[0]=Ap,Op[1]=zp,Ed.point=pr,Up=null}function yr(t,n){if(Up){var e=t-Rp;Sd.add(sd(e)>180?e+(e>0?360:-360):e)}else Lp=t,qp=n;Nd.point(t,n),dr(t,n)}function gr(){Nd.lineStart()}function mr(){yr(Lp,qp),Nd.lineEnd(),sd(Sd)>ed&&(Ap=-(zp=180)),Op[0]=Ap,Op[1]=zp,Up=null}function xr(t,n){return(n-=t)<0?n+360:n}function br(t,n){return t[0]-n[0]}function wr(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}function Mr(t,n){t*=cd;var e=hd(n*=cd);Tr(e*hd(t),e*yd(t),yd(n))}function Tr(t,n,e){Yp+=(t-Yp)/++Fp,Bp+=(n-Bp)/Fp,jp+=(e-jp)/Fp}function kr(){Ad.point=Nr}function Nr(t,n){t*=cd;var e=hd(n*=cd);Qp=e*hd(t),Kp=e*yd(t),td=yd(n),Ad.point=Sr,Tr(Qp,Kp,td)}function Sr(t,n){t*=cd;var e=hd(n*=cd),r=e*hd(t),i=e*yd(t),o=yd(n),u=ld(md((u=Kp*o-td*i)*u+(u=td*r-Qp*o)*u+(u=Qp*i-Kp*r)*u),Qp*r+Kp*i+td*o);Ip+=u,Hp+=u*(Qp+(Qp=r)),Xp+=u*(Kp+(Kp=i)),$p+=u*(td+(td=o)),Tr(Qp,Kp,td)}function Er(){Ad.point=Mr}function Ar(){Ad.point=zr}function Cr(){Pr(Gp,Jp),Ad.point=Mr}function zr(t,n){Gp=t,Jp=n,t*=cd,n*=cd,Ad.point=Pr;var e=hd(n);Qp=e*hd(t),Kp=e*yd(t),td=yd(n),Tr(Qp,Kp,td)}function Pr(t,n){t*=cd;var e=hd(n*=cd),r=e*hd(t),i=e*yd(t),o=yd(n),u=Kp*o-td*i,a=td*r-Qp*o,c=Qp*i-Kp*r,s=md(u*u+a*a+c*c),f=Ge(s),l=s&&-f/s;Vp+=l*u,Wp+=l*a,Zp+=l*c,Ip+=f,Hp+=f*(Qp+(Qp=r)),Xp+=f*(Kp+(Kp=i)),$p+=f*(td+(td=o)),Tr(Qp,Kp,td)}function Rr(t,n){return[t>rd?t-ud:t<-rd?t+ud:t,n]}function Lr(t,n,e){return(t%=ud)?n||e?zd(Ur(t),Dr(n,e)):Ur(t):n||e?Dr(n,e):Rr}function qr(t){return function(n,e){return n+=t,[n>rd?n-ud:n<-rd?n+ud:n,e]}}function Ur(t){var n=qr(t);return n.invert=qr(-t),n}function Dr(t,n){function e(t,n){var e=hd(n),a=hd(t)*e,c=yd(t)*e,s=yd(n),f=s*r+a*i;return[ld(c*o-f*u,a*r-s*i),Ge(f*o+c*u)]}var r=hd(t),i=yd(t),o=hd(n),u=yd(n);return e.invert=function(t,n){var e=hd(n),a=hd(t)*e,c=yd(t)*e,s=yd(n),f=s*o-c*u;return[ld(c*o+s*u,a*r+f*i),Ge(f*r-a*i)]},e}function Or(t,n,e,r,i,o){if(e){var u=hd(n),a=yd(n),c=r*e;null==i?(i=n+r*ud,o=n-c/2):(i=Fr(u,i),o=Fr(u,o),(r>0?i<o:i>o)&&(i+=r*ud));for(var s,f=i;r>0?f>o:f<o;f-=c)s=ur([u,-a*hd(f),-a*yd(f)]),t.point(s[0],s[1])}}function Fr(t,n){(n=ar(n))[0]-=t,hr(n);var e=Ze(-n[1]);return((-n[2]<0?-e:e)+ud-ed)%ud}function Ir(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Yr(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function Br(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,a,s){var f=0,l=0;if(null==i||(f=u(i,a))!==(l=u(o,a))||c(i,o)<0^a>0)do{s.point(0===f||3===f?t:e,f>1?r:n)}while((f=(f+a+4)%4)!==l);else s.point(o[0],o[1])}function u(r,i){return sd(r[0]-t)<ed?i>0?0:3:sd(r[0]-e)<ed?i>0?2:1:sd(r[1]-n)<ed?i>0?1:0:i>0?3:2}function a(t,n){return c(t.x,n.x)}function c(t,n){var e=u(t,1),r=u(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){function c(t,n){i(t,n)&&w.point(t,n)}function s(){for(var n=0,e=0,i=h.length;e<i;++e)for(var o,u,a=h[e],c=1,s=a.length,f=a[0],l=f[0],p=f[1];c<s;++c)o=l,u=p,l=(f=a[c])[0],p=f[1],u<=r?p>r&&(l-o)*(r-u)>(p-u)*(t-o)&&++n:p<=r&&(l-o)*(r-u)<(p-u)*(t-o)&&--n;return n}function f(o,u){var a=i(o,u);if(h&&p.push([o,u]),x)d=o,v=u,_=a,x=!1,a&&(w.lineStart(),w.point(o,u));else if(a&&m)w.point(o,u);else{var c=[y=Math.max(Zd,Math.min(Wd,y)),g=Math.max(Zd,Math.min(Wd,g))],s=[o=Math.max(Zd,Math.min(Wd,o)),u=Math.max(Zd,Math.min(Wd,u))];Xd(c,s,t,n,e,r)?(m||(w.lineStart(),w.point(c[0],c[1])),w.point(s[0],s[1]),a||w.lineEnd(),b=!1):a&&(w.lineStart(),w.point(o,u),b=!1)}y=o,g=u,m=a}var l,h,p,d,v,_,y,g,m,x,b,w=u,M=Hd(),T={point:c,lineStart:function(){T.point=f,h&&h.push(p=[]),x=!0,m=!1,y=g=NaN},lineEnd:function(){l&&(f(d,v),_&&m&&M.rejoin(),l.push(M.result())),T.point=c,m&&w.lineEnd()},polygonStart:function(){w=M,l=[],h=[],b=!0},polygonEnd:function(){var t=s(),n=b&&t,e=(l=Cs(l)).length;(n||e)&&(u.polygonStart(),n&&(u.lineStart(),o(null,null,1,u),u.lineEnd()),e&&Vd(l,a,t,o,u),u.polygonEnd()),w=u,l=h=p=null}};return T}}function jr(){Kd.point=Kd.lineEnd=Qe}function Hr(t,n){Pd=t*=cd,Rd=yd(n*=cd),Ld=hd(n),Kd.point=Xr}function Xr(t,n){t*=cd;var e=yd(n*=cd),r=hd(n),i=sd(t-Pd),o=hd(i),u=r*yd(i),a=Ld*e-Rd*r*o,c=Rd*e+Ld*r*o;Qd.add(ld(md(u*u+a*a),c)),Pd=t,Rd=e,Ld=r}function $r(t,n){return!(!t||!ov.hasOwnProperty(t.type))&&ov[t.type](t,n)}function Vr(t,n){return 0===rv(t,n)}function Wr(t,n){var e=rv(t[0],t[1]);return rv(t[0],n)+rv(n,t[1])<=e+ed}function Zr(t,n){return!!Jd(t.map(Gr),Jr(n))}function Gr(t){return(t=t.map(Jr)).pop(),t}function Jr(t){return[t[0]*cd,t[1]*cd]}function Qr(t,n,e){var r=Ms(t,n-ed,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function Kr(t,n,e){var r=Ms(t,n-ed,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function ti(){function t(){return{type:"MultiLineString",coordinates:n()}}function n(){return Ms(pd(o/_)*_,i,_).map(h).concat(Ms(pd(s/y)*y,c,y).map(p)).concat(Ms(pd(r/d)*d,e,d).filter(function(t){return sd(t%_)>ed}).map(f)).concat(Ms(pd(a/v)*v,u,v).filter(function(t){return sd(t%y)>ed}).map(l))}var e,r,i,o,u,a,c,s,f,l,h,p,d=10,v=d,_=90,y=360,g=2.5;return t.lines=function(){return n().map(function(t){return{type:"LineString",coordinates:t}})},t.outline=function(){return{type:"Polygon",coordinates:[h(o).concat(p(c).slice(1),h(i).reverse().slice(1),p(s).reverse().slice(1))]}},t.extent=function(n){return arguments.length?t.extentMajor(n).extentMinor(n):t.extentMinor()},t.extentMajor=function(n){return arguments.length?(o=+n[0][0],i=+n[1][0],s=+n[0][1],c=+n[1][1],o>i&&(n=o,o=i,i=n),s>c&&(n=s,s=c,c=n),t.precision(g)):[[o,s],[i,c]]},t.extentMinor=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],a=+n[0][1],u=+n[1][1],r>e&&(n=r,r=e,e=n),a>u&&(n=a,a=u,u=n),t.precision(g)):[[r,a],[e,u]]},t.step=function(n){return arguments.length?t.stepMajor(n).stepMinor(n):t.stepMinor()},t.stepMajor=function(n){return arguments.length?(_=+n[0],y=+n[1],t):[_,y]},t.stepMinor=function(n){return arguments.length?(d=+n[0],v=+n[1],t):[d,v]},t.precision=function(n){return arguments.length?(g=+n,f=Qr(a,u,90),l=Kr(r,e,g),h=Qr(s,c,90),p=Kr(o,i,g),t):g},t.extentMajor([[-180,-90+ed],[180,90-ed]]).extentMinor([[-180,-80-ed],[180,80+ed]])}function ni(){sv.point=ei}function ei(t,n){sv.point=ri,qd=Dd=t,Ud=Od=n}function ri(t,n){cv.add(Od*t-Dd*n),Dd=t,Od=n}function ii(){ri(qd,Ud)}function oi(t,n){vv+=t,_v+=n,++yv}function ui(){Tv.point=ai}function ai(t,n){Tv.point=ci,oi(Yd=t,Bd=n)}function ci(t,n){var e=t-Yd,r=n-Bd,i=md(e*e+r*r);gv+=i*(Yd+t)/2,mv+=i*(Bd+n)/2,xv+=i,oi(Yd=t,Bd=n)}function si(){Tv.point=oi}function fi(){Tv.point=hi}function li(){pi(Fd,Id)}function hi(t,n){Tv.point=pi,oi(Fd=Yd=t,Id=Bd=n)}function pi(t,n){var e=t-Yd,r=n-Bd,i=md(e*e+r*r);gv+=i*(Yd+t)/2,mv+=i*(Bd+n)/2,xv+=i,bv+=(i=Bd*t-Yd*n)*(Yd+t),wv+=i*(Bd+n),Mv+=3*i,oi(Yd=t,Bd=n)}function di(t){this._context=t}function vi(t,n){zv.point=_i,Nv=Ev=t,Sv=Av=n}function _i(t,n){Ev-=t,Av-=n,Cv.add(md(Ev*Ev+Av*Av)),Ev=t,Av=n}function yi(){this._string=[]}function gi(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function mi(t){return t.length>1}function xi(t,n){return((t=t.x)[0]<0?t[1]-id-ed:id-t[1])-((n=n.x)[0]<0?n[1]-id-ed:id-n[1])}function bi(t,n,e,r){var i,o,u=yd(t-e);return sd(u)>ed?fd((yd(n)*(o=hd(r))*yd(e)-yd(r)*(i=hd(n))*yd(t))/(i*o*u)):(n+r)/2}function wi(t){return function(n){var e=new Mi;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Mi(){}function Ti(t,n,e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=t.clipExtent&&t.clipExtent();t.scale(150).translate([0,0]),null!=o&&t.clipExtent(null),Md(e,t.stream(dv));var u=dv.result(),a=Math.min(r/(u[1][0]-u[0][0]),i/(u[1][1]-u[0][1])),c=+n[0][0]+(r-a*(u[1][0]+u[0][0]))/2,s=+n[0][1]+(i-a*(u[1][1]+u[0][1]))/2;return null!=o&&t.clipExtent(o),t.scale(150*a).translate([c,s])}function ki(t,n,e){return Ti(t,[[0,0],n],e)}function Ni(t){return wi({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}function Si(t,n){function e(r,i,o,u,a,c,s,f,l,h,p,d,v,_){var y=s-r,g=f-i,m=y*y+g*g;if(m>4*n&&v--){var x=u+h,b=a+p,w=c+d,M=md(x*x+b*b+w*w),T=Ge(w/=M),k=sd(sd(w)-1)<ed||sd(o-l)<ed?(o+l)/2:ld(b,x),N=t(k,T),S=N[0],E=N[1],A=S-r,C=E-i,z=g*A-y*C;(z*z/m>n||sd((y*A+g*C)/m-.5)>.3||u*h+a*p+c*d<Uv)&&(e(r,i,o,u,a,c,S,E,k,x/=M,b/=M,w,v,_),_.point(S,E),e(S,E,k,x,b,w,s,f,l,h,p,d,v,_))}}return function(n){function r(e,r){e=t(e,r),n.point(e[0],e[1])}function i(){y=NaN,w.point=o,n.lineStart()}function o(r,i){var o=ar([r,i]),u=t(r,i);e(y,g,_,m,x,b,y=u[0],g=u[1],_=r,m=o[0],x=o[1],b=o[2],qv,n),n.point(y,g)}function u(){w.point=r,n.lineEnd()}function a(){i(),w.point=c,w.lineEnd=s}function c(t,n){o(f=t,n),l=y,h=g,p=m,d=x,v=b,w.point=o}function s(){e(y,g,_,m,x,b,l,h,f,p,d,v,qv,n),w.lineEnd=u,u()}var f,l,h,p,d,v,_,y,g,m,x,b,w={point:r,lineStart:i,lineEnd:u,polygonStart:function(){n.polygonStart(),w.lineStart=a},polygonEnd:function(){n.polygonEnd(),w.lineStart=i}};return w}}function Ei(t){return Ai(function(){return t})()}function Ai(t){function n(t){return t=f(t[0]*cd,t[1]*cd),[t[0]*_+a,c-t[1]*_]}function e(t){return(t=f.invert((t[0]-a)/_,(c-t[1])/_))&&[t[0]*ad,t[1]*ad]}function r(t,n){return t=u(t,n),[t[0]*_+a,c-t[1]*_]}function i(){f=zd(s=Lr(b,w,M),u);var t=u(m,x);return a=y-t[0]*_,c=g+t[1]*_,o()}function o(){return d=v=null,n}var u,a,c,s,f,l,h,p,d,v,_=150,y=480,g=250,m=0,x=0,b=0,w=0,M=0,T=null,k=Rv,N=null,S=uv,E=.5,A=Dv(r,E);return n.stream=function(t){return d&&v===t?d:d=Ov(k(s,A(S(v=t))))},n.clipAngle=function(t){return arguments.length?(k=+t?Lv(T=t*cd,6*cd):(T=null,Rv),o()):T*ad},n.clipExtent=function(t){return arguments.length?(S=null==t?(N=l=h=p=null,uv):Br(N=+t[0][0],l=+t[0][1],h=+t[1][0],p=+t[1][1]),o()):null==N?null:[[N,l],[h,p]]},n.scale=function(t){return arguments.length?(_=+t,i()):_},n.translate=function(t){return arguments.length?(y=+t[0],g=+t[1],i()):[y,g]},n.center=function(t){return arguments.length?(m=t[0]%360*cd,x=t[1]%360*cd,i()):[m*ad,x*ad]},n.rotate=function(t){return arguments.length?(b=t[0]%360*cd,w=t[1]%360*cd,M=t.length>2?t[2]%360*cd:0,i()):[b*ad,w*ad,M*ad]},n.precision=function(t){return arguments.length?(A=Dv(r,E=t*t),o()):md(E)},n.fitExtent=function(t,e){return Ti(n,t,e)},n.fitSize=function(t,e){return ki(n,t,e)},function(){return u=t.apply(this,arguments),n.invert=u.invert&&e,i()}}function Ci(t){var n=0,e=rd/3,r=Ai(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*cd,e=t[1]*cd):[n*ad,e*ad]},i}function zi(t){function n(t,n){return[t*e,yd(n)/e]}var e=hd(t);return n.invert=function(t,n){return[t/e,Ge(n*e)]},n}function Pi(t,n){function e(t,n){var e=md(o-2*i*yd(n))/i;return[e*yd(t*=i),u-e*hd(t)]}var r=yd(t),i=(r+yd(n))/2;if(sd(i)<ed)return zi(t);var o=1+r*(2*i-r),u=md(o)/i;return e.invert=function(t,n){var e=u-n;return[ld(t,sd(e))/i*gd(e),Ge((o-(t*t+e*e)*i*i)/(2*i))]},e}function Ri(t){var n=t.length;return{point:function(e,r){for(var i=-1;++i<n;)t[i].point(e,r)},sphere:function(){for(var e=-1;++e<n;)t[e].sphere()},lineStart:function(){for(var e=-1;++e<n;)t[e].lineStart()},lineEnd:function(){for(var e=-1;++e<n;)t[e].lineEnd()},polygonStart:function(){for(var e=-1;++e<n;)t[e].polygonStart()},polygonEnd:function(){for(var e=-1;++e<n;)t[e].polygonEnd()}}}function Li(t){return function(n,e){var r=hd(n),i=hd(e),o=t(r*i);return[o*i*yd(n),o*yd(e)]}}function qi(t){return function(n,e){var r=md(n*n+e*e),i=t(r),o=yd(i),u=hd(i);return[ld(n*o,r*u),Ge(r&&e*o/r)]}}function Ui(t,n){return[t,vd(xd((id+n)/2))]}function Di(t){function n(){var n=rd*a(),u=o(jd(o.rotate()).invert([0,0]));return s(null==f?[[u[0]-n,u[1]-n],[u[0]+n,u[1]+n]]:t===Ui?[[Math.max(u[0]-n,f),e],[Math.min(u[0]+n,r),i]]:[[f,Math.max(u[1]-n,e)],[r,Math.min(u[1]+n,i)]])}var e,r,i,o=Ei(t),u=o.center,a=o.scale,c=o.translate,s=o.clipExtent,f=null;return o.scale=function(t){return arguments.length?(a(t),n()):a()},o.translate=function(t){return arguments.length?(c(t),n()):c()},o.center=function(t){return arguments.length?(u(t),n()):u()},o.clipExtent=function(t){return arguments.length?(null==t?f=e=r=i=null:(f=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),n()):null==f?null:[[f,e],[r,i]]},n()}function Oi(t){return xd((id+t)/2)}function Fi(t,n){function e(t,n){o>0?n<-id+ed&&(n=-id+ed):n>id-ed&&(n=id-ed);var e=o/_d(Oi(n),i);return[e*yd(i*t),o-e*hd(i*t)]}var r=hd(t),i=t===n?yd(t):vd(r/hd(n))/vd(Oi(n)/Oi(t)),o=r*_d(Oi(t),i)/i;return i?(e.invert=function(t,n){var e=o-n,r=gd(i)*md(t*t+e*e);return[ld(t,sd(e))/i*gd(e),2*fd(_d(o/r,1/i))-id]},e):Ui}function Ii(t,n){return[t,n]}function Yi(t,n){function e(t,n){var e=o-n,r=i*t;return[e*yd(r),o-e*hd(r)]}var r=hd(t),i=t===n?yd(t):(r-hd(n))/(n-t),o=r/i+t;return sd(i)<ed?Ii:(e.invert=function(t,n){var e=o-n;return[ld(t,sd(e))/i*gd(e),o-gd(i)*md(t*t+e*e)]},e)}function Bi(t,n){var e=hd(n),r=hd(t)*e;return[e*yd(t)/r,yd(n)/r]}function ji(t,n,e,r){return 1===t&&1===n&&0===e&&0===r?uv:wi({point:function(i,o){this.stream.point(i*t+e,o*n+r)}})}function Hi(t,n){return[hd(n)*yd(t),yd(n)]}function Xi(t,n){var e=hd(n),r=1+hd(t)*e;return[e*yd(t)/r,yd(n)/r]}function $i(t,n){return[vd(xd((id+n)/2)),-t]}function Vi(t,n){return t.parent===n.parent?1:2}function Wi(t){return t.reduce(Zi,0)/t.length}function Zi(t,n){return t+n.x}function Gi(t){return 1+t.reduce(Ji,0)}function Ji(t,n){return Math.max(t,n.y)}function Qi(t){for(var n;n=t.children;)t=n[0];return t}function Ki(t){for(var n;n=t.children;)t=n[n.length-1];return t}function to(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function no(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}function eo(t,n){var e,r,i,o,u,a=new uo(t),c=+t.value&&(a.value=t.value),s=[a];for(null==n&&(n=ro);e=s.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(u=i.length))for(e.children=new Array(u),o=u-1;o>=0;--o)s.push(r=e.children[o]=new uo(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(oo)}function ro(t){return t.children}function io(t){t.data=t.data.data}function oo(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function uo(t){this.data=t,this.depth=this.height=0,this.parent=null}function ao(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}function co(t,n){var e,r;if(lo(n,t))return[n];for(e=0;e<t.length;++e)if(so(n,t[e])&&lo(vo(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(so(vo(t[e],t[r]),n)&&so(vo(t[e],n),t[r])&&so(vo(t[r],n),t[e])&&lo(_o(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function so(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function fo(t,n){var e=t.r-n.r+1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function lo(t,n){for(var e=0;e<n.length;++e)if(!fo(t,n[e]))return!1;return!0}function ho(t){switch(t.length){case 1:return po(t[0]);case 2:return vo(t[0],t[1]);case 3:return _o(t[0],t[1],t[2])}}function po(t){return{x:t.x,y:t.y,r:t.r}}function vo(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,u=n.y,a=n.r,c=o-e,s=u-r,f=a-i,l=Math.sqrt(c*c+s*s);return{x:(e+o+c/l*f)/2,y:(r+u+s/l*f)/2,r:(l+i+a)/2}}function _o(t,n,e){var r=t.x,i=t.y,o=t.r,u=n.x,a=n.y,c=n.r,s=e.x,f=e.y,l=e.r,h=r-u,p=r-s,d=i-a,v=i-f,_=c-o,y=l-o,g=r*r+i*i-o*o,m=g-u*u-a*a+c*c,x=g-s*s-f*f+l*l,b=p*d-h*v,w=(d*x-v*m)/(2*b)-r,M=(v*_-d*y)/b,T=(p*m-h*x)/(2*b)-i,k=(h*y-p*_)/b,N=M*M+k*k-1,S=2*(o+w*M+T*k),E=w*w+T*T-o*o,A=-(N?(S+Math.sqrt(S*S-4*N*E))/(2*N):E/S);return{x:r+w+M*A,y:i+T+k*A,r:A}}function yo(t,n,e){var r=t.x,i=t.y,o=n.r+e.r,u=t.r+e.r,a=n.x-r,c=n.y-i,s=a*a+c*c;if(s){var f=.5+((u*=u)-(o*=o))/(2*s),l=Math.sqrt(Math.max(0,2*o*(u+s)-(u-=s)*u-o*o))/(2*s);e.x=r+f*a+l*c,e.y=i+f*c-l*a}else e.x=r+u,e.y=i}function go(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return i*i-1e-6>e*e+r*r}function mo(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function xo(t){this._=t,this.next=null,this.previous=null}function bo(t){if(!(i=t.length))return 0;var n,e,r,i,o,u,a,c,s,f,l;if(n=t[0],n.x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;yo(e,n,r=t[2]),n=new xo(n),e=new xo(e),r=new xo(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(a=3;a<i;++a){yo(n._,e._,r=t[a]),r=new xo(r),c=e.next,s=n.previous,f=e._.r,l=n._.r;do{if(f<=l){if(go(c._,r._)){e=c,n.next=e,e.previous=n,--a;continue t}f+=c._.r,c=c.next}else{if(go(s._,r._)){(n=s).next=e,e.previous=n,--a;continue t}l+=s._.r,s=s.previous}}while(c!==s.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=mo(n);(r=r.next)!==e;)(u=mo(r))<o&&(n=r,o=u);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Hv(n),a=0;a<i;++a)n=t[a],n.x-=r.x,n.y-=r.y;return r.r}function wo(t){return null==t?null:Mo(t)}function Mo(t){if("function"!=typeof t)throw new Error;return t}function To(){return 0}function ko(t){return Math.sqrt(t.value)}function No(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function So(t,n){return function(e){if(r=e.children){var r,i,o,u=r.length,a=t(e)*n||0;if(a)for(i=0;i<u;++i)r[i].r+=a;if(o=bo(r),a)for(i=0;i<u;++i)r[i].r-=a;e.r=o+a}}}function Eo(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Ao(t){return t.id}function Co(t){return t.parentId}function zo(t,n){return t.parent===n.parent?1:2}function Po(t){var n=t.children;return n?n[0]:t.t}function Ro(t){var n=t.children;return n?n[n.length-1]:t.t}function Lo(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function qo(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}function Uo(t,n,e){return t.a.parent===n.parent?t.a:e}function Do(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Oo(t){for(var n,e,r,i,o,u=new Do(t,0),a=[u];n=a.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)a.push(e=n.children[i]=new Do(r[i],i)),e.parent=n;return(u.parent=new Do(null,0)).children=[u],u}function Fo(t,n,e,r,i,o){for(var u,a,c,s,f,l,h,p,d,v,_,y=[],g=n.children,m=0,x=0,b=g.length,w=n.value;m<b;){c=i-e,s=o-r;do{f=g[x++].value}while(!f&&x<b);for(l=h=f,_=f*f*(v=Math.max(s/c,c/s)/(w*t)),d=Math.max(h/_,_/l);x<b;++x){if(f+=a=g[x].value,a<l&&(l=a),a>h&&(h=a),_=f*f*v,(p=Math.max(h/_,_/l))>d){f-=a;break}d=p}y.push(u={value:f,dice:c<s,children:g.slice(m,x)}),u.dice?Vv(u,e,r,i,w?r+=s*f/w:o):Jv(u,e,r,w?e+=c*f/w:i,o),w-=f,m=x}return y}function Io(t,n){return t[0]-n[0]||t[1]-n[1]}function Yo(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&n_(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function Bo(t){this._size=t,this._call=this._error=null,this._tasks=[],this._data=[],this._waiting=this._active=this._ended=this._start=0}function jo(t){if(!t._start)try{Ho(t)}catch(n){if(t._tasks[t._ended+t._active-1])$o(t,n);else if(!t._data)throw n}}function Ho(t){for(;t._start=t._waiting&&t._active<t._size;){var n=t._ended+t._active,e=t._tasks[n],r=e.length-1,i=e[r];e[r]=Xo(t,n),--t._waiting,++t._active,e=i.apply(null,e),t._tasks[n]&&(t._tasks[n]=e||r_)}}function Xo(t,n){return function(e,r){t._tasks[n]&&(--t._active,++t._ended,t._tasks[n]=null,null==t._error&&(null!=e?$o(t,e):(t._data[n]=r,t._waiting?jo(t):Vo(t))))}}function $o(t,n){var e,r=t._tasks.length;for(t._error=n,t._data=void 0,t._waiting=NaN;--r>=0;)if((e=t._tasks[r])&&(t._tasks[r]=null,e.abort))try{e.abort()}catch(n){}t._active=NaN,Vo(t)}function Vo(t){if(!t._active&&t._call){var n=t._data;t._data=void 0,t._call(t._error,n)}}function Wo(t){if(null==t)t=1/0;else if(!((t=+t)>=1))throw new Error("invalid concurrency");return new Bo(t)}function Zo(t){return function(n,e){t(null==n?e:null)}}function Go(t){var n=t.responseType;return n&&"text"!==n?t.response:t.responseText}function Jo(t,n){return function(e){return t(e.responseText,n)}}function Qo(t){function n(n){var o=n+"",u=e.get(o);if(!u){if(i!==M_)return i;e.set(o,u=r.push(n))}return t[(u-1)%t.length]}var e=we(),r=[],i=M_;return t=null==t?[]:w_.call(t),n.domain=function(t){if(!arguments.length)return r.slice();r=[],e=we();for(var i,o,u=-1,a=t.length;++u<a;)e.has(o=(i=t[u])+"")||e.set(o,r.push(i));return n},n.range=function(e){return arguments.length?(t=w_.call(e),n):t.slice()},n.unknown=function(t){return arguments.length?(i=t,n):i},n.copy=function(){return Qo().domain(r).range(t).unknown(i)},n}function Ko(){function t(){var t=i().length,r=u[1]<u[0],l=u[r-0],h=u[1-r];n=(h-l)/Math.max(1,t-c+2*s),a&&(n=Math.floor(n)),l+=(h-l-n*(t-c))*f,e=n*(1-c),a&&(l=Math.round(l),e=Math.round(e));var p=Ms(t).map(function(t){return l+n*t});return o(r?p.reverse():p)}var n,e,r=Qo().unknown(void 0),i=r.domain,o=r.range,u=[0,1],a=!1,c=0,s=0,f=.5;return delete r.unknown,r.domain=function(n){return arguments.length?(i(n),t()):i()},r.range=function(n){return arguments.length?(u=[+n[0],+n[1]],t()):u.slice()},r.rangeRound=function(n){return u=[+n[0],+n[1]],a=!0,t()},r.bandwidth=function(){return e},r.step=function(){return n},r.round=function(n){return arguments.length?(a=!!n,t()):a},r.padding=function(n){return arguments.length?(c=s=Math.max(0,Math.min(1,n)),t()):c},r.paddingInner=function(n){return arguments.length?(c=Math.max(0,Math.min(1,n)),t()):c},r.paddingOuter=function(n){return arguments.length?(s=Math.max(0,Math.min(1,n)),t()):s},r.align=function(n){return arguments.length?(f=Math.max(0,Math.min(1,n)),t()):f},r.copy=function(){return Ko().domain(i()).range(u).round(a).paddingInner(c).paddingOuter(s).align(f)},t()}function tu(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return tu(n())},t}function nu(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:T_(n)}function eu(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}function ru(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}function iu(t,n,e,r){var i=t[0],o=t[1],u=n[0],a=n[1];return o<i?(i=e(o,i),u=r(a,u)):(i=e(i,o),u=r(u,a)),function(t){return u(i(t))}}function ou(t,n,e,r){var i=Math.min(t.length,n.length)-1,o=new Array(i),u=new Array(i),a=-1;for(t[i]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<i;)o[a]=e(t[a],t[a+1]),u[a]=r(n[a],n[a+1]);return function(n){var e=hs(t,n,1,i)-1;return u[e](o[e](n))}}function uu(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp())}function au(t,n){function e(){return i=Math.min(a.length,c.length)>2?ou:iu,o=u=null,r}function r(n){return(o||(o=i(a,c,f?eu(t):t,s)))(+n)}var i,o,u,a=N_,c=N_,s=cl,f=!1;return r.invert=function(t){return(u||(u=i(c,a,nu,f?ru(n):n)))(+t)},r.domain=function(t){return arguments.length?(a=b_.call(t,k_),e()):a.slice()},r.range=function(t){return arguments.length?(c=w_.call(t),e()):c.slice()},r.rangeRound=function(t){return c=w_.call(t),s=sl,e()},r.clamp=function(t){return arguments.length?(f=!!t,e()):f},r.interpolate=function(t){return arguments.length?(s=t,e()):s},e()}function cu(t){var n=t.domain;return t.ticks=function(t){var e=n();return Ss(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){return S_(n(),t,e)},t.nice=function(e){null==e&&(e=10);var i,o=n(),u=0,a=o.length-1,c=o[u],s=o[a];return s<c&&(i=c,c=s,s=i,i=u,u=a,a=i),(i=r(c,s,e))>0?i=r(c=Math.floor(c/i)*i,s=Math.ceil(s/i)*i,e):i<0&&(i=r(c=Math.ceil(c*i)/i,s=Math.floor(s*i)/i,e)),i>0?(o[u]=Math.floor(c/i)*i,o[a]=Math.ceil(s/i)*i,n(o)):i<0&&(o[u]=Math.ceil(c*i)/i,o[a]=Math.floor(s*i)/i,n(o)),t},t}function su(){var t=au(nu,rl);return t.copy=function(){return uu(t,su())},cu(t)}function fu(){function t(t){return+t}var n=[0,1];return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=b_.call(e,k_),t):n.slice()},t.copy=function(){return fu().domain(n)},cu(t)}function lu(t,n){return(n=Math.log(n/t))?function(e){return Math.log(e/t)/n}:T_(n)}function hu(t,n){return t<0?function(e){return-Math.pow(-n,e)*Math.pow(-t,1-e)}:function(e){return Math.pow(n,e)*Math.pow(t,1-e)}}function pu(t){return isFinite(t)?+("1e"+t):t<0?0:t}function du(t){return 10===t?pu:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}function vu(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}function _u(t){return function(n){return-t(-n)}}function yu(){function n(){return o=vu(i),u=du(i),r()[0]<0&&(o=_u(o),u=_u(u)),e}var e=au(lu,hu).domain([1,10]),r=e.domain,i=10,o=vu(10),u=du(10);return e.base=function(t){return arguments.length?(i=+t,n()):i},e.domain=function(t){return arguments.length?(r(t),n()):r()},e.ticks=function(t){var n,e=r(),a=e[0],c=e[e.length-1];(n=c<a)&&(h=a,a=c,c=h);var s,f,l,h=o(a),p=o(c),d=null==t?10:+t,v=[];if(!(i%1)&&p-h<d){if(h=Math.round(h)-1,p=Math.round(p)+1,a>0){for(;h<p;++h)for(f=1,s=u(h);f<i;++f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else for(;h<p;++h)for(f=i-1,s=u(h);f>=1;--f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else v=Ss(h,p,Math.min(p-h,d)).map(u);return n?v.reverse():v},e.tickFormat=function(n,r){if(null==r&&(r=10===i?".0e":","),"function"!=typeof r&&(r=t.format(r)),n===1/0)return r;null==n&&(n=10);var a=Math.max(1,i*n/e.ticks().length);return function(t){var n=t/u(Math.round(o(t)));return n*i<i-.5&&(n*=i),n<=a?r(t):""}},e.nice=function(){return r(E_(r(),{floor:function(t){return u(Math.floor(o(t)))},ceil:function(t){return u(Math.ceil(o(t)))}}))},e.copy=function(){return uu(e,yu().base(i))},e}function gu(t,n){return t<0?-Math.pow(-t,n):Math.pow(t,n)}function mu(){var t=1,n=au(function(n,e){return(e=gu(e,t)-(n=gu(n,t)))?function(r){return(gu(r,t)-n)/e}:T_(e)},function(n,e){return e=gu(e,t)-(n=gu(n,t)),function(r){return gu(n+e*r,1/t)}}),e=n.domain;return n.exponent=function(n){return arguments.length?(t=+n,e(e())):t},n.copy=function(){return uu(n,mu().exponent(t))},cu(n)}function xu(){function t(){var t=0,o=Math.max(1,r.length);for(i=new Array(o-1);++t<o;)i[t-1]=As(e,t/o);return n}function n(t){if(!isNaN(t=+t))return r[hs(i,t)]}var e=[],r=[],i=[];return n.invertExtent=function(t){var n=r.indexOf(t);return n<0?[NaN,NaN]:[n>0?i[n-1]:e[0],n<i.length?i[n]:e[e.length-1]]},n.domain=function(n){if(!arguments.length)return e.slice();e=[];for(var r,i=0,o=n.length;i<o;++i)null==(r=n[i])||isNaN(r=+r)||e.push(r);return e.sort(ss),t()},n.range=function(n){return arguments.length?(r=w_.call(n),t()):r.slice()},n.quantiles=function(){return i.slice()},n.copy=function(){return xu().domain(e).range(r)},n}function bu(){function t(t){if(t<=t)return u[hs(o,t,0,i)]}function n(){var n=-1;for(o=new Array(i);++n<i;)o[n]=((n+1)*r-(n-i)*e)/(i+1);return t}var e=0,r=1,i=1,o=[.5],u=[0,1];return t.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n()):[e,r]},t.range=function(t){return arguments.length?(i=(u=w_.call(t)).length-1,n()):u.slice()},t.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},t.copy=function(){return bu().domain([e,r]).range(u)},cu(t)}function wu(){function t(t){if(t<=t)return e[hs(n,t,0,r)]}var n=[.5],e=[0,1],r=1;return t.domain=function(i){return arguments.length?(n=w_.call(i),r=Math.min(n.length,e.length-1),t):n.slice()},t.range=function(i){return arguments.length?(e=w_.call(i),r=Math.min(n.length,e.length-1),t):e.slice()},t.invertExtent=function(t){var r=e.indexOf(t);return[n[r-1],n[r]]},t.copy=function(){return wu().domain(n).range(e)},t}function Mu(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(new Date(+e))}while(n(e,o),t(e),e<r);return u},i.filter=function(e){return Mu(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return A_.setTime(+n),C_.setTime(+r),t(A_),t(C_),Math.floor(e(A_,C_))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}function Tu(t){return Mu(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*R_)/L_})}function ku(t){return Mu(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/L_})}function Nu(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Su(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Eu(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function Au(t){function n(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,s=t.length;for(e instanceof Date||(e=new Date(+e));++a<s;)37===t.charCodeAt(a)&&(u.push(t.slice(c,a)),null!=(i=Py[r=t.charAt(++a)])?r=t.charAt(++a):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),u.push(r),c=a+1);return u.push(t.slice(c,a)),u.join("")}}function e(t,n){return function(e){var i=Eu(1900);if(r(i,t,e+="",0)!=e.length)return null;if("p"in i&&(i.H=i.H%12+12*i.p),"W"in i||"U"in i){"w"in i||(i.w="W"in i?1:0);var o="Z"in i?Su(Eu(i.y)).getUTCDay():n(Eu(i.y)).getDay();i.m=0,i.d="W"in i?(i.w+6)%7+7*i.W-(o+5)%7:i.w+7*i.U-(o+6)%7}return"Z"in i?(i.H+=i.Z/100|0,i.M+=i.Z%100,Su(i)):n(i)}}function r(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u<a;){if(r>=c)return-1;if(37===(i=n.charCodeAt(u++))){if(i=n.charAt(u++),!(o=T[i in Py?n.charAt(u++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}var i=t.dateTime,o=t.date,u=t.time,a=t.periods,c=t.days,s=t.shortDays,f=t.months,l=t.shortMonths,h=Pu(a),p=Ru(a),d=Pu(c),v=Ru(c),_=Pu(s),y=Ru(s),g=Pu(f),m=Ru(f),x=Pu(l),b=Ru(l),w={a:function(t){return s[t.getDay()]},A:function(t){return c[t.getDay()]},b:function(t){return l[t.getMonth()]},B:function(t){return f[t.getMonth()]},c:null,d:Wu,e:Wu,H:Zu,I:Gu,j:Ju,L:Qu,m:Ku,M:ta,p:function(t){return a[+(t.getHours()>=12)]},S:na,U:ea,w:ra,W:ia,x:null,X:null,y:oa,Y:ua,Z:aa,"%":wa},M={a:function(t){return s[t.getUTCDay()]},A:function(t){return c[t.getUTCDay()]},b:function(t){return l[t.getUTCMonth()]},B:function(t){return f[t.getUTCMonth()]},c:null,d:ca,e:ca,H:sa,I:fa,j:la,L:ha,m:pa,M:da,p:function(t){return a[+(t.getUTCHours()>=12)]},S:va,U:_a,w:ya,W:ga,x:null,X:null,y:ma,Y:xa,Z:ba,"%":wa},T={a:function(t,n,e){var r=_.exec(n.slice(e));return r?(t.w=y[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=v[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=x.exec(n.slice(e));return r?(t.m=b[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=m[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,n,e){return r(t,i,n,e)},d:Yu,e:Yu,H:ju,I:ju,j:Bu,L:$u,m:Iu,M:Hu,p:function(t,n,e){var r=h.exec(n.slice(e));return r?(t.p=p[r[0].toLowerCase()],e+r[0].length):-1},S:Xu,U:qu,w:Lu,W:Uu,x:function(t,n,e){return r(t,o,n,e)},X:function(t,n,e){return r(t,u,n,e)},y:Ou,Y:Du,Z:Fu,"%":Vu};return w.x=n(o,w),w.X=n(u,w),w.c=n(i,w),M.x=n(o,M),M.X=n(u,M),M.c=n(i,M),{format:function(t){var e=n(t+="",w);return e.toString=function(){return t},e},parse:function(t){var n=e(t+="",Nu);return n.toString=function(){return t},n},utcFormat:function(t){var e=n(t+="",M);return e.toString=function(){return t},e},utcParse:function(t){var n=e(t,Su);return n.toString=function(){return t},n}}}function Cu(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function zu(t){return t.replace(qy,"\\$&")}function Pu(t){return new RegExp("^(?:"+t.map(zu).join("|")+")","i")}function Ru(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function Lu(t,n,e){var r=Ry.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function qu(t,n,e){var r=Ry.exec(n.slice(e));return r?(t.U=+r[0],e+r[0].length):-1}function Uu(t,n,e){var r=Ry.exec(n.slice(e));return r?(t.W=+r[0],e+r[0].length):-1}function Du(t,n,e){var r=Ry.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function Ou(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function Fu(t,n,e){var r=/^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Iu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function Yu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function Bu(t,n,e){var r=Ry.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function ju(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Hu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Xu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function $u(t,n,e){var r=Ry.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Vu(t,n,e){var r=Ly.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Wu(t,n){return Cu(t.getDate(),n,2)}function Zu(t,n){return Cu(t.getHours(),n,2)}function Gu(t,n){return Cu(t.getHours()%12||12,n,2)}function Ju(t,n){return Cu(1+Y_.count(oy(t),t),n,3)}function Qu(t,n){return Cu(t.getMilliseconds(),n,3)}function Ku(t,n){return Cu(t.getMonth()+1,n,2)}function ta(t,n){return Cu(t.getMinutes(),n,2)}function na(t,n){return Cu(t.getSeconds(),n,2)}function ea(t,n){return Cu(j_.count(oy(t),t),n,2)}function ra(t){return t.getDay()}function ia(t,n){return Cu(H_.count(oy(t),t),n,2)}function oa(t,n){return Cu(t.getFullYear()%100,n,2)}function ua(t,n){return Cu(t.getFullYear()%1e4,n,4)}function aa(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Cu(n/60|0,"0",2)+Cu(n%60,"0",2)}function ca(t,n){return Cu(t.getUTCDate(),n,2)}function sa(t,n){return Cu(t.getUTCHours(),n,2)}function fa(t,n){return Cu(t.getUTCHours()%12||12,n,2)}function la(t,n){return Cu(1+ly.count(Ay(t),t),n,3)}function ha(t,n){return Cu(t.getUTCMilliseconds(),n,3)}function pa(t,n){return Cu(t.getUTCMonth()+1,n,2)}function da(t,n){return Cu(t.getUTCMinutes(),n,2)}function va(t,n){return Cu(t.getUTCSeconds(),n,2)}function _a(t,n){return Cu(py.count(Ay(t),t),n,2)}function ya(t){return t.getUTCDay()}function ga(t,n){return Cu(dy.count(Ay(t),t),n,2)}function ma(t,n){return Cu(t.getUTCFullYear()%100,n,2)}function xa(t,n){return Cu(t.getUTCFullYear()%1e4,n,4)}function ba(){return"+0000"}function wa(){return"%"}function Ma(n){return Cy=Au(n),t.timeFormat=Cy.format,t.timeParse=Cy.parse,t.utcFormat=Cy.utcFormat,t.utcParse=Cy.utcParse,Cy}function Ta(t){return new Date(t)}function ka(t){return t instanceof Date?+t:+new Date(+t)}function Na(t,n,e,r,o,u,a,c,s){function f(i){return(a(i)<i?v:u(i)<i?_:o(i)<i?y:r(i)<i?g:n(i)<i?e(i)<i?m:x:t(i)<i?b:w)(i)}function l(n,e,r,o){if(null==n&&(n=10),"number"==typeof n){var u=Math.abs(r-e)/n,a=fs(function(t){return t[2]}).right(M,u);a===M.length?(o=i(e/Hy,r/Hy,n),n=t):a?(o=(a=M[u/M[a-1][2]<M[a][2]/u?a-1:a])[1],n=a[0]):(o=i(e,r,n),n=c)}return null==o?n:n.every(o)}var h=au(nu,rl),p=h.invert,d=h.domain,v=s(".%L"),_=s(":%S"),y=s("%I:%M"),g=s("%I %p"),m=s("%a %d"),x=s("%b %d"),b=s("%B"),w=s("%Y"),M=[[a,1,Oy],[a,5,5*Oy],[a,15,15*Oy],[a,30,30*Oy],[u,1,Fy],[u,5,5*Fy],[u,15,15*Fy],[u,30,30*Fy],[o,1,Iy],[o,3,3*Iy],[o,6,6*Iy],[o,12,12*Iy],[r,1,Yy],[r,2,2*Yy],[e,1,By],[n,1,jy],[n,3,3*jy],[t,1,Hy]];return h.invert=function(t){return new Date(p(t))},h.domain=function(t){return arguments.length?d(b_.call(t,ka)):d().map(Ta)},h.ticks=function(t,n){var e,r=d(),i=r[0],o=r[r.length-1],u=o<i;return u&&(e=i,i=o,o=e),e=l(t,i,o,n),e=e?e.range(i,o+1):[],u?e.reverse():e},h.tickFormat=function(t,n){return null==n?f:s(n)},h.nice=function(t,n){var e=d();return(t=l(t,e[0],e[e.length-1],n))?d(E_(e,t)):h},h.copy=function(){return uu(h,Na(t,n,e,r,o,u,a,c,s))},h}function Sa(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}function Ea(t){function n(n){var o=(n-e)/(r-e);return t(i?Math.max(0,Math.min(1,o)):o)}var e=0,r=1,i=!1;return n.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n):[e,r]},n.clamp=function(t){return arguments.length?(i=!!t,n):i},n.interpolator=function(e){return arguments.length?(t=e,n):t},n.copy=function(){return Ea(t).domain([e,r]).clamp(i)},cu(n)}function Aa(t){return t>1?0:t<-1?pg:Math.acos(t)}function Ca(t){return t>=1?dg:t<=-1?-dg:Math.asin(t)}function za(t){return t.innerRadius}function Pa(t){return t.outerRadius}function Ra(t){return t.startAngle}function La(t){return t.endAngle}function qa(t){return t&&t.padAngle}function Ua(t,n,e,r,i,o,u,a){var c=e-t,s=r-n,f=u-i,l=a-o,h=(f*(n-o)-l*(t-i))/(l*c-f*s);return[t+h*c,n+h*s]}function Da(t,n,e,r,i,o,u){var a=t-e,c=n-r,s=(u?o:-o)/lg(a*a+c*c),f=s*c,l=-s*a,h=t+f,p=n+l,d=e+f,v=r+l,_=(h+d)/2,y=(p+v)/2,g=d-h,m=v-p,x=g*g+m*m,b=i-o,w=h*v-d*p,M=(m<0?-1:1)*lg(cg(0,b*b*x-w*w)),T=(w*m-g*M)/x,k=(-w*g-m*M)/x,N=(w*m+g*M)/x,S=(-w*g+m*M)/x,E=T-_,A=k-y,C=N-_,z=S-y;return E*E+A*A>C*C+z*z&&(T=N,k=S),{cx:T,cy:k,x01:-f,y01:-l,x11:T*(i/b-1),y11:k*(i/b-1)}}function Oa(t){this._context=t}function Fa(t){return t[0]}function Ia(t){return t[1]}function Ya(t){this._curve=t}function Ba(t){function n(n){return new Ya(t(n))}return n._curve=t,n}function ja(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Ba(t)):n()._curve},t}function Ha(t){return t.source}function Xa(t){return t.target}function $a(t){function n(){var n,a=kg.call(arguments),c=e.apply(this,a),s=r.apply(this,a);if(u||(u=n=ve()),t(u,+i.apply(this,(a[0]=c,a)),+o.apply(this,a),+i.apply(this,(a[0]=s,a)),+o.apply(this,a)),n)return u=null,n+""||null}var e=Ha,r=Xa,i=Fa,o=Ia,u=null;return n.source=function(t){return arguments.length?(e=t,n):e},n.target=function(t){return arguments.length?(r=t,n):r},n.x=function(t){return arguments.length?(i="function"==typeof t?t:ig(+t),n):i},n.y=function(t){return arguments.length?(o="function"==typeof t?t:ig(+t),n):o},n.context=function(t){return arguments.length?(u=null==t?null:t,n):u},n}function Va(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function Wa(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function Za(t,n,e,r,i){var o=Tg(n,e),u=Tg(n,e=(e+i)/2),a=Tg(r,e),c=Tg(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(u[0],u[1],a[0],a[1],c[0],c[1])}function Ga(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Ja(t){this._context=t}function Qa(t){this._context=t}function Ka(t){this._context=t}function tc(t,n){this._basis=new Ja(t),this._beta=n}function nc(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function ec(t,n){this._context=t,this._k=(1-n)/6}function rc(t,n){this._context=t,this._k=(1-n)/6}function ic(t,n){this._context=t,this._k=(1-n)/6}function oc(t,n,e){var r=t._x1,i=t._y1,o=t._x2,u=t._y2;if(t._l01_a>hg){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>hg){var s=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*s+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*s+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function uc(t,n){this._context=t,this._alpha=n}function ac(t,n){this._context=t,this._alpha=n}function cc(t,n){this._context=t,this._alpha=n}function sc(t){this._context=t}function fc(t){return t<0?-1:1}function lc(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(fc(o)+fc(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function hc(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function pc(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function dc(t){this._context=t}function vc(t){this._context=new _c(t)}function _c(t){this._context=t}function yc(t){this._context=t}function gc(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(i[0]=0,o[0]=2,u[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,u[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,u[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,u[n]-=e*u[n-1];for(i[r-1]=u[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(u[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function mc(t,n){this._context=t,this._t=n}function xc(t,n){return t[n]}function bc(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function wc(t){return t[0]}function Mc(t){return t[1]}function Tc(){this._=null}function kc(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function Nc(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Sc(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function Ec(t){for(;t.L;)t=t.L;return t}function Ac(t,n,e,r){var i=[null,null],o=um.push(i)-1;return i.left=t,i.right=n,e&&zc(i,t,n,e),r&&zc(i,n,t,r),im[t.index].halfedges.push(o),im[n.index].halfedges.push(o),i}function Cc(t,n,e){var r=[n,e];return r.left=t,r}function zc(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function Pc(t,n,e,r,i){var o,u=t[0],a=t[1],c=u[0],s=u[1],f=0,l=1,h=a[0]-c,p=a[1]-s;if(o=n-c,h||!(o>0)){if(o/=h,h<0){if(o<f)return;o<l&&(l=o)}else if(h>0){if(o>l)return;o>f&&(f=o)}if(o=r-c,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>f&&(f=o)}else if(h>0){if(o<f)return;o<l&&(l=o)}if(o=e-s,p||!(o>0)){if(o/=p,p<0){if(o<f)return;o<l&&(l=o)}else if(p>0){if(o>l)return;o>f&&(f=o)}if(o=i-s,p||!(o<0)){if(o/=p,p<0){if(o>l)return;o>f&&(f=o)}else if(p>0){if(o<f)return;o<l&&(l=o)}return!(f>0||l<1)||(f>0&&(t[0]=[c+f*h,s+f*p]),l<1&&(t[1]=[c+l*h,s+l*p]),!0)}}}}}function Rc(t,n,e,r,i){var o=t[1];if(o)return!0;var u,a,c=t[0],s=t.left,f=t.right,l=s[0],h=s[1],p=f[0],d=f[1],v=(l+p)/2,_=(h+d)/2;if(d===h){if(v<n||v>=r)return;if(l>p){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=(l-p)/(d-h),a=_-u*v,u<-1||u>1)if(l>p){if(c){if(c[1]>=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]<e)return}else c=[(i-a)/u,i];o=[(e-a)/u,e]}else if(h<d){if(c){if(c[0]>=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]<n)return}else c=[r,u*r+a];o=[n,u*n+a]}return t[0]=c,t[1]=o,!0}function Lc(t,n,e,r){for(var i,o=um.length;o--;)Rc(i=um[o],t,n,e,r)&&Pc(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>sm||Math.abs(i[0][1]-i[1][1])>sm)||delete um[o]}function qc(t){return im[t.index]={site:t,halfedges:[]}}function Uc(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function Dc(t,n){return n[+(n.left!==t.site)]}function Oc(t,n){return n[+(n.left===t.site)]}function Fc(){for(var t,n,e,r,i=0,o=im.length;i<o;++i)if((t=im[i])&&(r=(n=t.halfedges).length)){var u=new Array(r),a=new Array(r);for(e=0;e<r;++e)u[e]=e,a[e]=Uc(t,um[n[e]]);for(u.sort(function(t,n){return a[n]-a[t]}),e=0;e<r;++e)a[e]=n[u[e]];for(e=0;e<r;++e)n[e]=a[e]}}function Ic(t,n,e,r){var i,o,u,a,c,s,f,l,h,p,d,v,_=im.length,y=!0;for(i=0;i<_;++i)if(o=im[i]){for(u=o.site,a=(c=o.halfedges).length;a--;)um[c[a]]||c.splice(a,1);for(a=0,s=c.length;a<s;)d=(p=Oc(o,um[c[a]]))[0],v=p[1],l=(f=Dc(o,um[c[++a%s]]))[0],h=f[1],(Math.abs(d-l)>sm||Math.abs(v-h)>sm)&&(c.splice(a,0,um.push(Cc(u,p,Math.abs(d-t)<sm&&r-v>sm?[t,Math.abs(l-t)<sm?h:r]:Math.abs(v-r)<sm&&e-d>sm?[Math.abs(h-r)<sm?l:e,r]:Math.abs(d-e)<sm&&v-n>sm?[e,Math.abs(l-e)<sm?h:n]:Math.abs(v-n)<sm&&d-t>sm?[Math.abs(h-n)<sm?l:t,n]:null))-1),++s);s&&(y=!1)}if(y){var g,m,x,b=1/0;for(i=0,y=null;i<_;++i)(o=im[i])&&(x=(g=(u=o.site)[0]-t)*g+(m=u[1]-n)*m)<b&&(b=x,y=o);if(y){var w=[t,n],M=[t,r],T=[e,r],k=[e,n];y.halfedges.push(um.push(Cc(u=y.site,w,M))-1,um.push(Cc(u,M,T))-1,um.push(Cc(u,T,k))-1,um.push(Cc(u,k,w))-1)}}for(i=0;i<_;++i)(o=im[i])&&(o.halfedges.length||delete im[i])}function Yc(){kc(this),this.x=this.y=this.arc=this.site=this.cy=null}function Bc(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var u=i[0],a=i[1],c=r[0]-u,s=r[1]-a,f=o[0]-u,l=o[1]-a,h=2*(c*l-s*f);if(!(h>=-fm)){var p=c*c+s*s,d=f*f+l*l,v=(l*p-s*d)/h,_=(c*d-f*p)/h,y=am.pop()||new Yc;y.arc=t,y.site=i,y.x=v+u,y.y=(y.cy=_+a)+Math.sqrt(v*v+_*_),t.circle=y;for(var g=null,m=om._;m;)if(y.y<m.y||y.y===m.y&&y.x<=m.x){if(!m.L){g=m.P;break}m=m.L}else{if(!m.R){g=m;break}m=m.R}om.insert(g,y),g||(em=y)}}}}function jc(t){var n=t.circle;n&&(n.P||(em=n.N),om.remove(n),am.push(n),kc(n),t.circle=null)}function Hc(){kc(this),this.edge=this.site=this.circle=null}function Xc(t){var n=cm.pop()||new Hc;return n.site=t,n}function $c(t){jc(t),rm.remove(t),cm.push(t),kc(t)}function Vc(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,u=t.N,a=[t];$c(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<sm&&Math.abs(r-c.circle.cy)<sm;)o=c.P,a.unshift(c),$c(c),c=o;a.unshift(c),jc(c);for(var s=u;s.circle&&Math.abs(e-s.circle.x)<sm&&Math.abs(r-s.circle.cy)<sm;)u=s.N,a.push(s),$c(s),s=u;a.push(s),jc(s);var f,l=a.length;for(f=1;f<l;++f)s=a[f],c=a[f-1],zc(s.edge,c.site,s.site,i);c=a[0],(s=a[l-1]).edge=Ac(c.site,s.site,null,i),Bc(c),Bc(s)}function Wc(t){for(var n,e,r,i,o=t[0],u=t[1],a=rm._;a;)if((r=Zc(a,u)-o)>sm)a=a.L;else{if(!((i=o-Gc(a,u))>sm)){r>-sm?(n=a.P,e=a):i>-sm?(n=a,e=a.N):n=e=a;break}if(!a.R){n=a;break}a=a.R}qc(t);var c=Xc(t);if(rm.insert(n,c),n||e){if(n===e)return jc(n),e=Xc(n.site),rm.insert(c,e),c.edge=e.edge=Ac(n.site,c.site),Bc(n),void Bc(e);if(e){jc(n),jc(e);var s=n.site,f=s[0],l=s[1],h=t[0]-f,p=t[1]-l,d=e.site,v=d[0]-f,_=d[1]-l,y=2*(h*_-p*v),g=h*h+p*p,m=v*v+_*_,x=[(_*g-p*m)/y+f,(h*m-v*g)/y+l];zc(e.edge,s,d,x),c.edge=Ac(s,t,null,x),e.edge=Ac(t,d,null,x),Bc(n),Bc(e)}else c.edge=Ac(n.site,c.site)}}function Zc(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var u=t.P;if(!u)return-1/0;var a=(e=u.site)[0],c=e[1],s=c-n;if(!s)return a;var f=a-r,l=1/o-1/s,h=f/s;return l?(-h+Math.sqrt(h*h-2*l*(f*f/(-2*s)-c+s/2+i-o/2)))/l+r:(r+a)/2}function Gc(t,n){var e=t.N;if(e)return Zc(e,n);var r=t.site;return r[1]===n?r[0]:1/0}function Jc(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function Qc(t,n){return n[1]-t[1]||n[0]-t[0]}function Kc(t,n){var e,r,i,o=t.sort(Qc).pop();for(um=[],im=new Array(t.length),rm=new Tc,om=new Tc;;)if(i=em,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(Wc(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;Vc(i.arc)}if(Fc(),n){var u=+n[0][0],a=+n[0][1],c=+n[1][0],s=+n[1][1];Lc(u,a,c,s),Ic(u,a,c,s)}this.edges=um,this.cells=im,rm=om=um=im=null}function ts(t,n,e){this.target=t,this.type=n,this.transform=e}function ns(t,n,e){this.k=t,this.x=n,this.y=e}function es(t){return t.__zoom||hm}function rs(){t.event.stopImmediatePropagation()}function is(){return!t.event.button}function os(){var t,n,e=this;return e instanceof SVGElement?(t=(e=e.ownerSVGElement||e).width.baseVal.value,n=e.height.baseVal.value):(t=e.clientWidth,n=e.clientHeight),[[0,0],[t,n]]}function us(){return this.__zoom||hm}function as(){return-t.event.deltaY*(t.event.deltaMode?120:1)/500}function cs(){return"ontouchstart"in this}var ss=function(t,n){return t<n?-1:t>n?1:t>=n?0:NaN},fs=function(t){return 1===t.length&&(t=n(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}},ls=fs(ss),hs=ls.right,ps=ls.left,ds=function(t){return null===t?NaN:+t},vs=function(t,n){var e,r,i=t.length,o=0,u=-1,a=0,c=0;if(null==n)for(;++u<i;)isNaN(e=ds(t[u]))||(c+=(r=e-a)*(e-(a+=r/++o)));else for(;++u<i;)isNaN(e=ds(n(t[u],u,t)))||(c+=(r=e-a)*(e-(a+=r/++o)));if(o>1)return c/(o-1)},_s=function(t,n){var e=vs(t,n);return e?Math.sqrt(e):e},ys=function(t,n){var e,r,i,o=t.length,u=-1;if(null==n){for(;++u<o;)if(null!=(e=t[u])&&e>=e)for(r=i=e;++u<o;)null!=(e=t[u])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++u<o;)if(null!=(e=n(t[u],u,t))&&e>=e)for(r=i=e;++u<o;)null!=(e=n(t[u],u,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]},gs=Array.prototype,ms=gs.slice,xs=gs.map,bs=function(t){return function(){return t}},ws=function(t){return t},Ms=function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o},Ts=Math.sqrt(50),ks=Math.sqrt(10),Ns=Math.sqrt(2),Ss=function(t,n,e){var i,o,u,a=n<t,c=-1;if(a&&(i=t,t=n,n=i),0===(u=r(t,n,e))||!isFinite(u))return[];if(u>0)for(t=Math.ceil(t/u),n=Math.floor(n/u),o=new Array(i=Math.ceil(n-t+1));++c<i;)o[c]=(t+c)*u;else for(t=Math.floor(t*u),n=Math.ceil(n*u),o=new Array(i=Math.ceil(t-n+1));++c<i;)o[c]=(t-c)/u;return a&&o.reverse(),o},Es=function(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1},As=function(t,n,e){if(null==e&&(e=ds),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t);return u+(+e(t[o+1],o+1,t)-u)*(i-o)}},Cs=function(t){for(var n,e,r,i=t.length,o=-1,u=0;++o<i;)u+=t[o].length;for(e=new Array(u);--i>=0;)for(n=(r=t[i]).length;--n>=0;)e[--u]=r[n];return e},zs=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r},Ps=function(t){if(!(i=t.length))return[];for(var n=-1,e=zs(t,o),r=new Array(e);++n<e;)for(var i,u=-1,a=r[n]=new Array(i);++u<i;)a[u]=t[u][n];return r},Rs=Array.prototype.slice,Ls=function(t){return t},qs=1,Us=2,Ds=3,Os=4,Fs=1e-6,Is={value:function(){}};p.prototype=h.prototype={constructor:p,on:function(t,n){var e,r=this._,i=d(t+"",r),o=-1,u=i.length;{if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<u;)if(e=(t=i[o]).type)r[e]=_(r[e],t.name,n);else if(null==n)for(e in r)r[e]=_(r[e],t.name,null);return this}for(;++o<u;)if((e=(t=i[o]).type)&&(e=v(r[e],t.name)))return e}},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new p(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var Ys="http://www.w3.org/1999/xhtml",Bs={svg:"http://www.w3.org/2000/svg",xhtml:Ys,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},js=function(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Bs.hasOwnProperty(n)?{space:Bs[n],local:t}:t},Hs=function(t){var n=js(t);return(n.local?g:y)(n)},Xs=0;x.prototype=m.prototype={constructor:x,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};var $s=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var Vs=document.documentElement;if(!Vs.matches){var Ws=Vs.webkitMatchesSelector||Vs.msMatchesSelector||Vs.mozMatchesSelector||Vs.oMatchesSelector;$s=function(t){return function(){return Ws.call(this,t)}}}}var Zs=$s,Gs={};t.event=null,"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(Gs={mouseenter:"mouseover",mouseleave:"mouseout"}));var Js=function(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e},Qs=function(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,r=r.matrixTransform(t.getScreenCTM().inverse()),[r.x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]},Ks=function(t){var n=Js();return n.changedTouches&&(n=n.changedTouches[0]),Qs(t,n)},tf=function(t){return null==t?S:function(){return this.querySelector(t)}},nf=function(t){return null==t?E:function(){return this.querySelectorAll(t)}},ef=function(t){return new Array(t.length)};A.prototype={constructor:A,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var rf=function(t){return function(){return t}},of="$",uf=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};W.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var af=[null];pt.prototype=dt.prototype={constructor:pt,select:function(t){"function"!=typeof t&&(t=tf(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u,a=n[i],c=a.length,s=r[i]=new Array(c),f=0;f<c;++f)(o=a[f])&&(u=t.call(o,o.__data__,f,a))&&("__data__"in o&&(u.__data__=o.__data__),s[f]=u);return new pt(r,this._parents)},selectAll:function(t){"function"!=typeof t&&(t=nf(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var u,a=n[o],c=a.length,s=0;s<c;++s)(u=a[s])&&(r.push(t.call(u,u.__data__,s,a)),i.push(u));return new pt(r,i)},filter:function(t){"function"!=typeof t&&(t=Zs(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new pt(r,this._parents)},data:function(t,n){if(!t)return p=new Array(this.size()),s=-1,this.each(function(t){p[++s]=t}),p;var e=n?z:C,r=this._parents,i=this._groups;"function"!=typeof t&&(t=rf(t));for(var o=i.length,u=new Array(o),a=new Array(o),c=new Array(o),s=0;s<o;++s){var f=r[s],l=i[s],h=l.length,p=t.call(f,f&&f.__data__,s,r),d=p.length,v=a[s]=new Array(d),_=u[s]=new Array(d);e(f,l,v,_,c[s]=new Array(h),p,n);for(var y,g,m=0,x=0;m<d;++m)if(y=v[m]){for(m>=x&&(x=m+1);!(g=_[x])&&++x<d;);y._next=g||null}}return u=new pt(u,r),u._enter=a,u._exit=c,u},enter:function(){return new pt(this._enter||this._groups.map(ef),this._parents)},exit:function(){return new pt(this._exit||this._groups.map(ef),this._parents)},merge:function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new pt(u,this._parents)},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,u=i[o];--o>=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){t||(t=P);for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i){for(var o,u=n[i],a=u.length,c=r[i]=new Array(a),s=0;s<a;++s)(o=u[s])&&(c[s]=o);c.sort(function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e})}return new pt(r,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var u=r[i];if(u)return u}return null},size:function(){var t=0;return this.each(function(){++t}),t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],u=0,a=o.length;u<a;++u)(i=o[u])&&t.call(i,i.__data__,u,o);return this},attr:function(t,n){var e=js(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?L:R:"function"==typeof n?e.local?O:D:e.local?U:q)(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?F:"function"==typeof n?Y:I)(t,n,null==e?"":e)):B(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?j:"function"==typeof n?X:H)(t,n)):this.node()[t]},classed:function(t,n){var e=$(t+"");if(arguments.length<2){for(var r=V(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?K:n?J:Q)(e,n))},text:function(t){return arguments.length?this.each(null==t?tt:("function"==typeof t?et:nt)(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?rt:("function"==typeof t?ot:it)(t)):this.node().innerHTML},raise:function(){return this.each(ut)},lower:function(){return this.each(at)},append:function(t){var n="function"==typeof t?t:Hs(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},insert:function(t,n){var e="function"==typeof t?t:Hs(t),r=null==n?ct:"function"==typeof n?n:tf(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},remove:function(){return this.each(st)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=M(t+""),u=o.length;{if(!(arguments.length<2)){for(a=n?k:T,null==e&&(e=!1),r=0;r<u;++r)this.each(a(o[r],n,e));return this}var a=this.node().__on;if(a)for(var c,s=0,f=a.length;s<f;++s)for(r=0,c=a[s];r<u;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value}},dispatch:function(t,n){return this.each(("function"==typeof n?ht:lt)(t,n))}};var cf=function(t){return"string"==typeof t?new pt([[document.querySelector(t)]],[document.documentElement]):new pt([[t]],af)},sf=function(t,n,e){arguments.length<3&&(e=n,n=Js().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Qs(t,r);return null},ff=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},lf=function(t){var n=t.document.documentElement,e=cf(t).on("dragstart.drag",ff,!0);"onselectstart"in n?e.on("selectstart.drag",ff,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")},hf=function(t){return function(){return t}};yt.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var pf=function(t,n,e){t.prototype=n.prototype=e,e.constructor=t},df="\\s*([+-]?\\d+)\\s*",vf="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",_f="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",yf=/^#([0-9a-f]{3})$/,gf=/^#([0-9a-f]{6})$/,mf=new RegExp("^rgb\\("+[df,df,df]+"\\)$"),xf=new RegExp("^rgb\\("+[_f,_f,_f]+"\\)$"),bf=new RegExp("^rgba\\("+[df,df,df,vf]+"\\)$"),wf=new RegExp("^rgba\\("+[_f,_f,_f,vf]+"\\)$"),Mf=new RegExp("^hsl\\("+[vf,_f,_f]+"\\)$"),Tf=new RegExp("^hsla\\("+[vf,_f,_f,vf]+"\\)$"),kf={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};pf(Mt,Tt,{displayable:function(){return this.rgb().displayable()},toString:function(){return this.rgb()+""}}),pf(At,Et,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new At(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new At(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),pf(Rt,Pt,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new At(Lt(t>=240?t-240:t+120,i,r),Lt(t,i,r),Lt(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Nf=Math.PI/180,Sf=180/Math.PI,Ef=.95047,Af=1,Cf=1.08883,zf=4/29,Pf=6/29,Rf=3*Pf*Pf,Lf=Pf*Pf*Pf;pf(Dt,Ut,wt(Mt,{brighter:function(t){return new Dt(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Dt(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=Af*Ft(t),n=Ef*Ft(n),e=Cf*Ft(e),new At(It(3.2404542*n-1.5371385*t-.4985314*e),It(-.969266*n+1.8760108*t+.041556*e),It(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),pf(Ht,jt,wt(Mt,{brighter:function(t){return new Ht(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Ht(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return qt(this).rgb()}}));var qf=-.14861,Uf=1.78277,Df=-.29227,Of=-.90649,Ff=1.97294,If=Ff*Of,Yf=Ff*Uf,Bf=Uf*Df-Of*qf;pf(Vt,$t,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Vt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Vt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Nf,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new At(255*(n+e*(qf*r+Uf*i)),255*(n+e*(Df*r+Of*i)),255*(n+e*(Ff*r)),this.opacity)}}));var jf,Hf,Xf,$f,Vf,Wf,Zf=function(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=r<n-1?t[r+2]:2*o-i;return Wt((e-r/n)*n,u,i,o,a)}},Gf=function(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],u=t[(r+1)%n],a=t[(r+2)%n];return Wt((e-r/n)*n,i,o,u,a)}},Jf=function(t){return function(){return t}},Qf=function t(n){function e(t,n){var e=r((t=Et(t)).r,(n=Et(n)).r),i=r(t.g,n.g),o=r(t.b,n.b),u=Kt(t.opacity,n.opacity);return function(n){return t.r=e(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}var r=Qt(n);return e.gamma=t,e}(1),Kf=tn(Zf),tl=tn(Gf),nl=function(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(r),u=new Array(r);for(e=0;e<i;++e)o[e]=cl(t[e],n[e]);for(;e<r;++e)u[e]=n[e];return function(t){for(e=0;e<i;++e)u[e]=o[e](t);return u}},el=function(t,n){var e=new Date;return t=+t,n-=t,function(r){return e.setTime(t+n*r),e}},rl=function(t,n){return t=+t,n-=t,function(e){return t+n*e}},il=function(t,n){var e,r={},i={};null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={});for(e in n)e in t?r[e]=cl(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}},ol=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ul=new RegExp(ol.source,"g"),al=function(t,n){var e,r,i,o=ol.lastIndex=ul.lastIndex=0,u=-1,a=[],c=[];for(t+="",n+="";(e=ol.exec(t))&&(r=ul.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:rl(e,r)})),o=ul.lastIndex;return o<n.length&&(i=n.slice(o),a[u]?a[u]+=i:a[++u]=i),a.length<2?c[0]?en(c[0].x):nn(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)a[(e=c[r]).i]=e.x(t);return a.join("")})},cl=function(t,n){var e,r=typeof n;return null==n||"boolean"===r?Jf(n):("number"===r?rl:"string"===r?(e=Tt(n))?(n=e,Qf):al:n instanceof Tt?Qf:n instanceof Date?el:Array.isArray(n)?nl:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?il:rl)(t,n)},sl=function(t,n){return t=+t,n-=t,function(e){return Math.round(t+n*e)}},fl=180/Math.PI,ll={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1},hl=function(t,n,e,r,i,o){var u,a,c;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,c/=a),t*r<n*e&&(t=-t,n=-n,c=-c,u=-u),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*fl,skewX:Math.atan(c)*fl,scaleX:u,scaleY:a}},pl=rn(function(t){return"none"===t?ll:(jf||(jf=document.createElement("DIV"),Hf=document.documentElement,Xf=document.defaultView),jf.style.transform=t,t=Xf.getComputedStyle(Hf.appendChild(jf),null).getPropertyValue("transform"),Hf.removeChild(jf),t=t.slice(7,-1).split(","),hl(+t[0],+t[1],+t[2],+t[3],+t[4],+t[5]))},"px, ","px)","deg)"),dl=rn(function(t){return null==t?ll:($f||($f=document.createElementNS("http://www.w3.org/2000/svg","g")),$f.setAttribute("transform",t),(t=$f.transform.baseVal.consolidate())?(t=t.matrix,hl(t.a,t.b,t.c,t.d,t.e,t.f)):ll)},", ",")",")"),vl=Math.SQRT2,_l=function(t,n){var e,r,i=t[0],o=t[1],u=t[2],a=n[0],c=n[1],s=n[2],f=a-i,l=c-o,h=f*f+l*l;if(h<1e-12)r=Math.log(s/u)/vl,e=function(t){return[i+t*f,o+t*l,u*Math.exp(vl*t*r)]};else{var p=Math.sqrt(h),d=(s*s-u*u+4*h)/(2*u*2*p),v=(s*s-u*u-4*h)/(2*s*2*p),_=Math.log(Math.sqrt(d*d+1)-d),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-_)/vl,e=function(t){var n=t*r,e=on(_),a=u/(2*p)*(e*an(vl*n+_)-un(_));return[i+a*f,o+a*l,u*e/on(vl*n+_)]}}return e.duration=1e3*r,e},yl=cn(Jt),gl=cn(Kt),ml=sn(Jt),xl=sn(Kt),bl=fn(Jt),wl=fn(Kt),Ml=0,Tl=0,kl=0,Nl=1e3,Sl=0,El=0,Al=0,Cl="object"==typeof performance&&performance.now?performance:Date,zl="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};pn.prototype=dn.prototype={constructor:pn,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?ln():+e)+(null==n?0:+n),this._next||Wf===this||(Wf?Wf._next=this:Vf=this,Wf=this),this._call=t,this._time=e,mn()},stop:function(){this._call&&(this._call=null,this._time=1/0,mn())}};var Pl=function(t,n,e){var r=new pn;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},Rl=h("start","end","interrupt"),Ll=[],ql=0,Ul=1,Dl=2,Ol=3,Fl=4,Il=5,Yl=6,Bl=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};Mn(t,e,{name:n,index:r,group:i,on:Rl,tween:Ll,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:ql})},jl=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){n=null==n?null:n+"";for(i in o)(e=o[i]).name===n?(r=e.state>Dl&&e.state<Il,e.state=Yl,e.timer.stop(),r&&e.on.call("interrupt",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}},Hl=function(t,n){var e;return("number"==typeof n?rl:n instanceof Tt?Qf:(e=Tt(n))?(n=e,Qf):al)(t,n)},Xl=dt.prototype.constructor,$l=0,Vl=dt.prototype;Gn.prototype=Jn.prototype={constructor:Gn,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=tf(t));for(var r=this._groups,i=r.length,o=new Array(i),u=0;u<i;++u)for(var a,c,s=r[u],f=s.length,l=o[u]=new Array(f),h=0;h<f;++h)(a=s[h])&&(c=t.call(a,a.__data__,h,s))&&("__data__"in a&&(c.__data__=a.__data__),l[h]=c,Bl(l[h],n,e,h,l,wn(a,e)));return new Gn(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=nf(t));for(var r=this._groups,i=r.length,o=[],u=[],a=0;a<i;++a)for(var c,s=r[a],f=s.length,l=0;l<f;++l)if(c=s[l]){for(var h,p=t.call(c,c.__data__,l,s),d=wn(c,e),v=0,_=p.length;v<_;++v)(h=p[v])&&Bl(h,n,e,v,p,d);o.push(p),u.push(c)}return new Gn(o,u,n,e)},filter:function(t){"function"!=typeof t&&(t=Zs(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new Gn(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new Gn(u,this._parents,this._name,this._id)},selection:function(){return new Xl(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Qn(),r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)if(u=a[s]){var f=wn(u,n);Bl(u,t,e,s,a,{time:f.time+f.delay+f.duration,delay:0,duration:f.duration,ease:f.ease})}return new Gn(r,this._parents,t,e)},call:Vl.call,nodes:Vl.nodes,node:Vl.node,size:Vl.size,empty:Vl.empty,each:Vl.each,on:function(t,n){var e=this._id;return arguments.length<2?wn(this.node(),e).on.on(t):this.each(Yn(e,t,n))},attr:function(t,n){var e=js(t),r="transform"===e?dl:Hl;return this.attrTween(t,"function"==typeof n?(e.local?Pn:zn)(e,r,Nn(this,"attr."+t,n)):null==n?(e.local?En:Sn)(e):(e.local?Cn:An)(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=js(t);return this.tween(e,(r.local?Rn:Ln)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?pl:Hl;return null==n?this.styleTween(t,jn(t,r)).on("end.style."+t,Hn(t)):this.styleTween(t,"function"==typeof n?$n(t,r,Nn(this,"style."+t,n)):Xn(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,Vn(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?Zn(Nn(this,"text",t)):Wn(null==t?"":t+""))},remove:function(){return this.on("end.remove",Bn(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=wn(this.node(),e).tween,o=0,u=i.length;o<u;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?Tn:kn)(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?qn:Un)(n,t)):wn(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?Dn:On)(n,t)):wn(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(Fn(n,t)):wn(this.node(),n).ease}};var Wl=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),Zl=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Gl=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Jl=Math.PI,Ql=Jl/2,Kl=4/11,th=6/11,nh=8/11,eh=.75,rh=9/11,ih=10/11,oh=.9375,uh=21/22,ah=63/64,ch=1/Kl/Kl,sh=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),fh=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),lh=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),hh=2*Math.PI,ph=function t(n,e){function r(t){return n*Math.pow(2,10*--t)*Math.sin((i-t)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),dh=function t(n,e){function r(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+i)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),vh=function t(n,e){function r(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((i-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((i+t)/e))/2}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),_h={time:null,delay:0,duration:250,ease:te};dt.prototype.interrupt=function(t){return this.each(function(){jl(this,t)})},dt.prototype.transition=function(t){var n,e;t instanceof Gn?(n=t._id,t=t._name):(n=Qn(),(e=_h).time=ln(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)(u=a[s])&&Bl(u,t,n,s,a,e||oe(u,n));return new Gn(r,this._parents,t,n)};var yh=[null],gh=function(t){return function(){return t}},mh=function(t,n,e){this.target=t,this.type=n,this.selection=e},xh=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},bh={name:"drag"},wh={name:"space"},Mh={name:"handle"},Th={name:"center"},kh={name:"x",handles:["e","w"].map(ae),input:function(t,n){return t&&[[t[0],n[0][1]],[t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Nh={name:"y",handles:["n","s"].map(ae),input:function(t,n){return t&&[[n[0][0],t[0]],[n[1][0],t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Sh={name:"xy",handles:["n","e","s","w","nw","ne","se","sw"].map(ae),input:function(t){return t},output:function(t){return t}},Eh={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ah={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ch={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},zh={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Ph={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1},Rh=Math.cos,Lh=Math.sin,qh=Math.PI,Uh=qh/2,Dh=2*qh,Oh=Math.max,Fh=Array.prototype.slice,Ih=function(t){return function(){return t}},Yh=Math.PI,Bh=2*Yh,jh=Bh-1e-6;de.prototype=ve.prototype={constructor:de,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,u=this._y1,a=e-t,c=r-n,s=o-t,f=u-n,l=s*s+f*f;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(f*a-c*s)>1e-6&&i){var h=e-o,p=r-u,d=a*a+c*c,v=h*h+p*p,_=Math.sqrt(d),y=Math.sqrt(l),g=i*Math.tan((Yh-Math.acos((d+l-v)/(2*_*y)))/2),m=g/y,x=g/_;Math.abs(m-1)>1e-6&&(this._+="L"+(t+m*s)+","+(n+m*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>s*p)+","+(this._x1=t+x*a)+","+(this._y1=n+x*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,s=n+a,f=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+s:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-s)>1e-6)&&(this._+="L"+c+","+s),e&&(l<0&&(l=l%Bh+Bh),l>jh?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=s):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Yh)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};be.prototype=we.prototype={constructor:be,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var Hh=we.prototype;Se.prototype=Ee.prototype={constructor:Se,has:Hh.has,add:function(t){return t+="",this["$"+t]=t,this},remove:Hh.remove,clear:Hh.clear,values:Hh.keys,size:Hh.size,empty:Hh.empty,each:Hh.each};var Xh=function(t){function n(t,n){function e(){if(f>=s)return a;if(i)return i=!1,u;var n,e=f;if(34===t.charCodeAt(e)){for(var r=e;r++<s;)if(34===t.charCodeAt(r)){if(34!==t.charCodeAt(r+1))break;++r}return f=r+2,13===(n=t.charCodeAt(r+1))?(i=!0,10===t.charCodeAt(r+2)&&++f):10===n&&(i=!0),t.slice(e+1,r).replace(/""/g,'"')}for(;f<s;){var c=1;if(10===(n=t.charCodeAt(f++)))i=!0;else if(13===n)i=!0,10===t.charCodeAt(f)&&(++f,++c);else if(n!==o)continue;return t.slice(e,f-c)}return t.slice(e)}for(var r,i,u={},a={},c=[],s=t.length,f=0,l=0;(r=e())!==a;){for(var h=[];r!==u&&r!==a;)h.push(r),r=e();n&&null==(h=n(h,l++))||c.push(h)}return c}function e(n){return n.map(r).join(t)}function r(t){return null==t?"":i.test(t+="")?'"'+t.replace(/\"/g,'""')+'"':t}var i=new RegExp('["'+t+"\n\r]"),o=t.charCodeAt(0);return{parse:function(t,e){var r,i,o=n(t,function(t,n){if(r)return r(t,n-1);i=t,r=e?Ce(t,e):Ae(t)});return o.columns=i,o},parseRows:n,format:function(n,e){return null==e&&(e=ze(n)),[e.map(r).join(t)].concat(n.map(function(n){return e.map(function(t){return r(n[t])}).join(t)})).join("\n")},formatRows:function(t){return t.map(e).join("\n")}}},$h=Xh(","),Vh=$h.parse,Wh=$h.parseRows,Zh=$h.format,Gh=$h.formatRows,Jh=Xh("\t"),Qh=Jh.parse,Kh=Jh.parseRows,tp=Jh.format,np=Jh.formatRows,ep=function(t){return function(){return t}},rp=function(){return 1e-6*(Math.random()-.5)},ip=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i},op=qe.prototype=Ue.prototype;op.copy=function(){var t,n,e=new Ue(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=De(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=De(n));return e},op.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return Pe(this.cover(n,e),n,e,t)},op.addAll=function(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,s=1/0,f=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(u[e]=r,a[e]=i,r<c&&(c=r),r>f&&(f=r),i<s&&(s=i),i>l&&(l=i));for(f<c&&(c=this._x0,f=this._x1),l<s&&(s=this._y0,l=this._y1),this.cover(c,s).cover(f,l),e=0;e<o;++e)Pe(this,u[e],a[e],t[e]);return this},op.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{if(!(e>t||t>i||r>n||n>o))return this;var u,a,c=i-e,s=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,o=r+c,t>i||n>o);break;case 1:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,o=r+c,e>t||n>o);break;case 2:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,r=o-c,t>i||r>n);break;case 3:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,r=o-c,e>t||r>n)}this._root&&this._root.length&&(this._root=s)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},op.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},op.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},op.find=function(t,n,e){var r,i,o,u,a,c,s,f=this._x0,l=this._y0,h=this._x1,p=this._y1,d=[],v=this._root;for(v&&d.push(new ip(v,f,l,h,p)),null==e?e=1/0:(f=t-e,l=n-e,h=t+e,p=n+e,e*=e);c=d.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>p||(u=c.x1)<f||(a=c.y1)<l))if(v.length){var _=(i+u)/2,y=(o+a)/2;d.push(new ip(v[3],_,y,u,a),new ip(v[2],i,y,_,a),new ip(v[1],_,o,u,y),new ip(v[0],i,o,_,y)),(s=(n>=y)<<1|t>=_)&&(c=d[d.length-1],d[d.length-1]=d[d.length-1-s],d[d.length-1-s]=c)}else{var g=t-+this._x.call(null,v.data),m=n-+this._y.call(null,v.data),x=g*g+m*m;if(x<e){var b=Math.sqrt(e=x);f=t-b,l=n-b,h=t+b,p=n+b,r=v.data}}return r},op.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(u=+this._y.call(null,t)))return this;var n,e,r,i,o,u,a,c,s,f,l,h,p=this._root,d=this._x0,v=this._y0,_=this._x1,y=this._y1;if(!p)return this;if(p.length)for(;;){if((s=o>=(a=(d+_)/2))?d=a:_=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=p,!(p=p[l=f<<1|s]))return this;if(!p.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;p.data!==t;)if(r=p,!(p=p.next))return this;return(i=p.next)&&delete p.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(p=n[0]||n[1]||n[2]||n[3])&&p===(n[3]||n[2]||n[1]||n[0])&&!p.length&&(e?e[h]=p:this._root=p),this):(this._root=i,this)},op.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},op.root=function(){return this._root},op.size=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},op.visit=function(t){var n,e,r,i,o,u,a=[],c=this._root;for(c&&a.push(new ip(c,this._x0,this._y0,this._x1,this._y1));n=a.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,u=n.y1)&&c.length){var s=(r+o)/2,f=(i+u)/2;(e=c[3])&&a.push(new ip(e,s,f,o,u)),(e=c[2])&&a.push(new ip(e,r,f,s,u)),(e=c[1])&&a.push(new ip(e,s,i,o,f)),(e=c[0])&&a.push(new ip(e,r,i,s,f))}return this},op.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new ip(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,u=n.x0,a=n.y0,c=n.x1,s=n.y1,f=(u+c)/2,l=(a+s)/2;(o=i[0])&&e.push(new ip(o,u,a,f,l)),(o=i[1])&&e.push(new ip(o,f,a,c,l)),(o=i[2])&&e.push(new ip(o,u,l,f,s)),(o=i[3])&&e.push(new ip(o,f,l,c,s))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},op.x=function(t){return arguments.length?(this._x=t,this):this._x},op.y=function(t){return arguments.length?(this._y=t,this):this._y};var up,ap=10,cp=Math.PI*(3-Math.sqrt(5)),sp=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},fp=function(t){return(t=sp(Math.abs(t)))?t[1]:NaN},lp=function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}},hp=function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}},pp=function(t,n){var e=sp(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},dp={"":function(t,n){t:for(var e,r=(t=t.toPrecision(n)).length,i=1,o=-1;i<r;++i)switch(t[i]){case".":o=e=i;break;case"0":0===o&&(o=i),e=i;break;case"e":break t;default:o>0&&(o=0)}return o>0?t.slice(0,o)+t.slice(e+1):t},"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return pp(100*t,n)},r:pp,s:function(t,n){var e=sp(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(up=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+sp(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},vp=/^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;He.prototype=Xe.prototype,Xe.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var _p,yp=function(t){return t},gp=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],mp=function(t){function n(t){function n(t){var n,r,u,f=_,x=y;if("c"===v)x=g(t)+x,t="";else{var b=(t=+t)<0;if(t=g(Math.abs(t),d),b&&0==+t&&(b=!1),f=(b?"("===s?s:"-":"-"===s||"("===s?"":s)+f,x=x+("s"===v?gp[8+up/3]:"")+(b&&"("===s?")":""),m)for(n=-1,r=t.length;++n<r;)if(48>(u=t.charCodeAt(n))||u>57){x=(46===u?i+t.slice(n+1):t.slice(n))+x,t=t.slice(0,n);break}}p&&!l&&(t=e(t,1/0));var w=f.length+t.length+x.length,M=w<h?new Array(h-w+1).join(a):"";switch(p&&l&&(t=e(M+t,M.length?h-x.length:1/0),M=""),c){case"<":t=f+t+x+M;break;case"=":t=f+M+t+x;break;case"^":t=M.slice(0,w=M.length>>1)+f+t+x+M.slice(w);break;default:t=M+f+t+x}return o(t)}var a=(t=He(t)).fill,c=t.align,s=t.sign,f=t.symbol,l=t.zero,h=t.width,p=t.comma,d=t.precision,v=t.type,_="$"===f?r[0]:"#"===f&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",y="$"===f?r[1]:/[%p]/.test(v)?u:"",g=dp[v],m=!v||/[defgprs%]/.test(v);return d=null==d?v?6:12:/[gprs]/.test(v)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),n.toString=function(){return t+""},n}var e=t.grouping&&t.thousands?lp(t.grouping,t.thousands):yp,r=t.currency,i=t.decimal,o=t.numerals?hp(t.numerals):yp,u=t.percent||"%";return{format:n,formatPrefix:function(t,e){var r=n((t=He(t),t.type="f",t)),i=3*Math.max(-8,Math.min(8,Math.floor(fp(e)/3))),o=Math.pow(10,-i),u=gp[8+i/3];return function(t){return r(o*t)+u}}}};$e({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var xp=function(t){return Math.max(0,-fp(Math.abs(t)))},bp=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(fp(n)/3)))-fp(Math.abs(t)))},wp=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,fp(n)-fp(t))+1},Mp=function(){return new Ve};Ve.prototype={constructor:Ve,reset:function(){this.s=this.t=0},add:function(t){We(nd,t,this.t),We(this,nd.s,this.s),this.s?this.t+=nd.t:this.s=nd.t},valueOf:function(){return this.s}};var Tp,kp,Np,Sp,Ep,Ap,Cp,zp,Pp,Rp,Lp,qp,Up,Dp,Op,Fp,Ip,Yp,Bp,jp,Hp,Xp,$p,Vp,Wp,Zp,Gp,Jp,Qp,Kp,td,nd=new Ve,ed=1e-6,rd=Math.PI,id=rd/2,od=rd/4,ud=2*rd,ad=180/rd,cd=rd/180,sd=Math.abs,fd=Math.atan,ld=Math.atan2,hd=Math.cos,pd=Math.ceil,dd=Math.exp,vd=Math.log,_d=Math.pow,yd=Math.sin,gd=Math.sign||function(t){return t>0?1:t<0?-1:0},md=Math.sqrt,xd=Math.tan,bd={Feature:function(t,n){Ke(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)Ke(e[r].geometry,n)}},wd={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){tr(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)tr(e[r],n,0)},Polygon:function(t,n){nr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)nr(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)Ke(e[r],n)}},Md=function(t,n){t&&bd.hasOwnProperty(t.type)?bd[t.type](t,n):Ke(t,n)},Td=Mp(),kd=Mp(),Nd={point:Qe,lineStart:Qe,lineEnd:Qe,polygonStart:function(){Td.reset(),Nd.lineStart=er,Nd.lineEnd=rr},polygonEnd:function(){var t=+Td;kd.add(t<0?ud+t:t),this.lineStart=this.lineEnd=this.point=Qe},sphere:function(){kd.add(ud)}},Sd=Mp(),Ed={point:pr,lineStart:vr,lineEnd:_r,polygonStart:function(){Ed.point=yr,Ed.lineStart=gr,Ed.lineEnd=mr,Sd.reset(),Nd.polygonStart()},polygonEnd:function(){Nd.polygonEnd(),Ed.point=pr,Ed.lineStart=vr,Ed.lineEnd=_r,Td<0?(Ap=-(zp=180),Cp=-(Pp=90)):Sd>ed?Pp=90:Sd<-ed&&(Cp=-90),Op[0]=Ap,Op[1]=zp}},Ad={sphere:Qe,point:Mr,lineStart:kr,lineEnd:Er,polygonStart:function(){Ad.lineStart=Ar,Ad.lineEnd=Cr},polygonEnd:function(){Ad.lineStart=kr,Ad.lineEnd=Er}},Cd=function(t){return function(){return t}},zd=function(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e};Rr.invert=Rr;var Pd,Rd,Ld,qd,Ud,Dd,Od,Fd,Id,Yd,Bd,jd=function(t){function n(n){return n=t(n[0]*cd,n[1]*cd),n[0]*=ad,n[1]*=ad,n}return t=Lr(t[0]*cd,t[1]*cd,t.length>2?t[2]*cd:0),n.invert=function(n){return n=t.invert(n[0]*cd,n[1]*cd),n[0]*=ad,n[1]*=ad,n},n},Hd=function(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:Qe,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}},Xd=function(t,n,e,r,i,o){var u,a=t[0],c=t[1],s=0,f=1,l=n[0]-a,h=n[1]-c;if(u=e-a,l||!(u>0)){if(u/=l,l<0){if(u<s)return;u<f&&(f=u)}else if(l>0){if(u>f)return;u>s&&(s=u)}if(u=i-a,l||!(u<0)){if(u/=l,l<0){if(u>f)return;u>s&&(s=u)}else if(l>0){if(u<s)return;u<f&&(f=u)}if(u=r-c,h||!(u>0)){if(u/=h,h<0){if(u<s)return;u<f&&(f=u)}else if(h>0){if(u>f)return;u>s&&(s=u)}if(u=o-c,h||!(u<0)){if(u/=h,h<0){if(u>f)return;u>s&&(s=u)}else if(h>0){if(u<s)return;u<f&&(f=u)}return s>0&&(t[0]=a+s*l,t[1]=c+s*h),f<1&&(n[0]=a+f*l,n[1]=c+f*h),!0}}}}},$d=function(t,n){return sd(t[0]-n[0])<ed&&sd(t[1]-n[1])<ed},Vd=function(t,n,e,r,i){var o,u,a=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],u=t[n];if($d(r,u)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);i.lineEnd()}else a.push(e=new Ir(r,t,null,!0)),c.push(e.o=new Ir(r,null,e,!1)),a.push(e=new Ir(u,t,null,!1)),c.push(e.o=new Ir(u,null,e,!0))}}),a.length){for(c.sort(n),Yr(a),Yr(c),o=0,u=c.length;o<u;++o)c[o].e=e=!e;for(var s,f,l=a[0];;){for(var h=l,p=!0;h.v;)if((h=h.n)===l)return;s=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(p)for(o=0,u=s.length;o<u;++o)i.point((f=s[o])[0],f[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(p)for(s=h.p.z,o=s.length-1;o>=0;--o)i.point((f=s[o])[0],f[1]);else r(h.x,h.p.x,-1,i);h=h.p}s=(h=h.o).z,p=!p}while(!h.v);i.lineEnd()}}},Wd=1e9,Zd=-Wd,Gd=Mp(),Jd=function(t,n){var e=n[0],r=n[1],i=[yd(e),-hd(e),0],o=0,u=0;Gd.reset();for(var a=0,c=t.length;a<c;++a)if(f=(s=t[a]).length)for(var s,f,l=s[f-1],h=l[0],p=l[1]/2+od,d=yd(p),v=hd(p),_=0;_<f;++_,h=g,d=x,v=b,l=y){var y=s[_],g=y[0],m=y[1]/2+od,x=yd(m),b=hd(m),w=g-h,M=w>=0?1:-1,T=M*w,k=T>rd,N=d*x;if(Gd.add(ld(N*M*yd(T),v*b+N*hd(T))),o+=k?w+M*ud:w,k^h>=e^g>=e){var S=sr(ar(l),ar(y));hr(S);var E=sr(i,S);hr(E);var A=(k^w>=0?-1:1)*Ge(E[2]);(r>A||r===A&&(S[0]||S[1]))&&(u+=k^w>=0?1:-1)}}return(o<-ed||o<ed&&Gd<-ed)^1&u},Qd=Mp(),Kd={sphere:Qe,point:Qe,lineStart:function(){Kd.point=Hr,Kd.lineEnd=jr},lineEnd:Qe,polygonStart:Qe,polygonEnd:Qe},tv=function(t){return Qd.reset(),Md(t,Kd),+Qd},nv=[null,null],ev={type:"LineString",coordinates:nv},rv=function(t,n){return nv[0]=t,nv[1]=n,tv(ev)},iv={Feature:function(t,n){return $r(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if($r(e[r].geometry,n))return!0;return!1}},ov={Sphere:function(){return!0},Point:function(t,n){return Vr(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Vr(e[r],n))return!0;return!1},LineString:function(t,n){return Wr(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Wr(e[r],n))return!0;return!1},Polygon:function(t,n){return Zr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Zr(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if($r(e[r],n))return!0;return!1}},uv=function(t){return t},av=Mp(),cv=Mp(),sv={point:Qe,lineStart:Qe,lineEnd:Qe,polygonStart:function(){sv.lineStart=ni,sv.lineEnd=ii},polygonEnd:function(){sv.lineStart=sv.lineEnd=sv.point=Qe,av.add(sd(cv)),cv.reset()},result:function(){var t=av/2;return av.reset(),t}},fv=1/0,lv=fv,hv=-fv,pv=hv,dv={point:function(t,n){t<fv&&(fv=t),t>hv&&(hv=t),n<lv&&(lv=n),n>pv&&(pv=n)},lineStart:Qe,lineEnd:Qe,polygonStart:Qe,polygonEnd:Qe,result:function(){var t=[[fv,lv],[hv,pv]];return hv=pv=-(lv=fv=1/0),t}},vv=0,_v=0,yv=0,gv=0,mv=0,xv=0,bv=0,wv=0,Mv=0,Tv={point:oi,lineStart:ui,lineEnd:si,polygonStart:function(){Tv.lineStart=fi,Tv.lineEnd=li},polygonEnd:function(){Tv.point=oi,Tv.lineStart=ui,Tv.lineEnd=si},result:function(){var t=Mv?[bv/Mv,wv/Mv]:xv?[gv/xv,mv/xv]:yv?[vv/yv,_v/yv]:[NaN,NaN];return vv=_v=yv=gv=mv=xv=bv=wv=Mv=0,t}};di.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,ud)}},result:Qe};var kv,Nv,Sv,Ev,Av,Cv=Mp(),zv={point:Qe,lineStart:function(){zv.point=vi},lineEnd:function(){kv&&_i(Nv,Sv),zv.point=Qe},polygonStart:function(){kv=!0},polygonEnd:function(){kv=null},result:function(){var t=+Cv;return Cv.reset(),t}};yi.prototype={_radius:4.5,_circle:gi(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=gi(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}};var Pv=function(t,n,e,r){return function(i,o){function u(n,e){var r=i(n,e);t(n=r[0],e=r[1])&&o.point(n,e)}function a(t,n){var e=i(t,n);_.point(e[0],e[1])}function c(){b.point=a,_.lineStart()}function s(){b.point=u,_.lineEnd()}function f(t,n){v.push([t,n]);var e=i(t,n);m.point(e[0],e[1])}function l(){m.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),m.lineEnd();var t,n,e,r,i=m.clean(),u=g.result(),a=u.length;if(v.pop(),p.push(v),v=null,a)if(1&i){if(e=u[0],(n=e.length-1)>0){for(x||(o.polygonStart(),x=!0),o.lineStart(),t=0;t<n;++t)o.point((r=e[t])[0],r[1]);o.lineEnd()}}else a>1&&2&i&&u.push(u.pop().concat(u.shift())),d.push(u.filter(mi))}var p,d,v,_=n(o),y=i.invert(r[0],r[1]),g=Hd(),m=n(g),x=!1,b={point:u,lineStart:c,lineEnd:s,polygonStart:function(){b.point=f,b.lineStart=l,b.lineEnd=h,d=[],p=[]},polygonEnd:function(){b.point=u,b.lineStart=c,b.lineEnd=s,d=Cs(d);var t=Jd(p,y);d.length?(x||(o.polygonStart(),x=!0),Vd(d,xi,t,e,o)):t&&(x||(o.polygonStart(),x=!0),o.lineStart(),e(null,null,1,o),o.lineEnd()),x&&(o.polygonEnd(),x=!1),d=p=null},sphere:function(){o.polygonStart(),o.lineStart(),e(null,null,1,o),o.lineEnd(),o.polygonEnd()}};return b}},Rv=Pv(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,u){var a=o>0?rd:-rd,c=sd(o-e);sd(c-rd)<ed?(t.point(e,r=(r+u)/2>0?id:-id),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),t.point(o,r),n=0):i!==a&&c>=rd&&(sd(e-i)<ed&&(e-=i*ed),sd(o-a)<ed&&(o-=a*ed),r=bi(e,r,o,u),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),n=0),t.point(e=o,r=u),i=a},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*id,r.point(-rd,i),r.point(0,i),r.point(rd,i),r.point(rd,0),r.point(rd,-i),r.point(0,-i),r.point(-rd,-i),r.point(-rd,0),r.point(-rd,i);else if(sd(t[0]-n[0])>ed){var o=t[0]<n[0]?rd:-rd;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])},[-rd,-id]),Lv=function(t,n){function e(t,n){return hd(t)*hd(n)>o}function r(t,n,e){var r=[1,0,0],i=sr(ar(t),ar(n)),u=cr(i,i),a=i[0],c=u-a*a;if(!c)return!e&&t;var s=o*u/c,f=-o*a/c,l=sr(r,i),h=lr(r,s);fr(h,lr(i,f));var p=l,d=cr(h,p),v=cr(p,p),_=d*d-v*(cr(h,h)-1);if(!(_<0)){var y=md(_),g=lr(p,(-d-y)/v);if(fr(g,h),g=ur(g),!e)return g;var m,x=t[0],b=n[0],w=t[1],M=n[1];b<x&&(m=x,x=b,b=m);var T=b-x,k=sd(T-rd)<ed,N=k||T<ed;if(!k&&M<w&&(m=w,w=M,M=m),N?k?w+M>0^g[1]<(sd(g[0]-x)<ed?w:M):w<=g[1]&&g[1]<=M:T>rd^(x<=g[0]&&g[0]<=b)){var S=lr(p,(-d+y)/v);return fr(S,h),[g,ur(S)]}}}function i(n,e){var r=u?t:rd-t,i=0;return n<-r?i|=1:n>r&&(i|=2),e<-r?i|=4:e>r&&(i|=8),i}var o=hd(t),u=o>0,a=sd(o)>ed;return Pv(e,function(t){var n,o,c,s,f;return{lineStart:function(){s=c=!1,f=1},point:function(l,h){var p,d=[l,h],v=e(l,h),_=u?v?0:i(l,h):v?i(l+(l<0?rd:-rd),h):0;if(!n&&(s=c=v)&&t.lineStart(),v!==c&&(!(p=r(n,d))||$d(n,p)||$d(d,p))&&(d[0]+=ed,d[1]+=ed,v=e(d[0],d[1])),v!==c)f=0,v?(t.lineStart(),p=r(d,n),t.point(p[0],p[1])):(p=r(n,d),t.point(p[0],p[1]),t.lineEnd()),n=p;else if(a&&n&&u^v){var y;_&o||!(y=r(d,n,!0))||(f=0,u?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&$d(n,d)||t.point(d[0],d[1]),n=d,c=v,o=_},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return f|(s&&c)<<1}}},function(e,r,i,o){Or(o,t,n,i,e,r)},u?[0,-t]:[-rd,t-rd])};Mi.prototype={constructor:Mi,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var qv=16,Uv=hd(30*cd),Dv=function(t,n){return+n?Si(t,n):Ni(t)},Ov=wi({point:function(t,n){this.stream.point(t*cd,n*cd)}}),Fv=function(){return Ci(Pi).scale(155.424).center([0,33.6442])},Iv=function(){return Fv().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])},Yv=Li(function(t){return md(2/(1+t))});Yv.invert=qi(function(t){return 2*Ge(t/2)});var Bv=Li(function(t){return(t=Ze(t))&&t/yd(t)});Bv.invert=qi(function(t){return t});Ui.invert=function(t,n){return[t,2*fd(dd(n))-id]};Ii.invert=Ii;Bi.invert=qi(fd);Hi.invert=qi(Ge);Xi.invert=qi(function(t){return 2*fd(t)});$i.invert=function(t,n){return[-n,2*fd(dd(t))-id]};uo.prototype=eo.prototype={constructor:uo,count:function(){return this.eachAfter(to)},each:function(t){var n,e,r,i,o=this,u=[o];do{for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)u.push(e[r])}while(u.length);return this},eachAfter:function(t){for(var n,e,r,i=this,o=[i],u=[];i=o.pop();)if(u.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=u.pop();)t(i);return this},eachBefore:function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=no(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return eo(this).eachBefore(io)}};var jv=Array.prototype.slice,Hv=function(t){for(var n,e,r=0,i=(t=ao(jv.call(t))).length,o=[];r<i;)n=t[r],e&&fo(e,n)?++r:(e=ho(o=co(o,n)),r=0);return e},Xv=function(t){return function(){return t}},$v=function(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)},Vv=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(r-n)/t.value;++a<c;)(o=u[a]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*s},Wv="$",Zv={depth:-1},Gv={};Do.prototype=Object.create(uo.prototype);var Jv=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(i-e)/t.value;++a<c;)(o=u[a]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*s},Qv=(1+Math.sqrt(5))/2,Kv=function t(n){function e(t,e,r,i,o){Fo(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Qv),t_=function t(n){function e(t,e,r,i,o){if((u=t._squarify)&&u.ratio===n)for(var u,a,c,s,f,l=-1,h=u.length,p=t.value;++l<h;){for(c=(a=u[l]).children,s=a.value=0,f=c.length;s<f;++s)a.value+=c[s].value;a.dice?Vv(a,e,r,i,r+=(o-r)*a.value/p):Jv(a,e,r,e+=(i-e)*a.value/p,o),p-=a.value}else t._squarify=u=Fo(n,t,e,r,i,o),u.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Qv),n_=function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])},e_=[].slice,r_={};Bo.prototype=Wo.prototype={constructor:Bo,defer:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("defer after await");if(null!=this._error)return this;var n=e_.call(arguments,1);return n.push(t),++this._waiting,this._tasks.push(n),jo(this),this},abort:function(){return null==this._error&&$o(this,new Error("abort")),this},await:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=function(n,e){t.apply(null,[n].concat(e))},Vo(this),this},awaitAll:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=t,Vo(this),this}};var i_=function(){return Math.random()},o_=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(i_),u_=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(i_),a_=function t(n){function e(){var t=u_.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(i_),c_=function t(n){function e(t){return function(){for(var e=0,r=0;r<t;++r)e+=n();return e}}return e.source=t,e}(i_),s_=function t(n){function e(t){var e=c_.source(n)(t);return function(){return e()/t}}return e.source=t,e}(i_),f_=function t(n){function e(t){return function(){return-Math.log(1-n())/t}}return e.source=t,e}(i_),l_=function(t,n){function e(t){var n,e=s.status;if(!e&&Go(s)||e>=200&&e<300||304===e){if(o)try{n=o.call(r,s)}catch(t){return void a.call("error",r,t)}else n=s;a.call("load",r,n)}else a.call("error",r,t)}var r,i,o,u,a=h("beforesend","progress","load","error"),c=we(),s=new XMLHttpRequest,f=null,l=null,p=0;if("undefined"==typeof XDomainRequest||"withCredentials"in s||!/^(http(s)?:)?\/\//.test(t)||(s=new XDomainRequest),"onload"in s?s.onload=s.onerror=s.ontimeout=e:s.onreadystatechange=function(t){s.readyState>3&&e(t)},s.onprogress=function(t){a.call("progress",r,t)},r={header:function(t,n){return t=(t+"").toLowerCase(),arguments.length<2?c.get(t):(null==n?c.remove(t):c.set(t,n+""),r)},mimeType:function(t){return arguments.length?(i=null==t?null:t+"",r):i},responseType:function(t){return arguments.length?(u=t,r):u},timeout:function(t){return arguments.length?(p=+t,r):p},user:function(t){return arguments.length<1?f:(f=null==t?null:t+"",r)},password:function(t){return arguments.length<1?l:(l=null==t?null:t+"",r)},response:function(t){return o=t,r},get:function(t,n){return r.send("GET",t,n)},post:function(t,n){return r.send("POST",t,n)},send:function(n,e,o){return s.open(n,t,!0,f,l),null==i||c.has("accept")||c.set("accept",i+",*/*"),s.setRequestHeader&&c.each(function(t,n){s.setRequestHeader(n,t)}),null!=i&&s.overrideMimeType&&s.overrideMimeType(i),null!=u&&(s.responseType=u),p>0&&(s.timeout=p),null==o&&"function"==typeof e&&(o=e,e=null),null!=o&&1===o.length&&(o=Zo(o)),null!=o&&r.on("error",o).on("load",function(t){o(null,t)}),a.call("beforesend",r,s),s.send(null==e?null:e),r},abort:function(){return s.abort(),r},on:function(){var t=a.on.apply(a,arguments);return t===a?r:t}},null!=n){if("function"!=typeof n)throw new Error("invalid callback: "+n);return r.get(n)}return r},h_=function(t,n){return function(e,r){var i=l_(e).mimeType(t).response(n);if(null!=r){if("function"!=typeof r)throw new Error("invalid callback: "+r);return i.get(r)}return i}},p_=h_("text/html",function(t){return document.createRange().createContextualFragment(t.responseText)}),d_=h_("application/json",function(t){return JSON.parse(t.responseText)}),v_=h_("text/plain",function(t){return t.responseText}),__=h_("application/xml",function(t){var n=t.responseXML;if(!n)throw new Error("parse error");return n}),y_=function(t,n){return function(e,r,i){arguments.length<3&&(i=r,r=null);var o=l_(e).mimeType(t);return o.row=function(t){return arguments.length?o.response(Jo(n,r=t)):r},o.row(r),i?o.get(i):o}},g_=y_("text/csv",Vh),m_=y_("text/tab-separated-values",Qh),x_=Array.prototype,b_=x_.map,w_=x_.slice,M_={name:"implicit"},T_=function(t){return function(){return t}},k_=function(t){return+t},N_=[0,1],S_=function(n,e,r){var o,u=n[0],a=n[n.length-1],c=i(u,a,null==e?10:e);switch((r=He(null==r?",f":r)).type){case"s":var s=Math.max(Math.abs(u),Math.abs(a));return null!=r.precision||isNaN(o=bp(c,s))||(r.precision=o),t.formatPrefix(r,s);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(o=wp(c,Math.max(Math.abs(u),Math.abs(a))))||(r.precision=o-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(o=xp(c))||(r.precision=o-2*("%"===r.type))}return t.format(r)},E_=function(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],u=t[i];return u<o&&(e=r,r=i,i=e,e=o,o=u,u=e),t[r]=n.floor(o),t[i]=n.ceil(u),t},A_=new Date,C_=new Date,z_=Mu(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});z_.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Mu(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):z_:null};var P_=z_.range,R_=6e4,L_=6048e5,q_=Mu(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),U_=q_.range,D_=Mu(function(t){t.setTime(Math.floor(t/R_)*R_)},function(t,n){t.setTime(+t+n*R_)},function(t,n){return(n-t)/R_},function(t){return t.getMinutes()}),O_=D_.range,F_=Mu(function(t){var n=t.getTimezoneOffset()*R_%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),I_=F_.range,Y_=Mu(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*R_)/864e5},function(t){return t.getDate()-1}),B_=Y_.range,j_=Tu(0),H_=Tu(1),X_=Tu(2),$_=Tu(3),V_=Tu(4),W_=Tu(5),Z_=Tu(6),G_=j_.range,J_=H_.range,Q_=X_.range,K_=$_.range,ty=V_.range,ny=W_.range,ey=Z_.range,ry=Mu(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),iy=ry.range,oy=Mu(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});oy.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Mu(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var uy=oy.range,ay=Mu(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*R_)},function(t,n){return(n-t)/R_},function(t){return t.getUTCMinutes()}),cy=ay.range,sy=Mu(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),fy=sy.range,ly=Mu(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),hy=ly.range,py=ku(0),dy=ku(1),vy=ku(2),_y=ku(3),yy=ku(4),gy=ku(5),my=ku(6),xy=py.range,by=dy.range,wy=vy.range,My=_y.range,Ty=yy.range,ky=gy.range,Ny=my.range,Sy=Mu(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),Ey=Sy.range,Ay=Mu(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});Ay.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Mu(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Cy,zy=Ay.range,Py={"-":"",_:" ",0:"0"},Ry=/^\s*\d+/,Ly=/^%/,qy=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;Ma({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Uy=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ"),Dy=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),Oy=1e3,Fy=60*Oy,Iy=60*Fy,Yy=24*Iy,By=7*Yy,jy=30*Yy,Hy=365*Yy,Xy=function(t){return t.match(/.{6}/g).map(function(t){return"#"+t})},$y=Xy("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),Vy=Xy("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6"),Wy=Xy("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9"),Zy=Xy("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5"),Gy=wl($t(300,.5,0),$t(-240,.5,1)),Jy=wl($t(-100,.75,.35),$t(80,1.5,.8)),Qy=wl($t(260,.75,.35),$t(80,1.5,.8)),Ky=$t(),tg=Sa(Xy("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),ng=Sa(Xy("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),eg=Sa(Xy("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),rg=Sa(Xy("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921")),ig=function(t){return function(){return t}},og=Math.abs,ug=Math.atan2,ag=Math.cos,cg=Math.max,sg=Math.min,fg=Math.sin,lg=Math.sqrt,hg=1e-12,pg=Math.PI,dg=pg/2,vg=2*pg;Oa.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var _g=function(t){return new Oa(t)},yg=function(){function t(t){var a,c,s,f=t.length,l=!1;for(null==i&&(u=o(s=ve())),a=0;a<=f;++a)!(a<f&&r(c=t[a],a,t))===l&&((l=!l)?u.lineStart():u.lineEnd()),l&&u.point(+n(c,a,t),+e(c,a,t));if(s)return u=null,s+""||null}var n=Fa,e=Ia,r=ig(!0),i=null,o=_g,u=null;return t.x=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.defined=function(n){return arguments.length?(r="function"==typeof n?n:ig(!!n),t):r},t.curve=function(n){return arguments.length?(o=n,null!=i&&(u=o(i)),t):o},t.context=function(n){return arguments.length?(null==n?i=u=null:u=o(i=n),t):i},t},gg=function(){function t(t){var n,f,l,h,p,d=t.length,v=!1,_=new Array(d),y=new Array(d);for(null==a&&(s=c(p=ve())),n=0;n<=d;++n){if(!(n<d&&u(h=t[n],n,t))===v)if(v=!v)f=n,s.areaStart(),s.lineStart();else{for(s.lineEnd(),s.lineStart(),l=n-1;l>=f;--l)s.point(_[l],y[l]);s.lineEnd(),s.areaEnd()}v&&(_[n]=+e(h,n,t),y[n]=+i(h,n,t),s.point(r?+r(h,n,t):_[n],o?+o(h,n,t):y[n]))}if(p)return s=null,p+""||null}function n(){return yg().defined(u).curve(c).context(a)}var e=Fa,r=null,i=ig(0),o=Ia,u=ig(!0),a=null,c=_g,s=null;return t.x=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),r=null,t):e},t.x0=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.x1=function(n){return arguments.length?(r=null==n?null:"function"==typeof n?n:ig(+n),t):r},t.y=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),o=null,t):i},t.y0=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.y1=function(n){return arguments.length?(o=null==n?null:"function"==typeof n?n:ig(+n),t):o},t.lineX0=t.lineY0=function(){return n().x(e).y(i)},t.lineY1=function(){return n().x(e).y(o)},t.lineX1=function(){return n().x(r).y(i)},t.defined=function(n){return arguments.length?(u="function"==typeof n?n:ig(!!n),t):u},t.curve=function(n){return arguments.length?(c=n,null!=a&&(s=c(a)),t):c},t.context=function(n){return arguments.length?(null==n?a=s=null:s=c(a=n),t):a},t},mg=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},xg=function(t){return t},bg=Ba(_g);Ya.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var wg=function(){return ja(yg().curve(bg))},Mg=function(){var t=gg().curve(bg),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return ja(e())},delete t.lineX0,t.lineEndAngle=function(){return ja(r())},delete t.lineX1,t.lineInnerRadius=function(){return ja(i())},delete t.lineY0,t.lineOuterRadius=function(){return ja(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Ba(t)):n()._curve},t},Tg=function(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]},kg=Array.prototype.slice,Ng={draw:function(t,n){var e=Math.sqrt(n/pg);t.moveTo(e,0),t.arc(0,0,e,0,vg)}},Sg={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},Eg=Math.sqrt(1/3),Ag=2*Eg,Cg={draw:function(t,n){var e=Math.sqrt(n/Ag),r=e*Eg;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},zg=Math.sin(pg/10)/Math.sin(7*pg/10),Pg=Math.sin(vg/10)*zg,Rg=-Math.cos(vg/10)*zg,Lg={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=Pg*e,i=Rg*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var u=vg*o/5,a=Math.cos(u),c=Math.sin(u);t.lineTo(c*e,-a*e),t.lineTo(a*r-c*i,c*r+a*i)}t.closePath()}},qg={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},Ug=Math.sqrt(3),Dg={draw:function(t,n){var e=-Math.sqrt(n/(3*Ug));t.moveTo(0,2*e),t.lineTo(-Ug*e,-e),t.lineTo(Ug*e,-e),t.closePath()}},Og=-.5,Fg=Math.sqrt(3)/2,Ig=1/Math.sqrt(12),Yg=3*(Ig/2+1),Bg={draw:function(t,n){var e=Math.sqrt(n/Yg),r=e/2,i=e*Ig,o=r,u=e*Ig+e,a=-o,c=u;t.moveTo(r,i),t.lineTo(o,u),t.lineTo(a,c),t.lineTo(Og*r-Fg*i,Fg*r+Og*i),t.lineTo(Og*o-Fg*u,Fg*o+Og*u),t.lineTo(Og*a-Fg*c,Fg*a+Og*c),t.lineTo(Og*r+Fg*i,Og*i-Fg*r),t.lineTo(Og*o+Fg*u,Og*u-Fg*o),t.lineTo(Og*a+Fg*c,Og*c-Fg*a),t.closePath()}},jg=[Ng,Sg,Cg,qg,Lg,Dg,Bg],Hg=function(){};Ja.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Ga(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};Qa.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};Ka.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};tc.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],u=t[e]-i,a=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*u),this._beta*n[c]+(1-this._beta)*(o+r*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Xg=function t(n){function e(t){return 1===n?new Ja(t):new tc(t,n)}return e.beta=function(n){return t(+n)},e}(.85);ec.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:nc(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var $g=function t(n){function e(t){return new ec(t,n)}return e.tension=function(n){return t(+n)},e}(0);rc.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Vg=function t(n){function e(t){return new rc(t,n)}return e.tension=function(n){return t(+n)},e}(0);ic.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Wg=function t(n){function e(t){return new ic(t,n)}return e.tension=function(n){return t(+n)},e}(0);uc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Zg=function t(n){function e(t){return n?new uc(t,n):new ec(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);ac.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Gg=function t(n){function e(t){return n?new ac(t,n):new rc(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);cc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Jg=function t(n){function e(t){return n?new cc(t,n):new ic(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);sc.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}};dc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:pc(this,this._t0,hc(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(t=+t,n=+n,t!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,pc(this,hc(this,e=lc(this,t,n)),e);break;default:pc(this,this._t0,e=lc(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(vc.prototype=Object.create(dc.prototype)).point=function(t,n){dc.prototype.point.call(this,n,t)},_c.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},yc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=gc(t),i=gc(n),o=0,u=1;u<e;++o,++u)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[u],n[u]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}};mc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var Qg=function(t,n){if((i=t.length)>1)for(var e,r,i,o=1,u=t[n[0]],a=u.length;o<i;++o)for(r=u,u=t[n[o]],e=0;e<a;++e)u[e][1]+=u[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]},Kg=function(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e},tm=function(t){var n=t.map(bc);return Kg(t).sort(function(t,e){return n[t]-n[e]})},nm=function(t){return function(){return t}};Tc.prototype={constructor:Tc,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=Ec(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(Nc(this,e),e=(t=e).U),e.C=!1,r.C=!0,Sc(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(Sc(this,e),e=(t=e).U),e.C=!1,r.C=!0,Nc(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,u=t.R;if(e=o?u?Ec(u):o:u,i?i.L===t?i.L=e:i.R=e:this._=e,o&&u?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==u?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=u,u.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,Nc(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,Sc(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,Nc(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,Sc(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,Nc(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,Sc(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var em,rm,im,om,um,am=[],cm=[],sm=1e-6,fm=1e-12;Kc.prototype={constructor:Kc,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return Dc(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,u,a=e.site,c=-1,s=n[i[o-1]],f=s.left===a?s.right:s.left;++c<o;)u=f,f=(s=n[i[c]]).left===a?s.right:s.left,u&&f&&r<u.index&&r<f.index&&Jc(a,u,f)<0&&t.push([a.data,u.data,f.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,u=o._found||0,a=o.cells.length;!(i=o.cells[u]);)if(++u>=a)return null;var c=t-i.site[0],s=n-i.site[1],f=c*c+s*s;do{i=o.cells[r=u],u=null,i.halfedges.forEach(function(e){var r=o.edges[e],a=r.left;if(a!==i.site&&a||(a=r.right)){var c=t-a[0],s=n-a[1],l=c*c+s*s;l<f&&(f=l,u=a.index)}})}while(null!==u);return o._found=r,null==e||f<=e*e?i.site:null}};var lm=function(t){return function(){return t}};ns.prototype={constructor:ns,scale:function(t){return 1===t?this:new ns(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ns(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var hm=new ns(1,0,0);es.prototype=ns.prototype;var pm=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()};t.version="4.10.0",t.bisect=hs,t.bisectRight=hs,t.bisectLeft=ps,t.ascending=ss,t.bisector=fs,t.cross=function(t,n,r){var i,o,u,a,c=t.length,s=n.length,f=new Array(c*s);for(null==r&&(r=e),i=u=0;i<c;++i)for(a=t[i],o=0;o<s;++o,++u)f[u]=r(a,n[o]);return f},t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=_s,t.extent=ys,t.histogram=function(){function t(t){var o,u,a=t.length,c=new Array(a);for(o=0;o<a;++o)c[o]=n(t[o],o,t);var s=e(c),f=s[0],l=s[1],h=r(c,f,l);Array.isArray(h)||(h=i(f,l,h),h=Ms(Math.ceil(f/h)*h,Math.floor(l/h)*h,h));for(var p=h.length;h[0]<=f;)h.shift(),--p;for(;h[p-1]>l;)h.pop(),--p;var d,v=new Array(p+1);for(o=0;o<=p;++o)(d=v[o]=[]).x0=o>0?h[o-1]:f,d.x1=o<p?h[o]:l;for(o=0;o<a;++o)f<=(u=c[o])&&u<=l&&v[hs(h,u,0,p)].push(t[o]);return v}var n=ws,e=ys,r=Es;return t.value=function(e){return arguments.length?(n="function"==typeof e?e:bs(e),t):n},t.domain=function(n){return arguments.length?(e="function"==typeof n?n:bs([n[0],n[1]]),t):e},t.thresholds=function(n){return arguments.length?(r="function"==typeof n?n:bs(Array.isArray(n)?ms.call(n):n),t):r},t},t.thresholdFreedmanDiaconis=function(t,n,e){return t=xs.call(t,ds).sort(ss),Math.ceil((e-n)/(2*(As(t,.75)-As(t,.25))*Math.pow(t.length,-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*_s(t)*Math.pow(t.length,-1/3)))},t.thresholdSturges=Es,t.max=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r},t.mean=function(t,n){var e,r=t.length,i=r,o=-1,u=0;if(null==n)for(;++o<r;)isNaN(e=ds(t[o]))?--i:u+=e;else for(;++o<r;)isNaN(e=ds(n(t[o],o,t)))?--i:u+=e;if(i)return u/i},t.median=function(t,n){var e,r=t.length,i=-1,o=[];if(null==n)for(;++i<r;)isNaN(e=ds(t[i]))||o.push(e);else for(;++i<r;)isNaN(e=ds(n(t[i],i,t)))||o.push(e);return As(o.sort(ss),.5)},t.merge=Cs,t.min=zs,t.pairs=function(t,n){null==n&&(n=e);for(var r=0,i=t.length-1,o=t[0],u=new Array(i<0?0:i);r<i;)u[r]=n(o,o=t[++r]);return u},t.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},t.quantile=As,t.range=Ms,t.scan=function(t,n){if(e=t.length){var e,r,i=0,o=0,u=t[o];for(null==n&&(n=ss);++i<e;)(n(r=t[i],u)<0||0!==n(u,u))&&(u=r,o=i);return 0===n(u,u)?o:void 0}},t.shuffle=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},t.sum=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},t.ticks=Ss,t.tickIncrement=r,t.tickStep=i,t.transpose=Ps,t.variance=vs,t.zip=function(){return Ps(arguments)},t.axisTop=function(t){return l(qs,t)},t.axisRight=function(t){return l(Us,t)},t.axisBottom=function(t){return l(Ds,t)},t.axisLeft=function(t){return l(Os,t)},t.brush=function(){return he(Sh)},t.brushX=function(){return he(kh)},t.brushY=function(){return he(Nh)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.chord=function(){function t(t){var o,u,a,c,s,f,l=t.length,h=[],p=Ms(l),d=[],v=[],_=v.groups=new Array(l),y=new Array(l*l);for(o=0,s=-1;++s<l;){for(u=0,f=-1;++f<l;)u+=t[s][f];h.push(u),d.push(Ms(l)),o+=u}for(e&&p.sort(function(t,n){return e(h[t],h[n])}),r&&d.forEach(function(n,e){n.sort(function(n,i){return r(t[e][n],t[e][i])})}),c=(o=Oh(0,Dh-n*l)/o)?n:Dh/l,u=0,s=-1;++s<l;){for(a=u,f=-1;++f<l;){var g=p[s],m=d[g][f],x=t[g][m],b=u,w=u+=x*o;y[m*l+g]={index:g,subindex:m,startAngle:b,endAngle:w,value:x}}_[g]={index:g,startAngle:a,endAngle:u,value:h[g]},u+=c}for(s=-1;++s<l;)for(f=s-1;++f<l;){var M=y[f*l+s],T=y[s*l+f];(M.value||T.value)&&v.push(M.value<T.value?{source:T,target:M}:{source:M,target:T})}return i?v.sort(i):v}var n=0,e=null,r=null,i=null;return t.padAngle=function(e){return arguments.length?(n=Oh(0,e),t):n},t.sortGroups=function(n){return arguments.length?(e=n,t):e},t.sortSubgroups=function(n){return arguments.length?(r=n,t):r},t.sortChords=function(n){return arguments.length?(null==n?i=null:(i=pe(n))._=n,t):i&&i._},t},t.ribbon=function(){function t(){var t,a=Fh.call(arguments),c=n.apply(this,a),s=e.apply(this,a),f=+r.apply(this,(a[0]=c,a)),l=i.apply(this,a)-Uh,h=o.apply(this,a)-Uh,p=f*Rh(l),d=f*Lh(l),v=+r.apply(this,(a[0]=s,a)),_=i.apply(this,a)-Uh,y=o.apply(this,a)-Uh;if(u||(u=t=ve()),u.moveTo(p,d),u.arc(0,0,f,l,h),l===_&&h===y||(u.quadraticCurveTo(0,0,v*Rh(_),v*Lh(_)),u.arc(0,0,v,_,y)),u.quadraticCurveTo(0,0,p,d),u.closePath(),t)return u=null,t+""||null}var n=_e,e=ye,r=ge,i=me,o=xe,u=null;return t.radius=function(n){return arguments.length?(r="function"==typeof n?n:Ih(+n),t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:Ih(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:Ih(+n),t):o},t.source=function(e){return arguments.length?(n=e,t):n},t.target=function(n){return arguments.length?(e=n,t):e},t.context=function(n){return arguments.length?(u=null==n?null:n,t):u},t},t.nest=function(){function t(n,i,u,a){if(i>=o.length)return null!=e&&n.sort(e),null!=r?r(n):n;for(var c,s,f,l=-1,h=n.length,p=o[i++],d=we(),v=u();++l<h;)(f=d.get(c=p(s=n[l])+""))?f.push(s):d.set(c,[s]);return d.each(function(n,e){a(v,e,t(n,i,u,a))}),v}function n(t,e){if(++e>o.length)return t;var i,a=u[e-1];return null!=r&&e>=o.length?i=t.entries():(i=[],t.each(function(t,r){i.push({key:r,values:n(t,e)})})),null!=a?i.sort(function(t,n){return a(t.key,n.key)}):i}var e,r,i,o=[],u=[];return i={object:function(n){return t(n,0,Me,Te)},map:function(n){return t(n,0,ke,Ne)},entries:function(e){return n(t(e,0,ke,Ne),0)},key:function(t){return o.push(t),i},sortKeys:function(t){return u[o.length-1]=t,i},sortValues:function(t){return e=t,i},rollup:function(t){return r=t,i}}},t.set=Ee,t.map=we,t.keys=function(t){var n=[];for(var e in t)n.push(e);return n},t.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},t.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},t.color=Tt,t.rgb=Et,t.hsl=Pt,t.lab=Ut,t.hcl=jt,t.cubehelix=$t,t.dispatch=h,t.drag=function(){function n(t){t.on("mousedown.drag",e).filter(bt).on("touchstart.drag",o).on("touchmove.drag",u).on("touchend.drag touchcancel.drag",a).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(){if(!p&&d.apply(this,arguments)){var n=c("mouse",v.apply(this,arguments),Ks,this,arguments);n&&(cf(t.event.view).on("mousemove.drag",r,!0).on("mouseup.drag",i,!0),lf(t.event.view),vt(),l=!1,s=t.event.clientX,f=t.event.clientY,n("start"))}}function r(){if(ff(),!l){var n=t.event.clientX-s,e=t.event.clientY-f;l=n*n+e*e>x}y.mouse("drag")}function i(){cf(t.event.view).on("mousemove.drag mouseup.drag",null),_t(t.event.view,l),ff(),y.mouse("end")}function o(){if(d.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=v.apply(this,arguments),o=r.length;for(n=0;n<o;++n)(e=c(r[n].identifier,i,sf,this,arguments))&&(vt(),e("start"))}}function u(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=y[r[n].identifier])&&(ff(),e("drag"))}function a(){var n,e,r=t.event.changedTouches,i=r.length;for(p&&clearTimeout(p),p=setTimeout(function(){p=null},500),n=0;n<i;++n)(e=y[r[n].identifier])&&(vt(),e("end"))}function c(e,r,i,o,u){var a,c,s,f=i(r,e),l=g.copy();if(N(new yt(n,"beforestart",a,e,m,f[0],f[1],0,0,l),function(){return null!=(t.event.subject=a=_.apply(o,u))&&(c=a.x-f[0]||0,s=a.y-f[1]||0,!0)}))return function t(h){var p,d=f;switch(h){case"start":y[e]=t,p=m++;break;case"end":delete y[e],--m;case"drag":f=i(r,e),p=m}N(new yt(n,h,a,e,p,f[0]+c,f[1]+s,f[0]-d[0],f[1]-d[1],l),l.apply,l,[h,o,u])}}var s,f,l,p,d=gt,v=mt,_=xt,y={},g=h("start","drag","end"),m=0,x=0;return n.filter=function(t){return arguments.length?(d="function"==typeof t?t:hf(!!t),n):d},n.container=function(t){return arguments.length?(v="function"==typeof t?t:hf(t),n):v},n.subject=function(t){return arguments.length?(_="function"==typeof t?t:hf(t),n):_},n.on=function(){var t=g.on.apply(g,arguments);return t===g?n:t},n.clickDistance=function(t){return arguments.length?(x=(t=+t)*t,n):Math.sqrt(x)},n},t.dragDisable=lf,t.dragEnable=_t,t.dsvFormat=Xh,t.csvParse=Vh,t.csvParseRows=Wh,t.csvFormat=Zh,t.csvFormatRows=Gh,t.tsvParse=Qh,t.tsvParseRows=Kh,t.tsvFormat=tp,t.tsvFormatRows=np,t.easeLinear=function(t){return+t},t.easeQuad=Kn,t.easeQuadIn=function(t){return t*t},t.easeQuadOut=function(t){return t*(2-t)},t.easeQuadInOut=Kn,t.easeCubic=te,t.easeCubicIn=function(t){return t*t*t},t.easeCubicOut=function(t){return--t*t*t+1},t.easeCubicInOut=te,t.easePoly=Gl,t.easePolyIn=Wl,t.easePolyOut=Zl,t.easePolyInOut=Gl,t.easeSin=ne,t.easeSinIn=function(t){return 1-Math.cos(t*Ql)},t.easeSinOut=function(t){return Math.sin(t*Ql)},t.easeSinInOut=ne,t.easeExp=ee,t.easeExpIn=function(t){return Math.pow(2,10*t-10)},t.easeExpOut=function(t){return 1-Math.pow(2,-10*t)},t.easeExpInOut=ee,t.easeCircle=re,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCircleInOut=re,t.easeBounce=ie,t.easeBounceIn=function(t){return 1-ie(1-t)},t.easeBounceOut=ie,t.easeBounceInOut=function(t){return((t*=2)<=1?1-ie(1-t):ie(t-1)+1)/2},t.easeBack=lh,t.easeBackIn=sh,t.easeBackOut=fh,t.easeBackInOut=lh,t.easeElastic=dh,t.easeElasticIn=ph,t.easeElasticOut=dh,t.easeElasticInOut=vh,t.forceCenter=function(t,n){function e(){var e,i,o=r.length,u=0,a=0;for(e=0;e<o;++e)u+=(i=r[e]).x,a+=i.y;for(u=u/o-t,a=a/o-n,e=0;e<o;++e)(i=r[e]).x-=u,i.y-=a}var r;return null==t&&(t=0),null==n&&(n=0),e.initialize=function(t){r=t},e.x=function(n){return arguments.length?(t=+n,e):t},e.y=function(t){return arguments.length?(n=+t,e):n},e},t.forceCollide=function(t){function n(){for(var t,n,r,c,s,f,l,h=i.length,p=0;p<a;++p)for(n=qe(i,Oe,Fe).visitAfter(e),t=0;t<h;++t)r=i[t],f=o[r.index],l=f*f,c=r.x+r.vx,s=r.y+r.vy,n.visit(function(t,n,e,i,o){var a=t.data,h=t.r,p=f+h;if(!a)return n>c+p||i<c-p||e>s+p||o<s-p;if(a.index>r.index){var d=c-a.x-a.vx,v=s-a.y-a.vy,_=d*d+v*v;_<p*p&&(0===d&&(d=rp(),_+=d*d),0===v&&(v=rp(),_+=v*v),_=(p-(_=Math.sqrt(_)))/_*u,r.vx+=(d*=_)*(p=(h*=h)/(l+h)),r.vy+=(v*=_)*p,a.vx-=d*(p=1-p),a.vy-=v*p)}})}function e(t){if(t.data)return t.r=o[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function r(){if(i){var n,e,r=i.length;for(o=new Array(r),n=0;n<r;++n)e=i[n],o[e.index]=+t(e,n,i)}}var i,o,u=1,a=1;return"function"!=typeof t&&(t=ep(null==t?1:+t)),n.initialize=function(t){i=t,r()},n.iterations=function(t){return arguments.length?(a=+t,n):a},n.strength=function(t){return arguments.length?(u=+t,n):u},n.radius=function(e){return arguments.length?(t="function"==typeof e?e:ep(+e),r(),n):t},n},t.forceLink=function(t){function n(n){for(var e=0,r=t.length;e<p;++e)for(var i,a,c,f,l,h,d,v=0;v<r;++v)a=(i=t[v]).source,f=(c=i.target).x+c.vx-a.x-a.vx||rp(),l=c.y+c.vy-a.y-a.vy||rp(),f*=h=((h=Math.sqrt(f*f+l*l))-u[v])/h*n*o[v],l*=h,c.vx-=f*(d=s[v]),c.vy-=l*d,a.vx+=f*(d=1-d),a.vy+=l*d}function e(){if(a){var n,e,l=a.length,h=t.length,p=we(a,f);for(n=0,c=new Array(l);n<h;++n)(e=t[n]).index=n,"object"!=typeof e.source&&(e.source=Ye(p,e.source)),"object"!=typeof e.target&&(e.target=Ye(p,e.target)),c[e.source.index]=(c[e.source.index]||0)+1,c[e.target.index]=(c[e.target.index]||0)+1;for(n=0,s=new Array(h);n<h;++n)e=t[n],s[n]=c[e.source.index]/(c[e.source.index]+c[e.target.index]);o=new Array(h),r(),u=new Array(h),i()}}function r(){if(a)for(var n=0,e=t.length;n<e;++n)o[n]=+l(t[n],n,t)}function i(){if(a)for(var n=0,e=t.length;n<e;++n)u[n]=+h(t[n],n,t)}var o,u,a,c,s,f=Ie,l=function(t){return 1/Math.min(c[t.source.index],c[t.target.index])},h=ep(30),p=1;return null==t&&(t=[]),n.initialize=function(t){a=t,e()},n.links=function(r){return arguments.length?(t=r,e(),n):t},n.id=function(t){return arguments.length?(f=t,n):f},n.iterations=function(t){return arguments.length?(p=+t,n):p},n.strength=function(t){return arguments.length?(l="function"==typeof t?t:ep(+t),r(),n):l},n.distance=function(t){return arguments.length?(h="function"==typeof t?t:ep(+t),i(),n):h},n},t.forceManyBody=function(){function t(t){var n,a=i.length,c=qe(i,Be,je).visitAfter(e);for(u=t,n=0;n<a;++n)o=i[n],c.visit(r)}function n(){if(i){var t,n,e=i.length;for(a=new Array(e),t=0;t<e;++t)n=i[t],a[n.index]=+c(n,t,i)}}function e(t){var n,e,r,i,o,u=0;if(t.length){for(r=i=o=0;o<4;++o)(n=t[o])&&(e=n.value)&&(u+=e,r+=e*n.x,i+=e*n.y);t.x=r/u,t.y=i/u}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=a[n.data.index]}while(n=n.next)}t.value=u}function r(t,n,e,r){if(!t.value)return!0;var i=t.x-o.x,c=t.y-o.y,h=r-n,p=i*i+c*c;if(h*h/l<p)return p<f&&(0===i&&(i=rp(),p+=i*i),0===c&&(c=rp(),p+=c*c),p<s&&(p=Math.sqrt(s*p)),o.vx+=i*t.value*u/p,o.vy+=c*t.value*u/p),!0;if(!(t.length||p>=f)){(t.data!==o||t.next)&&(0===i&&(i=rp(),p+=i*i),0===c&&(c=rp(),p+=c*c),p<s&&(p=Math.sqrt(s*p)));do{t.data!==o&&(h=a[t.data.index]*u/p,o.vx+=i*h,o.vy+=c*h)}while(t=t.next)}}var i,o,u,a,c=ep(-30),s=1,f=1/0,l=.81;return t.initialize=function(t){i=t,n()},t.strength=function(e){return arguments.length?(c="function"==typeof e?e:ep(+e),n(),t):c},t.distanceMin=function(n){return arguments.length?(s=n*n,t):Math.sqrt(s)},t.distanceMax=function(n){return arguments.length?(f=n*n,t):Math.sqrt(f)},t.theta=function(n){return arguments.length?(l=n*n,t):Math.sqrt(l)},t},t.forceSimulation=function(t){function n(){e(),d.call("tick",o),u<a&&(p.stop(),d.call("end",o))}function e(){var n,e,r=t.length;for(u+=(s-u)*c,l.each(function(t){t(u)}),n=0;n<r;++n)null==(e=t[n]).fx?e.x+=e.vx*=f:(e.x=e.fx,e.vx=0),null==e.fy?e.y+=e.vy*=f:(e.y=e.fy,e.vy=0)}function r(){for(var n,e=0,r=t.length;e<r;++e){if(n=t[e],n.index=e,isNaN(n.x)||isNaN(n.y)){var i=ap*Math.sqrt(e),o=e*cp;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function i(n){return n.initialize&&n.initialize(t),n}var o,u=1,a=.001,c=1-Math.pow(a,1/300),s=0,f=.6,l=we(),p=dn(n),d=h("tick","end");return null==t&&(t=[]),r(),o={tick:e,restart:function(){return p.restart(n),o},stop:function(){return p.stop(),o},nodes:function(n){return arguments.length?(t=n,r(),l.each(i),o):t},alpha:function(t){return arguments.length?(u=+t,o):u},alphaMin:function(t){return arguments.length?(a=+t,o):a},alphaDecay:function(t){return arguments.length?(c=+t,o):+c},alphaTarget:function(t){return arguments.length?(s=+t,o):s},velocityDecay:function(t){return arguments.length?(f=1-t,o):1-f},force:function(t,n){return arguments.length>1?(null==n?l.remove(t):l.set(t,i(n)),o):l.get(t)},find:function(n,e,r){var i,o,u,a,c,s=0,f=t.length;for(null==r?r=1/0:r*=r,s=0;s<f;++s)(u=(i=n-(a=t[s]).x)*i+(o=e-a.y)*o)<r&&(c=a,r=u);return c},on:function(t,n){return arguments.length>1?(d.on(t,n),o):d.on(t)}}},t.forceX=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)(n=r[e]).vx+=(o[e]-n.x)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=ep(.1);return"function"!=typeof t&&(t=ep(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),e(),n):u},n.x=function(r){return arguments.length?(t="function"==typeof r?r:ep(+r),e(),n):t},n},t.forceY=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)(n=r[e]).vy+=(o[e]-n.y)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=ep(.1);return"function"!=typeof t&&(t=ep(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),e(),n):u},n.y=function(r){return arguments.length?(t="function"==typeof r?r:ep(+r),e(),n):t},n},t.formatDefaultLocale=$e,t.formatLocale=mp,t.formatSpecifier=He,t.precisionFixed=xp,t.precisionPrefix=bp,t.precisionRound=wp,t.geoArea=function(t){return kd.reset(),Md(t,Nd),2*kd},t.geoBounds=function(t){var n,e,r,i,o,u,a;if(Pp=zp=-(Ap=Cp=1/0),Dp=[],Md(t,Ed),e=Dp.length){for(Dp.sort(br),n=1,o=[r=Dp[0]];n<e;++n)wr(r,(i=Dp[n])[0])||wr(r,i[1])?(xr(r[0],i[1])>xr(r[0],r[1])&&(r[1]=i[1]),xr(i[0],r[1])>xr(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(a=xr(r[1],i[0]))>u&&(u=a,Ap=i[0],zp=r[1])}return Dp=Op=null,Ap===1/0||Cp===1/0?[[NaN,NaN],[NaN,NaN]]:[[Ap,Cp],[zp,Pp]]},t.geoCentroid=function(t){Fp=Ip=Yp=Bp=jp=Hp=Xp=$p=Vp=Wp=Zp=0,Md(t,Ad);var n=Vp,e=Wp,r=Zp,i=n*n+e*e+r*r;return i<1e-12&&(n=Hp,e=Xp,r=$p,Ip<ed&&(n=Yp,e=Bp,r=jp),(i=n*n+e*e+r*r)<1e-12)?[NaN,NaN]:[ld(e,n)*ad,Ge(r/md(i))*ad]},t.geoCircle=function(){function t(){var t=r.apply(this,arguments),a=i.apply(this,arguments)*cd,c=o.apply(this,arguments)*cd;return n=[],e=Lr(-t[0]*cd,-t[1]*cd,0).invert,Or(u,a,c,1),t={type:"Polygon",coordinates:[n]},n=e=null,t}var n,e,r=Cd([0,0]),i=Cd(90),o=Cd(6),u={point:function(t,r){n.push(t=e(t,r)),t[0]*=ad,t[1]*=ad}};return t.center=function(n){return arguments.length?(r="function"==typeof n?n:Cd([+n[0],+n[1]]),t):r},t.radius=function(n){return arguments.length?(i="function"==typeof n?n:Cd(+n),t):i},t.precision=function(n){return arguments.length?(o="function"==typeof n?n:Cd(+n),t):o},t},t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,u=500;return e={stream:function(e){return t&&n===e?t:t=Br(r,i,o,u)(n=e)},extent:function(a){return arguments.length?(r=+a[0][0],i=+a[0][1],o=+a[1][0],u=+a[1][1],t=n=null,e):[[r,i],[o,u]]}}},t.geoContains=function(t,n){return(t&&iv.hasOwnProperty(t.type)?iv[t.type]:$r)(t,n)},t.geoDistance=rv,t.geoGraticule=ti,t.geoGraticule10=function(){return ti()()},t.geoInterpolate=function(t,n){var e=t[0]*cd,r=t[1]*cd,i=n[0]*cd,o=n[1]*cd,u=hd(r),a=yd(r),c=hd(o),s=yd(o),f=u*hd(e),l=u*yd(e),h=c*hd(i),p=c*yd(i),d=2*Ge(md(Je(o-r)+u*c*Je(i-e))),v=yd(d),_=d?function(t){var n=yd(t*=d)/v,e=yd(d-t)/v,r=e*f+n*h,i=e*l+n*p,o=e*a+n*s;return[ld(i,r)*ad,ld(o,md(r*r+i*i))*ad]}:function(){return[e*ad,r*ad]};return _.distance=d,_},t.geoLength=tv,t.geoPath=function(t,n){function e(t){return t&&("function"==typeof o&&i.pointRadius(+o.apply(this,arguments)),Md(t,r(i))),i.result()}var r,i,o=4.5;return e.area=function(t){return Md(t,r(sv)),sv.result()},e.measure=function(t){return Md(t,r(zv)),zv.result()},e.bounds=function(t){return Md(t,r(dv)),dv.result()},e.centroid=function(t){return Md(t,r(Tv)),Tv.result()},e.projection=function(n){return arguments.length?(r=null==n?(t=null,uv):(t=n).stream,e):t},e.context=function(t){return arguments.length?(i=null==t?(n=null,new yi):new di(n=t),"function"!=typeof o&&i.pointRadius(o),e):n},e.pointRadius=function(t){return arguments.length?(o="function"==typeof t?t:(i.pointRadius(+t),+t),e):o},e.projection(t).context(n)},t.geoAlbers=Iv,t.geoAlbersUsa=function(){function t(t){var n=t[0],e=t[1];return a=null,i.point(n,e),a||(o.point(n,e),a)||(u.point(n,e),a)}function n(){return e=r=null,t}var e,r,i,o,u,a,c=Iv(),s=Fv().rotate([154,0]).center([-2,58.5]).parallels([55,65]),f=Fv().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(t,n){a=[t,n]}};return t.invert=function(t){var n=c.scale(),e=c.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?f:c).invert(t)},t.stream=function(t){return e&&r===t?e:e=Ri([c.stream(r=t),s.stream(t),f.stream(t)])},t.precision=function(t){return arguments.length?(c.precision(t),s.precision(t),f.precision(t),n()):c.precision()},t.scale=function(n){return arguments.length?(c.scale(n),s.scale(.35*n),f.scale(n),t.translate(c.translate())):c.scale()},t.translate=function(t){if(!arguments.length)return c.translate();var e=c.scale(),r=+t[0],a=+t[1];return i=c.translate(t).clipExtent([[r-.455*e,a-.238*e],[r+.455*e,a+.238*e]]).stream(l),o=s.translate([r-.307*e,a+.201*e]).clipExtent([[r-.425*e+ed,a+.12*e+ed],[r-.214*e-ed,a+.234*e-ed]]).stream(l),u=f.translate([r-.205*e,a+.212*e]).clipExtent([[r-.214*e+ed,a+.166*e+ed],[r-.115*e-ed,a+.234*e-ed]]).stream(l),n()},t.fitExtent=function(n,e){return Ti(t,n,e)},t.fitSize=function(n,e){return ki(t,n,e)},t.scale(1070)},t.geoAzimuthalEqualArea=function(){return Ei(Yv).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Yv,t.geoAzimuthalEquidistant=function(){return Ei(Bv).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=Bv,t.geoConicConformal=function(){return Ci(Fi).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=Fi,t.geoConicEqualArea=Fv,t.geoConicEqualAreaRaw=Pi,t.geoConicEquidistant=function(){return Ci(Yi).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=Yi,t.geoEquirectangular=function(){return Ei(Ii).scale(152.63)},t.geoEquirectangularRaw=Ii,t.geoGnomonic=function(){return Ei(Bi).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=Bi,t.geoIdentity=function(){function t(){return i=o=null,u}var n,e,r,i,o,u,a=1,c=0,s=0,f=1,l=1,h=uv,p=null,d=uv;return u={stream:function(t){return i&&o===t?i:i=h(d(o=t))},clipExtent:function(i){return arguments.length?(d=null==i?(p=n=e=r=null,uv):Br(p=+i[0][0],n=+i[0][1],e=+i[1][0],r=+i[1][1]),t()):null==p?null:[[p,n],[e,r]]},scale:function(n){return arguments.length?(h=ji((a=+n)*f,a*l,c,s),t()):a},translate:function(n){return arguments.length?(h=ji(a*f,a*l,c=+n[0],s=+n[1]),t()):[c,s]},reflectX:function(n){return arguments.length?(h=ji(a*(f=n?-1:1),a*l,c,s),t()):f<0},reflectY:function(n){return arguments.length?(h=ji(a*f,a*(l=n?-1:1),c,s),t()):l<0},fitExtent:function(t,n){return Ti(u,t,n)},fitSize:function(t,n){return ki(u,t,n)}}},t.geoProjection=Ei,t.geoProjectionMutator=Ai,t.geoMercator=function(){return Di(Ui).scale(961/ud)},t.geoMercatorRaw=Ui,t.geoOrthographic=function(){return Ei(Hi).scale(249.5).clipAngle(90+ed)},t.geoOrthographicRaw=Hi,t.geoStereographic=function(){return Ei(Xi).scale(250).clipAngle(142)},t.geoStereographicRaw=Xi,t.geoTransverseMercator=function(){var t=Di($i),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):(t=n(),[t[1],-t[0]])},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):(t=e(),[t[0],t[1],t[2]-90])},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=$i,t.geoRotation=jd,t.geoStream=Md,t.geoTransform=function(t){return{stream:wi(t)}},t.cluster=function(){function t(t){var o,u=0;t.eachAfter(function(t){var e=t.children;e?(t.x=Wi(e),t.y=Gi(e)):(t.x=o?u+=n(t,o):0,t.y=0,o=t)});var a=Qi(t),c=Ki(t),s=a.x-n(a,c)/2,f=c.x+n(c,a)/2;return t.eachAfter(i?function(n){n.x=(n.x-t.x)*e,n.y=(t.y-n.y)*r}:function(n){n.x=(n.x-s)/(f-s)*e,n.y=(1-(t.y?n.y/t.y:1))*r})}var n=Vi,e=1,r=1,i=!1;return t.separation=function(e){return arguments.length?(n=e,t):n},t.size=function(n){return arguments.length?(i=!1,e=+n[0],r=+n[1],t):i?null:[e,r]},t.nodeSize=function(n){return arguments.length?(i=!0,e=+n[0],r=+n[1],t):i?[e,r]:null},t},t.hierarchy=eo,t.pack=function(){function t(t){return t.x=e/2,t.y=r/2,n?t.eachBefore(No(n)).eachAfter(So(i,.5)).eachBefore(Eo(1)):t.eachBefore(No(ko)).eachAfter(So(To,1)).eachAfter(So(i,t.r/Math.min(e,r))).eachBefore(Eo(Math.min(e,r)/(2*t.r))),t}var n=null,e=1,r=1,i=To;return t.radius=function(e){return arguments.length?(n=wo(e),t):n},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i="function"==typeof n?n:Xv(+n),t):i},t},t.packSiblings=function(t){return bo(t),t},t.packEnclose=Hv,t.partition=function(){function t(t){var u=t.height+1;return t.x0=t.y0=i,t.x1=e,t.y1=r/u,t.eachBefore(n(r,u)),o&&t.eachBefore($v),t}function n(t,n){return function(e){e.children&&Vv(e,e.x0,t*(e.depth+1)/n,e.x1,t*(e.depth+2)/n);var r=e.x0,o=e.y0,u=e.x1-i,a=e.y1-i;u<r&&(r=u=(r+u)/2),a<o&&(o=a=(o+a)/2),e.x0=r,e.y0=o,e.x1=u,e.y1=a}}var e=1,r=1,i=0,o=!1;return t.round=function(n){return arguments.length?(o=!!n,t):o},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i=+n,t):i},t},t.stratify=function(){function t(t){var r,i,o,u,a,c,s,f=t.length,l=new Array(f),h={};for(i=0;i<f;++i)r=t[i],a=l[i]=new uo(r),null!=(c=n(r,i,t))&&(c+="")&&(h[s=Wv+(a.id=c)]=s in h?Gv:a);for(i=0;i<f;++i)if(a=l[i],null!=(c=e(t[i],i,t))&&(c+="")){if(!(u=h[Wv+c]))throw new Error("missing: "+c);if(u===Gv)throw new Error("ambiguous: "+c);u.children?u.children.push(a):u.children=[a],a.parent=u}else{if(o)throw new Error("multiple roots");o=a}if(!o)throw new Error("no root");if(o.parent=Zv,o.eachBefore(function(t){t.depth=t.parent.depth+1,--f}).eachBefore(oo),o.parent=null,f>0)throw new Error("cycle");return o}var n=Ao,e=Co;return t.id=function(e){return arguments.length?(n=Mo(e),t):n},t.parentId=function(n){return arguments.length?(e=Mo(n),t):e},t},t.tree=function(){function t(t){var r=Oo(t);if(r.eachAfter(n),r.parent.m=-r.z,r.eachBefore(e),c)t.eachBefore(i);else{var s=t,f=t,l=t;t.eachBefore(function(t){t.x<s.x&&(s=t),t.x>f.x&&(f=t),t.depth>l.depth&&(l=t)});var h=s===f?1:o(s,f)/2,p=h-s.x,d=u/(f.x+h+p),v=a/(l.depth||1);t.eachBefore(function(t){t.x=(t.x+p)*d,t.y=t.depth*v})}return t}function n(t){var n=t.children,e=t.parent.children,i=t.i?e[t.i-1]:null;if(n){qo(t);var u=(n[0].z+n[n.length-1].z)/2;i?(t.z=i.z+o(t._,i._),t.m=t.z-u):t.z=u}else i&&(t.z=i.z+o(t._,i._));t.parent.A=r(t,i,t.parent.A||e[0])}function e(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function r(t,n,e){if(n){for(var r,i=t,u=t,a=n,c=i.parent.children[0],s=i.m,f=u.m,l=a.m,h=c.m;a=Ro(a),i=Po(i),a&&i;)c=Po(c),(u=Ro(u)).a=t,(r=a.z+l-i.z-s+o(a._,i._))>0&&(Lo(Uo(a,t,e),t,r),s+=r,f+=r),l+=a.m,s+=i.m,h+=c.m,f+=u.m;a&&!Ro(u)&&(u.t=a,u.m+=l-f),i&&!Po(c)&&(c.t=i,c.m+=s-h,e=t)}return e}function i(t){t.x*=u,t.y=t.depth*a}var o=zo,u=1,a=1,c=null;return t.separation=function(n){return arguments.length?(o=n,t):o},t.size=function(n){return arguments.length?(c=!1,u=+n[0],a=+n[1],t):c?null:[u,a]},t.nodeSize=function(n){return arguments.length?(c=!0,u=+n[0],a=+n[1],t):c?[u,a]:null},t},t.treemap=function(){function t(t){return t.x0=t.y0=0,t.x1=i,t.y1=o,t.eachBefore(n),u=[0],r&&t.eachBefore($v),t}function n(t){var n=u[t.depth],r=t.x0+n,i=t.y0+n,o=t.x1-n,h=t.y1-n;o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),t.x0=r,t.y0=i,t.x1=o,t.y1=h,t.children&&(n=u[t.depth+1]=a(t)/2,r+=l(t)-n,i+=c(t)-n,o-=s(t)-n,h-=f(t)-n,o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),e(t,r,i,o,h))}var e=Kv,r=!1,i=1,o=1,u=[0],a=To,c=To,s=To,f=To,l=To;return t.round=function(n){return arguments.length?(r=!!n,t):r},t.size=function(n){return arguments.length?(i=+n[0],o=+n[1],t):[i,o]},t.tile=function(n){return arguments.length?(e=Mo(n),t):e},t.padding=function(n){return arguments.length?t.paddingInner(n).paddingOuter(n):t.paddingInner()},t.paddingInner=function(n){return arguments.length?(a="function"==typeof n?n:Xv(+n),t):a},t.paddingOuter=function(n){return arguments.length?t.paddingTop(n).paddingRight(n).paddingBottom(n).paddingLeft(n):t.paddingTop()},t.paddingTop=function(n){return arguments.length?(c="function"==typeof n?n:Xv(+n),t):c},t.paddingRight=function(n){return arguments.length?(s="function"==typeof n?n:Xv(+n),t):s},t.paddingBottom=function(n){return arguments.length?(f="function"==typeof n?n:Xv(+n),t):f},t.paddingLeft=function(n){return arguments.length?(l="function"==typeof n?n:Xv(+n),t):l},t},t.treemapBinary=function(t,n,e,r,i){function o(t,n,e,r,i,u,a){if(t>=n-1){var s=c[t];return s.x0=r,s.y0=i,s.x1=u,void(s.y1=a)}for(var l=f[t],h=e/2+l,p=t+1,d=n-1;p<d;){var v=p+d>>>1;f[v]<h?p=v+1:d=v}h-f[p-1]<f[p]-h&&t+1<p&&--p;var _=f[p]-l,y=e-_;if(u-r>a-i){var g=(r*y+u*_)/e;o(t,p,_,r,i,g,a),o(p,n,y,g,i,u,a)}else{var m=(i*y+a*_)/e;o(t,p,_,r,i,u,m),o(p,n,y,r,m,u,a)}}var u,a,c=t.children,s=c.length,f=new Array(s+1);for(f[0]=a=u=0;u<s;++u)f[u+1]=a+=c[u].value;o(0,s,t.value,n,e,r,i)},t.treemapDice=Vv,t.treemapSlice=Jv,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Jv:Vv)(t,n,e,r,i)},t.treemapSquarify=Kv,t.treemapResquarify=t_,t.interpolate=cl,t.interpolateArray=nl,t.interpolateBasis=Zf,t.interpolateBasisClosed=Gf,t.interpolateDate=el,t.interpolateNumber=rl,t.interpolateObject=il,t.interpolateRound=sl,t.interpolateString=al,t.interpolateTransformCss=pl,t.interpolateTransformSvg=dl,t.interpolateZoom=_l,t.interpolateRgb=Qf,t.interpolateRgbBasis=Kf,t.interpolateRgbBasisClosed=tl,t.interpolateHsl=yl,t.interpolateHslLong=gl,t.interpolateLab=function(t,n){var e=Kt((t=Ut(t)).l,(n=Ut(n)).l),r=Kt(t.a,n.a),i=Kt(t.b,n.b),o=Kt(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateHcl=ml,t.interpolateHclLong=xl,t.interpolateCubehelix=bl,t.interpolateCubehelixLong=wl,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.path=ve,t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,u=0,a=t[i-1],c=0;++r<i;)n=a,a=t[r],c+=e=n[0]*a[1]-a[0]*n[1],o+=(n[0]+a[0])*e,u+=(n[1]+a[1])*e;return c*=3,[o/c,u/c]},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(Io),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=Yo(r),u=Yo(i),a=u[0]===o[0],c=u[u.length-1]===o[o.length-1],s=[];for(n=o.length-1;n>=0;--n)s.push(t[r[o[n]][2]]);for(n=+a;n<u.length-c;++n)s.push(t[r[u[n]][2]]);return s},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],u=n[0],a=n[1],c=o[0],s=o[1],f=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>a!=s>a&&u<(c-e)*(a-r)/(s-r)+e&&(f=!f),c=e,s=r;return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],u=o[0],a=o[1],c=0;++r<i;)n=u,e=a,n-=u=(o=t[r])[0],e-=a=o[1],c+=Math.sqrt(n*n+e*e);return c},t.quadtree=qe,t.queue=Wo,t.randomUniform=o_,t.randomNormal=u_,t.randomLogNormal=a_,t.randomBates=s_,t.randomIrwinHall=c_,t.randomExponential=f_,t.request=l_,t.html=p_,t.json=d_,t.text=v_,t.xml=__,t.csv=g_,t.tsv=m_,t.scaleBand=Ko,t.scalePoint=function(){return tu(Ko().paddingInner(1))},t.scaleIdentity=fu,t.scaleLinear=su,t.scaleLog=yu,t.scaleOrdinal=Qo,t.scaleImplicit=M_,t.scalePow=mu,t.scaleSqrt=function(){return mu().exponent(.5)},t.scaleQuantile=xu,t.scaleQuantize=bu,t.scaleThreshold=wu,t.scaleTime=function(){return Na(oy,ry,j_,Y_,F_,D_,q_,z_,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)])},t.scaleUtc=function(){return Na(Ay,Sy,py,ly,sy,ay,q_,z_,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)])},t.schemeCategory10=$y,t.schemeCategory20b=Vy,t.schemeCategory20c=Wy,t.schemeCategory20=Zy,t.interpolateCubehelixDefault=Gy,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return Ky.h=360*t-100,Ky.s=1.5-1.5*n,Ky.l=.8-.9*n,Ky+""},t.interpolateWarm=Jy,t.interpolateCool=Qy,t.interpolateViridis=tg,t.interpolateMagma=ng,t.interpolateInferno=eg,t.interpolatePlasma=rg,t.scaleSequential=Ea,t.creator=Hs,t.local=m,t.matcher=Zs,t.mouse=Ks,t.namespace=js,t.namespaces=Bs,t.select=cf,t.selectAll=function(t){return"string"==typeof t?new pt([document.querySelectorAll(t)],[document.documentElement]):new pt([null==t?[]:t],af)},t.selection=dt,t.selector=tf,t.selectorAll=nf,t.style=B,t.touch=sf,t.touches=function(t,n){null==n&&(n=Js().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Qs(t,n[e]);return i},t.window=uf,t.customEvent=N,t.arc=function(){function t(){var t,s,f=+n.apply(this,arguments),l=+e.apply(this,arguments),h=o.apply(this,arguments)-dg,p=u.apply(this,arguments)-dg,d=og(p-h),v=p>h;if(c||(c=t=ve()),l<f&&(s=l,l=f,f=s),l>hg)if(d>vg-hg)c.moveTo(l*ag(h),l*fg(h)),c.arc(0,0,l,h,p,!v),f>hg&&(c.moveTo(f*ag(p),f*fg(p)),c.arc(0,0,f,p,h,v));else{var _,y,g=h,m=p,x=h,b=p,w=d,M=d,T=a.apply(this,arguments)/2,k=T>hg&&(i?+i.apply(this,arguments):lg(f*f+l*l)),N=sg(og(l-f)/2,+r.apply(this,arguments)),S=N,E=N;if(k>hg){var A=Ca(k/f*fg(T)),C=Ca(k/l*fg(T));(w-=2*A)>hg?(A*=v?1:-1,x+=A,b-=A):(w=0,x=b=(h+p)/2),(M-=2*C)>hg?(C*=v?1:-1,g+=C,m-=C):(M=0,g=m=(h+p)/2)}var z=l*ag(g),P=l*fg(g),R=f*ag(b),L=f*fg(b);if(N>hg){var q=l*ag(m),U=l*fg(m),D=f*ag(x),O=f*fg(x);if(d<pg){var F=w>hg?Ua(z,P,D,O,q,U,R,L):[R,L],I=z-F[0],Y=P-F[1],B=q-F[0],j=U-F[1],H=1/fg(Aa((I*B+Y*j)/(lg(I*I+Y*Y)*lg(B*B+j*j)))/2),X=lg(F[0]*F[0]+F[1]*F[1]);S=sg(N,(f-X)/(H-1)),E=sg(N,(l-X)/(H+1))}}M>hg?E>hg?(_=Da(D,O,z,P,l,E,v),y=Da(q,U,R,L,l,E,v),c.moveTo(_.cx+_.x01,_.cy+_.y01),E<N?c.arc(_.cx,_.cy,E,ug(_.y01,_.x01),ug(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,E,ug(_.y01,_.x01),ug(_.y11,_.x11),!v),c.arc(0,0,l,ug(_.cy+_.y11,_.cx+_.x11),ug(y.cy+y.y11,y.cx+y.x11),!v),c.arc(y.cx,y.cy,E,ug(y.y11,y.x11),ug(y.y01,y.x01),!v))):(c.moveTo(z,P),c.arc(0,0,l,g,m,!v)):c.moveTo(z,P),f>hg&&w>hg?S>hg?(_=Da(R,L,q,U,f,-S,v),y=Da(z,P,D,O,f,-S,v),c.lineTo(_.cx+_.x01,_.cy+_.y01),S<N?c.arc(_.cx,_.cy,S,ug(_.y01,_.x01),ug(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,S,ug(_.y01,_.x01),ug(_.y11,_.x11),!v),c.arc(0,0,f,ug(_.cy+_.y11,_.cx+_.x11),ug(y.cy+y.y11,y.cx+y.x11),v),c.arc(y.cx,y.cy,S,ug(y.y11,y.x11),ug(y.y01,y.x01),!v))):c.arc(0,0,f,b,x,v):c.lineTo(R,L)}else c.moveTo(0,0);if(c.closePath(),t)return c=null,t+""||null}var n=za,e=Pa,r=ig(0),i=null,o=Ra,u=La,a=qa,c=null;return t.centroid=function(){var t=(+n.apply(this,arguments)+ +e.apply(this,arguments))/2,r=(+o.apply(this,arguments)+ +u.apply(this,arguments))/2-pg/2;return[ag(r)*t,fg(r)*t]},t.innerRadius=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.outerRadius=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.cornerRadius=function(n){return arguments.length?(r="function"==typeof n?n:ig(+n),t):r},t.padRadius=function(n){return arguments.length?(i=null==n?null:"function"==typeof n?n:ig(+n),t):i},t.startAngle=function(n){return arguments.length?(o="function"==typeof n?n:ig(+n),t):o},t.endAngle=function(n){return arguments.length?(u="function"==typeof n?n:ig(+n),t):u},t.padAngle=function(n){return arguments.length?(a="function"==typeof n?n:ig(+n),t):a},t.context=function(n){return arguments.length?(c=null==n?null:n,t):c},t},t.area=gg,t.line=yg,t.pie=function(){function t(t){var a,c,s,f,l,h=t.length,p=0,d=new Array(h),v=new Array(h),_=+i.apply(this,arguments),y=Math.min(vg,Math.max(-vg,o.apply(this,arguments)-_)),g=Math.min(Math.abs(y)/h,u.apply(this,arguments)),m=g*(y<0?-1:1);for(a=0;a<h;++a)(l=v[d[a]=a]=+n(t[a],a,t))>0&&(p+=l);for(null!=e?d.sort(function(t,n){return e(v[t],v[n])}):null!=r&&d.sort(function(n,e){return r(t[n],t[e])}),a=0,s=p?(y-h*m)/p:0;a<h;++a,_=f)c=d[a],f=_+((l=v[c])>0?l*s:0)+m,v[c]={data:t[c],index:a,value:l,startAngle:_,endAngle:f,padAngle:g};return v}var n=xg,e=mg,r=null,i=ig(0),o=ig(vg),u=ig(0);return t.value=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.sortValues=function(n){return arguments.length?(e=n,r=null,t):e},t.sort=function(n){return arguments.length?(r=n,e=null,t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:ig(+n),t):o},t.padAngle=function(n){return arguments.length?(u="function"==typeof n?n:ig(+n),t):u},t},t.areaRadial=Mg,t.radialArea=Mg,t.lineRadial=wg,t.radialLine=wg,t.pointRadial=Tg,t.linkHorizontal=function(){return $a(Va)},t.linkVertical=function(){return $a(Wa)},t.linkRadial=function(){var t=$a(Za);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.symbol=function(){function t(){var t;if(r||(r=t=ve()),n.apply(this,arguments).draw(r,+e.apply(this,arguments)),t)return r=null,t+""||null}var n=ig(Ng),e=ig(64),r=null;return t.type=function(e){return arguments.length?(n="function"==typeof e?e:ig(e),t):n},t.size=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.context=function(n){return arguments.length?(r=null==n?null:n,t):r},t},t.symbols=jg,t.symbolCircle=Ng,t.symbolCross=Sg,t.symbolDiamond=Cg,t.symbolSquare=qg,t.symbolStar=Lg,t.symbolTriangle=Dg,t.symbolWye=Bg,t.curveBasisClosed=function(t){return new Qa(t)},t.curveBasisOpen=function(t){return new Ka(t)},t.curveBasis=function(t){return new Ja(t)},t.curveBundle=Xg,t.curveCardinalClosed=Vg,t.curveCardinalOpen=Wg,t.curveCardinal=$g,t.curveCatmullRomClosed=Gg,t.curveCatmullRomOpen=Jg,t.curveCatmullRom=Zg,t.curveLinearClosed=function(t){return new sc(t)},t.curveLinear=_g,t.curveMonotoneX=function(t){return new dc(t)},t.curveMonotoneY=function(t){return new vc(t)},t.curveNatural=function(t){return new yc(t)},t.curveStep=function(t){return new mc(t,.5)},t.curveStepAfter=function(t){return new mc(t,1)},t.curveStepBefore=function(t){return new mc(t,0)},t.stack=function(){function t(t){var o,u,a=n.apply(this,arguments),c=t.length,s=a.length,f=new Array(s);for(o=0;o<s;++o){for(var l,h=a[o],p=f[o]=new Array(c),d=0;d<c;++d)p[d]=l=[0,+i(t[d],h,d,t)],l.data=t[d];p.key=h}for(o=0,u=e(f);o<s;++o)f[u[o]].index=o;return r(f,u),f}var n=ig([]),e=Kg,r=Qg,i=xc;return t.keys=function(e){return arguments.length?(n="function"==typeof e?e:ig(kg.call(e)),t):n},t.value=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.order=function(n){return arguments.length?(e=null==n?Kg:"function"==typeof n?n:ig(kg.call(n)),t):e},t.offset=function(n){return arguments.length?(r=null==n?Qg:n,t):r},t},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,u=t[0].length;o<u;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}Qg(t,n)}},t.stackOffsetDiverging=function(t,n){if((a=t.length)>1)for(var e,r,i,o,u,a,c=0,s=t[n[0]].length;c<s;++c)for(o=u=0,e=0;e<a;++e)(i=(r=t[n[e]][c])[1]-r[0])>=0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=u,r[0]=u+=i):r[0]=o},t.stackOffsetNone=Qg,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var u=0,a=0;u<e;++u)a+=t[u][r][1]||0;i[r][1]+=i[r][0]=-a/2}Qg(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,u=1;u<r;++u){for(var a=0,c=0,s=0;a<i;++a){for(var f=t[n[a]],l=f[u][1]||0,h=(l-(f[u-1][1]||0))/2,p=0;p<a;++p){var d=t[n[p]];h+=(d[u][1]||0)-(d[u-1][1]||0)}c+=l,s+=h*l}e[u-1][1]+=e[u-1][0]=o,c&&(o-=s/c)}e[u-1][1]+=e[u-1][0]=o,Qg(t,n)}},t.stackOrderAscending=tm,t.stackOrderDescending=function(t){return tm(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(bc),o=Kg(t).sort(function(t,n){return i[n]-i[t]}),u=0,a=0,c=[],s=[];for(n=0;n<r;++n)e=o[n],u<a?(u+=i[e],c.push(e)):(a+=i[e],s.push(e));return s.reverse().concat(c)},t.stackOrderNone=Kg,t.stackOrderReverse=function(t){return Kg(t).reverse()},t.timeInterval=Mu,t.timeMillisecond=z_,t.timeMilliseconds=P_,t.utcMillisecond=z_,t.utcMilliseconds=P_,t.timeSecond=q_,t.timeSeconds=U_,t.utcSecond=q_,t.utcSeconds=U_,t.timeMinute=D_,t.timeMinutes=O_,t.timeHour=F_,t.timeHours=I_,t.timeDay=Y_,t.timeDays=B_,t.timeWeek=j_,t.timeWeeks=G_,t.timeSunday=j_,t.timeSundays=G_,t.timeMonday=H_,t.timeMondays=J_,t.timeTuesday=X_,t.timeTuesdays=Q_,t.timeWednesday=$_,t.timeWednesdays=K_,t.timeThursday=V_,t.timeThursdays=ty,t.timeFriday=W_,t.timeFridays=ny,t.timeSaturday=Z_,t.timeSaturdays=ey,t.timeMonth=ry,t.timeMonths=iy,t.timeYear=oy,t.timeYears=uy,t.utcMinute=ay,t.utcMinutes=cy,t.utcHour=sy,t.utcHours=fy,t.utcDay=ly,t.utcDays=hy,t.utcWeek=py,t.utcWeeks=xy,t.utcSunday=py,t.utcSundays=xy,t.utcMonday=dy,t.utcMondays=by,t.utcTuesday=vy,t.utcTuesdays=wy,t.utcWednesday=_y,t.utcWednesdays=My,t.utcThursday=yy,t.utcThursdays=Ty,t.utcFriday=gy,t.utcFridays=ky,t.utcSaturday=my,t.utcSaturdays=Ny,t.utcMonth=Sy,t.utcMonths=Ey,t.utcYear=Ay,t.utcYears=zy,t.timeFormatDefaultLocale=Ma,t.timeFormatLocale=Au,t.isoFormat=Uy,t.isoParse=Dy,t.now=ln,t.timer=dn,t.timerFlush=vn,t.timeout=Pl,t.interval=function(t,n,e){var r=new pn,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?ln():+e,r.restart(function o(u){u+=i,r.restart(o,i+=n,e),t(u)},n,e),r)},t.transition=Jn,t.active=function(t,n){var e,r,i=t.__transition;if(i){n=null==n?null:n+"";for(r in i)if((e=i[r]).state>Ul&&e.name===n)return new Gn([[t]],yh,n,+r)}return null},t.interrupt=jl,t.voronoi=function(){function t(t){return new Kc(t.map(function(r,i){var o=[Math.round(n(r,i,t)/sm)*sm,Math.round(e(r,i,t)/sm)*sm];return o.index=i,o.data=r,o}),r)}var n=wc,e=Mc,r=null;return t.polygons=function(n){return t(n).polygons()},t.links=function(n){return t(n).links()},t.triangles=function(n){return t(n).triangles()},t.x=function(e){return arguments.length?(n="function"==typeof e?e:nm(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:nm(+n),t):e},t.extent=function(n){return arguments.length?(r=null==n?null:[[+n[0][0],+n[0][1]],[+n[1][0],+n[1][1]]],t):r&&[[r[0][0],r[0][1]],[r[1][0],r[1][1]]]},t.size=function(n){return arguments.length?(r=null==n?null:[[0,0],[+n[0],+n[1]]],t):r&&[r[1][0]-r[0][0],r[1][1]-r[0][1]]},t},t.zoom=function(){function n(t){t.property("__zoom",us).on("wheel.zoom",s).on("mousedown.zoom",f).on("dblclick.zoom",l).filter(cs).on("touchstart.zoom",p).on("touchmove.zoom",d).on("touchend.zoom touchcancel.zoom",v).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(t,n){return(n=Math.max(b,Math.min(w,n)))===t.k?t:new ns(n,t.x,t.y)}function r(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ns(t.k,r,i)}function i(t,n){var e=t.invertX(n[0][0])-M,r=t.invertX(n[1][0])-T,i=t.invertY(n[0][1])-k,o=t.invertY(n[1][1])-S;return t.translate(r>e?(e+r)/2:Math.min(0,e)||Math.max(0,r),o>i?(i+o)/2:Math.min(0,i)||Math.max(0,o))}function o(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function u(t,n,e){t.on("start.zoom",function(){a(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){a(this,arguments).end()}).tween("zoom",function(){var t=this,r=arguments,i=a(t,r),u=m.apply(t,r),c=e||o(u),s=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),f=t.__zoom,l="function"==typeof n?n.apply(t,r):n,h=A(f.invert(c).concat(s/f.k),l.invert(c).concat(s/l.k));return function(t){if(1===t)t=l;else{var n=h(t),e=s/n[2];t=new ns(e,c[0]-n[0]*e,c[1]-n[1]*e)}i.zoom(null,t)}})}function a(t,n){for(var e,r=0,i=C.length;r<i;++r)if((e=C[r]).that===t)return e;return new c(t,n)}function c(t,n){this.that=t,this.args=n,this.index=-1,this.active=0,this.extent=m.apply(t,n)}function s(){if(g.apply(this,arguments)){var t=a(this,arguments),n=this.__zoom,o=Math.max(b,Math.min(w,n.k*Math.pow(2,x.apply(this,arguments)))),u=Ks(this);if(t.wheel)t.mouse[0][0]===u[0]&&t.mouse[0][1]===u[1]||(t.mouse[1]=n.invert(t.mouse[0]=u)),clearTimeout(t.wheel);else{if(n.k===o)return;t.mouse=[u,n.invert(u)],jl(this),t.start()}pm(),t.wheel=setTimeout(function(){t.wheel=null,t.end()},R),t.zoom("mouse",i(r(e(n,o),t.mouse[0],t.mouse[1]),t.extent))}}function f(){if(!y&&g.apply(this,arguments)){var n=a(this,arguments),e=cf(t.event.view).on("mousemove.zoom",function(){if(pm(),!n.moved){var e=t.event.clientX-u,o=t.event.clientY-c;n.moved=e*e+o*o>L}n.zoom("mouse",i(r(n.that.__zoom,n.mouse[0]=Ks(n.that),n.mouse[1]),n.extent))},!0).on("mouseup.zoom",function(){e.on("mousemove.zoom mouseup.zoom",null),_t(t.event.view,n.moved),pm(),n.end()},!0),o=Ks(this),u=t.event.clientX,c=t.event.clientY;lf(t.event.view),rs(),n.mouse=[o,this.__zoom.invert(o)],jl(this),n.start()}}function l(){if(g.apply(this,arguments)){var o=this.__zoom,a=Ks(this),c=o.invert(a),s=i(r(e(o,o.k*(t.event.shiftKey?.5:2)),a,c),m.apply(this,arguments));pm(),E>0?cf(this).transition().duration(E).call(u,s,a):cf(this).call(n.transform,s)}}function p(){if(g.apply(this,arguments)){var n,e,r,i,o=a(this,arguments),u=t.event.changedTouches,c=u.length;for(rs(),e=0;e<c;++e)r=u[e],i=[i=sf(this,u,r.identifier),this.__zoom.invert(i),r.identifier],o.touch0?o.touch1||(o.touch1=i):(o.touch0=i,n=!0);if(_&&(_=clearTimeout(_),!o.touch1))return o.end(),void((i=cf(this).on("dblclick.zoom"))&&i.apply(this,arguments));n&&(_=setTimeout(function(){_=null},P),jl(this),o.start())}}function d(){var n,o,u,c,s=a(this,arguments),f=t.event.changedTouches,l=f.length;for(pm(),_&&(_=clearTimeout(_)),n=0;n<l;++n)o=f[n],u=sf(this,f,o.identifier),s.touch0&&s.touch0[2]===o.identifier?s.touch0[0]=u:s.touch1&&s.touch1[2]===o.identifier&&(s.touch1[0]=u);if(o=s.that.__zoom,s.touch1){var h=s.touch0[0],p=s.touch0[1],d=s.touch1[0],v=s.touch1[1],y=(y=d[0]-h[0])*y+(y=d[1]-h[1])*y,g=(g=v[0]-p[0])*g+(g=v[1]-p[1])*g;o=e(o,Math.sqrt(y/g)),u=[(h[0]+d[0])/2,(h[1]+d[1])/2],c=[(p[0]+v[0])/2,(p[1]+v[1])/2]}else{if(!s.touch0)return;u=s.touch0[0],c=s.touch0[1]}s.zoom("touch",i(r(o,u,c),s.extent))}function v(){var n,e,r=a(this,arguments),i=t.event.changedTouches,o=i.length;for(rs(),y&&clearTimeout(y),y=setTimeout(function(){y=null},P),n=0;n<o;++n)e=i[n],r.touch0&&r.touch0[2]===e.identifier?delete r.touch0:r.touch1&&r.touch1[2]===e.identifier&&delete r.touch1;r.touch1&&!r.touch0&&(r.touch0=r.touch1,delete r.touch1),r.touch0?r.touch0[1]=this.__zoom.invert(r.touch0[0]):r.end()}var _,y,g=is,m=os,x=as,b=0,w=1/0,M=-w,T=w,k=M,S=T,E=250,A=_l,C=[],z=h("start","zoom","end"),P=500,R=150,L=0;return n.transform=function(t,n){var e=t.selection?t.selection():t;e.property("__zoom",us),t!==e?u(t,n):e.interrupt().each(function(){a(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},n.scaleBy=function(t,e){n.scaleTo(t,function(){return this.__zoom.k*("function"==typeof e?e.apply(this,arguments):e)})},n.scaleTo=function(t,u){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,a=o(t),c=n.invert(a);return i(r(e(n,"function"==typeof u?u.apply(this,arguments):u),a,c),t)})},n.translateBy=function(t,e,r){n.transform(t,function(){return i(this.__zoom.translate("function"==typeof e?e.apply(this,arguments):e,"function"==typeof r?r.apply(this,arguments):r),m.apply(this,arguments))})},n.translateTo=function(t,e,r){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,u=o(t);return i(hm.translate(u[0],u[1]).scale(n.k).translate("function"==typeof e?-e.apply(this,arguments):-e,"function"==typeof r?-r.apply(this,arguments):-r),t)})},c.prototype={start:function(){return 1==++this.active&&(this.index=C.push(this)-1,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(C.splice(this.index,1),this.index=-1,this.emit("end")),this},emit:function(t){N(new ts(n,t,this.that.__zoom),z.apply,z,[t,this.that,this.args])}},n.wheelDelta=function(t){return arguments.length?(x="function"==typeof t?t:lm(+t),n):x},n.filter=function(t){return arguments.length?(g="function"==typeof t?t:lm(!!t),n):g},n.extent=function(t){return arguments.length?(m="function"==typeof t?t:lm([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),n):m},n.scaleExtent=function(t){return arguments.length?(b=+t[0],w=+t[1],n):[b,w]},n.translateExtent=function(t){return arguments.length?(M=+t[0][0],T=+t[1][0],k=+t[0][1],S=+t[1][1],n):[[M,k],[T,S]]},n.duration=function(t){return arguments.length?(E=+t,n):E},n.interpolate=function(t){return arguments.length?(A=t,n):A},n.on=function(){var t=z.on.apply(z,arguments);return t===z?n:t},n.clickDistance=function(t){return arguments.length?(L=(t=+t)*t,n):Math.sqrt(L)},n},t.zoomTransform=es,t.zoomIdentity=hm,Object.defineProperty(t,"__esModule",{value:!0})});
\ No newline at end of file diff --git a/library/cpp/lwtrace/mon/static/js/filesaver.min.js b/library/cpp/lwtrace/mon/static/js/filesaver.min.js index b431d9bc5b..eaebca442a 100644 --- a/library/cpp/lwtrace/mon/static/js/filesaver.min.js +++ b/library/cpp/lwtrace/mon/static/js/filesaver.min.js @@ -1 +1 @@ -(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(b,c,d){var e=new XMLHttpRequest;e.open("GET",b),e.responseType="blob",e.onload=function(){a(e.response,c,d)},e.onerror=function(){console.error("could not download file")},e.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(a,b,d,e){if(e=e||open("","_blank"),e&&(e.document.title=e.document.body.innerText="downloading..."),"string"==typeof a)return c(a,b,d);var g="application/octet-stream"===a.type,h=/constructor/i.test(f.HTMLElement)||f.safari,i=/CriOS\/[\d]+/.test(navigator.userAgent);if((i||g&&h)&&"undefined"!=typeof FileReader){var j=new FileReader;j.onloadend=function(){var a=j.result;a=i?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),e?e.location.href=a:location=a,e=null},j.readAsDataURL(a)}else{var k=f.URL||f.webkitURL,l=k.createObjectURL(a);e?e.location=l:location.href=l,e=null,setTimeout(function(){k.revokeObjectURL(l)},4E4)}});f.saveAs=a.saveAs=a,"undefined"!=typeof module&&(module.exports=a)}); +(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(b,c,d){var e=new XMLHttpRequest;e.open("GET",b),e.responseType="blob",e.onload=function(){a(e.response,c,d)},e.onerror=function(){console.error("could not download file")},e.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(a,b,d,e){if(e=e||open("","_blank"),e&&(e.document.title=e.document.body.innerText="downloading..."),"string"==typeof a)return c(a,b,d);var g="application/octet-stream"===a.type,h=/constructor/i.test(f.HTMLElement)||f.safari,i=/CriOS\/[\d]+/.test(navigator.userAgent);if((i||g&&h)&&"undefined"!=typeof FileReader){var j=new FileReader;j.onloadend=function(){var a=j.result;a=i?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),e?e.location.href=a:location=a,e=null},j.readAsDataURL(a)}else{var k=f.URL||f.webkitURL,l=k.createObjectURL(a);e?e.location=l:location.href=l,e=null,setTimeout(function(){k.revokeObjectURL(l)},4E4)}});f.saveAs=a.saveAs=a,"undefined"!=typeof module&&(module.exports=a)}); diff --git a/library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js b/library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js index c17018b4f6..c8012fde62 100644 --- a/library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js +++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js @@ -1,196 +1,196 @@ -/* - * Copyright 2012, Serge V. Izmaylov - * Released under GPL Version 2 license. - */ - -(function ($) { - var options = { - series: { - extents: { - show: false, - lineWidth: 1, - barHeight: 17, - color: "rgba(192, 192, 192, 1.0)", - showConnections: true, - connectionColor: "rgba(0, 192, 128, 0.8)", - fill: true, - fillColor: "rgba(64, 192, 255, 0.5)", - showLabels: true, - rowHeight: 20, - rows: 7, - barVAlign: "top", - labelHAlign: "left" - } - } - }; - - function processRawData(plot, series, data, datapoints) { - if (!series.extents || !series.extents.show) - return; - - // Fool Flot with fake datapoints - datapoints.format = [ // Fake format - { x: true, number: true, required: true }, - { y: true, number: true, required: true }, - ]; - datapoints.points = []; // Empty data - datapoints.pointsize = 2; // Fake size - - // Check if we have extents data - if (series.extentdata == null) - return; - - // Process our real data - var row = 0; - for (i = 0; i < series.extentdata.length; i++) { - // Skip bad extents - if ((series.extentdata[i].start == null) || (series.extentdata[i].end == null)) - continue; - - if (series.extentdata[i].end < series.extentdata[i].start) { - var t = series.extentdata[i].end; - series.extentdata[i].end = series.extentdata[i].start; - series.extentdata[i].start = t; - } - if ((series.extentdata[i].labelHAlign != "left") && (series.extentdata[i].labelHAlign != "right")) - series.extentdata[i].labelHAlign = series.extents.labelHAlign; - if (series.extentdata[i].row == null) { - series.extentdata[i].row = row; - row = (row+1) % series.extents.rows; - } else { - row = (series.extentdata[i].row+1) % series.extents.rows; - } - if (series.extentdata[i].color == null) - series.extentdata[i].color = series.extents.color; - if (series.extentdata[i].fillColor == null) - series.extentdata[i].fillColor = series.extents.fillColor; - } - - }; - - function drawSingleExtent(ctx, width, height, xfrom, xto, series, extent) { - if (xfrom < 0) xfrom = 0; - if (xto > width) xto = width; - var bw = xto-xfrom; - - var yfrom; - if (series.extents.barVAlign == "top") - yfrom = 4 + series.extents.rowHeight*extent.row; - else - yfrom = height - 4 - series.extents.rowHeight*(extent.row) - series.extents.barHeight; - - if (series.extents.fill) { - ctx.fillStyle = extent.fillColor; - ctx.fillRect(xfrom, yfrom, bw, series.extents.barHeight); - } - - ctx.strokeStyle = extent.color; - ctx.strokeRect(xfrom, yfrom, bw, series.extents.barHeight); - } - - function drawSingleConnection(ctx, width, height, xfrom, xto, rfrom, rto, series) { - if (xfrom < 0) xfrom = 0; - if (xto > width) xto = width; - - var yfrom, yto; - if (series.extents.barVAlign == "top") { - yfrom = 4 + Math.round(series.extents.rowHeight*rfrom) + Math.round(series.extents.barHeight*0.5); - yto = 4 + Math.round(series.extents.rowHeight*rto) + Math.round(series.extents.barHeight*0.5); - } else { - yfrom = height - 4 - Math.round(series.extents.rowHeight*rfrom) - Math.round(series.extents.barHeight*0.5); - yto = height - 4 - Math.round(series.extents.rowHeight*rto) - Math.round(series.extents.barHeight*0.5); - } - - ctx.beginPath(); - ctx.moveTo(xfrom, yfrom); - ctx.lineTo(xfrom+10, yfrom); - ctx.lineTo(xto-10, yto); - ctx.lineTo(xto, yto); - ctx.lineTo(xto-6, yto-3); - ctx.lineTo(xto-6, yto+3); - ctx.lineTo(xto, yto); - ctx.stroke(); - } - - function addExtentLabel(placeholder, plotOffset, width, xfrom, xto, series, extent) { - var styles = []; - if (series.extents.barVAlign == "top") - styles.push("top:"+Math.round((plotOffset.top+series.extents.rowHeight*extent.row+4))+"px"); - else - styles.push("bottom:"+Math.round((plotOffset.bottom+series.extents.rowHeight*extent.row+4))+"px"); - if (extent.labelHAlign == "left") - styles.push("left:"+Math.round((plotOffset.left+xfrom+3))+"px"); - else - styles.push("right:"+Math.round((plotOffset.right+(width-xto)+3))+"px"); - styles.push(""); - - placeholder.append('<div '+((extent.id !=null)?('id="'+extent.id+'" '):'')+'class="extentLabel" style="font-size:smaller;position:absolute;'+(styles.join(';'))+'">'+extent.label+'</div>'); - } - - function drawSeries(plot, ctx, series) { - if (!series.extents || !series.extents.show || !series.extentdata) - return; - - var placeholder = plot.getPlaceholder(); - placeholder.find(".extentLabel").remove(); - - ctx.save(); - - var plotOffset = plot.getPlotOffset(); - var axes = plot.getAxes(); - var yf = axes.yaxis.p2c(axes.yaxis.min); - var yt = axes.yaxis.p2c(axes.yaxis.max); - var ytop = (yf>yt)?yt:yf; - var ybot = (yf>yt)?yf:yt; - var width = plot.width(); - var height = plot.height(); - - ctx.translate(plotOffset.left, plotOffset.top); - ctx.lineJoin = "round"; - - for (var i = 0; i < series.extentdata.length; i++) { - var xfrom, xto; - if ((series.extentdata[i].start == null) || (series.extentdata[i].end == null)) - continue; - if ((series.extentdata[i].start < axes.xaxis.max) && (series.extentdata[i].end > axes.xaxis.min)) { - xfrom = axes.xaxis.p2c((series.extentdata[i].start<axes.xaxis.min)?axes.xaxis.min:series.extentdata[i].start); - xto = axes.xaxis.p2c((series.extentdata[i].end>axes.xaxis.max)?axes.xaxis.max:series.extentdata[i].end); - drawSingleExtent(ctx, width, height, xfrom, xto, series, series.extentdata[i]); - - if (series.extents.showConnections && (series.extentdata[i].start > axes.xaxis.min) && (series.extentdata[i].start < axes.xaxis.max)) - if ((series.extentdata[i].depends != null) && (series.extentdata[i].depends.length != null) && (series.extentdata[i].depends.length > 0)) - for (var j=0; j<series.extentdata[i].depends.length; j++) { - var k = series.extentdata[i].depends[j]; - if ((k < 0) || (k >= series.extentdata.length)) - continue; - if ((series.extentdata[k].start == null) || (series.extentdata[k].end == null)) - continue; - var cxto = xfrom; - var cxfrom = series.extentdata[k].end; - if (cxfrom < axes.xaxis.min) cxfrom = axes.xaxis.min; - if (cxfrom > axes.xaxis.max) cxfrom = axes.xaxis.max; - cxfrom = axes.xaxis.p2c(cxfrom); - ctx.strokeStyle = series.extents.connectionColor; - drawSingleConnection(ctx, width, height, cxfrom, cxto, series.extentdata[k].row, series.extentdata[i].row, series); - } - - if (series.extents.showLabels && (series.extentdata[i].label != null)) - addExtentLabel(placeholder, plotOffset, width, xfrom, xto, series, series.extentdata[i]); - } - } - - ctx.restore(); - }; - - function init(plot) { - plot.hooks.processRawData.push(processRawData); - plot.hooks.drawSeries.push(drawSeries); - }; - - $.plot.plugins.push({ - init: init, - name: "extents", - options: options, - version: "0.3" - }); -})(jQuery); +/* + * Copyright 2012, Serge V. Izmaylov + * Released under GPL Version 2 license. + */ + +(function ($) { + var options = { + series: { + extents: { + show: false, + lineWidth: 1, + barHeight: 17, + color: "rgba(192, 192, 192, 1.0)", + showConnections: true, + connectionColor: "rgba(0, 192, 128, 0.8)", + fill: true, + fillColor: "rgba(64, 192, 255, 0.5)", + showLabels: true, + rowHeight: 20, + rows: 7, + barVAlign: "top", + labelHAlign: "left" + } + } + }; + + function processRawData(plot, series, data, datapoints) { + if (!series.extents || !series.extents.show) + return; + + // Fool Flot with fake datapoints + datapoints.format = [ // Fake format + { x: true, number: true, required: true }, + { y: true, number: true, required: true }, + ]; + datapoints.points = []; // Empty data + datapoints.pointsize = 2; // Fake size + + // Check if we have extents data + if (series.extentdata == null) + return; + + // Process our real data + var row = 0; + for (i = 0; i < series.extentdata.length; i++) { + // Skip bad extents + if ((series.extentdata[i].start == null) || (series.extentdata[i].end == null)) + continue; + + if (series.extentdata[i].end < series.extentdata[i].start) { + var t = series.extentdata[i].end; + series.extentdata[i].end = series.extentdata[i].start; + series.extentdata[i].start = t; + } + if ((series.extentdata[i].labelHAlign != "left") && (series.extentdata[i].labelHAlign != "right")) + series.extentdata[i].labelHAlign = series.extents.labelHAlign; + if (series.extentdata[i].row == null) { + series.extentdata[i].row = row; + row = (row+1) % series.extents.rows; + } else { + row = (series.extentdata[i].row+1) % series.extents.rows; + } + if (series.extentdata[i].color == null) + series.extentdata[i].color = series.extents.color; + if (series.extentdata[i].fillColor == null) + series.extentdata[i].fillColor = series.extents.fillColor; + } + + }; + + function drawSingleExtent(ctx, width, height, xfrom, xto, series, extent) { + if (xfrom < 0) xfrom = 0; + if (xto > width) xto = width; + var bw = xto-xfrom; + + var yfrom; + if (series.extents.barVAlign == "top") + yfrom = 4 + series.extents.rowHeight*extent.row; + else + yfrom = height - 4 - series.extents.rowHeight*(extent.row) - series.extents.barHeight; + + if (series.extents.fill) { + ctx.fillStyle = extent.fillColor; + ctx.fillRect(xfrom, yfrom, bw, series.extents.barHeight); + } + + ctx.strokeStyle = extent.color; + ctx.strokeRect(xfrom, yfrom, bw, series.extents.barHeight); + } + + function drawSingleConnection(ctx, width, height, xfrom, xto, rfrom, rto, series) { + if (xfrom < 0) xfrom = 0; + if (xto > width) xto = width; + + var yfrom, yto; + if (series.extents.barVAlign == "top") { + yfrom = 4 + Math.round(series.extents.rowHeight*rfrom) + Math.round(series.extents.barHeight*0.5); + yto = 4 + Math.round(series.extents.rowHeight*rto) + Math.round(series.extents.barHeight*0.5); + } else { + yfrom = height - 4 - Math.round(series.extents.rowHeight*rfrom) - Math.round(series.extents.barHeight*0.5); + yto = height - 4 - Math.round(series.extents.rowHeight*rto) - Math.round(series.extents.barHeight*0.5); + } + + ctx.beginPath(); + ctx.moveTo(xfrom, yfrom); + ctx.lineTo(xfrom+10, yfrom); + ctx.lineTo(xto-10, yto); + ctx.lineTo(xto, yto); + ctx.lineTo(xto-6, yto-3); + ctx.lineTo(xto-6, yto+3); + ctx.lineTo(xto, yto); + ctx.stroke(); + } + + function addExtentLabel(placeholder, plotOffset, width, xfrom, xto, series, extent) { + var styles = []; + if (series.extents.barVAlign == "top") + styles.push("top:"+Math.round((plotOffset.top+series.extents.rowHeight*extent.row+4))+"px"); + else + styles.push("bottom:"+Math.round((plotOffset.bottom+series.extents.rowHeight*extent.row+4))+"px"); + if (extent.labelHAlign == "left") + styles.push("left:"+Math.round((plotOffset.left+xfrom+3))+"px"); + else + styles.push("right:"+Math.round((plotOffset.right+(width-xto)+3))+"px"); + styles.push(""); + + placeholder.append('<div '+((extent.id !=null)?('id="'+extent.id+'" '):'')+'class="extentLabel" style="font-size:smaller;position:absolute;'+(styles.join(';'))+'">'+extent.label+'</div>'); + } + + function drawSeries(plot, ctx, series) { + if (!series.extents || !series.extents.show || !series.extentdata) + return; + + var placeholder = plot.getPlaceholder(); + placeholder.find(".extentLabel").remove(); + + ctx.save(); + + var plotOffset = plot.getPlotOffset(); + var axes = plot.getAxes(); + var yf = axes.yaxis.p2c(axes.yaxis.min); + var yt = axes.yaxis.p2c(axes.yaxis.max); + var ytop = (yf>yt)?yt:yf; + var ybot = (yf>yt)?yf:yt; + var width = plot.width(); + var height = plot.height(); + + ctx.translate(plotOffset.left, plotOffset.top); + ctx.lineJoin = "round"; + + for (var i = 0; i < series.extentdata.length; i++) { + var xfrom, xto; + if ((series.extentdata[i].start == null) || (series.extentdata[i].end == null)) + continue; + if ((series.extentdata[i].start < axes.xaxis.max) && (series.extentdata[i].end > axes.xaxis.min)) { + xfrom = axes.xaxis.p2c((series.extentdata[i].start<axes.xaxis.min)?axes.xaxis.min:series.extentdata[i].start); + xto = axes.xaxis.p2c((series.extentdata[i].end>axes.xaxis.max)?axes.xaxis.max:series.extentdata[i].end); + drawSingleExtent(ctx, width, height, xfrom, xto, series, series.extentdata[i]); + + if (series.extents.showConnections && (series.extentdata[i].start > axes.xaxis.min) && (series.extentdata[i].start < axes.xaxis.max)) + if ((series.extentdata[i].depends != null) && (series.extentdata[i].depends.length != null) && (series.extentdata[i].depends.length > 0)) + for (var j=0; j<series.extentdata[i].depends.length; j++) { + var k = series.extentdata[i].depends[j]; + if ((k < 0) || (k >= series.extentdata.length)) + continue; + if ((series.extentdata[k].start == null) || (series.extentdata[k].end == null)) + continue; + var cxto = xfrom; + var cxfrom = series.extentdata[k].end; + if (cxfrom < axes.xaxis.min) cxfrom = axes.xaxis.min; + if (cxfrom > axes.xaxis.max) cxfrom = axes.xaxis.max; + cxfrom = axes.xaxis.p2c(cxfrom); + ctx.strokeStyle = series.extents.connectionColor; + drawSingleConnection(ctx, width, height, cxfrom, cxto, series.extentdata[k].row, series.extentdata[i].row, series); + } + + if (series.extents.showLabels && (series.extentdata[i].label != null)) + addExtentLabel(placeholder, plotOffset, width, xfrom, xto, series, series.extentdata[i]); + } + } + + ctx.restore(); + }; + + function init(plot) { + plot.hooks.processRawData.push(processRawData); + plot.hooks.drawSeries.push(drawSeries); + }; + + $.plot.plugins.push({ + init: init, + name: "extents", + options: options, + version: "0.3" + }); +})(jQuery); diff --git a/library/cpp/lwtrace/mon/static/js/jquery.flot.min.js b/library/cpp/lwtrace/mon/static/js/jquery.flot.min.js index 81083f1819..c39799c804 100644 --- a/library/cpp/lwtrace/mon/static/js/jquery.flot.min.js +++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.min.js @@ -1,8 +1,8 @@ -/* Javascript plotting library for jQuery, version 0.8.3. - -Copyright (c) 2007-2014 IOLA and Ole Laursen. -Licensed under the MIT license. - -*/ -(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function($){var hasOwnProperty=Object.prototype.hasOwnProperty;if(!$.fn.detach){$.fn.detach=function(){return this.each(function(){if(this.parentNode){this.parentNode.removeChild(this)}})}}function Canvas(cls,container){var element=container.children("."+cls)[0];if(element==null){element=document.createElement("canvas");element.className=cls;$(element).css({direction:"ltr",position:"absolute",left:0,top:0}).appendTo(container);if(!element.getContext){if(window.G_vmlCanvasManager){element=window.G_vmlCanvasManager.initElement(element)}else{throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.")}}}this.element=element;var context=this.context=element.getContext("2d");var devicePixelRatio=window.devicePixelRatio||1,backingStoreRatio=context.webkitBackingStorePixelRatio||context.mozBackingStorePixelRatio||context.msBackingStorePixelRatio||context.oBackingStorePixelRatio||context.backingStorePixelRatio||1;this.pixelRatio=devicePixelRatio/backingStoreRatio;this.resize(container.width(),container.height());this.textContainer=null;this.text={};this._textCache={}}Canvas.prototype.resize=function(width,height){if(width<=0||height<=0){throw new Error("Invalid dimensions for plot, width = "+width+", height = "+height)}var element=this.element,context=this.context,pixelRatio=this.pixelRatio;if(this.width!=width){element.width=width*pixelRatio;element.style.width=width+"px";this.width=width}if(this.height!=height){element.height=height*pixelRatio;element.style.height=height+"px";this.height=height}context.restore();context.save();context.scale(pixelRatio,pixelRatio)};Canvas.prototype.clear=function(){this.context.clearRect(0,0,this.width,this.height)};Canvas.prototype.render=function(){var cache=this._textCache;for(var layerKey in cache){if(hasOwnProperty.call(cache,layerKey)){var layer=this.getTextLayer(layerKey),layerCache=cache[layerKey];layer.hide();for(var styleKey in layerCache){if(hasOwnProperty.call(layerCache,styleKey)){var styleCache=layerCache[styleKey];for(var key in styleCache){if(hasOwnProperty.call(styleCache,key)){var positions=styleCache[key].positions;for(var i=0,position;position=positions[i];i++){if(position.active){if(!position.rendered){layer.append(position.element);position.rendered=true}}else{positions.splice(i--,1);if(position.rendered){position.element.detach()}}}if(positions.length==0){delete styleCache[key]}}}}}layer.show()}}};Canvas.prototype.getTextLayer=function(classes){var layer=this.text[classes];if(layer==null){if(this.textContainer==null){this.textContainer=$("<div class='flot-text'></div>").css({position:"absolute",top:0,left:0,bottom:0,right:0,"font-size":"smaller",color:"#545454"}).insertAfter(this.element)}layer=this.text[classes]=$("<div></div>").addClass(classes).css({position:"absolute",top:0,left:0,bottom:0,right:0}).appendTo(this.textContainer)}return layer};Canvas.prototype.getTextInfo=function(layer,text,font,angle,width){var textStyle,layerCache,styleCache,info;text=""+text;if(typeof font==="object"){textStyle=font.style+" "+font.variant+" "+font.weight+" "+font.size+"px/"+font.lineHeight+"px "+font.family}else{textStyle=font}layerCache=this._textCache[layer];if(layerCache==null){layerCache=this._textCache[layer]={}}styleCache=layerCache[textStyle];if(styleCache==null){styleCache=layerCache[textStyle]={}}info=styleCache[text];if(info==null){var element=$("<div></div>").html(text).css({position:"absolute","max-width":width,top:-9999}).appendTo(this.getTextLayer(layer));if(typeof font==="object"){element.css({font:textStyle,color:font.color})}else if(typeof font==="string"){element.addClass(font)}info=styleCache[text]={width:element.outerWidth(true),height:element.outerHeight(true),element:element,positions:[]};element.detach()}return info};Canvas.prototype.addText=function(layer,x,y,text,font,angle,width,halign,valign){var info=this.getTextInfo(layer,text,font,angle,width),positions=info.positions;if(halign=="center"){x-=info.width/2}else if(halign=="right"){x-=info.width}if(valign=="middle"){y-=info.height/2}else if(valign=="bottom"){y-=info.height}for(var i=0,position;position=positions[i];i++){if(position.x==x&&position.y==y){position.active=true;return}}position={active:true,rendered:false,element:positions.length?info.element.clone():info.element,x:x,y:y};positions.push(position);position.element.css({top:Math.round(y),left:Math.round(x),"text-align":halign})};Canvas.prototype.removeText=function(layer,x,y,text,font,angle){if(text==null){var layerCache=this._textCache[layer];if(layerCache!=null){for(var styleKey in layerCache){if(hasOwnProperty.call(layerCache,styleKey)){var styleCache=layerCache[styleKey];for(var key in styleCache){if(hasOwnProperty.call(styleCache,key)){var positions=styleCache[key].positions;for(var i=0,position;position=positions[i];i++){position.active=false}}}}}}}else{var positions=this.getTextInfo(layer,text,font,angle).positions;for(var i=0,position;position=positions[i];i++){if(position.x==x&&position.y==y){position.active=false}}}};function Plot(placeholder,data_,options_,plugins){var series=[],options={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:.85,sorted:null},xaxis:{show:null,position:"bottom",mode:null,font:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null},yaxis:{autoscaleMargin:.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false,zero:true},shadowSize:3,highlightColor:null},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,margin:0,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},interaction:{redrawOverlayInterval:1e3/60},hooks:{}},surface=null,overlay=null,eventHolder=null,ctx=null,octx=null,xaxes=[],yaxes=[],plotOffset={left:0,right:0,top:0,bottom:0},plotWidth=0,plotHeight=0,hooks={processOptions:[],processRawData:[],processDatapoints:[],processOffset:[],drawBackground:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},plot=this;plot.setData=setData;plot.setupGrid=setupGrid;plot.draw=draw;plot.getPlaceholder=function(){return placeholder};plot.getCanvas=function(){return surface.element};plot.getPlotOffset=function(){return plotOffset};plot.width=function(){return plotWidth};plot.height=function(){return plotHeight};plot.offset=function(){var o=eventHolder.offset();o.left+=plotOffset.left;o.top+=plotOffset.top;return o};plot.getData=function(){return series};plot.getAxes=function(){var res={},i;$.each(xaxes.concat(yaxes),function(_,axis){if(axis)res[axis.direction+(axis.n!=1?axis.n:"")+"axis"]=axis});return res};plot.getXAxes=function(){return xaxes};plot.getYAxes=function(){return yaxes};plot.c2p=canvasToAxisCoords;plot.p2c=axisToCanvasCoords;plot.getOptions=function(){return options};plot.highlight=highlight;plot.unhighlight=unhighlight;plot.triggerRedrawOverlay=triggerRedrawOverlay;plot.pointOffset=function(point){return{left:parseInt(xaxes[axisNumber(point,"x")-1].p2c(+point.x)+plotOffset.left,10),top:parseInt(yaxes[axisNumber(point,"y")-1].p2c(+point.y)+plotOffset.top,10)}};plot.shutdown=shutdown;plot.destroy=function(){shutdown();placeholder.removeData("plot").empty();series=[];options=null;surface=null;overlay=null;eventHolder=null;ctx=null;octx=null;xaxes=[];yaxes=[];hooks=null;highlights=[];plot=null};plot.resize=function(){var width=placeholder.width(),height=placeholder.height();surface.resize(width,height);overlay.resize(width,height)};plot.hooks=hooks;initPlugins(plot);parseOptions(options_);setupCanvases();setData(data_);setupGrid();draw();bindEvents();function executeHooks(hook,args){args=[plot].concat(args);for(var i=0;i<hook.length;++i)hook[i].apply(this,args)}function initPlugins(){var classes={Canvas:Canvas};for(var i=0;i<plugins.length;++i){var p=plugins[i];p.init(plot,classes);if(p.options)$.extend(true,options,p.options)}}function parseOptions(opts){$.extend(true,options,opts);if(opts&&opts.colors){options.colors=opts.colors}if(options.xaxis.color==null)options.xaxis.color=$.color.parse(options.grid.color).scale("a",.22).toString();if(options.yaxis.color==null)options.yaxis.color=$.color.parse(options.grid.color).scale("a",.22).toString();if(options.xaxis.tickColor==null)options.xaxis.tickColor=options.grid.tickColor||options.xaxis.color;if(options.yaxis.tickColor==null)options.yaxis.tickColor=options.grid.tickColor||options.yaxis.color;if(options.grid.borderColor==null)options.grid.borderColor=options.grid.color;if(options.grid.tickColor==null)options.grid.tickColor=$.color.parse(options.grid.color).scale("a",.22).toString();var i,axisOptions,axisCount,fontSize=placeholder.css("font-size"),fontSizeDefault=fontSize?+fontSize.replace("px",""):13,fontDefaults={style:placeholder.css("font-style"),size:Math.round(.8*fontSizeDefault),variant:placeholder.css("font-variant"),weight:placeholder.css("font-weight"),family:placeholder.css("font-family")};axisCount=options.xaxes.length||1;for(i=0;i<axisCount;++i){axisOptions=options.xaxes[i];if(axisOptions&&!axisOptions.tickColor){axisOptions.tickColor=axisOptions.color}axisOptions=$.extend(true,{},options.xaxis,axisOptions);options.xaxes[i]=axisOptions;if(axisOptions.font){axisOptions.font=$.extend({},fontDefaults,axisOptions.font);if(!axisOptions.font.color){axisOptions.font.color=axisOptions.color}if(!axisOptions.font.lineHeight){axisOptions.font.lineHeight=Math.round(axisOptions.font.size*1.15)}}}axisCount=options.yaxes.length||1;for(i=0;i<axisCount;++i){axisOptions=options.yaxes[i];if(axisOptions&&!axisOptions.tickColor){axisOptions.tickColor=axisOptions.color}axisOptions=$.extend(true,{},options.yaxis,axisOptions);options.yaxes[i]=axisOptions;if(axisOptions.font){axisOptions.font=$.extend({},fontDefaults,axisOptions.font);if(!axisOptions.font.color){axisOptions.font.color=axisOptions.color}if(!axisOptions.font.lineHeight){axisOptions.font.lineHeight=Math.round(axisOptions.font.size*1.15)}}}if(options.xaxis.noTicks&&options.xaxis.ticks==null)options.xaxis.ticks=options.xaxis.noTicks;if(options.yaxis.noTicks&&options.yaxis.ticks==null)options.yaxis.ticks=options.yaxis.noTicks;if(options.x2axis){options.xaxes[1]=$.extend(true,{},options.xaxis,options.x2axis);options.xaxes[1].position="top";if(options.x2axis.min==null){options.xaxes[1].min=null}if(options.x2axis.max==null){options.xaxes[1].max=null}}if(options.y2axis){options.yaxes[1]=$.extend(true,{},options.yaxis,options.y2axis);options.yaxes[1].position="right";if(options.y2axis.min==null){options.yaxes[1].min=null}if(options.y2axis.max==null){options.yaxes[1].max=null}}if(options.grid.coloredAreas)options.grid.markings=options.grid.coloredAreas;if(options.grid.coloredAreasColor)options.grid.markingsColor=options.grid.coloredAreasColor;if(options.lines)$.extend(true,options.series.lines,options.lines);if(options.points)$.extend(true,options.series.points,options.points);if(options.bars)$.extend(true,options.series.bars,options.bars);if(options.shadowSize!=null)options.series.shadowSize=options.shadowSize;if(options.highlightColor!=null)options.series.highlightColor=options.highlightColor;for(i=0;i<options.xaxes.length;++i)getOrCreateAxis(xaxes,i+1).options=options.xaxes[i];for(i=0;i<options.yaxes.length;++i)getOrCreateAxis(yaxes,i+1).options=options.yaxes[i];for(var n in hooks)if(options.hooks[n]&&options.hooks[n].length)hooks[n]=hooks[n].concat(options.hooks[n]);executeHooks(hooks.processOptions,[options])}function setData(d){series=parseData(d);fillInSeriesOptions();processData()}function parseData(d){var res=[];for(var i=0;i<d.length;++i){var s=$.extend(true,{},options.series);if(d[i].data!=null){s.data=d[i].data;delete d[i].data;$.extend(true,s,d[i]);d[i].data=s.data}else s.data=d[i];res.push(s)}return res}function axisNumber(obj,coord){var a=obj[coord+"axis"];if(typeof a=="object")a=a.n;if(typeof a!="number")a=1;return a}function allAxes(){return $.grep(xaxes.concat(yaxes),function(a){return a})}function canvasToAxisCoords(pos){var res={},i,axis;for(i=0;i<xaxes.length;++i){axis=xaxes[i];if(axis&&axis.used)res["x"+axis.n]=axis.c2p(pos.left)}for(i=0;i<yaxes.length;++i){axis=yaxes[i];if(axis&&axis.used)res["y"+axis.n]=axis.c2p(pos.top)}if(res.x1!==undefined)res.x=res.x1;if(res.y1!==undefined)res.y=res.y1;return res}function axisToCanvasCoords(pos){var res={},i,axis,key;for(i=0;i<xaxes.length;++i){axis=xaxes[i];if(axis&&axis.used){key="x"+axis.n;if(pos[key]==null&&axis.n==1)key="x";if(pos[key]!=null){res.left=axis.p2c(pos[key]);break}}}for(i=0;i<yaxes.length;++i){axis=yaxes[i];if(axis&&axis.used){key="y"+axis.n;if(pos[key]==null&&axis.n==1)key="y";if(pos[key]!=null){res.top=axis.p2c(pos[key]);break}}}return res}function getOrCreateAxis(axes,number){if(!axes[number-1])axes[number-1]={n:number,direction:axes==xaxes?"x":"y",options:$.extend(true,{},axes==xaxes?options.xaxis:options.yaxis)};return axes[number-1]}function fillInSeriesOptions(){var neededColors=series.length,maxIndex=-1,i;for(i=0;i<series.length;++i){var sc=series[i].color;if(sc!=null){neededColors--;if(typeof sc=="number"&&sc>maxIndex){maxIndex=sc}}}if(neededColors<=maxIndex){neededColors=maxIndex+1}var c,colors=[],colorPool=options.colors,colorPoolSize=colorPool.length,variation=0;for(i=0;i<neededColors;i++){c=$.color.parse(colorPool[i%colorPoolSize]||"#666");if(i%colorPoolSize==0&&i){if(variation>=0){if(variation<.5){variation=-variation-.2}else variation=0}else variation=-variation}colors[i]=c.scale("rgb",1+variation)}var colori=0,s;for(i=0;i<series.length;++i){s=series[i];if(s.color==null){s.color=colors[colori].toString();++colori}else if(typeof s.color=="number")s.color=colors[s.color].toString();if(s.lines.show==null){var v,show=true;for(v in s)if(s[v]&&s[v].show){show=false;break}if(show)s.lines.show=true}if(s.lines.zero==null){s.lines.zero=!!s.lines.fill}s.xaxis=getOrCreateAxis(xaxes,axisNumber(s,"x"));s.yaxis=getOrCreateAxis(yaxes,axisNumber(s,"y"))}}function processData(){var topSentry=Number.POSITIVE_INFINITY,bottomSentry=Number.NEGATIVE_INFINITY,fakeInfinity=Number.MAX_VALUE,i,j,k,m,length,s,points,ps,x,y,axis,val,f,p,data,format;function updateAxis(axis,min,max){if(min<axis.datamin&&min!=-fakeInfinity)axis.datamin=min;if(max>axis.datamax&&max!=fakeInfinity)axis.datamax=max}$.each(allAxes(),function(_,axis){axis.datamin=topSentry;axis.datamax=bottomSentry;axis.used=false});for(i=0;i<series.length;++i){s=series[i];s.datapoints={points:[]};executeHooks(hooks.processRawData,[s,s.data,s.datapoints])}for(i=0;i<series.length;++i){s=series[i];data=s.data;format=s.datapoints.format;if(!format){format=[];format.push({x:true,number:true,required:true});format.push({y:true,number:true,required:true});if(s.bars.show||s.lines.show&&s.lines.fill){var autoscale=!!(s.bars.show&&s.bars.zero||s.lines.show&&s.lines.zero);format.push({y:true,number:true,required:false,defaultValue:0,autoscale:autoscale});if(s.bars.horizontal){delete format[format.length-1].y;format[format.length-1].x=true}}s.datapoints.format=format}if(s.datapoints.pointsize!=null)continue;s.datapoints.pointsize=format.length;ps=s.datapoints.pointsize;points=s.datapoints.points;var insertSteps=s.lines.show&&s.lines.steps;s.xaxis.used=s.yaxis.used=true;for(j=k=0;j<data.length;++j,k+=ps){p=data[j];var nullify=p==null;if(!nullify){for(m=0;m<ps;++m){val=p[m];f=format[m];if(f){if(f.number&&val!=null){val=+val;if(isNaN(val))val=null;else if(val==Infinity)val=fakeInfinity;else if(val==-Infinity)val=-fakeInfinity}if(val==null){if(f.required)nullify=true;if(f.defaultValue!=null)val=f.defaultValue}}points[k+m]=val}}if(nullify){for(m=0;m<ps;++m){val=points[k+m];if(val!=null){f=format[m];if(f.autoscale!==false){if(f.x){updateAxis(s.xaxis,val,val)}if(f.y){updateAxis(s.yaxis,val,val)}}}points[k+m]=null}}else{if(insertSteps&&k>0&&points[k-ps]!=null&&points[k-ps]!=points[k]&&points[k-ps+1]!=points[k+1]){for(m=0;m<ps;++m)points[k+ps+m]=points[k+m];points[k+1]=points[k-ps+1];k+=ps}}}}for(i=0;i<series.length;++i){s=series[i];executeHooks(hooks.processDatapoints,[s,s.datapoints])}for(i=0;i<series.length;++i){s=series[i];points=s.datapoints.points;ps=s.datapoints.pointsize;format=s.datapoints.format;var xmin=topSentry,ymin=topSentry,xmax=bottomSentry,ymax=bottomSentry;for(j=0;j<points.length;j+=ps){if(points[j]==null)continue;for(m=0;m<ps;++m){val=points[j+m];f=format[m];if(!f||f.autoscale===false||val==fakeInfinity||val==-fakeInfinity)continue;if(f.x){if(val<xmin)xmin=val;if(val>xmax)xmax=val}if(f.y){if(val<ymin)ymin=val;if(val>ymax)ymax=val}}}if(s.bars.show){var delta;switch(s.bars.align){case"left":delta=0;break;case"right":delta=-s.bars.barWidth;break;default:delta=-s.bars.barWidth/2}if(s.bars.horizontal){ymin+=delta;ymax+=delta+s.bars.barWidth}else{xmin+=delta;xmax+=delta+s.bars.barWidth}}updateAxis(s.xaxis,xmin,xmax);updateAxis(s.yaxis,ymin,ymax)}$.each(allAxes(),function(_,axis){if(axis.datamin==topSentry)axis.datamin=null;if(axis.datamax==bottomSentry)axis.datamax=null})}function setupCanvases(){placeholder.css("padding",0).children().filter(function(){return!$(this).hasClass("flot-overlay")&&!$(this).hasClass("flot-base")}).remove();if(placeholder.css("position")=="static")placeholder.css("position","relative");surface=new Canvas("flot-base",placeholder);overlay=new Canvas("flot-overlay",placeholder);ctx=surface.context;octx=overlay.context;eventHolder=$(overlay.element).unbind();var existing=placeholder.data("plot");if(existing){existing.shutdown();overlay.clear()}placeholder.data("plot",plot)}function bindEvents(){if(options.grid.hoverable){eventHolder.mousemove(onMouseMove);eventHolder.bind("mouseleave",onMouseLeave)}if(options.grid.clickable)eventHolder.click(onClick);executeHooks(hooks.bindEvents,[eventHolder])}function shutdown(){if(redrawTimeout)clearTimeout(redrawTimeout);eventHolder.unbind("mousemove",onMouseMove);eventHolder.unbind("mouseleave",onMouseLeave);eventHolder.unbind("click",onClick);executeHooks(hooks.shutdown,[eventHolder])}function setTransformationHelpers(axis){function identity(x){return x}var s,m,t=axis.options.transform||identity,it=axis.options.inverseTransform;if(axis.direction=="x"){s=axis.scale=plotWidth/Math.abs(t(axis.max)-t(axis.min));m=Math.min(t(axis.max),t(axis.min))}else{s=axis.scale=plotHeight/Math.abs(t(axis.max)-t(axis.min));s=-s;m=Math.max(t(axis.max),t(axis.min))}if(t==identity)axis.p2c=function(p){return(p-m)*s};else axis.p2c=function(p){return(t(p)-m)*s};if(!it)axis.c2p=function(c){return m+c/s};else axis.c2p=function(c){return it(m+c/s)}}function measureTickLabels(axis){var opts=axis.options,ticks=axis.ticks||[],labelWidth=opts.labelWidth||0,labelHeight=opts.labelHeight||0,maxWidth=labelWidth||(axis.direction=="x"?Math.floor(surface.width/(ticks.length||1)):null),legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=opts.font||"flot-tick-label tickLabel";for(var i=0;i<ticks.length;++i){var t=ticks[i];if(!t.label)continue;var info=surface.getTextInfo(layer,t.label,font,null,maxWidth);labelWidth=Math.max(labelWidth,info.width);labelHeight=Math.max(labelHeight,info.height)}axis.labelWidth=opts.labelWidth||labelWidth;axis.labelHeight=opts.labelHeight||labelHeight}function allocateAxisBoxFirstPhase(axis){var lw=axis.labelWidth,lh=axis.labelHeight,pos=axis.options.position,isXAxis=axis.direction==="x",tickLength=axis.options.tickLength,axisMargin=options.grid.axisMargin,padding=options.grid.labelMargin,innermost=true,outermost=true,first=true,found=false;$.each(isXAxis?xaxes:yaxes,function(i,a){if(a&&(a.show||a.reserveSpace)){if(a===axis){found=true}else if(a.options.position===pos){if(found){outermost=false}else{innermost=false}}if(!found){first=false}}});if(outermost){axisMargin=0}if(tickLength==null){tickLength=first?"full":5}if(!isNaN(+tickLength))padding+=+tickLength;if(isXAxis){lh+=padding;if(pos=="bottom"){plotOffset.bottom+=lh+axisMargin;axis.box={top:surface.height-plotOffset.bottom,height:lh}}else{axis.box={top:plotOffset.top+axisMargin,height:lh};plotOffset.top+=lh+axisMargin}}else{lw+=padding;if(pos=="left"){axis.box={left:plotOffset.left+axisMargin,width:lw};plotOffset.left+=lw+axisMargin}else{plotOffset.right+=lw+axisMargin;axis.box={left:surface.width-plotOffset.right,width:lw}}}axis.position=pos;axis.tickLength=tickLength;axis.box.padding=padding;axis.innermost=innermost}function allocateAxisBoxSecondPhase(axis){if(axis.direction=="x"){axis.box.left=plotOffset.left-axis.labelWidth/2;axis.box.width=surface.width-plotOffset.left-plotOffset.right+axis.labelWidth}else{axis.box.top=plotOffset.top-axis.labelHeight/2;axis.box.height=surface.height-plotOffset.bottom-plotOffset.top+axis.labelHeight}}function adjustLayoutForThingsStickingOut(){var minMargin=options.grid.minBorderMargin,axis,i;if(minMargin==null){minMargin=0;for(i=0;i<series.length;++i)minMargin=Math.max(minMargin,2*(series[i].points.radius+series[i].points.lineWidth/2))}var margins={left:minMargin,right:minMargin,top:minMargin,bottom:minMargin};$.each(allAxes(),function(_,axis){if(axis.reserveSpace&&axis.ticks&&axis.ticks.length){if(axis.direction==="x"){margins.left=Math.max(margins.left,axis.labelWidth/2);margins.right=Math.max(margins.right,axis.labelWidth/2)}else{margins.bottom=Math.max(margins.bottom,axis.labelHeight/2);margins.top=Math.max(margins.top,axis.labelHeight/2)}}});plotOffset.left=Math.ceil(Math.max(margins.left,plotOffset.left));plotOffset.right=Math.ceil(Math.max(margins.right,plotOffset.right));plotOffset.top=Math.ceil(Math.max(margins.top,plotOffset.top));plotOffset.bottom=Math.ceil(Math.max(margins.bottom,plotOffset.bottom))}function setupGrid(){var i,axes=allAxes(),showGrid=options.grid.show;for(var a in plotOffset){var margin=options.grid.margin||0;plotOffset[a]=typeof margin=="number"?margin:margin[a]||0}executeHooks(hooks.processOffset,[plotOffset]);for(var a in plotOffset){if(typeof options.grid.borderWidth=="object"){plotOffset[a]+=showGrid?options.grid.borderWidth[a]:0}else{plotOffset[a]+=showGrid?options.grid.borderWidth:0}}$.each(axes,function(_,axis){var axisOpts=axis.options;axis.show=axisOpts.show==null?axis.used:axisOpts.show;axis.reserveSpace=axisOpts.reserveSpace==null?axis.show:axisOpts.reserveSpace;setRange(axis)});if(showGrid){var allocatedAxes=$.grep(axes,function(axis){return axis.show||axis.reserveSpace});$.each(allocatedAxes,function(_,axis){setupTickGeneration(axis);setTicks(axis);snapRangeToTicks(axis,axis.ticks);measureTickLabels(axis)});for(i=allocatedAxes.length-1;i>=0;--i)allocateAxisBoxFirstPhase(allocatedAxes[i]);adjustLayoutForThingsStickingOut();$.each(allocatedAxes,function(_,axis){allocateAxisBoxSecondPhase(axis)})}plotWidth=surface.width-plotOffset.left-plotOffset.right;plotHeight=surface.height-plotOffset.bottom-plotOffset.top;$.each(axes,function(_,axis){setTransformationHelpers(axis)});if(showGrid){drawAxisLabels()}insertLegend()}function setRange(axis){var opts=axis.options,min=+(opts.min!=null?opts.min:axis.datamin),max=+(opts.max!=null?opts.max:axis.datamax),delta=max-min;if(delta==0){var widen=max==0?1:.01;if(opts.min==null)min-=widen;if(opts.max==null||opts.min!=null)max+=widen}else{var margin=opts.autoscaleMargin;if(margin!=null){if(opts.min==null){min-=delta*margin;if(min<0&&axis.datamin!=null&&axis.datamin>=0)min=0}if(opts.max==null){max+=delta*margin;if(max>0&&axis.datamax!=null&&axis.datamax<=0)max=0}}}axis.min=min;axis.max=max}function setupTickGeneration(axis){var opts=axis.options;var noTicks;if(typeof opts.ticks=="number"&&opts.ticks>0)noTicks=opts.ticks;else noTicks=.3*Math.sqrt(axis.direction=="x"?surface.width:surface.height);var delta=(axis.max-axis.min)/noTicks,dec=-Math.floor(Math.log(delta)/Math.LN10),maxDec=opts.tickDecimals;if(maxDec!=null&&dec>maxDec){dec=maxDec}var magn=Math.pow(10,-dec),norm=delta/magn,size;if(norm<1.5){size=1}else if(norm<3){size=2;if(norm>2.25&&(maxDec==null||dec+1<=maxDec)){size=2.5;++dec}}else if(norm<7.5){size=5}else{size=10}size*=magn;if(opts.minTickSize!=null&&size<opts.minTickSize){size=opts.minTickSize}axis.delta=delta;axis.tickDecimals=Math.max(0,maxDec!=null?maxDec:dec);axis.tickSize=opts.tickSize||size;if(opts.mode=="time"&&!axis.tickGenerator){throw new Error("Time mode requires the flot.time plugin.")}if(!axis.tickGenerator){axis.tickGenerator=function(axis){var ticks=[],start=floorInBase(axis.min,axis.tickSize),i=0,v=Number.NaN,prev;do{prev=v;v=start+i*axis.tickSize;ticks.push(v);++i}while(v<axis.max&&v!=prev);return ticks};axis.tickFormatter=function(value,axis){var factor=axis.tickDecimals?Math.pow(10,axis.tickDecimals):1;var formatted=""+Math.round(value*factor)/factor;if(axis.tickDecimals!=null){var decimal=formatted.indexOf(".");var precision=decimal==-1?0:formatted.length-decimal-1;if(precision<axis.tickDecimals){return(precision?formatted:formatted+".")+(""+factor).substr(1,axis.tickDecimals-precision)}}return formatted}}if($.isFunction(opts.tickFormatter))axis.tickFormatter=function(v,axis){return""+opts.tickFormatter(v,axis)};if(opts.alignTicksWithAxis!=null){var otherAxis=(axis.direction=="x"?xaxes:yaxes)[opts.alignTicksWithAxis-1];if(otherAxis&&otherAxis.used&&otherAxis!=axis){var niceTicks=axis.tickGenerator(axis);if(niceTicks.length>0){if(opts.min==null)axis.min=Math.min(axis.min,niceTicks[0]);if(opts.max==null&&niceTicks.length>1)axis.max=Math.max(axis.max,niceTicks[niceTicks.length-1])}axis.tickGenerator=function(axis){var ticks=[],v,i;for(i=0;i<otherAxis.ticks.length;++i){v=(otherAxis.ticks[i].v-otherAxis.min)/(otherAxis.max-otherAxis.min);v=axis.min+v*(axis.max-axis.min);ticks.push(v)}return ticks};if(!axis.mode&&opts.tickDecimals==null){var extraDec=Math.max(0,-Math.floor(Math.log(axis.delta)/Math.LN10)+1),ts=axis.tickGenerator(axis);if(!(ts.length>1&&/\..*0$/.test((ts[1]-ts[0]).toFixed(extraDec))))axis.tickDecimals=extraDec}}}}function setTicks(axis){var oticks=axis.options.ticks,ticks=[];if(oticks==null||typeof oticks=="number"&&oticks>0)ticks=axis.tickGenerator(axis);else if(oticks){if($.isFunction(oticks))ticks=oticks(axis);else ticks=oticks}var i,v;axis.ticks=[];for(i=0;i<ticks.length;++i){var label=null;var t=ticks[i];if(typeof t=="object"){v=+t[0];if(t.length>1)label=t[1]}else v=+t;if(label==null)label=axis.tickFormatter(v,axis);if(!isNaN(v))axis.ticks.push({v:v,label:label})}}function snapRangeToTicks(axis,ticks){if(axis.options.autoscaleMargin&&ticks.length>0){if(axis.options.min==null)axis.min=Math.min(axis.min,ticks[0].v);if(axis.options.max==null&&ticks.length>1)axis.max=Math.max(axis.max,ticks[ticks.length-1].v)}}function draw(){surface.clear();executeHooks(hooks.drawBackground,[ctx]);var grid=options.grid;if(grid.show&&grid.backgroundColor)drawBackground();if(grid.show&&!grid.aboveData){drawGrid()}for(var i=0;i<series.length;++i){executeHooks(hooks.drawSeries,[ctx,series[i]]);drawSeries(series[i])}executeHooks(hooks.draw,[ctx]);if(grid.show&&grid.aboveData){drawGrid()}surface.render();triggerRedrawOverlay()}function extractRange(ranges,coord){var axis,from,to,key,axes=allAxes();for(var i=0;i<axes.length;++i){axis=axes[i];if(axis.direction==coord){key=coord+axis.n+"axis";if(!ranges[key]&&axis.n==1)key=coord+"axis";if(ranges[key]){from=ranges[key].from;to=ranges[key].to;break}}}if(!ranges[key]){axis=coord=="x"?xaxes[0]:yaxes[0];from=ranges[coord+"1"];to=ranges[coord+"2"]}if(from!=null&&to!=null&&from>to){var tmp=from;from=to;to=tmp}return{from:from,to:to,axis:axis}}function drawBackground(){ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.fillStyle=getColorOrGradient(options.grid.backgroundColor,plotHeight,0,"rgba(255, 255, 255, 0)");ctx.fillRect(0,0,plotWidth,plotHeight);ctx.restore()}function drawGrid(){var i,axes,bw,bc;ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var markings=options.grid.markings;if(markings){if($.isFunction(markings)){axes=plot.getAxes();axes.xmin=axes.xaxis.min;axes.xmax=axes.xaxis.max;axes.ymin=axes.yaxis.min;axes.ymax=axes.yaxis.max;markings=markings(axes)}for(i=0;i<markings.length;++i){var m=markings[i],xrange=extractRange(m,"x"),yrange=extractRange(m,"y");if(xrange.from==null)xrange.from=xrange.axis.min;if(xrange.to==null)xrange.to=xrange.axis.max; -if(yrange.from==null)yrange.from=yrange.axis.min;if(yrange.to==null)yrange.to=yrange.axis.max;if(xrange.to<xrange.axis.min||xrange.from>xrange.axis.max||yrange.to<yrange.axis.min||yrange.from>yrange.axis.max)continue;xrange.from=Math.max(xrange.from,xrange.axis.min);xrange.to=Math.min(xrange.to,xrange.axis.max);yrange.from=Math.max(yrange.from,yrange.axis.min);yrange.to=Math.min(yrange.to,yrange.axis.max);var xequal=xrange.from===xrange.to,yequal=yrange.from===yrange.to;if(xequal&&yequal){continue}xrange.from=Math.floor(xrange.axis.p2c(xrange.from));xrange.to=Math.floor(xrange.axis.p2c(xrange.to));yrange.from=Math.floor(yrange.axis.p2c(yrange.from));yrange.to=Math.floor(yrange.axis.p2c(yrange.to));if(xequal||yequal){var lineWidth=m.lineWidth||options.grid.markingsLineWidth,subPixel=lineWidth%2?.5:0;ctx.beginPath();ctx.strokeStyle=m.color||options.grid.markingsColor;ctx.lineWidth=lineWidth;if(xequal){ctx.moveTo(xrange.to+subPixel,yrange.from);ctx.lineTo(xrange.to+subPixel,yrange.to)}else{ctx.moveTo(xrange.from,yrange.to+subPixel);ctx.lineTo(xrange.to,yrange.to+subPixel)}ctx.stroke()}else{ctx.fillStyle=m.color||options.grid.markingsColor;ctx.fillRect(xrange.from,yrange.to,xrange.to-xrange.from,yrange.from-yrange.to)}}}axes=allAxes();bw=options.grid.borderWidth;for(var j=0;j<axes.length;++j){var axis=axes[j],box=axis.box,t=axis.tickLength,x,y,xoff,yoff;if(!axis.show||axis.ticks.length==0)continue;ctx.lineWidth=1;if(axis.direction=="x"){x=0;if(t=="full")y=axis.position=="top"?0:plotHeight;else y=box.top-plotOffset.top+(axis.position=="top"?box.height:0)}else{y=0;if(t=="full")x=axis.position=="left"?0:plotWidth;else x=box.left-plotOffset.left+(axis.position=="left"?box.width:0)}if(!axis.innermost){ctx.strokeStyle=axis.options.color;ctx.beginPath();xoff=yoff=0;if(axis.direction=="x")xoff=plotWidth+1;else yoff=plotHeight+1;if(ctx.lineWidth==1){if(axis.direction=="x"){y=Math.floor(y)+.5}else{x=Math.floor(x)+.5}}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff);ctx.stroke()}ctx.strokeStyle=axis.options.tickColor;ctx.beginPath();for(i=0;i<axis.ticks.length;++i){var v=axis.ticks[i].v;xoff=yoff=0;if(isNaN(v)||v<axis.min||v>axis.max||t=="full"&&(typeof bw=="object"&&bw[axis.position]>0||bw>0)&&(v==axis.min||v==axis.max))continue;if(axis.direction=="x"){x=axis.p2c(v);yoff=t=="full"?-plotHeight:t;if(axis.position=="top")yoff=-yoff}else{y=axis.p2c(v);xoff=t=="full"?-plotWidth:t;if(axis.position=="left")xoff=-xoff}if(ctx.lineWidth==1){if(axis.direction=="x")x=Math.floor(x)+.5;else y=Math.floor(y)+.5}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff)}ctx.stroke()}if(bw){bc=options.grid.borderColor;if(typeof bw=="object"||typeof bc=="object"){if(typeof bw!=="object"){bw={top:bw,right:bw,bottom:bw,left:bw}}if(typeof bc!=="object"){bc={top:bc,right:bc,bottom:bc,left:bc}}if(bw.top>0){ctx.strokeStyle=bc.top;ctx.lineWidth=bw.top;ctx.beginPath();ctx.moveTo(0-bw.left,0-bw.top/2);ctx.lineTo(plotWidth,0-bw.top/2);ctx.stroke()}if(bw.right>0){ctx.strokeStyle=bc.right;ctx.lineWidth=bw.right;ctx.beginPath();ctx.moveTo(plotWidth+bw.right/2,0-bw.top);ctx.lineTo(plotWidth+bw.right/2,plotHeight);ctx.stroke()}if(bw.bottom>0){ctx.strokeStyle=bc.bottom;ctx.lineWidth=bw.bottom;ctx.beginPath();ctx.moveTo(plotWidth+bw.right,plotHeight+bw.bottom/2);ctx.lineTo(0,plotHeight+bw.bottom/2);ctx.stroke()}if(bw.left>0){ctx.strokeStyle=bc.left;ctx.lineWidth=bw.left;ctx.beginPath();ctx.moveTo(0-bw.left/2,plotHeight+bw.bottom);ctx.lineTo(0-bw.left/2,0);ctx.stroke()}}else{ctx.lineWidth=bw;ctx.strokeStyle=options.grid.borderColor;ctx.strokeRect(-bw/2,-bw/2,plotWidth+bw,plotHeight+bw)}}ctx.restore()}function drawAxisLabels(){$.each(allAxes(),function(_,axis){var box=axis.box,legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=axis.options.font||"flot-tick-label tickLabel",tick,x,y,halign,valign;surface.removeText(layer);if(!axis.show||axis.ticks.length==0)return;for(var i=0;i<axis.ticks.length;++i){tick=axis.ticks[i];if(!tick.label||tick.v<axis.min||tick.v>axis.max)continue;if(axis.direction=="x"){halign="center";x=plotOffset.left+axis.p2c(tick.v);if(axis.position=="bottom"){y=box.top+box.padding}else{y=box.top+box.height-box.padding;valign="bottom"}}else{valign="middle";y=plotOffset.top+axis.p2c(tick.v);if(axis.position=="left"){x=box.left+box.width-box.padding;halign="right"}else{x=box.left+box.padding}}surface.addText(layer,x,y,tick.label,font,null,null,halign,valign)}})}function drawSeries(series){if(series.lines.show)drawSeriesLines(series);if(series.bars.show)drawSeriesBars(series);if(series.points.show)drawSeriesPoints(series)}function drawSeriesLines(series){function plotLine(datapoints,xoffset,yoffset,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,prevx=null,prevy=null;ctx.beginPath();for(var i=ps;i<points.length;i+=ps){var x1=points[i-ps],y1=points[i-ps+1],x2=points[i],y2=points[i+1];if(x1==null||x2==null)continue;if(y1<=y2&&y1<axisy.min){if(y2<axisy.min)continue;x1=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.min}else if(y2<=y1&&y2<axisy.min){if(y1<axisy.min)continue;x2=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.min}if(y1>=y2&&y1>axisy.max){if(y2>axisy.max)continue;x1=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.max}else if(y2>=y1&&y2>axisy.max){if(y1>axisy.max)continue;x2=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.max}if(x1<=x2&&x1<axisx.min){if(x2<axisx.min)continue;y1=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.min}else if(x2<=x1&&x2<axisx.min){if(x1<axisx.min)continue;y2=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.min}if(x1>=x2&&x1>axisx.max){if(x2>axisx.max)continue;y1=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.max}else if(x2>=x1&&x2>axisx.max){if(x1>axisx.max)continue;y2=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.max}if(x1!=prevx||y1!=prevy)ctx.moveTo(axisx.p2c(x1)+xoffset,axisy.p2c(y1)+yoffset);prevx=x2;prevy=y2;ctx.lineTo(axisx.p2c(x2)+xoffset,axisy.p2c(y2)+yoffset)}ctx.stroke()}function plotLineArea(datapoints,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,bottom=Math.min(Math.max(0,axisy.min),axisy.max),i=0,top,areaOpen=false,ypos=1,segmentStart=0,segmentEnd=0;while(true){if(ps>0&&i>points.length+ps)break;i+=ps;var x1=points[i-ps],y1=points[i-ps+ypos],x2=points[i],y2=points[i+ypos];if(areaOpen){if(ps>0&&x1!=null&&x2==null){segmentEnd=i;ps=-ps;ypos=2;continue}if(ps<0&&i==segmentStart+ps){ctx.fill();areaOpen=false;ps=-ps;ypos=1;i=segmentStart=segmentEnd+ps;continue}}if(x1==null||x2==null)continue;if(x1<=x2&&x1<axisx.min){if(x2<axisx.min)continue;y1=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.min}else if(x2<=x1&&x2<axisx.min){if(x1<axisx.min)continue;y2=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.min}if(x1>=x2&&x1>axisx.max){if(x2>axisx.max)continue;y1=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.max}else if(x2>=x1&&x2>axisx.max){if(x1>axisx.max)continue;y2=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.max}if(!areaOpen){ctx.beginPath();ctx.moveTo(axisx.p2c(x1),axisy.p2c(bottom));areaOpen=true}if(y1>=axisy.max&&y2>=axisy.max){ctx.lineTo(axisx.p2c(x1),axisy.p2c(axisy.max));ctx.lineTo(axisx.p2c(x2),axisy.p2c(axisy.max));continue}else if(y1<=axisy.min&&y2<=axisy.min){ctx.lineTo(axisx.p2c(x1),axisy.p2c(axisy.min));ctx.lineTo(axisx.p2c(x2),axisy.p2c(axisy.min));continue}var x1old=x1,x2old=x2;if(y1<=y2&&y1<axisy.min&&y2>=axisy.min){x1=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.min}else if(y2<=y1&&y2<axisy.min&&y1>=axisy.min){x2=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.min}if(y1>=y2&&y1>axisy.max&&y2<=axisy.max){x1=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.max}else if(y2>=y1&&y2>axisy.max&&y1<=axisy.max){x2=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.max}if(x1!=x1old){ctx.lineTo(axisx.p2c(x1old),axisy.p2c(y1))}ctx.lineTo(axisx.p2c(x1),axisy.p2c(y1));ctx.lineTo(axisx.p2c(x2),axisy.p2c(y2));if(x2!=x2old){ctx.lineTo(axisx.p2c(x2),axisy.p2c(y2));ctx.lineTo(axisx.p2c(x2old),axisy.p2c(y2))}}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.lineJoin="round";var lw=series.lines.lineWidth,sw=series.shadowSize;if(lw>0&&sw>0){ctx.lineWidth=sw;ctx.strokeStyle="rgba(0,0,0,0.1)";var angle=Math.PI/18;plotLine(series.datapoints,Math.sin(angle)*(lw/2+sw/2),Math.cos(angle)*(lw/2+sw/2),series.xaxis,series.yaxis);ctx.lineWidth=sw/2;plotLine(series.datapoints,Math.sin(angle)*(lw/2+sw/4),Math.cos(angle)*(lw/2+sw/4),series.xaxis,series.yaxis)}ctx.lineWidth=lw;ctx.strokeStyle=series.color;var fillStyle=getFillStyle(series.lines,series.color,0,plotHeight);if(fillStyle){ctx.fillStyle=fillStyle;plotLineArea(series.datapoints,series.xaxis,series.yaxis)}if(lw>0)plotLine(series.datapoints,0,0,series.xaxis,series.yaxis);ctx.restore()}function drawSeriesPoints(series){function plotPoints(datapoints,radius,fillStyle,offset,shadow,axisx,axisy,symbol){var points=datapoints.points,ps=datapoints.pointsize;for(var i=0;i<points.length;i+=ps){var x=points[i],y=points[i+1];if(x==null||x<axisx.min||x>axisx.max||y<axisy.min||y>axisy.max)continue;ctx.beginPath();x=axisx.p2c(x);y=axisy.p2c(y)+offset;if(symbol=="circle")ctx.arc(x,y,radius,0,shadow?Math.PI:Math.PI*2,false);else symbol(ctx,x,y,radius,shadow);ctx.closePath();if(fillStyle){ctx.fillStyle=fillStyle;ctx.fill()}ctx.stroke()}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var lw=series.points.lineWidth,sw=series.shadowSize,radius=series.points.radius,symbol=series.points.symbol;if(lw==0)lw=1e-4;if(lw>0&&sw>0){var w=sw/2;ctx.lineWidth=w;ctx.strokeStyle="rgba(0,0,0,0.1)";plotPoints(series.datapoints,radius,null,w+w/2,true,series.xaxis,series.yaxis,symbol);ctx.strokeStyle="rgba(0,0,0,0.2)";plotPoints(series.datapoints,radius,null,w/2,true,series.xaxis,series.yaxis,symbol)}ctx.lineWidth=lw;ctx.strokeStyle=series.color;plotPoints(series.datapoints,radius,getFillStyle(series.points,series.color),0,false,series.xaxis,series.yaxis,symbol);ctx.restore()}function drawBar(x,y,b,barLeft,barRight,fillStyleCallback,axisx,axisy,c,horizontal,lineWidth){var left,right,bottom,top,drawLeft,drawRight,drawTop,drawBottom,tmp;if(horizontal){drawBottom=drawRight=drawTop=true;drawLeft=false;left=b;right=x;top=y+barLeft;bottom=y+barRight;if(right<left){tmp=right;right=left;left=tmp;drawLeft=true;drawRight=false}}else{drawLeft=drawRight=drawTop=true;drawBottom=false;left=x+barLeft;right=x+barRight;bottom=b;top=y;if(top<bottom){tmp=top;top=bottom;bottom=tmp;drawBottom=true;drawTop=false}}if(right<axisx.min||left>axisx.max||top<axisy.min||bottom>axisy.max)return;if(left<axisx.min){left=axisx.min;drawLeft=false}if(right>axisx.max){right=axisx.max;drawRight=false}if(bottom<axisy.min){bottom=axisy.min;drawBottom=false}if(top>axisy.max){top=axisy.max;drawTop=false}left=axisx.p2c(left);bottom=axisy.p2c(bottom);right=axisx.p2c(right);top=axisy.p2c(top);if(fillStyleCallback){c.fillStyle=fillStyleCallback(bottom,top);c.fillRect(left,top,right-left,bottom-top)}if(lineWidth>0&&(drawLeft||drawRight||drawTop||drawBottom)){c.beginPath();c.moveTo(left,bottom);if(drawLeft)c.lineTo(left,top);else c.moveTo(left,top);if(drawTop)c.lineTo(right,top);else c.moveTo(right,top);if(drawRight)c.lineTo(right,bottom);else c.moveTo(right,bottom);if(drawBottom)c.lineTo(left,bottom);else c.moveTo(left,bottom);c.stroke()}}function drawSeriesBars(series){function plotBars(datapoints,barLeft,barRight,fillStyleCallback,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize;for(var i=0;i<points.length;i+=ps){if(points[i]==null)continue;drawBar(points[i],points[i+1],points[i+2],barLeft,barRight,fillStyleCallback,axisx,axisy,ctx,series.bars.horizontal,series.bars.lineWidth)}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.lineWidth=series.bars.lineWidth;ctx.strokeStyle=series.color;var barLeft;switch(series.bars.align){case"left":barLeft=0;break;case"right":barLeft=-series.bars.barWidth;break;default:barLeft=-series.bars.barWidth/2}var fillStyleCallback=series.bars.fill?function(bottom,top){return getFillStyle(series.bars,series.color,bottom,top)}:null;plotBars(series.datapoints,barLeft,barLeft+series.bars.barWidth,fillStyleCallback,series.xaxis,series.yaxis);ctx.restore()}function getFillStyle(filloptions,seriesColor,bottom,top){var fill=filloptions.fill;if(!fill)return null;if(filloptions.fillColor)return getColorOrGradient(filloptions.fillColor,bottom,top,seriesColor);var c=$.color.parse(seriesColor);c.a=typeof fill=="number"?fill:.4;c.normalize();return c.toString()}function insertLegend(){if(options.legend.container!=null){$(options.legend.container).html("")}else{placeholder.find(".legend").remove()}if(!options.legend.show){return}var fragments=[],entries=[],rowStarted=false,lf=options.legend.labelFormatter,s,label;for(var i=0;i<series.length;++i){s=series[i];if(s.label){label=lf?lf(s.label,s):s.label;if(label){entries.push({label:label,color:s.color})}}}if(options.legend.sorted){if($.isFunction(options.legend.sorted)){entries.sort(options.legend.sorted)}else if(options.legend.sorted=="reverse"){entries.reverse()}else{var ascending=options.legend.sorted!="descending";entries.sort(function(a,b){return a.label==b.label?0:a.label<b.label!=ascending?1:-1})}}for(var i=0;i<entries.length;++i){var entry=entries[i];if(i%options.legend.noColumns==0){if(rowStarted)fragments.push("</tr>");fragments.push("<tr>");rowStarted=true}fragments.push('<td class="legendColorBox"><div style="border:1px solid '+options.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+entry.color+';overflow:hidden"></div></div></td>'+'<td class="legendLabel">'+entry.label+"</td>")}if(rowStarted)fragments.push("</tr>");if(fragments.length==0)return;var table='<table style="font-size:smaller;color:'+options.grid.color+'">'+fragments.join("")+"</table>";if(options.legend.container!=null)$(options.legend.container).html(table);else{var pos="",p=options.legend.position,m=options.legend.margin;if(m[0]==null)m=[m,m];if(p.charAt(0)=="n")pos+="top:"+(m[1]+plotOffset.top)+"px;";else if(p.charAt(0)=="s")pos+="bottom:"+(m[1]+plotOffset.bottom)+"px;";if(p.charAt(1)=="e")pos+="right:"+(m[0]+plotOffset.right)+"px;";else if(p.charAt(1)=="w")pos+="left:"+(m[0]+plotOffset.left)+"px;";var legend=$('<div class="legend">'+table.replace('style="','style="position:absolute;'+pos+";")+"</div>").appendTo(placeholder);if(options.legend.backgroundOpacity!=0){var c=options.legend.backgroundColor;if(c==null){c=options.grid.backgroundColor;if(c&&typeof c=="string")c=$.color.parse(c);else c=$.color.extract(legend,"background-color");c.a=1;c=c.toString()}var div=legend.children();$('<div style="position:absolute;width:'+div.width()+"px;height:"+div.height()+"px;"+pos+"background-color:"+c+';"> </div>').prependTo(legend).css("opacity",options.legend.backgroundOpacity)}}}var highlights=[],redrawTimeout=null;function findNearbyItem(mouseX,mouseY,seriesFilter){var maxDistance=options.grid.mouseActiveRadius,smallestDistance=maxDistance*maxDistance+1,item=null,foundPoint=false,i,j,ps;for(i=series.length-1;i>=0;--i){if(!seriesFilter(series[i]))continue;var s=series[i],axisx=s.xaxis,axisy=s.yaxis,points=s.datapoints.points,mx=axisx.c2p(mouseX),my=axisy.c2p(mouseY),maxx=maxDistance/axisx.scale,maxy=maxDistance/axisy.scale;ps=s.datapoints.pointsize;if(axisx.options.inverseTransform)maxx=Number.MAX_VALUE;if(axisy.options.inverseTransform)maxy=Number.MAX_VALUE;if(s.lines.show||s.points.show){for(j=0;j<points.length;j+=ps){var x=points[j],y=points[j+1];if(x==null)continue;if(x-mx>maxx||x-mx<-maxx||y-my>maxy||y-my<-maxy)continue;var dx=Math.abs(axisx.p2c(x)-mouseX),dy=Math.abs(axisy.p2c(y)-mouseY),dist=dx*dx+dy*dy;if(dist<smallestDistance){smallestDistance=dist;item=[i,j/ps]}}}if(s.bars.show&&!item){var barLeft,barRight;switch(s.bars.align){case"left":barLeft=0;break;case"right":barLeft=-s.bars.barWidth;break;default:barLeft=-s.bars.barWidth/2}barRight=barLeft+s.bars.barWidth;for(j=0;j<points.length;j+=ps){var x=points[j],y=points[j+1],b=points[j+2];if(x==null)continue;if(series[i].bars.horizontal?mx<=Math.max(b,x)&&mx>=Math.min(b,x)&&my>=y+barLeft&&my<=y+barRight:mx>=x+barLeft&&mx<=x+barRight&&my>=Math.min(b,y)&&my<=Math.max(b,y))item=[i,j/ps]}}}if(item){i=item[0];j=item[1];ps=series[i].datapoints.pointsize;return{datapoint:series[i].datapoints.points.slice(j*ps,(j+1)*ps),dataIndex:j,series:series[i],seriesIndex:i}}return null}function onMouseMove(e){if(options.grid.hoverable)triggerClickHoverEvent("plothover",e,function(s){return s["hoverable"]!=false})}function onMouseLeave(e){if(options.grid.hoverable)triggerClickHoverEvent("plothover",e,function(s){return false})}function onClick(e){triggerClickHoverEvent("plotclick",e,function(s){return s["clickable"]!=false})}function triggerClickHoverEvent(eventname,event,seriesFilter){var offset=eventHolder.offset(),canvasX=event.pageX-offset.left-plotOffset.left,canvasY=event.pageY-offset.top-plotOffset.top,pos=canvasToAxisCoords({left:canvasX,top:canvasY});pos.pageX=event.pageX;pos.pageY=event.pageY;var item=findNearbyItem(canvasX,canvasY,seriesFilter);if(item){item.pageX=parseInt(item.series.xaxis.p2c(item.datapoint[0])+offset.left+plotOffset.left,10);item.pageY=parseInt(item.series.yaxis.p2c(item.datapoint[1])+offset.top+plotOffset.top,10)}if(options.grid.autoHighlight){for(var i=0;i<highlights.length;++i){var h=highlights[i];if(h.auto==eventname&&!(item&&h.series==item.series&&h.point[0]==item.datapoint[0]&&h.point[1]==item.datapoint[1]))unhighlight(h.series,h.point)}if(item)highlight(item.series,item.datapoint,eventname)}placeholder.trigger(eventname,[pos,item])}function triggerRedrawOverlay(){var t=options.interaction.redrawOverlayInterval;if(t==-1){drawOverlay();return}if(!redrawTimeout)redrawTimeout=setTimeout(drawOverlay,t)}function drawOverlay(){redrawTimeout=null;octx.save();overlay.clear();octx.translate(plotOffset.left,plotOffset.top);var i,hi;for(i=0;i<highlights.length;++i){hi=highlights[i];if(hi.series.bars.show)drawBarHighlight(hi.series,hi.point);else drawPointHighlight(hi.series,hi.point)}octx.restore();executeHooks(hooks.drawOverlay,[octx])}function highlight(s,point,auto){if(typeof s=="number")s=series[s];if(typeof point=="number"){var ps=s.datapoints.pointsize;point=s.datapoints.points.slice(ps*point,ps*(point+1))}var i=indexOfHighlight(s,point);if(i==-1){highlights.push({series:s,point:point,auto:auto});triggerRedrawOverlay()}else if(!auto)highlights[i].auto=false}function unhighlight(s,point){if(s==null&&point==null){highlights=[];triggerRedrawOverlay();return}if(typeof s=="number")s=series[s];if(typeof point=="number"){var ps=s.datapoints.pointsize;point=s.datapoints.points.slice(ps*point,ps*(point+1))}var i=indexOfHighlight(s,point);if(i!=-1){highlights.splice(i,1);triggerRedrawOverlay()}}function indexOfHighlight(s,p){for(var i=0;i<highlights.length;++i){var h=highlights[i];if(h.series==s&&h.point[0]==p[0]&&h.point[1]==p[1])return i}return-1}function drawPointHighlight(series,point){var x=point[0],y=point[1],axisx=series.xaxis,axisy=series.yaxis,highlightColor=typeof series.highlightColor==="string"?series.highlightColor:$.color.parse(series.color).scale("a",.5).toString();if(x<axisx.min||x>axisx.max||y<axisy.min||y>axisy.max)return;var pointRadius=series.points.radius+series.points.lineWidth/2;octx.lineWidth=pointRadius;octx.strokeStyle=highlightColor;var radius=1.5*pointRadius;x=axisx.p2c(x);y=axisy.p2c(y);octx.beginPath();if(series.points.symbol=="circle")octx.arc(x,y,radius,0,2*Math.PI,false);else series.points.symbol(octx,x,y,radius,false);octx.closePath();octx.stroke()}function drawBarHighlight(series,point){var highlightColor=typeof series.highlightColor==="string"?series.highlightColor:$.color.parse(series.color).scale("a",.5).toString(),fillStyle=highlightColor,barLeft;switch(series.bars.align){case"left":barLeft=0;break;case"right":barLeft=-series.bars.barWidth;break;default:barLeft=-series.bars.barWidth/2}octx.lineWidth=series.bars.lineWidth;octx.strokeStyle=highlightColor;drawBar(point[0],point[1],point[2]||0,barLeft,barLeft+series.bars.barWidth,function(){return fillStyle},series.xaxis,series.yaxis,octx,series.bars.horizontal,series.bars.lineWidth)}function getColorOrGradient(spec,bottom,top,defaultColor){if(typeof spec=="string")return spec;else{var gradient=ctx.createLinearGradient(0,top,0,bottom);for(var i=0,l=spec.colors.length;i<l;++i){var c=spec.colors[i];if(typeof c!="string"){var co=$.color.parse(defaultColor);if(c.brightness!=null)co=co.scale("rgb",c.brightness);if(c.opacity!=null)co.a*=c.opacity;c=co.toString()}gradient.addColorStop(i/(l-1),c)}return gradient}}}$.plot=function(placeholder,data,options){var plot=new Plot($(placeholder),data,options,$.plot.plugins);return plot};$.plot.version="0.8.3";$.plot.plugins=[];$.fn.plot=function(data,options){return this.each(function(){$.plot(this,data,options)})};function floorInBase(n,base){return base*Math.floor(n/base)}})(jQuery); +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ +(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function($){var hasOwnProperty=Object.prototype.hasOwnProperty;if(!$.fn.detach){$.fn.detach=function(){return this.each(function(){if(this.parentNode){this.parentNode.removeChild(this)}})}}function Canvas(cls,container){var element=container.children("."+cls)[0];if(element==null){element=document.createElement("canvas");element.className=cls;$(element).css({direction:"ltr",position:"absolute",left:0,top:0}).appendTo(container);if(!element.getContext){if(window.G_vmlCanvasManager){element=window.G_vmlCanvasManager.initElement(element)}else{throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.")}}}this.element=element;var context=this.context=element.getContext("2d");var devicePixelRatio=window.devicePixelRatio||1,backingStoreRatio=context.webkitBackingStorePixelRatio||context.mozBackingStorePixelRatio||context.msBackingStorePixelRatio||context.oBackingStorePixelRatio||context.backingStorePixelRatio||1;this.pixelRatio=devicePixelRatio/backingStoreRatio;this.resize(container.width(),container.height());this.textContainer=null;this.text={};this._textCache={}}Canvas.prototype.resize=function(width,height){if(width<=0||height<=0){throw new Error("Invalid dimensions for plot, width = "+width+", height = "+height)}var element=this.element,context=this.context,pixelRatio=this.pixelRatio;if(this.width!=width){element.width=width*pixelRatio;element.style.width=width+"px";this.width=width}if(this.height!=height){element.height=height*pixelRatio;element.style.height=height+"px";this.height=height}context.restore();context.save();context.scale(pixelRatio,pixelRatio)};Canvas.prototype.clear=function(){this.context.clearRect(0,0,this.width,this.height)};Canvas.prototype.render=function(){var cache=this._textCache;for(var layerKey in cache){if(hasOwnProperty.call(cache,layerKey)){var layer=this.getTextLayer(layerKey),layerCache=cache[layerKey];layer.hide();for(var styleKey in layerCache){if(hasOwnProperty.call(layerCache,styleKey)){var styleCache=layerCache[styleKey];for(var key in styleCache){if(hasOwnProperty.call(styleCache,key)){var positions=styleCache[key].positions;for(var i=0,position;position=positions[i];i++){if(position.active){if(!position.rendered){layer.append(position.element);position.rendered=true}}else{positions.splice(i--,1);if(position.rendered){position.element.detach()}}}if(positions.length==0){delete styleCache[key]}}}}}layer.show()}}};Canvas.prototype.getTextLayer=function(classes){var layer=this.text[classes];if(layer==null){if(this.textContainer==null){this.textContainer=$("<div class='flot-text'></div>").css({position:"absolute",top:0,left:0,bottom:0,right:0,"font-size":"smaller",color:"#545454"}).insertAfter(this.element)}layer=this.text[classes]=$("<div></div>").addClass(classes).css({position:"absolute",top:0,left:0,bottom:0,right:0}).appendTo(this.textContainer)}return layer};Canvas.prototype.getTextInfo=function(layer,text,font,angle,width){var textStyle,layerCache,styleCache,info;text=""+text;if(typeof font==="object"){textStyle=font.style+" "+font.variant+" "+font.weight+" "+font.size+"px/"+font.lineHeight+"px "+font.family}else{textStyle=font}layerCache=this._textCache[layer];if(layerCache==null){layerCache=this._textCache[layer]={}}styleCache=layerCache[textStyle];if(styleCache==null){styleCache=layerCache[textStyle]={}}info=styleCache[text];if(info==null){var element=$("<div></div>").html(text).css({position:"absolute","max-width":width,top:-9999}).appendTo(this.getTextLayer(layer));if(typeof font==="object"){element.css({font:textStyle,color:font.color})}else if(typeof font==="string"){element.addClass(font)}info=styleCache[text]={width:element.outerWidth(true),height:element.outerHeight(true),element:element,positions:[]};element.detach()}return info};Canvas.prototype.addText=function(layer,x,y,text,font,angle,width,halign,valign){var info=this.getTextInfo(layer,text,font,angle,width),positions=info.positions;if(halign=="center"){x-=info.width/2}else if(halign=="right"){x-=info.width}if(valign=="middle"){y-=info.height/2}else if(valign=="bottom"){y-=info.height}for(var i=0,position;position=positions[i];i++){if(position.x==x&&position.y==y){position.active=true;return}}position={active:true,rendered:false,element:positions.length?info.element.clone():info.element,x:x,y:y};positions.push(position);position.element.css({top:Math.round(y),left:Math.round(x),"text-align":halign})};Canvas.prototype.removeText=function(layer,x,y,text,font,angle){if(text==null){var layerCache=this._textCache[layer];if(layerCache!=null){for(var styleKey in layerCache){if(hasOwnProperty.call(layerCache,styleKey)){var styleCache=layerCache[styleKey];for(var key in styleCache){if(hasOwnProperty.call(styleCache,key)){var positions=styleCache[key].positions;for(var i=0,position;position=positions[i];i++){position.active=false}}}}}}}else{var positions=this.getTextInfo(layer,text,font,angle).positions;for(var i=0,position;position=positions[i];i++){if(position.x==x&&position.y==y){position.active=false}}}};function Plot(placeholder,data_,options_,plugins){var series=[],options={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:.85,sorted:null},xaxis:{show:null,position:"bottom",mode:null,font:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null},yaxis:{autoscaleMargin:.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false,zero:true},shadowSize:3,highlightColor:null},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,margin:0,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},interaction:{redrawOverlayInterval:1e3/60},hooks:{}},surface=null,overlay=null,eventHolder=null,ctx=null,octx=null,xaxes=[],yaxes=[],plotOffset={left:0,right:0,top:0,bottom:0},plotWidth=0,plotHeight=0,hooks={processOptions:[],processRawData:[],processDatapoints:[],processOffset:[],drawBackground:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},plot=this;plot.setData=setData;plot.setupGrid=setupGrid;plot.draw=draw;plot.getPlaceholder=function(){return placeholder};plot.getCanvas=function(){return surface.element};plot.getPlotOffset=function(){return plotOffset};plot.width=function(){return plotWidth};plot.height=function(){return plotHeight};plot.offset=function(){var o=eventHolder.offset();o.left+=plotOffset.left;o.top+=plotOffset.top;return o};plot.getData=function(){return series};plot.getAxes=function(){var res={},i;$.each(xaxes.concat(yaxes),function(_,axis){if(axis)res[axis.direction+(axis.n!=1?axis.n:"")+"axis"]=axis});return res};plot.getXAxes=function(){return xaxes};plot.getYAxes=function(){return yaxes};plot.c2p=canvasToAxisCoords;plot.p2c=axisToCanvasCoords;plot.getOptions=function(){return options};plot.highlight=highlight;plot.unhighlight=unhighlight;plot.triggerRedrawOverlay=triggerRedrawOverlay;plot.pointOffset=function(point){return{left:parseInt(xaxes[axisNumber(point,"x")-1].p2c(+point.x)+plotOffset.left,10),top:parseInt(yaxes[axisNumber(point,"y")-1].p2c(+point.y)+plotOffset.top,10)}};plot.shutdown=shutdown;plot.destroy=function(){shutdown();placeholder.removeData("plot").empty();series=[];options=null;surface=null;overlay=null;eventHolder=null;ctx=null;octx=null;xaxes=[];yaxes=[];hooks=null;highlights=[];plot=null};plot.resize=function(){var width=placeholder.width(),height=placeholder.height();surface.resize(width,height);overlay.resize(width,height)};plot.hooks=hooks;initPlugins(plot);parseOptions(options_);setupCanvases();setData(data_);setupGrid();draw();bindEvents();function executeHooks(hook,args){args=[plot].concat(args);for(var i=0;i<hook.length;++i)hook[i].apply(this,args)}function initPlugins(){var classes={Canvas:Canvas};for(var i=0;i<plugins.length;++i){var p=plugins[i];p.init(plot,classes);if(p.options)$.extend(true,options,p.options)}}function parseOptions(opts){$.extend(true,options,opts);if(opts&&opts.colors){options.colors=opts.colors}if(options.xaxis.color==null)options.xaxis.color=$.color.parse(options.grid.color).scale("a",.22).toString();if(options.yaxis.color==null)options.yaxis.color=$.color.parse(options.grid.color).scale("a",.22).toString();if(options.xaxis.tickColor==null)options.xaxis.tickColor=options.grid.tickColor||options.xaxis.color;if(options.yaxis.tickColor==null)options.yaxis.tickColor=options.grid.tickColor||options.yaxis.color;if(options.grid.borderColor==null)options.grid.borderColor=options.grid.color;if(options.grid.tickColor==null)options.grid.tickColor=$.color.parse(options.grid.color).scale("a",.22).toString();var i,axisOptions,axisCount,fontSize=placeholder.css("font-size"),fontSizeDefault=fontSize?+fontSize.replace("px",""):13,fontDefaults={style:placeholder.css("font-style"),size:Math.round(.8*fontSizeDefault),variant:placeholder.css("font-variant"),weight:placeholder.css("font-weight"),family:placeholder.css("font-family")};axisCount=options.xaxes.length||1;for(i=0;i<axisCount;++i){axisOptions=options.xaxes[i];if(axisOptions&&!axisOptions.tickColor){axisOptions.tickColor=axisOptions.color}axisOptions=$.extend(true,{},options.xaxis,axisOptions);options.xaxes[i]=axisOptions;if(axisOptions.font){axisOptions.font=$.extend({},fontDefaults,axisOptions.font);if(!axisOptions.font.color){axisOptions.font.color=axisOptions.color}if(!axisOptions.font.lineHeight){axisOptions.font.lineHeight=Math.round(axisOptions.font.size*1.15)}}}axisCount=options.yaxes.length||1;for(i=0;i<axisCount;++i){axisOptions=options.yaxes[i];if(axisOptions&&!axisOptions.tickColor){axisOptions.tickColor=axisOptions.color}axisOptions=$.extend(true,{},options.yaxis,axisOptions);options.yaxes[i]=axisOptions;if(axisOptions.font){axisOptions.font=$.extend({},fontDefaults,axisOptions.font);if(!axisOptions.font.color){axisOptions.font.color=axisOptions.color}if(!axisOptions.font.lineHeight){axisOptions.font.lineHeight=Math.round(axisOptions.font.size*1.15)}}}if(options.xaxis.noTicks&&options.xaxis.ticks==null)options.xaxis.ticks=options.xaxis.noTicks;if(options.yaxis.noTicks&&options.yaxis.ticks==null)options.yaxis.ticks=options.yaxis.noTicks;if(options.x2axis){options.xaxes[1]=$.extend(true,{},options.xaxis,options.x2axis);options.xaxes[1].position="top";if(options.x2axis.min==null){options.xaxes[1].min=null}if(options.x2axis.max==null){options.xaxes[1].max=null}}if(options.y2axis){options.yaxes[1]=$.extend(true,{},options.yaxis,options.y2axis);options.yaxes[1].position="right";if(options.y2axis.min==null){options.yaxes[1].min=null}if(options.y2axis.max==null){options.yaxes[1].max=null}}if(options.grid.coloredAreas)options.grid.markings=options.grid.coloredAreas;if(options.grid.coloredAreasColor)options.grid.markingsColor=options.grid.coloredAreasColor;if(options.lines)$.extend(true,options.series.lines,options.lines);if(options.points)$.extend(true,options.series.points,options.points);if(options.bars)$.extend(true,options.series.bars,options.bars);if(options.shadowSize!=null)options.series.shadowSize=options.shadowSize;if(options.highlightColor!=null)options.series.highlightColor=options.highlightColor;for(i=0;i<options.xaxes.length;++i)getOrCreateAxis(xaxes,i+1).options=options.xaxes[i];for(i=0;i<options.yaxes.length;++i)getOrCreateAxis(yaxes,i+1).options=options.yaxes[i];for(var n in hooks)if(options.hooks[n]&&options.hooks[n].length)hooks[n]=hooks[n].concat(options.hooks[n]);executeHooks(hooks.processOptions,[options])}function setData(d){series=parseData(d);fillInSeriesOptions();processData()}function parseData(d){var res=[];for(var i=0;i<d.length;++i){var s=$.extend(true,{},options.series);if(d[i].data!=null){s.data=d[i].data;delete d[i].data;$.extend(true,s,d[i]);d[i].data=s.data}else s.data=d[i];res.push(s)}return res}function axisNumber(obj,coord){var a=obj[coord+"axis"];if(typeof a=="object")a=a.n;if(typeof a!="number")a=1;return a}function allAxes(){return $.grep(xaxes.concat(yaxes),function(a){return a})}function canvasToAxisCoords(pos){var res={},i,axis;for(i=0;i<xaxes.length;++i){axis=xaxes[i];if(axis&&axis.used)res["x"+axis.n]=axis.c2p(pos.left)}for(i=0;i<yaxes.length;++i){axis=yaxes[i];if(axis&&axis.used)res["y"+axis.n]=axis.c2p(pos.top)}if(res.x1!==undefined)res.x=res.x1;if(res.y1!==undefined)res.y=res.y1;return res}function axisToCanvasCoords(pos){var res={},i,axis,key;for(i=0;i<xaxes.length;++i){axis=xaxes[i];if(axis&&axis.used){key="x"+axis.n;if(pos[key]==null&&axis.n==1)key="x";if(pos[key]!=null){res.left=axis.p2c(pos[key]);break}}}for(i=0;i<yaxes.length;++i){axis=yaxes[i];if(axis&&axis.used){key="y"+axis.n;if(pos[key]==null&&axis.n==1)key="y";if(pos[key]!=null){res.top=axis.p2c(pos[key]);break}}}return res}function getOrCreateAxis(axes,number){if(!axes[number-1])axes[number-1]={n:number,direction:axes==xaxes?"x":"y",options:$.extend(true,{},axes==xaxes?options.xaxis:options.yaxis)};return axes[number-1]}function fillInSeriesOptions(){var neededColors=series.length,maxIndex=-1,i;for(i=0;i<series.length;++i){var sc=series[i].color;if(sc!=null){neededColors--;if(typeof sc=="number"&&sc>maxIndex){maxIndex=sc}}}if(neededColors<=maxIndex){neededColors=maxIndex+1}var c,colors=[],colorPool=options.colors,colorPoolSize=colorPool.length,variation=0;for(i=0;i<neededColors;i++){c=$.color.parse(colorPool[i%colorPoolSize]||"#666");if(i%colorPoolSize==0&&i){if(variation>=0){if(variation<.5){variation=-variation-.2}else variation=0}else variation=-variation}colors[i]=c.scale("rgb",1+variation)}var colori=0,s;for(i=0;i<series.length;++i){s=series[i];if(s.color==null){s.color=colors[colori].toString();++colori}else if(typeof s.color=="number")s.color=colors[s.color].toString();if(s.lines.show==null){var v,show=true;for(v in s)if(s[v]&&s[v].show){show=false;break}if(show)s.lines.show=true}if(s.lines.zero==null){s.lines.zero=!!s.lines.fill}s.xaxis=getOrCreateAxis(xaxes,axisNumber(s,"x"));s.yaxis=getOrCreateAxis(yaxes,axisNumber(s,"y"))}}function processData(){var topSentry=Number.POSITIVE_INFINITY,bottomSentry=Number.NEGATIVE_INFINITY,fakeInfinity=Number.MAX_VALUE,i,j,k,m,length,s,points,ps,x,y,axis,val,f,p,data,format;function updateAxis(axis,min,max){if(min<axis.datamin&&min!=-fakeInfinity)axis.datamin=min;if(max>axis.datamax&&max!=fakeInfinity)axis.datamax=max}$.each(allAxes(),function(_,axis){axis.datamin=topSentry;axis.datamax=bottomSentry;axis.used=false});for(i=0;i<series.length;++i){s=series[i];s.datapoints={points:[]};executeHooks(hooks.processRawData,[s,s.data,s.datapoints])}for(i=0;i<series.length;++i){s=series[i];data=s.data;format=s.datapoints.format;if(!format){format=[];format.push({x:true,number:true,required:true});format.push({y:true,number:true,required:true});if(s.bars.show||s.lines.show&&s.lines.fill){var autoscale=!!(s.bars.show&&s.bars.zero||s.lines.show&&s.lines.zero);format.push({y:true,number:true,required:false,defaultValue:0,autoscale:autoscale});if(s.bars.horizontal){delete format[format.length-1].y;format[format.length-1].x=true}}s.datapoints.format=format}if(s.datapoints.pointsize!=null)continue;s.datapoints.pointsize=format.length;ps=s.datapoints.pointsize;points=s.datapoints.points;var insertSteps=s.lines.show&&s.lines.steps;s.xaxis.used=s.yaxis.used=true;for(j=k=0;j<data.length;++j,k+=ps){p=data[j];var nullify=p==null;if(!nullify){for(m=0;m<ps;++m){val=p[m];f=format[m];if(f){if(f.number&&val!=null){val=+val;if(isNaN(val))val=null;else if(val==Infinity)val=fakeInfinity;else if(val==-Infinity)val=-fakeInfinity}if(val==null){if(f.required)nullify=true;if(f.defaultValue!=null)val=f.defaultValue}}points[k+m]=val}}if(nullify){for(m=0;m<ps;++m){val=points[k+m];if(val!=null){f=format[m];if(f.autoscale!==false){if(f.x){updateAxis(s.xaxis,val,val)}if(f.y){updateAxis(s.yaxis,val,val)}}}points[k+m]=null}}else{if(insertSteps&&k>0&&points[k-ps]!=null&&points[k-ps]!=points[k]&&points[k-ps+1]!=points[k+1]){for(m=0;m<ps;++m)points[k+ps+m]=points[k+m];points[k+1]=points[k-ps+1];k+=ps}}}}for(i=0;i<series.length;++i){s=series[i];executeHooks(hooks.processDatapoints,[s,s.datapoints])}for(i=0;i<series.length;++i){s=series[i];points=s.datapoints.points;ps=s.datapoints.pointsize;format=s.datapoints.format;var xmin=topSentry,ymin=topSentry,xmax=bottomSentry,ymax=bottomSentry;for(j=0;j<points.length;j+=ps){if(points[j]==null)continue;for(m=0;m<ps;++m){val=points[j+m];f=format[m];if(!f||f.autoscale===false||val==fakeInfinity||val==-fakeInfinity)continue;if(f.x){if(val<xmin)xmin=val;if(val>xmax)xmax=val}if(f.y){if(val<ymin)ymin=val;if(val>ymax)ymax=val}}}if(s.bars.show){var delta;switch(s.bars.align){case"left":delta=0;break;case"right":delta=-s.bars.barWidth;break;default:delta=-s.bars.barWidth/2}if(s.bars.horizontal){ymin+=delta;ymax+=delta+s.bars.barWidth}else{xmin+=delta;xmax+=delta+s.bars.barWidth}}updateAxis(s.xaxis,xmin,xmax);updateAxis(s.yaxis,ymin,ymax)}$.each(allAxes(),function(_,axis){if(axis.datamin==topSentry)axis.datamin=null;if(axis.datamax==bottomSentry)axis.datamax=null})}function setupCanvases(){placeholder.css("padding",0).children().filter(function(){return!$(this).hasClass("flot-overlay")&&!$(this).hasClass("flot-base")}).remove();if(placeholder.css("position")=="static")placeholder.css("position","relative");surface=new Canvas("flot-base",placeholder);overlay=new Canvas("flot-overlay",placeholder);ctx=surface.context;octx=overlay.context;eventHolder=$(overlay.element).unbind();var existing=placeholder.data("plot");if(existing){existing.shutdown();overlay.clear()}placeholder.data("plot",plot)}function bindEvents(){if(options.grid.hoverable){eventHolder.mousemove(onMouseMove);eventHolder.bind("mouseleave",onMouseLeave)}if(options.grid.clickable)eventHolder.click(onClick);executeHooks(hooks.bindEvents,[eventHolder])}function shutdown(){if(redrawTimeout)clearTimeout(redrawTimeout);eventHolder.unbind("mousemove",onMouseMove);eventHolder.unbind("mouseleave",onMouseLeave);eventHolder.unbind("click",onClick);executeHooks(hooks.shutdown,[eventHolder])}function setTransformationHelpers(axis){function identity(x){return x}var s,m,t=axis.options.transform||identity,it=axis.options.inverseTransform;if(axis.direction=="x"){s=axis.scale=plotWidth/Math.abs(t(axis.max)-t(axis.min));m=Math.min(t(axis.max),t(axis.min))}else{s=axis.scale=plotHeight/Math.abs(t(axis.max)-t(axis.min));s=-s;m=Math.max(t(axis.max),t(axis.min))}if(t==identity)axis.p2c=function(p){return(p-m)*s};else axis.p2c=function(p){return(t(p)-m)*s};if(!it)axis.c2p=function(c){return m+c/s};else axis.c2p=function(c){return it(m+c/s)}}function measureTickLabels(axis){var opts=axis.options,ticks=axis.ticks||[],labelWidth=opts.labelWidth||0,labelHeight=opts.labelHeight||0,maxWidth=labelWidth||(axis.direction=="x"?Math.floor(surface.width/(ticks.length||1)):null),legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=opts.font||"flot-tick-label tickLabel";for(var i=0;i<ticks.length;++i){var t=ticks[i];if(!t.label)continue;var info=surface.getTextInfo(layer,t.label,font,null,maxWidth);labelWidth=Math.max(labelWidth,info.width);labelHeight=Math.max(labelHeight,info.height)}axis.labelWidth=opts.labelWidth||labelWidth;axis.labelHeight=opts.labelHeight||labelHeight}function allocateAxisBoxFirstPhase(axis){var lw=axis.labelWidth,lh=axis.labelHeight,pos=axis.options.position,isXAxis=axis.direction==="x",tickLength=axis.options.tickLength,axisMargin=options.grid.axisMargin,padding=options.grid.labelMargin,innermost=true,outermost=true,first=true,found=false;$.each(isXAxis?xaxes:yaxes,function(i,a){if(a&&(a.show||a.reserveSpace)){if(a===axis){found=true}else if(a.options.position===pos){if(found){outermost=false}else{innermost=false}}if(!found){first=false}}});if(outermost){axisMargin=0}if(tickLength==null){tickLength=first?"full":5}if(!isNaN(+tickLength))padding+=+tickLength;if(isXAxis){lh+=padding;if(pos=="bottom"){plotOffset.bottom+=lh+axisMargin;axis.box={top:surface.height-plotOffset.bottom,height:lh}}else{axis.box={top:plotOffset.top+axisMargin,height:lh};plotOffset.top+=lh+axisMargin}}else{lw+=padding;if(pos=="left"){axis.box={left:plotOffset.left+axisMargin,width:lw};plotOffset.left+=lw+axisMargin}else{plotOffset.right+=lw+axisMargin;axis.box={left:surface.width-plotOffset.right,width:lw}}}axis.position=pos;axis.tickLength=tickLength;axis.box.padding=padding;axis.innermost=innermost}function allocateAxisBoxSecondPhase(axis){if(axis.direction=="x"){axis.box.left=plotOffset.left-axis.labelWidth/2;axis.box.width=surface.width-plotOffset.left-plotOffset.right+axis.labelWidth}else{axis.box.top=plotOffset.top-axis.labelHeight/2;axis.box.height=surface.height-plotOffset.bottom-plotOffset.top+axis.labelHeight}}function adjustLayoutForThingsStickingOut(){var minMargin=options.grid.minBorderMargin,axis,i;if(minMargin==null){minMargin=0;for(i=0;i<series.length;++i)minMargin=Math.max(minMargin,2*(series[i].points.radius+series[i].points.lineWidth/2))}var margins={left:minMargin,right:minMargin,top:minMargin,bottom:minMargin};$.each(allAxes(),function(_,axis){if(axis.reserveSpace&&axis.ticks&&axis.ticks.length){if(axis.direction==="x"){margins.left=Math.max(margins.left,axis.labelWidth/2);margins.right=Math.max(margins.right,axis.labelWidth/2)}else{margins.bottom=Math.max(margins.bottom,axis.labelHeight/2);margins.top=Math.max(margins.top,axis.labelHeight/2)}}});plotOffset.left=Math.ceil(Math.max(margins.left,plotOffset.left));plotOffset.right=Math.ceil(Math.max(margins.right,plotOffset.right));plotOffset.top=Math.ceil(Math.max(margins.top,plotOffset.top));plotOffset.bottom=Math.ceil(Math.max(margins.bottom,plotOffset.bottom))}function setupGrid(){var i,axes=allAxes(),showGrid=options.grid.show;for(var a in plotOffset){var margin=options.grid.margin||0;plotOffset[a]=typeof margin=="number"?margin:margin[a]||0}executeHooks(hooks.processOffset,[plotOffset]);for(var a in plotOffset){if(typeof options.grid.borderWidth=="object"){plotOffset[a]+=showGrid?options.grid.borderWidth[a]:0}else{plotOffset[a]+=showGrid?options.grid.borderWidth:0}}$.each(axes,function(_,axis){var axisOpts=axis.options;axis.show=axisOpts.show==null?axis.used:axisOpts.show;axis.reserveSpace=axisOpts.reserveSpace==null?axis.show:axisOpts.reserveSpace;setRange(axis)});if(showGrid){var allocatedAxes=$.grep(axes,function(axis){return axis.show||axis.reserveSpace});$.each(allocatedAxes,function(_,axis){setupTickGeneration(axis);setTicks(axis);snapRangeToTicks(axis,axis.ticks);measureTickLabels(axis)});for(i=allocatedAxes.length-1;i>=0;--i)allocateAxisBoxFirstPhase(allocatedAxes[i]);adjustLayoutForThingsStickingOut();$.each(allocatedAxes,function(_,axis){allocateAxisBoxSecondPhase(axis)})}plotWidth=surface.width-plotOffset.left-plotOffset.right;plotHeight=surface.height-plotOffset.bottom-plotOffset.top;$.each(axes,function(_,axis){setTransformationHelpers(axis)});if(showGrid){drawAxisLabels()}insertLegend()}function setRange(axis){var opts=axis.options,min=+(opts.min!=null?opts.min:axis.datamin),max=+(opts.max!=null?opts.max:axis.datamax),delta=max-min;if(delta==0){var widen=max==0?1:.01;if(opts.min==null)min-=widen;if(opts.max==null||opts.min!=null)max+=widen}else{var margin=opts.autoscaleMargin;if(margin!=null){if(opts.min==null){min-=delta*margin;if(min<0&&axis.datamin!=null&&axis.datamin>=0)min=0}if(opts.max==null){max+=delta*margin;if(max>0&&axis.datamax!=null&&axis.datamax<=0)max=0}}}axis.min=min;axis.max=max}function setupTickGeneration(axis){var opts=axis.options;var noTicks;if(typeof opts.ticks=="number"&&opts.ticks>0)noTicks=opts.ticks;else noTicks=.3*Math.sqrt(axis.direction=="x"?surface.width:surface.height);var delta=(axis.max-axis.min)/noTicks,dec=-Math.floor(Math.log(delta)/Math.LN10),maxDec=opts.tickDecimals;if(maxDec!=null&&dec>maxDec){dec=maxDec}var magn=Math.pow(10,-dec),norm=delta/magn,size;if(norm<1.5){size=1}else if(norm<3){size=2;if(norm>2.25&&(maxDec==null||dec+1<=maxDec)){size=2.5;++dec}}else if(norm<7.5){size=5}else{size=10}size*=magn;if(opts.minTickSize!=null&&size<opts.minTickSize){size=opts.minTickSize}axis.delta=delta;axis.tickDecimals=Math.max(0,maxDec!=null?maxDec:dec);axis.tickSize=opts.tickSize||size;if(opts.mode=="time"&&!axis.tickGenerator){throw new Error("Time mode requires the flot.time plugin.")}if(!axis.tickGenerator){axis.tickGenerator=function(axis){var ticks=[],start=floorInBase(axis.min,axis.tickSize),i=0,v=Number.NaN,prev;do{prev=v;v=start+i*axis.tickSize;ticks.push(v);++i}while(v<axis.max&&v!=prev);return ticks};axis.tickFormatter=function(value,axis){var factor=axis.tickDecimals?Math.pow(10,axis.tickDecimals):1;var formatted=""+Math.round(value*factor)/factor;if(axis.tickDecimals!=null){var decimal=formatted.indexOf(".");var precision=decimal==-1?0:formatted.length-decimal-1;if(precision<axis.tickDecimals){return(precision?formatted:formatted+".")+(""+factor).substr(1,axis.tickDecimals-precision)}}return formatted}}if($.isFunction(opts.tickFormatter))axis.tickFormatter=function(v,axis){return""+opts.tickFormatter(v,axis)};if(opts.alignTicksWithAxis!=null){var otherAxis=(axis.direction=="x"?xaxes:yaxes)[opts.alignTicksWithAxis-1];if(otherAxis&&otherAxis.used&&otherAxis!=axis){var niceTicks=axis.tickGenerator(axis);if(niceTicks.length>0){if(opts.min==null)axis.min=Math.min(axis.min,niceTicks[0]);if(opts.max==null&&niceTicks.length>1)axis.max=Math.max(axis.max,niceTicks[niceTicks.length-1])}axis.tickGenerator=function(axis){var ticks=[],v,i;for(i=0;i<otherAxis.ticks.length;++i){v=(otherAxis.ticks[i].v-otherAxis.min)/(otherAxis.max-otherAxis.min);v=axis.min+v*(axis.max-axis.min);ticks.push(v)}return ticks};if(!axis.mode&&opts.tickDecimals==null){var extraDec=Math.max(0,-Math.floor(Math.log(axis.delta)/Math.LN10)+1),ts=axis.tickGenerator(axis);if(!(ts.length>1&&/\..*0$/.test((ts[1]-ts[0]).toFixed(extraDec))))axis.tickDecimals=extraDec}}}}function setTicks(axis){var oticks=axis.options.ticks,ticks=[];if(oticks==null||typeof oticks=="number"&&oticks>0)ticks=axis.tickGenerator(axis);else if(oticks){if($.isFunction(oticks))ticks=oticks(axis);else ticks=oticks}var i,v;axis.ticks=[];for(i=0;i<ticks.length;++i){var label=null;var t=ticks[i];if(typeof t=="object"){v=+t[0];if(t.length>1)label=t[1]}else v=+t;if(label==null)label=axis.tickFormatter(v,axis);if(!isNaN(v))axis.ticks.push({v:v,label:label})}}function snapRangeToTicks(axis,ticks){if(axis.options.autoscaleMargin&&ticks.length>0){if(axis.options.min==null)axis.min=Math.min(axis.min,ticks[0].v);if(axis.options.max==null&&ticks.length>1)axis.max=Math.max(axis.max,ticks[ticks.length-1].v)}}function draw(){surface.clear();executeHooks(hooks.drawBackground,[ctx]);var grid=options.grid;if(grid.show&&grid.backgroundColor)drawBackground();if(grid.show&&!grid.aboveData){drawGrid()}for(var i=0;i<series.length;++i){executeHooks(hooks.drawSeries,[ctx,series[i]]);drawSeries(series[i])}executeHooks(hooks.draw,[ctx]);if(grid.show&&grid.aboveData){drawGrid()}surface.render();triggerRedrawOverlay()}function extractRange(ranges,coord){var axis,from,to,key,axes=allAxes();for(var i=0;i<axes.length;++i){axis=axes[i];if(axis.direction==coord){key=coord+axis.n+"axis";if(!ranges[key]&&axis.n==1)key=coord+"axis";if(ranges[key]){from=ranges[key].from;to=ranges[key].to;break}}}if(!ranges[key]){axis=coord=="x"?xaxes[0]:yaxes[0];from=ranges[coord+"1"];to=ranges[coord+"2"]}if(from!=null&&to!=null&&from>to){var tmp=from;from=to;to=tmp}return{from:from,to:to,axis:axis}}function drawBackground(){ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.fillStyle=getColorOrGradient(options.grid.backgroundColor,plotHeight,0,"rgba(255, 255, 255, 0)");ctx.fillRect(0,0,plotWidth,plotHeight);ctx.restore()}function drawGrid(){var i,axes,bw,bc;ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var markings=options.grid.markings;if(markings){if($.isFunction(markings)){axes=plot.getAxes();axes.xmin=axes.xaxis.min;axes.xmax=axes.xaxis.max;axes.ymin=axes.yaxis.min;axes.ymax=axes.yaxis.max;markings=markings(axes)}for(i=0;i<markings.length;++i){var m=markings[i],xrange=extractRange(m,"x"),yrange=extractRange(m,"y");if(xrange.from==null)xrange.from=xrange.axis.min;if(xrange.to==null)xrange.to=xrange.axis.max; +if(yrange.from==null)yrange.from=yrange.axis.min;if(yrange.to==null)yrange.to=yrange.axis.max;if(xrange.to<xrange.axis.min||xrange.from>xrange.axis.max||yrange.to<yrange.axis.min||yrange.from>yrange.axis.max)continue;xrange.from=Math.max(xrange.from,xrange.axis.min);xrange.to=Math.min(xrange.to,xrange.axis.max);yrange.from=Math.max(yrange.from,yrange.axis.min);yrange.to=Math.min(yrange.to,yrange.axis.max);var xequal=xrange.from===xrange.to,yequal=yrange.from===yrange.to;if(xequal&&yequal){continue}xrange.from=Math.floor(xrange.axis.p2c(xrange.from));xrange.to=Math.floor(xrange.axis.p2c(xrange.to));yrange.from=Math.floor(yrange.axis.p2c(yrange.from));yrange.to=Math.floor(yrange.axis.p2c(yrange.to));if(xequal||yequal){var lineWidth=m.lineWidth||options.grid.markingsLineWidth,subPixel=lineWidth%2?.5:0;ctx.beginPath();ctx.strokeStyle=m.color||options.grid.markingsColor;ctx.lineWidth=lineWidth;if(xequal){ctx.moveTo(xrange.to+subPixel,yrange.from);ctx.lineTo(xrange.to+subPixel,yrange.to)}else{ctx.moveTo(xrange.from,yrange.to+subPixel);ctx.lineTo(xrange.to,yrange.to+subPixel)}ctx.stroke()}else{ctx.fillStyle=m.color||options.grid.markingsColor;ctx.fillRect(xrange.from,yrange.to,xrange.to-xrange.from,yrange.from-yrange.to)}}}axes=allAxes();bw=options.grid.borderWidth;for(var j=0;j<axes.length;++j){var axis=axes[j],box=axis.box,t=axis.tickLength,x,y,xoff,yoff;if(!axis.show||axis.ticks.length==0)continue;ctx.lineWidth=1;if(axis.direction=="x"){x=0;if(t=="full")y=axis.position=="top"?0:plotHeight;else y=box.top-plotOffset.top+(axis.position=="top"?box.height:0)}else{y=0;if(t=="full")x=axis.position=="left"?0:plotWidth;else x=box.left-plotOffset.left+(axis.position=="left"?box.width:0)}if(!axis.innermost){ctx.strokeStyle=axis.options.color;ctx.beginPath();xoff=yoff=0;if(axis.direction=="x")xoff=plotWidth+1;else yoff=plotHeight+1;if(ctx.lineWidth==1){if(axis.direction=="x"){y=Math.floor(y)+.5}else{x=Math.floor(x)+.5}}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff);ctx.stroke()}ctx.strokeStyle=axis.options.tickColor;ctx.beginPath();for(i=0;i<axis.ticks.length;++i){var v=axis.ticks[i].v;xoff=yoff=0;if(isNaN(v)||v<axis.min||v>axis.max||t=="full"&&(typeof bw=="object"&&bw[axis.position]>0||bw>0)&&(v==axis.min||v==axis.max))continue;if(axis.direction=="x"){x=axis.p2c(v);yoff=t=="full"?-plotHeight:t;if(axis.position=="top")yoff=-yoff}else{y=axis.p2c(v);xoff=t=="full"?-plotWidth:t;if(axis.position=="left")xoff=-xoff}if(ctx.lineWidth==1){if(axis.direction=="x")x=Math.floor(x)+.5;else y=Math.floor(y)+.5}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff)}ctx.stroke()}if(bw){bc=options.grid.borderColor;if(typeof bw=="object"||typeof bc=="object"){if(typeof bw!=="object"){bw={top:bw,right:bw,bottom:bw,left:bw}}if(typeof bc!=="object"){bc={top:bc,right:bc,bottom:bc,left:bc}}if(bw.top>0){ctx.strokeStyle=bc.top;ctx.lineWidth=bw.top;ctx.beginPath();ctx.moveTo(0-bw.left,0-bw.top/2);ctx.lineTo(plotWidth,0-bw.top/2);ctx.stroke()}if(bw.right>0){ctx.strokeStyle=bc.right;ctx.lineWidth=bw.right;ctx.beginPath();ctx.moveTo(plotWidth+bw.right/2,0-bw.top);ctx.lineTo(plotWidth+bw.right/2,plotHeight);ctx.stroke()}if(bw.bottom>0){ctx.strokeStyle=bc.bottom;ctx.lineWidth=bw.bottom;ctx.beginPath();ctx.moveTo(plotWidth+bw.right,plotHeight+bw.bottom/2);ctx.lineTo(0,plotHeight+bw.bottom/2);ctx.stroke()}if(bw.left>0){ctx.strokeStyle=bc.left;ctx.lineWidth=bw.left;ctx.beginPath();ctx.moveTo(0-bw.left/2,plotHeight+bw.bottom);ctx.lineTo(0-bw.left/2,0);ctx.stroke()}}else{ctx.lineWidth=bw;ctx.strokeStyle=options.grid.borderColor;ctx.strokeRect(-bw/2,-bw/2,plotWidth+bw,plotHeight+bw)}}ctx.restore()}function drawAxisLabels(){$.each(allAxes(),function(_,axis){var box=axis.box,legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=axis.options.font||"flot-tick-label tickLabel",tick,x,y,halign,valign;surface.removeText(layer);if(!axis.show||axis.ticks.length==0)return;for(var i=0;i<axis.ticks.length;++i){tick=axis.ticks[i];if(!tick.label||tick.v<axis.min||tick.v>axis.max)continue;if(axis.direction=="x"){halign="center";x=plotOffset.left+axis.p2c(tick.v);if(axis.position=="bottom"){y=box.top+box.padding}else{y=box.top+box.height-box.padding;valign="bottom"}}else{valign="middle";y=plotOffset.top+axis.p2c(tick.v);if(axis.position=="left"){x=box.left+box.width-box.padding;halign="right"}else{x=box.left+box.padding}}surface.addText(layer,x,y,tick.label,font,null,null,halign,valign)}})}function drawSeries(series){if(series.lines.show)drawSeriesLines(series);if(series.bars.show)drawSeriesBars(series);if(series.points.show)drawSeriesPoints(series)}function drawSeriesLines(series){function plotLine(datapoints,xoffset,yoffset,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,prevx=null,prevy=null;ctx.beginPath();for(var i=ps;i<points.length;i+=ps){var x1=points[i-ps],y1=points[i-ps+1],x2=points[i],y2=points[i+1];if(x1==null||x2==null)continue;if(y1<=y2&&y1<axisy.min){if(y2<axisy.min)continue;x1=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.min}else if(y2<=y1&&y2<axisy.min){if(y1<axisy.min)continue;x2=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.min}if(y1>=y2&&y1>axisy.max){if(y2>axisy.max)continue;x1=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.max}else if(y2>=y1&&y2>axisy.max){if(y1>axisy.max)continue;x2=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.max}if(x1<=x2&&x1<axisx.min){if(x2<axisx.min)continue;y1=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.min}else if(x2<=x1&&x2<axisx.min){if(x1<axisx.min)continue;y2=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.min}if(x1>=x2&&x1>axisx.max){if(x2>axisx.max)continue;y1=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.max}else if(x2>=x1&&x2>axisx.max){if(x1>axisx.max)continue;y2=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.max}if(x1!=prevx||y1!=prevy)ctx.moveTo(axisx.p2c(x1)+xoffset,axisy.p2c(y1)+yoffset);prevx=x2;prevy=y2;ctx.lineTo(axisx.p2c(x2)+xoffset,axisy.p2c(y2)+yoffset)}ctx.stroke()}function plotLineArea(datapoints,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,bottom=Math.min(Math.max(0,axisy.min),axisy.max),i=0,top,areaOpen=false,ypos=1,segmentStart=0,segmentEnd=0;while(true){if(ps>0&&i>points.length+ps)break;i+=ps;var x1=points[i-ps],y1=points[i-ps+ypos],x2=points[i],y2=points[i+ypos];if(areaOpen){if(ps>0&&x1!=null&&x2==null){segmentEnd=i;ps=-ps;ypos=2;continue}if(ps<0&&i==segmentStart+ps){ctx.fill();areaOpen=false;ps=-ps;ypos=1;i=segmentStart=segmentEnd+ps;continue}}if(x1==null||x2==null)continue;if(x1<=x2&&x1<axisx.min){if(x2<axisx.min)continue;y1=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.min}else if(x2<=x1&&x2<axisx.min){if(x1<axisx.min)continue;y2=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.min}if(x1>=x2&&x1>axisx.max){if(x2>axisx.max)continue;y1=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.max}else if(x2>=x1&&x2>axisx.max){if(x1>axisx.max)continue;y2=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.max}if(!areaOpen){ctx.beginPath();ctx.moveTo(axisx.p2c(x1),axisy.p2c(bottom));areaOpen=true}if(y1>=axisy.max&&y2>=axisy.max){ctx.lineTo(axisx.p2c(x1),axisy.p2c(axisy.max));ctx.lineTo(axisx.p2c(x2),axisy.p2c(axisy.max));continue}else if(y1<=axisy.min&&y2<=axisy.min){ctx.lineTo(axisx.p2c(x1),axisy.p2c(axisy.min));ctx.lineTo(axisx.p2c(x2),axisy.p2c(axisy.min));continue}var x1old=x1,x2old=x2;if(y1<=y2&&y1<axisy.min&&y2>=axisy.min){x1=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.min}else if(y2<=y1&&y2<axisy.min&&y1>=axisy.min){x2=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.min}if(y1>=y2&&y1>axisy.max&&y2<=axisy.max){x1=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.max}else if(y2>=y1&&y2>axisy.max&&y1<=axisy.max){x2=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.max}if(x1!=x1old){ctx.lineTo(axisx.p2c(x1old),axisy.p2c(y1))}ctx.lineTo(axisx.p2c(x1),axisy.p2c(y1));ctx.lineTo(axisx.p2c(x2),axisy.p2c(y2));if(x2!=x2old){ctx.lineTo(axisx.p2c(x2),axisy.p2c(y2));ctx.lineTo(axisx.p2c(x2old),axisy.p2c(y2))}}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.lineJoin="round";var lw=series.lines.lineWidth,sw=series.shadowSize;if(lw>0&&sw>0){ctx.lineWidth=sw;ctx.strokeStyle="rgba(0,0,0,0.1)";var angle=Math.PI/18;plotLine(series.datapoints,Math.sin(angle)*(lw/2+sw/2),Math.cos(angle)*(lw/2+sw/2),series.xaxis,series.yaxis);ctx.lineWidth=sw/2;plotLine(series.datapoints,Math.sin(angle)*(lw/2+sw/4),Math.cos(angle)*(lw/2+sw/4),series.xaxis,series.yaxis)}ctx.lineWidth=lw;ctx.strokeStyle=series.color;var fillStyle=getFillStyle(series.lines,series.color,0,plotHeight);if(fillStyle){ctx.fillStyle=fillStyle;plotLineArea(series.datapoints,series.xaxis,series.yaxis)}if(lw>0)plotLine(series.datapoints,0,0,series.xaxis,series.yaxis);ctx.restore()}function drawSeriesPoints(series){function plotPoints(datapoints,radius,fillStyle,offset,shadow,axisx,axisy,symbol){var points=datapoints.points,ps=datapoints.pointsize;for(var i=0;i<points.length;i+=ps){var x=points[i],y=points[i+1];if(x==null||x<axisx.min||x>axisx.max||y<axisy.min||y>axisy.max)continue;ctx.beginPath();x=axisx.p2c(x);y=axisy.p2c(y)+offset;if(symbol=="circle")ctx.arc(x,y,radius,0,shadow?Math.PI:Math.PI*2,false);else symbol(ctx,x,y,radius,shadow);ctx.closePath();if(fillStyle){ctx.fillStyle=fillStyle;ctx.fill()}ctx.stroke()}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var lw=series.points.lineWidth,sw=series.shadowSize,radius=series.points.radius,symbol=series.points.symbol;if(lw==0)lw=1e-4;if(lw>0&&sw>0){var w=sw/2;ctx.lineWidth=w;ctx.strokeStyle="rgba(0,0,0,0.1)";plotPoints(series.datapoints,radius,null,w+w/2,true,series.xaxis,series.yaxis,symbol);ctx.strokeStyle="rgba(0,0,0,0.2)";plotPoints(series.datapoints,radius,null,w/2,true,series.xaxis,series.yaxis,symbol)}ctx.lineWidth=lw;ctx.strokeStyle=series.color;plotPoints(series.datapoints,radius,getFillStyle(series.points,series.color),0,false,series.xaxis,series.yaxis,symbol);ctx.restore()}function drawBar(x,y,b,barLeft,barRight,fillStyleCallback,axisx,axisy,c,horizontal,lineWidth){var left,right,bottom,top,drawLeft,drawRight,drawTop,drawBottom,tmp;if(horizontal){drawBottom=drawRight=drawTop=true;drawLeft=false;left=b;right=x;top=y+barLeft;bottom=y+barRight;if(right<left){tmp=right;right=left;left=tmp;drawLeft=true;drawRight=false}}else{drawLeft=drawRight=drawTop=true;drawBottom=false;left=x+barLeft;right=x+barRight;bottom=b;top=y;if(top<bottom){tmp=top;top=bottom;bottom=tmp;drawBottom=true;drawTop=false}}if(right<axisx.min||left>axisx.max||top<axisy.min||bottom>axisy.max)return;if(left<axisx.min){left=axisx.min;drawLeft=false}if(right>axisx.max){right=axisx.max;drawRight=false}if(bottom<axisy.min){bottom=axisy.min;drawBottom=false}if(top>axisy.max){top=axisy.max;drawTop=false}left=axisx.p2c(left);bottom=axisy.p2c(bottom);right=axisx.p2c(right);top=axisy.p2c(top);if(fillStyleCallback){c.fillStyle=fillStyleCallback(bottom,top);c.fillRect(left,top,right-left,bottom-top)}if(lineWidth>0&&(drawLeft||drawRight||drawTop||drawBottom)){c.beginPath();c.moveTo(left,bottom);if(drawLeft)c.lineTo(left,top);else c.moveTo(left,top);if(drawTop)c.lineTo(right,top);else c.moveTo(right,top);if(drawRight)c.lineTo(right,bottom);else c.moveTo(right,bottom);if(drawBottom)c.lineTo(left,bottom);else c.moveTo(left,bottom);c.stroke()}}function drawSeriesBars(series){function plotBars(datapoints,barLeft,barRight,fillStyleCallback,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize;for(var i=0;i<points.length;i+=ps){if(points[i]==null)continue;drawBar(points[i],points[i+1],points[i+2],barLeft,barRight,fillStyleCallback,axisx,axisy,ctx,series.bars.horizontal,series.bars.lineWidth)}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.lineWidth=series.bars.lineWidth;ctx.strokeStyle=series.color;var barLeft;switch(series.bars.align){case"left":barLeft=0;break;case"right":barLeft=-series.bars.barWidth;break;default:barLeft=-series.bars.barWidth/2}var fillStyleCallback=series.bars.fill?function(bottom,top){return getFillStyle(series.bars,series.color,bottom,top)}:null;plotBars(series.datapoints,barLeft,barLeft+series.bars.barWidth,fillStyleCallback,series.xaxis,series.yaxis);ctx.restore()}function getFillStyle(filloptions,seriesColor,bottom,top){var fill=filloptions.fill;if(!fill)return null;if(filloptions.fillColor)return getColorOrGradient(filloptions.fillColor,bottom,top,seriesColor);var c=$.color.parse(seriesColor);c.a=typeof fill=="number"?fill:.4;c.normalize();return c.toString()}function insertLegend(){if(options.legend.container!=null){$(options.legend.container).html("")}else{placeholder.find(".legend").remove()}if(!options.legend.show){return}var fragments=[],entries=[],rowStarted=false,lf=options.legend.labelFormatter,s,label;for(var i=0;i<series.length;++i){s=series[i];if(s.label){label=lf?lf(s.label,s):s.label;if(label){entries.push({label:label,color:s.color})}}}if(options.legend.sorted){if($.isFunction(options.legend.sorted)){entries.sort(options.legend.sorted)}else if(options.legend.sorted=="reverse"){entries.reverse()}else{var ascending=options.legend.sorted!="descending";entries.sort(function(a,b){return a.label==b.label?0:a.label<b.label!=ascending?1:-1})}}for(var i=0;i<entries.length;++i){var entry=entries[i];if(i%options.legend.noColumns==0){if(rowStarted)fragments.push("</tr>");fragments.push("<tr>");rowStarted=true}fragments.push('<td class="legendColorBox"><div style="border:1px solid '+options.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+entry.color+';overflow:hidden"></div></div></td>'+'<td class="legendLabel">'+entry.label+"</td>")}if(rowStarted)fragments.push("</tr>");if(fragments.length==0)return;var table='<table style="font-size:smaller;color:'+options.grid.color+'">'+fragments.join("")+"</table>";if(options.legend.container!=null)$(options.legend.container).html(table);else{var pos="",p=options.legend.position,m=options.legend.margin;if(m[0]==null)m=[m,m];if(p.charAt(0)=="n")pos+="top:"+(m[1]+plotOffset.top)+"px;";else if(p.charAt(0)=="s")pos+="bottom:"+(m[1]+plotOffset.bottom)+"px;";if(p.charAt(1)=="e")pos+="right:"+(m[0]+plotOffset.right)+"px;";else if(p.charAt(1)=="w")pos+="left:"+(m[0]+plotOffset.left)+"px;";var legend=$('<div class="legend">'+table.replace('style="','style="position:absolute;'+pos+";")+"</div>").appendTo(placeholder);if(options.legend.backgroundOpacity!=0){var c=options.legend.backgroundColor;if(c==null){c=options.grid.backgroundColor;if(c&&typeof c=="string")c=$.color.parse(c);else c=$.color.extract(legend,"background-color");c.a=1;c=c.toString()}var div=legend.children();$('<div style="position:absolute;width:'+div.width()+"px;height:"+div.height()+"px;"+pos+"background-color:"+c+';"> </div>').prependTo(legend).css("opacity",options.legend.backgroundOpacity)}}}var highlights=[],redrawTimeout=null;function findNearbyItem(mouseX,mouseY,seriesFilter){var maxDistance=options.grid.mouseActiveRadius,smallestDistance=maxDistance*maxDistance+1,item=null,foundPoint=false,i,j,ps;for(i=series.length-1;i>=0;--i){if(!seriesFilter(series[i]))continue;var s=series[i],axisx=s.xaxis,axisy=s.yaxis,points=s.datapoints.points,mx=axisx.c2p(mouseX),my=axisy.c2p(mouseY),maxx=maxDistance/axisx.scale,maxy=maxDistance/axisy.scale;ps=s.datapoints.pointsize;if(axisx.options.inverseTransform)maxx=Number.MAX_VALUE;if(axisy.options.inverseTransform)maxy=Number.MAX_VALUE;if(s.lines.show||s.points.show){for(j=0;j<points.length;j+=ps){var x=points[j],y=points[j+1];if(x==null)continue;if(x-mx>maxx||x-mx<-maxx||y-my>maxy||y-my<-maxy)continue;var dx=Math.abs(axisx.p2c(x)-mouseX),dy=Math.abs(axisy.p2c(y)-mouseY),dist=dx*dx+dy*dy;if(dist<smallestDistance){smallestDistance=dist;item=[i,j/ps]}}}if(s.bars.show&&!item){var barLeft,barRight;switch(s.bars.align){case"left":barLeft=0;break;case"right":barLeft=-s.bars.barWidth;break;default:barLeft=-s.bars.barWidth/2}barRight=barLeft+s.bars.barWidth;for(j=0;j<points.length;j+=ps){var x=points[j],y=points[j+1],b=points[j+2];if(x==null)continue;if(series[i].bars.horizontal?mx<=Math.max(b,x)&&mx>=Math.min(b,x)&&my>=y+barLeft&&my<=y+barRight:mx>=x+barLeft&&mx<=x+barRight&&my>=Math.min(b,y)&&my<=Math.max(b,y))item=[i,j/ps]}}}if(item){i=item[0];j=item[1];ps=series[i].datapoints.pointsize;return{datapoint:series[i].datapoints.points.slice(j*ps,(j+1)*ps),dataIndex:j,series:series[i],seriesIndex:i}}return null}function onMouseMove(e){if(options.grid.hoverable)triggerClickHoverEvent("plothover",e,function(s){return s["hoverable"]!=false})}function onMouseLeave(e){if(options.grid.hoverable)triggerClickHoverEvent("plothover",e,function(s){return false})}function onClick(e){triggerClickHoverEvent("plotclick",e,function(s){return s["clickable"]!=false})}function triggerClickHoverEvent(eventname,event,seriesFilter){var offset=eventHolder.offset(),canvasX=event.pageX-offset.left-plotOffset.left,canvasY=event.pageY-offset.top-plotOffset.top,pos=canvasToAxisCoords({left:canvasX,top:canvasY});pos.pageX=event.pageX;pos.pageY=event.pageY;var item=findNearbyItem(canvasX,canvasY,seriesFilter);if(item){item.pageX=parseInt(item.series.xaxis.p2c(item.datapoint[0])+offset.left+plotOffset.left,10);item.pageY=parseInt(item.series.yaxis.p2c(item.datapoint[1])+offset.top+plotOffset.top,10)}if(options.grid.autoHighlight){for(var i=0;i<highlights.length;++i){var h=highlights[i];if(h.auto==eventname&&!(item&&h.series==item.series&&h.point[0]==item.datapoint[0]&&h.point[1]==item.datapoint[1]))unhighlight(h.series,h.point)}if(item)highlight(item.series,item.datapoint,eventname)}placeholder.trigger(eventname,[pos,item])}function triggerRedrawOverlay(){var t=options.interaction.redrawOverlayInterval;if(t==-1){drawOverlay();return}if(!redrawTimeout)redrawTimeout=setTimeout(drawOverlay,t)}function drawOverlay(){redrawTimeout=null;octx.save();overlay.clear();octx.translate(plotOffset.left,plotOffset.top);var i,hi;for(i=0;i<highlights.length;++i){hi=highlights[i];if(hi.series.bars.show)drawBarHighlight(hi.series,hi.point);else drawPointHighlight(hi.series,hi.point)}octx.restore();executeHooks(hooks.drawOverlay,[octx])}function highlight(s,point,auto){if(typeof s=="number")s=series[s];if(typeof point=="number"){var ps=s.datapoints.pointsize;point=s.datapoints.points.slice(ps*point,ps*(point+1))}var i=indexOfHighlight(s,point);if(i==-1){highlights.push({series:s,point:point,auto:auto});triggerRedrawOverlay()}else if(!auto)highlights[i].auto=false}function unhighlight(s,point){if(s==null&&point==null){highlights=[];triggerRedrawOverlay();return}if(typeof s=="number")s=series[s];if(typeof point=="number"){var ps=s.datapoints.pointsize;point=s.datapoints.points.slice(ps*point,ps*(point+1))}var i=indexOfHighlight(s,point);if(i!=-1){highlights.splice(i,1);triggerRedrawOverlay()}}function indexOfHighlight(s,p){for(var i=0;i<highlights.length;++i){var h=highlights[i];if(h.series==s&&h.point[0]==p[0]&&h.point[1]==p[1])return i}return-1}function drawPointHighlight(series,point){var x=point[0],y=point[1],axisx=series.xaxis,axisy=series.yaxis,highlightColor=typeof series.highlightColor==="string"?series.highlightColor:$.color.parse(series.color).scale("a",.5).toString();if(x<axisx.min||x>axisx.max||y<axisy.min||y>axisy.max)return;var pointRadius=series.points.radius+series.points.lineWidth/2;octx.lineWidth=pointRadius;octx.strokeStyle=highlightColor;var radius=1.5*pointRadius;x=axisx.p2c(x);y=axisy.p2c(y);octx.beginPath();if(series.points.symbol=="circle")octx.arc(x,y,radius,0,2*Math.PI,false);else series.points.symbol(octx,x,y,radius,false);octx.closePath();octx.stroke()}function drawBarHighlight(series,point){var highlightColor=typeof series.highlightColor==="string"?series.highlightColor:$.color.parse(series.color).scale("a",.5).toString(),fillStyle=highlightColor,barLeft;switch(series.bars.align){case"left":barLeft=0;break;case"right":barLeft=-series.bars.barWidth;break;default:barLeft=-series.bars.barWidth/2}octx.lineWidth=series.bars.lineWidth;octx.strokeStyle=highlightColor;drawBar(point[0],point[1],point[2]||0,barLeft,barLeft+series.bars.barWidth,function(){return fillStyle},series.xaxis,series.yaxis,octx,series.bars.horizontal,series.bars.lineWidth)}function getColorOrGradient(spec,bottom,top,defaultColor){if(typeof spec=="string")return spec;else{var gradient=ctx.createLinearGradient(0,top,0,bottom);for(var i=0,l=spec.colors.length;i<l;++i){var c=spec.colors[i];if(typeof c!="string"){var co=$.color.parse(defaultColor);if(c.brightness!=null)co=co.scale("rgb",c.brightness);if(c.opacity!=null)co.a*=c.opacity;c=co.toString()}gradient.addColorStop(i/(l-1),c)}return gradient}}}$.plot=function(placeholder,data,options){var plot=new Plot($(placeholder),data,options,$.plot.plugins);return plot};$.plot.version="0.8.3";$.plot.plugins=[];$.fn.plot=function(data,options){return this.each(function(){$.plot(this,data,options)})};function floorInBase(n,base){return base*Math.floor(n/base)}})(jQuery); diff --git a/library/cpp/lwtrace/mon/static/js/jquery.flot.navigate.min.js b/library/cpp/lwtrace/mon/static/js/jquery.flot.navigate.min.js index af5ecd21e1..a7593fc8a7 100644 --- a/library/cpp/lwtrace/mon/static/js/jquery.flot.navigate.min.js +++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.navigate.min.js @@ -1,7 +1,7 @@ -/* Javascript plotting library for jQuery, version 0.8.3. - -Copyright (c) 2007-2014 IOLA and Ole Laursen. -Licensed under the MIT license. - -*/ -(function(a){function e(h){var k,j=this,l=h.data||{};if(l.elem)j=h.dragTarget=l.elem,h.dragProxy=d.proxy||j,h.cursorOffsetX=l.pageX-l.left,h.cursorOffsetY=l.pageY-l.top,h.offsetX=h.pageX-h.cursorOffsetX,h.offsetY=h.pageY-h.cursorOffsetY;else if(d.dragging||l.which>0&&h.which!=l.which||a(h.target).is(l.not))return;switch(h.type){case"mousedown":return a.extend(l,a(j).offset(),{elem:j,target:h.target,pageX:h.pageX,pageY:h.pageY}),b.add(document,"mousemove mouseup",e,l),i(j,!1),d.dragging=null,!1;case!d.dragging&&"mousemove":if(g(h.pageX-l.pageX)+g(h.pageY-l.pageY)<l.distance)break;h.target=l.target,k=f(h,"dragstart",j),k!==!1&&(d.dragging=j,d.proxy=h.dragProxy=a(k||j)[0]);case"mousemove":if(d.dragging){if(k=f(h,"drag",j),c.drop&&(c.drop.allowed=k!==!1,c.drop.handler(h)),k!==!1)break;h.type="mouseup"}case"mouseup":b.remove(document,"mousemove mouseup",e),d.dragging&&(c.drop&&c.drop.handler(h),f(h,"dragend",j)),i(j,!0),d.dragging=d.proxy=l.elem=!1}return!0}function f(b,c,d){b.type=c;var e=a.event.dispatch.call(d,b);return e===!1?!1:e||b.result}function g(a){return Math.pow(a,2)}function h(){return d.dragging===!1}function i(a,b){a&&(a.unselectable=b?"off":"on",a.onselectstart=function(){return b},a.style&&(a.style.MozUserSelect=b?"":"none"))}a.fn.drag=function(a,b,c){return b&&this.bind("dragstart",a),c&&this.bind("dragend",c),a?this.bind("drag",b?b:a):this.trigger("drag")};var b=a.event,c=b.special,d=c.drag={not:":input",distance:0,which:1,dragging:!1,setup:function(c){c=a.extend({distance:d.distance,which:d.which,not:d.not},c||{}),c.distance=g(c.distance),b.add(this,"mousedown",e,c),this.attachEvent&&this.attachEvent("ondragstart",h)},teardown:function(){b.remove(this,"mousedown",e),this===d.dragging&&(d.dragging=d.proxy=!1),i(this,!0),this.detachEvent&&this.detachEvent("ondragstart",h)}};c.dragstart=c.dragend={setup:function(){},teardown:function(){}}})(jQuery);(function(d){function e(a){var b=a||window.event,c=[].slice.call(arguments,1),f=0,e=0,g=0,a=d.event.fix(b);a.type="mousewheel";b.wheelDelta&&(f=b.wheelDelta/120);b.detail&&(f=-b.detail/3);g=f;void 0!==b.axis&&b.axis===b.HORIZONTAL_AXIS&&(g=0,e=-1*f);void 0!==b.wheelDeltaY&&(g=b.wheelDeltaY/120);void 0!==b.wheelDeltaX&&(e=-1*b.wheelDeltaX/120);c.unshift(a,f,e,g);return(d.event.dispatch||d.event.handle).apply(this,c)}var c=["DOMMouseScroll","mousewheel"];if(d.event.fixHooks)for(var h=c.length;h;)d.event.fixHooks[c[--h]]=d.event.mouseHooks;d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=c.length;a;)this.addEventListener(c[--a],e,!1);else this.onmousewheel=e},teardown:function(){if(this.removeEventListener)for(var a=c.length;a;)this.removeEventListener(c[--a],e,!1);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);(function($){var options={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:false,trigger:"dblclick",amount:1.5},pan:{interactive:false,cursor:"move",frameRate:20}};function init(plot){function onZoomClick(e,zoomOut){var c=plot.offset();c.left=e.pageX-c.left;c.top=e.pageY-c.top;if(zoomOut)plot.zoomOut({center:c});else plot.zoom({center:c})}function onMouseWheel(e,delta){e.preventDefault();onZoomClick(e,delta<0);return false}var prevCursor="default",prevPageX=0,prevPageY=0,panTimeout=null;function onDragStart(e){if(e.which!=1)return false;var c=plot.getPlaceholder().css("cursor");if(c)prevCursor=c;plot.getPlaceholder().css("cursor",plot.getOptions().pan.cursor);prevPageX=e.pageX;prevPageY=e.pageY}function onDrag(e){var frameRate=plot.getOptions().pan.frameRate;if(panTimeout||!frameRate)return;panTimeout=setTimeout(function(){plot.pan({left:prevPageX-e.pageX,top:prevPageY-e.pageY});prevPageX=e.pageX;prevPageY=e.pageY;panTimeout=null},1/frameRate*1e3)}function onDragEnd(e){if(panTimeout){clearTimeout(panTimeout);panTimeout=null}plot.getPlaceholder().css("cursor",prevCursor);plot.pan({left:prevPageX-e.pageX,top:prevPageY-e.pageY})}function bindEvents(plot,eventHolder){var o=plot.getOptions();if(o.zoom.interactive){eventHolder[o.zoom.trigger](onZoomClick);eventHolder.mousewheel(onMouseWheel)}if(o.pan.interactive){eventHolder.bind("dragstart",{distance:10},onDragStart);eventHolder.bind("drag",onDrag);eventHolder.bind("dragend",onDragEnd)}}plot.zoomOut=function(args){if(!args)args={};if(!args.amount)args.amount=plot.getOptions().zoom.amount;args.amount=1/args.amount;plot.zoom(args)};plot.zoom=function(args){if(!args)args={};var c=args.center,amount=args.amount||plot.getOptions().zoom.amount,w=plot.width(),h=plot.height();if(!c)c={left:w/2,top:h/2};var xf=c.left/w,yf=c.top/h,minmax={x:{min:c.left-xf*w/amount,max:c.left+(1-xf)*w/amount},y:{min:c.top-yf*h/amount,max:c.top+(1-yf)*h/amount}};$.each(plot.getAxes(),function(_,axis){var opts=axis.options,min=minmax[axis.direction].min,max=minmax[axis.direction].max,zr=opts.zoomRange,pr=opts.panRange;if(zr===false)return;min=axis.c2p(min);max=axis.c2p(max);if(min>max){var tmp=min;min=max;max=tmp}if(pr){if(pr[0]!=null&&min<pr[0]){min=pr[0]}if(pr[1]!=null&&max>pr[1]){max=pr[1]}}var range=max-min;if(zr&&(zr[0]!=null&&range<zr[0]&&amount>1||zr[1]!=null&&range>zr[1]&&amount<1))return;opts.min=min;opts.max=max});plot.setupGrid();plot.draw();if(!args.preventEvent)plot.getPlaceholder().trigger("plotzoom",[plot,args])};plot.pan=function(args){var delta={x:+args.left,y:+args.top};if(isNaN(delta.x))delta.x=0;if(isNaN(delta.y))delta.y=0;$.each(plot.getAxes(),function(_,axis){var opts=axis.options,min,max,d=delta[axis.direction];min=axis.c2p(axis.p2c(axis.min)+d),max=axis.c2p(axis.p2c(axis.max)+d);var pr=opts.panRange;if(pr===false)return;if(pr){if(pr[0]!=null&&pr[0]>min){d=pr[0]-min;min+=d;max+=d}if(pr[1]!=null&&pr[1]<max){d=pr[1]-max;min+=d;max+=d}}opts.min=min;opts.max=max});plot.setupGrid();plot.draw();if(!args.preventEvent)plot.getPlaceholder().trigger("plotpan",[plot,args])};function shutdown(plot,eventHolder){eventHolder.unbind(plot.getOptions().zoom.trigger,onZoomClick);eventHolder.unbind("mousewheel",onMouseWheel);eventHolder.unbind("dragstart",onDragStart);eventHolder.unbind("drag",onDrag);eventHolder.unbind("dragend",onDragEnd);if(panTimeout)clearTimeout(panTimeout)}plot.hooks.bindEvents.push(bindEvents);plot.hooks.shutdown.push(shutdown)}$.plot.plugins.push({init:init,options:options,name:"navigate",version:"1.3"})})(jQuery); +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ +(function(a){function e(h){var k,j=this,l=h.data||{};if(l.elem)j=h.dragTarget=l.elem,h.dragProxy=d.proxy||j,h.cursorOffsetX=l.pageX-l.left,h.cursorOffsetY=l.pageY-l.top,h.offsetX=h.pageX-h.cursorOffsetX,h.offsetY=h.pageY-h.cursorOffsetY;else if(d.dragging||l.which>0&&h.which!=l.which||a(h.target).is(l.not))return;switch(h.type){case"mousedown":return a.extend(l,a(j).offset(),{elem:j,target:h.target,pageX:h.pageX,pageY:h.pageY}),b.add(document,"mousemove mouseup",e,l),i(j,!1),d.dragging=null,!1;case!d.dragging&&"mousemove":if(g(h.pageX-l.pageX)+g(h.pageY-l.pageY)<l.distance)break;h.target=l.target,k=f(h,"dragstart",j),k!==!1&&(d.dragging=j,d.proxy=h.dragProxy=a(k||j)[0]);case"mousemove":if(d.dragging){if(k=f(h,"drag",j),c.drop&&(c.drop.allowed=k!==!1,c.drop.handler(h)),k!==!1)break;h.type="mouseup"}case"mouseup":b.remove(document,"mousemove mouseup",e),d.dragging&&(c.drop&&c.drop.handler(h),f(h,"dragend",j)),i(j,!0),d.dragging=d.proxy=l.elem=!1}return!0}function f(b,c,d){b.type=c;var e=a.event.dispatch.call(d,b);return e===!1?!1:e||b.result}function g(a){return Math.pow(a,2)}function h(){return d.dragging===!1}function i(a,b){a&&(a.unselectable=b?"off":"on",a.onselectstart=function(){return b},a.style&&(a.style.MozUserSelect=b?"":"none"))}a.fn.drag=function(a,b,c){return b&&this.bind("dragstart",a),c&&this.bind("dragend",c),a?this.bind("drag",b?b:a):this.trigger("drag")};var b=a.event,c=b.special,d=c.drag={not:":input",distance:0,which:1,dragging:!1,setup:function(c){c=a.extend({distance:d.distance,which:d.which,not:d.not},c||{}),c.distance=g(c.distance),b.add(this,"mousedown",e,c),this.attachEvent&&this.attachEvent("ondragstart",h)},teardown:function(){b.remove(this,"mousedown",e),this===d.dragging&&(d.dragging=d.proxy=!1),i(this,!0),this.detachEvent&&this.detachEvent("ondragstart",h)}};c.dragstart=c.dragend={setup:function(){},teardown:function(){}}})(jQuery);(function(d){function e(a){var b=a||window.event,c=[].slice.call(arguments,1),f=0,e=0,g=0,a=d.event.fix(b);a.type="mousewheel";b.wheelDelta&&(f=b.wheelDelta/120);b.detail&&(f=-b.detail/3);g=f;void 0!==b.axis&&b.axis===b.HORIZONTAL_AXIS&&(g=0,e=-1*f);void 0!==b.wheelDeltaY&&(g=b.wheelDeltaY/120);void 0!==b.wheelDeltaX&&(e=-1*b.wheelDeltaX/120);c.unshift(a,f,e,g);return(d.event.dispatch||d.event.handle).apply(this,c)}var c=["DOMMouseScroll","mousewheel"];if(d.event.fixHooks)for(var h=c.length;h;)d.event.fixHooks[c[--h]]=d.event.mouseHooks;d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=c.length;a;)this.addEventListener(c[--a],e,!1);else this.onmousewheel=e},teardown:function(){if(this.removeEventListener)for(var a=c.length;a;)this.removeEventListener(c[--a],e,!1);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);(function($){var options={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:false,trigger:"dblclick",amount:1.5},pan:{interactive:false,cursor:"move",frameRate:20}};function init(plot){function onZoomClick(e,zoomOut){var c=plot.offset();c.left=e.pageX-c.left;c.top=e.pageY-c.top;if(zoomOut)plot.zoomOut({center:c});else plot.zoom({center:c})}function onMouseWheel(e,delta){e.preventDefault();onZoomClick(e,delta<0);return false}var prevCursor="default",prevPageX=0,prevPageY=0,panTimeout=null;function onDragStart(e){if(e.which!=1)return false;var c=plot.getPlaceholder().css("cursor");if(c)prevCursor=c;plot.getPlaceholder().css("cursor",plot.getOptions().pan.cursor);prevPageX=e.pageX;prevPageY=e.pageY}function onDrag(e){var frameRate=plot.getOptions().pan.frameRate;if(panTimeout||!frameRate)return;panTimeout=setTimeout(function(){plot.pan({left:prevPageX-e.pageX,top:prevPageY-e.pageY});prevPageX=e.pageX;prevPageY=e.pageY;panTimeout=null},1/frameRate*1e3)}function onDragEnd(e){if(panTimeout){clearTimeout(panTimeout);panTimeout=null}plot.getPlaceholder().css("cursor",prevCursor);plot.pan({left:prevPageX-e.pageX,top:prevPageY-e.pageY})}function bindEvents(plot,eventHolder){var o=plot.getOptions();if(o.zoom.interactive){eventHolder[o.zoom.trigger](onZoomClick);eventHolder.mousewheel(onMouseWheel)}if(o.pan.interactive){eventHolder.bind("dragstart",{distance:10},onDragStart);eventHolder.bind("drag",onDrag);eventHolder.bind("dragend",onDragEnd)}}plot.zoomOut=function(args){if(!args)args={};if(!args.amount)args.amount=plot.getOptions().zoom.amount;args.amount=1/args.amount;plot.zoom(args)};plot.zoom=function(args){if(!args)args={};var c=args.center,amount=args.amount||plot.getOptions().zoom.amount,w=plot.width(),h=plot.height();if(!c)c={left:w/2,top:h/2};var xf=c.left/w,yf=c.top/h,minmax={x:{min:c.left-xf*w/amount,max:c.left+(1-xf)*w/amount},y:{min:c.top-yf*h/amount,max:c.top+(1-yf)*h/amount}};$.each(plot.getAxes(),function(_,axis){var opts=axis.options,min=minmax[axis.direction].min,max=minmax[axis.direction].max,zr=opts.zoomRange,pr=opts.panRange;if(zr===false)return;min=axis.c2p(min);max=axis.c2p(max);if(min>max){var tmp=min;min=max;max=tmp}if(pr){if(pr[0]!=null&&min<pr[0]){min=pr[0]}if(pr[1]!=null&&max>pr[1]){max=pr[1]}}var range=max-min;if(zr&&(zr[0]!=null&&range<zr[0]&&amount>1||zr[1]!=null&&range>zr[1]&&amount<1))return;opts.min=min;opts.max=max});plot.setupGrid();plot.draw();if(!args.preventEvent)plot.getPlaceholder().trigger("plotzoom",[plot,args])};plot.pan=function(args){var delta={x:+args.left,y:+args.top};if(isNaN(delta.x))delta.x=0;if(isNaN(delta.y))delta.y=0;$.each(plot.getAxes(),function(_,axis){var opts=axis.options,min,max,d=delta[axis.direction];min=axis.c2p(axis.p2c(axis.min)+d),max=axis.c2p(axis.p2c(axis.max)+d);var pr=opts.panRange;if(pr===false)return;if(pr){if(pr[0]!=null&&pr[0]>min){d=pr[0]-min;min+=d;max+=d}if(pr[1]!=null&&pr[1]<max){d=pr[1]-max;min+=d;max+=d}}opts.min=min;opts.max=max});plot.setupGrid();plot.draw();if(!args.preventEvent)plot.getPlaceholder().trigger("plotpan",[plot,args])};function shutdown(plot,eventHolder){eventHolder.unbind(plot.getOptions().zoom.trigger,onZoomClick);eventHolder.unbind("mousewheel",onMouseWheel);eventHolder.unbind("dragstart",onDragStart);eventHolder.unbind("drag",onDrag);eventHolder.unbind("dragend",onDragEnd);if(panTimeout)clearTimeout(panTimeout)}plot.hooks.bindEvents.push(bindEvents);plot.hooks.shutdown.push(shutdown)}$.plot.plugins.push({init:init,options:options,name:"navigate",version:"1.3"})})(jQuery); diff --git a/library/cpp/lwtrace/mon/static/js/jquery.flot.selection.min.js b/library/cpp/lwtrace/mon/static/js/jquery.flot.selection.min.js index a0154fbc5b..da6185b1ef 100644 --- a/library/cpp/lwtrace/mon/static/js/jquery.flot.selection.min.js +++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.selection.min.js @@ -1,7 +1,7 @@ -/* Javascript plotting library for jQuery, version 0.8.3. - -Copyright (c) 2007-2014 IOLA and Ole Laursen. -Licensed under the MIT license. - -*/ -(function($){function init(plot){var selection={first:{x:-1,y:-1},second:{x:-1,y:-1},show:false,active:false};var savedhandlers={};var mouseUpHandler=null;function onMouseMove(e){if(selection.active){updateSelection(e);plot.getPlaceholder().trigger("plotselecting",[getSelection()])}}function onMouseDown(e){if(e.which!=1)return;document.body.focus();if(document.onselectstart!==undefined&&savedhandlers.onselectstart==null){savedhandlers.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!==undefined&&savedhandlers.ondrag==null){savedhandlers.ondrag=document.ondrag;document.ondrag=function(){return false}}setSelectionPos(selection.first,e);selection.active=true;mouseUpHandler=function(e){onMouseUp(e)};$(document).one("mouseup",mouseUpHandler)}function onMouseUp(e){mouseUpHandler=null;if(document.onselectstart!==undefined)document.onselectstart=savedhandlers.onselectstart;if(document.ondrag!==undefined)document.ondrag=savedhandlers.ondrag;selection.active=false;updateSelection(e);if(selectionIsSane())triggerSelectedEvent();else{plot.getPlaceholder().trigger("plotunselected",[]);plot.getPlaceholder().trigger("plotselecting",[null])}return false}function getSelection(){if(!selectionIsSane())return null;if(!selection.show)return null;var r={},c1=selection.first,c2=selection.second;$.each(plot.getAxes(),function(name,axis){if(axis.used){var p1=axis.c2p(c1[axis.direction]),p2=axis.c2p(c2[axis.direction]);r[name]={from:Math.min(p1,p2),to:Math.max(p1,p2)}}});return r}function triggerSelectedEvent(){var r=getSelection();plot.getPlaceholder().trigger("plotselected",[r]);if(r.xaxis&&r.yaxis)plot.getPlaceholder().trigger("selected",[{x1:r.xaxis.from,y1:r.yaxis.from,x2:r.xaxis.to,y2:r.yaxis.to}])}function clamp(min,value,max){return value<min?min:value>max?max:value}function setSelectionPos(pos,e){var o=plot.getOptions();var offset=plot.getPlaceholder().offset();var plotOffset=plot.getPlotOffset();pos.x=clamp(0,e.pageX-offset.left-plotOffset.left,plot.width());pos.y=clamp(0,e.pageY-offset.top-plotOffset.top,plot.height());if(o.selection.mode=="y")pos.x=pos==selection.first?0:plot.width();if(o.selection.mode=="x")pos.y=pos==selection.first?0:plot.height()}function updateSelection(pos){if(pos.pageX==null)return;setSelectionPos(selection.second,pos);if(selectionIsSane()){selection.show=true;plot.triggerRedrawOverlay()}else clearSelection(true)}function clearSelection(preventEvent){if(selection.show){selection.show=false;plot.triggerRedrawOverlay();if(!preventEvent)plot.getPlaceholder().trigger("plotunselected",[])}}function extractRange(ranges,coord){var axis,from,to,key,axes=plot.getAxes();for(var k in axes){axis=axes[k];if(axis.direction==coord){key=coord+axis.n+"axis";if(!ranges[key]&&axis.n==1)key=coord+"axis";if(ranges[key]){from=ranges[key].from;to=ranges[key].to;break}}}if(!ranges[key]){axis=coord=="x"?plot.getXAxes()[0]:plot.getYAxes()[0];from=ranges[coord+"1"];to=ranges[coord+"2"]}if(from!=null&&to!=null&&from>to){var tmp=from;from=to;to=tmp}return{from:from,to:to,axis:axis}}function setSelection(ranges,preventEvent){var axis,range,o=plot.getOptions();if(o.selection.mode=="y"){selection.first.x=0;selection.second.x=plot.width()}else{range=extractRange(ranges,"x");selection.first.x=range.axis.p2c(range.from);selection.second.x=range.axis.p2c(range.to)}if(o.selection.mode=="x"){selection.first.y=0;selection.second.y=plot.height()}else{range=extractRange(ranges,"y");selection.first.y=range.axis.p2c(range.from);selection.second.y=range.axis.p2c(range.to)}selection.show=true;plot.triggerRedrawOverlay();if(!preventEvent&&selectionIsSane())triggerSelectedEvent()}function selectionIsSane(){var minSize=plot.getOptions().selection.minSize;return Math.abs(selection.second.x-selection.first.x)>=minSize&&Math.abs(selection.second.y-selection.first.y)>=minSize}plot.clearSelection=clearSelection;plot.setSelection=setSelection;plot.getSelection=getSelection;plot.hooks.bindEvents.push(function(plot,eventHolder){var o=plot.getOptions();if(o.selection.mode!=null){eventHolder.mousemove(onMouseMove);eventHolder.mousedown(onMouseDown)}});plot.hooks.drawOverlay.push(function(plot,ctx){if(selection.show&&selectionIsSane()){var plotOffset=plot.getPlotOffset();var o=plot.getOptions();ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var c=$.color.parse(o.selection.color);ctx.strokeStyle=c.scale("a",.8).toString();ctx.lineWidth=1;ctx.lineJoin=o.selection.shape;ctx.fillStyle=c.scale("a",.4).toString();var x=Math.min(selection.first.x,selection.second.x)+.5,y=Math.min(selection.first.y,selection.second.y)+.5,w=Math.abs(selection.second.x-selection.first.x)-1,h=Math.abs(selection.second.y-selection.first.y)-1;ctx.fillRect(x,y,w,h);ctx.strokeRect(x,y,w,h);ctx.restore()}});plot.hooks.shutdown.push(function(plot,eventHolder){eventHolder.unbind("mousemove",onMouseMove);eventHolder.unbind("mousedown",onMouseDown);if(mouseUpHandler)$(document).unbind("mouseup",mouseUpHandler)})}$.plot.plugins.push({init:init,options:{selection:{mode:null,color:"#e8cfac",shape:"round",minSize:5}},name:"selection",version:"1.1"})})(jQuery);
\ No newline at end of file +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ +(function($){function init(plot){var selection={first:{x:-1,y:-1},second:{x:-1,y:-1},show:false,active:false};var savedhandlers={};var mouseUpHandler=null;function onMouseMove(e){if(selection.active){updateSelection(e);plot.getPlaceholder().trigger("plotselecting",[getSelection()])}}function onMouseDown(e){if(e.which!=1)return;document.body.focus();if(document.onselectstart!==undefined&&savedhandlers.onselectstart==null){savedhandlers.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!==undefined&&savedhandlers.ondrag==null){savedhandlers.ondrag=document.ondrag;document.ondrag=function(){return false}}setSelectionPos(selection.first,e);selection.active=true;mouseUpHandler=function(e){onMouseUp(e)};$(document).one("mouseup",mouseUpHandler)}function onMouseUp(e){mouseUpHandler=null;if(document.onselectstart!==undefined)document.onselectstart=savedhandlers.onselectstart;if(document.ondrag!==undefined)document.ondrag=savedhandlers.ondrag;selection.active=false;updateSelection(e);if(selectionIsSane())triggerSelectedEvent();else{plot.getPlaceholder().trigger("plotunselected",[]);plot.getPlaceholder().trigger("plotselecting",[null])}return false}function getSelection(){if(!selectionIsSane())return null;if(!selection.show)return null;var r={},c1=selection.first,c2=selection.second;$.each(plot.getAxes(),function(name,axis){if(axis.used){var p1=axis.c2p(c1[axis.direction]),p2=axis.c2p(c2[axis.direction]);r[name]={from:Math.min(p1,p2),to:Math.max(p1,p2)}}});return r}function triggerSelectedEvent(){var r=getSelection();plot.getPlaceholder().trigger("plotselected",[r]);if(r.xaxis&&r.yaxis)plot.getPlaceholder().trigger("selected",[{x1:r.xaxis.from,y1:r.yaxis.from,x2:r.xaxis.to,y2:r.yaxis.to}])}function clamp(min,value,max){return value<min?min:value>max?max:value}function setSelectionPos(pos,e){var o=plot.getOptions();var offset=plot.getPlaceholder().offset();var plotOffset=plot.getPlotOffset();pos.x=clamp(0,e.pageX-offset.left-plotOffset.left,plot.width());pos.y=clamp(0,e.pageY-offset.top-plotOffset.top,plot.height());if(o.selection.mode=="y")pos.x=pos==selection.first?0:plot.width();if(o.selection.mode=="x")pos.y=pos==selection.first?0:plot.height()}function updateSelection(pos){if(pos.pageX==null)return;setSelectionPos(selection.second,pos);if(selectionIsSane()){selection.show=true;plot.triggerRedrawOverlay()}else clearSelection(true)}function clearSelection(preventEvent){if(selection.show){selection.show=false;plot.triggerRedrawOverlay();if(!preventEvent)plot.getPlaceholder().trigger("plotunselected",[])}}function extractRange(ranges,coord){var axis,from,to,key,axes=plot.getAxes();for(var k in axes){axis=axes[k];if(axis.direction==coord){key=coord+axis.n+"axis";if(!ranges[key]&&axis.n==1)key=coord+"axis";if(ranges[key]){from=ranges[key].from;to=ranges[key].to;break}}}if(!ranges[key]){axis=coord=="x"?plot.getXAxes()[0]:plot.getYAxes()[0];from=ranges[coord+"1"];to=ranges[coord+"2"]}if(from!=null&&to!=null&&from>to){var tmp=from;from=to;to=tmp}return{from:from,to:to,axis:axis}}function setSelection(ranges,preventEvent){var axis,range,o=plot.getOptions();if(o.selection.mode=="y"){selection.first.x=0;selection.second.x=plot.width()}else{range=extractRange(ranges,"x");selection.first.x=range.axis.p2c(range.from);selection.second.x=range.axis.p2c(range.to)}if(o.selection.mode=="x"){selection.first.y=0;selection.second.y=plot.height()}else{range=extractRange(ranges,"y");selection.first.y=range.axis.p2c(range.from);selection.second.y=range.axis.p2c(range.to)}selection.show=true;plot.triggerRedrawOverlay();if(!preventEvent&&selectionIsSane())triggerSelectedEvent()}function selectionIsSane(){var minSize=plot.getOptions().selection.minSize;return Math.abs(selection.second.x-selection.first.x)>=minSize&&Math.abs(selection.second.y-selection.first.y)>=minSize}plot.clearSelection=clearSelection;plot.setSelection=setSelection;plot.getSelection=getSelection;plot.hooks.bindEvents.push(function(plot,eventHolder){var o=plot.getOptions();if(o.selection.mode!=null){eventHolder.mousemove(onMouseMove);eventHolder.mousedown(onMouseDown)}});plot.hooks.drawOverlay.push(function(plot,ctx){if(selection.show&&selectionIsSane()){var plotOffset=plot.getPlotOffset();var o=plot.getOptions();ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var c=$.color.parse(o.selection.color);ctx.strokeStyle=c.scale("a",.8).toString();ctx.lineWidth=1;ctx.lineJoin=o.selection.shape;ctx.fillStyle=c.scale("a",.4).toString();var x=Math.min(selection.first.x,selection.second.x)+.5,y=Math.min(selection.first.y,selection.second.y)+.5,w=Math.abs(selection.second.x-selection.first.x)-1,h=Math.abs(selection.second.y-selection.first.y)-1;ctx.fillRect(x,y,w,h);ctx.strokeRect(x,y,w,h);ctx.restore()}});plot.hooks.shutdown.push(function(plot,eventHolder){eventHolder.unbind("mousemove",onMouseMove);eventHolder.unbind("mousedown",onMouseDown);if(mouseUpHandler)$(document).unbind("mouseup",mouseUpHandler)})}$.plot.plugins.push({init:init,options:{selection:{mode:null,color:"#e8cfac",shape:"round",minSize:5}},name:"selection",version:"1.1"})})(jQuery);
\ No newline at end of file diff --git a/library/cpp/lwtrace/mon/static/js/jquery.min.js b/library/cpp/lwtrace/mon/static/js/jquery.min.js index ee48790811..c82a235fee 100644 --- a/library/cpp/lwtrace/mon/static/js/jquery.min.js +++ b/library/cpp/lwtrace/mon/static/js/jquery.min.js @@ -1,5 +1,5 @@ -(function(window,undefined){var rootjQuery,readyList,document=window.document,location=window.location,navigator=window.navigator,_jQuery=window.jQuery,_$=window.$,core_push=Array.prototype.push,core_slice=Array.prototype.slice,core_indexOf=Array.prototype.indexOf,core_toString=Object.prototype.toString,core_hasOwn=Object.prototype.hasOwnProperty,core_trim=String.prototype.trim,jQuery=function(selector,context){return new jQuery.fn.init(selector,context,rootjQuery)},core_pnum=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,core_rnotwhite=/\S/,core_rspace=/\s+/,rtrim=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,rquickExpr=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,rsingleTag=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,rvalidchars=/^[\],:{}\s]*$/,rvalidbraces=/(?:^|:|,)(?:\s*\[)+/g,rvalidescape=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,rvalidtokens=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,rmsPrefix=/^-ms-/,rdashAlpha=/-([\da-z])/gi,fcamelCase=function(all,letter){return(letter+"").toUpperCase()},DOMContentLoaded=function(){if(document.addEventListener){document.removeEventListener("DOMContentLoaded",DOMContentLoaded,false);jQuery.ready()}else if(document.readyState==="complete"){document.detachEvent("onreadystatechange",DOMContentLoaded);jQuery.ready()}},class2type={};jQuery.fn=jQuery.prototype={constructor:jQuery,init:function(selector,context,rootjQuery){var match,elem,ret,doc;if(!selector){return this}if(selector.nodeType){this.context=this[0]=selector;this.length=1;return this}if(typeof selector==="string"){if(selector.charAt(0)==="<"&&selector.charAt(selector.length-1)===">"&&selector.length>=3){match=[null,selector,null]}else{match=rquickExpr.exec(selector)}if(match&&(match[1]||!context)){if(match[1]){context=context instanceof jQuery?context[0]:context;doc=context&&context.nodeType?context.ownerDocument||context:document;selector=jQuery.parseHTML(match[1],doc,true);if(rsingleTag.test(match[1])&&jQuery.isPlainObject(context)){this.attr.call(selector,context,true)}return jQuery.merge(this,selector)}else{elem=document.getElementById(match[2]);if(elem&&elem.parentNode){if(elem.id!==match[2]){return rootjQuery.find(selector)}this.length=1;this[0]=elem}this.context=document;this.selector=selector;return this}}else if(!context||context.jquery){return(context||rootjQuery).find(selector)}else{return this.constructor(context).find(selector)}}else if(jQuery.isFunction(selector)){return rootjQuery.ready(selector)}if(selector.selector!==undefined){this.selector=selector.selector;this.context=selector.context}return jQuery.makeArray(selector,this)},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return core_slice.call(this)},get:function(num){return num==null?this.toArray():num<0?this[this.length+num]:this[num]},pushStack:function(elems,name,selector){var ret=jQuery.merge(this.constructor(),elems);ret.prevObject=this;ret.context=this.context;if(name==="find"){ret.selector=this.selector+(this.selector?" ":"")+selector}else if(name){ret.selector=this.selector+"."+name+"("+selector+")"}return ret},each:function(callback,args){return jQuery.each(this,callback,args)},ready:function(fn){jQuery.ready.promise().done(fn);return this},eq:function(i){i=+i;return i===-1?this.slice(i):this.slice(i,i+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(core_slice.apply(this,arguments),"slice",core_slice.call(arguments).join(","))},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem)}))},end:function(){return this.prevObject||this.constructor(null)},push:core_push,sort:[].sort,splice:[].splice};jQuery.fn.init.prototype=jQuery.fn;jQuery.extend=jQuery.fn.extend=function(){var options,name,src,copy,copyIsArray,clone,target=arguments[0]||{},i=1,length=arguments.length,deep=false;if(typeof target==="boolean"){deep=target;target=arguments[1]||{};i=2}if(typeof target!=="object"&&!jQuery.isFunction(target)){target={}}if(length===i){target=this;--i}for(;i<length;i++){if((options=arguments[i])!=null){for(name in options){src=target[name];copy=options[name];if(target===copy){continue}if(deep&©&&(jQuery.isPlainObject(copy)||(copyIsArray=jQuery.isArray(copy)))){if(copyIsArray){copyIsArray=false;clone=src&&jQuery.isArray(src)?src:[]}else{clone=src&&jQuery.isPlainObject(src)?src:{}}target[name]=jQuery.extend(deep,clone,copy)}else if(copy!==undefined){target[name]=copy}}}}return target};jQuery.extend({noConflict:function(deep){if(window.$===jQuery){window.$=_$}if(deep&&window.jQuery===jQuery){window.jQuery=_jQuery}return jQuery},isReady:false,readyWait:1,holdReady:function(hold){if(hold){jQuery.readyWait++}else{jQuery.ready(true)}},ready:function(wait){if(wait===true?--jQuery.readyWait:jQuery.isReady){return}if(!document.body){return setTimeout(jQuery.ready,1)}jQuery.isReady=true;if(wait!==true&&--jQuery.readyWait>0){return}readyList.resolveWith(document,[jQuery]);if(jQuery.fn.trigger){jQuery(document).trigger("ready").off("ready")}},isFunction:function(obj){return jQuery.type(obj)==="function"},isArray:Array.isArray||function(obj){return jQuery.type(obj)==="array"},isWindow:function(obj){return obj!=null&&obj==obj.window},isNumeric:function(obj){return!isNaN(parseFloat(obj))&&isFinite(obj)},type:function(obj){return obj==null?String(obj):class2type[core_toString.call(obj)]||"object"},isPlainObject:function(obj){if(!obj||jQuery.type(obj)!=="object"||obj.nodeType||jQuery.isWindow(obj)){return false}try{if(obj.constructor&&!core_hasOwn.call(obj,"constructor")&&!core_hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){return false}}catch(e){return false}var key;for(key in obj){}return key===undefined||core_hasOwn.call(obj,key)},isEmptyObject:function(obj){var name;for(name in obj){return false}return true},error:function(msg){throw new Error(msg)},parseHTML:function(data,context,scripts){var parsed;if(!data||typeof data!=="string"){return null}if(typeof context==="boolean"){scripts=context;context=0}context=context||document;if(parsed=rsingleTag.exec(data)){return[context.createElement(parsed[1])]}parsed=jQuery.buildFragment([data],context,scripts?null:[]);return jQuery.merge([],(parsed.cacheable?jQuery.clone(parsed.fragment):parsed.fragment).childNodes)},parseJSON:function(data){if(!data||typeof data!=="string"){return null}data=jQuery.trim(data);if(window.JSON&&window.JSON.parse){return window.JSON.parse(data)}if(rvalidchars.test(data.replace(rvalidescape,"@").replace(rvalidtokens,"]").replace(rvalidbraces,""))){return new Function("return "+data)()}jQuery.error("Invalid JSON: "+data)},parseXML:function(data){var xml,tmp;if(!data||typeof data!=="string"){return null}try{if(window.DOMParser){tmp=new DOMParser;xml=tmp.parseFromString(data,"text/xml")}else{xml=new ActiveXObject("Microsoft.XMLDOM");xml.async="false";xml.loadXML(data)}}catch(e){xml=undefined}if(!xml||!xml.documentElement||xml.getElementsByTagName("parsererror").length){jQuery.error("Invalid XML: "+data)}return xml},noop:function(){},globalEval:function(data){if(data&&core_rnotwhite.test(data)){(window.execScript||function(data){window["eval"].call(window,data)})(data)}},camelCase:function(string){return string.replace(rmsPrefix,"ms-").replace(rdashAlpha,fcamelCase)},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toLowerCase()===name.toLowerCase()},each:function(obj,callback,args){var name,i=0,length=obj.length,isObj=length===undefined||jQuery.isFunction(obj);if(args){if(isObj){for(name in obj){if(callback.apply(obj[name],args)===false){break}}}else{for(;i<length;){if(callback.apply(obj[i++],args)===false){break}}}}else{if(isObj){for(name in obj){if(callback.call(obj[name],name,obj[name])===false){break}}}else{for(;i<length;){if(callback.call(obj[i],i,obj[i++])===false){break}}}}return obj},trim:core_trim&&!core_trim.call(" ")?function(text){return text==null?"":core_trim.call(text)}:function(text){return text==null?"":(text+"").replace(rtrim,"")},makeArray:function(arr,results){var type,ret=results||[];if(arr!=null){type=jQuery.type(arr);if(arr.length==null||type==="string"||type==="function"||type==="regexp"||jQuery.isWindow(arr)){core_push.call(ret,arr)}else{jQuery.merge(ret,arr)}}return ret},inArray:function(elem,arr,i){var len;if(arr){if(core_indexOf){return core_indexOf.call(arr,elem,i)}len=arr.length;i=i?i<0?Math.max(0,len+i):i:0;for(;i<len;i++){if(i in arr&&arr[i]===elem){return i}}}return-1},merge:function(first,second){var l=second.length,i=first.length,j=0;if(typeof l==="number"){for(;j<l;j++){first[i++]=second[j]}}else{while(second[j]!==undefined){first[i++]=second[j++]}}first.length=i;return first},grep:function(elems,callback,inv){var retVal,ret=[],i=0,length=elems.length;inv=!!inv;for(;i<length;i++){retVal=!!callback(elems[i],i);if(inv!==retVal){ret.push(elems[i])}}return ret},map:function(elems,callback,arg){var value,key,ret=[],i=0,length=elems.length,isArray=elems instanceof jQuery||length!==undefined&&typeof length==="number"&&(length>0&&elems[0]&&elems[length-1]||length===0||jQuery.isArray(elems));if(isArray){for(;i<length;i++){value=callback(elems[i],i,arg);if(value!=null){ret[ret.length]=value}}}else{for(key in elems){value=callback(elems[key],key,arg);if(value!=null){ret[ret.length]=value}}}return ret.concat.apply([],ret)},guid:1,proxy:function(fn,context){var tmp,args,proxy;if(typeof context==="string"){tmp=fn[context];context=fn;fn=tmp}if(!jQuery.isFunction(fn)){return undefined}args=core_slice.call(arguments,2);proxy=function(){return fn.apply(context,args.concat(core_slice.call(arguments)))};proxy.guid=fn.guid=fn.guid||jQuery.guid++;return proxy},access:function(elems,fn,key,value,chainable,emptyGet,pass){var exec,bulk=key==null,i=0,length=elems.length;if(key&&typeof key==="object"){for(i in key){jQuery.access(elems,fn,i,key[i],1,emptyGet,value)}chainable=1}else if(value!==undefined){exec=pass===undefined&&jQuery.isFunction(value);if(bulk){if(exec){exec=fn;fn=function(elem,key,value){return exec.call(jQuery(elem),value)}}else{fn.call(elems,value);fn=null}}if(fn){for(;i<length;i++){fn(elems[i],key,exec?value.call(elems[i],i,fn(elems[i],key)):value,pass)}}chainable=1}return chainable?elems:bulk?fn.call(elems):length?fn(elems[0],key):emptyGet},now:function(){return(new Date).getTime()}});jQuery.ready.promise=function(obj){if(!readyList){readyList=jQuery.Deferred();if(document.readyState==="complete"){setTimeout(jQuery.ready,1)}else if(document.addEventListener){document.addEventListener("DOMContentLoaded",DOMContentLoaded,false);window.addEventListener("load",jQuery.ready,false)}else{document.attachEvent("onreadystatechange",DOMContentLoaded);window.attachEvent("onload",jQuery.ready);var top=false;try{top=window.frameElement==null&&document.documentElement}catch(e){}if(top&&top.doScroll){(function doScrollCheck(){if(!jQuery.isReady){try{top.doScroll("left")}catch(e){return setTimeout(doScrollCheck,50)}jQuery.ready()}})()}}}return readyList.promise(obj)};jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(i,name){class2type["[object "+name+"]"]=name.toLowerCase()});rootjQuery=jQuery(document);var optionsCache={};function createOptions(options){var object=optionsCache[options]={};jQuery.each(options.split(core_rspace),function(_,flag){object[flag]=true});return object}jQuery.Callbacks=function(options){options=typeof options==="string"?optionsCache[options]||createOptions(options):jQuery.extend({},options);var memory,fired,firing,firingStart,firingLength,firingIndex,list=[],stack=!options.once&&[],fire=function(data){memory=options.memory&&data;fired=true;firingIndex=firingStart||0;firingStart=0;firingLength=list.length;firing=true;for(;list&&firingIndex<firingLength;firingIndex++){if(list[firingIndex].apply(data[0],data[1])===false&&options.stopOnFalse){memory=false;break}}firing=false;if(list){if(stack){if(stack.length){fire(stack.shift())}}else if(memory){list=[]}else{self.disable()}}},self={add:function(){if(list){var start=list.length;(function add(args){jQuery.each(args,function(_,arg){var type=jQuery.type(arg);if(type==="function"){if(!options.unique||!self.has(arg)){list.push(arg)}}else if(arg&&arg.length&&type!=="string"){add(arg)}})})(arguments);if(firing){firingLength=list.length}else if(memory){firingStart=start;fire(memory)}}return this},remove:function(){if(list){jQuery.each(arguments,function(_,arg){var index;while((index=jQuery.inArray(arg,list,index))>-1){list.splice(index,1);if(firing){if(index<=firingLength){firingLength--}if(index<=firingIndex){firingIndex--}}}})}return this},has:function(fn){return jQuery.inArray(fn,list)>-1},empty:function(){list=[];return this},disable:function(){list=stack=memory=undefined;return this},disabled:function(){return!list},lock:function(){stack=undefined;if(!memory){self.disable()}return this},locked:function(){return!stack},fireWith:function(context,args){args=args||[];args=[context,args.slice?args.slice():args];if(list&&(!fired||stack)){if(firing){stack.push(args)}else{fire(args)}}return this},fire:function(){self.fireWith(this,arguments);return this},fired:function(){return!!fired}};return self};jQuery.extend({Deferred:function(func){var tuples=[["resolve","done",jQuery.Callbacks("once memory"),"resolved"],["reject","fail",jQuery.Callbacks("once memory"),"rejected"],["notify","progress",jQuery.Callbacks("memory")]],state="pending",promise={state:function(){return state},always:function(){deferred.done(arguments).fail(arguments);return this},then:function(){var fns=arguments;return jQuery.Deferred(function(newDefer){jQuery.each(tuples,function(i,tuple){var action=tuple[0],fn=fns[i];deferred[tuple[1]](jQuery.isFunction(fn)?function(){var returned=fn.apply(this,arguments);if(returned&&jQuery.isFunction(returned.promise)){returned.promise().done(newDefer.resolve).fail(newDefer.reject).progress(newDefer.notify)}else{newDefer[action+"With"](this===deferred?newDefer:this,[returned])}}:newDefer[action])});fns=null}).promise()},promise:function(obj){return obj!=null?jQuery.extend(obj,promise):promise}},deferred={};promise.pipe=promise.then;jQuery.each(tuples,function(i,tuple){var list=tuple[2],stateString=tuple[3];promise[tuple[1]]=list.add;if(stateString){list.add(function(){state=stateString},tuples[i^1][2].disable,tuples[2][2].lock)}deferred[tuple[0]]=list.fire;deferred[tuple[0]+"With"]=list.fireWith});promise.promise(deferred);if(func){func.call(deferred,deferred)}return deferred},when:function(subordinate){var i=0,resolveValues=core_slice.call(arguments),length=resolveValues.length,remaining=length!==1||subordinate&&jQuery.isFunction(subordinate.promise)?length:0,deferred=remaining===1?subordinate:jQuery.Deferred(),updateFunc=function(i,contexts,values){return function(value){contexts[i]=this;values[i]=arguments.length>1?core_slice.call(arguments):value;if(values===progressValues){deferred.notifyWith(contexts,values)}else if(!--remaining){deferred.resolveWith(contexts,values)}}},progressValues,progressContexts,resolveContexts;if(length>1){progressValues=new Array(length);progressContexts=new Array(length);resolveContexts=new Array(length);for(;i<length;i++){if(resolveValues[i]&&jQuery.isFunction(resolveValues[i].promise)){resolveValues[i].promise().done(updateFunc(i,resolveContexts,resolveValues)).fail(deferred.reject).progress(updateFunc(i,progressContexts,progressValues))}else{--remaining}}}if(!remaining){deferred.resolveWith(resolveContexts,resolveValues)}return deferred.promise()}});jQuery.support=function(){var support,all,a,select,opt,input,fragment,eventName,i,isSupported,clickFn,div=document.createElement("div");div.setAttribute("className","t");div.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";all=div.getElementsByTagName("*");a=div.getElementsByTagName("a")[0];if(!all||!a||!all.length){return{}}select=document.createElement("select");opt=select.appendChild(document.createElement("option"));input=div.getElementsByTagName("input")[0];a.style.cssText="top:1px;float:left;opacity:.5";support={leadingWhitespace:div.firstChild.nodeType===3,tbody:!div.getElementsByTagName("tbody").length,htmlSerialize:!!div.getElementsByTagName("link").length,style:/top/.test(a.getAttribute("style")),hrefNormalized:a.getAttribute("href")==="/a",opacity:/^0.5/.test(a.style.opacity),cssFloat:!!a.style.cssFloat,checkOn:input.value==="on",optSelected:opt.selected,getSetAttribute:div.className!=="t",enctype:!!document.createElement("form").enctype,html5Clone:document.createElement("nav").cloneNode(true).outerHTML!=="<:nav></:nav>",boxModel:document.compatMode==="CSS1Compat",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true,boxSizingReliable:true,pixelPosition:false};input.checked=true;support.noCloneChecked=input.cloneNode(true).checked;select.disabled=true;support.optDisabled=!opt.disabled;try{delete div.test}catch(e){support.deleteExpando=false}if(!div.addEventListener&&div.attachEvent&&div.fireEvent){div.attachEvent("onclick",clickFn=function(){support.noCloneEvent=false});div.cloneNode(true).fireEvent("onclick");div.detachEvent("onclick",clickFn)}input=document.createElement("input");input.value="t";input.setAttribute("type","radio");support.radioValue=input.value==="t";input.setAttribute("checked","checked");input.setAttribute("name","t");div.appendChild(input);fragment=document.createDocumentFragment();fragment.appendChild(div.lastChild);support.checkClone=fragment.cloneNode(true).cloneNode(true).lastChild.checked;support.appendChecked=input.checked;fragment.removeChild(input);fragment.appendChild(div);if(div.attachEvent){for(i in{submit:true,change:true,focusin:true}){eventName="on"+i;isSupported=eventName in div;if(!isSupported){div.setAttribute(eventName,"return;");isSupported=typeof div[eventName]==="function"}support[i+"Bubbles"]=isSupported}}jQuery(function(){var container,div,tds,marginDiv,divReset="padding:0;margin:0;border:0;display:block;overflow:hidden;",body=document.getElementsByTagName("body")[0];if(!body){return}container=document.createElement("div");container.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";body.insertBefore(container,body.firstChild);div=document.createElement("div");container.appendChild(div);div.innerHTML="<table><tr><td></td><td>t</td></tr></table>";tds=div.getElementsByTagName("td");tds[0].style.cssText="padding:0;margin:0;border:0;display:none";isSupported=tds[0].offsetHeight===0;tds[0].style.display="";tds[1].style.display="none";support.reliableHiddenOffsets=isSupported&&tds[0].offsetHeight===0;div.innerHTML="";div.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";support.boxSizing=div.offsetWidth===4;support.doesNotIncludeMarginInBodyOffset=body.offsetTop!==1;if(window.getComputedStyle){support.pixelPosition=(window.getComputedStyle(div,null)||{}).top!=="1%";support.boxSizingReliable=(window.getComputedStyle(div,null)||{width:"4px"}).width==="4px";marginDiv=document.createElement("div");marginDiv.style.cssText=div.style.cssText=divReset;marginDiv.style.marginRight=marginDiv.style.width="0";div.style.width="1px";div.appendChild(marginDiv);support.reliableMarginRight=!parseFloat((window.getComputedStyle(marginDiv,null)||{}).marginRight)}if(typeof div.style.zoom!=="undefined"){div.innerHTML="";div.style.cssText=divReset+"width:1px;padding:1px;display:inline;zoom:1";support.inlineBlockNeedsLayout=div.offsetWidth===3;div.style.display="block";div.style.overflow="visible";div.innerHTML="<div></div>";div.firstChild.style.width="5px";support.shrinkWrapBlocks=div.offsetWidth!==3;container.style.zoom=1}body.removeChild(container);container=div=tds=marginDiv=null});fragment.removeChild(div);all=a=select=opt=input=fragment=div=null;return support}();var rbrace=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,rmultiDash=/([A-Z])/g;jQuery.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(jQuery.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(elem){elem=elem.nodeType?jQuery.cache[elem[jQuery.expando]]:elem[jQuery.expando];return!!elem&&!isEmptyDataObject(elem)},data:function(elem,name,data,pvt){if(!jQuery.acceptData(elem)){return}var thisCache,ret,internalKey=jQuery.expando,getByName=typeof name==="string",isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[internalKey]:elem[internalKey]&&internalKey;if((!id||!cache[id]||!pvt&&!cache[id].data)&&getByName&&data===undefined){return}if(!id){if(isNode){elem[internalKey]=id=jQuery.deletedIds.pop()||jQuery.guid++}else{id=internalKey}}if(!cache[id]){cache[id]={};if(!isNode){cache[id].toJSON=jQuery.noop}}if(typeof name==="object"||typeof name==="function"){if(pvt){cache[id]=jQuery.extend(cache[id],name)}else{cache[id].data=jQuery.extend(cache[id].data,name)}}thisCache=cache[id];if(!pvt){if(!thisCache.data){thisCache.data={}}thisCache=thisCache.data}if(data!==undefined){thisCache[jQuery.camelCase(name)]=data}if(getByName){ret=thisCache[name];if(ret==null){ret=thisCache[jQuery.camelCase(name)]}}else{ret=thisCache}return ret},removeData:function(elem,name,pvt){if(!jQuery.acceptData(elem)){return}var thisCache,i,l,isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[jQuery.expando]:jQuery.expando;if(!cache[id]){return}if(name){thisCache=pvt?cache[id]:cache[id].data;if(thisCache){if(!jQuery.isArray(name)){if(name in thisCache){name=[name]}else{name=jQuery.camelCase(name);if(name in thisCache){name=[name]}else{name=name.split(" ")}}}for(i=0,l=name.length;i<l;i++){delete thisCache[name[i]]}if(!(pvt?isEmptyDataObject:jQuery.isEmptyObject)(thisCache)){return}}}if(!pvt){delete cache[id].data;if(!isEmptyDataObject(cache[id])){return}}if(isNode){jQuery.cleanData([elem],true)}else if(jQuery.support.deleteExpando||cache!=cache.window){delete cache[id]}else{cache[id]=null}},_data:function(elem,name,data){return jQuery.data(elem,name,data,true)},acceptData:function(elem){var noData=elem.nodeName&&jQuery.noData[elem.nodeName.toLowerCase()];return!noData||noData!==true&&elem.getAttribute("classid")===noData}});jQuery.fn.extend({data:function(key,value){var parts,part,attr,name,l,elem=this[0],i=0,data=null;if(key===undefined){if(this.length){data=jQuery.data(elem);if(elem.nodeType===1&&!jQuery._data(elem,"parsedAttrs")){attr=elem.attributes;for(l=attr.length;i<l;i++){name=attr[i].name;if(!name.indexOf("data-")){name=jQuery.camelCase(name.substring(5));dataAttr(elem,name,data[name])}}jQuery._data(elem,"parsedAttrs",true)}}return data}if(typeof key==="object"){return this.each(function(){jQuery.data(this,key)})}parts=key.split(".",2);parts[1]=parts[1]?"."+parts[1]:"";part=parts[1]+"!";return jQuery.access(this,function(value){if(value===undefined){data=this.triggerHandler("getData"+part,[parts[0]]);if(data===undefined&&elem){data=jQuery.data(elem,key);data=dataAttr(elem,key,data)}return data===undefined&&parts[1]?this.data(parts[0]):data}parts[1]=value;this.each(function(){var self=jQuery(this);self.triggerHandler("setData"+part,parts);jQuery.data(this,key,value);self.triggerHandler("changeData"+part,parts)})},null,value,arguments.length>1,null,false)},removeData:function(key){return this.each(function(){jQuery.removeData(this,key)})}});function dataAttr(elem,key,data){if(data===undefined&&elem.nodeType===1){var name="data-"+key.replace(rmultiDash,"-$1").toLowerCase();data=elem.getAttribute(name);if(typeof data==="string"){try{data=data==="true"?true:data==="false"?false:data==="null"?null:+data+""===data?+data:rbrace.test(data)?jQuery.parseJSON(data):data}catch(e){}jQuery.data(elem,key,data)}else{data=undefined}}return data}function isEmptyDataObject(obj){var name;for(name in obj){if(name==="data"&&jQuery.isEmptyObject(obj[name])){continue}if(name!=="toJSON"){return false}}return true}jQuery.extend({queue:function(elem,type,data){var queue;if(elem){type=(type||"fx")+"queue";queue=jQuery._data(elem,type);if(data){if(!queue||jQuery.isArray(data)){queue=jQuery._data(elem,type,jQuery.makeArray(data))}else{queue.push(data)}}return queue||[]}},dequeue:function(elem,type){type=type||"fx";var queue=jQuery.queue(elem,type),startLength=queue.length,fn=queue.shift(),hooks=jQuery._queueHooks(elem,type),next=function(){jQuery.dequeue(elem,type)};if(fn==="inprogress"){fn=queue.shift();startLength--}if(fn){if(type==="fx"){queue.unshift("inprogress")}delete hooks.stop;fn.call(elem,next,hooks)}if(!startLength&&hooks){hooks.empty.fire()}},_queueHooks:function(elem,type){var key=type+"queueHooks";return jQuery._data(elem,key)||jQuery._data(elem,key,{empty:jQuery.Callbacks("once memory").add(function(){jQuery.removeData(elem,type+"queue",true);jQuery.removeData(elem,key,true)})})}});jQuery.fn.extend({queue:function(type,data){var setter=2;if(typeof type!=="string"){data=type;type="fx";setter--}if(arguments.length<setter){return jQuery.queue(this[0],type)}return data===undefined?this:this.each(function(){var queue=jQuery.queue(this,type,data);jQuery._queueHooks(this,type);if(type==="fx"&&queue[0]!=="inprogress"){jQuery.dequeue(this,type)}})},dequeue:function(type){return this.each(function(){jQuery.dequeue(this,type)})},delay:function(time,type){time=jQuery.fx?jQuery.fx.speeds[time]||time:time;type=type||"fx";return this.queue(type,function(next,hooks){var timeout=setTimeout(next,time);hooks.stop=function(){clearTimeout(timeout)}})},clearQueue:function(type){return this.queue(type||"fx",[])},promise:function(type,obj){var tmp,count=1,defer=jQuery.Deferred(),elements=this,i=this.length,resolve=function(){if(!--count){defer.resolveWith(elements,[elements])}};if(typeof type!=="string"){obj=type;type=undefined}type=type||"fx";while(i--){tmp=jQuery._data(elements[i],type+"queueHooks");if(tmp&&tmp.empty){count++;tmp.empty.add(resolve)}}resolve();return defer.promise(obj)}});var nodeHook,boolHook,fixSpecified,rclass=/[\t\r\n]/g,rreturn=/\r/g,rtype=/^(?:button|input)$/i,rfocusable=/^(?:button|input|object|select|textarea)$/i,rclickable=/^a(?:rea|)$/i,rboolean=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,getSetAttribute=jQuery.support.getSetAttribute;jQuery.fn.extend({attr:function(name,value){return jQuery.access(this,jQuery.attr,name,value,arguments.length>1)},removeAttr:function(name){return this.each(function(){jQuery.removeAttr(this,name)})},prop:function(name,value){return jQuery.access(this,jQuery.prop,name,value,arguments.length>1)},removeProp:function(name){name=jQuery.propFix[name]||name;return this.each(function(){try{this[name]=undefined;delete this[name]}catch(e){}})},addClass:function(value){var classNames,i,l,elem,setClass,c,cl;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).addClass(value.call(this,j,this.className))})}if(value&&typeof value==="string"){classNames=value.split(core_rspace);for(i=0,l=this.length;i<l;i++){elem=this[i];if(elem.nodeType===1){if(!elem.className&&classNames.length===1){elem.className=value}else{setClass=" "+elem.className+" ";for(c=0,cl=classNames.length;c<cl;c++){if(setClass.indexOf(" "+classNames[c]+" ")<0){setClass+=classNames[c]+" "}}elem.className=jQuery.trim(setClass)}}}}return this},removeClass:function(value){var removes,className,elem,c,cl,i,l;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).removeClass(value.call(this,j,this.className))})}if(value&&typeof value==="string"||value===undefined){removes=(value||"").split(core_rspace);for(i=0,l=this.length;i<l;i++){elem=this[i];if(elem.nodeType===1&&elem.className){className=(" "+elem.className+" ").replace(rclass," ");for(c=0,cl=removes.length;c<cl;c++){while(className.indexOf(" "+removes[c]+" ")>=0){className=className.replace(" "+removes[c]+" "," ")}}elem.className=value?jQuery.trim(className):""}}}return this},toggleClass:function(value,stateVal){var type=typeof value,isBool=typeof stateVal==="boolean";if(jQuery.isFunction(value)){return this.each(function(i){jQuery(this).toggleClass(value.call(this,i,this.className,stateVal),stateVal)})}return this.each(function(){if(type==="string"){var className,i=0,self=jQuery(this),state=stateVal,classNames=value.split(core_rspace);while(className=classNames[i++]){state=isBool?state:!self.hasClass(className);self[state?"addClass":"removeClass"](className)}}else if(type==="undefined"||type==="boolean"){if(this.className){jQuery._data(this,"__className__",this.className)}this.className=this.className||value===false?"":jQuery._data(this,"__className__")||""}})},hasClass:function(selector){var className=" "+selector+" ",i=0,l=this.length;for(;i<l;i++){if(this[i].nodeType===1&&(" "+this[i].className+" ").replace(rclass," ").indexOf(className)>=0){return true}}return false},val:function(value){var hooks,ret,isFunction,elem=this[0];if(!arguments.length){if(elem){hooks=jQuery.valHooks[elem.type]||jQuery.valHooks[elem.nodeName.toLowerCase()];if(hooks&&"get"in hooks&&(ret=hooks.get(elem,"value"))!==undefined){return ret}ret=elem.value;return typeof ret==="string"?ret.replace(rreturn,""):ret==null?"":ret}return}isFunction=jQuery.isFunction(value);return this.each(function(i){var val,self=jQuery(this);if(this.nodeType!==1){return}if(isFunction){val=value.call(this,i,self.val())}else{val=value}if(val==null){val=""}else if(typeof val==="number"){val+=""}else if(jQuery.isArray(val)){val=jQuery.map(val,function(value){return value==null?"":value+""})}hooks=jQuery.valHooks[this.type]||jQuery.valHooks[this.nodeName.toLowerCase()];if(!hooks||!("set"in hooks)||hooks.set(this,val,"value")===undefined){this.value=val}})}});jQuery.extend({valHooks:{option:{get:function(elem){var val=elem.attributes.value;return!val||val.specified?elem.value:elem.text}},select:{get:function(elem){var value,option,options=elem.options,index=elem.selectedIndex,one=elem.type==="select-one"||index<0,values=one?null:[],max=one?index+1:options.length,i=index<0?max:one?index:0;for(;i<max;i++){option=options[i];if((option.selected||i===index)&&(jQuery.support.optDisabled?!option.disabled:option.getAttribute("disabled")===null)&&(!option.parentNode.disabled||!jQuery.nodeName(option.parentNode,"optgroup"))){value=jQuery(option).val();if(one){return value}values.push(value)}}return values},set:function(elem,value){var values=jQuery.makeArray(value);jQuery(elem).find("option").each(function(){this.selected=jQuery.inArray(jQuery(this).val(),values)>=0});if(!values.length){elem.selectedIndex=-1}return values}}},attrFn:{},attr:function(elem,name,value,pass){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return}if(pass&&jQuery.isFunction(jQuery.fn[name])){return jQuery(elem)[name](value)}if(typeof elem.getAttribute==="undefined"){return jQuery.prop(elem,name,value)}notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=name.toLowerCase();hooks=jQuery.attrHooks[name]||(rboolean.test(name)?boolHook:nodeHook)}if(value!==undefined){if(value===null){jQuery.removeAttr(elem,name);return}else if(hooks&&"set"in hooks&¬xml&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{elem.setAttribute(name,value+"");return value}}else if(hooks&&"get"in hooks&¬xml&&(ret=hooks.get(elem,name))!==null){return ret}else{ret=elem.getAttribute(name);return ret===null?undefined:ret}},removeAttr:function(elem,value){var propName,attrNames,name,isBool,i=0;if(value&&elem.nodeType===1){attrNames=value.split(core_rspace);for(;i<attrNames.length;i++){name=attrNames[i];if(name){propName=jQuery.propFix[name]||name;isBool=rboolean.test(name);if(!isBool){jQuery.attr(elem,name,"")}elem.removeAttribute(getSetAttribute?name:propName);if(isBool&&propName in elem){elem[propName]=false}}}}},attrHooks:{type:{set:function(elem,value){if(rtype.test(elem.nodeName)&&elem.parentNode){jQuery.error("type property can't be changed") -}else if(!jQuery.support.radioValue&&value==="radio"&&jQuery.nodeName(elem,"input")){var val=elem.value;elem.setAttribute("type",value);if(val){elem.value=val}return value}}},value:{get:function(elem,name){if(nodeHook&&jQuery.nodeName(elem,"button")){return nodeHook.get(elem,name)}return name in elem?elem.value:null},set:function(elem,value,name){if(nodeHook&&jQuery.nodeName(elem,"button")){return nodeHook.set(elem,value,name)}elem.value=value}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(elem,name,value){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return}notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=jQuery.propFix[name]||name;hooks=jQuery.propHooks[name]}if(value!==undefined){if(hooks&&"set"in hooks&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{return elem[name]=value}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,name))!==null){return ret}else{return elem[name]}}},propHooks:{tabIndex:{get:function(elem){var attributeNode=elem.getAttributeNode("tabindex");return attributeNode&&attributeNode.specified?parseInt(attributeNode.value,10):rfocusable.test(elem.nodeName)||rclickable.test(elem.nodeName)&&elem.href?0:undefined}}}});boolHook={get:function(elem,name){var attrNode,property=jQuery.prop(elem,name);return property===true||typeof property!=="boolean"&&(attrNode=elem.getAttributeNode(name))&&attrNode.nodeValue!==false?name.toLowerCase():undefined},set:function(elem,value,name){var propName;if(value===false){jQuery.removeAttr(elem,name)}else{propName=jQuery.propFix[name]||name;if(propName in elem){elem[propName]=true}elem.setAttribute(name,name.toLowerCase())}return name}};if(!getSetAttribute){fixSpecified={name:true,id:true,coords:true};nodeHook=jQuery.valHooks.button={get:function(elem,name){var ret;ret=elem.getAttributeNode(name);return ret&&(fixSpecified[name]?ret.value!=="":ret.specified)?ret.value:undefined},set:function(elem,value,name){var ret=elem.getAttributeNode(name);if(!ret){ret=document.createAttribute(name);elem.setAttributeNode(ret)}return ret.value=value+""}};jQuery.each(["width","height"],function(i,name){jQuery.attrHooks[name]=jQuery.extend(jQuery.attrHooks[name],{set:function(elem,value){if(value===""){elem.setAttribute(name,"auto");return value}}})});jQuery.attrHooks.contenteditable={get:nodeHook.get,set:function(elem,value,name){if(value===""){value="false"}nodeHook.set(elem,value,name)}}}if(!jQuery.support.hrefNormalized){jQuery.each(["href","src","width","height"],function(i,name){jQuery.attrHooks[name]=jQuery.extend(jQuery.attrHooks[name],{get:function(elem){var ret=elem.getAttribute(name,2);return ret===null?undefined:ret}})})}if(!jQuery.support.style){jQuery.attrHooks.style={get:function(elem){return elem.style.cssText.toLowerCase()||undefined},set:function(elem,value){return elem.style.cssText=value+""}}}if(!jQuery.support.optSelected){jQuery.propHooks.selected=jQuery.extend(jQuery.propHooks.selected,{get:function(elem){var parent=elem.parentNode;if(parent){parent.selectedIndex;if(parent.parentNode){parent.parentNode.selectedIndex}}return null}})}if(!jQuery.support.enctype){jQuery.propFix.enctype="encoding"}if(!jQuery.support.checkOn){jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]={get:function(elem){return elem.getAttribute("value")===null?"on":elem.value}}})}jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]=jQuery.extend(jQuery.valHooks[this],{set:function(elem,value){if(jQuery.isArray(value)){return elem.checked=jQuery.inArray(jQuery(elem).val(),value)>=0}}})});var rformElems=/^(?:textarea|input|select)$/i,rtypenamespace=/^([^\.]*|)(?:\.(.+)|)$/,rhoverHack=/(?:^|\s)hover(\.\S+|)\b/,rkeyEvent=/^key/,rmouseEvent=/^(?:mouse|contextmenu)|click/,rfocusMorph=/^(?:focusinfocus|focusoutblur)$/,hoverHack=function(events){return jQuery.event.special.hover?events:events.replace(rhoverHack,"mouseenter$1 mouseleave$1")};jQuery.event={add:function(elem,types,handler,data,selector){var elemData,eventHandle,events,t,tns,type,namespaces,handleObj,handleObjIn,handlers,special;if(elem.nodeType===3||elem.nodeType===8||!types||!handler||!(elemData=jQuery._data(elem))){return}if(handler.handler){handleObjIn=handler;handler=handleObjIn.handler;selector=handleObjIn.selector}if(!handler.guid){handler.guid=jQuery.guid++}events=elemData.events;if(!events){elemData.events=events={}}eventHandle=elemData.handle;if(!eventHandle){elemData.handle=eventHandle=function(e){return typeof jQuery!=="undefined"&&(!e||jQuery.event.triggered!==e.type)?jQuery.event.dispatch.apply(eventHandle.elem,arguments):undefined};eventHandle.elem=elem}types=jQuery.trim(hoverHack(types)).split(" ");for(t=0;t<types.length;t++){tns=rtypenamespace.exec(types[t])||[];type=tns[1];namespaces=(tns[2]||"").split(".").sort();special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;special=jQuery.event.special[type]||{};handleObj=jQuery.extend({type:type,origType:tns[1],data:data,handler:handler,guid:handler.guid,selector:selector,needsContext:selector&&jQuery.expr.match.needsContext.test(selector),namespace:namespaces.join(".")},handleObjIn);handlers=events[type];if(!handlers){handlers=events[type]=[];handlers.delegateCount=0;if(!special.setup||special.setup.call(elem,data,namespaces,eventHandle)===false){if(elem.addEventListener){elem.addEventListener(type,eventHandle,false)}else if(elem.attachEvent){elem.attachEvent("on"+type,eventHandle)}}}if(special.add){special.add.call(elem,handleObj);if(!handleObj.handler.guid){handleObj.handler.guid=handler.guid}}if(selector){handlers.splice(handlers.delegateCount++,0,handleObj)}else{handlers.push(handleObj)}jQuery.event.global[type]=true}elem=null},global:{},remove:function(elem,types,handler,selector,mappedTypes){var t,tns,type,origType,namespaces,origCount,j,events,special,eventType,handleObj,elemData=jQuery.hasData(elem)&&jQuery._data(elem);if(!elemData||!(events=elemData.events)){return}types=jQuery.trim(hoverHack(types||"")).split(" ");for(t=0;t<types.length;t++){tns=rtypenamespace.exec(types[t])||[];type=origType=tns[1];namespaces=tns[2];if(!type){for(type in events){jQuery.event.remove(elem,type+types[t],handler,selector,true)}continue}special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;eventType=events[type]||[];origCount=eventType.length;namespaces=namespaces?new RegExp("(^|\\.)"+namespaces.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(j=0;j<eventType.length;j++){handleObj=eventType[j];if((mappedTypes||origType===handleObj.origType)&&(!handler||handler.guid===handleObj.guid)&&(!namespaces||namespaces.test(handleObj.namespace))&&(!selector||selector===handleObj.selector||selector==="**"&&handleObj.selector)){eventType.splice(j--,1);if(handleObj.selector){eventType.delegateCount--}if(special.remove){special.remove.call(elem,handleObj)}}}if(eventType.length===0&&origCount!==eventType.length){if(!special.teardown||special.teardown.call(elem,namespaces,elemData.handle)===false){jQuery.removeEvent(elem,type,elemData.handle)}delete events[type]}}if(jQuery.isEmptyObject(events)){delete elemData.handle;jQuery.removeData(elem,"events",true)}},customEvent:{getData:true,setData:true,changeData:true},trigger:function(event,data,elem,onlyHandlers){if(elem&&(elem.nodeType===3||elem.nodeType===8)){return}var cache,exclusive,i,cur,old,ontype,special,handle,eventPath,bubbleType,type=event.type||event,namespaces=[];if(rfocusMorph.test(type+jQuery.event.triggered)){return}if(type.indexOf("!")>=0){type=type.slice(0,-1);exclusive=true}if(type.indexOf(".")>=0){namespaces=type.split(".");type=namespaces.shift();namespaces.sort()}if((!elem||jQuery.event.customEvent[type])&&!jQuery.event.global[type]){return}event=typeof event==="object"?event[jQuery.expando]?event:new jQuery.Event(type,event):new jQuery.Event(type);event.type=type;event.isTrigger=true;event.exclusive=exclusive;event.namespace=namespaces.join(".");event.namespace_re=event.namespace?new RegExp("(^|\\.)"+namespaces.join("\\.(?:.*\\.|)")+"(\\.|$)"):null;ontype=type.indexOf(":")<0?"on"+type:"";if(!elem){cache=jQuery.cache;for(i in cache){if(cache[i].events&&cache[i].events[type]){jQuery.event.trigger(event,data,cache[i].handle.elem,true)}}return}event.result=undefined;if(!event.target){event.target=elem}data=data!=null?jQuery.makeArray(data):[];data.unshift(event);special=jQuery.event.special[type]||{};if(special.trigger&&special.trigger.apply(elem,data)===false){return}eventPath=[[elem,special.bindType||type]];if(!onlyHandlers&&!special.noBubble&&!jQuery.isWindow(elem)){bubbleType=special.delegateType||type;cur=rfocusMorph.test(bubbleType+type)?elem:elem.parentNode;for(old=elem;cur;cur=cur.parentNode){eventPath.push([cur,bubbleType]);old=cur}if(old===(elem.ownerDocument||document)){eventPath.push([old.defaultView||old.parentWindow||window,bubbleType])}}for(i=0;i<eventPath.length&&!event.isPropagationStopped();i++){cur=eventPath[i][0];event.type=eventPath[i][1];handle=(jQuery._data(cur,"events")||{})[event.type]&&jQuery._data(cur,"handle");if(handle){handle.apply(cur,data)}handle=ontype&&cur[ontype];if(handle&&jQuery.acceptData(cur)&&handle.apply&&handle.apply(cur,data)===false){event.preventDefault()}}event.type=type;if(!onlyHandlers&&!event.isDefaultPrevented()){if((!special._default||special._default.apply(elem.ownerDocument,data)===false)&&!(type==="click"&&jQuery.nodeName(elem,"a"))&&jQuery.acceptData(elem)){if(ontype&&elem[type]&&(type!=="focus"&&type!=="blur"||event.target.offsetWidth!==0)&&!jQuery.isWindow(elem)){old=elem[ontype];if(old){elem[ontype]=null}jQuery.event.triggered=type;elem[type]();jQuery.event.triggered=undefined;if(old){elem[ontype]=old}}}}return event.result},dispatch:function(event){event=jQuery.event.fix(event||window.event);var i,j,cur,ret,selMatch,matched,matches,handleObj,sel,related,handlers=(jQuery._data(this,"events")||{})[event.type]||[],delegateCount=handlers.delegateCount,args=core_slice.call(arguments),run_all=!event.exclusive&&!event.namespace,special=jQuery.event.special[event.type]||{},handlerQueue=[];args[0]=event;event.delegateTarget=this;if(special.preDispatch&&special.preDispatch.call(this,event)===false){return}if(delegateCount&&!(event.button&&event.type==="click")){for(cur=event.target;cur!=this;cur=cur.parentNode||this){if(cur.disabled!==true||event.type!=="click"){selMatch={};matches=[];for(i=0;i<delegateCount;i++){handleObj=handlers[i];sel=handleObj.selector;if(selMatch[sel]===undefined){selMatch[sel]=handleObj.needsContext?jQuery(sel,this).index(cur)>=0:jQuery.find(sel,this,null,[cur]).length}if(selMatch[sel]){matches.push(handleObj)}}if(matches.length){handlerQueue.push({elem:cur,matches:matches})}}}}if(handlers.length>delegateCount){handlerQueue.push({elem:this,matches:handlers.slice(delegateCount)})}for(i=0;i<handlerQueue.length&&!event.isPropagationStopped();i++){matched=handlerQueue[i];event.currentTarget=matched.elem;for(j=0;j<matched.matches.length&&!event.isImmediatePropagationStopped();j++){handleObj=matched.matches[j];if(run_all||!event.namespace&&!handleObj.namespace||event.namespace_re&&event.namespace_re.test(handleObj.namespace)){event.data=handleObj.data;event.handleObj=handleObj;ret=((jQuery.event.special[handleObj.origType]||{}).handle||handleObj.handler).apply(matched.elem,args);if(ret!==undefined){event.result=ret;if(ret===false){event.preventDefault();event.stopPropagation()}}}}}if(special.postDispatch){special.postDispatch.call(this,event)}return event.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(event,original){if(event.which==null){event.which=original.charCode!=null?original.charCode:original.keyCode}return event}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(event,original){var eventDoc,doc,body,button=original.button,fromElement=original.fromElement;if(event.pageX==null&&original.clientX!=null){eventDoc=event.target.ownerDocument||document;doc=eventDoc.documentElement;body=eventDoc.body;event.pageX=original.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc&&doc.clientLeft||body&&body.clientLeft||0);event.pageY=original.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc&&doc.clientTop||body&&body.clientTop||0)}if(!event.relatedTarget&&fromElement){event.relatedTarget=fromElement===event.target?original.toElement:fromElement}if(!event.which&&button!==undefined){event.which=button&1?1:button&2?3:button&4?2:0}return event}},fix:function(event){if(event[jQuery.expando]){return event}var i,prop,originalEvent=event,fixHook=jQuery.event.fixHooks[event.type]||{},copy=fixHook.props?this.props.concat(fixHook.props):this.props;event=jQuery.Event(originalEvent);for(i=copy.length;i;){prop=copy[--i];event[prop]=originalEvent[prop]}if(!event.target){event.target=originalEvent.srcElement||document}if(event.target.nodeType===3){event.target=event.target.parentNode}event.metaKey=!!event.metaKey;return fixHook.filter?fixHook.filter(event,originalEvent):event},special:{load:{noBubble:true},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(data,namespaces,eventHandle){if(jQuery.isWindow(this)){this.onbeforeunload=eventHandle}},teardown:function(namespaces,eventHandle){if(this.onbeforeunload===eventHandle){this.onbeforeunload=null}}}},simulate:function(type,elem,event,bubble){var e=jQuery.extend(new jQuery.Event,event,{type:type,isSimulated:true,originalEvent:{}});if(bubble){jQuery.event.trigger(e,null,elem)}else{jQuery.event.dispatch.call(elem,e)}if(e.isDefaultPrevented()){event.preventDefault()}}};jQuery.event.handle=jQuery.event.dispatch;jQuery.removeEvent=document.removeEventListener?function(elem,type,handle){if(elem.removeEventListener){elem.removeEventListener(type,handle,false)}}:function(elem,type,handle){var name="on"+type;if(elem.detachEvent){if(typeof elem[name]==="undefined"){elem[name]=null}elem.detachEvent(name,handle)}};jQuery.Event=function(src,props){if(!(this instanceof jQuery.Event)){return new jQuery.Event(src,props)}if(src&&src.type){this.originalEvent=src;this.type=src.type;this.isDefaultPrevented=src.defaultPrevented||src.returnValue===false||src.getPreventDefault&&src.getPreventDefault()?returnTrue:returnFalse}else{this.type=src}if(props){jQuery.extend(this,props)}this.timeStamp=src&&src.timeStamp||jQuery.now();this[jQuery.expando]=true};function returnFalse(){return false}function returnTrue(){return true}jQuery.Event.prototype={preventDefault:function(){this.isDefaultPrevented=returnTrue;var e=this.originalEvent;if(!e){return}if(e.preventDefault){e.preventDefault()}else{e.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=returnTrue;var e=this.originalEvent;if(!e){return}if(e.stopPropagation){e.stopPropagation()}e.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=returnTrue;this.stopPropagation()},isDefaultPrevented:returnFalse,isPropagationStopped:returnFalse,isImmediatePropagationStopped:returnFalse};jQuery.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(orig,fix){jQuery.event.special[orig]={delegateType:fix,bindType:fix,handle:function(event){var ret,target=this,related=event.relatedTarget,handleObj=event.handleObj,selector=handleObj.selector;if(!related||related!==target&&!jQuery.contains(target,related)){event.type=handleObj.origType;ret=handleObj.handler.apply(this,arguments);event.type=fix}return ret}}});if(!jQuery.support.submitBubbles){jQuery.event.special.submit={setup:function(){if(jQuery.nodeName(this,"form")){return false}jQuery.event.add(this,"click._submit keypress._submit",function(e){var elem=e.target,form=jQuery.nodeName(elem,"input")||jQuery.nodeName(elem,"button")?elem.form:undefined;if(form&&!jQuery._data(form,"_submit_attached")){jQuery.event.add(form,"submit._submit",function(event){event._submit_bubble=true});jQuery._data(form,"_submit_attached",true)}})},postDispatch:function(event){if(event._submit_bubble){delete event._submit_bubble;if(this.parentNode&&!event.isTrigger){jQuery.event.simulate("submit",this.parentNode,event,true)}}},teardown:function(){if(jQuery.nodeName(this,"form")){return false}jQuery.event.remove(this,"._submit")}}}if(!jQuery.support.changeBubbles){jQuery.event.special.change={setup:function(){if(rformElems.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio"){jQuery.event.add(this,"propertychange._change",function(event){if(event.originalEvent.propertyName==="checked"){this._just_changed=true}});jQuery.event.add(this,"click._change",function(event){if(this._just_changed&&!event.isTrigger){this._just_changed=false}jQuery.event.simulate("change",this,event,true)})}return false}jQuery.event.add(this,"beforeactivate._change",function(e){var elem=e.target;if(rformElems.test(elem.nodeName)&&!jQuery._data(elem,"_change_attached")){jQuery.event.add(elem,"change._change",function(event){if(this.parentNode&&!event.isSimulated&&!event.isTrigger){jQuery.event.simulate("change",this.parentNode,event,true)}});jQuery._data(elem,"_change_attached",true)}})},handle:function(event){var elem=event.target;if(this!==elem||event.isSimulated||event.isTrigger||elem.type!=="radio"&&elem.type!=="checkbox"){return event.handleObj.handler.apply(this,arguments)}},teardown:function(){jQuery.event.remove(this,"._change");return!rformElems.test(this.nodeName)}}}if(!jQuery.support.focusinBubbles){jQuery.each({focus:"focusin",blur:"focusout"},function(orig,fix){var attaches=0,handler=function(event){jQuery.event.simulate(fix,event.target,jQuery.event.fix(event),true)};jQuery.event.special[fix]={setup:function(){if(attaches++===0){document.addEventListener(orig,handler,true)}},teardown:function(){if(--attaches===0){document.removeEventListener(orig,handler,true)}}}})}jQuery.fn.extend({on:function(types,selector,data,fn,one){var origFn,type;if(typeof types==="object"){if(typeof selector!=="string"){data=data||selector;selector=undefined}for(type in types){this.on(type,selector,data,types[type],one)}return this}if(data==null&&fn==null){fn=selector;data=selector=undefined}else if(fn==null){if(typeof selector==="string"){fn=data;data=undefined}else{fn=data;data=selector;selector=undefined}}if(fn===false){fn=returnFalse}else if(!fn){return this}if(one===1){origFn=fn;fn=function(event){jQuery().off(event);return origFn.apply(this,arguments)};fn.guid=origFn.guid||(origFn.guid=jQuery.guid++)}return this.each(function(){jQuery.event.add(this,types,fn,data,selector)})},one:function(types,selector,data,fn){return this.on(types,selector,data,fn,1)},off:function(types,selector,fn){var handleObj,type;if(types&&types.preventDefault&&types.handleObj){handleObj=types.handleObj;jQuery(types.delegateTarget).off(handleObj.namespace?handleObj.origType+"."+handleObj.namespace:handleObj.origType,handleObj.selector,handleObj.handler);return this}if(typeof types==="object"){for(type in types){this.off(type,selector,types[type])}return this}if(selector===false||typeof selector==="function"){fn=selector;selector=undefined}if(fn===false){fn=returnFalse}return this.each(function(){jQuery.event.remove(this,types,fn,selector)})},bind:function(types,data,fn){return this.on(types,null,data,fn)},unbind:function(types,fn){return this.off(types,null,fn)},live:function(types,data,fn){jQuery(this.context).on(types,this.selector,data,fn);return this},die:function(types,fn){jQuery(this.context).off(types,this.selector||"**",fn);return this},delegate:function(selector,types,data,fn){return this.on(types,selector,data,fn)},undelegate:function(selector,types,fn){return arguments.length===1?this.off(selector,"**"):this.off(types,selector||"**",fn)},trigger:function(type,data){return this.each(function(){jQuery.event.trigger(type,data,this)})},triggerHandler:function(type,data){if(this[0]){return jQuery.event.trigger(type,data,this[0],true)}},toggle:function(fn){var args=arguments,guid=fn.guid||jQuery.guid++,i=0,toggler=function(event){var lastToggle=(jQuery._data(this,"lastToggle"+fn.guid)||0)%i;jQuery._data(this,"lastToggle"+fn.guid,lastToggle+1);event.preventDefault();return args[lastToggle].apply(this,arguments)||false};toggler.guid=guid;while(i<args.length){args[i++].guid=guid}return this.click(toggler)},hover:function(fnOver,fnOut){return this.mouseenter(fnOver).mouseleave(fnOut||fnOver)}});jQuery.each(("blur focus focusin focusout load resize scroll unload click dblclick "+"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave "+"change select submit keydown keypress keyup error contextmenu").split(" "),function(i,name){jQuery.fn[name]=function(data,fn){if(fn==null){fn=data;data=null}return arguments.length>0?this.on(name,null,data,fn):this.trigger(name)};if(rkeyEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.keyHooks}if(rmouseEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.mouseHooks}});(function(window,undefined){var cachedruns,assertGetIdNotName,Expr,getText,isXML,contains,compile,sortOrder,hasDuplicate,outermostContext,baseHasDuplicate=true,strundefined="undefined",expando=("sizcache"+Math.random()).replace(".",""),Token=String,document=window.document,docElem=document.documentElement,dirruns=0,done=0,pop=[].pop,push=[].push,slice=[].slice,indexOf=[].indexOf||function(elem){var i=0,len=this.length;for(;i<len;i++){if(this[i]===elem){return i}}return-1},markFunction=function(fn,value){fn[expando]=value==null||value;return fn},createCache=function(){var cache={},keys=[];return markFunction(function(key,value){if(keys.push(key)>Expr.cacheLength){delete cache[keys.shift()]}return cache[key+" "]=value},cache)},classCache=createCache(),tokenCache=createCache(),compilerCache=createCache(),whitespace="[\\x20\\t\\r\\n\\f]",characterEncoding="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",identifier=characterEncoding.replace("w","w#"),operators="([*^$|!~]?=)",attributes="\\["+whitespace+"*("+characterEncoding+")"+whitespace+"*(?:"+operators+whitespace+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+identifier+")|)|)"+whitespace+"*\\]",pseudos=":("+characterEncoding+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+attributes+")|[^:]|\\\\.)*|.*))\\)|)",pos=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+whitespace+"*((?:-\\d)?\\d*)"+whitespace+"*\\)|)(?=[^-]|$)",rtrim=new RegExp("^"+whitespace+"+|((?:^|[^\\\\])(?:\\\\.)*)"+whitespace+"+$","g"),rcomma=new RegExp("^"+whitespace+"*,"+whitespace+"*"),rcombinators=new RegExp("^"+whitespace+"*([\\x20\\t\\r\\n\\f>+~])"+whitespace+"*"),rpseudo=new RegExp(pseudos),rquickExpr=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,rnot=/^:not/,rsibling=/[\x20\t\r\n\f]*[+~]/,rendsWithNot=/:not\($/,rheader=/h\d/i,rinputs=/input|select|textarea|button/i,rbackslash=/\\(?!\\)/g,matchExpr={ID:new RegExp("^#("+characterEncoding+")"),CLASS:new RegExp("^\\.("+characterEncoding+")"),NAME:new RegExp("^\\[name=['\"]?("+characterEncoding+")['\"]?\\]"),TAG:new RegExp("^("+characterEncoding.replace("w","w*")+")"),ATTR:new RegExp("^"+attributes),PSEUDO:new RegExp("^"+pseudos),POS:new RegExp(pos,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+whitespace+"*(even|odd|(([+-]|)(\\d*)n|)"+whitespace+"*(?:([+-]|)"+whitespace+"*(\\d+)|))"+whitespace+"*\\)|)","i"),needsContext:new RegExp("^"+whitespace+"*[>+~]|"+pos,"i")},assert=function(fn){var div=document.createElement("div");try{return fn(div)}catch(e){return false}finally{div=null}},assertTagNameNoComments=assert(function(div){div.appendChild(document.createComment(""));return!div.getElementsByTagName("*").length}),assertHrefNotNormalized=assert(function(div){div.innerHTML="<a href='#'></a>";return div.firstChild&&typeof div.firstChild.getAttribute!==strundefined&&div.firstChild.getAttribute("href")==="#"}),assertAttributes=assert(function(div){div.innerHTML="<select></select>";var type=typeof div.lastChild.getAttribute("multiple");return type!=="boolean"&&type!=="string"}),assertUsableClassName=assert(function(div){div.innerHTML="<div class='hidden e'></div><div class='hidden'></div>";if(!div.getElementsByClassName||!div.getElementsByClassName("e").length){return false}div.lastChild.className="e";return div.getElementsByClassName("e").length===2}),assertUsableName=assert(function(div){div.id=expando+0;div.innerHTML="<a name='"+expando+"'></a><div name='"+expando+"'></div>";docElem.insertBefore(div,docElem.firstChild);var pass=document.getElementsByName&&document.getElementsByName(expando).length===2+document.getElementsByName(expando+0).length;assertGetIdNotName=!document.getElementById(expando);docElem.removeChild(div);return pass});try{slice.call(docElem.childNodes,0)[0].nodeType}catch(e){slice=function(i){var elem,results=[];for(;elem=this[i];i++){results.push(elem)}return results}}function Sizzle(selector,context,results,seed){results=results||[];context=context||document;var match,elem,xml,m,nodeType=context.nodeType;if(!selector||typeof selector!=="string"){return results}if(nodeType!==1&&nodeType!==9){return[]}xml=isXML(context);if(!xml&&!seed){if(match=rquickExpr.exec(selector)){if(m=match[1]){if(nodeType===9){elem=context.getElementById(m);if(elem&&elem.parentNode){if(elem.id===m){results.push(elem);return results}}else{return results}}else{if(context.ownerDocument&&(elem=context.ownerDocument.getElementById(m))&&contains(context,elem)&&elem.id===m){results.push(elem);return results}}}else if(match[2]){push.apply(results,slice.call(context.getElementsByTagName(selector),0));return results}else if((m=match[3])&&assertUsableClassName&&context.getElementsByClassName){push.apply(results,slice.call(context.getElementsByClassName(m),0));return results}}}return select(selector.replace(rtrim,"$1"),context,results,seed,xml)}Sizzle.matches=function(expr,elements){return Sizzle(expr,null,null,elements)};Sizzle.matchesSelector=function(elem,expr){return Sizzle(expr,null,null,[elem]).length>0};function createInputPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type===type}}function createButtonPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return(name==="input"||name==="button")&&elem.type===type}}function createPositionalPseudo(fn){return markFunction(function(argument){argument=+argument;return markFunction(function(seed,matches){var j,matchIndexes=fn([],seed.length,argument),i=matchIndexes.length;while(i--){if(seed[j=matchIndexes[i]]){seed[j]=!(matches[j]=seed[j])}}})})}getText=Sizzle.getText=function(elem){var node,ret="",i=0,nodeType=elem.nodeType;if(nodeType){if(nodeType===1||nodeType===9||nodeType===11){if(typeof elem.textContent==="string"){return elem.textContent}else{for(elem=elem.firstChild;elem;elem=elem.nextSibling){ret+=getText(elem)}}}else if(nodeType===3||nodeType===4){return elem.nodeValue}}else{for(;node=elem[i];i++){ret+=getText(node)}}return ret};isXML=Sizzle.isXML=function(elem){var documentElement=elem&&(elem.ownerDocument||elem).documentElement;return documentElement?documentElement.nodeName!=="HTML":false};contains=Sizzle.contains=docElem.contains?function(a,b){var adown=a.nodeType===9?a.documentElement:a,bup=b&&b.parentNode;return a===bup||!!(bup&&bup.nodeType===1&&adown.contains&&adown.contains(bup))}:docElem.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode){if(b===a){return true}}return false};Sizzle.attr=function(elem,name){var val,xml=isXML(elem);if(!xml){name=name.toLowerCase()}if(val=Expr.attrHandle[name]){return val(elem)}if(xml||assertAttributes){return elem.getAttribute(name)}val=elem.getAttributeNode(name);return val?typeof elem[name]==="boolean"?elem[name]?name:null:val.specified?val.value:null:null};Expr=Sizzle.selectors={cacheLength:50,createPseudo:markFunction,match:matchExpr,attrHandle:assertHrefNotNormalized?{}:{href:function(elem){return elem.getAttribute("href",2)},type:function(elem){return elem.getAttribute("type")}},find:{ID:assertGetIdNotName?function(id,context,xml){if(typeof context.getElementById!==strundefined&&!xml){var m=context.getElementById(id);return m&&m.parentNode?[m]:[]}}:function(id,context,xml){if(typeof context.getElementById!==strundefined&&!xml){var m=context.getElementById(id);return m?m.id===id||typeof m.getAttributeNode!==strundefined&&m.getAttributeNode("id").value===id?[m]:undefined:[]}},TAG:assertTagNameNoComments?function(tag,context){if(typeof context.getElementsByTagName!==strundefined){return context.getElementsByTagName(tag)}}:function(tag,context){var results=context.getElementsByTagName(tag);if(tag==="*"){var elem,tmp=[],i=0;for(;elem=results[i];i++){if(elem.nodeType===1){tmp.push(elem)}}return tmp}return results},NAME:assertUsableName&&function(tag,context){if(typeof context.getElementsByName!==strundefined){return context.getElementsByName(name)}},CLASS:assertUsableClassName&&function(className,context,xml){if(typeof context.getElementsByClassName!==strundefined&&!xml){return context.getElementsByClassName(className)}}},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(match){match[1]=match[1].replace(rbackslash,"");match[3]=(match[4]||match[5]||"").replace(rbackslash,"");if(match[2]==="~="){match[3]=" "+match[3]+" "}return match.slice(0,4)},CHILD:function(match){match[1]=match[1].toLowerCase();if(match[1]==="nth"){if(!match[2]){Sizzle.error(match[0])}match[3]=+(match[3]?match[4]+(match[5]||1):2*(match[2]==="even"||match[2]==="odd"));match[4]=+(match[6]+match[7]||match[2]==="odd")}else if(match[2]){Sizzle.error(match[0])}return match},PSEUDO:function(match){var unquoted,excess;if(matchExpr["CHILD"].test(match[0])){return null}if(match[3]){match[2]=match[3]}else if(unquoted=match[4]){if(rpseudo.test(unquoted)&&(excess=tokenize(unquoted,true))&&(excess=unquoted.indexOf(")",unquoted.length-excess)-unquoted.length)){unquoted=unquoted.slice(0,excess);match[0]=match[0].slice(0,excess)}match[2]=unquoted}return match.slice(0,3)}},filter:{ID:assertGetIdNotName?function(id){id=id.replace(rbackslash,"");return function(elem){return elem.getAttribute("id")===id}}:function(id){id=id.replace(rbackslash,"");return function(elem){var node=typeof elem.getAttributeNode!==strundefined&&elem.getAttributeNode("id");return node&&node.value===id}},TAG:function(nodeName){if(nodeName==="*"){return function(){return true}}nodeName=nodeName.replace(rbackslash,"").toLowerCase();return function(elem){return elem.nodeName&&elem.nodeName.toLowerCase()===nodeName}},CLASS:function(className){var pattern=classCache[expando][className+" "];return pattern||(pattern=new RegExp("(^|"+whitespace+")"+className+"("+whitespace+"|$)"))&&classCache(className,function(elem){return pattern.test(elem.className||typeof elem.getAttribute!==strundefined&&elem.getAttribute("class")||"")})},ATTR:function(name,operator,check){return function(elem,context){var result=Sizzle.attr(elem,name);if(result==null){return operator==="!="}if(!operator){return true}result+="";return operator==="="?result===check:operator==="!="?result!==check:operator==="^="?check&&result.indexOf(check)===0:operator==="*="?check&&result.indexOf(check)>-1:operator==="$="?check&&result.substr(result.length-check.length)===check:operator==="~="?(" "+result+" ").indexOf(check)>-1:operator==="|="?result===check||result.substr(0,check.length+1)===check+"-":false}},CHILD:function(type,argument,first,last){if(type==="nth"){return function(elem){var node,diff,parent=elem.parentNode;if(first===1&&last===0){return true}if(parent){diff=0;for(node=parent.firstChild;node;node=node.nextSibling){if(node.nodeType===1){diff++; -if(elem===node){break}}}}diff-=last;return diff===first||diff%first===0&&diff/first>=0}}return function(elem){var node=elem;switch(type){case"only":case"first":while(node=node.previousSibling){if(node.nodeType===1){return false}}if(type==="first"){return true}node=elem;case"last":while(node=node.nextSibling){if(node.nodeType===1){return false}}return true}}},PSEUDO:function(pseudo,argument){var args,fn=Expr.pseudos[pseudo]||Expr.setFilters[pseudo.toLowerCase()]||Sizzle.error("unsupported pseudo: "+pseudo);if(fn[expando]){return fn(argument)}if(fn.length>1){args=[pseudo,pseudo,"",argument];return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase())?markFunction(function(seed,matches){var idx,matched=fn(seed,argument),i=matched.length;while(i--){idx=indexOf.call(seed,matched[i]);seed[idx]=!(matches[idx]=matched[i])}}):function(elem){return fn(elem,0,args)}}return fn}},pseudos:{not:markFunction(function(selector){var input=[],results=[],matcher=compile(selector.replace(rtrim,"$1"));return matcher[expando]?markFunction(function(seed,matches,context,xml){var elem,unmatched=matcher(seed,null,xml,[]),i=seed.length;while(i--){if(elem=unmatched[i]){seed[i]=!(matches[i]=elem)}}}):function(elem,context,xml){input[0]=elem;matcher(input,null,xml,results);return!results.pop()}}),has:markFunction(function(selector){return function(elem){return Sizzle(selector,elem).length>0}}),contains:markFunction(function(text){return function(elem){return(elem.textContent||elem.innerText||getText(elem)).indexOf(text)>-1}}),enabled:function(elem){return elem.disabled===false},disabled:function(elem){return elem.disabled===true},checked:function(elem){var nodeName=elem.nodeName.toLowerCase();return nodeName==="input"&&!!elem.checked||nodeName==="option"&&!!elem.selected},selected:function(elem){if(elem.parentNode){elem.parentNode.selectedIndex}return elem.selected===true},parent:function(elem){return!Expr.pseudos["empty"](elem)},empty:function(elem){var nodeType;elem=elem.firstChild;while(elem){if(elem.nodeName>"@"||(nodeType=elem.nodeType)===3||nodeType===4){return false}elem=elem.nextSibling}return true},header:function(elem){return rheader.test(elem.nodeName)},text:function(elem){var type,attr;return elem.nodeName.toLowerCase()==="input"&&(type=elem.type)==="text"&&((attr=elem.getAttribute("type"))==null||attr.toLowerCase()===type)},radio:createInputPseudo("radio"),checkbox:createInputPseudo("checkbox"),file:createInputPseudo("file"),password:createInputPseudo("password"),image:createInputPseudo("image"),submit:createButtonPseudo("submit"),reset:createButtonPseudo("reset"),button:function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type==="button"||name==="button"},input:function(elem){return rinputs.test(elem.nodeName)},focus:function(elem){var doc=elem.ownerDocument;return elem===doc.activeElement&&(!doc.hasFocus||doc.hasFocus())&&!!(elem.type||elem.href||~elem.tabIndex)},active:function(elem){return elem===elem.ownerDocument.activeElement},first:createPositionalPseudo(function(){return[0]}),last:createPositionalPseudo(function(matchIndexes,length){return[length-1]}),eq:createPositionalPseudo(function(matchIndexes,length,argument){return[argument<0?argument+length:argument]}),even:createPositionalPseudo(function(matchIndexes,length){for(var i=0;i<length;i+=2){matchIndexes.push(i)}return matchIndexes}),odd:createPositionalPseudo(function(matchIndexes,length){for(var i=1;i<length;i+=2){matchIndexes.push(i)}return matchIndexes}),lt:createPositionalPseudo(function(matchIndexes,length,argument){for(var i=argument<0?argument+length:argument;--i>=0;){matchIndexes.push(i)}return matchIndexes}),gt:createPositionalPseudo(function(matchIndexes,length,argument){for(var i=argument<0?argument+length:argument;++i<length;){matchIndexes.push(i)}return matchIndexes})}};function siblingCheck(a,b,ret){if(a===b){return ret}var cur=a.nextSibling;while(cur){if(cur===b){return-1}cur=cur.nextSibling}return 1}sortOrder=docElem.compareDocumentPosition?function(a,b){if(a===b){hasDuplicate=true;return 0}return(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b){hasDuplicate=true;return 0}else if(a.sourceIndex&&b.sourceIndex){return a.sourceIndex-b.sourceIndex}var al,bl,ap=[],bp=[],aup=a.parentNode,bup=b.parentNode,cur=aup;if(aup===bup){return siblingCheck(a,b)}else if(!aup){return-1}else if(!bup){return 1}while(cur){ap.unshift(cur);cur=cur.parentNode}cur=bup;while(cur){bp.unshift(cur);cur=cur.parentNode}al=ap.length;bl=bp.length;for(var i=0;i<al&&i<bl;i++){if(ap[i]!==bp[i]){return siblingCheck(ap[i],bp[i])}}return i===al?siblingCheck(a,bp[i],-1):siblingCheck(ap[i],b,1)};[0,0].sort(sortOrder);baseHasDuplicate=!hasDuplicate;Sizzle.uniqueSort=function(results){var elem,duplicates=[],i=1,j=0;hasDuplicate=baseHasDuplicate;results.sort(sortOrder);if(hasDuplicate){for(;elem=results[i];i++){if(elem===results[i-1]){j=duplicates.push(i)}}while(j--){results.splice(duplicates[j],1)}}return results};Sizzle.error=function(msg){throw new Error("Syntax error, unrecognized expression: "+msg)};function tokenize(selector,parseOnly){var matched,match,tokens,type,soFar,groups,preFilters,cached=tokenCache[expando][selector+" "];if(cached){return parseOnly?0:cached.slice(0)}soFar=selector;groups=[];preFilters=Expr.preFilter;while(soFar){if(!matched||(match=rcomma.exec(soFar))){if(match){soFar=soFar.slice(match[0].length)||soFar}groups.push(tokens=[])}matched=false;if(match=rcombinators.exec(soFar)){tokens.push(matched=new Token(match.shift()));soFar=soFar.slice(matched.length);matched.type=match[0].replace(rtrim," ")}for(type in Expr.filter){if((match=matchExpr[type].exec(soFar))&&(!preFilters[type]||(match=preFilters[type](match)))){tokens.push(matched=new Token(match.shift()));soFar=soFar.slice(matched.length);matched.type=type;matched.matches=match}}if(!matched){break}}return parseOnly?soFar.length:soFar?Sizzle.error(selector):tokenCache(selector,groups).slice(0)}function addCombinator(matcher,combinator,base){var dir=combinator.dir,checkNonElements=base&&combinator.dir==="parentNode",doneName=done++;return combinator.first?function(elem,context,xml){while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){return matcher(elem,context,xml)}}}:function(elem,context,xml){if(!xml){var cache,dirkey=dirruns+" "+doneName+" ",cachedkey=dirkey+cachedruns;while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){if((cache=elem[expando])===cachedkey){return elem.sizset}else if(typeof cache==="string"&&cache.indexOf(dirkey)===0){if(elem.sizset){return elem}}else{elem[expando]=cachedkey;if(matcher(elem,context,xml)){elem.sizset=true;return elem}elem.sizset=false}}}}else{while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){if(matcher(elem,context,xml)){return elem}}}}}}function elementMatcher(matchers){return matchers.length>1?function(elem,context,xml){var i=matchers.length;while(i--){if(!matchers[i](elem,context,xml)){return false}}return true}:matchers[0]}function condense(unmatched,map,filter,context,xml){var elem,newUnmatched=[],i=0,len=unmatched.length,mapped=map!=null;for(;i<len;i++){if(elem=unmatched[i]){if(!filter||filter(elem,context,xml)){newUnmatched.push(elem);if(mapped){map.push(i)}}}}return newUnmatched}function setMatcher(preFilter,selector,matcher,postFilter,postFinder,postSelector){if(postFilter&&!postFilter[expando]){postFilter=setMatcher(postFilter)}if(postFinder&&!postFinder[expando]){postFinder=setMatcher(postFinder,postSelector)}return markFunction(function(seed,results,context,xml){var temp,i,elem,preMap=[],postMap=[],preexisting=results.length,elems=seed||multipleContexts(selector||"*",context.nodeType?[context]:context,[]),matcherIn=preFilter&&(seed||!selector)?condense(elems,preMap,preFilter,context,xml):elems,matcherOut=matcher?postFinder||(seed?preFilter:preexisting||postFilter)?[]:results:matcherIn;if(matcher){matcher(matcherIn,matcherOut,context,xml)}if(postFilter){temp=condense(matcherOut,postMap);postFilter(temp,[],context,xml);i=temp.length;while(i--){if(elem=temp[i]){matcherOut[postMap[i]]=!(matcherIn[postMap[i]]=elem)}}}if(seed){if(postFinder||preFilter){if(postFinder){temp=[];i=matcherOut.length;while(i--){if(elem=matcherOut[i]){temp.push(matcherIn[i]=elem)}}postFinder(null,matcherOut=[],temp,xml)}i=matcherOut.length;while(i--){if((elem=matcherOut[i])&&(temp=postFinder?indexOf.call(seed,elem):preMap[i])>-1){seed[temp]=!(results[temp]=elem)}}}}else{matcherOut=condense(matcherOut===results?matcherOut.splice(preexisting,matcherOut.length):matcherOut);if(postFinder){postFinder(null,results,matcherOut,xml)}else{push.apply(results,matcherOut)}}})}function matcherFromTokens(tokens){var checkContext,matcher,j,len=tokens.length,leadingRelative=Expr.relative[tokens[0].type],implicitRelative=leadingRelative||Expr.relative[" "],i=leadingRelative?1:0,matchContext=addCombinator(function(elem){return elem===checkContext},implicitRelative,true),matchAnyContext=addCombinator(function(elem){return indexOf.call(checkContext,elem)>-1},implicitRelative,true),matchers=[function(elem,context,xml){return!leadingRelative&&(xml||context!==outermostContext)||((checkContext=context).nodeType?matchContext(elem,context,xml):matchAnyContext(elem,context,xml))}];for(;i<len;i++){if(matcher=Expr.relative[tokens[i].type]){matchers=[addCombinator(elementMatcher(matchers),matcher)]}else{matcher=Expr.filter[tokens[i].type].apply(null,tokens[i].matches);if(matcher[expando]){j=++i;for(;j<len;j++){if(Expr.relative[tokens[j].type]){break}}return setMatcher(i>1&&elementMatcher(matchers),i>1&&tokens.slice(0,i-1).join("").replace(rtrim,"$1"),matcher,i<j&&matcherFromTokens(tokens.slice(i,j)),j<len&&matcherFromTokens(tokens=tokens.slice(j)),j<len&&tokens.join(""))}matchers.push(matcher)}}return elementMatcher(matchers)}function matcherFromGroupMatchers(elementMatchers,setMatchers){var bySet=setMatchers.length>0,byElement=elementMatchers.length>0,superMatcher=function(seed,context,xml,results,expandContext){var elem,j,matcher,setMatched=[],matchedCount=0,i="0",unmatched=seed&&[],outermost=expandContext!=null,contextBackup=outermostContext,elems=seed||byElement&&Expr.find["TAG"]("*",expandContext&&context.parentNode||context),dirrunsUnique=dirruns+=contextBackup==null?1:Math.E;if(outermost){outermostContext=context!==document&&context;cachedruns=superMatcher.el}for(;(elem=elems[i])!=null;i++){if(byElement&&elem){for(j=0;matcher=elementMatchers[j];j++){if(matcher(elem,context,xml)){results.push(elem);break}}if(outermost){dirruns=dirrunsUnique;cachedruns=++superMatcher.el}}if(bySet){if(elem=!matcher&&elem){matchedCount--}if(seed){unmatched.push(elem)}}}matchedCount+=i;if(bySet&&i!==matchedCount){for(j=0;matcher=setMatchers[j];j++){matcher(unmatched,setMatched,context,xml)}if(seed){if(matchedCount>0){while(i--){if(!(unmatched[i]||setMatched[i])){setMatched[i]=pop.call(results)}}}setMatched=condense(setMatched)}push.apply(results,setMatched);if(outermost&&!seed&&setMatched.length>0&&matchedCount+setMatchers.length>1){Sizzle.uniqueSort(results)}}if(outermost){dirruns=dirrunsUnique;outermostContext=contextBackup}return unmatched};superMatcher.el=0;return bySet?markFunction(superMatcher):superMatcher}compile=Sizzle.compile=function(selector,group){var i,setMatchers=[],elementMatchers=[],cached=compilerCache[expando][selector+" "];if(!cached){if(!group){group=tokenize(selector)}i=group.length;while(i--){cached=matcherFromTokens(group[i]);if(cached[expando]){setMatchers.push(cached)}else{elementMatchers.push(cached)}}cached=compilerCache(selector,matcherFromGroupMatchers(elementMatchers,setMatchers))}return cached};function multipleContexts(selector,contexts,results){var i=0,len=contexts.length;for(;i<len;i++){Sizzle(selector,contexts[i],results)}return results}function select(selector,context,results,seed,xml){var i,tokens,token,type,find,match=tokenize(selector),j=match.length;if(!seed){if(match.length===1){tokens=match[0]=match[0].slice(0);if(tokens.length>2&&(token=tokens[0]).type==="ID"&&context.nodeType===9&&!xml&&Expr.relative[tokens[1].type]){context=Expr.find["ID"](token.matches[0].replace(rbackslash,""),context,xml)[0];if(!context){return results}selector=selector.slice(tokens.shift().length)}for(i=matchExpr["POS"].test(selector)?-1:tokens.length-1;i>=0;i--){token=tokens[i];if(Expr.relative[type=token.type]){break}if(find=Expr.find[type]){if(seed=find(token.matches[0].replace(rbackslash,""),rsibling.test(tokens[0].type)&&context.parentNode||context,xml)){tokens.splice(i,1);selector=seed.length&&tokens.join("");if(!selector){push.apply(results,slice.call(seed,0));return results}break}}}}}compile(selector,match)(seed,context,xml,results,rsibling.test(selector));return results}if(document.querySelectorAll){(function(){var disconnectedMatch,oldSelect=select,rescape=/'|\\/g,rattributeQuotes=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,rbuggyQSA=[":focus"],rbuggyMatches=[":active"],matches=docElem.matchesSelector||docElem.mozMatchesSelector||docElem.webkitMatchesSelector||docElem.oMatchesSelector||docElem.msMatchesSelector;assert(function(div){div.innerHTML="<select><option selected=''></option></select>";if(!div.querySelectorAll("[selected]").length){rbuggyQSA.push("\\["+whitespace+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)")}if(!div.querySelectorAll(":checked").length){rbuggyQSA.push(":checked")}});assert(function(div){div.innerHTML="<p test=''></p>";if(div.querySelectorAll("[test^='']").length){rbuggyQSA.push("[*^$]="+whitespace+"*(?:\"\"|'')")}div.innerHTML="<input type='hidden'/>";if(!div.querySelectorAll(":enabled").length){rbuggyQSA.push(":enabled",":disabled")}});rbuggyQSA=new RegExp(rbuggyQSA.join("|"));select=function(selector,context,results,seed,xml){if(!seed&&!xml&&!rbuggyQSA.test(selector)){var groups,i,old=true,nid=expando,newContext=context,newSelector=context.nodeType===9&&selector;if(context.nodeType===1&&context.nodeName.toLowerCase()!=="object"){groups=tokenize(selector);if(old=context.getAttribute("id")){nid=old.replace(rescape,"\\$&")}else{context.setAttribute("id",nid)}nid="[id='"+nid+"'] ";i=groups.length;while(i--){groups[i]=nid+groups[i].join("")}newContext=rsibling.test(selector)&&context.parentNode||context;newSelector=groups.join(",")}if(newSelector){try{push.apply(results,slice.call(newContext.querySelectorAll(newSelector),0));return results}catch(qsaError){}finally{if(!old){context.removeAttribute("id")}}}}return oldSelect(selector,context,results,seed,xml)};if(matches){assert(function(div){disconnectedMatch=matches.call(div,"div");try{matches.call(div,"[test!='']:sizzle");rbuggyMatches.push("!=",pseudos)}catch(e){}});rbuggyMatches=new RegExp(rbuggyMatches.join("|"));Sizzle.matchesSelector=function(elem,expr){expr=expr.replace(rattributeQuotes,"='$1']");if(!isXML(elem)&&!rbuggyMatches.test(expr)&&!rbuggyQSA.test(expr)){try{var ret=matches.call(elem,expr);if(ret||disconnectedMatch||elem.document&&elem.document.nodeType!==11){return ret}}catch(e){}}return Sizzle(expr,null,null,[elem]).length>0}}})()}Expr.pseudos["nth"]=Expr.pseudos["eq"];function setFilters(){}Expr.filters=setFilters.prototype=Expr.pseudos;Expr.setFilters=new setFilters;Sizzle.attr=jQuery.attr;jQuery.find=Sizzle;jQuery.expr=Sizzle.selectors;jQuery.expr[":"]=jQuery.expr.pseudos;jQuery.unique=Sizzle.uniqueSort;jQuery.text=Sizzle.getText;jQuery.isXMLDoc=Sizzle.isXML;jQuery.contains=Sizzle.contains})(window);var runtil=/Until$/,rparentsprev=/^(?:parents|prev(?:Until|All))/,isSimple=/^.[^:#\[\.,]*$/,rneedsContext=jQuery.expr.match.needsContext,guaranteedUnique={children:true,contents:true,next:true,prev:true};jQuery.fn.extend({find:function(selector){var i,l,length,n,r,ret,self=this;if(typeof selector!=="string"){return jQuery(selector).filter(function(){for(i=0,l=self.length;i<l;i++){if(jQuery.contains(self[i],this)){return true}}})}ret=this.pushStack("","find",selector);for(i=0,l=this.length;i<l;i++){length=ret.length;jQuery.find(selector,this[i],ret);if(i>0){for(n=length;n<ret.length;n++){for(r=0;r<length;r++){if(ret[r]===ret[n]){ret.splice(n--,1);break}}}}}return ret},has:function(target){var i,targets=jQuery(target,this),len=targets.length;return this.filter(function(){for(i=0;i<len;i++){if(jQuery.contains(this,targets[i])){return true}}})},not:function(selector){return this.pushStack(winnow(this,selector,false),"not",selector)},filter:function(selector){return this.pushStack(winnow(this,selector,true),"filter",selector)},is:function(selector){return!!selector&&(typeof selector==="string"?rneedsContext.test(selector)?jQuery(selector,this.context).index(this[0])>=0:jQuery.filter(selector,this).length>0:this.filter(selector).length>0)},closest:function(selectors,context){var cur,i=0,l=this.length,ret=[],pos=rneedsContext.test(selectors)||typeof selectors!=="string"?jQuery(selectors,context||this.context):0;for(;i<l;i++){cur=this[i];while(cur&&cur.ownerDocument&&cur!==context&&cur.nodeType!==11){if(pos?pos.index(cur)>-1:jQuery.find.matchesSelector(cur,selectors)){ret.push(cur);break}cur=cur.parentNode}}ret=ret.length>1?jQuery.unique(ret):ret;return this.pushStack(ret,"closest",selectors)},index:function(elem){if(!elem){return this[0]&&this[0].parentNode?this.prevAll().length:-1}if(typeof elem==="string"){return jQuery.inArray(this[0],jQuery(elem))}return jQuery.inArray(elem.jquery?elem[0]:elem,this)},add:function(selector,context){var set=typeof selector==="string"?jQuery(selector,context):jQuery.makeArray(selector&&selector.nodeType?[selector]:selector),all=jQuery.merge(this.get(),set);return this.pushStack(isDisconnected(set[0])||isDisconnected(all[0])?all:jQuery.unique(all))},addBack:function(selector){return this.add(selector==null?this.prevObject:this.prevObject.filter(selector))}});jQuery.fn.andSelf=jQuery.fn.addBack;function isDisconnected(node){return!node||!node.parentNode||node.parentNode.nodeType===11}function sibling(cur,dir){do{cur=cur[dir]}while(cur&&cur.nodeType!==1);return cur}jQuery.each({parent:function(elem){var parent=elem.parentNode;return parent&&parent.nodeType!==11?parent:null},parents:function(elem){return jQuery.dir(elem,"parentNode")},parentsUntil:function(elem,i,until){return jQuery.dir(elem,"parentNode",until)},next:function(elem){return sibling(elem,"nextSibling")},prev:function(elem){return sibling(elem,"previousSibling")},nextAll:function(elem){return jQuery.dir(elem,"nextSibling")},prevAll:function(elem){return jQuery.dir(elem,"previousSibling")},nextUntil:function(elem,i,until){return jQuery.dir(elem,"nextSibling",until)},prevUntil:function(elem,i,until){return jQuery.dir(elem,"previousSibling",until)},siblings:function(elem){return jQuery.sibling((elem.parentNode||{}).firstChild,elem)},children:function(elem){return jQuery.sibling(elem.firstChild)},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.merge([],elem.childNodes)}},function(name,fn){jQuery.fn[name]=function(until,selector){var ret=jQuery.map(this,fn,until);if(!runtil.test(name)){selector=until}if(selector&&typeof selector==="string"){ret=jQuery.filter(selector,ret)}ret=this.length>1&&!guaranteedUnique[name]?jQuery.unique(ret):ret;if(this.length>1&&rparentsprev.test(name)){ret=ret.reverse()}return this.pushStack(ret,name,core_slice.call(arguments).join(","))}});jQuery.extend({filter:function(expr,elems,not){if(not){expr=":not("+expr+")"}return elems.length===1?jQuery.find.matchesSelector(elems[0],expr)?[elems[0]]:[]:jQuery.find.matches(expr,elems)},dir:function(elem,dir,until){var matched=[],cur=elem[dir];while(cur&&cur.nodeType!==9&&(until===undefined||cur.nodeType!==1||!jQuery(cur).is(until))){if(cur.nodeType===1){matched.push(cur)}cur=cur[dir]}return matched},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType===1&&n!==elem){r.push(n)}}return r}});function winnow(elements,qualifier,keep){qualifier=qualifier||0;if(jQuery.isFunction(qualifier)){return jQuery.grep(elements,function(elem,i){var retVal=!!qualifier.call(elem,i,elem);return retVal===keep})}else if(qualifier.nodeType){return jQuery.grep(elements,function(elem,i){return elem===qualifier===keep})}else if(typeof qualifier==="string"){var filtered=jQuery.grep(elements,function(elem){return elem.nodeType===1});if(isSimple.test(qualifier)){return jQuery.filter(qualifier,filtered,!keep)}else{qualifier=jQuery.filter(qualifier,filtered)}}return jQuery.grep(elements,function(elem,i){return jQuery.inArray(elem,qualifier)>=0===keep})}function createSafeFragment(document){var list=nodeNames.split("|"),safeFrag=document.createDocumentFragment();if(safeFrag.createElement){while(list.length){safeFrag.createElement(list.pop())}}return safeFrag}var nodeNames="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|"+"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",rinlinejQuery=/ jQuery\d+="(?:null|\d+)"/g,rleadingWhitespace=/^\s+/,rxhtmlTag=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,rtagName=/<([\w:]+)/,rtbody=/<tbody/i,rhtml=/<|&#?\w+;/,rnoInnerhtml=/<(?:script|style|link)/i,rnocache=/<(?:script|object|embed|option|style)/i,rnoshimcache=new RegExp("<(?:"+nodeNames+")[\\s/>]","i"),rcheckableType=/^(?:checkbox|radio)$/,rchecked=/checked\s*(?:[^=]|=\s*.checked.)/i,rscriptType=/\/(java|ecma)script/i,rcleanScript=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,wrapMap={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},safeFragment=createSafeFragment(document),fragmentDiv=safeFragment.appendChild(document.createElement("div"));wrapMap.optgroup=wrapMap.option;wrapMap.tbody=wrapMap.tfoot=wrapMap.colgroup=wrapMap.caption=wrapMap.thead;wrapMap.th=wrapMap.td;if(!jQuery.support.htmlSerialize){wrapMap._default=[1,"X<div>","</div>"]}jQuery.fn.extend({text:function(value){return jQuery.access(this,function(value){return value===undefined?jQuery.text(this):this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(value))},null,value,arguments.length)},wrapAll:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapAll(html.call(this,i))})}if(this[0]){var wrap=jQuery(html,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){wrap.insertBefore(this[0])}wrap.map(function(){var elem=this;while(elem.firstChild&&elem.firstChild.nodeType===1){elem=elem.firstChild}return elem}).append(this)}return this},wrapInner:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapInner(html.call(this,i))})}return this.each(function(){var self=jQuery(this),contents=self.contents();if(contents.length){contents.wrapAll(html)}else{self.append(html)}})},wrap:function(html){var isFunction=jQuery.isFunction(html);return this.each(function(i){jQuery(this).wrapAll(isFunction?html.call(this,i):html)})},unwrap:function(){return this.parent().each(function(){if(!jQuery.nodeName(this,"body")){jQuery(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1||this.nodeType===11){this.appendChild(elem)}})},prepend:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1||this.nodeType===11){this.insertBefore(elem,this.firstChild)}})},before:function(){if(!isDisconnected(this[0])){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this)})}if(arguments.length){var set=jQuery.clean(arguments);return this.pushStack(jQuery.merge(set,this),"before",this.selector)}},after:function(){if(!isDisconnected(this[0])){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this.nextSibling)})}if(arguments.length){var set=jQuery.clean(arguments);return this.pushStack(jQuery.merge(this,set),"after",this.selector)}},remove:function(selector,keepData){var elem,i=0;for(;(elem=this[i])!=null;i++){if(!selector||jQuery.filter(selector,[elem]).length){if(!keepData&&elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));jQuery.cleanData([elem])}if(elem.parentNode){elem.parentNode.removeChild(elem)}}}return this},empty:function(){var elem,i=0;for(;(elem=this[i])!=null;i++){if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"))}while(elem.firstChild){elem.removeChild(elem.firstChild)}}return this},clone:function(dataAndEvents,deepDataAndEvents){dataAndEvents=dataAndEvents==null?false:dataAndEvents;deepDataAndEvents=deepDataAndEvents==null?dataAndEvents:deepDataAndEvents;return this.map(function(){return jQuery.clone(this,dataAndEvents,deepDataAndEvents)})},html:function(value){return jQuery.access(this,function(value){var elem=this[0]||{},i=0,l=this.length;if(value===undefined){return elem.nodeType===1?elem.innerHTML.replace(rinlinejQuery,""):undefined}if(typeof value==="string"&&!rnoInnerhtml.test(value)&&(jQuery.support.htmlSerialize||!rnoshimcache.test(value))&&(jQuery.support.leadingWhitespace||!rleadingWhitespace.test(value))&&!wrapMap[(rtagName.exec(value)||["",""])[1].toLowerCase()]){value=value.replace(rxhtmlTag,"<$1></$2>");try{for(;i<l;i++){elem=this[i]||{};if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));elem.innerHTML=value}}elem=0}catch(e){}}if(elem){this.empty().append(value)}},null,value,arguments.length)},replaceWith:function(value){if(!isDisconnected(this[0])){if(jQuery.isFunction(value)){return this.each(function(i){var self=jQuery(this),old=self.html();self.replaceWith(value.call(this,i,old))})}if(typeof value!=="string"){value=jQuery(value).detach()}return this.each(function(){var next=this.nextSibling,parent=this.parentNode;jQuery(this).remove();if(next){jQuery(next).before(value)}else{jQuery(parent).append(value)}})}return this.length?this.pushStack(jQuery(jQuery.isFunction(value)?value():value),"replaceWith",value):this},detach:function(selector){return this.remove(selector,true)},domManip:function(args,table,callback){args=[].concat.apply([],args);var results,first,fragment,iNoClone,i=0,value=args[0],scripts=[],l=this.length;if(!jQuery.support.checkClone&&l>1&&typeof value==="string"&&rchecked.test(value)){return this.each(function(){jQuery(this).domManip(args,table,callback)})}if(jQuery.isFunction(value)){return this.each(function(i){var self=jQuery(this);args[0]=value.call(this,i,table?self.html():undefined);self.domManip(args,table,callback)})}if(this[0]){results=jQuery.buildFragment(args,this,scripts);fragment=results.fragment;first=fragment.firstChild;if(fragment.childNodes.length===1){fragment=first}if(first){table=table&&jQuery.nodeName(first,"tr");for(iNoClone=results.cacheable||l-1;i<l;i++){callback.call(table&&jQuery.nodeName(this[i],"table")?findOrAppend(this[i],"tbody"):this[i],i===iNoClone?fragment:jQuery.clone(fragment,true,true))}}fragment=first=null;if(scripts.length){jQuery.each(scripts,function(i,elem){if(elem.src){if(jQuery.ajax){jQuery.ajax({url:elem.src,type:"GET",dataType:"script",async:false,global:false,"throws":true})}else{jQuery.error("no ajax")}}else{jQuery.globalEval((elem.text||elem.textContent||elem.innerHTML||"").replace(rcleanScript,""))}if(elem.parentNode){elem.parentNode.removeChild(elem)}})}}return this}});function findOrAppend(elem,tag){return elem.getElementsByTagName(tag)[0]||elem.appendChild(elem.ownerDocument.createElement(tag))}function cloneCopyEvent(src,dest){if(dest.nodeType!==1||!jQuery.hasData(src)){return}var type,i,l,oldData=jQuery._data(src),curData=jQuery._data(dest,oldData),events=oldData.events;if(events){delete curData.handle;curData.events={};for(type in events){for(i=0,l=events[type].length;i<l;i++){jQuery.event.add(dest,type,events[type][i])}}}if(curData.data){curData.data=jQuery.extend({},curData.data)}}function cloneFixAttributes(src,dest){var nodeName;if(dest.nodeType!==1){return}if(dest.clearAttributes){dest.clearAttributes()}if(dest.mergeAttributes){dest.mergeAttributes(src)}nodeName=dest.nodeName.toLowerCase();if(nodeName==="object"){if(dest.parentNode){dest.outerHTML=src.outerHTML}if(jQuery.support.html5Clone&&(src.innerHTML&&!jQuery.trim(dest.innerHTML))){dest.innerHTML=src.innerHTML}}else if(nodeName==="input"&&rcheckableType.test(src.type)){dest.defaultChecked=dest.checked=src.checked;if(dest.value!==src.value){dest.value=src.value}}else if(nodeName==="option"){dest.selected=src.defaultSelected}else if(nodeName==="input"||nodeName==="textarea"){dest.defaultValue=src.defaultValue}else if(nodeName==="script"&&dest.text!==src.text){dest.text=src.text}dest.removeAttribute(jQuery.expando)}jQuery.buildFragment=function(args,context,scripts){var fragment,cacheable,cachehit,first=args[0];context=context||document;context=!context.nodeType&&context[0]||context;context=context.ownerDocument||context;if(args.length===1&&typeof first==="string"&&first.length<512&&context===document&&first.charAt(0)==="<"&&!rnocache.test(first)&&(jQuery.support.checkClone||!rchecked.test(first))&&(jQuery.support.html5Clone||!rnoshimcache.test(first))){cacheable=true;fragment=jQuery.fragments[first];cachehit=fragment!==undefined}if(!fragment){fragment=context.createDocumentFragment();jQuery.clean(args,context,fragment,scripts);if(cacheable){jQuery.fragments[first]=cachehit&&fragment}}return{fragment:fragment,cacheable:cacheable}};jQuery.fragments={};jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(selector){var elems,i=0,ret=[],insert=jQuery(selector),l=insert.length,parent=this.length===1&&this[0].parentNode;if((parent==null||parent&&parent.nodeType===11&&parent.childNodes.length===1)&&l===1){insert[original](this[0]);return this}else{for(;i<l;i++){elems=(i>0?this.clone(true):this).get();jQuery(insert[i])[original](elems);ret=ret.concat(elems)}return this.pushStack(ret,name,insert.selector)}}});function getAll(elem){if(typeof elem.getElementsByTagName!=="undefined"){return elem.getElementsByTagName("*")}else if(typeof elem.querySelectorAll!=="undefined"){return elem.querySelectorAll("*")}else{return[]}}function fixDefaultChecked(elem){if(rcheckableType.test(elem.type)){elem.defaultChecked=elem.checked}}jQuery.extend({clone:function(elem,dataAndEvents,deepDataAndEvents){var srcElements,destElements,i,clone;if(jQuery.support.html5Clone||jQuery.isXMLDoc(elem)||!rnoshimcache.test("<"+elem.nodeName+">")){clone=elem.cloneNode(true)}else{fragmentDiv.innerHTML=elem.outerHTML;fragmentDiv.removeChild(clone=fragmentDiv.firstChild)}if((!jQuery.support.noCloneEvent||!jQuery.support.noCloneChecked)&&(elem.nodeType===1||elem.nodeType===11)&&!jQuery.isXMLDoc(elem)){cloneFixAttributes(elem,clone);srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){if(destElements[i]){cloneFixAttributes(srcElements[i],destElements[i])}}}if(dataAndEvents){cloneCopyEvent(elem,clone);if(deepDataAndEvents){srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){cloneCopyEvent(srcElements[i],destElements[i])}}}srcElements=destElements=null;return clone},clean:function(elems,context,fragment,scripts){var i,j,elem,tag,wrap,depth,div,hasBody,tbody,len,handleScript,jsTags,safe=context===document&&safeFragment,ret=[];if(!context||typeof context.createDocumentFragment==="undefined"){context=document}for(i=0;(elem=elems[i])!=null;i++){if(typeof elem==="number"){elem+=""}if(!elem){continue}if(typeof elem==="string"){if(!rhtml.test(elem)){elem=context.createTextNode(elem)}else{safe=safe||createSafeFragment(context);div=context.createElement("div");safe.appendChild(div);elem=elem.replace(rxhtmlTag,"<$1></$2>");tag=(rtagName.exec(elem)||["",""])[1].toLowerCase();wrap=wrapMap[tag]||wrapMap._default;depth=wrap[0];div.innerHTML=wrap[1]+elem+wrap[2];while(depth--){div=div.lastChild -}if(!jQuery.support.tbody){hasBody=rtbody.test(elem);tbody=tag==="table"&&!hasBody?div.firstChild&&div.firstChild.childNodes:wrap[1]==="<table>"&&!hasBody?div.childNodes:[];for(j=tbody.length-1;j>=0;--j){if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length){tbody[j].parentNode.removeChild(tbody[j])}}}if(!jQuery.support.leadingWhitespace&&rleadingWhitespace.test(elem)){div.insertBefore(context.createTextNode(rleadingWhitespace.exec(elem)[0]),div.firstChild)}elem=div.childNodes;div.parentNode.removeChild(div)}}if(elem.nodeType){ret.push(elem)}else{jQuery.merge(ret,elem)}}if(div){elem=div=safe=null}if(!jQuery.support.appendChecked){for(i=0;(elem=ret[i])!=null;i++){if(jQuery.nodeName(elem,"input")){fixDefaultChecked(elem)}else if(typeof elem.getElementsByTagName!=="undefined"){jQuery.grep(elem.getElementsByTagName("input"),fixDefaultChecked)}}}if(fragment){handleScript=function(elem){if(!elem.type||rscriptType.test(elem.type)){return scripts?scripts.push(elem.parentNode?elem.parentNode.removeChild(elem):elem):fragment.appendChild(elem)}};for(i=0;(elem=ret[i])!=null;i++){if(!(jQuery.nodeName(elem,"script")&&handleScript(elem))){fragment.appendChild(elem);if(typeof elem.getElementsByTagName!=="undefined"){jsTags=jQuery.grep(jQuery.merge([],elem.getElementsByTagName("script")),handleScript);ret.splice.apply(ret,[i+1,0].concat(jsTags));i+=jsTags.length}}}}return ret},cleanData:function(elems,acceptData){var data,id,elem,type,i=0,internalKey=jQuery.expando,cache=jQuery.cache,deleteExpando=jQuery.support.deleteExpando,special=jQuery.event.special;for(;(elem=elems[i])!=null;i++){if(acceptData||jQuery.acceptData(elem)){id=elem[internalKey];data=id&&cache[id];if(data){if(data.events){for(type in data.events){if(special[type]){jQuery.event.remove(elem,type)}else{jQuery.removeEvent(elem,type,data.handle)}}}if(cache[id]){delete cache[id];if(deleteExpando){delete elem[internalKey]}else if(elem.removeAttribute){elem.removeAttribute(internalKey)}else{elem[internalKey]=null}jQuery.deletedIds.push(id)}}}}}});(function(){var matched,browser;jQuery.uaMatch=function(ua){ua=ua.toLowerCase();var match=/(chrome)[ \/]([\w.]+)/.exec(ua)||/(webkit)[ \/]([\w.]+)/.exec(ua)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua)||/(msie) ([\w.]+)/.exec(ua)||ua.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua)||[];return{browser:match[1]||"",version:match[2]||"0"}};matched=jQuery.uaMatch(navigator.userAgent);browser={};if(matched.browser){browser[matched.browser]=true;browser.version=matched.version}if(browser.chrome){browser.webkit=true}else if(browser.webkit){browser.safari=true}jQuery.browser=browser;jQuery.sub=function(){function jQuerySub(selector,context){return new jQuerySub.fn.init(selector,context)}jQuery.extend(true,jQuerySub,this);jQuerySub.superclass=this;jQuerySub.fn=jQuerySub.prototype=this();jQuerySub.fn.constructor=jQuerySub;jQuerySub.sub=this.sub;jQuerySub.fn.init=function init(selector,context){if(context&&context instanceof jQuery&&!(context instanceof jQuerySub)){context=jQuerySub(context)}return jQuery.fn.init.call(this,selector,context,rootjQuerySub)};jQuerySub.fn.init.prototype=jQuerySub.fn;var rootjQuerySub=jQuerySub(document);return jQuerySub}})();var curCSS,iframe,iframeDoc,ralpha=/alpha\([^)]*\)/i,ropacity=/opacity=([^)]*)/,rposition=/^(top|right|bottom|left)$/,rdisplayswap=/^(none|table(?!-c[ea]).+)/,rmargin=/^margin/,rnumsplit=new RegExp("^("+core_pnum+")(.*)$","i"),rnumnonpx=new RegExp("^("+core_pnum+")(?!px)[a-z%]+$","i"),rrelNum=new RegExp("^([-+])=("+core_pnum+")","i"),elemdisplay={BODY:"block"},cssShow={position:"absolute",visibility:"hidden",display:"block"},cssNormalTransform={letterSpacing:0,fontWeight:400},cssExpand=["Top","Right","Bottom","Left"],cssPrefixes=["Webkit","O","Moz","ms"],eventsToggle=jQuery.fn.toggle;function vendorPropName(style,name){if(name in style){return name}var capName=name.charAt(0).toUpperCase()+name.slice(1),origName=name,i=cssPrefixes.length;while(i--){name=cssPrefixes[i]+capName;if(name in style){return name}}return origName}function isHidden(elem,el){elem=el||elem;return jQuery.css(elem,"display")==="none"||!jQuery.contains(elem.ownerDocument,elem)}function showHide(elements,show){var elem,display,values=[],index=0,length=elements.length;for(;index<length;index++){elem=elements[index];if(!elem.style){continue}values[index]=jQuery._data(elem,"olddisplay");if(show){if(!values[index]&&elem.style.display==="none"){elem.style.display=""}if(elem.style.display===""&&isHidden(elem)){values[index]=jQuery._data(elem,"olddisplay",css_defaultDisplay(elem.nodeName))}}else{display=curCSS(elem,"display");if(!values[index]&&display!=="none"){jQuery._data(elem,"olddisplay",display)}}}for(index=0;index<length;index++){elem=elements[index];if(!elem.style){continue}if(!show||elem.style.display==="none"||elem.style.display===""){elem.style.display=show?values[index]||"":"none"}}return elements}jQuery.fn.extend({css:function(name,value){return jQuery.access(this,function(elem,name,value){return value!==undefined?jQuery.style(elem,name,value):jQuery.css(elem,name)},name,value,arguments.length>1)},show:function(){return showHide(this,true)},hide:function(){return showHide(this)},toggle:function(state,fn2){var bool=typeof state==="boolean";if(jQuery.isFunction(state)&&jQuery.isFunction(fn2)){return eventsToggle.apply(this,arguments)}return this.each(function(){if(bool?state:isHidden(this)){jQuery(this).show()}else{jQuery(this).hide()}})}});jQuery.extend({cssHooks:{opacity:{get:function(elem,computed){if(computed){var ret=curCSS(elem,"opacity");return ret===""?"1":ret}}}},cssNumber:{fillOpacity:true,fontWeight:true,lineHeight:true,opacity:true,orphans:true,widows:true,zIndex:true,zoom:true},cssProps:{"float":jQuery.support.cssFloat?"cssFloat":"styleFloat"},style:function(elem,name,value,extra){if(!elem||elem.nodeType===3||elem.nodeType===8||!elem.style){return}var ret,type,hooks,origName=jQuery.camelCase(name),style=elem.style;name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(value!==undefined){type=typeof value;if(type==="string"&&(ret=rrelNum.exec(value))){value=(ret[1]+1)*ret[2]+parseFloat(jQuery.css(elem,name));type="number"}if(value==null||type==="number"&&isNaN(value)){return}if(type==="number"&&!jQuery.cssNumber[origName]){value+="px"}if(!hooks||!("set"in hooks)||(value=hooks.set(elem,value,extra))!==undefined){try{style[name]=value}catch(e){}}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,false,extra))!==undefined){return ret}return style[name]}},css:function(elem,name,numeric,extra){var val,num,hooks,origName=jQuery.camelCase(name);name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(elem.style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(hooks&&"get"in hooks){val=hooks.get(elem,true,extra)}if(val===undefined){val=curCSS(elem,name)}if(val==="normal"&&name in cssNormalTransform){val=cssNormalTransform[name]}if(numeric||extra!==undefined){num=parseFloat(val);return numeric||jQuery.isNumeric(num)?num||0:val}return val},swap:function(elem,options,callback){var ret,name,old={};for(name in options){old[name]=elem.style[name];elem.style[name]=options[name]}ret=callback.call(elem);for(name in options){elem.style[name]=old[name]}return ret}});if(window.getComputedStyle){curCSS=function(elem,name){var ret,width,minWidth,maxWidth,computed=window.getComputedStyle(elem,null),style=elem.style;if(computed){ret=computed.getPropertyValue(name)||computed[name];if(ret===""&&!jQuery.contains(elem.ownerDocument,elem)){ret=jQuery.style(elem,name)}if(rnumnonpx.test(ret)&&rmargin.test(name)){width=style.width;minWidth=style.minWidth;maxWidth=style.maxWidth;style.minWidth=style.maxWidth=style.width=ret;ret=computed.width;style.width=width;style.minWidth=minWidth;style.maxWidth=maxWidth}}return ret}}else if(document.documentElement.currentStyle){curCSS=function(elem,name){var left,rsLeft,ret=elem.currentStyle&&elem.currentStyle[name],style=elem.style;if(ret==null&&style&&style[name]){ret=style[name]}if(rnumnonpx.test(ret)&&!rposition.test(name)){left=style.left;rsLeft=elem.runtimeStyle&&elem.runtimeStyle.left;if(rsLeft){elem.runtimeStyle.left=elem.currentStyle.left}style.left=name==="fontSize"?"1em":ret;ret=style.pixelLeft+"px";style.left=left;if(rsLeft){elem.runtimeStyle.left=rsLeft}}return ret===""?"auto":ret}}function setPositiveNumber(elem,value,subtract){var matches=rnumsplit.exec(value);return matches?Math.max(0,matches[1]-(subtract||0))+(matches[2]||"px"):value}function augmentWidthOrHeight(elem,name,extra,isBorderBox){var i=extra===(isBorderBox?"border":"content")?4:name==="width"?1:0,val=0;for(;i<4;i+=2){if(extra==="margin"){val+=jQuery.css(elem,extra+cssExpand[i],true)}if(isBorderBox){if(extra==="content"){val-=parseFloat(curCSS(elem,"padding"+cssExpand[i]))||0}if(extra!=="margin"){val-=parseFloat(curCSS(elem,"border"+cssExpand[i]+"Width"))||0}}else{val+=parseFloat(curCSS(elem,"padding"+cssExpand[i]))||0;if(extra!=="padding"){val+=parseFloat(curCSS(elem,"border"+cssExpand[i]+"Width"))||0}}}return val}function getWidthOrHeight(elem,name,extra){var val=name==="width"?elem.offsetWidth:elem.offsetHeight,valueIsBorderBox=true,isBorderBox=jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing")==="border-box";if(val<=0||val==null){val=curCSS(elem,name);if(val<0||val==null){val=elem.style[name]}if(rnumnonpx.test(val)){return val}valueIsBorderBox=isBorderBox&&(jQuery.support.boxSizingReliable||val===elem.style[name]);val=parseFloat(val)||0}return val+augmentWidthOrHeight(elem,name,extra||(isBorderBox?"border":"content"),valueIsBorderBox)+"px"}function css_defaultDisplay(nodeName){if(elemdisplay[nodeName]){return elemdisplay[nodeName]}var elem=jQuery("<"+nodeName+">").appendTo(document.body),display=elem.css("display");elem.remove();if(display==="none"||display===""){iframe=document.body.appendChild(iframe||jQuery.extend(document.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!iframeDoc||!iframe.createElement){iframeDoc=(iframe.contentWindow||iframe.contentDocument).document;iframeDoc.write("<!doctype html><html><body>");iframeDoc.close()}elem=iframeDoc.body.appendChild(iframeDoc.createElement(nodeName));display=curCSS(elem,"display");document.body.removeChild(iframe)}elemdisplay[nodeName]=display;return display}jQuery.each(["height","width"],function(i,name){jQuery.cssHooks[name]={get:function(elem,computed,extra){if(computed){if(elem.offsetWidth===0&&rdisplayswap.test(curCSS(elem,"display"))){return jQuery.swap(elem,cssShow,function(){return getWidthOrHeight(elem,name,extra)})}else{return getWidthOrHeight(elem,name,extra)}}},set:function(elem,value,extra){return setPositiveNumber(elem,value,extra?augmentWidthOrHeight(elem,name,extra,jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing")==="border-box"):0)}}});if(!jQuery.support.opacity){jQuery.cssHooks.opacity={get:function(elem,computed){return ropacity.test((computed&&elem.currentStyle?elem.currentStyle.filter:elem.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":computed?"1":""},set:function(elem,value){var style=elem.style,currentStyle=elem.currentStyle,opacity=jQuery.isNumeric(value)?"alpha(opacity="+value*100+")":"",filter=currentStyle&¤tStyle.filter||style.filter||"";style.zoom=1;if(value>=1&&jQuery.trim(filter.replace(ralpha,""))===""&&style.removeAttribute){style.removeAttribute("filter");if(currentStyle&&!currentStyle.filter){return}}style.filter=ralpha.test(filter)?filter.replace(ralpha,opacity):filter+" "+opacity}}}jQuery(function(){if(!jQuery.support.reliableMarginRight){jQuery.cssHooks.marginRight={get:function(elem,computed){return jQuery.swap(elem,{display:"inline-block"},function(){if(computed){return curCSS(elem,"marginRight")}})}}}if(!jQuery.support.pixelPosition&&jQuery.fn.position){jQuery.each(["top","left"],function(i,prop){jQuery.cssHooks[prop]={get:function(elem,computed){if(computed){var ret=curCSS(elem,prop);return rnumnonpx.test(ret)?jQuery(elem).position()[prop]+"px":ret}}}})}});if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.hidden=function(elem){return elem.offsetWidth===0&&elem.offsetHeight===0||!jQuery.support.reliableHiddenOffsets&&(elem.style&&elem.style.display||curCSS(elem,"display"))==="none"};jQuery.expr.filters.visible=function(elem){return!jQuery.expr.filters.hidden(elem)}}jQuery.each({margin:"",padding:"",border:"Width"},function(prefix,suffix){jQuery.cssHooks[prefix+suffix]={expand:function(value){var i,parts=typeof value==="string"?value.split(" "):[value],expanded={};for(i=0;i<4;i++){expanded[prefix+cssExpand[i]+suffix]=parts[i]||parts[i-2]||parts[0]}return expanded}};if(!rmargin.test(prefix)){jQuery.cssHooks[prefix+suffix].set=setPositiveNumber}});var r20=/%20/g,rbracket=/\[\]$/,rCRLF=/\r?\n/g,rinput=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,rselectTextarea=/^(?:select|textarea)/i;jQuery.fn.extend({serialize:function(){return jQuery.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?jQuery.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||rselectTextarea.test(this.nodeName)||rinput.test(this.type))}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:jQuery.isArray(val)?jQuery.map(val,function(val,i){return{name:elem.name,value:val.replace(rCRLF,"\r\n")}}):{name:elem.name,value:val.replace(rCRLF,"\r\n")}}).get()}});jQuery.param=function(a,traditional){var prefix,s=[],add=function(key,value){value=jQuery.isFunction(value)?value():value==null?"":value;s[s.length]=encodeURIComponent(key)+"="+encodeURIComponent(value)};if(traditional===undefined){traditional=jQuery.ajaxSettings&&jQuery.ajaxSettings.traditional}if(jQuery.isArray(a)||a.jquery&&!jQuery.isPlainObject(a)){jQuery.each(a,function(){add(this.name,this.value)})}else{for(prefix in a){buildParams(prefix,a[prefix],traditional,add)}}return s.join("&").replace(r20,"+")};function buildParams(prefix,obj,traditional,add){var name;if(jQuery.isArray(obj)){jQuery.each(obj,function(i,v){if(traditional||rbracket.test(prefix)){add(prefix,v)}else{buildParams(prefix+"["+(typeof v==="object"?i:"")+"]",v,traditional,add)}})}else if(!traditional&&jQuery.type(obj)==="object"){for(name in obj){buildParams(prefix+"["+name+"]",obj[name],traditional,add)}}else{add(prefix,obj)}}var ajaxLocParts,ajaxLocation,rhash=/#.*$/,rheaders=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,rlocalProtocol=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,rnoContent=/^(?:GET|HEAD)$/,rprotocol=/^\/\//,rquery=/\?/,rscript=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,rts=/([?&])_=[^&]*/,rurl=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,_load=jQuery.fn.load,prefilters={},transports={},allTypes=["*/"]+["*"];try{ajaxLocation=location.href}catch(e){ajaxLocation=document.createElement("a");ajaxLocation.href="";ajaxLocation=ajaxLocation.href}ajaxLocParts=rurl.exec(ajaxLocation.toLowerCase())||[];function addToPrefiltersOrTransports(structure){return function(dataTypeExpression,func){if(typeof dataTypeExpression!=="string"){func=dataTypeExpression;dataTypeExpression="*"}var dataType,list,placeBefore,dataTypes=dataTypeExpression.toLowerCase().split(core_rspace),i=0,length=dataTypes.length;if(jQuery.isFunction(func)){for(;i<length;i++){dataType=dataTypes[i];placeBefore=/^\+/.test(dataType);if(placeBefore){dataType=dataType.substr(1)||"*"}list=structure[dataType]=structure[dataType]||[];list[placeBefore?"unshift":"push"](func)}}}}function inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,dataType,inspected){dataType=dataType||options.dataTypes[0];inspected=inspected||{};inspected[dataType]=true;var selection,list=structure[dataType],i=0,length=list?list.length:0,executeOnly=structure===prefilters;for(;i<length&&(executeOnly||!selection);i++){selection=list[i](options,originalOptions,jqXHR);if(typeof selection==="string"){if(!executeOnly||inspected[selection]){selection=undefined}else{options.dataTypes.unshift(selection);selection=inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,selection,inspected)}}}if((executeOnly||!selection)&&!inspected["*"]){selection=inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,"*",inspected)}return selection}function ajaxExtend(target,src){var key,deep,flatOptions=jQuery.ajaxSettings.flatOptions||{};for(key in src){if(src[key]!==undefined){(flatOptions[key]?target:deep||(deep={}))[key]=src[key]}}if(deep){jQuery.extend(true,target,deep)}}jQuery.fn.load=function(url,params,callback){if(typeof url!=="string"&&_load){return _load.apply(this,arguments)}if(!this.length){return this}var selector,type,response,self=this,off=url.indexOf(" ");if(off>=0){selector=url.slice(off,url.length);url=url.slice(0,off)}if(jQuery.isFunction(params)){callback=params;params=undefined}else if(params&&typeof params==="object"){type="POST"}jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(jqXHR,status){if(callback){self.each(callback,response||[jqXHR.responseText,status,jqXHR])}}}).done(function(responseText){response=arguments;self.html(selector?jQuery("<div>").append(responseText.replace(rscript,"")).find(selector):responseText)});return this};jQuery.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(i,o){jQuery.fn[o]=function(f){return this.on(o,f)}});jQuery.each(["get","post"],function(i,method){jQuery[method]=function(url,data,callback,type){if(jQuery.isFunction(data)){type=type||callback;callback=data;data=undefined}return jQuery.ajax({type:method,url:url,data:data,success:callback,dataType:type})}});jQuery.extend({getScript:function(url,callback){return jQuery.get(url,undefined,callback,"script")},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json")},ajaxSetup:function(target,settings){if(settings){ajaxExtend(target,jQuery.ajaxSettings)}else{settings=target;target=jQuery.ajaxSettings}ajaxExtend(target,settings);return target},ajaxSettings:{url:ajaxLocation,isLocal:rlocalProtocol.test(ajaxLocParts[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":allTypes},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":window.String,"text html":true,"text json":jQuery.parseJSON,"text xml":jQuery.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:addToPrefiltersOrTransports(prefilters),ajaxTransport:addToPrefiltersOrTransports(transports),ajax:function(url,options){if(typeof url==="object"){options=url;url=undefined}options=options||{};var ifModifiedKey,responseHeadersString,responseHeaders,transport,timeoutTimer,parts,fireGlobals,i,s=jQuery.ajaxSetup({},options),callbackContext=s.context||s,globalEventContext=callbackContext!==s&&(callbackContext.nodeType||callbackContext instanceof jQuery)?jQuery(callbackContext):jQuery.event,deferred=jQuery.Deferred(),completeDeferred=jQuery.Callbacks("once memory"),statusCode=s.statusCode||{},requestHeaders={},requestHeadersNames={},state=0,strAbort="canceled",jqXHR={readyState:0,setRequestHeader:function(name,value){if(!state){var lname=name.toLowerCase();name=requestHeadersNames[lname]=requestHeadersNames[lname]||name;requestHeaders[name]=value}return this},getAllResponseHeaders:function(){return state===2?responseHeadersString:null},getResponseHeader:function(key){var match;if(state===2){if(!responseHeaders){responseHeaders={};while(match=rheaders.exec(responseHeadersString)){responseHeaders[match[1].toLowerCase()]=match[2]}}match=responseHeaders[key.toLowerCase()]}return match===undefined?null:match},overrideMimeType:function(type){if(!state){s.mimeType=type}return this},abort:function(statusText){statusText=statusText||strAbort;if(transport){transport.abort(statusText)}done(0,statusText);return this}};function done(status,nativeStatusText,responses,headers){var isSuccess,success,error,response,modified,statusText=nativeStatusText;if(state===2){return}state=2;if(timeoutTimer){clearTimeout(timeoutTimer)}transport=undefined;responseHeadersString=headers||"";jqXHR.readyState=status>0?4:0;if(responses){response=ajaxHandleResponses(s,jqXHR,responses)}if(status>=200&&status<300||status===304){if(s.ifModified){modified=jqXHR.getResponseHeader("Last-Modified");if(modified){jQuery.lastModified[ifModifiedKey]=modified}modified=jqXHR.getResponseHeader("Etag");if(modified){jQuery.etag[ifModifiedKey]=modified}}if(status===304){statusText="notmodified";isSuccess=true}else{isSuccess=ajaxConvert(s,response);statusText=isSuccess.state;success=isSuccess.data;error=isSuccess.error;isSuccess=!error}}else{error=statusText;if(!statusText||status){statusText="error";if(status<0){status=0}}}jqXHR.status=status;jqXHR.statusText=(nativeStatusText||statusText)+"";if(isSuccess){deferred.resolveWith(callbackContext,[success,statusText,jqXHR])}else{deferred.rejectWith(callbackContext,[jqXHR,statusText,error])}jqXHR.statusCode(statusCode);statusCode=undefined;if(fireGlobals){globalEventContext.trigger("ajax"+(isSuccess?"Success":"Error"),[jqXHR,s,isSuccess?success:error])}completeDeferred.fireWith(callbackContext,[jqXHR,statusText]);if(fireGlobals){globalEventContext.trigger("ajaxComplete",[jqXHR,s]);if(!--jQuery.active){jQuery.event.trigger("ajaxStop")}}}deferred.promise(jqXHR);jqXHR.success=jqXHR.done;jqXHR.error=jqXHR.fail;jqXHR.complete=completeDeferred.add;jqXHR.statusCode=function(map){if(map){var tmp;if(state<2){for(tmp in map){statusCode[tmp]=[statusCode[tmp],map[tmp]]}}else{tmp=map[jqXHR.status];jqXHR.always(tmp)}}return this};s.url=((url||s.url)+"").replace(rhash,"").replace(rprotocol,ajaxLocParts[1]+"//");s.dataTypes=jQuery.trim(s.dataType||"*").toLowerCase().split(core_rspace);if(s.crossDomain==null){parts=rurl.exec(s.url.toLowerCase());s.crossDomain=!!(parts&&(parts[1]!==ajaxLocParts[1]||parts[2]!==ajaxLocParts[2]||(parts[3]||(parts[1]==="http:"?80:443))!=(ajaxLocParts[3]||(ajaxLocParts[1]==="http:"?80:443))))}if(s.data&&s.processData&&typeof s.data!=="string"){s.data=jQuery.param(s.data,s.traditional)}inspectPrefiltersOrTransports(prefilters,s,options,jqXHR);if(state===2){return jqXHR}fireGlobals=s.global;s.type=s.type.toUpperCase();s.hasContent=!rnoContent.test(s.type);if(fireGlobals&&jQuery.active++===0){jQuery.event.trigger("ajaxStart")}if(!s.hasContent){if(s.data){s.url+=(rquery.test(s.url)?"&":"?")+s.data;delete s.data}ifModifiedKey=s.url;if(s.cache===false){var ts=jQuery.now(),ret=s.url.replace(rts,"$1_="+ts);s.url=ret+(ret===s.url?(rquery.test(s.url)?"&":"?")+"_="+ts:"")}}if(s.data&&s.hasContent&&s.contentType!==false||options.contentType){jqXHR.setRequestHeader("Content-Type",s.contentType)}if(s.ifModified){ifModifiedKey=ifModifiedKey||s.url;if(jQuery.lastModified[ifModifiedKey]){jqXHR.setRequestHeader("If-Modified-Since",jQuery.lastModified[ifModifiedKey])}if(jQuery.etag[ifModifiedKey]){jqXHR.setRequestHeader("If-None-Match",jQuery.etag[ifModifiedKey])}}jqXHR.setRequestHeader("Accept",s.dataTypes[0]&&s.accepts[s.dataTypes[0]]?s.accepts[s.dataTypes[0]]+(s.dataTypes[0]!=="*"?", "+allTypes+"; q=0.01":""):s.accepts["*"]);for(i in s.headers){jqXHR.setRequestHeader(i,s.headers[i])}if(s.beforeSend&&(s.beforeSend.call(callbackContext,jqXHR,s)===false||state===2)){return jqXHR.abort()}strAbort="abort";for(i in{success:1,error:1,complete:1}){jqXHR[i](s[i])}transport=inspectPrefiltersOrTransports(transports,s,options,jqXHR);if(!transport){done(-1,"No Transport")}else{jqXHR.readyState=1;if(fireGlobals){globalEventContext.trigger("ajaxSend",[jqXHR,s])}if(s.async&&s.timeout>0){timeoutTimer=setTimeout(function(){jqXHR.abort("timeout")},s.timeout)}try{state=1;transport.send(requestHeaders,done)}catch(e){if(state<2){done(-1,e)}else{throw e}}}return jqXHR},active:0,lastModified:{},etag:{}});function ajaxHandleResponses(s,jqXHR,responses){var ct,type,finalDataType,firstDataType,contents=s.contents,dataTypes=s.dataTypes,responseFields=s.responseFields;for(type in responseFields){if(type in responses){jqXHR[responseFields[type]]=responses[type]}}while(dataTypes[0]==="*"){dataTypes.shift();if(ct===undefined){ct=s.mimeType||jqXHR.getResponseHeader("content-type")}}if(ct){for(type in contents){if(contents[type]&&contents[type].test(ct)){dataTypes.unshift(type);break}}}if(dataTypes[0]in responses){finalDataType=dataTypes[0]}else{for(type in responses){if(!dataTypes[0]||s.converters[type+" "+dataTypes[0]]){finalDataType=type;break}if(!firstDataType){firstDataType=type}}finalDataType=finalDataType||firstDataType}if(finalDataType){if(finalDataType!==dataTypes[0]){dataTypes.unshift(finalDataType)}return responses[finalDataType]}}function ajaxConvert(s,response){var conv,conv2,current,tmp,dataTypes=s.dataTypes.slice(),prev=dataTypes[0],converters={},i=0;if(s.dataFilter){response=s.dataFilter(response,s.dataType)}if(dataTypes[1]){for(conv in s.converters){converters[conv.toLowerCase()]=s.converters[conv]}}for(;current=dataTypes[++i];){if(current!=="*"){if(prev!=="*"&&prev!==current){conv=converters[prev+" "+current]||converters["* "+current];if(!conv){for(conv2 in converters){tmp=conv2.split(" ");if(tmp[1]===current){conv=converters[prev+" "+tmp[0]]||converters["* "+tmp[0]];if(conv){if(conv===true){conv=converters[conv2]}else if(converters[conv2]!==true){current=tmp[0];dataTypes.splice(i--,0,current)}break}}}}if(conv!==true){if(conv&&s["throws"]){response=conv(response)}else{try{response=conv(response)}catch(e){return{state:"parsererror",error:conv?e:"No conversion from "+prev+" to "+current}}}}}prev=current}}return{state:"success",data:response}}var oldCallbacks=[],rquestion=/\?/,rjsonp=/(=)\?(?=&|$)|\?\?/,nonce=jQuery.now();jQuery.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var callback=oldCallbacks.pop()||jQuery.expando+"_"+nonce++;this[callback]=true;return callback}});jQuery.ajaxPrefilter("json jsonp",function(s,originalSettings,jqXHR){var callbackName,overwritten,responseContainer,data=s.data,url=s.url,hasCallback=s.jsonp!==false,replaceInUrl=hasCallback&&rjsonp.test(url),replaceInData=hasCallback&&!replaceInUrl&&typeof data==="string"&&!(s.contentType||"").indexOf("application/x-www-form-urlencoded")&&rjsonp.test(data);if(s.dataTypes[0]==="jsonp"||replaceInUrl||replaceInData){callbackName=s.jsonpCallback=jQuery.isFunction(s.jsonpCallback)?s.jsonpCallback():s.jsonpCallback;overwritten=window[callbackName];if(replaceInUrl){s.url=url.replace(rjsonp,"$1"+callbackName)}else if(replaceInData){s.data=data.replace(rjsonp,"$1"+callbackName)}else if(hasCallback){s.url+=(rquestion.test(url)?"&":"?")+s.jsonp+"="+callbackName}s.converters["script json"]=function(){if(!responseContainer){jQuery.error(callbackName+" was not called")}return responseContainer[0]};s.dataTypes[0]="json";window[callbackName]=function(){responseContainer=arguments};jqXHR.always(function(){window[callbackName]=overwritten;if(s[callbackName]){s.jsonpCallback=originalSettings.jsonpCallback;oldCallbacks.push(callbackName)}if(responseContainer&&jQuery.isFunction(overwritten)){overwritten(responseContainer[0])}responseContainer=overwritten=undefined});return"script"}});jQuery.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(text){jQuery.globalEval(text);return text}}});jQuery.ajaxPrefilter("script",function(s){if(s.cache===undefined){s.cache=false}if(s.crossDomain){s.type="GET";s.global=false}});jQuery.ajaxTransport("script",function(s){if(s.crossDomain){var script,head=document.head||document.getElementsByTagName("head")[0]||document.documentElement;return{send:function(_,callback){script=document.createElement("script");script.async="async";if(s.scriptCharset){script.charset=s.scriptCharset}script.src=s.url;script.onload=script.onreadystatechange=function(_,isAbort){if(isAbort||!script.readyState||/loaded|complete/.test(script.readyState)){script.onload=script.onreadystatechange=null;if(head&&script.parentNode){head.removeChild(script)}script=undefined;if(!isAbort){callback(200,"success")}}};head.insertBefore(script,head.firstChild)},abort:function(){if(script){script.onload(0,1)}}}}});var xhrCallbacks,xhrOnUnloadAbort=window.ActiveXObject?function(){for(var key in xhrCallbacks){xhrCallbacks[key](0,1)}}:false,xhrId=0;function createStandardXHR(){try{return new window.XMLHttpRequest}catch(e){}}function createActiveXHR(){try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(e){}}jQuery.ajaxSettings.xhr=window.ActiveXObject?function(){return!this.isLocal&&createStandardXHR()||createActiveXHR()}:createStandardXHR;(function(xhr){jQuery.extend(jQuery.support,{ajax:!!xhr,cors:!!xhr&&"withCredentials"in xhr})})(jQuery.ajaxSettings.xhr());if(jQuery.support.ajax){jQuery.ajaxTransport(function(s){if(!s.crossDomain||jQuery.support.cors){var callback;return{send:function(headers,complete){var handle,i,xhr=s.xhr();if(s.username){xhr.open(s.type,s.url,s.async,s.username,s.password)}else{xhr.open(s.type,s.url,s.async)}if(s.xhrFields){for(i in s.xhrFields){xhr[i]=s.xhrFields[i]}}if(s.mimeType&&xhr.overrideMimeType){xhr.overrideMimeType(s.mimeType)}if(!s.crossDomain&&!headers["X-Requested-With"]){headers["X-Requested-With"]="XMLHttpRequest"}try{for(i in headers){xhr.setRequestHeader(i,headers[i])}}catch(_){}xhr.send(s.hasContent&&s.data||null);callback=function(_,isAbort){var status,statusText,responseHeaders,responses,xml;try{if(callback&&(isAbort||xhr.readyState===4)){callback=undefined;if(handle){xhr.onreadystatechange=jQuery.noop;if(xhrOnUnloadAbort){delete xhrCallbacks[handle]}}if(isAbort){if(xhr.readyState!==4){xhr.abort()}}else{status=xhr.status;responseHeaders=xhr.getAllResponseHeaders();responses={};xml=xhr.responseXML;if(xml&&xml.documentElement){responses.xml=xml}try{responses.text=xhr.responseText}catch(e){}try{statusText=xhr.statusText}catch(e){statusText=""}if(!status&&s.isLocal&&!s.crossDomain){status=responses.text?200:404}else if(status===1223){status=204}}}}catch(firefoxAccessException){if(!isAbort){complete(-1,firefoxAccessException)}}if(responses){complete(status,statusText,responses,responseHeaders)}};if(!s.async){callback()}else if(xhr.readyState===4){setTimeout(callback,0)}else{handle=++xhrId;if(xhrOnUnloadAbort){if(!xhrCallbacks){xhrCallbacks={};jQuery(window).unload(xhrOnUnloadAbort)}xhrCallbacks[handle]=callback}xhr.onreadystatechange=callback}},abort:function(){if(callback){callback(0,1)}}}}})}var fxNow,timerId,rfxtypes=/^(?:toggle|show|hide)$/,rfxnum=new RegExp("^(?:([-+])=|)("+core_pnum+")([a-z%]*)$","i"),rrun=/queueHooks$/,animationPrefilters=[defaultPrefilter],tweeners={"*":[function(prop,value){var end,unit,tween=this.createTween(prop,value),parts=rfxnum.exec(value),target=tween.cur(),start=+target||0,scale=1,maxIterations=20;if(parts){end=+parts[2];unit=parts[3]||(jQuery.cssNumber[prop]?"":"px");if(unit!=="px"&&start){start=jQuery.css(tween.elem,prop,true)||end||1;do{scale=scale||".5";start=start/scale;jQuery.style(tween.elem,prop,start+unit)}while(scale!==(scale=tween.cur()/target)&&scale!==1&&--maxIterations)}tween.unit=unit;tween.start=start;tween.end=parts[1]?start+(parts[1]+1)*end:end}return tween}]};function createFxNow(){setTimeout(function(){fxNow=undefined},0);return fxNow=jQuery.now()}function createTweens(animation,props){jQuery.each(props,function(prop,value){var collection=(tweeners[prop]||[]).concat(tweeners["*"]),index=0,length=collection.length;for(;index<length;index++){if(collection[index].call(animation,prop,value)){return}}})}function Animation(elem,properties,options){var result,index=0,tweenerIndex=0,length=animationPrefilters.length,deferred=jQuery.Deferred().always(function(){delete tick.elem}),tick=function(){var currentTime=fxNow||createFxNow(),remaining=Math.max(0,animation.startTime+animation.duration-currentTime),temp=remaining/animation.duration||0,percent=1-temp,index=0,length=animation.tweens.length; -for(;index<length;index++){animation.tweens[index].run(percent)}deferred.notifyWith(elem,[animation,percent,remaining]);if(percent<1&&length){return remaining}else{deferred.resolveWith(elem,[animation]);return false}},animation=deferred.promise({elem:elem,props:jQuery.extend({},properties),opts:jQuery.extend(true,{specialEasing:{}},options),originalProperties:properties,originalOptions:options,startTime:fxNow||createFxNow(),duration:options.duration,tweens:[],createTween:function(prop,end,easing){var tween=jQuery.Tween(elem,animation.opts,prop,end,animation.opts.specialEasing[prop]||animation.opts.easing);animation.tweens.push(tween);return tween},stop:function(gotoEnd){var index=0,length=gotoEnd?animation.tweens.length:0;for(;index<length;index++){animation.tweens[index].run(1)}if(gotoEnd){deferred.resolveWith(elem,[animation,gotoEnd])}else{deferred.rejectWith(elem,[animation,gotoEnd])}return this}}),props=animation.props;propFilter(props,animation.opts.specialEasing);for(;index<length;index++){result=animationPrefilters[index].call(animation,elem,props,animation.opts);if(result){return result}}createTweens(animation,props);if(jQuery.isFunction(animation.opts.start)){animation.opts.start.call(elem,animation)}jQuery.fx.timer(jQuery.extend(tick,{anim:animation,queue:animation.opts.queue,elem:elem}));return animation.progress(animation.opts.progress).done(animation.opts.done,animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always)}function propFilter(props,specialEasing){var index,name,easing,value,hooks;for(index in props){name=jQuery.camelCase(index);easing=specialEasing[name];value=props[index];if(jQuery.isArray(value)){easing=value[1];value=props[index]=value[0]}if(index!==name){props[name]=value;delete props[index]}hooks=jQuery.cssHooks[name];if(hooks&&"expand"in hooks){value=hooks.expand(value);delete props[name];for(index in value){if(!(index in props)){props[index]=value[index];specialEasing[index]=easing}}}else{specialEasing[name]=easing}}}jQuery.Animation=jQuery.extend(Animation,{tweener:function(props,callback){if(jQuery.isFunction(props)){callback=props;props=["*"]}else{props=props.split(" ")}var prop,index=0,length=props.length;for(;index<length;index++){prop=props[index];tweeners[prop]=tweeners[prop]||[];tweeners[prop].unshift(callback)}},prefilter:function(callback,prepend){if(prepend){animationPrefilters.unshift(callback)}else{animationPrefilters.push(callback)}}});function defaultPrefilter(elem,props,opts){var index,prop,value,length,dataShow,toggle,tween,hooks,oldfire,anim=this,style=elem.style,orig={},handled=[],hidden=elem.nodeType&&isHidden(elem);if(!opts.queue){hooks=jQuery._queueHooks(elem,"fx");if(hooks.unqueued==null){hooks.unqueued=0;oldfire=hooks.empty.fire;hooks.empty.fire=function(){if(!hooks.unqueued){oldfire()}}}hooks.unqueued++;anim.always(function(){anim.always(function(){hooks.unqueued--;if(!jQuery.queue(elem,"fx").length){hooks.empty.fire()}})})}if(elem.nodeType===1&&("height"in props||"width"in props)){opts.overflow=[style.overflow,style.overflowX,style.overflowY];if(jQuery.css(elem,"display")==="inline"&&jQuery.css(elem,"float")==="none"){if(!jQuery.support.inlineBlockNeedsLayout||css_defaultDisplay(elem.nodeName)==="inline"){style.display="inline-block"}else{style.zoom=1}}}if(opts.overflow){style.overflow="hidden";if(!jQuery.support.shrinkWrapBlocks){anim.done(function(){style.overflow=opts.overflow[0];style.overflowX=opts.overflow[1];style.overflowY=opts.overflow[2]})}}for(index in props){value=props[index];if(rfxtypes.exec(value)){delete props[index];toggle=toggle||value==="toggle";if(value===(hidden?"hide":"show")){continue}handled.push(index)}}length=handled.length;if(length){dataShow=jQuery._data(elem,"fxshow")||jQuery._data(elem,"fxshow",{});if("hidden"in dataShow){hidden=dataShow.hidden}if(toggle){dataShow.hidden=!hidden}if(hidden){jQuery(elem).show()}else{anim.done(function(){jQuery(elem).hide()})}anim.done(function(){var prop;jQuery.removeData(elem,"fxshow",true);for(prop in orig){jQuery.style(elem,prop,orig[prop])}});for(index=0;index<length;index++){prop=handled[index];tween=anim.createTween(prop,hidden?dataShow[prop]:0);orig[prop]=dataShow[prop]||jQuery.style(elem,prop);if(!(prop in dataShow)){dataShow[prop]=tween.start;if(hidden){tween.end=tween.start;tween.start=prop==="width"||prop==="height"?1:0}}}}}function Tween(elem,options,prop,end,easing){return new Tween.prototype.init(elem,options,prop,end,easing)}jQuery.Tween=Tween;Tween.prototype={constructor:Tween,init:function(elem,options,prop,end,easing,unit){this.elem=elem;this.prop=prop;this.easing=easing||"swing";this.options=options;this.start=this.now=this.cur();this.end=end;this.unit=unit||(jQuery.cssNumber[prop]?"":"px")},cur:function(){var hooks=Tween.propHooks[this.prop];return hooks&&hooks.get?hooks.get(this):Tween.propHooks._default.get(this)},run:function(percent){var eased,hooks=Tween.propHooks[this.prop];if(this.options.duration){this.pos=eased=jQuery.easing[this.easing](percent,this.options.duration*percent,0,1,this.options.duration)}else{this.pos=eased=percent}this.now=(this.end-this.start)*eased+this.start;if(this.options.step){this.options.step.call(this.elem,this.now,this)}if(hooks&&hooks.set){hooks.set(this)}else{Tween.propHooks._default.set(this)}return this}};Tween.prototype.init.prototype=Tween.prototype;Tween.propHooks={_default:{get:function(tween){var result;if(tween.elem[tween.prop]!=null&&(!tween.elem.style||tween.elem.style[tween.prop]==null)){return tween.elem[tween.prop]}result=jQuery.css(tween.elem,tween.prop,false,"");return!result||result==="auto"?0:result},set:function(tween){if(jQuery.fx.step[tween.prop]){jQuery.fx.step[tween.prop](tween)}else if(tween.elem.style&&(tween.elem.style[jQuery.cssProps[tween.prop]]!=null||jQuery.cssHooks[tween.prop])){jQuery.style(tween.elem,tween.prop,tween.now+tween.unit)}else{tween.elem[tween.prop]=tween.now}}}};Tween.propHooks.scrollTop=Tween.propHooks.scrollLeft={set:function(tween){if(tween.elem.nodeType&&tween.elem.parentNode){tween.elem[tween.prop]=tween.now}}};jQuery.each(["toggle","show","hide"],function(i,name){var cssFn=jQuery.fn[name];jQuery.fn[name]=function(speed,easing,callback){return speed==null||typeof speed==="boolean"||!i&&jQuery.isFunction(speed)&&jQuery.isFunction(easing)?cssFn.apply(this,arguments):this.animate(genFx(name,true),speed,easing,callback)}});jQuery.fn.extend({fadeTo:function(speed,to,easing,callback){return this.filter(isHidden).css("opacity",0).show().end().animate({opacity:to},speed,easing,callback)},animate:function(prop,speed,easing,callback){var empty=jQuery.isEmptyObject(prop),optall=jQuery.speed(speed,easing,callback),doAnimation=function(){var anim=Animation(this,jQuery.extend({},prop),optall);if(empty){anim.stop(true)}};return empty||optall.queue===false?this.each(doAnimation):this.queue(optall.queue,doAnimation)},stop:function(type,clearQueue,gotoEnd){var stopQueue=function(hooks){var stop=hooks.stop;delete hooks.stop;stop(gotoEnd)};if(typeof type!=="string"){gotoEnd=clearQueue;clearQueue=type;type=undefined}if(clearQueue&&type!==false){this.queue(type||"fx",[])}return this.each(function(){var dequeue=true,index=type!=null&&type+"queueHooks",timers=jQuery.timers,data=jQuery._data(this);if(index){if(data[index]&&data[index].stop){stopQueue(data[index])}}else{for(index in data){if(data[index]&&data[index].stop&&rrun.test(index)){stopQueue(data[index])}}}for(index=timers.length;index--;){if(timers[index].elem===this&&(type==null||timers[index].queue===type)){timers[index].anim.stop(gotoEnd);dequeue=false;timers.splice(index,1)}}if(dequeue||!gotoEnd){jQuery.dequeue(this,type)}})}});function genFx(type,includeWidth){var which,attrs={height:type},i=0;includeWidth=includeWidth?1:0;for(;i<4;i+=2-includeWidth){which=cssExpand[i];attrs["margin"+which]=attrs["padding"+which]=type}if(includeWidth){attrs.opacity=attrs.width=type}return attrs}jQuery.each({slideDown:genFx("show"),slideUp:genFx("hide"),slideToggle:genFx("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(name,props){jQuery.fn[name]=function(speed,easing,callback){return this.animate(props,speed,easing,callback)}});jQuery.speed=function(speed,easing,fn){var opt=speed&&typeof speed==="object"?jQuery.extend({},speed):{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&!jQuery.isFunction(easing)&&easing};opt.duration=jQuery.fx.off?0:typeof opt.duration==="number"?opt.duration:opt.duration in jQuery.fx.speeds?jQuery.fx.speeds[opt.duration]:jQuery.fx.speeds._default;if(opt.queue==null||opt.queue===true){opt.queue="fx"}opt.old=opt.complete;opt.complete=function(){if(jQuery.isFunction(opt.old)){opt.old.call(this)}if(opt.queue){jQuery.dequeue(this,opt.queue)}};return opt};jQuery.easing={linear:function(p){return p},swing:function(p){return.5-Math.cos(p*Math.PI)/2}};jQuery.timers=[];jQuery.fx=Tween.prototype.init;jQuery.fx.tick=function(){var timer,timers=jQuery.timers,i=0;fxNow=jQuery.now();for(;i<timers.length;i++){timer=timers[i];if(!timer()&&timers[i]===timer){timers.splice(i--,1)}}if(!timers.length){jQuery.fx.stop()}fxNow=undefined};jQuery.fx.timer=function(timer){if(timer()&&jQuery.timers.push(timer)&&!timerId){timerId=setInterval(jQuery.fx.tick,jQuery.fx.interval)}};jQuery.fx.interval=13;jQuery.fx.stop=function(){clearInterval(timerId);timerId=null};jQuery.fx.speeds={slow:600,fast:200,_default:400};jQuery.fx.step={};if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.animated=function(elem){return jQuery.grep(jQuery.timers,function(fn){return elem===fn.elem}).length}}var rroot=/^(?:body|html)$/i;jQuery.fn.offset=function(options){if(arguments.length){return options===undefined?this:this.each(function(i){jQuery.offset.setOffset(this,options,i)})}var docElem,body,win,clientTop,clientLeft,scrollTop,scrollLeft,box={top:0,left:0},elem=this[0],doc=elem&&elem.ownerDocument;if(!doc){return}if((body=doc.body)===elem){return jQuery.offset.bodyOffset(elem)}docElem=doc.documentElement;if(!jQuery.contains(docElem,elem)){return box}if(typeof elem.getBoundingClientRect!=="undefined"){box=elem.getBoundingClientRect()}win=getWindow(doc);clientTop=docElem.clientTop||body.clientTop||0;clientLeft=docElem.clientLeft||body.clientLeft||0;scrollTop=win.pageYOffset||docElem.scrollTop;scrollLeft=win.pageXOffset||docElem.scrollLeft;return{top:box.top+scrollTop-clientTop,left:box.left+scrollLeft-clientLeft}};jQuery.offset={bodyOffset:function(body){var top=body.offsetTop,left=body.offsetLeft;if(jQuery.support.doesNotIncludeMarginInBodyOffset){top+=parseFloat(jQuery.css(body,"marginTop"))||0;left+=parseFloat(jQuery.css(body,"marginLeft"))||0}return{top:top,left:left}},setOffset:function(elem,options,i){var position=jQuery.css(elem,"position");if(position==="static"){elem.style.position="relative"}var curElem=jQuery(elem),curOffset=curElem.offset(),curCSSTop=jQuery.css(elem,"top"),curCSSLeft=jQuery.css(elem,"left"),calculatePosition=(position==="absolute"||position==="fixed")&&jQuery.inArray("auto",[curCSSTop,curCSSLeft])>-1,props={},curPosition={},curTop,curLeft;if(calculatePosition){curPosition=curElem.position();curTop=curPosition.top;curLeft=curPosition.left}else{curTop=parseFloat(curCSSTop)||0;curLeft=parseFloat(curCSSLeft)||0}if(jQuery.isFunction(options)){options=options.call(elem,i,curOffset)}if(options.top!=null){props.top=options.top-curOffset.top+curTop}if(options.left!=null){props.left=options.left-curOffset.left+curLeft}if("using"in options){options.using.call(elem,props)}else{curElem.css(props)}}};jQuery.fn.extend({position:function(){if(!this[0]){return}var elem=this[0],offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=rroot.test(offsetParent[0].nodeName)?{top:0,left:0}:offsetParent.offset();offset.top-=parseFloat(jQuery.css(elem,"marginTop"))||0;offset.left-=parseFloat(jQuery.css(elem,"marginLeft"))||0;parentOffset.top+=parseFloat(jQuery.css(offsetParent[0],"borderTopWidth"))||0;parentOffset.left+=parseFloat(jQuery.css(offsetParent[0],"borderLeftWidth"))||0;return{top:offset.top-parentOffset.top,left:offset.left-parentOffset.left}},offsetParent:function(){return this.map(function(){var offsetParent=this.offsetParent||document.body;while(offsetParent&&(!rroot.test(offsetParent.nodeName)&&jQuery.css(offsetParent,"position")==="static")){offsetParent=offsetParent.offsetParent}return offsetParent||document.body})}});jQuery.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(method,prop){var top=/Y/.test(prop);jQuery.fn[method]=function(val){return jQuery.access(this,function(elem,method,val){var win=getWindow(elem);if(val===undefined){return win?prop in win?win[prop]:win.document.documentElement[method]:elem[method]}if(win){win.scrollTo(!top?val:jQuery(win).scrollLeft(),top?val:jQuery(win).scrollTop())}else{elem[method]=val}},method,val,arguments.length,null)}});function getWindow(elem){return jQuery.isWindow(elem)?elem:elem.nodeType===9?elem.defaultView||elem.parentWindow:false}jQuery.each({Height:"height",Width:"width"},function(name,type){jQuery.each({padding:"inner"+name,content:type,"":"outer"+name},function(defaultExtra,funcName){jQuery.fn[funcName]=function(margin,value){var chainable=arguments.length&&(defaultExtra||typeof margin!=="boolean"),extra=defaultExtra||(margin===true||value===true?"margin":"border");return jQuery.access(this,function(elem,type,value){var doc;if(jQuery.isWindow(elem)){return elem.document.documentElement["client"+name]}if(elem.nodeType===9){doc=elem.documentElement;return Math.max(elem.body["scroll"+name],doc["scroll"+name],elem.body["offset"+name],doc["offset"+name],doc["client"+name])}return value===undefined?jQuery.css(elem,type,value,extra):jQuery.style(elem,type,value,extra)},type,chainable?margin:undefined,chainable,null)}})});window.jQuery=window.$=jQuery;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return jQuery})}})(window);
\ No newline at end of file +(function(window,undefined){var rootjQuery,readyList,document=window.document,location=window.location,navigator=window.navigator,_jQuery=window.jQuery,_$=window.$,core_push=Array.prototype.push,core_slice=Array.prototype.slice,core_indexOf=Array.prototype.indexOf,core_toString=Object.prototype.toString,core_hasOwn=Object.prototype.hasOwnProperty,core_trim=String.prototype.trim,jQuery=function(selector,context){return new jQuery.fn.init(selector,context,rootjQuery)},core_pnum=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,core_rnotwhite=/\S/,core_rspace=/\s+/,rtrim=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,rquickExpr=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,rsingleTag=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,rvalidchars=/^[\],:{}\s]*$/,rvalidbraces=/(?:^|:|,)(?:\s*\[)+/g,rvalidescape=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,rvalidtokens=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,rmsPrefix=/^-ms-/,rdashAlpha=/-([\da-z])/gi,fcamelCase=function(all,letter){return(letter+"").toUpperCase()},DOMContentLoaded=function(){if(document.addEventListener){document.removeEventListener("DOMContentLoaded",DOMContentLoaded,false);jQuery.ready()}else if(document.readyState==="complete"){document.detachEvent("onreadystatechange",DOMContentLoaded);jQuery.ready()}},class2type={};jQuery.fn=jQuery.prototype={constructor:jQuery,init:function(selector,context,rootjQuery){var match,elem,ret,doc;if(!selector){return this}if(selector.nodeType){this.context=this[0]=selector;this.length=1;return this}if(typeof selector==="string"){if(selector.charAt(0)==="<"&&selector.charAt(selector.length-1)===">"&&selector.length>=3){match=[null,selector,null]}else{match=rquickExpr.exec(selector)}if(match&&(match[1]||!context)){if(match[1]){context=context instanceof jQuery?context[0]:context;doc=context&&context.nodeType?context.ownerDocument||context:document;selector=jQuery.parseHTML(match[1],doc,true);if(rsingleTag.test(match[1])&&jQuery.isPlainObject(context)){this.attr.call(selector,context,true)}return jQuery.merge(this,selector)}else{elem=document.getElementById(match[2]);if(elem&&elem.parentNode){if(elem.id!==match[2]){return rootjQuery.find(selector)}this.length=1;this[0]=elem}this.context=document;this.selector=selector;return this}}else if(!context||context.jquery){return(context||rootjQuery).find(selector)}else{return this.constructor(context).find(selector)}}else if(jQuery.isFunction(selector)){return rootjQuery.ready(selector)}if(selector.selector!==undefined){this.selector=selector.selector;this.context=selector.context}return jQuery.makeArray(selector,this)},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return core_slice.call(this)},get:function(num){return num==null?this.toArray():num<0?this[this.length+num]:this[num]},pushStack:function(elems,name,selector){var ret=jQuery.merge(this.constructor(),elems);ret.prevObject=this;ret.context=this.context;if(name==="find"){ret.selector=this.selector+(this.selector?" ":"")+selector}else if(name){ret.selector=this.selector+"."+name+"("+selector+")"}return ret},each:function(callback,args){return jQuery.each(this,callback,args)},ready:function(fn){jQuery.ready.promise().done(fn);return this},eq:function(i){i=+i;return i===-1?this.slice(i):this.slice(i,i+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(core_slice.apply(this,arguments),"slice",core_slice.call(arguments).join(","))},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem)}))},end:function(){return this.prevObject||this.constructor(null)},push:core_push,sort:[].sort,splice:[].splice};jQuery.fn.init.prototype=jQuery.fn;jQuery.extend=jQuery.fn.extend=function(){var options,name,src,copy,copyIsArray,clone,target=arguments[0]||{},i=1,length=arguments.length,deep=false;if(typeof target==="boolean"){deep=target;target=arguments[1]||{};i=2}if(typeof target!=="object"&&!jQuery.isFunction(target)){target={}}if(length===i){target=this;--i}for(;i<length;i++){if((options=arguments[i])!=null){for(name in options){src=target[name];copy=options[name];if(target===copy){continue}if(deep&©&&(jQuery.isPlainObject(copy)||(copyIsArray=jQuery.isArray(copy)))){if(copyIsArray){copyIsArray=false;clone=src&&jQuery.isArray(src)?src:[]}else{clone=src&&jQuery.isPlainObject(src)?src:{}}target[name]=jQuery.extend(deep,clone,copy)}else if(copy!==undefined){target[name]=copy}}}}return target};jQuery.extend({noConflict:function(deep){if(window.$===jQuery){window.$=_$}if(deep&&window.jQuery===jQuery){window.jQuery=_jQuery}return jQuery},isReady:false,readyWait:1,holdReady:function(hold){if(hold){jQuery.readyWait++}else{jQuery.ready(true)}},ready:function(wait){if(wait===true?--jQuery.readyWait:jQuery.isReady){return}if(!document.body){return setTimeout(jQuery.ready,1)}jQuery.isReady=true;if(wait!==true&&--jQuery.readyWait>0){return}readyList.resolveWith(document,[jQuery]);if(jQuery.fn.trigger){jQuery(document).trigger("ready").off("ready")}},isFunction:function(obj){return jQuery.type(obj)==="function"},isArray:Array.isArray||function(obj){return jQuery.type(obj)==="array"},isWindow:function(obj){return obj!=null&&obj==obj.window},isNumeric:function(obj){return!isNaN(parseFloat(obj))&&isFinite(obj)},type:function(obj){return obj==null?String(obj):class2type[core_toString.call(obj)]||"object"},isPlainObject:function(obj){if(!obj||jQuery.type(obj)!=="object"||obj.nodeType||jQuery.isWindow(obj)){return false}try{if(obj.constructor&&!core_hasOwn.call(obj,"constructor")&&!core_hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){return false}}catch(e){return false}var key;for(key in obj){}return key===undefined||core_hasOwn.call(obj,key)},isEmptyObject:function(obj){var name;for(name in obj){return false}return true},error:function(msg){throw new Error(msg)},parseHTML:function(data,context,scripts){var parsed;if(!data||typeof data!=="string"){return null}if(typeof context==="boolean"){scripts=context;context=0}context=context||document;if(parsed=rsingleTag.exec(data)){return[context.createElement(parsed[1])]}parsed=jQuery.buildFragment([data],context,scripts?null:[]);return jQuery.merge([],(parsed.cacheable?jQuery.clone(parsed.fragment):parsed.fragment).childNodes)},parseJSON:function(data){if(!data||typeof data!=="string"){return null}data=jQuery.trim(data);if(window.JSON&&window.JSON.parse){return window.JSON.parse(data)}if(rvalidchars.test(data.replace(rvalidescape,"@").replace(rvalidtokens,"]").replace(rvalidbraces,""))){return new Function("return "+data)()}jQuery.error("Invalid JSON: "+data)},parseXML:function(data){var xml,tmp;if(!data||typeof data!=="string"){return null}try{if(window.DOMParser){tmp=new DOMParser;xml=tmp.parseFromString(data,"text/xml")}else{xml=new ActiveXObject("Microsoft.XMLDOM");xml.async="false";xml.loadXML(data)}}catch(e){xml=undefined}if(!xml||!xml.documentElement||xml.getElementsByTagName("parsererror").length){jQuery.error("Invalid XML: "+data)}return xml},noop:function(){},globalEval:function(data){if(data&&core_rnotwhite.test(data)){(window.execScript||function(data){window["eval"].call(window,data)})(data)}},camelCase:function(string){return string.replace(rmsPrefix,"ms-").replace(rdashAlpha,fcamelCase)},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toLowerCase()===name.toLowerCase()},each:function(obj,callback,args){var name,i=0,length=obj.length,isObj=length===undefined||jQuery.isFunction(obj);if(args){if(isObj){for(name in obj){if(callback.apply(obj[name],args)===false){break}}}else{for(;i<length;){if(callback.apply(obj[i++],args)===false){break}}}}else{if(isObj){for(name in obj){if(callback.call(obj[name],name,obj[name])===false){break}}}else{for(;i<length;){if(callback.call(obj[i],i,obj[i++])===false){break}}}}return obj},trim:core_trim&&!core_trim.call(" ")?function(text){return text==null?"":core_trim.call(text)}:function(text){return text==null?"":(text+"").replace(rtrim,"")},makeArray:function(arr,results){var type,ret=results||[];if(arr!=null){type=jQuery.type(arr);if(arr.length==null||type==="string"||type==="function"||type==="regexp"||jQuery.isWindow(arr)){core_push.call(ret,arr)}else{jQuery.merge(ret,arr)}}return ret},inArray:function(elem,arr,i){var len;if(arr){if(core_indexOf){return core_indexOf.call(arr,elem,i)}len=arr.length;i=i?i<0?Math.max(0,len+i):i:0;for(;i<len;i++){if(i in arr&&arr[i]===elem){return i}}}return-1},merge:function(first,second){var l=second.length,i=first.length,j=0;if(typeof l==="number"){for(;j<l;j++){first[i++]=second[j]}}else{while(second[j]!==undefined){first[i++]=second[j++]}}first.length=i;return first},grep:function(elems,callback,inv){var retVal,ret=[],i=0,length=elems.length;inv=!!inv;for(;i<length;i++){retVal=!!callback(elems[i],i);if(inv!==retVal){ret.push(elems[i])}}return ret},map:function(elems,callback,arg){var value,key,ret=[],i=0,length=elems.length,isArray=elems instanceof jQuery||length!==undefined&&typeof length==="number"&&(length>0&&elems[0]&&elems[length-1]||length===0||jQuery.isArray(elems));if(isArray){for(;i<length;i++){value=callback(elems[i],i,arg);if(value!=null){ret[ret.length]=value}}}else{for(key in elems){value=callback(elems[key],key,arg);if(value!=null){ret[ret.length]=value}}}return ret.concat.apply([],ret)},guid:1,proxy:function(fn,context){var tmp,args,proxy;if(typeof context==="string"){tmp=fn[context];context=fn;fn=tmp}if(!jQuery.isFunction(fn)){return undefined}args=core_slice.call(arguments,2);proxy=function(){return fn.apply(context,args.concat(core_slice.call(arguments)))};proxy.guid=fn.guid=fn.guid||jQuery.guid++;return proxy},access:function(elems,fn,key,value,chainable,emptyGet,pass){var exec,bulk=key==null,i=0,length=elems.length;if(key&&typeof key==="object"){for(i in key){jQuery.access(elems,fn,i,key[i],1,emptyGet,value)}chainable=1}else if(value!==undefined){exec=pass===undefined&&jQuery.isFunction(value);if(bulk){if(exec){exec=fn;fn=function(elem,key,value){return exec.call(jQuery(elem),value)}}else{fn.call(elems,value);fn=null}}if(fn){for(;i<length;i++){fn(elems[i],key,exec?value.call(elems[i],i,fn(elems[i],key)):value,pass)}}chainable=1}return chainable?elems:bulk?fn.call(elems):length?fn(elems[0],key):emptyGet},now:function(){return(new Date).getTime()}});jQuery.ready.promise=function(obj){if(!readyList){readyList=jQuery.Deferred();if(document.readyState==="complete"){setTimeout(jQuery.ready,1)}else if(document.addEventListener){document.addEventListener("DOMContentLoaded",DOMContentLoaded,false);window.addEventListener("load",jQuery.ready,false)}else{document.attachEvent("onreadystatechange",DOMContentLoaded);window.attachEvent("onload",jQuery.ready);var top=false;try{top=window.frameElement==null&&document.documentElement}catch(e){}if(top&&top.doScroll){(function doScrollCheck(){if(!jQuery.isReady){try{top.doScroll("left")}catch(e){return setTimeout(doScrollCheck,50)}jQuery.ready()}})()}}}return readyList.promise(obj)};jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(i,name){class2type["[object "+name+"]"]=name.toLowerCase()});rootjQuery=jQuery(document);var optionsCache={};function createOptions(options){var object=optionsCache[options]={};jQuery.each(options.split(core_rspace),function(_,flag){object[flag]=true});return object}jQuery.Callbacks=function(options){options=typeof options==="string"?optionsCache[options]||createOptions(options):jQuery.extend({},options);var memory,fired,firing,firingStart,firingLength,firingIndex,list=[],stack=!options.once&&[],fire=function(data){memory=options.memory&&data;fired=true;firingIndex=firingStart||0;firingStart=0;firingLength=list.length;firing=true;for(;list&&firingIndex<firingLength;firingIndex++){if(list[firingIndex].apply(data[0],data[1])===false&&options.stopOnFalse){memory=false;break}}firing=false;if(list){if(stack){if(stack.length){fire(stack.shift())}}else if(memory){list=[]}else{self.disable()}}},self={add:function(){if(list){var start=list.length;(function add(args){jQuery.each(args,function(_,arg){var type=jQuery.type(arg);if(type==="function"){if(!options.unique||!self.has(arg)){list.push(arg)}}else if(arg&&arg.length&&type!=="string"){add(arg)}})})(arguments);if(firing){firingLength=list.length}else if(memory){firingStart=start;fire(memory)}}return this},remove:function(){if(list){jQuery.each(arguments,function(_,arg){var index;while((index=jQuery.inArray(arg,list,index))>-1){list.splice(index,1);if(firing){if(index<=firingLength){firingLength--}if(index<=firingIndex){firingIndex--}}}})}return this},has:function(fn){return jQuery.inArray(fn,list)>-1},empty:function(){list=[];return this},disable:function(){list=stack=memory=undefined;return this},disabled:function(){return!list},lock:function(){stack=undefined;if(!memory){self.disable()}return this},locked:function(){return!stack},fireWith:function(context,args){args=args||[];args=[context,args.slice?args.slice():args];if(list&&(!fired||stack)){if(firing){stack.push(args)}else{fire(args)}}return this},fire:function(){self.fireWith(this,arguments);return this},fired:function(){return!!fired}};return self};jQuery.extend({Deferred:function(func){var tuples=[["resolve","done",jQuery.Callbacks("once memory"),"resolved"],["reject","fail",jQuery.Callbacks("once memory"),"rejected"],["notify","progress",jQuery.Callbacks("memory")]],state="pending",promise={state:function(){return state},always:function(){deferred.done(arguments).fail(arguments);return this},then:function(){var fns=arguments;return jQuery.Deferred(function(newDefer){jQuery.each(tuples,function(i,tuple){var action=tuple[0],fn=fns[i];deferred[tuple[1]](jQuery.isFunction(fn)?function(){var returned=fn.apply(this,arguments);if(returned&&jQuery.isFunction(returned.promise)){returned.promise().done(newDefer.resolve).fail(newDefer.reject).progress(newDefer.notify)}else{newDefer[action+"With"](this===deferred?newDefer:this,[returned])}}:newDefer[action])});fns=null}).promise()},promise:function(obj){return obj!=null?jQuery.extend(obj,promise):promise}},deferred={};promise.pipe=promise.then;jQuery.each(tuples,function(i,tuple){var list=tuple[2],stateString=tuple[3];promise[tuple[1]]=list.add;if(stateString){list.add(function(){state=stateString},tuples[i^1][2].disable,tuples[2][2].lock)}deferred[tuple[0]]=list.fire;deferred[tuple[0]+"With"]=list.fireWith});promise.promise(deferred);if(func){func.call(deferred,deferred)}return deferred},when:function(subordinate){var i=0,resolveValues=core_slice.call(arguments),length=resolveValues.length,remaining=length!==1||subordinate&&jQuery.isFunction(subordinate.promise)?length:0,deferred=remaining===1?subordinate:jQuery.Deferred(),updateFunc=function(i,contexts,values){return function(value){contexts[i]=this;values[i]=arguments.length>1?core_slice.call(arguments):value;if(values===progressValues){deferred.notifyWith(contexts,values)}else if(!--remaining){deferred.resolveWith(contexts,values)}}},progressValues,progressContexts,resolveContexts;if(length>1){progressValues=new Array(length);progressContexts=new Array(length);resolveContexts=new Array(length);for(;i<length;i++){if(resolveValues[i]&&jQuery.isFunction(resolveValues[i].promise)){resolveValues[i].promise().done(updateFunc(i,resolveContexts,resolveValues)).fail(deferred.reject).progress(updateFunc(i,progressContexts,progressValues))}else{--remaining}}}if(!remaining){deferred.resolveWith(resolveContexts,resolveValues)}return deferred.promise()}});jQuery.support=function(){var support,all,a,select,opt,input,fragment,eventName,i,isSupported,clickFn,div=document.createElement("div");div.setAttribute("className","t");div.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";all=div.getElementsByTagName("*");a=div.getElementsByTagName("a")[0];if(!all||!a||!all.length){return{}}select=document.createElement("select");opt=select.appendChild(document.createElement("option"));input=div.getElementsByTagName("input")[0];a.style.cssText="top:1px;float:left;opacity:.5";support={leadingWhitespace:div.firstChild.nodeType===3,tbody:!div.getElementsByTagName("tbody").length,htmlSerialize:!!div.getElementsByTagName("link").length,style:/top/.test(a.getAttribute("style")),hrefNormalized:a.getAttribute("href")==="/a",opacity:/^0.5/.test(a.style.opacity),cssFloat:!!a.style.cssFloat,checkOn:input.value==="on",optSelected:opt.selected,getSetAttribute:div.className!=="t",enctype:!!document.createElement("form").enctype,html5Clone:document.createElement("nav").cloneNode(true).outerHTML!=="<:nav></:nav>",boxModel:document.compatMode==="CSS1Compat",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true,boxSizingReliable:true,pixelPosition:false};input.checked=true;support.noCloneChecked=input.cloneNode(true).checked;select.disabled=true;support.optDisabled=!opt.disabled;try{delete div.test}catch(e){support.deleteExpando=false}if(!div.addEventListener&&div.attachEvent&&div.fireEvent){div.attachEvent("onclick",clickFn=function(){support.noCloneEvent=false});div.cloneNode(true).fireEvent("onclick");div.detachEvent("onclick",clickFn)}input=document.createElement("input");input.value="t";input.setAttribute("type","radio");support.radioValue=input.value==="t";input.setAttribute("checked","checked");input.setAttribute("name","t");div.appendChild(input);fragment=document.createDocumentFragment();fragment.appendChild(div.lastChild);support.checkClone=fragment.cloneNode(true).cloneNode(true).lastChild.checked;support.appendChecked=input.checked;fragment.removeChild(input);fragment.appendChild(div);if(div.attachEvent){for(i in{submit:true,change:true,focusin:true}){eventName="on"+i;isSupported=eventName in div;if(!isSupported){div.setAttribute(eventName,"return;");isSupported=typeof div[eventName]==="function"}support[i+"Bubbles"]=isSupported}}jQuery(function(){var container,div,tds,marginDiv,divReset="padding:0;margin:0;border:0;display:block;overflow:hidden;",body=document.getElementsByTagName("body")[0];if(!body){return}container=document.createElement("div");container.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";body.insertBefore(container,body.firstChild);div=document.createElement("div");container.appendChild(div);div.innerHTML="<table><tr><td></td><td>t</td></tr></table>";tds=div.getElementsByTagName("td");tds[0].style.cssText="padding:0;margin:0;border:0;display:none";isSupported=tds[0].offsetHeight===0;tds[0].style.display="";tds[1].style.display="none";support.reliableHiddenOffsets=isSupported&&tds[0].offsetHeight===0;div.innerHTML="";div.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";support.boxSizing=div.offsetWidth===4;support.doesNotIncludeMarginInBodyOffset=body.offsetTop!==1;if(window.getComputedStyle){support.pixelPosition=(window.getComputedStyle(div,null)||{}).top!=="1%";support.boxSizingReliable=(window.getComputedStyle(div,null)||{width:"4px"}).width==="4px";marginDiv=document.createElement("div");marginDiv.style.cssText=div.style.cssText=divReset;marginDiv.style.marginRight=marginDiv.style.width="0";div.style.width="1px";div.appendChild(marginDiv);support.reliableMarginRight=!parseFloat((window.getComputedStyle(marginDiv,null)||{}).marginRight)}if(typeof div.style.zoom!=="undefined"){div.innerHTML="";div.style.cssText=divReset+"width:1px;padding:1px;display:inline;zoom:1";support.inlineBlockNeedsLayout=div.offsetWidth===3;div.style.display="block";div.style.overflow="visible";div.innerHTML="<div></div>";div.firstChild.style.width="5px";support.shrinkWrapBlocks=div.offsetWidth!==3;container.style.zoom=1}body.removeChild(container);container=div=tds=marginDiv=null});fragment.removeChild(div);all=a=select=opt=input=fragment=div=null;return support}();var rbrace=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,rmultiDash=/([A-Z])/g;jQuery.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(jQuery.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(elem){elem=elem.nodeType?jQuery.cache[elem[jQuery.expando]]:elem[jQuery.expando];return!!elem&&!isEmptyDataObject(elem)},data:function(elem,name,data,pvt){if(!jQuery.acceptData(elem)){return}var thisCache,ret,internalKey=jQuery.expando,getByName=typeof name==="string",isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[internalKey]:elem[internalKey]&&internalKey;if((!id||!cache[id]||!pvt&&!cache[id].data)&&getByName&&data===undefined){return}if(!id){if(isNode){elem[internalKey]=id=jQuery.deletedIds.pop()||jQuery.guid++}else{id=internalKey}}if(!cache[id]){cache[id]={};if(!isNode){cache[id].toJSON=jQuery.noop}}if(typeof name==="object"||typeof name==="function"){if(pvt){cache[id]=jQuery.extend(cache[id],name)}else{cache[id].data=jQuery.extend(cache[id].data,name)}}thisCache=cache[id];if(!pvt){if(!thisCache.data){thisCache.data={}}thisCache=thisCache.data}if(data!==undefined){thisCache[jQuery.camelCase(name)]=data}if(getByName){ret=thisCache[name];if(ret==null){ret=thisCache[jQuery.camelCase(name)]}}else{ret=thisCache}return ret},removeData:function(elem,name,pvt){if(!jQuery.acceptData(elem)){return}var thisCache,i,l,isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[jQuery.expando]:jQuery.expando;if(!cache[id]){return}if(name){thisCache=pvt?cache[id]:cache[id].data;if(thisCache){if(!jQuery.isArray(name)){if(name in thisCache){name=[name]}else{name=jQuery.camelCase(name);if(name in thisCache){name=[name]}else{name=name.split(" ")}}}for(i=0,l=name.length;i<l;i++){delete thisCache[name[i]]}if(!(pvt?isEmptyDataObject:jQuery.isEmptyObject)(thisCache)){return}}}if(!pvt){delete cache[id].data;if(!isEmptyDataObject(cache[id])){return}}if(isNode){jQuery.cleanData([elem],true)}else if(jQuery.support.deleteExpando||cache!=cache.window){delete cache[id]}else{cache[id]=null}},_data:function(elem,name,data){return jQuery.data(elem,name,data,true)},acceptData:function(elem){var noData=elem.nodeName&&jQuery.noData[elem.nodeName.toLowerCase()];return!noData||noData!==true&&elem.getAttribute("classid")===noData}});jQuery.fn.extend({data:function(key,value){var parts,part,attr,name,l,elem=this[0],i=0,data=null;if(key===undefined){if(this.length){data=jQuery.data(elem);if(elem.nodeType===1&&!jQuery._data(elem,"parsedAttrs")){attr=elem.attributes;for(l=attr.length;i<l;i++){name=attr[i].name;if(!name.indexOf("data-")){name=jQuery.camelCase(name.substring(5));dataAttr(elem,name,data[name])}}jQuery._data(elem,"parsedAttrs",true)}}return data}if(typeof key==="object"){return this.each(function(){jQuery.data(this,key)})}parts=key.split(".",2);parts[1]=parts[1]?"."+parts[1]:"";part=parts[1]+"!";return jQuery.access(this,function(value){if(value===undefined){data=this.triggerHandler("getData"+part,[parts[0]]);if(data===undefined&&elem){data=jQuery.data(elem,key);data=dataAttr(elem,key,data)}return data===undefined&&parts[1]?this.data(parts[0]):data}parts[1]=value;this.each(function(){var self=jQuery(this);self.triggerHandler("setData"+part,parts);jQuery.data(this,key,value);self.triggerHandler("changeData"+part,parts)})},null,value,arguments.length>1,null,false)},removeData:function(key){return this.each(function(){jQuery.removeData(this,key)})}});function dataAttr(elem,key,data){if(data===undefined&&elem.nodeType===1){var name="data-"+key.replace(rmultiDash,"-$1").toLowerCase();data=elem.getAttribute(name);if(typeof data==="string"){try{data=data==="true"?true:data==="false"?false:data==="null"?null:+data+""===data?+data:rbrace.test(data)?jQuery.parseJSON(data):data}catch(e){}jQuery.data(elem,key,data)}else{data=undefined}}return data}function isEmptyDataObject(obj){var name;for(name in obj){if(name==="data"&&jQuery.isEmptyObject(obj[name])){continue}if(name!=="toJSON"){return false}}return true}jQuery.extend({queue:function(elem,type,data){var queue;if(elem){type=(type||"fx")+"queue";queue=jQuery._data(elem,type);if(data){if(!queue||jQuery.isArray(data)){queue=jQuery._data(elem,type,jQuery.makeArray(data))}else{queue.push(data)}}return queue||[]}},dequeue:function(elem,type){type=type||"fx";var queue=jQuery.queue(elem,type),startLength=queue.length,fn=queue.shift(),hooks=jQuery._queueHooks(elem,type),next=function(){jQuery.dequeue(elem,type)};if(fn==="inprogress"){fn=queue.shift();startLength--}if(fn){if(type==="fx"){queue.unshift("inprogress")}delete hooks.stop;fn.call(elem,next,hooks)}if(!startLength&&hooks){hooks.empty.fire()}},_queueHooks:function(elem,type){var key=type+"queueHooks";return jQuery._data(elem,key)||jQuery._data(elem,key,{empty:jQuery.Callbacks("once memory").add(function(){jQuery.removeData(elem,type+"queue",true);jQuery.removeData(elem,key,true)})})}});jQuery.fn.extend({queue:function(type,data){var setter=2;if(typeof type!=="string"){data=type;type="fx";setter--}if(arguments.length<setter){return jQuery.queue(this[0],type)}return data===undefined?this:this.each(function(){var queue=jQuery.queue(this,type,data);jQuery._queueHooks(this,type);if(type==="fx"&&queue[0]!=="inprogress"){jQuery.dequeue(this,type)}})},dequeue:function(type){return this.each(function(){jQuery.dequeue(this,type)})},delay:function(time,type){time=jQuery.fx?jQuery.fx.speeds[time]||time:time;type=type||"fx";return this.queue(type,function(next,hooks){var timeout=setTimeout(next,time);hooks.stop=function(){clearTimeout(timeout)}})},clearQueue:function(type){return this.queue(type||"fx",[])},promise:function(type,obj){var tmp,count=1,defer=jQuery.Deferred(),elements=this,i=this.length,resolve=function(){if(!--count){defer.resolveWith(elements,[elements])}};if(typeof type!=="string"){obj=type;type=undefined}type=type||"fx";while(i--){tmp=jQuery._data(elements[i],type+"queueHooks");if(tmp&&tmp.empty){count++;tmp.empty.add(resolve)}}resolve();return defer.promise(obj)}});var nodeHook,boolHook,fixSpecified,rclass=/[\t\r\n]/g,rreturn=/\r/g,rtype=/^(?:button|input)$/i,rfocusable=/^(?:button|input|object|select|textarea)$/i,rclickable=/^a(?:rea|)$/i,rboolean=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,getSetAttribute=jQuery.support.getSetAttribute;jQuery.fn.extend({attr:function(name,value){return jQuery.access(this,jQuery.attr,name,value,arguments.length>1)},removeAttr:function(name){return this.each(function(){jQuery.removeAttr(this,name)})},prop:function(name,value){return jQuery.access(this,jQuery.prop,name,value,arguments.length>1)},removeProp:function(name){name=jQuery.propFix[name]||name;return this.each(function(){try{this[name]=undefined;delete this[name]}catch(e){}})},addClass:function(value){var classNames,i,l,elem,setClass,c,cl;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).addClass(value.call(this,j,this.className))})}if(value&&typeof value==="string"){classNames=value.split(core_rspace);for(i=0,l=this.length;i<l;i++){elem=this[i];if(elem.nodeType===1){if(!elem.className&&classNames.length===1){elem.className=value}else{setClass=" "+elem.className+" ";for(c=0,cl=classNames.length;c<cl;c++){if(setClass.indexOf(" "+classNames[c]+" ")<0){setClass+=classNames[c]+" "}}elem.className=jQuery.trim(setClass)}}}}return this},removeClass:function(value){var removes,className,elem,c,cl,i,l;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).removeClass(value.call(this,j,this.className))})}if(value&&typeof value==="string"||value===undefined){removes=(value||"").split(core_rspace);for(i=0,l=this.length;i<l;i++){elem=this[i];if(elem.nodeType===1&&elem.className){className=(" "+elem.className+" ").replace(rclass," ");for(c=0,cl=removes.length;c<cl;c++){while(className.indexOf(" "+removes[c]+" ")>=0){className=className.replace(" "+removes[c]+" "," ")}}elem.className=value?jQuery.trim(className):""}}}return this},toggleClass:function(value,stateVal){var type=typeof value,isBool=typeof stateVal==="boolean";if(jQuery.isFunction(value)){return this.each(function(i){jQuery(this).toggleClass(value.call(this,i,this.className,stateVal),stateVal)})}return this.each(function(){if(type==="string"){var className,i=0,self=jQuery(this),state=stateVal,classNames=value.split(core_rspace);while(className=classNames[i++]){state=isBool?state:!self.hasClass(className);self[state?"addClass":"removeClass"](className)}}else if(type==="undefined"||type==="boolean"){if(this.className){jQuery._data(this,"__className__",this.className)}this.className=this.className||value===false?"":jQuery._data(this,"__className__")||""}})},hasClass:function(selector){var className=" "+selector+" ",i=0,l=this.length;for(;i<l;i++){if(this[i].nodeType===1&&(" "+this[i].className+" ").replace(rclass," ").indexOf(className)>=0){return true}}return false},val:function(value){var hooks,ret,isFunction,elem=this[0];if(!arguments.length){if(elem){hooks=jQuery.valHooks[elem.type]||jQuery.valHooks[elem.nodeName.toLowerCase()];if(hooks&&"get"in hooks&&(ret=hooks.get(elem,"value"))!==undefined){return ret}ret=elem.value;return typeof ret==="string"?ret.replace(rreturn,""):ret==null?"":ret}return}isFunction=jQuery.isFunction(value);return this.each(function(i){var val,self=jQuery(this);if(this.nodeType!==1){return}if(isFunction){val=value.call(this,i,self.val())}else{val=value}if(val==null){val=""}else if(typeof val==="number"){val+=""}else if(jQuery.isArray(val)){val=jQuery.map(val,function(value){return value==null?"":value+""})}hooks=jQuery.valHooks[this.type]||jQuery.valHooks[this.nodeName.toLowerCase()];if(!hooks||!("set"in hooks)||hooks.set(this,val,"value")===undefined){this.value=val}})}});jQuery.extend({valHooks:{option:{get:function(elem){var val=elem.attributes.value;return!val||val.specified?elem.value:elem.text}},select:{get:function(elem){var value,option,options=elem.options,index=elem.selectedIndex,one=elem.type==="select-one"||index<0,values=one?null:[],max=one?index+1:options.length,i=index<0?max:one?index:0;for(;i<max;i++){option=options[i];if((option.selected||i===index)&&(jQuery.support.optDisabled?!option.disabled:option.getAttribute("disabled")===null)&&(!option.parentNode.disabled||!jQuery.nodeName(option.parentNode,"optgroup"))){value=jQuery(option).val();if(one){return value}values.push(value)}}return values},set:function(elem,value){var values=jQuery.makeArray(value);jQuery(elem).find("option").each(function(){this.selected=jQuery.inArray(jQuery(this).val(),values)>=0});if(!values.length){elem.selectedIndex=-1}return values}}},attrFn:{},attr:function(elem,name,value,pass){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return}if(pass&&jQuery.isFunction(jQuery.fn[name])){return jQuery(elem)[name](value)}if(typeof elem.getAttribute==="undefined"){return jQuery.prop(elem,name,value)}notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=name.toLowerCase();hooks=jQuery.attrHooks[name]||(rboolean.test(name)?boolHook:nodeHook)}if(value!==undefined){if(value===null){jQuery.removeAttr(elem,name);return}else if(hooks&&"set"in hooks&¬xml&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{elem.setAttribute(name,value+"");return value}}else if(hooks&&"get"in hooks&¬xml&&(ret=hooks.get(elem,name))!==null){return ret}else{ret=elem.getAttribute(name);return ret===null?undefined:ret}},removeAttr:function(elem,value){var propName,attrNames,name,isBool,i=0;if(value&&elem.nodeType===1){attrNames=value.split(core_rspace);for(;i<attrNames.length;i++){name=attrNames[i];if(name){propName=jQuery.propFix[name]||name;isBool=rboolean.test(name);if(!isBool){jQuery.attr(elem,name,"")}elem.removeAttribute(getSetAttribute?name:propName);if(isBool&&propName in elem){elem[propName]=false}}}}},attrHooks:{type:{set:function(elem,value){if(rtype.test(elem.nodeName)&&elem.parentNode){jQuery.error("type property can't be changed") +}else if(!jQuery.support.radioValue&&value==="radio"&&jQuery.nodeName(elem,"input")){var val=elem.value;elem.setAttribute("type",value);if(val){elem.value=val}return value}}},value:{get:function(elem,name){if(nodeHook&&jQuery.nodeName(elem,"button")){return nodeHook.get(elem,name)}return name in elem?elem.value:null},set:function(elem,value,name){if(nodeHook&&jQuery.nodeName(elem,"button")){return nodeHook.set(elem,value,name)}elem.value=value}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(elem,name,value){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return}notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=jQuery.propFix[name]||name;hooks=jQuery.propHooks[name]}if(value!==undefined){if(hooks&&"set"in hooks&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{return elem[name]=value}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,name))!==null){return ret}else{return elem[name]}}},propHooks:{tabIndex:{get:function(elem){var attributeNode=elem.getAttributeNode("tabindex");return attributeNode&&attributeNode.specified?parseInt(attributeNode.value,10):rfocusable.test(elem.nodeName)||rclickable.test(elem.nodeName)&&elem.href?0:undefined}}}});boolHook={get:function(elem,name){var attrNode,property=jQuery.prop(elem,name);return property===true||typeof property!=="boolean"&&(attrNode=elem.getAttributeNode(name))&&attrNode.nodeValue!==false?name.toLowerCase():undefined},set:function(elem,value,name){var propName;if(value===false){jQuery.removeAttr(elem,name)}else{propName=jQuery.propFix[name]||name;if(propName in elem){elem[propName]=true}elem.setAttribute(name,name.toLowerCase())}return name}};if(!getSetAttribute){fixSpecified={name:true,id:true,coords:true};nodeHook=jQuery.valHooks.button={get:function(elem,name){var ret;ret=elem.getAttributeNode(name);return ret&&(fixSpecified[name]?ret.value!=="":ret.specified)?ret.value:undefined},set:function(elem,value,name){var ret=elem.getAttributeNode(name);if(!ret){ret=document.createAttribute(name);elem.setAttributeNode(ret)}return ret.value=value+""}};jQuery.each(["width","height"],function(i,name){jQuery.attrHooks[name]=jQuery.extend(jQuery.attrHooks[name],{set:function(elem,value){if(value===""){elem.setAttribute(name,"auto");return value}}})});jQuery.attrHooks.contenteditable={get:nodeHook.get,set:function(elem,value,name){if(value===""){value="false"}nodeHook.set(elem,value,name)}}}if(!jQuery.support.hrefNormalized){jQuery.each(["href","src","width","height"],function(i,name){jQuery.attrHooks[name]=jQuery.extend(jQuery.attrHooks[name],{get:function(elem){var ret=elem.getAttribute(name,2);return ret===null?undefined:ret}})})}if(!jQuery.support.style){jQuery.attrHooks.style={get:function(elem){return elem.style.cssText.toLowerCase()||undefined},set:function(elem,value){return elem.style.cssText=value+""}}}if(!jQuery.support.optSelected){jQuery.propHooks.selected=jQuery.extend(jQuery.propHooks.selected,{get:function(elem){var parent=elem.parentNode;if(parent){parent.selectedIndex;if(parent.parentNode){parent.parentNode.selectedIndex}}return null}})}if(!jQuery.support.enctype){jQuery.propFix.enctype="encoding"}if(!jQuery.support.checkOn){jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]={get:function(elem){return elem.getAttribute("value")===null?"on":elem.value}}})}jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]=jQuery.extend(jQuery.valHooks[this],{set:function(elem,value){if(jQuery.isArray(value)){return elem.checked=jQuery.inArray(jQuery(elem).val(),value)>=0}}})});var rformElems=/^(?:textarea|input|select)$/i,rtypenamespace=/^([^\.]*|)(?:\.(.+)|)$/,rhoverHack=/(?:^|\s)hover(\.\S+|)\b/,rkeyEvent=/^key/,rmouseEvent=/^(?:mouse|contextmenu)|click/,rfocusMorph=/^(?:focusinfocus|focusoutblur)$/,hoverHack=function(events){return jQuery.event.special.hover?events:events.replace(rhoverHack,"mouseenter$1 mouseleave$1")};jQuery.event={add:function(elem,types,handler,data,selector){var elemData,eventHandle,events,t,tns,type,namespaces,handleObj,handleObjIn,handlers,special;if(elem.nodeType===3||elem.nodeType===8||!types||!handler||!(elemData=jQuery._data(elem))){return}if(handler.handler){handleObjIn=handler;handler=handleObjIn.handler;selector=handleObjIn.selector}if(!handler.guid){handler.guid=jQuery.guid++}events=elemData.events;if(!events){elemData.events=events={}}eventHandle=elemData.handle;if(!eventHandle){elemData.handle=eventHandle=function(e){return typeof jQuery!=="undefined"&&(!e||jQuery.event.triggered!==e.type)?jQuery.event.dispatch.apply(eventHandle.elem,arguments):undefined};eventHandle.elem=elem}types=jQuery.trim(hoverHack(types)).split(" ");for(t=0;t<types.length;t++){tns=rtypenamespace.exec(types[t])||[];type=tns[1];namespaces=(tns[2]||"").split(".").sort();special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;special=jQuery.event.special[type]||{};handleObj=jQuery.extend({type:type,origType:tns[1],data:data,handler:handler,guid:handler.guid,selector:selector,needsContext:selector&&jQuery.expr.match.needsContext.test(selector),namespace:namespaces.join(".")},handleObjIn);handlers=events[type];if(!handlers){handlers=events[type]=[];handlers.delegateCount=0;if(!special.setup||special.setup.call(elem,data,namespaces,eventHandle)===false){if(elem.addEventListener){elem.addEventListener(type,eventHandle,false)}else if(elem.attachEvent){elem.attachEvent("on"+type,eventHandle)}}}if(special.add){special.add.call(elem,handleObj);if(!handleObj.handler.guid){handleObj.handler.guid=handler.guid}}if(selector){handlers.splice(handlers.delegateCount++,0,handleObj)}else{handlers.push(handleObj)}jQuery.event.global[type]=true}elem=null},global:{},remove:function(elem,types,handler,selector,mappedTypes){var t,tns,type,origType,namespaces,origCount,j,events,special,eventType,handleObj,elemData=jQuery.hasData(elem)&&jQuery._data(elem);if(!elemData||!(events=elemData.events)){return}types=jQuery.trim(hoverHack(types||"")).split(" ");for(t=0;t<types.length;t++){tns=rtypenamespace.exec(types[t])||[];type=origType=tns[1];namespaces=tns[2];if(!type){for(type in events){jQuery.event.remove(elem,type+types[t],handler,selector,true)}continue}special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;eventType=events[type]||[];origCount=eventType.length;namespaces=namespaces?new RegExp("(^|\\.)"+namespaces.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(j=0;j<eventType.length;j++){handleObj=eventType[j];if((mappedTypes||origType===handleObj.origType)&&(!handler||handler.guid===handleObj.guid)&&(!namespaces||namespaces.test(handleObj.namespace))&&(!selector||selector===handleObj.selector||selector==="**"&&handleObj.selector)){eventType.splice(j--,1);if(handleObj.selector){eventType.delegateCount--}if(special.remove){special.remove.call(elem,handleObj)}}}if(eventType.length===0&&origCount!==eventType.length){if(!special.teardown||special.teardown.call(elem,namespaces,elemData.handle)===false){jQuery.removeEvent(elem,type,elemData.handle)}delete events[type]}}if(jQuery.isEmptyObject(events)){delete elemData.handle;jQuery.removeData(elem,"events",true)}},customEvent:{getData:true,setData:true,changeData:true},trigger:function(event,data,elem,onlyHandlers){if(elem&&(elem.nodeType===3||elem.nodeType===8)){return}var cache,exclusive,i,cur,old,ontype,special,handle,eventPath,bubbleType,type=event.type||event,namespaces=[];if(rfocusMorph.test(type+jQuery.event.triggered)){return}if(type.indexOf("!")>=0){type=type.slice(0,-1);exclusive=true}if(type.indexOf(".")>=0){namespaces=type.split(".");type=namespaces.shift();namespaces.sort()}if((!elem||jQuery.event.customEvent[type])&&!jQuery.event.global[type]){return}event=typeof event==="object"?event[jQuery.expando]?event:new jQuery.Event(type,event):new jQuery.Event(type);event.type=type;event.isTrigger=true;event.exclusive=exclusive;event.namespace=namespaces.join(".");event.namespace_re=event.namespace?new RegExp("(^|\\.)"+namespaces.join("\\.(?:.*\\.|)")+"(\\.|$)"):null;ontype=type.indexOf(":")<0?"on"+type:"";if(!elem){cache=jQuery.cache;for(i in cache){if(cache[i].events&&cache[i].events[type]){jQuery.event.trigger(event,data,cache[i].handle.elem,true)}}return}event.result=undefined;if(!event.target){event.target=elem}data=data!=null?jQuery.makeArray(data):[];data.unshift(event);special=jQuery.event.special[type]||{};if(special.trigger&&special.trigger.apply(elem,data)===false){return}eventPath=[[elem,special.bindType||type]];if(!onlyHandlers&&!special.noBubble&&!jQuery.isWindow(elem)){bubbleType=special.delegateType||type;cur=rfocusMorph.test(bubbleType+type)?elem:elem.parentNode;for(old=elem;cur;cur=cur.parentNode){eventPath.push([cur,bubbleType]);old=cur}if(old===(elem.ownerDocument||document)){eventPath.push([old.defaultView||old.parentWindow||window,bubbleType])}}for(i=0;i<eventPath.length&&!event.isPropagationStopped();i++){cur=eventPath[i][0];event.type=eventPath[i][1];handle=(jQuery._data(cur,"events")||{})[event.type]&&jQuery._data(cur,"handle");if(handle){handle.apply(cur,data)}handle=ontype&&cur[ontype];if(handle&&jQuery.acceptData(cur)&&handle.apply&&handle.apply(cur,data)===false){event.preventDefault()}}event.type=type;if(!onlyHandlers&&!event.isDefaultPrevented()){if((!special._default||special._default.apply(elem.ownerDocument,data)===false)&&!(type==="click"&&jQuery.nodeName(elem,"a"))&&jQuery.acceptData(elem)){if(ontype&&elem[type]&&(type!=="focus"&&type!=="blur"||event.target.offsetWidth!==0)&&!jQuery.isWindow(elem)){old=elem[ontype];if(old){elem[ontype]=null}jQuery.event.triggered=type;elem[type]();jQuery.event.triggered=undefined;if(old){elem[ontype]=old}}}}return event.result},dispatch:function(event){event=jQuery.event.fix(event||window.event);var i,j,cur,ret,selMatch,matched,matches,handleObj,sel,related,handlers=(jQuery._data(this,"events")||{})[event.type]||[],delegateCount=handlers.delegateCount,args=core_slice.call(arguments),run_all=!event.exclusive&&!event.namespace,special=jQuery.event.special[event.type]||{},handlerQueue=[];args[0]=event;event.delegateTarget=this;if(special.preDispatch&&special.preDispatch.call(this,event)===false){return}if(delegateCount&&!(event.button&&event.type==="click")){for(cur=event.target;cur!=this;cur=cur.parentNode||this){if(cur.disabled!==true||event.type!=="click"){selMatch={};matches=[];for(i=0;i<delegateCount;i++){handleObj=handlers[i];sel=handleObj.selector;if(selMatch[sel]===undefined){selMatch[sel]=handleObj.needsContext?jQuery(sel,this).index(cur)>=0:jQuery.find(sel,this,null,[cur]).length}if(selMatch[sel]){matches.push(handleObj)}}if(matches.length){handlerQueue.push({elem:cur,matches:matches})}}}}if(handlers.length>delegateCount){handlerQueue.push({elem:this,matches:handlers.slice(delegateCount)})}for(i=0;i<handlerQueue.length&&!event.isPropagationStopped();i++){matched=handlerQueue[i];event.currentTarget=matched.elem;for(j=0;j<matched.matches.length&&!event.isImmediatePropagationStopped();j++){handleObj=matched.matches[j];if(run_all||!event.namespace&&!handleObj.namespace||event.namespace_re&&event.namespace_re.test(handleObj.namespace)){event.data=handleObj.data;event.handleObj=handleObj;ret=((jQuery.event.special[handleObj.origType]||{}).handle||handleObj.handler).apply(matched.elem,args);if(ret!==undefined){event.result=ret;if(ret===false){event.preventDefault();event.stopPropagation()}}}}}if(special.postDispatch){special.postDispatch.call(this,event)}return event.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(event,original){if(event.which==null){event.which=original.charCode!=null?original.charCode:original.keyCode}return event}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(event,original){var eventDoc,doc,body,button=original.button,fromElement=original.fromElement;if(event.pageX==null&&original.clientX!=null){eventDoc=event.target.ownerDocument||document;doc=eventDoc.documentElement;body=eventDoc.body;event.pageX=original.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc&&doc.clientLeft||body&&body.clientLeft||0);event.pageY=original.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc&&doc.clientTop||body&&body.clientTop||0)}if(!event.relatedTarget&&fromElement){event.relatedTarget=fromElement===event.target?original.toElement:fromElement}if(!event.which&&button!==undefined){event.which=button&1?1:button&2?3:button&4?2:0}return event}},fix:function(event){if(event[jQuery.expando]){return event}var i,prop,originalEvent=event,fixHook=jQuery.event.fixHooks[event.type]||{},copy=fixHook.props?this.props.concat(fixHook.props):this.props;event=jQuery.Event(originalEvent);for(i=copy.length;i;){prop=copy[--i];event[prop]=originalEvent[prop]}if(!event.target){event.target=originalEvent.srcElement||document}if(event.target.nodeType===3){event.target=event.target.parentNode}event.metaKey=!!event.metaKey;return fixHook.filter?fixHook.filter(event,originalEvent):event},special:{load:{noBubble:true},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(data,namespaces,eventHandle){if(jQuery.isWindow(this)){this.onbeforeunload=eventHandle}},teardown:function(namespaces,eventHandle){if(this.onbeforeunload===eventHandle){this.onbeforeunload=null}}}},simulate:function(type,elem,event,bubble){var e=jQuery.extend(new jQuery.Event,event,{type:type,isSimulated:true,originalEvent:{}});if(bubble){jQuery.event.trigger(e,null,elem)}else{jQuery.event.dispatch.call(elem,e)}if(e.isDefaultPrevented()){event.preventDefault()}}};jQuery.event.handle=jQuery.event.dispatch;jQuery.removeEvent=document.removeEventListener?function(elem,type,handle){if(elem.removeEventListener){elem.removeEventListener(type,handle,false)}}:function(elem,type,handle){var name="on"+type;if(elem.detachEvent){if(typeof elem[name]==="undefined"){elem[name]=null}elem.detachEvent(name,handle)}};jQuery.Event=function(src,props){if(!(this instanceof jQuery.Event)){return new jQuery.Event(src,props)}if(src&&src.type){this.originalEvent=src;this.type=src.type;this.isDefaultPrevented=src.defaultPrevented||src.returnValue===false||src.getPreventDefault&&src.getPreventDefault()?returnTrue:returnFalse}else{this.type=src}if(props){jQuery.extend(this,props)}this.timeStamp=src&&src.timeStamp||jQuery.now();this[jQuery.expando]=true};function returnFalse(){return false}function returnTrue(){return true}jQuery.Event.prototype={preventDefault:function(){this.isDefaultPrevented=returnTrue;var e=this.originalEvent;if(!e){return}if(e.preventDefault){e.preventDefault()}else{e.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=returnTrue;var e=this.originalEvent;if(!e){return}if(e.stopPropagation){e.stopPropagation()}e.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=returnTrue;this.stopPropagation()},isDefaultPrevented:returnFalse,isPropagationStopped:returnFalse,isImmediatePropagationStopped:returnFalse};jQuery.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(orig,fix){jQuery.event.special[orig]={delegateType:fix,bindType:fix,handle:function(event){var ret,target=this,related=event.relatedTarget,handleObj=event.handleObj,selector=handleObj.selector;if(!related||related!==target&&!jQuery.contains(target,related)){event.type=handleObj.origType;ret=handleObj.handler.apply(this,arguments);event.type=fix}return ret}}});if(!jQuery.support.submitBubbles){jQuery.event.special.submit={setup:function(){if(jQuery.nodeName(this,"form")){return false}jQuery.event.add(this,"click._submit keypress._submit",function(e){var elem=e.target,form=jQuery.nodeName(elem,"input")||jQuery.nodeName(elem,"button")?elem.form:undefined;if(form&&!jQuery._data(form,"_submit_attached")){jQuery.event.add(form,"submit._submit",function(event){event._submit_bubble=true});jQuery._data(form,"_submit_attached",true)}})},postDispatch:function(event){if(event._submit_bubble){delete event._submit_bubble;if(this.parentNode&&!event.isTrigger){jQuery.event.simulate("submit",this.parentNode,event,true)}}},teardown:function(){if(jQuery.nodeName(this,"form")){return false}jQuery.event.remove(this,"._submit")}}}if(!jQuery.support.changeBubbles){jQuery.event.special.change={setup:function(){if(rformElems.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio"){jQuery.event.add(this,"propertychange._change",function(event){if(event.originalEvent.propertyName==="checked"){this._just_changed=true}});jQuery.event.add(this,"click._change",function(event){if(this._just_changed&&!event.isTrigger){this._just_changed=false}jQuery.event.simulate("change",this,event,true)})}return false}jQuery.event.add(this,"beforeactivate._change",function(e){var elem=e.target;if(rformElems.test(elem.nodeName)&&!jQuery._data(elem,"_change_attached")){jQuery.event.add(elem,"change._change",function(event){if(this.parentNode&&!event.isSimulated&&!event.isTrigger){jQuery.event.simulate("change",this.parentNode,event,true)}});jQuery._data(elem,"_change_attached",true)}})},handle:function(event){var elem=event.target;if(this!==elem||event.isSimulated||event.isTrigger||elem.type!=="radio"&&elem.type!=="checkbox"){return event.handleObj.handler.apply(this,arguments)}},teardown:function(){jQuery.event.remove(this,"._change");return!rformElems.test(this.nodeName)}}}if(!jQuery.support.focusinBubbles){jQuery.each({focus:"focusin",blur:"focusout"},function(orig,fix){var attaches=0,handler=function(event){jQuery.event.simulate(fix,event.target,jQuery.event.fix(event),true)};jQuery.event.special[fix]={setup:function(){if(attaches++===0){document.addEventListener(orig,handler,true)}},teardown:function(){if(--attaches===0){document.removeEventListener(orig,handler,true)}}}})}jQuery.fn.extend({on:function(types,selector,data,fn,one){var origFn,type;if(typeof types==="object"){if(typeof selector!=="string"){data=data||selector;selector=undefined}for(type in types){this.on(type,selector,data,types[type],one)}return this}if(data==null&&fn==null){fn=selector;data=selector=undefined}else if(fn==null){if(typeof selector==="string"){fn=data;data=undefined}else{fn=data;data=selector;selector=undefined}}if(fn===false){fn=returnFalse}else if(!fn){return this}if(one===1){origFn=fn;fn=function(event){jQuery().off(event);return origFn.apply(this,arguments)};fn.guid=origFn.guid||(origFn.guid=jQuery.guid++)}return this.each(function(){jQuery.event.add(this,types,fn,data,selector)})},one:function(types,selector,data,fn){return this.on(types,selector,data,fn,1)},off:function(types,selector,fn){var handleObj,type;if(types&&types.preventDefault&&types.handleObj){handleObj=types.handleObj;jQuery(types.delegateTarget).off(handleObj.namespace?handleObj.origType+"."+handleObj.namespace:handleObj.origType,handleObj.selector,handleObj.handler);return this}if(typeof types==="object"){for(type in types){this.off(type,selector,types[type])}return this}if(selector===false||typeof selector==="function"){fn=selector;selector=undefined}if(fn===false){fn=returnFalse}return this.each(function(){jQuery.event.remove(this,types,fn,selector)})},bind:function(types,data,fn){return this.on(types,null,data,fn)},unbind:function(types,fn){return this.off(types,null,fn)},live:function(types,data,fn){jQuery(this.context).on(types,this.selector,data,fn);return this},die:function(types,fn){jQuery(this.context).off(types,this.selector||"**",fn);return this},delegate:function(selector,types,data,fn){return this.on(types,selector,data,fn)},undelegate:function(selector,types,fn){return arguments.length===1?this.off(selector,"**"):this.off(types,selector||"**",fn)},trigger:function(type,data){return this.each(function(){jQuery.event.trigger(type,data,this)})},triggerHandler:function(type,data){if(this[0]){return jQuery.event.trigger(type,data,this[0],true)}},toggle:function(fn){var args=arguments,guid=fn.guid||jQuery.guid++,i=0,toggler=function(event){var lastToggle=(jQuery._data(this,"lastToggle"+fn.guid)||0)%i;jQuery._data(this,"lastToggle"+fn.guid,lastToggle+1);event.preventDefault();return args[lastToggle].apply(this,arguments)||false};toggler.guid=guid;while(i<args.length){args[i++].guid=guid}return this.click(toggler)},hover:function(fnOver,fnOut){return this.mouseenter(fnOver).mouseleave(fnOut||fnOver)}});jQuery.each(("blur focus focusin focusout load resize scroll unload click dblclick "+"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave "+"change select submit keydown keypress keyup error contextmenu").split(" "),function(i,name){jQuery.fn[name]=function(data,fn){if(fn==null){fn=data;data=null}return arguments.length>0?this.on(name,null,data,fn):this.trigger(name)};if(rkeyEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.keyHooks}if(rmouseEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.mouseHooks}});(function(window,undefined){var cachedruns,assertGetIdNotName,Expr,getText,isXML,contains,compile,sortOrder,hasDuplicate,outermostContext,baseHasDuplicate=true,strundefined="undefined",expando=("sizcache"+Math.random()).replace(".",""),Token=String,document=window.document,docElem=document.documentElement,dirruns=0,done=0,pop=[].pop,push=[].push,slice=[].slice,indexOf=[].indexOf||function(elem){var i=0,len=this.length;for(;i<len;i++){if(this[i]===elem){return i}}return-1},markFunction=function(fn,value){fn[expando]=value==null||value;return fn},createCache=function(){var cache={},keys=[];return markFunction(function(key,value){if(keys.push(key)>Expr.cacheLength){delete cache[keys.shift()]}return cache[key+" "]=value},cache)},classCache=createCache(),tokenCache=createCache(),compilerCache=createCache(),whitespace="[\\x20\\t\\r\\n\\f]",characterEncoding="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",identifier=characterEncoding.replace("w","w#"),operators="([*^$|!~]?=)",attributes="\\["+whitespace+"*("+characterEncoding+")"+whitespace+"*(?:"+operators+whitespace+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+identifier+")|)|)"+whitespace+"*\\]",pseudos=":("+characterEncoding+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+attributes+")|[^:]|\\\\.)*|.*))\\)|)",pos=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+whitespace+"*((?:-\\d)?\\d*)"+whitespace+"*\\)|)(?=[^-]|$)",rtrim=new RegExp("^"+whitespace+"+|((?:^|[^\\\\])(?:\\\\.)*)"+whitespace+"+$","g"),rcomma=new RegExp("^"+whitespace+"*,"+whitespace+"*"),rcombinators=new RegExp("^"+whitespace+"*([\\x20\\t\\r\\n\\f>+~])"+whitespace+"*"),rpseudo=new RegExp(pseudos),rquickExpr=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,rnot=/^:not/,rsibling=/[\x20\t\r\n\f]*[+~]/,rendsWithNot=/:not\($/,rheader=/h\d/i,rinputs=/input|select|textarea|button/i,rbackslash=/\\(?!\\)/g,matchExpr={ID:new RegExp("^#("+characterEncoding+")"),CLASS:new RegExp("^\\.("+characterEncoding+")"),NAME:new RegExp("^\\[name=['\"]?("+characterEncoding+")['\"]?\\]"),TAG:new RegExp("^("+characterEncoding.replace("w","w*")+")"),ATTR:new RegExp("^"+attributes),PSEUDO:new RegExp("^"+pseudos),POS:new RegExp(pos,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+whitespace+"*(even|odd|(([+-]|)(\\d*)n|)"+whitespace+"*(?:([+-]|)"+whitespace+"*(\\d+)|))"+whitespace+"*\\)|)","i"),needsContext:new RegExp("^"+whitespace+"*[>+~]|"+pos,"i")},assert=function(fn){var div=document.createElement("div");try{return fn(div)}catch(e){return false}finally{div=null}},assertTagNameNoComments=assert(function(div){div.appendChild(document.createComment(""));return!div.getElementsByTagName("*").length}),assertHrefNotNormalized=assert(function(div){div.innerHTML="<a href='#'></a>";return div.firstChild&&typeof div.firstChild.getAttribute!==strundefined&&div.firstChild.getAttribute("href")==="#"}),assertAttributes=assert(function(div){div.innerHTML="<select></select>";var type=typeof div.lastChild.getAttribute("multiple");return type!=="boolean"&&type!=="string"}),assertUsableClassName=assert(function(div){div.innerHTML="<div class='hidden e'></div><div class='hidden'></div>";if(!div.getElementsByClassName||!div.getElementsByClassName("e").length){return false}div.lastChild.className="e";return div.getElementsByClassName("e").length===2}),assertUsableName=assert(function(div){div.id=expando+0;div.innerHTML="<a name='"+expando+"'></a><div name='"+expando+"'></div>";docElem.insertBefore(div,docElem.firstChild);var pass=document.getElementsByName&&document.getElementsByName(expando).length===2+document.getElementsByName(expando+0).length;assertGetIdNotName=!document.getElementById(expando);docElem.removeChild(div);return pass});try{slice.call(docElem.childNodes,0)[0].nodeType}catch(e){slice=function(i){var elem,results=[];for(;elem=this[i];i++){results.push(elem)}return results}}function Sizzle(selector,context,results,seed){results=results||[];context=context||document;var match,elem,xml,m,nodeType=context.nodeType;if(!selector||typeof selector!=="string"){return results}if(nodeType!==1&&nodeType!==9){return[]}xml=isXML(context);if(!xml&&!seed){if(match=rquickExpr.exec(selector)){if(m=match[1]){if(nodeType===9){elem=context.getElementById(m);if(elem&&elem.parentNode){if(elem.id===m){results.push(elem);return results}}else{return results}}else{if(context.ownerDocument&&(elem=context.ownerDocument.getElementById(m))&&contains(context,elem)&&elem.id===m){results.push(elem);return results}}}else if(match[2]){push.apply(results,slice.call(context.getElementsByTagName(selector),0));return results}else if((m=match[3])&&assertUsableClassName&&context.getElementsByClassName){push.apply(results,slice.call(context.getElementsByClassName(m),0));return results}}}return select(selector.replace(rtrim,"$1"),context,results,seed,xml)}Sizzle.matches=function(expr,elements){return Sizzle(expr,null,null,elements)};Sizzle.matchesSelector=function(elem,expr){return Sizzle(expr,null,null,[elem]).length>0};function createInputPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type===type}}function createButtonPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return(name==="input"||name==="button")&&elem.type===type}}function createPositionalPseudo(fn){return markFunction(function(argument){argument=+argument;return markFunction(function(seed,matches){var j,matchIndexes=fn([],seed.length,argument),i=matchIndexes.length;while(i--){if(seed[j=matchIndexes[i]]){seed[j]=!(matches[j]=seed[j])}}})})}getText=Sizzle.getText=function(elem){var node,ret="",i=0,nodeType=elem.nodeType;if(nodeType){if(nodeType===1||nodeType===9||nodeType===11){if(typeof elem.textContent==="string"){return elem.textContent}else{for(elem=elem.firstChild;elem;elem=elem.nextSibling){ret+=getText(elem)}}}else if(nodeType===3||nodeType===4){return elem.nodeValue}}else{for(;node=elem[i];i++){ret+=getText(node)}}return ret};isXML=Sizzle.isXML=function(elem){var documentElement=elem&&(elem.ownerDocument||elem).documentElement;return documentElement?documentElement.nodeName!=="HTML":false};contains=Sizzle.contains=docElem.contains?function(a,b){var adown=a.nodeType===9?a.documentElement:a,bup=b&&b.parentNode;return a===bup||!!(bup&&bup.nodeType===1&&adown.contains&&adown.contains(bup))}:docElem.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode){if(b===a){return true}}return false};Sizzle.attr=function(elem,name){var val,xml=isXML(elem);if(!xml){name=name.toLowerCase()}if(val=Expr.attrHandle[name]){return val(elem)}if(xml||assertAttributes){return elem.getAttribute(name)}val=elem.getAttributeNode(name);return val?typeof elem[name]==="boolean"?elem[name]?name:null:val.specified?val.value:null:null};Expr=Sizzle.selectors={cacheLength:50,createPseudo:markFunction,match:matchExpr,attrHandle:assertHrefNotNormalized?{}:{href:function(elem){return elem.getAttribute("href",2)},type:function(elem){return elem.getAttribute("type")}},find:{ID:assertGetIdNotName?function(id,context,xml){if(typeof context.getElementById!==strundefined&&!xml){var m=context.getElementById(id);return m&&m.parentNode?[m]:[]}}:function(id,context,xml){if(typeof context.getElementById!==strundefined&&!xml){var m=context.getElementById(id);return m?m.id===id||typeof m.getAttributeNode!==strundefined&&m.getAttributeNode("id").value===id?[m]:undefined:[]}},TAG:assertTagNameNoComments?function(tag,context){if(typeof context.getElementsByTagName!==strundefined){return context.getElementsByTagName(tag)}}:function(tag,context){var results=context.getElementsByTagName(tag);if(tag==="*"){var elem,tmp=[],i=0;for(;elem=results[i];i++){if(elem.nodeType===1){tmp.push(elem)}}return tmp}return results},NAME:assertUsableName&&function(tag,context){if(typeof context.getElementsByName!==strundefined){return context.getElementsByName(name)}},CLASS:assertUsableClassName&&function(className,context,xml){if(typeof context.getElementsByClassName!==strundefined&&!xml){return context.getElementsByClassName(className)}}},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(match){match[1]=match[1].replace(rbackslash,"");match[3]=(match[4]||match[5]||"").replace(rbackslash,"");if(match[2]==="~="){match[3]=" "+match[3]+" "}return match.slice(0,4)},CHILD:function(match){match[1]=match[1].toLowerCase();if(match[1]==="nth"){if(!match[2]){Sizzle.error(match[0])}match[3]=+(match[3]?match[4]+(match[5]||1):2*(match[2]==="even"||match[2]==="odd"));match[4]=+(match[6]+match[7]||match[2]==="odd")}else if(match[2]){Sizzle.error(match[0])}return match},PSEUDO:function(match){var unquoted,excess;if(matchExpr["CHILD"].test(match[0])){return null}if(match[3]){match[2]=match[3]}else if(unquoted=match[4]){if(rpseudo.test(unquoted)&&(excess=tokenize(unquoted,true))&&(excess=unquoted.indexOf(")",unquoted.length-excess)-unquoted.length)){unquoted=unquoted.slice(0,excess);match[0]=match[0].slice(0,excess)}match[2]=unquoted}return match.slice(0,3)}},filter:{ID:assertGetIdNotName?function(id){id=id.replace(rbackslash,"");return function(elem){return elem.getAttribute("id")===id}}:function(id){id=id.replace(rbackslash,"");return function(elem){var node=typeof elem.getAttributeNode!==strundefined&&elem.getAttributeNode("id");return node&&node.value===id}},TAG:function(nodeName){if(nodeName==="*"){return function(){return true}}nodeName=nodeName.replace(rbackslash,"").toLowerCase();return function(elem){return elem.nodeName&&elem.nodeName.toLowerCase()===nodeName}},CLASS:function(className){var pattern=classCache[expando][className+" "];return pattern||(pattern=new RegExp("(^|"+whitespace+")"+className+"("+whitespace+"|$)"))&&classCache(className,function(elem){return pattern.test(elem.className||typeof elem.getAttribute!==strundefined&&elem.getAttribute("class")||"")})},ATTR:function(name,operator,check){return function(elem,context){var result=Sizzle.attr(elem,name);if(result==null){return operator==="!="}if(!operator){return true}result+="";return operator==="="?result===check:operator==="!="?result!==check:operator==="^="?check&&result.indexOf(check)===0:operator==="*="?check&&result.indexOf(check)>-1:operator==="$="?check&&result.substr(result.length-check.length)===check:operator==="~="?(" "+result+" ").indexOf(check)>-1:operator==="|="?result===check||result.substr(0,check.length+1)===check+"-":false}},CHILD:function(type,argument,first,last){if(type==="nth"){return function(elem){var node,diff,parent=elem.parentNode;if(first===1&&last===0){return true}if(parent){diff=0;for(node=parent.firstChild;node;node=node.nextSibling){if(node.nodeType===1){diff++; +if(elem===node){break}}}}diff-=last;return diff===first||diff%first===0&&diff/first>=0}}return function(elem){var node=elem;switch(type){case"only":case"first":while(node=node.previousSibling){if(node.nodeType===1){return false}}if(type==="first"){return true}node=elem;case"last":while(node=node.nextSibling){if(node.nodeType===1){return false}}return true}}},PSEUDO:function(pseudo,argument){var args,fn=Expr.pseudos[pseudo]||Expr.setFilters[pseudo.toLowerCase()]||Sizzle.error("unsupported pseudo: "+pseudo);if(fn[expando]){return fn(argument)}if(fn.length>1){args=[pseudo,pseudo,"",argument];return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase())?markFunction(function(seed,matches){var idx,matched=fn(seed,argument),i=matched.length;while(i--){idx=indexOf.call(seed,matched[i]);seed[idx]=!(matches[idx]=matched[i])}}):function(elem){return fn(elem,0,args)}}return fn}},pseudos:{not:markFunction(function(selector){var input=[],results=[],matcher=compile(selector.replace(rtrim,"$1"));return matcher[expando]?markFunction(function(seed,matches,context,xml){var elem,unmatched=matcher(seed,null,xml,[]),i=seed.length;while(i--){if(elem=unmatched[i]){seed[i]=!(matches[i]=elem)}}}):function(elem,context,xml){input[0]=elem;matcher(input,null,xml,results);return!results.pop()}}),has:markFunction(function(selector){return function(elem){return Sizzle(selector,elem).length>0}}),contains:markFunction(function(text){return function(elem){return(elem.textContent||elem.innerText||getText(elem)).indexOf(text)>-1}}),enabled:function(elem){return elem.disabled===false},disabled:function(elem){return elem.disabled===true},checked:function(elem){var nodeName=elem.nodeName.toLowerCase();return nodeName==="input"&&!!elem.checked||nodeName==="option"&&!!elem.selected},selected:function(elem){if(elem.parentNode){elem.parentNode.selectedIndex}return elem.selected===true},parent:function(elem){return!Expr.pseudos["empty"](elem)},empty:function(elem){var nodeType;elem=elem.firstChild;while(elem){if(elem.nodeName>"@"||(nodeType=elem.nodeType)===3||nodeType===4){return false}elem=elem.nextSibling}return true},header:function(elem){return rheader.test(elem.nodeName)},text:function(elem){var type,attr;return elem.nodeName.toLowerCase()==="input"&&(type=elem.type)==="text"&&((attr=elem.getAttribute("type"))==null||attr.toLowerCase()===type)},radio:createInputPseudo("radio"),checkbox:createInputPseudo("checkbox"),file:createInputPseudo("file"),password:createInputPseudo("password"),image:createInputPseudo("image"),submit:createButtonPseudo("submit"),reset:createButtonPseudo("reset"),button:function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type==="button"||name==="button"},input:function(elem){return rinputs.test(elem.nodeName)},focus:function(elem){var doc=elem.ownerDocument;return elem===doc.activeElement&&(!doc.hasFocus||doc.hasFocus())&&!!(elem.type||elem.href||~elem.tabIndex)},active:function(elem){return elem===elem.ownerDocument.activeElement},first:createPositionalPseudo(function(){return[0]}),last:createPositionalPseudo(function(matchIndexes,length){return[length-1]}),eq:createPositionalPseudo(function(matchIndexes,length,argument){return[argument<0?argument+length:argument]}),even:createPositionalPseudo(function(matchIndexes,length){for(var i=0;i<length;i+=2){matchIndexes.push(i)}return matchIndexes}),odd:createPositionalPseudo(function(matchIndexes,length){for(var i=1;i<length;i+=2){matchIndexes.push(i)}return matchIndexes}),lt:createPositionalPseudo(function(matchIndexes,length,argument){for(var i=argument<0?argument+length:argument;--i>=0;){matchIndexes.push(i)}return matchIndexes}),gt:createPositionalPseudo(function(matchIndexes,length,argument){for(var i=argument<0?argument+length:argument;++i<length;){matchIndexes.push(i)}return matchIndexes})}};function siblingCheck(a,b,ret){if(a===b){return ret}var cur=a.nextSibling;while(cur){if(cur===b){return-1}cur=cur.nextSibling}return 1}sortOrder=docElem.compareDocumentPosition?function(a,b){if(a===b){hasDuplicate=true;return 0}return(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b){hasDuplicate=true;return 0}else if(a.sourceIndex&&b.sourceIndex){return a.sourceIndex-b.sourceIndex}var al,bl,ap=[],bp=[],aup=a.parentNode,bup=b.parentNode,cur=aup;if(aup===bup){return siblingCheck(a,b)}else if(!aup){return-1}else if(!bup){return 1}while(cur){ap.unshift(cur);cur=cur.parentNode}cur=bup;while(cur){bp.unshift(cur);cur=cur.parentNode}al=ap.length;bl=bp.length;for(var i=0;i<al&&i<bl;i++){if(ap[i]!==bp[i]){return siblingCheck(ap[i],bp[i])}}return i===al?siblingCheck(a,bp[i],-1):siblingCheck(ap[i],b,1)};[0,0].sort(sortOrder);baseHasDuplicate=!hasDuplicate;Sizzle.uniqueSort=function(results){var elem,duplicates=[],i=1,j=0;hasDuplicate=baseHasDuplicate;results.sort(sortOrder);if(hasDuplicate){for(;elem=results[i];i++){if(elem===results[i-1]){j=duplicates.push(i)}}while(j--){results.splice(duplicates[j],1)}}return results};Sizzle.error=function(msg){throw new Error("Syntax error, unrecognized expression: "+msg)};function tokenize(selector,parseOnly){var matched,match,tokens,type,soFar,groups,preFilters,cached=tokenCache[expando][selector+" "];if(cached){return parseOnly?0:cached.slice(0)}soFar=selector;groups=[];preFilters=Expr.preFilter;while(soFar){if(!matched||(match=rcomma.exec(soFar))){if(match){soFar=soFar.slice(match[0].length)||soFar}groups.push(tokens=[])}matched=false;if(match=rcombinators.exec(soFar)){tokens.push(matched=new Token(match.shift()));soFar=soFar.slice(matched.length);matched.type=match[0].replace(rtrim," ")}for(type in Expr.filter){if((match=matchExpr[type].exec(soFar))&&(!preFilters[type]||(match=preFilters[type](match)))){tokens.push(matched=new Token(match.shift()));soFar=soFar.slice(matched.length);matched.type=type;matched.matches=match}}if(!matched){break}}return parseOnly?soFar.length:soFar?Sizzle.error(selector):tokenCache(selector,groups).slice(0)}function addCombinator(matcher,combinator,base){var dir=combinator.dir,checkNonElements=base&&combinator.dir==="parentNode",doneName=done++;return combinator.first?function(elem,context,xml){while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){return matcher(elem,context,xml)}}}:function(elem,context,xml){if(!xml){var cache,dirkey=dirruns+" "+doneName+" ",cachedkey=dirkey+cachedruns;while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){if((cache=elem[expando])===cachedkey){return elem.sizset}else if(typeof cache==="string"&&cache.indexOf(dirkey)===0){if(elem.sizset){return elem}}else{elem[expando]=cachedkey;if(matcher(elem,context,xml)){elem.sizset=true;return elem}elem.sizset=false}}}}else{while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){if(matcher(elem,context,xml)){return elem}}}}}}function elementMatcher(matchers){return matchers.length>1?function(elem,context,xml){var i=matchers.length;while(i--){if(!matchers[i](elem,context,xml)){return false}}return true}:matchers[0]}function condense(unmatched,map,filter,context,xml){var elem,newUnmatched=[],i=0,len=unmatched.length,mapped=map!=null;for(;i<len;i++){if(elem=unmatched[i]){if(!filter||filter(elem,context,xml)){newUnmatched.push(elem);if(mapped){map.push(i)}}}}return newUnmatched}function setMatcher(preFilter,selector,matcher,postFilter,postFinder,postSelector){if(postFilter&&!postFilter[expando]){postFilter=setMatcher(postFilter)}if(postFinder&&!postFinder[expando]){postFinder=setMatcher(postFinder,postSelector)}return markFunction(function(seed,results,context,xml){var temp,i,elem,preMap=[],postMap=[],preexisting=results.length,elems=seed||multipleContexts(selector||"*",context.nodeType?[context]:context,[]),matcherIn=preFilter&&(seed||!selector)?condense(elems,preMap,preFilter,context,xml):elems,matcherOut=matcher?postFinder||(seed?preFilter:preexisting||postFilter)?[]:results:matcherIn;if(matcher){matcher(matcherIn,matcherOut,context,xml)}if(postFilter){temp=condense(matcherOut,postMap);postFilter(temp,[],context,xml);i=temp.length;while(i--){if(elem=temp[i]){matcherOut[postMap[i]]=!(matcherIn[postMap[i]]=elem)}}}if(seed){if(postFinder||preFilter){if(postFinder){temp=[];i=matcherOut.length;while(i--){if(elem=matcherOut[i]){temp.push(matcherIn[i]=elem)}}postFinder(null,matcherOut=[],temp,xml)}i=matcherOut.length;while(i--){if((elem=matcherOut[i])&&(temp=postFinder?indexOf.call(seed,elem):preMap[i])>-1){seed[temp]=!(results[temp]=elem)}}}}else{matcherOut=condense(matcherOut===results?matcherOut.splice(preexisting,matcherOut.length):matcherOut);if(postFinder){postFinder(null,results,matcherOut,xml)}else{push.apply(results,matcherOut)}}})}function matcherFromTokens(tokens){var checkContext,matcher,j,len=tokens.length,leadingRelative=Expr.relative[tokens[0].type],implicitRelative=leadingRelative||Expr.relative[" "],i=leadingRelative?1:0,matchContext=addCombinator(function(elem){return elem===checkContext},implicitRelative,true),matchAnyContext=addCombinator(function(elem){return indexOf.call(checkContext,elem)>-1},implicitRelative,true),matchers=[function(elem,context,xml){return!leadingRelative&&(xml||context!==outermostContext)||((checkContext=context).nodeType?matchContext(elem,context,xml):matchAnyContext(elem,context,xml))}];for(;i<len;i++){if(matcher=Expr.relative[tokens[i].type]){matchers=[addCombinator(elementMatcher(matchers),matcher)]}else{matcher=Expr.filter[tokens[i].type].apply(null,tokens[i].matches);if(matcher[expando]){j=++i;for(;j<len;j++){if(Expr.relative[tokens[j].type]){break}}return setMatcher(i>1&&elementMatcher(matchers),i>1&&tokens.slice(0,i-1).join("").replace(rtrim,"$1"),matcher,i<j&&matcherFromTokens(tokens.slice(i,j)),j<len&&matcherFromTokens(tokens=tokens.slice(j)),j<len&&tokens.join(""))}matchers.push(matcher)}}return elementMatcher(matchers)}function matcherFromGroupMatchers(elementMatchers,setMatchers){var bySet=setMatchers.length>0,byElement=elementMatchers.length>0,superMatcher=function(seed,context,xml,results,expandContext){var elem,j,matcher,setMatched=[],matchedCount=0,i="0",unmatched=seed&&[],outermost=expandContext!=null,contextBackup=outermostContext,elems=seed||byElement&&Expr.find["TAG"]("*",expandContext&&context.parentNode||context),dirrunsUnique=dirruns+=contextBackup==null?1:Math.E;if(outermost){outermostContext=context!==document&&context;cachedruns=superMatcher.el}for(;(elem=elems[i])!=null;i++){if(byElement&&elem){for(j=0;matcher=elementMatchers[j];j++){if(matcher(elem,context,xml)){results.push(elem);break}}if(outermost){dirruns=dirrunsUnique;cachedruns=++superMatcher.el}}if(bySet){if(elem=!matcher&&elem){matchedCount--}if(seed){unmatched.push(elem)}}}matchedCount+=i;if(bySet&&i!==matchedCount){for(j=0;matcher=setMatchers[j];j++){matcher(unmatched,setMatched,context,xml)}if(seed){if(matchedCount>0){while(i--){if(!(unmatched[i]||setMatched[i])){setMatched[i]=pop.call(results)}}}setMatched=condense(setMatched)}push.apply(results,setMatched);if(outermost&&!seed&&setMatched.length>0&&matchedCount+setMatchers.length>1){Sizzle.uniqueSort(results)}}if(outermost){dirruns=dirrunsUnique;outermostContext=contextBackup}return unmatched};superMatcher.el=0;return bySet?markFunction(superMatcher):superMatcher}compile=Sizzle.compile=function(selector,group){var i,setMatchers=[],elementMatchers=[],cached=compilerCache[expando][selector+" "];if(!cached){if(!group){group=tokenize(selector)}i=group.length;while(i--){cached=matcherFromTokens(group[i]);if(cached[expando]){setMatchers.push(cached)}else{elementMatchers.push(cached)}}cached=compilerCache(selector,matcherFromGroupMatchers(elementMatchers,setMatchers))}return cached};function multipleContexts(selector,contexts,results){var i=0,len=contexts.length;for(;i<len;i++){Sizzle(selector,contexts[i],results)}return results}function select(selector,context,results,seed,xml){var i,tokens,token,type,find,match=tokenize(selector),j=match.length;if(!seed){if(match.length===1){tokens=match[0]=match[0].slice(0);if(tokens.length>2&&(token=tokens[0]).type==="ID"&&context.nodeType===9&&!xml&&Expr.relative[tokens[1].type]){context=Expr.find["ID"](token.matches[0].replace(rbackslash,""),context,xml)[0];if(!context){return results}selector=selector.slice(tokens.shift().length)}for(i=matchExpr["POS"].test(selector)?-1:tokens.length-1;i>=0;i--){token=tokens[i];if(Expr.relative[type=token.type]){break}if(find=Expr.find[type]){if(seed=find(token.matches[0].replace(rbackslash,""),rsibling.test(tokens[0].type)&&context.parentNode||context,xml)){tokens.splice(i,1);selector=seed.length&&tokens.join("");if(!selector){push.apply(results,slice.call(seed,0));return results}break}}}}}compile(selector,match)(seed,context,xml,results,rsibling.test(selector));return results}if(document.querySelectorAll){(function(){var disconnectedMatch,oldSelect=select,rescape=/'|\\/g,rattributeQuotes=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,rbuggyQSA=[":focus"],rbuggyMatches=[":active"],matches=docElem.matchesSelector||docElem.mozMatchesSelector||docElem.webkitMatchesSelector||docElem.oMatchesSelector||docElem.msMatchesSelector;assert(function(div){div.innerHTML="<select><option selected=''></option></select>";if(!div.querySelectorAll("[selected]").length){rbuggyQSA.push("\\["+whitespace+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)")}if(!div.querySelectorAll(":checked").length){rbuggyQSA.push(":checked")}});assert(function(div){div.innerHTML="<p test=''></p>";if(div.querySelectorAll("[test^='']").length){rbuggyQSA.push("[*^$]="+whitespace+"*(?:\"\"|'')")}div.innerHTML="<input type='hidden'/>";if(!div.querySelectorAll(":enabled").length){rbuggyQSA.push(":enabled",":disabled")}});rbuggyQSA=new RegExp(rbuggyQSA.join("|"));select=function(selector,context,results,seed,xml){if(!seed&&!xml&&!rbuggyQSA.test(selector)){var groups,i,old=true,nid=expando,newContext=context,newSelector=context.nodeType===9&&selector;if(context.nodeType===1&&context.nodeName.toLowerCase()!=="object"){groups=tokenize(selector);if(old=context.getAttribute("id")){nid=old.replace(rescape,"\\$&")}else{context.setAttribute("id",nid)}nid="[id='"+nid+"'] ";i=groups.length;while(i--){groups[i]=nid+groups[i].join("")}newContext=rsibling.test(selector)&&context.parentNode||context;newSelector=groups.join(",")}if(newSelector){try{push.apply(results,slice.call(newContext.querySelectorAll(newSelector),0));return results}catch(qsaError){}finally{if(!old){context.removeAttribute("id")}}}}return oldSelect(selector,context,results,seed,xml)};if(matches){assert(function(div){disconnectedMatch=matches.call(div,"div");try{matches.call(div,"[test!='']:sizzle");rbuggyMatches.push("!=",pseudos)}catch(e){}});rbuggyMatches=new RegExp(rbuggyMatches.join("|"));Sizzle.matchesSelector=function(elem,expr){expr=expr.replace(rattributeQuotes,"='$1']");if(!isXML(elem)&&!rbuggyMatches.test(expr)&&!rbuggyQSA.test(expr)){try{var ret=matches.call(elem,expr);if(ret||disconnectedMatch||elem.document&&elem.document.nodeType!==11){return ret}}catch(e){}}return Sizzle(expr,null,null,[elem]).length>0}}})()}Expr.pseudos["nth"]=Expr.pseudos["eq"];function setFilters(){}Expr.filters=setFilters.prototype=Expr.pseudos;Expr.setFilters=new setFilters;Sizzle.attr=jQuery.attr;jQuery.find=Sizzle;jQuery.expr=Sizzle.selectors;jQuery.expr[":"]=jQuery.expr.pseudos;jQuery.unique=Sizzle.uniqueSort;jQuery.text=Sizzle.getText;jQuery.isXMLDoc=Sizzle.isXML;jQuery.contains=Sizzle.contains})(window);var runtil=/Until$/,rparentsprev=/^(?:parents|prev(?:Until|All))/,isSimple=/^.[^:#\[\.,]*$/,rneedsContext=jQuery.expr.match.needsContext,guaranteedUnique={children:true,contents:true,next:true,prev:true};jQuery.fn.extend({find:function(selector){var i,l,length,n,r,ret,self=this;if(typeof selector!=="string"){return jQuery(selector).filter(function(){for(i=0,l=self.length;i<l;i++){if(jQuery.contains(self[i],this)){return true}}})}ret=this.pushStack("","find",selector);for(i=0,l=this.length;i<l;i++){length=ret.length;jQuery.find(selector,this[i],ret);if(i>0){for(n=length;n<ret.length;n++){for(r=0;r<length;r++){if(ret[r]===ret[n]){ret.splice(n--,1);break}}}}}return ret},has:function(target){var i,targets=jQuery(target,this),len=targets.length;return this.filter(function(){for(i=0;i<len;i++){if(jQuery.contains(this,targets[i])){return true}}})},not:function(selector){return this.pushStack(winnow(this,selector,false),"not",selector)},filter:function(selector){return this.pushStack(winnow(this,selector,true),"filter",selector)},is:function(selector){return!!selector&&(typeof selector==="string"?rneedsContext.test(selector)?jQuery(selector,this.context).index(this[0])>=0:jQuery.filter(selector,this).length>0:this.filter(selector).length>0)},closest:function(selectors,context){var cur,i=0,l=this.length,ret=[],pos=rneedsContext.test(selectors)||typeof selectors!=="string"?jQuery(selectors,context||this.context):0;for(;i<l;i++){cur=this[i];while(cur&&cur.ownerDocument&&cur!==context&&cur.nodeType!==11){if(pos?pos.index(cur)>-1:jQuery.find.matchesSelector(cur,selectors)){ret.push(cur);break}cur=cur.parentNode}}ret=ret.length>1?jQuery.unique(ret):ret;return this.pushStack(ret,"closest",selectors)},index:function(elem){if(!elem){return this[0]&&this[0].parentNode?this.prevAll().length:-1}if(typeof elem==="string"){return jQuery.inArray(this[0],jQuery(elem))}return jQuery.inArray(elem.jquery?elem[0]:elem,this)},add:function(selector,context){var set=typeof selector==="string"?jQuery(selector,context):jQuery.makeArray(selector&&selector.nodeType?[selector]:selector),all=jQuery.merge(this.get(),set);return this.pushStack(isDisconnected(set[0])||isDisconnected(all[0])?all:jQuery.unique(all))},addBack:function(selector){return this.add(selector==null?this.prevObject:this.prevObject.filter(selector))}});jQuery.fn.andSelf=jQuery.fn.addBack;function isDisconnected(node){return!node||!node.parentNode||node.parentNode.nodeType===11}function sibling(cur,dir){do{cur=cur[dir]}while(cur&&cur.nodeType!==1);return cur}jQuery.each({parent:function(elem){var parent=elem.parentNode;return parent&&parent.nodeType!==11?parent:null},parents:function(elem){return jQuery.dir(elem,"parentNode")},parentsUntil:function(elem,i,until){return jQuery.dir(elem,"parentNode",until)},next:function(elem){return sibling(elem,"nextSibling")},prev:function(elem){return sibling(elem,"previousSibling")},nextAll:function(elem){return jQuery.dir(elem,"nextSibling")},prevAll:function(elem){return jQuery.dir(elem,"previousSibling")},nextUntil:function(elem,i,until){return jQuery.dir(elem,"nextSibling",until)},prevUntil:function(elem,i,until){return jQuery.dir(elem,"previousSibling",until)},siblings:function(elem){return jQuery.sibling((elem.parentNode||{}).firstChild,elem)},children:function(elem){return jQuery.sibling(elem.firstChild)},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.merge([],elem.childNodes)}},function(name,fn){jQuery.fn[name]=function(until,selector){var ret=jQuery.map(this,fn,until);if(!runtil.test(name)){selector=until}if(selector&&typeof selector==="string"){ret=jQuery.filter(selector,ret)}ret=this.length>1&&!guaranteedUnique[name]?jQuery.unique(ret):ret;if(this.length>1&&rparentsprev.test(name)){ret=ret.reverse()}return this.pushStack(ret,name,core_slice.call(arguments).join(","))}});jQuery.extend({filter:function(expr,elems,not){if(not){expr=":not("+expr+")"}return elems.length===1?jQuery.find.matchesSelector(elems[0],expr)?[elems[0]]:[]:jQuery.find.matches(expr,elems)},dir:function(elem,dir,until){var matched=[],cur=elem[dir];while(cur&&cur.nodeType!==9&&(until===undefined||cur.nodeType!==1||!jQuery(cur).is(until))){if(cur.nodeType===1){matched.push(cur)}cur=cur[dir]}return matched},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType===1&&n!==elem){r.push(n)}}return r}});function winnow(elements,qualifier,keep){qualifier=qualifier||0;if(jQuery.isFunction(qualifier)){return jQuery.grep(elements,function(elem,i){var retVal=!!qualifier.call(elem,i,elem);return retVal===keep})}else if(qualifier.nodeType){return jQuery.grep(elements,function(elem,i){return elem===qualifier===keep})}else if(typeof qualifier==="string"){var filtered=jQuery.grep(elements,function(elem){return elem.nodeType===1});if(isSimple.test(qualifier)){return jQuery.filter(qualifier,filtered,!keep)}else{qualifier=jQuery.filter(qualifier,filtered)}}return jQuery.grep(elements,function(elem,i){return jQuery.inArray(elem,qualifier)>=0===keep})}function createSafeFragment(document){var list=nodeNames.split("|"),safeFrag=document.createDocumentFragment();if(safeFrag.createElement){while(list.length){safeFrag.createElement(list.pop())}}return safeFrag}var nodeNames="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|"+"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",rinlinejQuery=/ jQuery\d+="(?:null|\d+)"/g,rleadingWhitespace=/^\s+/,rxhtmlTag=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,rtagName=/<([\w:]+)/,rtbody=/<tbody/i,rhtml=/<|&#?\w+;/,rnoInnerhtml=/<(?:script|style|link)/i,rnocache=/<(?:script|object|embed|option|style)/i,rnoshimcache=new RegExp("<(?:"+nodeNames+")[\\s/>]","i"),rcheckableType=/^(?:checkbox|radio)$/,rchecked=/checked\s*(?:[^=]|=\s*.checked.)/i,rscriptType=/\/(java|ecma)script/i,rcleanScript=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,wrapMap={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},safeFragment=createSafeFragment(document),fragmentDiv=safeFragment.appendChild(document.createElement("div"));wrapMap.optgroup=wrapMap.option;wrapMap.tbody=wrapMap.tfoot=wrapMap.colgroup=wrapMap.caption=wrapMap.thead;wrapMap.th=wrapMap.td;if(!jQuery.support.htmlSerialize){wrapMap._default=[1,"X<div>","</div>"]}jQuery.fn.extend({text:function(value){return jQuery.access(this,function(value){return value===undefined?jQuery.text(this):this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(value))},null,value,arguments.length)},wrapAll:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapAll(html.call(this,i))})}if(this[0]){var wrap=jQuery(html,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){wrap.insertBefore(this[0])}wrap.map(function(){var elem=this;while(elem.firstChild&&elem.firstChild.nodeType===1){elem=elem.firstChild}return elem}).append(this)}return this},wrapInner:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapInner(html.call(this,i))})}return this.each(function(){var self=jQuery(this),contents=self.contents();if(contents.length){contents.wrapAll(html)}else{self.append(html)}})},wrap:function(html){var isFunction=jQuery.isFunction(html);return this.each(function(i){jQuery(this).wrapAll(isFunction?html.call(this,i):html)})},unwrap:function(){return this.parent().each(function(){if(!jQuery.nodeName(this,"body")){jQuery(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1||this.nodeType===11){this.appendChild(elem)}})},prepend:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1||this.nodeType===11){this.insertBefore(elem,this.firstChild)}})},before:function(){if(!isDisconnected(this[0])){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this)})}if(arguments.length){var set=jQuery.clean(arguments);return this.pushStack(jQuery.merge(set,this),"before",this.selector)}},after:function(){if(!isDisconnected(this[0])){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this.nextSibling)})}if(arguments.length){var set=jQuery.clean(arguments);return this.pushStack(jQuery.merge(this,set),"after",this.selector)}},remove:function(selector,keepData){var elem,i=0;for(;(elem=this[i])!=null;i++){if(!selector||jQuery.filter(selector,[elem]).length){if(!keepData&&elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));jQuery.cleanData([elem])}if(elem.parentNode){elem.parentNode.removeChild(elem)}}}return this},empty:function(){var elem,i=0;for(;(elem=this[i])!=null;i++){if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"))}while(elem.firstChild){elem.removeChild(elem.firstChild)}}return this},clone:function(dataAndEvents,deepDataAndEvents){dataAndEvents=dataAndEvents==null?false:dataAndEvents;deepDataAndEvents=deepDataAndEvents==null?dataAndEvents:deepDataAndEvents;return this.map(function(){return jQuery.clone(this,dataAndEvents,deepDataAndEvents)})},html:function(value){return jQuery.access(this,function(value){var elem=this[0]||{},i=0,l=this.length;if(value===undefined){return elem.nodeType===1?elem.innerHTML.replace(rinlinejQuery,""):undefined}if(typeof value==="string"&&!rnoInnerhtml.test(value)&&(jQuery.support.htmlSerialize||!rnoshimcache.test(value))&&(jQuery.support.leadingWhitespace||!rleadingWhitespace.test(value))&&!wrapMap[(rtagName.exec(value)||["",""])[1].toLowerCase()]){value=value.replace(rxhtmlTag,"<$1></$2>");try{for(;i<l;i++){elem=this[i]||{};if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));elem.innerHTML=value}}elem=0}catch(e){}}if(elem){this.empty().append(value)}},null,value,arguments.length)},replaceWith:function(value){if(!isDisconnected(this[0])){if(jQuery.isFunction(value)){return this.each(function(i){var self=jQuery(this),old=self.html();self.replaceWith(value.call(this,i,old))})}if(typeof value!=="string"){value=jQuery(value).detach()}return this.each(function(){var next=this.nextSibling,parent=this.parentNode;jQuery(this).remove();if(next){jQuery(next).before(value)}else{jQuery(parent).append(value)}})}return this.length?this.pushStack(jQuery(jQuery.isFunction(value)?value():value),"replaceWith",value):this},detach:function(selector){return this.remove(selector,true)},domManip:function(args,table,callback){args=[].concat.apply([],args);var results,first,fragment,iNoClone,i=0,value=args[0],scripts=[],l=this.length;if(!jQuery.support.checkClone&&l>1&&typeof value==="string"&&rchecked.test(value)){return this.each(function(){jQuery(this).domManip(args,table,callback)})}if(jQuery.isFunction(value)){return this.each(function(i){var self=jQuery(this);args[0]=value.call(this,i,table?self.html():undefined);self.domManip(args,table,callback)})}if(this[0]){results=jQuery.buildFragment(args,this,scripts);fragment=results.fragment;first=fragment.firstChild;if(fragment.childNodes.length===1){fragment=first}if(first){table=table&&jQuery.nodeName(first,"tr");for(iNoClone=results.cacheable||l-1;i<l;i++){callback.call(table&&jQuery.nodeName(this[i],"table")?findOrAppend(this[i],"tbody"):this[i],i===iNoClone?fragment:jQuery.clone(fragment,true,true))}}fragment=first=null;if(scripts.length){jQuery.each(scripts,function(i,elem){if(elem.src){if(jQuery.ajax){jQuery.ajax({url:elem.src,type:"GET",dataType:"script",async:false,global:false,"throws":true})}else{jQuery.error("no ajax")}}else{jQuery.globalEval((elem.text||elem.textContent||elem.innerHTML||"").replace(rcleanScript,""))}if(elem.parentNode){elem.parentNode.removeChild(elem)}})}}return this}});function findOrAppend(elem,tag){return elem.getElementsByTagName(tag)[0]||elem.appendChild(elem.ownerDocument.createElement(tag))}function cloneCopyEvent(src,dest){if(dest.nodeType!==1||!jQuery.hasData(src)){return}var type,i,l,oldData=jQuery._data(src),curData=jQuery._data(dest,oldData),events=oldData.events;if(events){delete curData.handle;curData.events={};for(type in events){for(i=0,l=events[type].length;i<l;i++){jQuery.event.add(dest,type,events[type][i])}}}if(curData.data){curData.data=jQuery.extend({},curData.data)}}function cloneFixAttributes(src,dest){var nodeName;if(dest.nodeType!==1){return}if(dest.clearAttributes){dest.clearAttributes()}if(dest.mergeAttributes){dest.mergeAttributes(src)}nodeName=dest.nodeName.toLowerCase();if(nodeName==="object"){if(dest.parentNode){dest.outerHTML=src.outerHTML}if(jQuery.support.html5Clone&&(src.innerHTML&&!jQuery.trim(dest.innerHTML))){dest.innerHTML=src.innerHTML}}else if(nodeName==="input"&&rcheckableType.test(src.type)){dest.defaultChecked=dest.checked=src.checked;if(dest.value!==src.value){dest.value=src.value}}else if(nodeName==="option"){dest.selected=src.defaultSelected}else if(nodeName==="input"||nodeName==="textarea"){dest.defaultValue=src.defaultValue}else if(nodeName==="script"&&dest.text!==src.text){dest.text=src.text}dest.removeAttribute(jQuery.expando)}jQuery.buildFragment=function(args,context,scripts){var fragment,cacheable,cachehit,first=args[0];context=context||document;context=!context.nodeType&&context[0]||context;context=context.ownerDocument||context;if(args.length===1&&typeof first==="string"&&first.length<512&&context===document&&first.charAt(0)==="<"&&!rnocache.test(first)&&(jQuery.support.checkClone||!rchecked.test(first))&&(jQuery.support.html5Clone||!rnoshimcache.test(first))){cacheable=true;fragment=jQuery.fragments[first];cachehit=fragment!==undefined}if(!fragment){fragment=context.createDocumentFragment();jQuery.clean(args,context,fragment,scripts);if(cacheable){jQuery.fragments[first]=cachehit&&fragment}}return{fragment:fragment,cacheable:cacheable}};jQuery.fragments={};jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(selector){var elems,i=0,ret=[],insert=jQuery(selector),l=insert.length,parent=this.length===1&&this[0].parentNode;if((parent==null||parent&&parent.nodeType===11&&parent.childNodes.length===1)&&l===1){insert[original](this[0]);return this}else{for(;i<l;i++){elems=(i>0?this.clone(true):this).get();jQuery(insert[i])[original](elems);ret=ret.concat(elems)}return this.pushStack(ret,name,insert.selector)}}});function getAll(elem){if(typeof elem.getElementsByTagName!=="undefined"){return elem.getElementsByTagName("*")}else if(typeof elem.querySelectorAll!=="undefined"){return elem.querySelectorAll("*")}else{return[]}}function fixDefaultChecked(elem){if(rcheckableType.test(elem.type)){elem.defaultChecked=elem.checked}}jQuery.extend({clone:function(elem,dataAndEvents,deepDataAndEvents){var srcElements,destElements,i,clone;if(jQuery.support.html5Clone||jQuery.isXMLDoc(elem)||!rnoshimcache.test("<"+elem.nodeName+">")){clone=elem.cloneNode(true)}else{fragmentDiv.innerHTML=elem.outerHTML;fragmentDiv.removeChild(clone=fragmentDiv.firstChild)}if((!jQuery.support.noCloneEvent||!jQuery.support.noCloneChecked)&&(elem.nodeType===1||elem.nodeType===11)&&!jQuery.isXMLDoc(elem)){cloneFixAttributes(elem,clone);srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){if(destElements[i]){cloneFixAttributes(srcElements[i],destElements[i])}}}if(dataAndEvents){cloneCopyEvent(elem,clone);if(deepDataAndEvents){srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){cloneCopyEvent(srcElements[i],destElements[i])}}}srcElements=destElements=null;return clone},clean:function(elems,context,fragment,scripts){var i,j,elem,tag,wrap,depth,div,hasBody,tbody,len,handleScript,jsTags,safe=context===document&&safeFragment,ret=[];if(!context||typeof context.createDocumentFragment==="undefined"){context=document}for(i=0;(elem=elems[i])!=null;i++){if(typeof elem==="number"){elem+=""}if(!elem){continue}if(typeof elem==="string"){if(!rhtml.test(elem)){elem=context.createTextNode(elem)}else{safe=safe||createSafeFragment(context);div=context.createElement("div");safe.appendChild(div);elem=elem.replace(rxhtmlTag,"<$1></$2>");tag=(rtagName.exec(elem)||["",""])[1].toLowerCase();wrap=wrapMap[tag]||wrapMap._default;depth=wrap[0];div.innerHTML=wrap[1]+elem+wrap[2];while(depth--){div=div.lastChild +}if(!jQuery.support.tbody){hasBody=rtbody.test(elem);tbody=tag==="table"&&!hasBody?div.firstChild&&div.firstChild.childNodes:wrap[1]==="<table>"&&!hasBody?div.childNodes:[];for(j=tbody.length-1;j>=0;--j){if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length){tbody[j].parentNode.removeChild(tbody[j])}}}if(!jQuery.support.leadingWhitespace&&rleadingWhitespace.test(elem)){div.insertBefore(context.createTextNode(rleadingWhitespace.exec(elem)[0]),div.firstChild)}elem=div.childNodes;div.parentNode.removeChild(div)}}if(elem.nodeType){ret.push(elem)}else{jQuery.merge(ret,elem)}}if(div){elem=div=safe=null}if(!jQuery.support.appendChecked){for(i=0;(elem=ret[i])!=null;i++){if(jQuery.nodeName(elem,"input")){fixDefaultChecked(elem)}else if(typeof elem.getElementsByTagName!=="undefined"){jQuery.grep(elem.getElementsByTagName("input"),fixDefaultChecked)}}}if(fragment){handleScript=function(elem){if(!elem.type||rscriptType.test(elem.type)){return scripts?scripts.push(elem.parentNode?elem.parentNode.removeChild(elem):elem):fragment.appendChild(elem)}};for(i=0;(elem=ret[i])!=null;i++){if(!(jQuery.nodeName(elem,"script")&&handleScript(elem))){fragment.appendChild(elem);if(typeof elem.getElementsByTagName!=="undefined"){jsTags=jQuery.grep(jQuery.merge([],elem.getElementsByTagName("script")),handleScript);ret.splice.apply(ret,[i+1,0].concat(jsTags));i+=jsTags.length}}}}return ret},cleanData:function(elems,acceptData){var data,id,elem,type,i=0,internalKey=jQuery.expando,cache=jQuery.cache,deleteExpando=jQuery.support.deleteExpando,special=jQuery.event.special;for(;(elem=elems[i])!=null;i++){if(acceptData||jQuery.acceptData(elem)){id=elem[internalKey];data=id&&cache[id];if(data){if(data.events){for(type in data.events){if(special[type]){jQuery.event.remove(elem,type)}else{jQuery.removeEvent(elem,type,data.handle)}}}if(cache[id]){delete cache[id];if(deleteExpando){delete elem[internalKey]}else if(elem.removeAttribute){elem.removeAttribute(internalKey)}else{elem[internalKey]=null}jQuery.deletedIds.push(id)}}}}}});(function(){var matched,browser;jQuery.uaMatch=function(ua){ua=ua.toLowerCase();var match=/(chrome)[ \/]([\w.]+)/.exec(ua)||/(webkit)[ \/]([\w.]+)/.exec(ua)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua)||/(msie) ([\w.]+)/.exec(ua)||ua.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua)||[];return{browser:match[1]||"",version:match[2]||"0"}};matched=jQuery.uaMatch(navigator.userAgent);browser={};if(matched.browser){browser[matched.browser]=true;browser.version=matched.version}if(browser.chrome){browser.webkit=true}else if(browser.webkit){browser.safari=true}jQuery.browser=browser;jQuery.sub=function(){function jQuerySub(selector,context){return new jQuerySub.fn.init(selector,context)}jQuery.extend(true,jQuerySub,this);jQuerySub.superclass=this;jQuerySub.fn=jQuerySub.prototype=this();jQuerySub.fn.constructor=jQuerySub;jQuerySub.sub=this.sub;jQuerySub.fn.init=function init(selector,context){if(context&&context instanceof jQuery&&!(context instanceof jQuerySub)){context=jQuerySub(context)}return jQuery.fn.init.call(this,selector,context,rootjQuerySub)};jQuerySub.fn.init.prototype=jQuerySub.fn;var rootjQuerySub=jQuerySub(document);return jQuerySub}})();var curCSS,iframe,iframeDoc,ralpha=/alpha\([^)]*\)/i,ropacity=/opacity=([^)]*)/,rposition=/^(top|right|bottom|left)$/,rdisplayswap=/^(none|table(?!-c[ea]).+)/,rmargin=/^margin/,rnumsplit=new RegExp("^("+core_pnum+")(.*)$","i"),rnumnonpx=new RegExp("^("+core_pnum+")(?!px)[a-z%]+$","i"),rrelNum=new RegExp("^([-+])=("+core_pnum+")","i"),elemdisplay={BODY:"block"},cssShow={position:"absolute",visibility:"hidden",display:"block"},cssNormalTransform={letterSpacing:0,fontWeight:400},cssExpand=["Top","Right","Bottom","Left"],cssPrefixes=["Webkit","O","Moz","ms"],eventsToggle=jQuery.fn.toggle;function vendorPropName(style,name){if(name in style){return name}var capName=name.charAt(0).toUpperCase()+name.slice(1),origName=name,i=cssPrefixes.length;while(i--){name=cssPrefixes[i]+capName;if(name in style){return name}}return origName}function isHidden(elem,el){elem=el||elem;return jQuery.css(elem,"display")==="none"||!jQuery.contains(elem.ownerDocument,elem)}function showHide(elements,show){var elem,display,values=[],index=0,length=elements.length;for(;index<length;index++){elem=elements[index];if(!elem.style){continue}values[index]=jQuery._data(elem,"olddisplay");if(show){if(!values[index]&&elem.style.display==="none"){elem.style.display=""}if(elem.style.display===""&&isHidden(elem)){values[index]=jQuery._data(elem,"olddisplay",css_defaultDisplay(elem.nodeName))}}else{display=curCSS(elem,"display");if(!values[index]&&display!=="none"){jQuery._data(elem,"olddisplay",display)}}}for(index=0;index<length;index++){elem=elements[index];if(!elem.style){continue}if(!show||elem.style.display==="none"||elem.style.display===""){elem.style.display=show?values[index]||"":"none"}}return elements}jQuery.fn.extend({css:function(name,value){return jQuery.access(this,function(elem,name,value){return value!==undefined?jQuery.style(elem,name,value):jQuery.css(elem,name)},name,value,arguments.length>1)},show:function(){return showHide(this,true)},hide:function(){return showHide(this)},toggle:function(state,fn2){var bool=typeof state==="boolean";if(jQuery.isFunction(state)&&jQuery.isFunction(fn2)){return eventsToggle.apply(this,arguments)}return this.each(function(){if(bool?state:isHidden(this)){jQuery(this).show()}else{jQuery(this).hide()}})}});jQuery.extend({cssHooks:{opacity:{get:function(elem,computed){if(computed){var ret=curCSS(elem,"opacity");return ret===""?"1":ret}}}},cssNumber:{fillOpacity:true,fontWeight:true,lineHeight:true,opacity:true,orphans:true,widows:true,zIndex:true,zoom:true},cssProps:{"float":jQuery.support.cssFloat?"cssFloat":"styleFloat"},style:function(elem,name,value,extra){if(!elem||elem.nodeType===3||elem.nodeType===8||!elem.style){return}var ret,type,hooks,origName=jQuery.camelCase(name),style=elem.style;name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(value!==undefined){type=typeof value;if(type==="string"&&(ret=rrelNum.exec(value))){value=(ret[1]+1)*ret[2]+parseFloat(jQuery.css(elem,name));type="number"}if(value==null||type==="number"&&isNaN(value)){return}if(type==="number"&&!jQuery.cssNumber[origName]){value+="px"}if(!hooks||!("set"in hooks)||(value=hooks.set(elem,value,extra))!==undefined){try{style[name]=value}catch(e){}}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,false,extra))!==undefined){return ret}return style[name]}},css:function(elem,name,numeric,extra){var val,num,hooks,origName=jQuery.camelCase(name);name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(elem.style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(hooks&&"get"in hooks){val=hooks.get(elem,true,extra)}if(val===undefined){val=curCSS(elem,name)}if(val==="normal"&&name in cssNormalTransform){val=cssNormalTransform[name]}if(numeric||extra!==undefined){num=parseFloat(val);return numeric||jQuery.isNumeric(num)?num||0:val}return val},swap:function(elem,options,callback){var ret,name,old={};for(name in options){old[name]=elem.style[name];elem.style[name]=options[name]}ret=callback.call(elem);for(name in options){elem.style[name]=old[name]}return ret}});if(window.getComputedStyle){curCSS=function(elem,name){var ret,width,minWidth,maxWidth,computed=window.getComputedStyle(elem,null),style=elem.style;if(computed){ret=computed.getPropertyValue(name)||computed[name];if(ret===""&&!jQuery.contains(elem.ownerDocument,elem)){ret=jQuery.style(elem,name)}if(rnumnonpx.test(ret)&&rmargin.test(name)){width=style.width;minWidth=style.minWidth;maxWidth=style.maxWidth;style.minWidth=style.maxWidth=style.width=ret;ret=computed.width;style.width=width;style.minWidth=minWidth;style.maxWidth=maxWidth}}return ret}}else if(document.documentElement.currentStyle){curCSS=function(elem,name){var left,rsLeft,ret=elem.currentStyle&&elem.currentStyle[name],style=elem.style;if(ret==null&&style&&style[name]){ret=style[name]}if(rnumnonpx.test(ret)&&!rposition.test(name)){left=style.left;rsLeft=elem.runtimeStyle&&elem.runtimeStyle.left;if(rsLeft){elem.runtimeStyle.left=elem.currentStyle.left}style.left=name==="fontSize"?"1em":ret;ret=style.pixelLeft+"px";style.left=left;if(rsLeft){elem.runtimeStyle.left=rsLeft}}return ret===""?"auto":ret}}function setPositiveNumber(elem,value,subtract){var matches=rnumsplit.exec(value);return matches?Math.max(0,matches[1]-(subtract||0))+(matches[2]||"px"):value}function augmentWidthOrHeight(elem,name,extra,isBorderBox){var i=extra===(isBorderBox?"border":"content")?4:name==="width"?1:0,val=0;for(;i<4;i+=2){if(extra==="margin"){val+=jQuery.css(elem,extra+cssExpand[i],true)}if(isBorderBox){if(extra==="content"){val-=parseFloat(curCSS(elem,"padding"+cssExpand[i]))||0}if(extra!=="margin"){val-=parseFloat(curCSS(elem,"border"+cssExpand[i]+"Width"))||0}}else{val+=parseFloat(curCSS(elem,"padding"+cssExpand[i]))||0;if(extra!=="padding"){val+=parseFloat(curCSS(elem,"border"+cssExpand[i]+"Width"))||0}}}return val}function getWidthOrHeight(elem,name,extra){var val=name==="width"?elem.offsetWidth:elem.offsetHeight,valueIsBorderBox=true,isBorderBox=jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing")==="border-box";if(val<=0||val==null){val=curCSS(elem,name);if(val<0||val==null){val=elem.style[name]}if(rnumnonpx.test(val)){return val}valueIsBorderBox=isBorderBox&&(jQuery.support.boxSizingReliable||val===elem.style[name]);val=parseFloat(val)||0}return val+augmentWidthOrHeight(elem,name,extra||(isBorderBox?"border":"content"),valueIsBorderBox)+"px"}function css_defaultDisplay(nodeName){if(elemdisplay[nodeName]){return elemdisplay[nodeName]}var elem=jQuery("<"+nodeName+">").appendTo(document.body),display=elem.css("display");elem.remove();if(display==="none"||display===""){iframe=document.body.appendChild(iframe||jQuery.extend(document.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!iframeDoc||!iframe.createElement){iframeDoc=(iframe.contentWindow||iframe.contentDocument).document;iframeDoc.write("<!doctype html><html><body>");iframeDoc.close()}elem=iframeDoc.body.appendChild(iframeDoc.createElement(nodeName));display=curCSS(elem,"display");document.body.removeChild(iframe)}elemdisplay[nodeName]=display;return display}jQuery.each(["height","width"],function(i,name){jQuery.cssHooks[name]={get:function(elem,computed,extra){if(computed){if(elem.offsetWidth===0&&rdisplayswap.test(curCSS(elem,"display"))){return jQuery.swap(elem,cssShow,function(){return getWidthOrHeight(elem,name,extra)})}else{return getWidthOrHeight(elem,name,extra)}}},set:function(elem,value,extra){return setPositiveNumber(elem,value,extra?augmentWidthOrHeight(elem,name,extra,jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing")==="border-box"):0)}}});if(!jQuery.support.opacity){jQuery.cssHooks.opacity={get:function(elem,computed){return ropacity.test((computed&&elem.currentStyle?elem.currentStyle.filter:elem.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":computed?"1":""},set:function(elem,value){var style=elem.style,currentStyle=elem.currentStyle,opacity=jQuery.isNumeric(value)?"alpha(opacity="+value*100+")":"",filter=currentStyle&¤tStyle.filter||style.filter||"";style.zoom=1;if(value>=1&&jQuery.trim(filter.replace(ralpha,""))===""&&style.removeAttribute){style.removeAttribute("filter");if(currentStyle&&!currentStyle.filter){return}}style.filter=ralpha.test(filter)?filter.replace(ralpha,opacity):filter+" "+opacity}}}jQuery(function(){if(!jQuery.support.reliableMarginRight){jQuery.cssHooks.marginRight={get:function(elem,computed){return jQuery.swap(elem,{display:"inline-block"},function(){if(computed){return curCSS(elem,"marginRight")}})}}}if(!jQuery.support.pixelPosition&&jQuery.fn.position){jQuery.each(["top","left"],function(i,prop){jQuery.cssHooks[prop]={get:function(elem,computed){if(computed){var ret=curCSS(elem,prop);return rnumnonpx.test(ret)?jQuery(elem).position()[prop]+"px":ret}}}})}});if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.hidden=function(elem){return elem.offsetWidth===0&&elem.offsetHeight===0||!jQuery.support.reliableHiddenOffsets&&(elem.style&&elem.style.display||curCSS(elem,"display"))==="none"};jQuery.expr.filters.visible=function(elem){return!jQuery.expr.filters.hidden(elem)}}jQuery.each({margin:"",padding:"",border:"Width"},function(prefix,suffix){jQuery.cssHooks[prefix+suffix]={expand:function(value){var i,parts=typeof value==="string"?value.split(" "):[value],expanded={};for(i=0;i<4;i++){expanded[prefix+cssExpand[i]+suffix]=parts[i]||parts[i-2]||parts[0]}return expanded}};if(!rmargin.test(prefix)){jQuery.cssHooks[prefix+suffix].set=setPositiveNumber}});var r20=/%20/g,rbracket=/\[\]$/,rCRLF=/\r?\n/g,rinput=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,rselectTextarea=/^(?:select|textarea)/i;jQuery.fn.extend({serialize:function(){return jQuery.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?jQuery.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||rselectTextarea.test(this.nodeName)||rinput.test(this.type))}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:jQuery.isArray(val)?jQuery.map(val,function(val,i){return{name:elem.name,value:val.replace(rCRLF,"\r\n")}}):{name:elem.name,value:val.replace(rCRLF,"\r\n")}}).get()}});jQuery.param=function(a,traditional){var prefix,s=[],add=function(key,value){value=jQuery.isFunction(value)?value():value==null?"":value;s[s.length]=encodeURIComponent(key)+"="+encodeURIComponent(value)};if(traditional===undefined){traditional=jQuery.ajaxSettings&&jQuery.ajaxSettings.traditional}if(jQuery.isArray(a)||a.jquery&&!jQuery.isPlainObject(a)){jQuery.each(a,function(){add(this.name,this.value)})}else{for(prefix in a){buildParams(prefix,a[prefix],traditional,add)}}return s.join("&").replace(r20,"+")};function buildParams(prefix,obj,traditional,add){var name;if(jQuery.isArray(obj)){jQuery.each(obj,function(i,v){if(traditional||rbracket.test(prefix)){add(prefix,v)}else{buildParams(prefix+"["+(typeof v==="object"?i:"")+"]",v,traditional,add)}})}else if(!traditional&&jQuery.type(obj)==="object"){for(name in obj){buildParams(prefix+"["+name+"]",obj[name],traditional,add)}}else{add(prefix,obj)}}var ajaxLocParts,ajaxLocation,rhash=/#.*$/,rheaders=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,rlocalProtocol=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,rnoContent=/^(?:GET|HEAD)$/,rprotocol=/^\/\//,rquery=/\?/,rscript=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,rts=/([?&])_=[^&]*/,rurl=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,_load=jQuery.fn.load,prefilters={},transports={},allTypes=["*/"]+["*"];try{ajaxLocation=location.href}catch(e){ajaxLocation=document.createElement("a");ajaxLocation.href="";ajaxLocation=ajaxLocation.href}ajaxLocParts=rurl.exec(ajaxLocation.toLowerCase())||[];function addToPrefiltersOrTransports(structure){return function(dataTypeExpression,func){if(typeof dataTypeExpression!=="string"){func=dataTypeExpression;dataTypeExpression="*"}var dataType,list,placeBefore,dataTypes=dataTypeExpression.toLowerCase().split(core_rspace),i=0,length=dataTypes.length;if(jQuery.isFunction(func)){for(;i<length;i++){dataType=dataTypes[i];placeBefore=/^\+/.test(dataType);if(placeBefore){dataType=dataType.substr(1)||"*"}list=structure[dataType]=structure[dataType]||[];list[placeBefore?"unshift":"push"](func)}}}}function inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,dataType,inspected){dataType=dataType||options.dataTypes[0];inspected=inspected||{};inspected[dataType]=true;var selection,list=structure[dataType],i=0,length=list?list.length:0,executeOnly=structure===prefilters;for(;i<length&&(executeOnly||!selection);i++){selection=list[i](options,originalOptions,jqXHR);if(typeof selection==="string"){if(!executeOnly||inspected[selection]){selection=undefined}else{options.dataTypes.unshift(selection);selection=inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,selection,inspected)}}}if((executeOnly||!selection)&&!inspected["*"]){selection=inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,"*",inspected)}return selection}function ajaxExtend(target,src){var key,deep,flatOptions=jQuery.ajaxSettings.flatOptions||{};for(key in src){if(src[key]!==undefined){(flatOptions[key]?target:deep||(deep={}))[key]=src[key]}}if(deep){jQuery.extend(true,target,deep)}}jQuery.fn.load=function(url,params,callback){if(typeof url!=="string"&&_load){return _load.apply(this,arguments)}if(!this.length){return this}var selector,type,response,self=this,off=url.indexOf(" ");if(off>=0){selector=url.slice(off,url.length);url=url.slice(0,off)}if(jQuery.isFunction(params)){callback=params;params=undefined}else if(params&&typeof params==="object"){type="POST"}jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(jqXHR,status){if(callback){self.each(callback,response||[jqXHR.responseText,status,jqXHR])}}}).done(function(responseText){response=arguments;self.html(selector?jQuery("<div>").append(responseText.replace(rscript,"")).find(selector):responseText)});return this};jQuery.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(i,o){jQuery.fn[o]=function(f){return this.on(o,f)}});jQuery.each(["get","post"],function(i,method){jQuery[method]=function(url,data,callback,type){if(jQuery.isFunction(data)){type=type||callback;callback=data;data=undefined}return jQuery.ajax({type:method,url:url,data:data,success:callback,dataType:type})}});jQuery.extend({getScript:function(url,callback){return jQuery.get(url,undefined,callback,"script")},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json")},ajaxSetup:function(target,settings){if(settings){ajaxExtend(target,jQuery.ajaxSettings)}else{settings=target;target=jQuery.ajaxSettings}ajaxExtend(target,settings);return target},ajaxSettings:{url:ajaxLocation,isLocal:rlocalProtocol.test(ajaxLocParts[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":allTypes},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":window.String,"text html":true,"text json":jQuery.parseJSON,"text xml":jQuery.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:addToPrefiltersOrTransports(prefilters),ajaxTransport:addToPrefiltersOrTransports(transports),ajax:function(url,options){if(typeof url==="object"){options=url;url=undefined}options=options||{};var ifModifiedKey,responseHeadersString,responseHeaders,transport,timeoutTimer,parts,fireGlobals,i,s=jQuery.ajaxSetup({},options),callbackContext=s.context||s,globalEventContext=callbackContext!==s&&(callbackContext.nodeType||callbackContext instanceof jQuery)?jQuery(callbackContext):jQuery.event,deferred=jQuery.Deferred(),completeDeferred=jQuery.Callbacks("once memory"),statusCode=s.statusCode||{},requestHeaders={},requestHeadersNames={},state=0,strAbort="canceled",jqXHR={readyState:0,setRequestHeader:function(name,value){if(!state){var lname=name.toLowerCase();name=requestHeadersNames[lname]=requestHeadersNames[lname]||name;requestHeaders[name]=value}return this},getAllResponseHeaders:function(){return state===2?responseHeadersString:null},getResponseHeader:function(key){var match;if(state===2){if(!responseHeaders){responseHeaders={};while(match=rheaders.exec(responseHeadersString)){responseHeaders[match[1].toLowerCase()]=match[2]}}match=responseHeaders[key.toLowerCase()]}return match===undefined?null:match},overrideMimeType:function(type){if(!state){s.mimeType=type}return this},abort:function(statusText){statusText=statusText||strAbort;if(transport){transport.abort(statusText)}done(0,statusText);return this}};function done(status,nativeStatusText,responses,headers){var isSuccess,success,error,response,modified,statusText=nativeStatusText;if(state===2){return}state=2;if(timeoutTimer){clearTimeout(timeoutTimer)}transport=undefined;responseHeadersString=headers||"";jqXHR.readyState=status>0?4:0;if(responses){response=ajaxHandleResponses(s,jqXHR,responses)}if(status>=200&&status<300||status===304){if(s.ifModified){modified=jqXHR.getResponseHeader("Last-Modified");if(modified){jQuery.lastModified[ifModifiedKey]=modified}modified=jqXHR.getResponseHeader("Etag");if(modified){jQuery.etag[ifModifiedKey]=modified}}if(status===304){statusText="notmodified";isSuccess=true}else{isSuccess=ajaxConvert(s,response);statusText=isSuccess.state;success=isSuccess.data;error=isSuccess.error;isSuccess=!error}}else{error=statusText;if(!statusText||status){statusText="error";if(status<0){status=0}}}jqXHR.status=status;jqXHR.statusText=(nativeStatusText||statusText)+"";if(isSuccess){deferred.resolveWith(callbackContext,[success,statusText,jqXHR])}else{deferred.rejectWith(callbackContext,[jqXHR,statusText,error])}jqXHR.statusCode(statusCode);statusCode=undefined;if(fireGlobals){globalEventContext.trigger("ajax"+(isSuccess?"Success":"Error"),[jqXHR,s,isSuccess?success:error])}completeDeferred.fireWith(callbackContext,[jqXHR,statusText]);if(fireGlobals){globalEventContext.trigger("ajaxComplete",[jqXHR,s]);if(!--jQuery.active){jQuery.event.trigger("ajaxStop")}}}deferred.promise(jqXHR);jqXHR.success=jqXHR.done;jqXHR.error=jqXHR.fail;jqXHR.complete=completeDeferred.add;jqXHR.statusCode=function(map){if(map){var tmp;if(state<2){for(tmp in map){statusCode[tmp]=[statusCode[tmp],map[tmp]]}}else{tmp=map[jqXHR.status];jqXHR.always(tmp)}}return this};s.url=((url||s.url)+"").replace(rhash,"").replace(rprotocol,ajaxLocParts[1]+"//");s.dataTypes=jQuery.trim(s.dataType||"*").toLowerCase().split(core_rspace);if(s.crossDomain==null){parts=rurl.exec(s.url.toLowerCase());s.crossDomain=!!(parts&&(parts[1]!==ajaxLocParts[1]||parts[2]!==ajaxLocParts[2]||(parts[3]||(parts[1]==="http:"?80:443))!=(ajaxLocParts[3]||(ajaxLocParts[1]==="http:"?80:443))))}if(s.data&&s.processData&&typeof s.data!=="string"){s.data=jQuery.param(s.data,s.traditional)}inspectPrefiltersOrTransports(prefilters,s,options,jqXHR);if(state===2){return jqXHR}fireGlobals=s.global;s.type=s.type.toUpperCase();s.hasContent=!rnoContent.test(s.type);if(fireGlobals&&jQuery.active++===0){jQuery.event.trigger("ajaxStart")}if(!s.hasContent){if(s.data){s.url+=(rquery.test(s.url)?"&":"?")+s.data;delete s.data}ifModifiedKey=s.url;if(s.cache===false){var ts=jQuery.now(),ret=s.url.replace(rts,"$1_="+ts);s.url=ret+(ret===s.url?(rquery.test(s.url)?"&":"?")+"_="+ts:"")}}if(s.data&&s.hasContent&&s.contentType!==false||options.contentType){jqXHR.setRequestHeader("Content-Type",s.contentType)}if(s.ifModified){ifModifiedKey=ifModifiedKey||s.url;if(jQuery.lastModified[ifModifiedKey]){jqXHR.setRequestHeader("If-Modified-Since",jQuery.lastModified[ifModifiedKey])}if(jQuery.etag[ifModifiedKey]){jqXHR.setRequestHeader("If-None-Match",jQuery.etag[ifModifiedKey])}}jqXHR.setRequestHeader("Accept",s.dataTypes[0]&&s.accepts[s.dataTypes[0]]?s.accepts[s.dataTypes[0]]+(s.dataTypes[0]!=="*"?", "+allTypes+"; q=0.01":""):s.accepts["*"]);for(i in s.headers){jqXHR.setRequestHeader(i,s.headers[i])}if(s.beforeSend&&(s.beforeSend.call(callbackContext,jqXHR,s)===false||state===2)){return jqXHR.abort()}strAbort="abort";for(i in{success:1,error:1,complete:1}){jqXHR[i](s[i])}transport=inspectPrefiltersOrTransports(transports,s,options,jqXHR);if(!transport){done(-1,"No Transport")}else{jqXHR.readyState=1;if(fireGlobals){globalEventContext.trigger("ajaxSend",[jqXHR,s])}if(s.async&&s.timeout>0){timeoutTimer=setTimeout(function(){jqXHR.abort("timeout")},s.timeout)}try{state=1;transport.send(requestHeaders,done)}catch(e){if(state<2){done(-1,e)}else{throw e}}}return jqXHR},active:0,lastModified:{},etag:{}});function ajaxHandleResponses(s,jqXHR,responses){var ct,type,finalDataType,firstDataType,contents=s.contents,dataTypes=s.dataTypes,responseFields=s.responseFields;for(type in responseFields){if(type in responses){jqXHR[responseFields[type]]=responses[type]}}while(dataTypes[0]==="*"){dataTypes.shift();if(ct===undefined){ct=s.mimeType||jqXHR.getResponseHeader("content-type")}}if(ct){for(type in contents){if(contents[type]&&contents[type].test(ct)){dataTypes.unshift(type);break}}}if(dataTypes[0]in responses){finalDataType=dataTypes[0]}else{for(type in responses){if(!dataTypes[0]||s.converters[type+" "+dataTypes[0]]){finalDataType=type;break}if(!firstDataType){firstDataType=type}}finalDataType=finalDataType||firstDataType}if(finalDataType){if(finalDataType!==dataTypes[0]){dataTypes.unshift(finalDataType)}return responses[finalDataType]}}function ajaxConvert(s,response){var conv,conv2,current,tmp,dataTypes=s.dataTypes.slice(),prev=dataTypes[0],converters={},i=0;if(s.dataFilter){response=s.dataFilter(response,s.dataType)}if(dataTypes[1]){for(conv in s.converters){converters[conv.toLowerCase()]=s.converters[conv]}}for(;current=dataTypes[++i];){if(current!=="*"){if(prev!=="*"&&prev!==current){conv=converters[prev+" "+current]||converters["* "+current];if(!conv){for(conv2 in converters){tmp=conv2.split(" ");if(tmp[1]===current){conv=converters[prev+" "+tmp[0]]||converters["* "+tmp[0]];if(conv){if(conv===true){conv=converters[conv2]}else if(converters[conv2]!==true){current=tmp[0];dataTypes.splice(i--,0,current)}break}}}}if(conv!==true){if(conv&&s["throws"]){response=conv(response)}else{try{response=conv(response)}catch(e){return{state:"parsererror",error:conv?e:"No conversion from "+prev+" to "+current}}}}}prev=current}}return{state:"success",data:response}}var oldCallbacks=[],rquestion=/\?/,rjsonp=/(=)\?(?=&|$)|\?\?/,nonce=jQuery.now();jQuery.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var callback=oldCallbacks.pop()||jQuery.expando+"_"+nonce++;this[callback]=true;return callback}});jQuery.ajaxPrefilter("json jsonp",function(s,originalSettings,jqXHR){var callbackName,overwritten,responseContainer,data=s.data,url=s.url,hasCallback=s.jsonp!==false,replaceInUrl=hasCallback&&rjsonp.test(url),replaceInData=hasCallback&&!replaceInUrl&&typeof data==="string"&&!(s.contentType||"").indexOf("application/x-www-form-urlencoded")&&rjsonp.test(data);if(s.dataTypes[0]==="jsonp"||replaceInUrl||replaceInData){callbackName=s.jsonpCallback=jQuery.isFunction(s.jsonpCallback)?s.jsonpCallback():s.jsonpCallback;overwritten=window[callbackName];if(replaceInUrl){s.url=url.replace(rjsonp,"$1"+callbackName)}else if(replaceInData){s.data=data.replace(rjsonp,"$1"+callbackName)}else if(hasCallback){s.url+=(rquestion.test(url)?"&":"?")+s.jsonp+"="+callbackName}s.converters["script json"]=function(){if(!responseContainer){jQuery.error(callbackName+" was not called")}return responseContainer[0]};s.dataTypes[0]="json";window[callbackName]=function(){responseContainer=arguments};jqXHR.always(function(){window[callbackName]=overwritten;if(s[callbackName]){s.jsonpCallback=originalSettings.jsonpCallback;oldCallbacks.push(callbackName)}if(responseContainer&&jQuery.isFunction(overwritten)){overwritten(responseContainer[0])}responseContainer=overwritten=undefined});return"script"}});jQuery.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(text){jQuery.globalEval(text);return text}}});jQuery.ajaxPrefilter("script",function(s){if(s.cache===undefined){s.cache=false}if(s.crossDomain){s.type="GET";s.global=false}});jQuery.ajaxTransport("script",function(s){if(s.crossDomain){var script,head=document.head||document.getElementsByTagName("head")[0]||document.documentElement;return{send:function(_,callback){script=document.createElement("script");script.async="async";if(s.scriptCharset){script.charset=s.scriptCharset}script.src=s.url;script.onload=script.onreadystatechange=function(_,isAbort){if(isAbort||!script.readyState||/loaded|complete/.test(script.readyState)){script.onload=script.onreadystatechange=null;if(head&&script.parentNode){head.removeChild(script)}script=undefined;if(!isAbort){callback(200,"success")}}};head.insertBefore(script,head.firstChild)},abort:function(){if(script){script.onload(0,1)}}}}});var xhrCallbacks,xhrOnUnloadAbort=window.ActiveXObject?function(){for(var key in xhrCallbacks){xhrCallbacks[key](0,1)}}:false,xhrId=0;function createStandardXHR(){try{return new window.XMLHttpRequest}catch(e){}}function createActiveXHR(){try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(e){}}jQuery.ajaxSettings.xhr=window.ActiveXObject?function(){return!this.isLocal&&createStandardXHR()||createActiveXHR()}:createStandardXHR;(function(xhr){jQuery.extend(jQuery.support,{ajax:!!xhr,cors:!!xhr&&"withCredentials"in xhr})})(jQuery.ajaxSettings.xhr());if(jQuery.support.ajax){jQuery.ajaxTransport(function(s){if(!s.crossDomain||jQuery.support.cors){var callback;return{send:function(headers,complete){var handle,i,xhr=s.xhr();if(s.username){xhr.open(s.type,s.url,s.async,s.username,s.password)}else{xhr.open(s.type,s.url,s.async)}if(s.xhrFields){for(i in s.xhrFields){xhr[i]=s.xhrFields[i]}}if(s.mimeType&&xhr.overrideMimeType){xhr.overrideMimeType(s.mimeType)}if(!s.crossDomain&&!headers["X-Requested-With"]){headers["X-Requested-With"]="XMLHttpRequest"}try{for(i in headers){xhr.setRequestHeader(i,headers[i])}}catch(_){}xhr.send(s.hasContent&&s.data||null);callback=function(_,isAbort){var status,statusText,responseHeaders,responses,xml;try{if(callback&&(isAbort||xhr.readyState===4)){callback=undefined;if(handle){xhr.onreadystatechange=jQuery.noop;if(xhrOnUnloadAbort){delete xhrCallbacks[handle]}}if(isAbort){if(xhr.readyState!==4){xhr.abort()}}else{status=xhr.status;responseHeaders=xhr.getAllResponseHeaders();responses={};xml=xhr.responseXML;if(xml&&xml.documentElement){responses.xml=xml}try{responses.text=xhr.responseText}catch(e){}try{statusText=xhr.statusText}catch(e){statusText=""}if(!status&&s.isLocal&&!s.crossDomain){status=responses.text?200:404}else if(status===1223){status=204}}}}catch(firefoxAccessException){if(!isAbort){complete(-1,firefoxAccessException)}}if(responses){complete(status,statusText,responses,responseHeaders)}};if(!s.async){callback()}else if(xhr.readyState===4){setTimeout(callback,0)}else{handle=++xhrId;if(xhrOnUnloadAbort){if(!xhrCallbacks){xhrCallbacks={};jQuery(window).unload(xhrOnUnloadAbort)}xhrCallbacks[handle]=callback}xhr.onreadystatechange=callback}},abort:function(){if(callback){callback(0,1)}}}}})}var fxNow,timerId,rfxtypes=/^(?:toggle|show|hide)$/,rfxnum=new RegExp("^(?:([-+])=|)("+core_pnum+")([a-z%]*)$","i"),rrun=/queueHooks$/,animationPrefilters=[defaultPrefilter],tweeners={"*":[function(prop,value){var end,unit,tween=this.createTween(prop,value),parts=rfxnum.exec(value),target=tween.cur(),start=+target||0,scale=1,maxIterations=20;if(parts){end=+parts[2];unit=parts[3]||(jQuery.cssNumber[prop]?"":"px");if(unit!=="px"&&start){start=jQuery.css(tween.elem,prop,true)||end||1;do{scale=scale||".5";start=start/scale;jQuery.style(tween.elem,prop,start+unit)}while(scale!==(scale=tween.cur()/target)&&scale!==1&&--maxIterations)}tween.unit=unit;tween.start=start;tween.end=parts[1]?start+(parts[1]+1)*end:end}return tween}]};function createFxNow(){setTimeout(function(){fxNow=undefined},0);return fxNow=jQuery.now()}function createTweens(animation,props){jQuery.each(props,function(prop,value){var collection=(tweeners[prop]||[]).concat(tweeners["*"]),index=0,length=collection.length;for(;index<length;index++){if(collection[index].call(animation,prop,value)){return}}})}function Animation(elem,properties,options){var result,index=0,tweenerIndex=0,length=animationPrefilters.length,deferred=jQuery.Deferred().always(function(){delete tick.elem}),tick=function(){var currentTime=fxNow||createFxNow(),remaining=Math.max(0,animation.startTime+animation.duration-currentTime),temp=remaining/animation.duration||0,percent=1-temp,index=0,length=animation.tweens.length; +for(;index<length;index++){animation.tweens[index].run(percent)}deferred.notifyWith(elem,[animation,percent,remaining]);if(percent<1&&length){return remaining}else{deferred.resolveWith(elem,[animation]);return false}},animation=deferred.promise({elem:elem,props:jQuery.extend({},properties),opts:jQuery.extend(true,{specialEasing:{}},options),originalProperties:properties,originalOptions:options,startTime:fxNow||createFxNow(),duration:options.duration,tweens:[],createTween:function(prop,end,easing){var tween=jQuery.Tween(elem,animation.opts,prop,end,animation.opts.specialEasing[prop]||animation.opts.easing);animation.tweens.push(tween);return tween},stop:function(gotoEnd){var index=0,length=gotoEnd?animation.tweens.length:0;for(;index<length;index++){animation.tweens[index].run(1)}if(gotoEnd){deferred.resolveWith(elem,[animation,gotoEnd])}else{deferred.rejectWith(elem,[animation,gotoEnd])}return this}}),props=animation.props;propFilter(props,animation.opts.specialEasing);for(;index<length;index++){result=animationPrefilters[index].call(animation,elem,props,animation.opts);if(result){return result}}createTweens(animation,props);if(jQuery.isFunction(animation.opts.start)){animation.opts.start.call(elem,animation)}jQuery.fx.timer(jQuery.extend(tick,{anim:animation,queue:animation.opts.queue,elem:elem}));return animation.progress(animation.opts.progress).done(animation.opts.done,animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always)}function propFilter(props,specialEasing){var index,name,easing,value,hooks;for(index in props){name=jQuery.camelCase(index);easing=specialEasing[name];value=props[index];if(jQuery.isArray(value)){easing=value[1];value=props[index]=value[0]}if(index!==name){props[name]=value;delete props[index]}hooks=jQuery.cssHooks[name];if(hooks&&"expand"in hooks){value=hooks.expand(value);delete props[name];for(index in value){if(!(index in props)){props[index]=value[index];specialEasing[index]=easing}}}else{specialEasing[name]=easing}}}jQuery.Animation=jQuery.extend(Animation,{tweener:function(props,callback){if(jQuery.isFunction(props)){callback=props;props=["*"]}else{props=props.split(" ")}var prop,index=0,length=props.length;for(;index<length;index++){prop=props[index];tweeners[prop]=tweeners[prop]||[];tweeners[prop].unshift(callback)}},prefilter:function(callback,prepend){if(prepend){animationPrefilters.unshift(callback)}else{animationPrefilters.push(callback)}}});function defaultPrefilter(elem,props,opts){var index,prop,value,length,dataShow,toggle,tween,hooks,oldfire,anim=this,style=elem.style,orig={},handled=[],hidden=elem.nodeType&&isHidden(elem);if(!opts.queue){hooks=jQuery._queueHooks(elem,"fx");if(hooks.unqueued==null){hooks.unqueued=0;oldfire=hooks.empty.fire;hooks.empty.fire=function(){if(!hooks.unqueued){oldfire()}}}hooks.unqueued++;anim.always(function(){anim.always(function(){hooks.unqueued--;if(!jQuery.queue(elem,"fx").length){hooks.empty.fire()}})})}if(elem.nodeType===1&&("height"in props||"width"in props)){opts.overflow=[style.overflow,style.overflowX,style.overflowY];if(jQuery.css(elem,"display")==="inline"&&jQuery.css(elem,"float")==="none"){if(!jQuery.support.inlineBlockNeedsLayout||css_defaultDisplay(elem.nodeName)==="inline"){style.display="inline-block"}else{style.zoom=1}}}if(opts.overflow){style.overflow="hidden";if(!jQuery.support.shrinkWrapBlocks){anim.done(function(){style.overflow=opts.overflow[0];style.overflowX=opts.overflow[1];style.overflowY=opts.overflow[2]})}}for(index in props){value=props[index];if(rfxtypes.exec(value)){delete props[index];toggle=toggle||value==="toggle";if(value===(hidden?"hide":"show")){continue}handled.push(index)}}length=handled.length;if(length){dataShow=jQuery._data(elem,"fxshow")||jQuery._data(elem,"fxshow",{});if("hidden"in dataShow){hidden=dataShow.hidden}if(toggle){dataShow.hidden=!hidden}if(hidden){jQuery(elem).show()}else{anim.done(function(){jQuery(elem).hide()})}anim.done(function(){var prop;jQuery.removeData(elem,"fxshow",true);for(prop in orig){jQuery.style(elem,prop,orig[prop])}});for(index=0;index<length;index++){prop=handled[index];tween=anim.createTween(prop,hidden?dataShow[prop]:0);orig[prop]=dataShow[prop]||jQuery.style(elem,prop);if(!(prop in dataShow)){dataShow[prop]=tween.start;if(hidden){tween.end=tween.start;tween.start=prop==="width"||prop==="height"?1:0}}}}}function Tween(elem,options,prop,end,easing){return new Tween.prototype.init(elem,options,prop,end,easing)}jQuery.Tween=Tween;Tween.prototype={constructor:Tween,init:function(elem,options,prop,end,easing,unit){this.elem=elem;this.prop=prop;this.easing=easing||"swing";this.options=options;this.start=this.now=this.cur();this.end=end;this.unit=unit||(jQuery.cssNumber[prop]?"":"px")},cur:function(){var hooks=Tween.propHooks[this.prop];return hooks&&hooks.get?hooks.get(this):Tween.propHooks._default.get(this)},run:function(percent){var eased,hooks=Tween.propHooks[this.prop];if(this.options.duration){this.pos=eased=jQuery.easing[this.easing](percent,this.options.duration*percent,0,1,this.options.duration)}else{this.pos=eased=percent}this.now=(this.end-this.start)*eased+this.start;if(this.options.step){this.options.step.call(this.elem,this.now,this)}if(hooks&&hooks.set){hooks.set(this)}else{Tween.propHooks._default.set(this)}return this}};Tween.prototype.init.prototype=Tween.prototype;Tween.propHooks={_default:{get:function(tween){var result;if(tween.elem[tween.prop]!=null&&(!tween.elem.style||tween.elem.style[tween.prop]==null)){return tween.elem[tween.prop]}result=jQuery.css(tween.elem,tween.prop,false,"");return!result||result==="auto"?0:result},set:function(tween){if(jQuery.fx.step[tween.prop]){jQuery.fx.step[tween.prop](tween)}else if(tween.elem.style&&(tween.elem.style[jQuery.cssProps[tween.prop]]!=null||jQuery.cssHooks[tween.prop])){jQuery.style(tween.elem,tween.prop,tween.now+tween.unit)}else{tween.elem[tween.prop]=tween.now}}}};Tween.propHooks.scrollTop=Tween.propHooks.scrollLeft={set:function(tween){if(tween.elem.nodeType&&tween.elem.parentNode){tween.elem[tween.prop]=tween.now}}};jQuery.each(["toggle","show","hide"],function(i,name){var cssFn=jQuery.fn[name];jQuery.fn[name]=function(speed,easing,callback){return speed==null||typeof speed==="boolean"||!i&&jQuery.isFunction(speed)&&jQuery.isFunction(easing)?cssFn.apply(this,arguments):this.animate(genFx(name,true),speed,easing,callback)}});jQuery.fn.extend({fadeTo:function(speed,to,easing,callback){return this.filter(isHidden).css("opacity",0).show().end().animate({opacity:to},speed,easing,callback)},animate:function(prop,speed,easing,callback){var empty=jQuery.isEmptyObject(prop),optall=jQuery.speed(speed,easing,callback),doAnimation=function(){var anim=Animation(this,jQuery.extend({},prop),optall);if(empty){anim.stop(true)}};return empty||optall.queue===false?this.each(doAnimation):this.queue(optall.queue,doAnimation)},stop:function(type,clearQueue,gotoEnd){var stopQueue=function(hooks){var stop=hooks.stop;delete hooks.stop;stop(gotoEnd)};if(typeof type!=="string"){gotoEnd=clearQueue;clearQueue=type;type=undefined}if(clearQueue&&type!==false){this.queue(type||"fx",[])}return this.each(function(){var dequeue=true,index=type!=null&&type+"queueHooks",timers=jQuery.timers,data=jQuery._data(this);if(index){if(data[index]&&data[index].stop){stopQueue(data[index])}}else{for(index in data){if(data[index]&&data[index].stop&&rrun.test(index)){stopQueue(data[index])}}}for(index=timers.length;index--;){if(timers[index].elem===this&&(type==null||timers[index].queue===type)){timers[index].anim.stop(gotoEnd);dequeue=false;timers.splice(index,1)}}if(dequeue||!gotoEnd){jQuery.dequeue(this,type)}})}});function genFx(type,includeWidth){var which,attrs={height:type},i=0;includeWidth=includeWidth?1:0;for(;i<4;i+=2-includeWidth){which=cssExpand[i];attrs["margin"+which]=attrs["padding"+which]=type}if(includeWidth){attrs.opacity=attrs.width=type}return attrs}jQuery.each({slideDown:genFx("show"),slideUp:genFx("hide"),slideToggle:genFx("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(name,props){jQuery.fn[name]=function(speed,easing,callback){return this.animate(props,speed,easing,callback)}});jQuery.speed=function(speed,easing,fn){var opt=speed&&typeof speed==="object"?jQuery.extend({},speed):{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&!jQuery.isFunction(easing)&&easing};opt.duration=jQuery.fx.off?0:typeof opt.duration==="number"?opt.duration:opt.duration in jQuery.fx.speeds?jQuery.fx.speeds[opt.duration]:jQuery.fx.speeds._default;if(opt.queue==null||opt.queue===true){opt.queue="fx"}opt.old=opt.complete;opt.complete=function(){if(jQuery.isFunction(opt.old)){opt.old.call(this)}if(opt.queue){jQuery.dequeue(this,opt.queue)}};return opt};jQuery.easing={linear:function(p){return p},swing:function(p){return.5-Math.cos(p*Math.PI)/2}};jQuery.timers=[];jQuery.fx=Tween.prototype.init;jQuery.fx.tick=function(){var timer,timers=jQuery.timers,i=0;fxNow=jQuery.now();for(;i<timers.length;i++){timer=timers[i];if(!timer()&&timers[i]===timer){timers.splice(i--,1)}}if(!timers.length){jQuery.fx.stop()}fxNow=undefined};jQuery.fx.timer=function(timer){if(timer()&&jQuery.timers.push(timer)&&!timerId){timerId=setInterval(jQuery.fx.tick,jQuery.fx.interval)}};jQuery.fx.interval=13;jQuery.fx.stop=function(){clearInterval(timerId);timerId=null};jQuery.fx.speeds={slow:600,fast:200,_default:400};jQuery.fx.step={};if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.animated=function(elem){return jQuery.grep(jQuery.timers,function(fn){return elem===fn.elem}).length}}var rroot=/^(?:body|html)$/i;jQuery.fn.offset=function(options){if(arguments.length){return options===undefined?this:this.each(function(i){jQuery.offset.setOffset(this,options,i)})}var docElem,body,win,clientTop,clientLeft,scrollTop,scrollLeft,box={top:0,left:0},elem=this[0],doc=elem&&elem.ownerDocument;if(!doc){return}if((body=doc.body)===elem){return jQuery.offset.bodyOffset(elem)}docElem=doc.documentElement;if(!jQuery.contains(docElem,elem)){return box}if(typeof elem.getBoundingClientRect!=="undefined"){box=elem.getBoundingClientRect()}win=getWindow(doc);clientTop=docElem.clientTop||body.clientTop||0;clientLeft=docElem.clientLeft||body.clientLeft||0;scrollTop=win.pageYOffset||docElem.scrollTop;scrollLeft=win.pageXOffset||docElem.scrollLeft;return{top:box.top+scrollTop-clientTop,left:box.left+scrollLeft-clientLeft}};jQuery.offset={bodyOffset:function(body){var top=body.offsetTop,left=body.offsetLeft;if(jQuery.support.doesNotIncludeMarginInBodyOffset){top+=parseFloat(jQuery.css(body,"marginTop"))||0;left+=parseFloat(jQuery.css(body,"marginLeft"))||0}return{top:top,left:left}},setOffset:function(elem,options,i){var position=jQuery.css(elem,"position");if(position==="static"){elem.style.position="relative"}var curElem=jQuery(elem),curOffset=curElem.offset(),curCSSTop=jQuery.css(elem,"top"),curCSSLeft=jQuery.css(elem,"left"),calculatePosition=(position==="absolute"||position==="fixed")&&jQuery.inArray("auto",[curCSSTop,curCSSLeft])>-1,props={},curPosition={},curTop,curLeft;if(calculatePosition){curPosition=curElem.position();curTop=curPosition.top;curLeft=curPosition.left}else{curTop=parseFloat(curCSSTop)||0;curLeft=parseFloat(curCSSLeft)||0}if(jQuery.isFunction(options)){options=options.call(elem,i,curOffset)}if(options.top!=null){props.top=options.top-curOffset.top+curTop}if(options.left!=null){props.left=options.left-curOffset.left+curLeft}if("using"in options){options.using.call(elem,props)}else{curElem.css(props)}}};jQuery.fn.extend({position:function(){if(!this[0]){return}var elem=this[0],offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=rroot.test(offsetParent[0].nodeName)?{top:0,left:0}:offsetParent.offset();offset.top-=parseFloat(jQuery.css(elem,"marginTop"))||0;offset.left-=parseFloat(jQuery.css(elem,"marginLeft"))||0;parentOffset.top+=parseFloat(jQuery.css(offsetParent[0],"borderTopWidth"))||0;parentOffset.left+=parseFloat(jQuery.css(offsetParent[0],"borderLeftWidth"))||0;return{top:offset.top-parentOffset.top,left:offset.left-parentOffset.left}},offsetParent:function(){return this.map(function(){var offsetParent=this.offsetParent||document.body;while(offsetParent&&(!rroot.test(offsetParent.nodeName)&&jQuery.css(offsetParent,"position")==="static")){offsetParent=offsetParent.offsetParent}return offsetParent||document.body})}});jQuery.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(method,prop){var top=/Y/.test(prop);jQuery.fn[method]=function(val){return jQuery.access(this,function(elem,method,val){var win=getWindow(elem);if(val===undefined){return win?prop in win?win[prop]:win.document.documentElement[method]:elem[method]}if(win){win.scrollTo(!top?val:jQuery(win).scrollLeft(),top?val:jQuery(win).scrollTop())}else{elem[method]=val}},method,val,arguments.length,null)}});function getWindow(elem){return jQuery.isWindow(elem)?elem:elem.nodeType===9?elem.defaultView||elem.parentWindow:false}jQuery.each({Height:"height",Width:"width"},function(name,type){jQuery.each({padding:"inner"+name,content:type,"":"outer"+name},function(defaultExtra,funcName){jQuery.fn[funcName]=function(margin,value){var chainable=arguments.length&&(defaultExtra||typeof margin!=="boolean"),extra=defaultExtra||(margin===true||value===true?"margin":"border");return jQuery.access(this,function(elem,type,value){var doc;if(jQuery.isWindow(elem)){return elem.document.documentElement["client"+name]}if(elem.nodeType===9){doc=elem.documentElement;return Math.max(elem.body["scroll"+name],doc["scroll"+name],elem.body["offset"+name],doc["offset"+name],doc["client"+name])}return value===undefined?jQuery.css(elem,type,value,extra):jQuery.style(elem,type,value,extra)},type,chainable?margin:undefined,chainable,null)}})});window.jQuery=window.$=jQuery;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return jQuery})}})(window);
\ No newline at end of file diff --git a/library/cpp/lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js b/library/cpp/lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js index ac4a835205..8346d9d2f1 100644 --- a/library/cpp/lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js +++ b/library/cpp/lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js @@ -1,4 +1,4 @@ -$.extend($.fn.treegrid.defaults, { - expanderExpandedClass: 'glyphicon glyphicon-chevron-down', - expanderCollapsedClass: 'glyphicon glyphicon-chevron-right' -}); +$.extend($.fn.treegrid.defaults, { + expanderExpandedClass: 'glyphicon glyphicon-chevron-down', + expanderCollapsedClass: 'glyphicon glyphicon-chevron-right' +}); diff --git a/library/cpp/lwtrace/mon/static/js/jquery.treegrid.min.js b/library/cpp/lwtrace/mon/static/js/jquery.treegrid.min.js index 7b7566f323..345038c5ed 100644 --- a/library/cpp/lwtrace/mon/static/js/jquery.treegrid.min.js +++ b/library/cpp/lwtrace/mon/static/js/jquery.treegrid.min.js @@ -1,2 +1,2 @@ -/*! jquery-treegrid 0.3.0 */ -!function(a){var b={initTree:function(b){var c=a.extend({},this.treegrid.defaults,b);return this.each(function(){var b=a(this);b.treegrid("setTreeContainer",a(this)),b.treegrid("setSettings",c),c.getRootNodes.apply(this,[a(this)]).treegrid("initNode",c),b.treegrid("getRootNodes").treegrid("render")})},initNode:function(b){return this.each(function(){var c=a(this);c.treegrid("setTreeContainer",b.getTreeGridContainer.apply(this)),c.treegrid("getChildNodes").treegrid("initNode",b),c.treegrid("initExpander").treegrid("initIndent").treegrid("initEvents").treegrid("initState").treegrid("initChangeEvent").treegrid("initSettingsEvents")})},initChangeEvent:function(){var b=a(this);return b.on("change",function(){var b=a(this);b.treegrid("render"),b.treegrid("getSetting","saveState")&&b.treegrid("saveState")}),b},initEvents:function(){var b=a(this);return b.on("collapse",function(){var b=a(this);b.removeClass("treegrid-expanded"),b.addClass("treegrid-collapsed")}),b.on("expand",function(){var b=a(this);b.removeClass("treegrid-collapsed"),b.addClass("treegrid-expanded")}),b},initSettingsEvents:function(){var b=a(this);return b.on("change",function(){var b=a(this);"function"==typeof b.treegrid("getSetting","onChange")&&b.treegrid("getSetting","onChange").apply(b)}),b.on("collapse",function(){var b=a(this);"function"==typeof b.treegrid("getSetting","onCollapse")&&b.treegrid("getSetting","onCollapse").apply(b)}),b.on("expand",function(){var b=a(this);"function"==typeof b.treegrid("getSetting","onExpand")&&b.treegrid("getSetting","onExpand").apply(b)}),b},initExpander:function(){var b=a(this),c=b.find("td").get(b.treegrid("getSetting","treeColumn")),d=b.treegrid("getSetting","expanderTemplate"),e=b.treegrid("getSetting","getExpander").apply(this);return e&&e.remove(),a(d).prependTo(c).click(function(){a(a(this).closest("tr")).treegrid("toggle")}),b},initIndent:function(){var b=a(this);b.find(".treegrid-indent").remove();for(var c=b.treegrid("getSetting","indentTemplate"),d=b.find(".treegrid-expander"),e=b.treegrid("getDepth"),f=0;e>f;f++)a(c).insertBefore(d);return b},initState:function(){var b=a(this);return b.treegrid(b.treegrid("getSetting","saveState")&&!b.treegrid("isFirstInit")?"restoreState":"expanded"===b.treegrid("getSetting","initialState")?"expand":"collapse"),b},isFirstInit:function(){var b=a(this).treegrid("getTreeContainer");return void 0===b.data("first_init")&&b.data("first_init",void 0===a.cookie(b.treegrid("getSetting","saveStateName"))),b.data("first_init")},saveState:function(){var b=a(this);if("cookie"===b.treegrid("getSetting","saveStateMethod")){var c=a.cookie(b.treegrid("getSetting","saveStateName"))||"",d=""===c?[]:c.split(","),e=b.treegrid("getNodeId");b.treegrid("isExpanded")?-1===a.inArray(e,d)&&d.push(e):b.treegrid("isCollapsed")&&-1!==a.inArray(e,d)&&d.splice(a.inArray(e,d),1),a.cookie(b.treegrid("getSetting","saveStateName"),d.join(","))}return b},restoreState:function(){var b=a(this);if("cookie"===b.treegrid("getSetting","saveStateMethod")){var c=a.cookie(b.treegrid("getSetting","saveStateName")).split(",");b.treegrid(-1!==a.inArray(b.treegrid("getNodeId"),c)?"expand":"collapse")}return b},getSetting:function(b){return a(this).treegrid("getTreeContainer")?a(this).treegrid("getTreeContainer").data("settings")[b]:null},setSettings:function(b){a(this).treegrid("getTreeContainer").data("settings",b)},getTreeContainer:function(){return a(this).data("treegrid")},setTreeContainer:function(b){return a(this).data("treegrid",b)},getRootNodes:function(){return a(this).treegrid("getSetting","getRootNodes").apply(this,[a(this).treegrid("getTreeContainer")])},getAllNodes:function(){return a(this).treegrid("getSetting","getAllNodes").apply(this,[a(this).treegrid("getTreeContainer")])},isNode:function(){return null!==a(this).treegrid("getNodeId")},getNodeId:function(){return null===a(this).treegrid("getSetting","getNodeId")?null:a(this).treegrid("getSetting","getNodeId").apply(this)},getParentNodeId:function(){return a(this).treegrid("getSetting","getParentNodeId").apply(this)},getParentNode:function(){return null===a(this).treegrid("getParentNodeId")?null:a(this).treegrid("getSetting","getNodeById").apply(this,[a(this).treegrid("getParentNodeId"),a(this).treegrid("getTreeContainer")])},getChildNodes:function(){return a(this).treegrid("getSetting","getChildNodes").apply(this,[a(this).treegrid("getNodeId"),a(this).treegrid("getTreeContainer")])},getDepth:function(){return null===a(this).treegrid("getParentNode")?0:a(this).treegrid("getParentNode").treegrid("getDepth")+1},isRoot:function(){return 0===a(this).treegrid("getDepth")},isLeaf:function(){return 0===a(this).treegrid("getChildNodes").length},isLast:function(){if(a(this).treegrid("isNode")){var b=a(this).treegrid("getParentNode");if(null===b){if(a(this).treegrid("getNodeId")===a(this).treegrid("getRootNodes").last().treegrid("getNodeId"))return!0}else if(a(this).treegrid("getNodeId")===b.treegrid("getChildNodes").last().treegrid("getNodeId"))return!0}return!1},isFirst:function(){if(a(this).treegrid("isNode")){var b=a(this).treegrid("getParentNode");if(null===b){if(a(this).treegrid("getNodeId")===a(this).treegrid("getRootNodes").first().treegrid("getNodeId"))return!0}else if(a(this).treegrid("getNodeId")===b.treegrid("getChildNodes").first().treegrid("getNodeId"))return!0}return!1},isExpanded:function(){return a(this).hasClass("treegrid-expanded")},isCollapsed:function(){return a(this).hasClass("treegrid-collapsed")},isOneOfParentsCollapsed:function(){var b=a(this);return b.treegrid("isRoot")?!1:b.treegrid("getParentNode").treegrid("isCollapsed")?!0:b.treegrid("getParentNode").treegrid("isOneOfParentsCollapsed")},expand:function(){return this.treegrid("isLeaf")||this.treegrid("isExpanded")?this:(this.trigger("expand"),this.trigger("change"),this)},expandAll:function(){var b=a(this);return b.treegrid("getRootNodes").treegrid("expandRecursive"),b},expandRecursive:function(){return a(this).each(function(){var b=a(this);b.treegrid("expand"),b.treegrid("isLeaf")||b.treegrid("getChildNodes").treegrid("expandRecursive")})},collapse:function(){return a(this).each(function(){var b=a(this);b.treegrid("isLeaf")||b.treegrid("isCollapsed")||(b.trigger("collapse"),b.trigger("change"))})},collapseAll:function(){var b=a(this);return b.treegrid("getRootNodes").treegrid("collapseRecursive"),b},collapseRecursive:function(){return a(this).each(function(){var b=a(this);b.treegrid("collapse"),b.treegrid("isLeaf")||b.treegrid("getChildNodes").treegrid("collapseRecursive")})},toggle:function(){var b=a(this);return b.treegrid(b.treegrid("isExpanded")?"collapse":"expand"),b},render:function(){return a(this).each(function(){var b=a(this);b.treegrid("isOneOfParentsCollapsed")?b.hide():b.show(),b.treegrid("isLeaf")||(b.treegrid("renderExpander"),b.treegrid("getChildNodes").treegrid("render"))})},renderExpander:function(){return a(this).each(function(){var b=a(this),c=b.treegrid("getSetting","getExpander").apply(this);c?b.treegrid("isCollapsed")?(c.removeClass(b.treegrid("getSetting","expanderExpandedClass")),c.addClass(b.treegrid("getSetting","expanderCollapsedClass"))):(c.removeClass(b.treegrid("getSetting","expanderCollapsedClass")),c.addClass(b.treegrid("getSetting","expanderExpandedClass"))):(b.treegrid("initExpander"),b.treegrid("renderExpander"))})}};a.fn.treegrid=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method with name "+c+" does not exists for jQuery.treegrid"):b.initTree.apply(this,arguments)},a.fn.treegrid.defaults={initialState:"expanded",saveState:!1,saveStateMethod:"cookie",saveStateName:"tree-grid-state",expanderTemplate:'<span class="treegrid-expander"></span>',indentTemplate:'<span class="treegrid-indent"></span>',expanderExpandedClass:"treegrid-expander-expanded",expanderCollapsedClass:"treegrid-expander-collapsed",treeColumn:0,getExpander:function(){return a(this).find(".treegrid-expander")},getNodeId:function(){var b=/treegrid-([A-Za-z0-9_-]+)/;return b.test(a(this).attr("class"))?b.exec(a(this).attr("class"))[1]:null},getParentNodeId:function(){var b=/treegrid-parent-([A-Za-z0-9_-]+)/;return b.test(a(this).attr("class"))?b.exec(a(this).attr("class"))[1]:null},getNodeById:function(a,b){var c="treegrid-"+a;return b.find("tr."+c)},getChildNodes:function(a,b){var c="treegrid-parent-"+a;return b.find("tr."+c)},getTreeGridContainer:function(){return a(this).closest("table")},getRootNodes:function(b){var c=a.grep(b.find("tr"),function(b){var c=a(b).attr("class"),d=/treegrid-([A-Za-z0-9_-]+)/,e=/treegrid-parent-([A-Za-z0-9_-]+)/;return d.test(c)&&!e.test(c)});return a(c)},getAllNodes:function(b){var c=a.grep(b.find("tr"),function(b){var c=a(b).attr("class"),d=/treegrid-([A-Za-z0-9_-]+)/;return d.test(c)});return a(c)},onCollapse:null,onExpand:null,onChange:null}}(jQuery);
\ No newline at end of file +/*! jquery-treegrid 0.3.0 */ +!function(a){var b={initTree:function(b){var c=a.extend({},this.treegrid.defaults,b);return this.each(function(){var b=a(this);b.treegrid("setTreeContainer",a(this)),b.treegrid("setSettings",c),c.getRootNodes.apply(this,[a(this)]).treegrid("initNode",c),b.treegrid("getRootNodes").treegrid("render")})},initNode:function(b){return this.each(function(){var c=a(this);c.treegrid("setTreeContainer",b.getTreeGridContainer.apply(this)),c.treegrid("getChildNodes").treegrid("initNode",b),c.treegrid("initExpander").treegrid("initIndent").treegrid("initEvents").treegrid("initState").treegrid("initChangeEvent").treegrid("initSettingsEvents")})},initChangeEvent:function(){var b=a(this);return b.on("change",function(){var b=a(this);b.treegrid("render"),b.treegrid("getSetting","saveState")&&b.treegrid("saveState")}),b},initEvents:function(){var b=a(this);return b.on("collapse",function(){var b=a(this);b.removeClass("treegrid-expanded"),b.addClass("treegrid-collapsed")}),b.on("expand",function(){var b=a(this);b.removeClass("treegrid-collapsed"),b.addClass("treegrid-expanded")}),b},initSettingsEvents:function(){var b=a(this);return b.on("change",function(){var b=a(this);"function"==typeof b.treegrid("getSetting","onChange")&&b.treegrid("getSetting","onChange").apply(b)}),b.on("collapse",function(){var b=a(this);"function"==typeof b.treegrid("getSetting","onCollapse")&&b.treegrid("getSetting","onCollapse").apply(b)}),b.on("expand",function(){var b=a(this);"function"==typeof b.treegrid("getSetting","onExpand")&&b.treegrid("getSetting","onExpand").apply(b)}),b},initExpander:function(){var b=a(this),c=b.find("td").get(b.treegrid("getSetting","treeColumn")),d=b.treegrid("getSetting","expanderTemplate"),e=b.treegrid("getSetting","getExpander").apply(this);return e&&e.remove(),a(d).prependTo(c).click(function(){a(a(this).closest("tr")).treegrid("toggle")}),b},initIndent:function(){var b=a(this);b.find(".treegrid-indent").remove();for(var c=b.treegrid("getSetting","indentTemplate"),d=b.find(".treegrid-expander"),e=b.treegrid("getDepth"),f=0;e>f;f++)a(c).insertBefore(d);return b},initState:function(){var b=a(this);return b.treegrid(b.treegrid("getSetting","saveState")&&!b.treegrid("isFirstInit")?"restoreState":"expanded"===b.treegrid("getSetting","initialState")?"expand":"collapse"),b},isFirstInit:function(){var b=a(this).treegrid("getTreeContainer");return void 0===b.data("first_init")&&b.data("first_init",void 0===a.cookie(b.treegrid("getSetting","saveStateName"))),b.data("first_init")},saveState:function(){var b=a(this);if("cookie"===b.treegrid("getSetting","saveStateMethod")){var c=a.cookie(b.treegrid("getSetting","saveStateName"))||"",d=""===c?[]:c.split(","),e=b.treegrid("getNodeId");b.treegrid("isExpanded")?-1===a.inArray(e,d)&&d.push(e):b.treegrid("isCollapsed")&&-1!==a.inArray(e,d)&&d.splice(a.inArray(e,d),1),a.cookie(b.treegrid("getSetting","saveStateName"),d.join(","))}return b},restoreState:function(){var b=a(this);if("cookie"===b.treegrid("getSetting","saveStateMethod")){var c=a.cookie(b.treegrid("getSetting","saveStateName")).split(",");b.treegrid(-1!==a.inArray(b.treegrid("getNodeId"),c)?"expand":"collapse")}return b},getSetting:function(b){return a(this).treegrid("getTreeContainer")?a(this).treegrid("getTreeContainer").data("settings")[b]:null},setSettings:function(b){a(this).treegrid("getTreeContainer").data("settings",b)},getTreeContainer:function(){return a(this).data("treegrid")},setTreeContainer:function(b){return a(this).data("treegrid",b)},getRootNodes:function(){return a(this).treegrid("getSetting","getRootNodes").apply(this,[a(this).treegrid("getTreeContainer")])},getAllNodes:function(){return a(this).treegrid("getSetting","getAllNodes").apply(this,[a(this).treegrid("getTreeContainer")])},isNode:function(){return null!==a(this).treegrid("getNodeId")},getNodeId:function(){return null===a(this).treegrid("getSetting","getNodeId")?null:a(this).treegrid("getSetting","getNodeId").apply(this)},getParentNodeId:function(){return a(this).treegrid("getSetting","getParentNodeId").apply(this)},getParentNode:function(){return null===a(this).treegrid("getParentNodeId")?null:a(this).treegrid("getSetting","getNodeById").apply(this,[a(this).treegrid("getParentNodeId"),a(this).treegrid("getTreeContainer")])},getChildNodes:function(){return a(this).treegrid("getSetting","getChildNodes").apply(this,[a(this).treegrid("getNodeId"),a(this).treegrid("getTreeContainer")])},getDepth:function(){return null===a(this).treegrid("getParentNode")?0:a(this).treegrid("getParentNode").treegrid("getDepth")+1},isRoot:function(){return 0===a(this).treegrid("getDepth")},isLeaf:function(){return 0===a(this).treegrid("getChildNodes").length},isLast:function(){if(a(this).treegrid("isNode")){var b=a(this).treegrid("getParentNode");if(null===b){if(a(this).treegrid("getNodeId")===a(this).treegrid("getRootNodes").last().treegrid("getNodeId"))return!0}else if(a(this).treegrid("getNodeId")===b.treegrid("getChildNodes").last().treegrid("getNodeId"))return!0}return!1},isFirst:function(){if(a(this).treegrid("isNode")){var b=a(this).treegrid("getParentNode");if(null===b){if(a(this).treegrid("getNodeId")===a(this).treegrid("getRootNodes").first().treegrid("getNodeId"))return!0}else if(a(this).treegrid("getNodeId")===b.treegrid("getChildNodes").first().treegrid("getNodeId"))return!0}return!1},isExpanded:function(){return a(this).hasClass("treegrid-expanded")},isCollapsed:function(){return a(this).hasClass("treegrid-collapsed")},isOneOfParentsCollapsed:function(){var b=a(this);return b.treegrid("isRoot")?!1:b.treegrid("getParentNode").treegrid("isCollapsed")?!0:b.treegrid("getParentNode").treegrid("isOneOfParentsCollapsed")},expand:function(){return this.treegrid("isLeaf")||this.treegrid("isExpanded")?this:(this.trigger("expand"),this.trigger("change"),this)},expandAll:function(){var b=a(this);return b.treegrid("getRootNodes").treegrid("expandRecursive"),b},expandRecursive:function(){return a(this).each(function(){var b=a(this);b.treegrid("expand"),b.treegrid("isLeaf")||b.treegrid("getChildNodes").treegrid("expandRecursive")})},collapse:function(){return a(this).each(function(){var b=a(this);b.treegrid("isLeaf")||b.treegrid("isCollapsed")||(b.trigger("collapse"),b.trigger("change"))})},collapseAll:function(){var b=a(this);return b.treegrid("getRootNodes").treegrid("collapseRecursive"),b},collapseRecursive:function(){return a(this).each(function(){var b=a(this);b.treegrid("collapse"),b.treegrid("isLeaf")||b.treegrid("getChildNodes").treegrid("collapseRecursive")})},toggle:function(){var b=a(this);return b.treegrid(b.treegrid("isExpanded")?"collapse":"expand"),b},render:function(){return a(this).each(function(){var b=a(this);b.treegrid("isOneOfParentsCollapsed")?b.hide():b.show(),b.treegrid("isLeaf")||(b.treegrid("renderExpander"),b.treegrid("getChildNodes").treegrid("render"))})},renderExpander:function(){return a(this).each(function(){var b=a(this),c=b.treegrid("getSetting","getExpander").apply(this);c?b.treegrid("isCollapsed")?(c.removeClass(b.treegrid("getSetting","expanderExpandedClass")),c.addClass(b.treegrid("getSetting","expanderCollapsedClass"))):(c.removeClass(b.treegrid("getSetting","expanderCollapsedClass")),c.addClass(b.treegrid("getSetting","expanderExpandedClass"))):(b.treegrid("initExpander"),b.treegrid("renderExpander"))})}};a.fn.treegrid=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method with name "+c+" does not exists for jQuery.treegrid"):b.initTree.apply(this,arguments)},a.fn.treegrid.defaults={initialState:"expanded",saveState:!1,saveStateMethod:"cookie",saveStateName:"tree-grid-state",expanderTemplate:'<span class="treegrid-expander"></span>',indentTemplate:'<span class="treegrid-indent"></span>',expanderExpandedClass:"treegrid-expander-expanded",expanderCollapsedClass:"treegrid-expander-collapsed",treeColumn:0,getExpander:function(){return a(this).find(".treegrid-expander")},getNodeId:function(){var b=/treegrid-([A-Za-z0-9_-]+)/;return b.test(a(this).attr("class"))?b.exec(a(this).attr("class"))[1]:null},getParentNodeId:function(){var b=/treegrid-parent-([A-Za-z0-9_-]+)/;return b.test(a(this).attr("class"))?b.exec(a(this).attr("class"))[1]:null},getNodeById:function(a,b){var c="treegrid-"+a;return b.find("tr."+c)},getChildNodes:function(a,b){var c="treegrid-parent-"+a;return b.find("tr."+c)},getTreeGridContainer:function(){return a(this).closest("table")},getRootNodes:function(b){var c=a.grep(b.find("tr"),function(b){var c=a(b).attr("class"),d=/treegrid-([A-Za-z0-9_-]+)/,e=/treegrid-parent-([A-Za-z0-9_-]+)/;return d.test(c)&&!e.test(c)});return a(c)},getAllNodes:function(b){var c=a.grep(b.find("tr"),function(b){var c=a(b).attr("class"),d=/treegrid-([A-Za-z0-9_-]+)/;return d.test(c)});return a(c)},onCollapse:null,onExpand:null,onChange:null}}(jQuery);
\ No newline at end of file diff --git a/library/cpp/lwtrace/mon/static/js/jquery.url.min.js b/library/cpp/lwtrace/mon/static/js/jquery.url.min.js index 8ac9051a2a..f3b029c799 100644 --- a/library/cpp/lwtrace/mon/static/js/jquery.url.min.js +++ b/library/cpp/lwtrace/mon/static/js/jquery.url.min.js @@ -1 +1 @@ -/*! js-url - v2.0.2 - 2015-09-17 */window.url=function(){function a(){}function b(a){return decodeURIComponent(a.replace(/\+/g," "))}function c(a,b){var c=a.charAt(0),d=b.split(c);return c===a?d:(a=parseInt(a.substring(1),10),d[0>a?d.length+a:a-1])}function d(a,c){var d=a.charAt(0),e=c.split("&"),f=[],g={},h=[],i=a.substring(1);for(var j in e)if(f=e[j].match(/(.*?)=(.*)/),f||(f=[e[j],e[j],""]),""!==f[1].replace(/\s/g,"")){if(f[2]=b(f[2]||""),i===f[1])return f[2];h=f[1].match(/(.*)\[([0-9]+)\]/),h?(g[h[1]]=g[h[1]]||[],g[h[1]][h[2]]=f[2]):g[f[1]]=f[2]}return d===a?g:g[i]}return function(b,e){var f,g={};if("tld?"===b)return a();if(e=e||window.location.toString(),!b)return e;if(b=b.toString(),f=e.match(/^mailto:([^\/].+)/))g.protocol="mailto",g.email=f[1];else{if((f=e.match(/(.*?)#(.*)/))&&(g.hash=f[2],e=f[1]),g.hash&&b.match(/^#/))return d(b,g.hash);if((f=e.match(/(.*?)\?(.*)/))&&(g.query=f[2],e=f[1]),g.query&&b.match(/^\?/))return d(b,g.query);if((f=e.match(/(.*?)\:?\/\/(.*)/))&&(g.protocol=f[1].toLowerCase(),e=f[2]),(f=e.match(/(.*?)(\/.*)/))&&(g.path=f[2],e=f[1]),g.path=(g.path||"").replace(/^([^\/])/,"/$1").replace(/\/$/,""),b.match(/^[\-0-9]+$/)&&(b=b.replace(/^([^\/])/,"/$1")),b.match(/^\//))return c(b,g.path.substring(1));if(f=c("/-1",g.path.substring(1)),f&&(f=f.match(/(.*?)\.(.*)/))&&(g.file=f[0],g.filename=f[1],g.fileext=f[2]),(f=e.match(/(.*)\:([0-9]+)$/))&&(g.port=f[2],e=f[1]),(f=e.match(/(.*?)@(.*)/))&&(g.auth=f[1],e=f[2]),g.auth&&(f=g.auth.match(/(.*)\:(.*)/),g.user=f?f[1]:g.auth,g.pass=f?f[2]:void 0),g.hostname=e.toLowerCase(),"."===b.charAt(0))return c(b,g.hostname);a()&&(f=g.hostname.match(a()),f&&(g.tld=f[3],g.domain=f[2]?f[2]+"."+f[3]:void 0,g.sub=f[1]||void 0)),g.port=g.port||("https"===g.protocol?"443":"80"),g.protocol=g.protocol||("443"===g.port?"https":"http")}return b in g?g[b]:"[]"===b?g:void 0}}(),"undefined"!=typeof jQuery&&jQuery.extend({url:function(a,b){return window.url(a,b)}}); +/*! js-url - v2.0.2 - 2015-09-17 */window.url=function(){function a(){}function b(a){return decodeURIComponent(a.replace(/\+/g," "))}function c(a,b){var c=a.charAt(0),d=b.split(c);return c===a?d:(a=parseInt(a.substring(1),10),d[0>a?d.length+a:a-1])}function d(a,c){var d=a.charAt(0),e=c.split("&"),f=[],g={},h=[],i=a.substring(1);for(var j in e)if(f=e[j].match(/(.*?)=(.*)/),f||(f=[e[j],e[j],""]),""!==f[1].replace(/\s/g,"")){if(f[2]=b(f[2]||""),i===f[1])return f[2];h=f[1].match(/(.*)\[([0-9]+)\]/),h?(g[h[1]]=g[h[1]]||[],g[h[1]][h[2]]=f[2]):g[f[1]]=f[2]}return d===a?g:g[i]}return function(b,e){var f,g={};if("tld?"===b)return a();if(e=e||window.location.toString(),!b)return e;if(b=b.toString(),f=e.match(/^mailto:([^\/].+)/))g.protocol="mailto",g.email=f[1];else{if((f=e.match(/(.*?)#(.*)/))&&(g.hash=f[2],e=f[1]),g.hash&&b.match(/^#/))return d(b,g.hash);if((f=e.match(/(.*?)\?(.*)/))&&(g.query=f[2],e=f[1]),g.query&&b.match(/^\?/))return d(b,g.query);if((f=e.match(/(.*?)\:?\/\/(.*)/))&&(g.protocol=f[1].toLowerCase(),e=f[2]),(f=e.match(/(.*?)(\/.*)/))&&(g.path=f[2],e=f[1]),g.path=(g.path||"").replace(/^([^\/])/,"/$1").replace(/\/$/,""),b.match(/^[\-0-9]+$/)&&(b=b.replace(/^([^\/])/,"/$1")),b.match(/^\//))return c(b,g.path.substring(1));if(f=c("/-1",g.path.substring(1)),f&&(f=f.match(/(.*?)\.(.*)/))&&(g.file=f[0],g.filename=f[1],g.fileext=f[2]),(f=e.match(/(.*)\:([0-9]+)$/))&&(g.port=f[2],e=f[1]),(f=e.match(/(.*?)@(.*)/))&&(g.auth=f[1],e=f[2]),g.auth&&(f=g.auth.match(/(.*)\:(.*)/),g.user=f?f[1]:g.auth,g.pass=f?f[2]:void 0),g.hostname=e.toLowerCase(),"."===b.charAt(0))return c(b,g.hostname);a()&&(f=g.hostname.match(a()),f&&(g.tld=f[3],g.domain=f[2]?f[2]+"."+f[3]:void 0,g.sub=f[1]||void 0)),g.port=g.port||("https"===g.protocol?"443":"80"),g.protocol=g.protocol||("443"===g.port?"https":"http")}return b in g?g[b]:"[]"===b?g:void 0}}(),"undefined"!=typeof jQuery&&jQuery.extend({url:function(a,b){return window.url(a,b)}}); diff --git a/library/cpp/lwtrace/mon/trace.sh b/library/cpp/lwtrace/mon/trace.sh index 8414a9b0ca..0424e1548f 100755 --- a/library/cpp/lwtrace/mon/trace.sh +++ b/library/cpp/lwtrace/mon/trace.sh @@ -1,81 +1,81 @@ -#!/bin/sh -e -# $Id: trace.sh 2313967 2016-05-24 12:52:38Z serxa $ -# $HeadURL: svn+ssh://arcadia.yandex.ru/arc/trunk/arcadia/library/cpp/lwtrace/mon/trace.sh $ - -usage() { - if [ -n "$*" ]; then - echo "ERROR: $*" >&2 - else - echo "Script for LWTrace tracing management" >&2 - fi - echo "USAGE: `basename $0` COMMAND TRACEID HOST:PORT PARAM1=VALUE1 ..." >&2 - echo "COMMANDS:" >&2 - echo " new Start new tracing described by query from STDIN," >&2 - echo " uniquely named with TRACEID string," >&2 - echo " using HOST:PORT monitoring service." >&2 - echo " query can contain \$params that are substituted with corresponding values from cmdline" >&2 - echo " (alse \$\$ is replaced by \$, each param must be defined from cmdline)" >&2 - echo " delete Stop existing tracing with specified name TRACEID," >&2 - echo " on HOST:PORT monitoring service." >&2 - exit 1 -} - -COMMAND=$1 -ID="$2" -IDENC="$(perl -MURI::Escape -e '$id = $ARGV[0]; $id=uri_escape($id); $id =~ s{[+%]}{-}g; print $id;' "$ID")" -ADDRESS="$3" -if [ "$COMMAND" = "--help" ] || [ -z "$*" ]; then usage; fi -if [ -z "$ID" ]; then usage "TRACEID is not specified"; fi -if [ -z "$ADDRESS" ]; then usage "HOST:PORT is not specified"; fi - -shift 3 - -STATUS=0 -ERRFILE=/var/tmp/lwtrace.sh.$$ - -error() { - echo "ERROR: $*" >&2 - [ ! -e $ERRFILE ] || cat $ERRFILE >&2 - exit 1 -} - -stop() { rm -f $ERRFILE; } -trap stop INT ABRT EXIT - -case "$COMMAND" in - - new) - QUERY="$(perl -e 'use MIME::Base64; - local $/; - $a = <STDIN>; - for $arg (@ARGV) { - ($k,$v) = split "=",$arg,2; - $a =~ s{\$$k}{$v}g; - } - if ($a =~ /\$([A-Za-z_][\w_]*)/) { - print STDERR "undefined param in lwtrace query: $1\n"; - exit 0 - } - $a =~ s{\$\$}{\$}g; - print encode_base64($a, ""); - ' "$@" 2>$ERRFILE)" - if [ -z "$QUERY" ]; then error "lwtrace query errors"; fi - wget --post-data="id=$IDENC&query=$QUERY" \ - -O - http://$ADDRESS/trace?mode=new </dev/null 2>$ERRFILE || STATUS=$? - if [ $STATUS -ne 0 ]; then error "wget failure"; fi - ;; - - delete) - wget --post-data="id=$IDENC" \ - -O - http://$ADDRESS/trace?mode=delete </dev/null 2>$ERRFILE || STATUS=$? - if [ $STATUS -ne 0 ]; then error "wget failure"; fi - ;; - - *) - echo "usage: `basename $0` new TRACEID ADDRESS < query.txt" >&2 - echo " `basename $0` delete TRACEID ADDRESS" >&2 - exit 1 - ;; - -esac -echo "Done" +#!/bin/sh -e +# $Id: trace.sh 2313967 2016-05-24 12:52:38Z serxa $ +# $HeadURL: svn+ssh://arcadia.yandex.ru/arc/trunk/arcadia/library/cpp/lwtrace/mon/trace.sh $ + +usage() { + if [ -n "$*" ]; then + echo "ERROR: $*" >&2 + else + echo "Script for LWTrace tracing management" >&2 + fi + echo "USAGE: `basename $0` COMMAND TRACEID HOST:PORT PARAM1=VALUE1 ..." >&2 + echo "COMMANDS:" >&2 + echo " new Start new tracing described by query from STDIN," >&2 + echo " uniquely named with TRACEID string," >&2 + echo " using HOST:PORT monitoring service." >&2 + echo " query can contain \$params that are substituted with corresponding values from cmdline" >&2 + echo " (alse \$\$ is replaced by \$, each param must be defined from cmdline)" >&2 + echo " delete Stop existing tracing with specified name TRACEID," >&2 + echo " on HOST:PORT monitoring service." >&2 + exit 1 +} + +COMMAND=$1 +ID="$2" +IDENC="$(perl -MURI::Escape -e '$id = $ARGV[0]; $id=uri_escape($id); $id =~ s{[+%]}{-}g; print $id;' "$ID")" +ADDRESS="$3" +if [ "$COMMAND" = "--help" ] || [ -z "$*" ]; then usage; fi +if [ -z "$ID" ]; then usage "TRACEID is not specified"; fi +if [ -z "$ADDRESS" ]; then usage "HOST:PORT is not specified"; fi + +shift 3 + +STATUS=0 +ERRFILE=/var/tmp/lwtrace.sh.$$ + +error() { + echo "ERROR: $*" >&2 + [ ! -e $ERRFILE ] || cat $ERRFILE >&2 + exit 1 +} + +stop() { rm -f $ERRFILE; } +trap stop INT ABRT EXIT + +case "$COMMAND" in + + new) + QUERY="$(perl -e 'use MIME::Base64; + local $/; + $a = <STDIN>; + for $arg (@ARGV) { + ($k,$v) = split "=",$arg,2; + $a =~ s{\$$k}{$v}g; + } + if ($a =~ /\$([A-Za-z_][\w_]*)/) { + print STDERR "undefined param in lwtrace query: $1\n"; + exit 0 + } + $a =~ s{\$\$}{\$}g; + print encode_base64($a, ""); + ' "$@" 2>$ERRFILE)" + if [ -z "$QUERY" ]; then error "lwtrace query errors"; fi + wget --post-data="id=$IDENC&query=$QUERY" \ + -O - http://$ADDRESS/trace?mode=new </dev/null 2>$ERRFILE || STATUS=$? + if [ $STATUS -ne 0 ]; then error "wget failure"; fi + ;; + + delete) + wget --post-data="id=$IDENC" \ + -O - http://$ADDRESS/trace?mode=delete </dev/null 2>$ERRFILE || STATUS=$? + if [ $STATUS -ne 0 ]; then error "wget failure"; fi + ;; + + *) + echo "usage: `basename $0` new TRACEID ADDRESS < query.txt" >&2 + echo " `basename $0` delete TRACEID ADDRESS" >&2 + exit 1 + ;; + +esac +echo "Done" diff --git a/library/cpp/lwtrace/mon/ya.make b/library/cpp/lwtrace/mon/ya.make index bdcb315754..6c8c11887a 100644 --- a/library/cpp/lwtrace/mon/ya.make +++ b/library/cpp/lwtrace/mon/ya.make @@ -1,55 +1,55 @@ -LIBRARY() - +LIBRARY() + OWNER(serxa g:kikimr) - -RESOURCE( - static/common.css lwtrace/mon/static/common.css - static/common.js lwtrace/mon/static/common.js - static/css/bootstrap.min.css lwtrace/mon/static/css/bootstrap.min.css - static/css/d3-gantt.css lwtrace/mon/static/css/d3-gantt.css - static/css/jquery.treegrid.css lwtrace/mon/static/css/jquery.treegrid.css - static/analytics.css lwtrace/mon/static/analytics.css - static/analytics.flot.html lwtrace/mon/static/analytics.flot.html - static/analytics.gantt.html lwtrace/mon/static/analytics.gantt.html - static/analytics.header.html lwtrace/mon/static/analytics.header.html - static/analytics.js lwtrace/mon/static/analytics.js - static/fonts/glyphicons-halflings-regular.eot lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot - static/fonts/glyphicons-halflings-regular.svg lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg - static/fonts/glyphicons-halflings-regular.ttf lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf - static/fonts/glyphicons-halflings-regular.woff2 lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2 - static/fonts/glyphicons-halflings-regular.woff lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff - static/footer.html lwtrace/mon/static/footer.html - static/header.html lwtrace/mon/static/header.html - static/img/collapse.png lwtrace/mon/static/img/collapse.png - static/img/expand.png lwtrace/mon/static/img/expand.png - static/img/file.png lwtrace/mon/static/img/file.png - static/img/folder.png lwtrace/mon/static/img/folder.png - static/js/bootstrap.min.js lwtrace/mon/static/js/bootstrap.min.js - static/js/d3.v4.min.js lwtrace/mon/static/js/d3.v4.min.js - static/js/d3-gantt.js lwtrace/mon/static/js/d3-gantt.js - static/js/d3-tip-0.8.0-alpha.1.js lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js - static/js/filesaver.min.js lwtrace/mon/static/js/filesaver.min.js - static/js/jquery.flot.extents.js lwtrace/mon/static/js/jquery.flot.extents.js - static/js/jquery.flot.min.js lwtrace/mon/static/js/jquery.flot.min.js - static/js/jquery.flot.navigate.min.js lwtrace/mon/static/js/jquery.flot.navigate.min.js - static/js/jquery.flot.selection.min.js lwtrace/mon/static/js/jquery.flot.selection.min.js - static/js/jquery.min.js lwtrace/mon/static/js/jquery.min.js - static/js/jquery.treegrid.bootstrap3.js lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js - static/js/jquery.treegrid.min.js lwtrace/mon/static/js/jquery.treegrid.min.js - static/js/jquery.url.min.js lwtrace/mon/static/js/jquery.url.min.js -) - -SRCS( - mon_lwtrace.cpp -) - -PEERDIR( + +RESOURCE( + static/common.css lwtrace/mon/static/common.css + static/common.js lwtrace/mon/static/common.js + static/css/bootstrap.min.css lwtrace/mon/static/css/bootstrap.min.css + static/css/d3-gantt.css lwtrace/mon/static/css/d3-gantt.css + static/css/jquery.treegrid.css lwtrace/mon/static/css/jquery.treegrid.css + static/analytics.css lwtrace/mon/static/analytics.css + static/analytics.flot.html lwtrace/mon/static/analytics.flot.html + static/analytics.gantt.html lwtrace/mon/static/analytics.gantt.html + static/analytics.header.html lwtrace/mon/static/analytics.header.html + static/analytics.js lwtrace/mon/static/analytics.js + static/fonts/glyphicons-halflings-regular.eot lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot + static/fonts/glyphicons-halflings-regular.svg lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg + static/fonts/glyphicons-halflings-regular.ttf lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf + static/fonts/glyphicons-halflings-regular.woff2 lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2 + static/fonts/glyphicons-halflings-regular.woff lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff + static/footer.html lwtrace/mon/static/footer.html + static/header.html lwtrace/mon/static/header.html + static/img/collapse.png lwtrace/mon/static/img/collapse.png + static/img/expand.png lwtrace/mon/static/img/expand.png + static/img/file.png lwtrace/mon/static/img/file.png + static/img/folder.png lwtrace/mon/static/img/folder.png + static/js/bootstrap.min.js lwtrace/mon/static/js/bootstrap.min.js + static/js/d3.v4.min.js lwtrace/mon/static/js/d3.v4.min.js + static/js/d3-gantt.js lwtrace/mon/static/js/d3-gantt.js + static/js/d3-tip-0.8.0-alpha.1.js lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js + static/js/filesaver.min.js lwtrace/mon/static/js/filesaver.min.js + static/js/jquery.flot.extents.js lwtrace/mon/static/js/jquery.flot.extents.js + static/js/jquery.flot.min.js lwtrace/mon/static/js/jquery.flot.min.js + static/js/jquery.flot.navigate.min.js lwtrace/mon/static/js/jquery.flot.navigate.min.js + static/js/jquery.flot.selection.min.js lwtrace/mon/static/js/jquery.flot.selection.min.js + static/js/jquery.min.js lwtrace/mon/static/js/jquery.min.js + static/js/jquery.treegrid.bootstrap3.js lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js + static/js/jquery.treegrid.min.js lwtrace/mon/static/js/jquery.treegrid.min.js + static/js/jquery.url.min.js lwtrace/mon/static/js/jquery.url.min.js +) + +SRCS( + mon_lwtrace.cpp +) + +PEERDIR( library/cpp/html/pcdata library/cpp/lwtrace - library/cpp/lwtrace/mon/analytics + library/cpp/lwtrace/mon/analytics library/cpp/monlib/dynamic_counters library/cpp/resource library/cpp/string_utils/base64 -) - -END() +) + +END() diff --git a/library/cpp/lwtrace/perf.cpp b/library/cpp/lwtrace/perf.cpp index 03b68586ea..b3f109c1be 100644 --- a/library/cpp/lwtrace/perf.cpp +++ b/library/cpp/lwtrace/perf.cpp @@ -1,84 +1,84 @@ -#include "perf.h" - +#include "perf.h" + #include "probes.h" -#include <util/system/datetime.h> -#include <util/system/hp_timer.h> - -namespace NLWTrace { - LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER); - - TCpuTracker::TCpuTracker() - : MinReportPeriod(NHPTimer::GetCyclesPerSecond()) - { - ResetStats(); - } - - void TCpuTracker::Enter() { - LastTs = GetCycleCount(); - } - - void TCpuTracker::Exit(const TProbe* probe) { - ui64 exitTs = GetCycleCount(); - if (exitTs < LastTs) { - return; // probably TSC was reset - } - ui64 cycles = exitTs - LastTs; - LastTs = exitTs; - - AddStats(probe, cycles); - } - - void TCpuTracker::AddStats(const TProbe* probe, ui64 cycles) { - if (MaxCycles < cycles) { - MaxProbe = probe; - MaxCycles = cycles; - } - if (MinCycles > cycles) { - MinCycles = cycles; - } - ProbeCycles += cycles; - Count++; - - if (LastTs - LastReportTs > MinReportPeriod) { - Report(); - } - } - - void TCpuTracker::ResetStats() { - MaxCycles = 0; - MaxProbe = nullptr; - MinCycles = ui64(-1); - ProbeCycles = 0; - Count = 0; - } - - void TCpuTracker::Report() { - if (!Reporting) { - Reporting = true; - ReportNotReentrant(); - Reporting = false; - } - } - - void TCpuTracker::ReportNotReentrant() { - if (LastReportTs && Count > 0 && LastTs > LastReportTs) { - ui64 reportPeriod = LastTs - LastReportTs; - double share = double(ProbeCycles) / reportPeriod; - double minMs = MilliSeconds(MinCycles); - double maxMs = MilliSeconds(MaxCycles); - double avgMs = MilliSeconds(ProbeCycles) / Count; - LastReportTs = LastTs; - ResetStats(); - LWPROBE(PerfReport, share, minMs, maxMs, avgMs); - } else { - LastReportTs = LastTs; - ResetStats(); - } - } - - double TCpuTracker::MilliSeconds(ui64 cycles) { - return NHPTimer::GetSeconds(cycles) * 1000.0; - } - -} +#include <util/system/datetime.h> +#include <util/system/hp_timer.h> + +namespace NLWTrace { + LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER); + + TCpuTracker::TCpuTracker() + : MinReportPeriod(NHPTimer::GetCyclesPerSecond()) + { + ResetStats(); + } + + void TCpuTracker::Enter() { + LastTs = GetCycleCount(); + } + + void TCpuTracker::Exit(const TProbe* probe) { + ui64 exitTs = GetCycleCount(); + if (exitTs < LastTs) { + return; // probably TSC was reset + } + ui64 cycles = exitTs - LastTs; + LastTs = exitTs; + + AddStats(probe, cycles); + } + + void TCpuTracker::AddStats(const TProbe* probe, ui64 cycles) { + if (MaxCycles < cycles) { + MaxProbe = probe; + MaxCycles = cycles; + } + if (MinCycles > cycles) { + MinCycles = cycles; + } + ProbeCycles += cycles; + Count++; + + if (LastTs - LastReportTs > MinReportPeriod) { + Report(); + } + } + + void TCpuTracker::ResetStats() { + MaxCycles = 0; + MaxProbe = nullptr; + MinCycles = ui64(-1); + ProbeCycles = 0; + Count = 0; + } + + void TCpuTracker::Report() { + if (!Reporting) { + Reporting = true; + ReportNotReentrant(); + Reporting = false; + } + } + + void TCpuTracker::ReportNotReentrant() { + if (LastReportTs && Count > 0 && LastTs > LastReportTs) { + ui64 reportPeriod = LastTs - LastReportTs; + double share = double(ProbeCycles) / reportPeriod; + double minMs = MilliSeconds(MinCycles); + double maxMs = MilliSeconds(MaxCycles); + double avgMs = MilliSeconds(ProbeCycles) / Count; + LastReportTs = LastTs; + ResetStats(); + LWPROBE(PerfReport, share, minMs, maxMs, avgMs); + } else { + LastReportTs = LastTs; + ResetStats(); + } + } + + double TCpuTracker::MilliSeconds(ui64 cycles) { + return NHPTimer::GetSeconds(cycles) * 1000.0; + } + +} diff --git a/library/cpp/lwtrace/perf.h b/library/cpp/lwtrace/perf.h index d535247196..03564eeb3f 100644 --- a/library/cpp/lwtrace/perf.h +++ b/library/cpp/lwtrace/perf.h @@ -1,63 +1,63 @@ -#pragma once - -#include <util/system/types.h> -#include <util/thread/singleton.h> - -namespace NLWTrace { - struct TProbe; - - class TCpuTracker { - private: - const ui64 MinReportPeriod; - - // State - bool Reporting = false; - ui64 LastTs = 0; - ui64 LastReportTs = 0; - - // Statistics - ui64 MaxCycles; - const TProbe* MaxProbe; - ui64 MinCycles; - ui64 ProbeCycles; - ui64 Count; - - public: - TCpuTracker(); - void Enter(); - void Exit(const TProbe* Probe); - static TCpuTracker* TlsInstance() { - struct TCpuTrackerkHolder { - TCpuTracker Tracker; - }; - return &FastTlsSingletonWithPriority<TCpuTrackerkHolder, 4>()->Tracker; - } - - private: - void AddStats(const TProbe* probe, ui64 cycles); - void ResetStats(); - void Report(); - void ReportNotReentrant(); - static double MilliSeconds(ui64 cycles); - }; - - class TScopedThreadCpuTracker { - private: - const TProbe* Probe; - TCpuTracker* Tracker; - - public: - template <class T> - explicit TScopedThreadCpuTracker(const T& probe) - : Probe(&probe.Probe) - , Tracker(TCpuTracker::TlsInstance()) - { - Tracker->Enter(); - } - - ~TScopedThreadCpuTracker() { - Tracker->Exit(Probe); - } - }; - -} +#pragma once + +#include <util/system/types.h> +#include <util/thread/singleton.h> + +namespace NLWTrace { + struct TProbe; + + class TCpuTracker { + private: + const ui64 MinReportPeriod; + + // State + bool Reporting = false; + ui64 LastTs = 0; + ui64 LastReportTs = 0; + + // Statistics + ui64 MaxCycles; + const TProbe* MaxProbe; + ui64 MinCycles; + ui64 ProbeCycles; + ui64 Count; + + public: + TCpuTracker(); + void Enter(); + void Exit(const TProbe* Probe); + static TCpuTracker* TlsInstance() { + struct TCpuTrackerkHolder { + TCpuTracker Tracker; + }; + return &FastTlsSingletonWithPriority<TCpuTrackerkHolder, 4>()->Tracker; + } + + private: + void AddStats(const TProbe* probe, ui64 cycles); + void ResetStats(); + void Report(); + void ReportNotReentrant(); + static double MilliSeconds(ui64 cycles); + }; + + class TScopedThreadCpuTracker { + private: + const TProbe* Probe; + TCpuTracker* Tracker; + + public: + template <class T> + explicit TScopedThreadCpuTracker(const T& probe) + : Probe(&probe.Probe) + , Tracker(TCpuTracker::TlsInstance()) + { + Tracker->Enter(); + } + + ~TScopedThreadCpuTracker() { + Tracker->Exit(Probe); + } + }; + +} diff --git a/library/cpp/lwtrace/preprocessor.h b/library/cpp/lwtrace/preprocessor.h index 40865467b2..abc21870d6 100644 --- a/library/cpp/lwtrace/preprocessor.h +++ b/library/cpp/lwtrace/preprocessor.h @@ -1,8 +1,8 @@ -#pragma once - -#include "check.h" -#include "perf.h" -#include "symbol.h" +#pragma once + +#include "check.h" +#include "perf.h" +#include "symbol.h" #include <util/generic/hide_ptr.h> #include <util/system/platform.h> @@ -15,281 +15,281 @@ #endif // LWTRACE_DISABLE #endif // _win_ -// Maximum number of executors that can be attached to a probe -#define LWTRACE_MAX_ACTIONS 100 - -// Maximum number of groups that can be assigned to a probe -#define LWTRACE_MAX_GROUPS 100 - -#ifndef LWTRACE_DISABLE - -/* - * WARNING: All macros define in this header must be considered as implementation details and should NOT be used directly - * WARNING: See lwtrace/all.h for macros that represent a user interface of lwtrace library - * - */ - -// Use for code generation to handle parameter types. USAGE: -// 1. #define FOREACH_PARAMTYPE_MACRO(n, t, v, your_p1, your_p2) your code snippet -// 2. FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, your_p1_value, your_p1_value) -// FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, your_p1_another_value, your_p1_another_value) -// 3. #undef FOREACH_PARAMTYPE_MACRO +// Maximum number of executors that can be attached to a probe +#define LWTRACE_MAX_ACTIONS 100 + +// Maximum number of groups that can be assigned to a probe +#define LWTRACE_MAX_GROUPS 100 + +#ifndef LWTRACE_DISABLE + +/* + * WARNING: All macros define in this header must be considered as implementation details and should NOT be used directly + * WARNING: See lwtrace/all.h for macros that represent a user interface of lwtrace library + * + */ + +// Use for code generation to handle parameter types. USAGE: +// 1. #define FOREACH_PARAMTYPE_MACRO(n, t, v, your_p1, your_p2) your code snippet +// 2. FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, your_p1_value, your_p1_value) +// FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, your_p1_another_value, your_p1_another_value) +// 3. #undef FOREACH_PARAMTYPE_MACRO // Type order matters! -#define FOREACH_PARAMTYPE(MACRO, ...) \ - MACRO("i64", i64, I64, ##__VA_ARGS__) \ - MACRO("ui64", ui64, Ui64, ##__VA_ARGS__) \ - MACRO("double", double, Double, ##__VA_ARGS__) \ - MACRO("string", TString, Str, ##__VA_ARGS__) \ - MACRO("symbol", NLWTrace::TSymbol, Symbol, ##__VA_ARGS__) \ - MACRO("check", NLWTrace::TCheck, Check, ##__VA_ARGS__) \ - /**/ - -// Used with FOREACH_PARAMTYPE to handle TNil parameter type also -#define FOR_NIL_PARAMTYPE(MACRO, ...) \ - MACRO(NULL, TNil, Nil, ##__VA_ARGS__) \ - /**/ - +#define FOREACH_PARAMTYPE(MACRO, ...) \ + MACRO("i64", i64, I64, ##__VA_ARGS__) \ + MACRO("ui64", ui64, Ui64, ##__VA_ARGS__) \ + MACRO("double", double, Double, ##__VA_ARGS__) \ + MACRO("string", TString, Str, ##__VA_ARGS__) \ + MACRO("symbol", NLWTrace::TSymbol, Symbol, ##__VA_ARGS__) \ + MACRO("check", NLWTrace::TCheck, Check, ##__VA_ARGS__) \ + /**/ + +// Used with FOREACH_PARAMTYPE to handle TNil parameter type also +#define FOR_NIL_PARAMTYPE(MACRO, ...) \ + MACRO(NULL, TNil, Nil, ##__VA_ARGS__) \ + /**/ + // Used for math statements -#define FOR_MATH_PARAMTYPE(MACRO, ...) \ - MACRO("i64", i64, I64, ##__VA_ARGS__) \ - MACRO("ui64", ui64, Ui64, ##__VA_ARGS__) \ - MACRO("check", NLWTrace::TCheck, Check, ##__VA_ARGS__) \ +#define FOR_MATH_PARAMTYPE(MACRO, ...) \ + MACRO("i64", i64, I64, ##__VA_ARGS__) \ + MACRO("ui64", ui64, Ui64, ##__VA_ARGS__) \ + MACRO("check", NLWTrace::TCheck, Check, ##__VA_ARGS__) \ /**/ -// Use for code generation to handle parameter lists +// Use for code generation to handle parameter lists // NOTE: this is the only place to change if more parameters needed -#define FOREACH_PARAMNUM(MACRO, ...) \ - MACRO(0, ##__VA_ARGS__) \ - MACRO(1, ##__VA_ARGS__) \ - MACRO(2, ##__VA_ARGS__) \ - MACRO(3, ##__VA_ARGS__) \ - MACRO(4, ##__VA_ARGS__) \ - MACRO(5, ##__VA_ARGS__) \ - MACRO(6, ##__VA_ARGS__) \ - MACRO(7, ##__VA_ARGS__) \ - MACRO(8, ##__VA_ARGS__) \ - MACRO(9, ##__VA_ARGS__) \ - MACRO(10, ##__VA_ARGS__) \ - MACRO(11, ##__VA_ARGS__) \ - MACRO(12, ##__VA_ARGS__) \ - MACRO(13, ##__VA_ARGS__) \ - MACRO(14, ##__VA_ARGS__) \ - MACRO(15, ##__VA_ARGS__) \ - MACRO(16, ##__VA_ARGS__) \ - /**/ - +#define FOREACH_PARAMNUM(MACRO, ...) \ + MACRO(0, ##__VA_ARGS__) \ + MACRO(1, ##__VA_ARGS__) \ + MACRO(2, ##__VA_ARGS__) \ + MACRO(3, ##__VA_ARGS__) \ + MACRO(4, ##__VA_ARGS__) \ + MACRO(5, ##__VA_ARGS__) \ + MACRO(6, ##__VA_ARGS__) \ + MACRO(7, ##__VA_ARGS__) \ + MACRO(8, ##__VA_ARGS__) \ + MACRO(9, ##__VA_ARGS__) \ + MACRO(10, ##__VA_ARGS__) \ + MACRO(11, ##__VA_ARGS__) \ + MACRO(12, ##__VA_ARGS__) \ + MACRO(13, ##__VA_ARGS__) \ + MACRO(14, ##__VA_ARGS__) \ + MACRO(15, ##__VA_ARGS__) \ + MACRO(16, ##__VA_ARGS__) \ + /**/ + #define FOREACH_LEFT_TYPE(MACRO, ...) \ - MACRO(__VA_ARGS__, OT_VARIABLE) \ - MACRO(__VA_ARGS__, OT_LITERAL) \ - MACRO(__VA_ARGS__, OT_PARAMETER) \ + MACRO(__VA_ARGS__, OT_VARIABLE) \ + MACRO(__VA_ARGS__, OT_LITERAL) \ + MACRO(__VA_ARGS__, OT_PARAMETER) \ /**/ #define FOREACH_RIGHT_TYPE(MACRO, ...) \ - MACRO(__VA_ARGS__, OT_VARIABLE) \ - MACRO(__VA_ARGS__, OT_LITERAL) \ - MACRO(__VA_ARGS__, OT_PARAMETER) \ + MACRO(__VA_ARGS__, OT_VARIABLE) \ + MACRO(__VA_ARGS__, OT_LITERAL) \ + MACRO(__VA_ARGS__, OT_PARAMETER) \ /**/ #define FOREACH_DESTINATION_TYPE(MACRO, ...) \ - MACRO(__VA_ARGS__, OT_VARIABLE) \ + MACRO(__VA_ARGS__, OT_VARIABLE) \ /**/ -// Auxilary macros -#define LWTRACE_EXPAND(x) x -#define LWTRACE_EAT(...) - -// Eat last/first comma trick -#define LWTRACE_COMMA(bit) LWTRACE_COMMA_##bit() -#define LWTRACE_COMMA_0() -#define LWTRACE_COMMA_1() , - -// Macros to pack/unpack tuples, e.g. (x,y,z) -#define LWTRACE_UNROLL(...) __VA_ARGS__ -#define LWTRACE_ENROLL(...) (__VA_ARGS__) - -// Param types list handling macros -#define LWTRACE_TEMPLATE_PARAMS_I(i) (1) class TP##i = TNil LWTRACE_COMMA -#define LWTRACE_TEMPLATE_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_PARAMS_I)(0)) -#define LWTRACE_TEMPLATE_PARAMS_NODEF_I(i) (1) class TP##i LWTRACE_COMMA -#define LWTRACE_TEMPLATE_PARAMS_NODEF LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_PARAMS_NODEF_I)(0)) -#define LWTRACE_TEMPLATE_ARGS_I(i) (1) TP##i LWTRACE_COMMA -#define LWTRACE_TEMPLATE_ARGS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_ARGS_I)(0)) +// Auxilary macros +#define LWTRACE_EXPAND(x) x +#define LWTRACE_EAT(...) + +// Eat last/first comma trick +#define LWTRACE_COMMA(bit) LWTRACE_COMMA_##bit() +#define LWTRACE_COMMA_0() +#define LWTRACE_COMMA_1() , + +// Macros to pack/unpack tuples, e.g. (x,y,z) +#define LWTRACE_UNROLL(...) __VA_ARGS__ +#define LWTRACE_ENROLL(...) (__VA_ARGS__) + +// Param types list handling macros +#define LWTRACE_TEMPLATE_PARAMS_I(i) (1) class TP##i = TNil LWTRACE_COMMA +#define LWTRACE_TEMPLATE_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_PARAMS_I)(0)) +#define LWTRACE_TEMPLATE_PARAMS_NODEF_I(i) (1) class TP##i LWTRACE_COMMA +#define LWTRACE_TEMPLATE_PARAMS_NODEF LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_PARAMS_NODEF_I)(0)) +#define LWTRACE_TEMPLATE_ARGS_I(i) (1) TP##i LWTRACE_COMMA +#define LWTRACE_TEMPLATE_ARGS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_ARGS_I)(0)) #define LWTRACE_FUNCTION_PARAMS_I(i) (1) typename ::NLWTrace::TParamTraits<TP##i>::TFuncParam p##i = ERROR_not_enough_parameters() LWTRACE_COMMA -#define LWTRACE_FUNCTION_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_FUNCTION_PARAMS_I)(0)) +#define LWTRACE_FUNCTION_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_FUNCTION_PARAMS_I)(0)) #define LWTRACE_PREPARE_PARAMS_I(i, params) params.Param[i].template CopyConstruct<typename ::NLWTrace::TParamTraits<TP##i>::TStoreType>(::NLWTrace::TParamTraits<TP##i>::ToStoreType(p##i)); -#define LWTRACE_PREPARE_PARAMS(params) \ - do { \ - FOREACH_PARAMNUM(LWTRACE_PREPARE_PARAMS_I, params) \ - } while (false) -#define LWTRACE_COUNT_PARAMS_I(i) +(std::is_same<TP##i, ::NLWTrace::TNil>::value ? 0 : 1) -#define LWTRACE_COUNT_PARAMS (0 FOREACH_PARAMNUM(LWTRACE_COUNT_PARAMS_I)) -#define LWTRACE_MAX_PARAMS_I(i) +1 -#define LWTRACE_MAX_PARAMS (0 FOREACH_PARAMNUM(LWTRACE_MAX_PARAMS_I)) - -// Determine maximum sizeof(t) over all supported types -#define LWTRACE_MAX_PARAM_SIZE_TA_TAIL_I(n, t, v) v, -#define LWTRACE_MAX_PARAM_SIZE_TA_TAIL \ - FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TA_TAIL_I) \ - 0 -#define LWTRACE_MAX_PARAM_SIZE_TP_I(n, t, v) , size_t v = 0 -#define LWTRACE_MAX_PARAM_SIZE_TP size_t Head = 0 FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TP_I) -#define LWTRACE_MAX_PARAM_SIZE_TA_I(n, t, v) , sizeof(t) -#define LWTRACE_MAX_PARAM_SIZE_TA 0 FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TA_I) -#define LWTRACE_MAX_PARAM_SIZE ::NLWTrace::TMaxParamSize<LWTRACE_MAX_PARAM_SIZE_TA>::Result - -namespace NLWTrace { - template <LWTRACE_MAX_PARAM_SIZE_TP> - struct TMaxParamSize { - static const size_t Tail = TMaxParamSize<LWTRACE_MAX_PARAM_SIZE_TA_TAIL>::Result; - static const size_t Result = (Head > Tail ? Head : Tail); - }; - - template <> - struct TMaxParamSize<> { - static const size_t Result = 0; - }; - -} - -// Define stuff that is needed to register probes before main() -#define LWTRACE_REGISTER_PROBES(provider) \ - namespace LWTRACE_GET_NAMESPACE(provider) { \ - struct TInitLWTrace##provider { \ - TInitLWTrace##provider() { \ - Singleton<NLWTrace::TProbeRegistry>()->AddProbesList(LWTRACE_GET_PROBES(provider)); \ - } \ - /* This may not be in anonymous namespace because otherwise */ \ - /* it is called twice when .so loaded twice */ \ - }* InitLWTrace##provider = Singleton<TInitLWTrace##provider>(); \ - } \ - /**/ - -// Macro for TSignature POD structure static initialization -#define LWTRACE_SIGNATURE_CTOR(types, names) \ - { \ - /* ParamTypes */ ::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::ParamTypes, \ - /* ParamNames */ {LWTRACE_EXPAND(LWTRACE_UNROLL names)}, \ - /* ParamCount */ ::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::ParamCount, \ - /* SerializeParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::SerializeParams, \ - /* CloneParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::CloneParams, \ +#define LWTRACE_PREPARE_PARAMS(params) \ + do { \ + FOREACH_PARAMNUM(LWTRACE_PREPARE_PARAMS_I, params) \ + } while (false) +#define LWTRACE_COUNT_PARAMS_I(i) +(std::is_same<TP##i, ::NLWTrace::TNil>::value ? 0 : 1) +#define LWTRACE_COUNT_PARAMS (0 FOREACH_PARAMNUM(LWTRACE_COUNT_PARAMS_I)) +#define LWTRACE_MAX_PARAMS_I(i) +1 +#define LWTRACE_MAX_PARAMS (0 FOREACH_PARAMNUM(LWTRACE_MAX_PARAMS_I)) + +// Determine maximum sizeof(t) over all supported types +#define LWTRACE_MAX_PARAM_SIZE_TA_TAIL_I(n, t, v) v, +#define LWTRACE_MAX_PARAM_SIZE_TA_TAIL \ + FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TA_TAIL_I) \ + 0 +#define LWTRACE_MAX_PARAM_SIZE_TP_I(n, t, v) , size_t v = 0 +#define LWTRACE_MAX_PARAM_SIZE_TP size_t Head = 0 FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TP_I) +#define LWTRACE_MAX_PARAM_SIZE_TA_I(n, t, v) , sizeof(t) +#define LWTRACE_MAX_PARAM_SIZE_TA 0 FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TA_I) +#define LWTRACE_MAX_PARAM_SIZE ::NLWTrace::TMaxParamSize<LWTRACE_MAX_PARAM_SIZE_TA>::Result + +namespace NLWTrace { + template <LWTRACE_MAX_PARAM_SIZE_TP> + struct TMaxParamSize { + static const size_t Tail = TMaxParamSize<LWTRACE_MAX_PARAM_SIZE_TA_TAIL>::Result; + static const size_t Result = (Head > Tail ? Head : Tail); + }; + + template <> + struct TMaxParamSize<> { + static const size_t Result = 0; + }; + +} + +// Define stuff that is needed to register probes before main() +#define LWTRACE_REGISTER_PROBES(provider) \ + namespace LWTRACE_GET_NAMESPACE(provider) { \ + struct TInitLWTrace##provider { \ + TInitLWTrace##provider() { \ + Singleton<NLWTrace::TProbeRegistry>()->AddProbesList(LWTRACE_GET_PROBES(provider)); \ + } \ + /* This may not be in anonymous namespace because otherwise */ \ + /* it is called twice when .so loaded twice */ \ + }* InitLWTrace##provider = Singleton<TInitLWTrace##provider>(); \ + } \ + /**/ + +// Macro for TSignature POD structure static initialization +#define LWTRACE_SIGNATURE_CTOR(types, names) \ + { \ + /* ParamTypes */ ::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::ParamTypes, \ + /* ParamNames */ {LWTRACE_EXPAND(LWTRACE_UNROLL names)}, \ + /* ParamCount */ ::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::ParamCount, \ + /* SerializeParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::SerializeParams, \ + /* CloneParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::CloneParams, \ /* DestroyParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::DestroyParams, \ /* SerializeToPb */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::SerializeToPb, \ /* DeserializeFromPb */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::DeserializeFromPb\ - } - -// Macro for TEvent POD structure static initialization -#define LWTRACE_EVENT_CTOR(name, groups, types, names) \ - { \ - /* Name */ #name, \ - /* Groups */ {LWTRACE_EXPAND(LWTRACE_UNROLL_GROUPS groups)}, \ - /* Signature */ LWTRACE_SIGNATURE_CTOR(types, names) \ - } - -// Macro for TProbe POD structure static initialization -#define LWTRACE_PROBE_CTOR(name, groups, types, names) \ - { \ - /* Event */ LWTRACE_EVENT_CTOR(name, groups, types, names), \ - /* ExecutorsCount */ 0, \ - /* Lock */ {0}, \ - /* Executors */ {0}, \ - /* Front */ 0, \ - /* Back */ 0 \ - } - -// Provider static data accessors -#define LWTRACE_GET_NAMESPACE(provider) NLWTrace_##provider -#define LWTRACE_GET_NAME(name) lwtrace_##name -#define LWTRACE_GET_TYPE(name) TLWTrace_##name -#define LWTRACE_GET_PROBES_I(provider) gProbes##provider -#define LWTRACE_GET_EVENTS_I(provider) gEvents##provider - -// Declaration of provider static data -#define LWTRACE_DECLARE_PROBE(name, groups, types, names) \ - typedef ::NLWTrace::TUserProbe<LWTRACE_EXPAND(LWTRACE_UNROLL types)> LWTRACE_GET_TYPE(name); \ - extern LWTRACE_GET_TYPE(name) LWTRACE_GET_NAME(name); \ - /**/ -#define LWTRACE_DECLARE_EVENT(name, groups, types, names) \ - typedef ::NLWTrace::TUserEvent<LWTRACE_EXPAND(LWTRACE_UNROLL types)> LWTRACE_GET_TYPE(name); \ - extern LWTRACE_GET_TYPE(name) LWTRACE_GET_NAME(name); \ - /**/ -#define LWTRACE_DECLARE_PROVIDER_I(provider) \ - namespace LWTRACE_GET_NAMESPACE(provider) { \ - provider(LWTRACE_DECLARE_PROBE, LWTRACE_DECLARE_EVENT, LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \ - } \ - extern ::NLWTrace::TProbe* LWTRACE_GET_PROBES_I(provider)[]; \ - extern ::NLWTrace::TEvent* LWTRACE_GET_EVENTS_I(provider)[]; \ - /**/ - -// Initialization of provider static data -#define LWTRACE_UNROLL_GROUPS(x) #x, LWTRACE_UNROLL -#define LWTRACE_DEFINE_PROBE(name, groups, types, names) \ - LWTRACE_GET_TYPE(name) \ - LWTRACE_GET_NAME(name) = \ - {LWTRACE_PROBE_CTOR(name, groups, types, names)}; \ - /**/ -#define LWTRACE_DEFINE_EVENT(name, groups, types, names) \ - LWTRACE_GET_TYPE(name) \ - LWTRACE_GET_NAME(name) = \ - {LWTRACE_EVENT_CTOR(name, groups, types, names)}; \ - /**/ -#define LWTRACE_PROBE_ADDRESS_I(name, groups, types, names) \ - LWTRACE_GET_NAME(name).Probe, /**/ -#define LWTRACE_PROBE_ADDRESS(provider) \ - &LWTRACE_GET_NAMESPACE(provider)::LWTRACE_PROBE_ADDRESS_I /**/ -#define LWTRACE_EVENT_ADDRESS_I(name, groups, types, names) \ - LWTRACE_GET_NAME(name).Event, /**/ -#define LWTRACE_EVENT_ADDRESS(provider) \ - &LWTRACE_GET_NAMESPACE(provider)::LWTRACE_EVENT_ADDRESS_I /**/ -#define LWTRACE_DEFINE_PROVIDER_I(provider) \ - namespace LWTRACE_GET_NAMESPACE(provider) { \ - provider(LWTRACE_DEFINE_PROBE, LWTRACE_DEFINE_EVENT, (provider)LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \ - } \ - ::NLWTrace::TProbe* LWTRACE_GET_PROBES_I(provider)[] = { \ - provider(LWTRACE_PROBE_ADDRESS(provider), LWTRACE_EAT, LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \ - NULL}; \ - ::NLWTrace::TEvent* LWTRACE_GET_EVENTS_I(provider)[] = { \ - provider(LWTRACE_EAT, LWTRACE_EVENT_ADDRESS(provider), LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \ - NULL}; \ - LWTRACE_REGISTER_PROBES(provider) - /**/ - -#define LWPROBE_I(probe, ...) \ - do { \ - if ((probe).Probe.GetExecutorsCount() > 0) { \ - ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \ - TReadSpinLockGuard g((probe).Probe.Lock); \ - if ((probe).Probe.GetExecutorsCount() > 0) { \ - (probe)(__VA_ARGS__); \ - } \ - } \ - } while (false) /**/ - + } + +// Macro for TEvent POD structure static initialization +#define LWTRACE_EVENT_CTOR(name, groups, types, names) \ + { \ + /* Name */ #name, \ + /* Groups */ {LWTRACE_EXPAND(LWTRACE_UNROLL_GROUPS groups)}, \ + /* Signature */ LWTRACE_SIGNATURE_CTOR(types, names) \ + } + +// Macro for TProbe POD structure static initialization +#define LWTRACE_PROBE_CTOR(name, groups, types, names) \ + { \ + /* Event */ LWTRACE_EVENT_CTOR(name, groups, types, names), \ + /* ExecutorsCount */ 0, \ + /* Lock */ {0}, \ + /* Executors */ {0}, \ + /* Front */ 0, \ + /* Back */ 0 \ + } + +// Provider static data accessors +#define LWTRACE_GET_NAMESPACE(provider) NLWTrace_##provider +#define LWTRACE_GET_NAME(name) lwtrace_##name +#define LWTRACE_GET_TYPE(name) TLWTrace_##name +#define LWTRACE_GET_PROBES_I(provider) gProbes##provider +#define LWTRACE_GET_EVENTS_I(provider) gEvents##provider + +// Declaration of provider static data +#define LWTRACE_DECLARE_PROBE(name, groups, types, names) \ + typedef ::NLWTrace::TUserProbe<LWTRACE_EXPAND(LWTRACE_UNROLL types)> LWTRACE_GET_TYPE(name); \ + extern LWTRACE_GET_TYPE(name) LWTRACE_GET_NAME(name); \ + /**/ +#define LWTRACE_DECLARE_EVENT(name, groups, types, names) \ + typedef ::NLWTrace::TUserEvent<LWTRACE_EXPAND(LWTRACE_UNROLL types)> LWTRACE_GET_TYPE(name); \ + extern LWTRACE_GET_TYPE(name) LWTRACE_GET_NAME(name); \ + /**/ +#define LWTRACE_DECLARE_PROVIDER_I(provider) \ + namespace LWTRACE_GET_NAMESPACE(provider) { \ + provider(LWTRACE_DECLARE_PROBE, LWTRACE_DECLARE_EVENT, LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \ + } \ + extern ::NLWTrace::TProbe* LWTRACE_GET_PROBES_I(provider)[]; \ + extern ::NLWTrace::TEvent* LWTRACE_GET_EVENTS_I(provider)[]; \ + /**/ + +// Initialization of provider static data +#define LWTRACE_UNROLL_GROUPS(x) #x, LWTRACE_UNROLL +#define LWTRACE_DEFINE_PROBE(name, groups, types, names) \ + LWTRACE_GET_TYPE(name) \ + LWTRACE_GET_NAME(name) = \ + {LWTRACE_PROBE_CTOR(name, groups, types, names)}; \ + /**/ +#define LWTRACE_DEFINE_EVENT(name, groups, types, names) \ + LWTRACE_GET_TYPE(name) \ + LWTRACE_GET_NAME(name) = \ + {LWTRACE_EVENT_CTOR(name, groups, types, names)}; \ + /**/ +#define LWTRACE_PROBE_ADDRESS_I(name, groups, types, names) \ + LWTRACE_GET_NAME(name).Probe, /**/ +#define LWTRACE_PROBE_ADDRESS(provider) \ + &LWTRACE_GET_NAMESPACE(provider)::LWTRACE_PROBE_ADDRESS_I /**/ +#define LWTRACE_EVENT_ADDRESS_I(name, groups, types, names) \ + LWTRACE_GET_NAME(name).Event, /**/ +#define LWTRACE_EVENT_ADDRESS(provider) \ + &LWTRACE_GET_NAMESPACE(provider)::LWTRACE_EVENT_ADDRESS_I /**/ +#define LWTRACE_DEFINE_PROVIDER_I(provider) \ + namespace LWTRACE_GET_NAMESPACE(provider) { \ + provider(LWTRACE_DEFINE_PROBE, LWTRACE_DEFINE_EVENT, (provider)LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \ + } \ + ::NLWTrace::TProbe* LWTRACE_GET_PROBES_I(provider)[] = { \ + provider(LWTRACE_PROBE_ADDRESS(provider), LWTRACE_EAT, LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \ + NULL}; \ + ::NLWTrace::TEvent* LWTRACE_GET_EVENTS_I(provider)[] = { \ + provider(LWTRACE_EAT, LWTRACE_EVENT_ADDRESS(provider), LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \ + NULL}; \ + LWTRACE_REGISTER_PROBES(provider) + /**/ + +#define LWPROBE_I(probe, ...) \ + do { \ + if ((probe).Probe.GetExecutorsCount() > 0) { \ + ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \ + TReadSpinLockGuard g((probe).Probe.Lock); \ + if ((probe).Probe.GetExecutorsCount() > 0) { \ + (probe)(__VA_ARGS__); \ + } \ + } \ + } while (false) /**/ + #define LWPROBE_ENABLED_I(probe) ((probe).Probe.GetExecutorsCount() > 0) -#define LWPROBE_DURATION_I(probetype, uniqid, probe, ...) probetype ::TScopedDuration uniqid(probe, 0 /* fake P0 - used for duration */, ##__VA_ARGS__); - -#define LWTRACK_I(probe, orbit, ...) \ - do { \ - if ((probe).Probe.GetExecutorsCount() > 0) { \ - ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \ - TReadSpinLockGuard g((probe).Probe.Lock); \ - if ((probe).Probe.GetExecutorsCount() > 0) { \ - (probe).Run(orbit, ##__VA_ARGS__); \ - } \ - } else { \ - auto& _orbit = (orbit); \ - if (HasShuttles(_orbit)) { \ - ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \ - (probe).RunShuttles(_orbit, ##__VA_ARGS__); \ - } \ - } \ - } while (false) /**/ - -#define LWEVENT_I(event, ...) (event)(__VA_ARGS__) - -#else -#define LWTRACE_MAX_PARAM_SIZE sizeof(void*) -#define LWTRACE_MAX_PARAMS 1 -#define FOREACH_PARAMTYPE(MACRO, ...) - -#endif +#define LWPROBE_DURATION_I(probetype, uniqid, probe, ...) probetype ::TScopedDuration uniqid(probe, 0 /* fake P0 - used for duration */, ##__VA_ARGS__); + +#define LWTRACK_I(probe, orbit, ...) \ + do { \ + if ((probe).Probe.GetExecutorsCount() > 0) { \ + ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \ + TReadSpinLockGuard g((probe).Probe.Lock); \ + if ((probe).Probe.GetExecutorsCount() > 0) { \ + (probe).Run(orbit, ##__VA_ARGS__); \ + } \ + } else { \ + auto& _orbit = (orbit); \ + if (HasShuttles(_orbit)) { \ + ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \ + (probe).RunShuttles(_orbit, ##__VA_ARGS__); \ + } \ + } \ + } while (false) /**/ + +#define LWEVENT_I(event, ...) (event)(__VA_ARGS__) + +#else +#define LWTRACE_MAX_PARAM_SIZE sizeof(void*) +#define LWTRACE_MAX_PARAMS 1 +#define FOREACH_PARAMTYPE(MACRO, ...) + +#endif diff --git a/library/cpp/lwtrace/probe.h b/library/cpp/lwtrace/probe.h index 31fa282da3..1efd2361da 100644 --- a/library/cpp/lwtrace/probe.h +++ b/library/cpp/lwtrace/probe.h @@ -1,266 +1,266 @@ -#pragma once - -#include "event.h" -#include "preprocessor.h" -#include "rwspinlock.h" -#include "shuttle.h" - +#pragma once + +#include "event.h" +#include "preprocessor.h" +#include "rwspinlock.h" +#include "shuttle.h" + #include <util/datetime/cputimer.h> #include <util/generic/hide_ptr.h> #include <util/generic/scope.h> #include <util/system/atomic.h> -namespace NLWTrace { - // Represents a chain (linked list) of steps for execution of a trace query block - // NOTE: different executor objects are used on different probes (even for the same query block) - class IExecutor { - private: - IExecutor* Next; - - public: - IExecutor() - : Next(nullptr) - { - } - - virtual ~IExecutor() { - if (Next != nullptr) { - delete Next; - } - } - - void Execute(TOrbit& orbit, const TParams& params) { - if (DoExecute(orbit, params) && Next != nullptr) { - Next->Execute(orbit, params); - } - } - - void SetNext(IExecutor* next) { - Next = next; - } - - IExecutor* GetNext() { - return Next; - } - - const IExecutor* GetNext() const { - return Next; - } - - protected: - virtual bool DoExecute(TOrbit& orbit, const TParams& params) = 0; - }; - - // Common class for all probes - struct TProbe { - // Const configuration - TEvent Event; - - // State that don't need any locking - TAtomic ExecutorsCount; - - // State that must be accessed under lock - TRWSpinLock Lock; - IExecutor* Executors[LWTRACE_MAX_ACTIONS]; - IExecutor** Front; // Invalid if ExecutorsCount == 0 - IExecutor** Back; // Invalid if ExecutorsCount == 0 - - void Init() { - ExecutorsCount = 0; - Lock.Init(); - Zero(Executors); - Front = nullptr; - Back = nullptr; - } - - IExecutor** First() { - return Executors; - } - - IExecutor** Last() { - return Executors + LWTRACE_MAX_ACTIONS; - } - - void Inc(IExecutor**& it) { - it++; - if (it == Last()) { - it = First(); - } - } - - intptr_t GetExecutorsCount() const { - return AtomicGet(ExecutorsCount); - } - - bool Attach(IExecutor* exec) { - TWriteSpinLockGuard g(Lock); - if (ExecutorsCount > 0) { - for (IExecutor** it = Front;; Inc(it)) { - if (*it == nullptr) { - *it = exec; - AtomicIncrement(ExecutorsCount); - return true; // Inserted into free slot in [First; Last] - } - if (it == Back) { - break; - } - } - IExecutor** newBack = Back; - Inc(newBack); - if (newBack == Front) { - return false; // Buffer is full - } else { - Back = newBack; - *Back = exec; - AtomicIncrement(ExecutorsCount); - return true; // Inserted after Last - } - } else { - Front = Back = First(); - *Front = exec; - AtomicIncrement(ExecutorsCount); - return true; // Inserted as a first element - } - } - - bool Detach(IExecutor* exec) { - TWriteSpinLockGuard g(Lock); - for (IExecutor** it = First(); it != Last(); it++) { - if ((*it) == exec) { - *it = nullptr; - AtomicDecrement(ExecutorsCount); - if (ExecutorsCount > 0) { - for (;; Inc(Front)) { - if (*Front != nullptr) { - break; - } - if (Front == Back) { - break; - } - } - } - return true; - } - } - return false; - } - - void RunExecutors(TOrbit& orbit, const TParams& params) { - // Read lock is implied - if (ExecutorsCount > 0) { - for (IExecutor** it = Front;; Inc(it)) { - IExecutor* exec = *it; - if (exec) { - exec->Execute(orbit, params); - } - if (it == Back) { - break; - } - } - } - } - - void RunShuttles(TOrbit& orbit, const TParams& params) { - orbit.AddProbe(this, params); - } - }; - -#ifndef LWTRACE_DISABLE - - template <class T> - inline void PreparePtr(const T& ref, const T*& ptr) { - ptr = &ref; - } - - template <> - inline void PreparePtr<TNil>(const TNil&, const TNil*&) { - } - +namespace NLWTrace { + // Represents a chain (linked list) of steps for execution of a trace query block + // NOTE: different executor objects are used on different probes (even for the same query block) + class IExecutor { + private: + IExecutor* Next; + + public: + IExecutor() + : Next(nullptr) + { + } + + virtual ~IExecutor() { + if (Next != nullptr) { + delete Next; + } + } + + void Execute(TOrbit& orbit, const TParams& params) { + if (DoExecute(orbit, params) && Next != nullptr) { + Next->Execute(orbit, params); + } + } + + void SetNext(IExecutor* next) { + Next = next; + } + + IExecutor* GetNext() { + return Next; + } + + const IExecutor* GetNext() const { + return Next; + } + + protected: + virtual bool DoExecute(TOrbit& orbit, const TParams& params) = 0; + }; + + // Common class for all probes + struct TProbe { + // Const configuration + TEvent Event; + + // State that don't need any locking + TAtomic ExecutorsCount; + + // State that must be accessed under lock + TRWSpinLock Lock; + IExecutor* Executors[LWTRACE_MAX_ACTIONS]; + IExecutor** Front; // Invalid if ExecutorsCount == 0 + IExecutor** Back; // Invalid if ExecutorsCount == 0 + + void Init() { + ExecutorsCount = 0; + Lock.Init(); + Zero(Executors); + Front = nullptr; + Back = nullptr; + } + + IExecutor** First() { + return Executors; + } + + IExecutor** Last() { + return Executors + LWTRACE_MAX_ACTIONS; + } + + void Inc(IExecutor**& it) { + it++; + if (it == Last()) { + it = First(); + } + } + + intptr_t GetExecutorsCount() const { + return AtomicGet(ExecutorsCount); + } + + bool Attach(IExecutor* exec) { + TWriteSpinLockGuard g(Lock); + if (ExecutorsCount > 0) { + for (IExecutor** it = Front;; Inc(it)) { + if (*it == nullptr) { + *it = exec; + AtomicIncrement(ExecutorsCount); + return true; // Inserted into free slot in [First; Last] + } + if (it == Back) { + break; + } + } + IExecutor** newBack = Back; + Inc(newBack); + if (newBack == Front) { + return false; // Buffer is full + } else { + Back = newBack; + *Back = exec; + AtomicIncrement(ExecutorsCount); + return true; // Inserted after Last + } + } else { + Front = Back = First(); + *Front = exec; + AtomicIncrement(ExecutorsCount); + return true; // Inserted as a first element + } + } + + bool Detach(IExecutor* exec) { + TWriteSpinLockGuard g(Lock); + for (IExecutor** it = First(); it != Last(); it++) { + if ((*it) == exec) { + *it = nullptr; + AtomicDecrement(ExecutorsCount); + if (ExecutorsCount > 0) { + for (;; Inc(Front)) { + if (*Front != nullptr) { + break; + } + if (Front == Back) { + break; + } + } + } + return true; + } + } + return false; + } + + void RunExecutors(TOrbit& orbit, const TParams& params) { + // Read lock is implied + if (ExecutorsCount > 0) { + for (IExecutor** it = Front;; Inc(it)) { + IExecutor* exec = *it; + if (exec) { + exec->Execute(orbit, params); + } + if (it == Back) { + break; + } + } + } + } + + void RunShuttles(TOrbit& orbit, const TParams& params) { + orbit.AddProbe(this, params); + } + }; + +#ifndef LWTRACE_DISABLE + + template <class T> + inline void PreparePtr(const T& ref, const T*& ptr) { + ptr = &ref; + } + + template <> + inline void PreparePtr<TNil>(const TNil&, const TNil*&) { + } + #define LWTRACE_SCOPED_FUNCTION_PARAMS_I(i) (1) typename ::NLWTrace::TParamTraits<TP##i>::TFuncParam p##i = ERROR_not_enough_parameters() LWTRACE_COMMA -#define LWTRACE_SCOPED_FUNCTION_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_SCOPED_FUNCTION_PARAMS_I)(0)) -#define LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF_I(i) (1) typename ::NLWTrace::TParamTraits<TP##i>::TStoreType& p##i = *(ERROR_not_enough_parameters*)(HidePointerOrigin(nullptr))LWTRACE_COMMA -#define LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF_I)(0)) -#define LWTRACE_SCOPED_PREPARE_PTRS_I(i) PreparePtr(p##i, P##i); -#define LWTRACE_SCOPED_PREPARE_PTRS() \ - do { \ - FOREACH_PARAMNUM(LWTRACE_SCOPED_PREPARE_PTRS_I) \ - } while (false) -#define LWTRACE_SCOPED_PREPARE_PARAMS_I(i, params) params.Param[i].CopyConstruct<typename ::NLWTrace::TParamTraits<TP##i>::TStoreType>(*P##i); -#define LWTRACE_SCOPED_PREPARE_PARAMS(params) \ - do { \ - FOREACH_PARAMNUM(LWTRACE_SCOPED_PREPARE_PARAMS_I, params) \ - } while (false) - - template <LWTRACE_TEMPLATE_PARAMS> - struct TUserProbe; - - template <LWTRACE_TEMPLATE_PARAMS> - class TScopedDurationImpl { - private: - TUserProbe<LWTRACE_TEMPLATE_ARGS>* Probe; - ui64 Started; - TParams Params; - - public: - explicit TScopedDurationImpl(TUserProbe<LWTRACE_TEMPLATE_ARGS>& probe, LWTRACE_SCOPED_FUNCTION_PARAMS) { - if (probe.Probe.GetExecutorsCount() > 0) { - Probe = &probe; - LWTRACE_PREPARE_PARAMS(Params); - Started = GetCycleCount(); - } else { - Probe = nullptr; - } - } - ~TScopedDurationImpl() { - if (Probe) { - if (Probe->Probe.GetExecutorsCount() > 0) { - TReadSpinLockGuard g(Probe->Probe.Lock); - if (Probe->Probe.GetExecutorsCount() > 0) { - ui64 duration = CyclesToDuration(GetCycleCount() - Started).MicroSeconds(); - Params.Param[0].template CopyConstruct<typename TParamTraits<TP0>::TStoreType>(duration); - TOrbit orbit; - Probe->Probe.RunExecutors(orbit, Params); - } - } - TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(Params); - } - } - }; - - // Class representing a specific probe - template <LWTRACE_TEMPLATE_PARAMS_NODEF> - struct TUserProbe { - TProbe Probe; - - inline void operator()(LWTRACE_FUNCTION_PARAMS) { - TParams params; - LWTRACE_PREPARE_PARAMS(params); +#define LWTRACE_SCOPED_FUNCTION_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_SCOPED_FUNCTION_PARAMS_I)(0)) +#define LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF_I(i) (1) typename ::NLWTrace::TParamTraits<TP##i>::TStoreType& p##i = *(ERROR_not_enough_parameters*)(HidePointerOrigin(nullptr))LWTRACE_COMMA +#define LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF_I)(0)) +#define LWTRACE_SCOPED_PREPARE_PTRS_I(i) PreparePtr(p##i, P##i); +#define LWTRACE_SCOPED_PREPARE_PTRS() \ + do { \ + FOREACH_PARAMNUM(LWTRACE_SCOPED_PREPARE_PTRS_I) \ + } while (false) +#define LWTRACE_SCOPED_PREPARE_PARAMS_I(i, params) params.Param[i].CopyConstruct<typename ::NLWTrace::TParamTraits<TP##i>::TStoreType>(*P##i); +#define LWTRACE_SCOPED_PREPARE_PARAMS(params) \ + do { \ + FOREACH_PARAMNUM(LWTRACE_SCOPED_PREPARE_PARAMS_I, params) \ + } while (false) + + template <LWTRACE_TEMPLATE_PARAMS> + struct TUserProbe; + + template <LWTRACE_TEMPLATE_PARAMS> + class TScopedDurationImpl { + private: + TUserProbe<LWTRACE_TEMPLATE_ARGS>* Probe; + ui64 Started; + TParams Params; + + public: + explicit TScopedDurationImpl(TUserProbe<LWTRACE_TEMPLATE_ARGS>& probe, LWTRACE_SCOPED_FUNCTION_PARAMS) { + if (probe.Probe.GetExecutorsCount() > 0) { + Probe = &probe; + LWTRACE_PREPARE_PARAMS(Params); + Started = GetCycleCount(); + } else { + Probe = nullptr; + } + } + ~TScopedDurationImpl() { + if (Probe) { + if (Probe->Probe.GetExecutorsCount() > 0) { + TReadSpinLockGuard g(Probe->Probe.Lock); + if (Probe->Probe.GetExecutorsCount() > 0) { + ui64 duration = CyclesToDuration(GetCycleCount() - Started).MicroSeconds(); + Params.Param[0].template CopyConstruct<typename TParamTraits<TP0>::TStoreType>(duration); + TOrbit orbit; + Probe->Probe.RunExecutors(orbit, Params); + } + } + TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(Params); + } + } + }; + + // Class representing a specific probe + template <LWTRACE_TEMPLATE_PARAMS_NODEF> + struct TUserProbe { + TProbe Probe; + + inline void operator()(LWTRACE_FUNCTION_PARAMS) { + TParams params; + LWTRACE_PREPARE_PARAMS(params); Y_DEFER { TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(params); }; - TOrbit orbit; - Probe.RunExecutors(orbit, params); - } - - inline void Run(TOrbit& orbit, LWTRACE_FUNCTION_PARAMS) { - TParams params; - LWTRACE_PREPARE_PARAMS(params); + TOrbit orbit; + Probe.RunExecutors(orbit, params); + } + + inline void Run(TOrbit& orbit, LWTRACE_FUNCTION_PARAMS) { + TParams params; + LWTRACE_PREPARE_PARAMS(params); Y_DEFER { TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(params); }; - Probe.RunExecutors(orbit, params); - Probe.RunShuttles(orbit, params); // Executors can create shuttles - } - - // Required to avoid running executors w/o lock - inline void RunShuttles(TOrbit& orbit, LWTRACE_FUNCTION_PARAMS) { - TParams params; - LWTRACE_PREPARE_PARAMS(params); - Probe.RunShuttles(orbit, params); - TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(params); - } - - typedef TScopedDurationImpl<LWTRACE_TEMPLATE_ARGS> TScopedDuration; - }; - -#endif - -} + Probe.RunExecutors(orbit, params); + Probe.RunShuttles(orbit, params); // Executors can create shuttles + } + + // Required to avoid running executors w/o lock + inline void RunShuttles(TOrbit& orbit, LWTRACE_FUNCTION_PARAMS) { + TParams params; + LWTRACE_PREPARE_PARAMS(params); + Probe.RunShuttles(orbit, params); + TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(params); + } + + typedef TScopedDurationImpl<LWTRACE_TEMPLATE_ARGS> TScopedDuration; + }; + +#endif + +} diff --git a/library/cpp/lwtrace/probes.cpp b/library/cpp/lwtrace/probes.cpp index 6f19da0cc8..dba318d340 100644 --- a/library/cpp/lwtrace/probes.cpp +++ b/library/cpp/lwtrace/probes.cpp @@ -1,3 +1,3 @@ -#include "probes.h" - -LWTRACE_DEFINE_PROVIDER(LWTRACE_INTERNAL_PROVIDER) +#include "probes.h" + +LWTRACE_DEFINE_PROVIDER(LWTRACE_INTERNAL_PROVIDER) diff --git a/library/cpp/lwtrace/probes.h b/library/cpp/lwtrace/probes.h index 68810bd118..6c11355038 100644 --- a/library/cpp/lwtrace/probes.h +++ b/library/cpp/lwtrace/probes.h @@ -1,12 +1,12 @@ -#pragma once - +#pragma once + #include "all.h" - -#define LWTRACE_INTERNAL_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ - PROBE(PerfReport, GROUPS(), \ - TYPES(double, double, double, double), \ - NAMES("probeShare", "probeMinMs", "probeMaxMs", "probeAvgMs")) \ - PROBE(DeserializationError, GROUPS("LWTraceError"), \ + +#define LWTRACE_INTERNAL_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(PerfReport, GROUPS(), \ + TYPES(double, double, double, double), \ + NAMES("probeShare", "probeMinMs", "probeMaxMs", "probeAvgMs")) \ + PROBE(DeserializationError, GROUPS("LWTraceError"), \ TYPES(TString, TString), \ NAMES("probeName", "providerName")) \ PROBE(Fork, GROUPS(), \ @@ -15,9 +15,9 @@ PROBE(Join, GROUPS(), \ TYPES(ui64, ui64), \ NAMES("spanId", "trackLength")) \ - PROBE(OrbitIsUsedConcurrentlyError, GROUPS("LWTraceError"), \ - TYPES(TString), \ - NAMES("backtrace")) \ - /**/ - -LWTRACE_DECLARE_PROVIDER(LWTRACE_INTERNAL_PROVIDER) + PROBE(OrbitIsUsedConcurrentlyError, GROUPS("LWTraceError"), \ + TYPES(TString), \ + NAMES("backtrace")) \ + /**/ + +LWTRACE_DECLARE_PROVIDER(LWTRACE_INTERNAL_PROVIDER) diff --git a/library/cpp/lwtrace/protos/lwtrace.proto b/library/cpp/lwtrace/protos/lwtrace.proto index 0051095719..4c07b54625 100644 --- a/library/cpp/lwtrace/protos/lwtrace.proto +++ b/library/cpp/lwtrace/protos/lwtrace.proto @@ -1,64 +1,64 @@ -/* - * This file defines language for trace queries and serialization format for trace logs - */ +/* + * This file defines language for trace queries and serialization format for trace logs + */ syntax = "proto3"; -package NLWTrace; - +package NLWTrace; + option go_package = "a.yandex-team.ru/library/cpp/lwtrace/protos"; -message TProbeDesc { +message TProbeDesc { string Name = 1; // Use either name+provider string Provider = 3; string Group = 2; // or group -} - -enum EOperatorType { +} + +enum EOperatorType { OT_EQ = 0; OT_NE = 1; OT_LT = 2; OT_LE = 3; OT_GT = 4; OT_GE = 5; -} - +} + message TArgument { string Param = 1; - bytes Value = 2; + bytes Value = 2; string Variable = 3; } -message TOperator { +message TOperator { EOperatorType Type = 1; repeated TArgument Argument = 8; -} - -message TPredicate { - repeated TOperator Operators = 1; // All operators are combined using logical AND - double SampleRate = 2; // value 1.0 means trigger actions on 100% events (do not sample if value is not set) -} - -message TLogAction { +} + +message TPredicate { + repeated TOperator Operators = 1; // All operators are combined using logical AND + double SampleRate = 2; // value 1.0 means trigger actions on 100% events (do not sample if value is not set) +} + +message TLogAction { bool DoNotLogParams = 2; bool LogTimestamp = 3; uint32 MaxRecords = 4; // Do not write more than MaxRecords records to the log (count from the trace beginning, not start) -} - +} + message TPrintToStderrAction { } message TKillAction { -} - +} + message TSleepAction { uint64 NanoSeconds = 1; -} - -message TCustomAction { +} + +message TCustomAction { string Name = 1; - repeated string Opts = 2; -} - + repeated string Opts = 2; +} + enum EStatementType { ST_MOV = 0; ST_ADD = 1; @@ -77,133 +77,133 @@ message TStatementAction { repeated TArgument Argument = 2; } -message TRunLogShuttleAction { +message TRunLogShuttleAction { bool Ignore = 1; uint64 ShuttlesCount = 2; uint64 MaxTrackLength = 3; -} - -message TEditLogShuttleAction { +} + +message TEditLogShuttleAction { bool Ignore = 1; -} - -message TDropLogShuttleAction { -} - -message TAction { +} + +message TDropLogShuttleAction { +} + +message TAction { TLogAction LogAction = 2; TPrintToStderrAction PrintToStderrAction = 3; TCustomAction CustomAction = 4; TKillAction KillAction = 6; TSleepAction SleepAction = 7; TStatementAction StatementAction = 8; - + TRunLogShuttleAction RunLogShuttleAction = 100; TEditLogShuttleAction EditLogShuttleAction = 101; TDropLogShuttleAction DropLogShuttleAction = 102; -} - -message TBlock { +} + +message TBlock { TProbeDesc ProbeDesc = 1; TPredicate Predicate = 2; repeated TAction Action = 3; -} - -message TQuery { - // Number of events to hold for every thread in cyclic buffer - // (Won't be used if LogDurationUs is set to non-zero value) +} + +message TQuery { + // Number of events to hold for every thread in cyclic buffer + // (Won't be used if LogDurationUs is set to non-zero value) uint32 PerThreadLogSize = 1; - - // Hold events for last Duration microseconds - // (If zero, than per-thread cyclic buffer will be used to store events) + + // Hold events for last Duration microseconds + // (If zero, than per-thread cyclic buffer will be used to store events) uint64 LogDurationUs = 2; - - repeated TBlock Blocks = 3; -} - -message TDashboard { - message TCell { - optional string Url = 1; - optional string Title = 2; - optional string Text = 3; - optional uint32 RowSpan = 4; - optional uint32 ColSpan = 5; - } - - message TRow { - repeated TCell Cells = 1; - } - - optional string Name = 1; - optional string Description = 2; - repeated TRow Rows = 3; -} - -////////////////////////////////////////////////////////////////////////////////////////////// -// Serialization format for trace logs // -////////////////////////////////////////////////////////////////////////////////////////////// -enum EParamTypePb { - PT_UNKNOWN = 0; - PT_I64 = 1; - PT_Ui64 = 2; - PT_Double = 3; - PT_Str = 4; - PT_Symbol = 5; - PT_Check = 6; -} - -message TEventPb { + + repeated TBlock Blocks = 3; +} + +message TDashboard { + message TCell { + optional string Url = 1; + optional string Title = 2; + optional string Text = 3; + optional uint32 RowSpan = 4; + optional uint32 ColSpan = 5; + } + + message TRow { + repeated TCell Cells = 1; + } + + optional string Name = 1; + optional string Description = 2; + repeated TRow Rows = 3; +} + +////////////////////////////////////////////////////////////////////////////////////////////// +// Serialization format for trace logs // +////////////////////////////////////////////////////////////////////////////////////////////// +enum EParamTypePb { + PT_UNKNOWN = 0; + PT_I64 = 1; + PT_Ui64 = 2; + PT_Double = 3; + PT_Str = 4; + PT_Symbol = 5; + PT_Check = 6; +} + +message TEventPb { string Name = 1; - repeated string Groups = 2; // First group is provider - repeated EParamTypePb ParamTypes = 3; - repeated string ParamNames = 4; -} - -message TLogItemPb { + repeated string Groups = 2; // First group is provider + repeated EParamTypePb ParamTypes = 3; + repeated string ParamNames = 4; +} + +message TLogItemPb { uint64 Thread = 1; string Name = 2; string Provider = 3; - repeated bytes Params = 4; + repeated bytes Params = 4; uint64 Timestamp = 5; // microseconds since epoch uint64 TimestampCycles = 6; // cycles since machine boot -} - -message TThreadLogPb { +} + +message TThreadLogPb { uint64 ThreadId = 1; - repeated TLogItemPb LogItems = 2; -} - -message TLogPb { - // Trace info + repeated TLogItemPb LogItems = 2; +} + +message TLogPb { + // Trace info string Name = 1; string Description = 2; uint64 EventsCount = 3; uint64 CrtTime = 4; // Log creation time (seconds since epoch) - - // Traced host info + + // Traced host info string Hostname = 101; - - // Traced process info + + // Traced process info string ProcessName = 201; - bytes CommandLine = 202; + bytes CommandLine = 202; uint64 ProcessStartTime = 203; uint64 Pid = 204; string VersionInfo = 205; // Svn info - - // Trace query and results + + // Trace query and results TQuery Query = 301; - repeated TEventPb Events = 302; - repeated TThreadLogPb ThreadLogs = 303; -} - -message TShuttlePb { - repeated TLogPb Parts = 1; + repeated TEventPb Events = 302; + repeated TThreadLogPb ThreadLogs = 303; +} + +message TShuttlePb { + repeated TLogPb Parts = 1; TQuery Query = 2; -} - -message TOrbitPb { - repeated TShuttlePb Shuttles = 1; -} +} + +message TOrbitPb { + repeated TShuttlePb Shuttles = 1; +} //////////////////////////////////////////////////////////////////////////////// // Trace parameter. @@ -216,7 +216,7 @@ message TTraceParam int64 IntValue = 2; uint64 UintValue = 3; double DoubleValue = 4; - bytes StrValue = 5; + bytes StrValue = 5; } } diff --git a/library/cpp/lwtrace/protos/ya.make b/library/cpp/lwtrace/protos/ya.make index 503d5e515f..424bdd443b 100644 --- a/library/cpp/lwtrace/protos/ya.make +++ b/library/cpp/lwtrace/protos/ya.make @@ -1,6 +1,6 @@ -PROTO_LIBRARY() +PROTO_LIBRARY() -OWNER(serxa) +OWNER(serxa) INCLUDE_TAGS(GO_PROTO) diff --git a/library/cpp/lwtrace/rwspinlock.h b/library/cpp/lwtrace/rwspinlock.h index 7c518ec49e..bd04e2120f 100644 --- a/library/cpp/lwtrace/rwspinlock.h +++ b/library/cpp/lwtrace/rwspinlock.h @@ -1,88 +1,88 @@ -#pragma once - -#include <util/system/spinlock.h> - -// State can be one of: -// 0) [NOT_USED] State = 0: -// * any reader can acquire lock (State += 2: -> READING) -// * one writer can acquire lock (State = -1: -> WRITING) -// 1) [READING] even number: -// * State/2 = number of active readers -// * no writers are waiting -// * any reader can aqcuire lock (State += 2: -> READING) -// * active readers can release lock (State -= 2) -// * one writer can acquire lock (State += 1: -> WAITING) -// 2) [WAITING] odd number > 0: -// * (State-1)/2 = number of active readers -// * no more readers/writers can acquire lock -// * active readers can release lock (State -= 2: -> WAITING) -// * exactly one writer is waiting for active readers to release lock -// * if no more active readers left (State == 1) waiting writer acquires lock (State = -1: -> WRITING) -// 3) [WRITING] State = -1 -// * exactly one active writer -// * no active readers -// * no more readers/writers can acquire lock -// * writer can release lock (State = 0: -> READING) - -struct TRWSpinLock { - TAtomic State; // must be initialized by 'TRWSpinLock myLock = {0};' construction - - void Init() noexcept { - State = 0; - } - - void AcquireRead() noexcept { - while (true) { - TAtomic a = AtomicGet(State); - if ((a & 1) == 0 && AtomicCas(&State, a + 2, a)) { - break; - } - SpinLockPause(); - } - } - - void ReleaseRead() noexcept { - AtomicAdd(State, -2); - } - - void AcquireWrite() noexcept { - while (true) { - TAtomic a = AtomicGet(State); - if ((a & 1) == 0 && AtomicCas(&State, a + 1, a)) { - break; - } - SpinLockPause(); - } - +#pragma once + +#include <util/system/spinlock.h> + +// State can be one of: +// 0) [NOT_USED] State = 0: +// * any reader can acquire lock (State += 2: -> READING) +// * one writer can acquire lock (State = -1: -> WRITING) +// 1) [READING] even number: +// * State/2 = number of active readers +// * no writers are waiting +// * any reader can aqcuire lock (State += 2: -> READING) +// * active readers can release lock (State -= 2) +// * one writer can acquire lock (State += 1: -> WAITING) +// 2) [WAITING] odd number > 0: +// * (State-1)/2 = number of active readers +// * no more readers/writers can acquire lock +// * active readers can release lock (State -= 2: -> WAITING) +// * exactly one writer is waiting for active readers to release lock +// * if no more active readers left (State == 1) waiting writer acquires lock (State = -1: -> WRITING) +// 3) [WRITING] State = -1 +// * exactly one active writer +// * no active readers +// * no more readers/writers can acquire lock +// * writer can release lock (State = 0: -> READING) + +struct TRWSpinLock { + TAtomic State; // must be initialized by 'TRWSpinLock myLock = {0};' construction + + void Init() noexcept { + State = 0; + } + + void AcquireRead() noexcept { + while (true) { + TAtomic a = AtomicGet(State); + if ((a & 1) == 0 && AtomicCas(&State, a + 2, a)) { + break; + } + SpinLockPause(); + } + } + + void ReleaseRead() noexcept { + AtomicAdd(State, -2); + } + + void AcquireWrite() noexcept { + while (true) { + TAtomic a = AtomicGet(State); + if ((a & 1) == 0 && AtomicCas(&State, a + 1, a)) { + break; + } + SpinLockPause(); + } + while (!AtomicCas(&State, TAtomicBase(-1), 1)) { - SpinLockPause(); - } - } - - void ReleaseWrite() noexcept { - AtomicSet(State, 0); - } -}; - -struct TRWSpinLockReadOps { - static inline void Acquire(TRWSpinLock* t) noexcept { - t->AcquireRead(); - } - - static inline void Release(TRWSpinLock* t) noexcept { - t->ReleaseRead(); - } -}; - -struct TRWSpinLockWriteOps { - static inline void Acquire(TRWSpinLock* t) noexcept { - t->AcquireWrite(); - } - - static inline void Release(TRWSpinLock* t) noexcept { - t->ReleaseWrite(); - } -}; - + SpinLockPause(); + } + } + + void ReleaseWrite() noexcept { + AtomicSet(State, 0); + } +}; + +struct TRWSpinLockReadOps { + static inline void Acquire(TRWSpinLock* t) noexcept { + t->AcquireRead(); + } + + static inline void Release(TRWSpinLock* t) noexcept { + t->ReleaseRead(); + } +}; + +struct TRWSpinLockWriteOps { + static inline void Acquire(TRWSpinLock* t) noexcept { + t->AcquireWrite(); + } + + static inline void Release(TRWSpinLock* t) noexcept { + t->ReleaseWrite(); + } +}; + using TReadSpinLockGuard = TGuard<TRWSpinLock, TRWSpinLockReadOps>; using TWriteSpinLockGuard = TGuard<TRWSpinLock, TRWSpinLockWriteOps>; diff --git a/library/cpp/lwtrace/shuttle.cpp b/library/cpp/lwtrace/shuttle.cpp index 6ef6982aea..de506004ee 100644 --- a/library/cpp/lwtrace/shuttle.cpp +++ b/library/cpp/lwtrace/shuttle.cpp @@ -1,20 +1,20 @@ -#include "shuttle.h" - -#include "probes.h" - -#include <util/system/backtrace.h> -#include <util/stream/str.h> - -namespace NLWTrace { - LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER); - - inline TString CurrentBackTrace() { - TStringStream ss; - FormatBackTrace(&ss); - return ss.Str(); - } - - void TOrbit::LockFailed() { - LWPROBE(OrbitIsUsedConcurrentlyError, CurrentBackTrace()); - } -} // namespace NLWTrace +#include "shuttle.h" + +#include "probes.h" + +#include <util/system/backtrace.h> +#include <util/stream/str.h> + +namespace NLWTrace { + LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER); + + inline TString CurrentBackTrace() { + TStringStream ss; + FormatBackTrace(&ss); + return ss.Str(); + } + + void TOrbit::LockFailed() { + LWPROBE(OrbitIsUsedConcurrentlyError, CurrentBackTrace()); + } +} // namespace NLWTrace diff --git a/library/cpp/lwtrace/shuttle.h b/library/cpp/lwtrace/shuttle.h index 85c6e4da61..24c38e4c47 100644 --- a/library/cpp/lwtrace/shuttle.h +++ b/library/cpp/lwtrace/shuttle.h @@ -1,45 +1,45 @@ -#pragma once - +#pragma once + #include "event.h" #include <library/cpp/containers/stack_vector/stack_vec.h> -#include <util/generic/ptr.h> -#include <util/system/spinlock.h> - +#include <util/generic/ptr.h> +#include <util/system/spinlock.h> + #include <algorithm> -#include <type_traits> - -namespace NLWTrace { - struct TProbe; - - class IShuttle; - using TShuttlePtr = TIntrusivePtr<IShuttle>; - - // Represents interface of tracing context passing by application between probes - class alignas(8) IShuttle: public TThrRefBase { - private: - ui64 TraceIdx; +#include <type_traits> + +namespace NLWTrace { + struct TProbe; + + class IShuttle; + using TShuttlePtr = TIntrusivePtr<IShuttle>; + + // Represents interface of tracing context passing by application between probes + class alignas(8) IShuttle: public TThrRefBase { + private: + ui64 TraceIdx; ui64 SpanId; ui64 ParentSpanId = 0; - TAtomic Status = 0; - static constexpr ui64 DeadFlag = 0x1ull; - TShuttlePtr Next; - - public: + TAtomic Status = 0; + static constexpr ui64 DeadFlag = 0x1ull; + TShuttlePtr Next; + + public: explicit IShuttle(ui64 traceIdx, ui64 spanId) - : TraceIdx(traceIdx) + : TraceIdx(traceIdx) , SpanId(spanId) - { - } - - virtual ~IShuttle() { - } - - ui64 GetTraceIdx() const { - return TraceIdx; - } - + { + } + + virtual ~IShuttle() { + } + + ui64 GetTraceIdx() const { + return TraceIdx; + } + ui64 GetSpanId() const { return SpanId; } @@ -52,130 +52,130 @@ namespace NLWTrace { ParentSpanId = parentSpanId; } - template <class F, class R> - R UnlessDead(F func, R dead) { - while (true) { - ui64 status = AtomicGet(Status); - if (status & DeadFlag) { - return dead; - } - if (AtomicCas(&Status, status + 2, status)) { - R result = func(); - ATOMIC_COMPILER_BARRIER(); - AtomicSub(Status, 2); - return result; - } - } - } - - template <class F> - void UnlessDead(F func) { - while (true) { - ui64 status = AtomicGet(Status); - if (status & DeadFlag) { - return; - } - if (AtomicCas(&Status, status + 2, status)) { - func(); - ATOMIC_COMPILER_BARRIER(); - AtomicSub(Status, 2); - return; - } + template <class F, class R> + R UnlessDead(F func, R dead) { + while (true) { + ui64 status = AtomicGet(Status); + if (status & DeadFlag) { + return dead; + } + if (AtomicCas(&Status, status + 2, status)) { + R result = func(); + ATOMIC_COMPILER_BARRIER(); + AtomicSub(Status, 2); + return result; + } } } - void Serialize(TShuttleTrace& msg) { - UnlessDead([&] { - DoSerialize(msg); - }); - } - - // Returns false iff shuttle should be destroyed + template <class F> + void UnlessDead(F func) { + while (true) { + ui64 status = AtomicGet(Status); + if (status & DeadFlag) { + return; + } + if (AtomicCas(&Status, status + 2, status)) { + func(); + ATOMIC_COMPILER_BARRIER(); + AtomicSub(Status, 2); + return; + } + } + } + + void Serialize(TShuttleTrace& msg) { + UnlessDead([&] { + DoSerialize(msg); + }); + } + + // Returns false iff shuttle should be destroyed bool AddProbe(TProbe* probe, const TParams& params, ui64 timestamp = 0) { - return UnlessDead([&] { - return DoAddProbe(probe, params, timestamp); - }, false); - } - - // Track object was destroyed - void EndOfTrack() { - if (Next) { - Next->EndOfTrack(); - Next.Reset(); - } - UnlessDead([&] { - DoEndOfTrack(); - }); - } - - // Shuttle was dropped from orbit - TShuttlePtr Drop() { - UnlessDead([&] { - DoDrop(); - }); + return UnlessDead([&] { + return DoAddProbe(probe, params, timestamp); + }, false); + } + + // Track object was destroyed + void EndOfTrack() { + if (Next) { + Next->EndOfTrack(); + Next.Reset(); + } + UnlessDead([&] { + DoEndOfTrack(); + }); + } + + // Shuttle was dropped from orbit + TShuttlePtr Drop() { + UnlessDead([&] { + DoDrop(); + }); return Detach(); // Detached from orbit on Drop } TShuttlePtr Detach() { - TShuttlePtr result; + TShuttlePtr result; result.Swap(Next); - return result; - } - - // Trace session was destroyed - void Kill() { - AtomicAdd(Status, 1); // Sets DeadFlag - while (AtomicGet(Status) != 1) { // Wait until any vcall is over - SpinLockPause(); - } - // After this point all virtual calls on shuttle are disallowed - ATOMIC_COMPILER_BARRIER(); - } - - const TShuttlePtr& GetNext() const { - return Next; - } - - TShuttlePtr& GetNext() { - return Next; - } - - void SetNext(const TShuttlePtr& next) { - Next = next; - } - - bool Fork(TShuttlePtr& child) { - return UnlessDead([&] { - return DoFork(child); - }, true); + return result; + } + + // Trace session was destroyed + void Kill() { + AtomicAdd(Status, 1); // Sets DeadFlag + while (AtomicGet(Status) != 1) { // Wait until any vcall is over + SpinLockPause(); + } + // After this point all virtual calls on shuttle are disallowed + ATOMIC_COMPILER_BARRIER(); + } + + const TShuttlePtr& GetNext() const { + return Next; + } + + TShuttlePtr& GetNext() { + return Next; + } + + void SetNext(const TShuttlePtr& next) { + Next = next; + } + + bool Fork(TShuttlePtr& child) { + return UnlessDead([&] { + return DoFork(child); + }, true); } bool Join(TShuttlePtr& child) { - return UnlessDead([&] { - return DoJoin(child); - }, false); + return UnlessDead([&] { + return DoJoin(child); + }, false); } bool IsDead() { return AtomicGet(Status) & DeadFlag; } - protected: + protected: virtual bool DoAddProbe(TProbe* probe, const TParams& params, ui64 timestamp) = 0; - virtual void DoEndOfTrack() = 0; - virtual void DoDrop() = 0; + virtual void DoEndOfTrack() = 0; + virtual void DoDrop() = 0; virtual void DoSerialize(TShuttleTrace& msg) = 0; - virtual bool DoFork(TShuttlePtr& child) = 0; + virtual bool DoFork(TShuttlePtr& child) = 0; virtual bool DoJoin(const TShuttlePtr& child) = 0; - }; - - // Not thread-safe orbit - // Orbit should not be used concurrenty, lock is used - // to ensure this is the case and avoid race condition if not. - class TOrbit { - private: - TShuttlePtr HeadNoLock; - public: + }; + + // Not thread-safe orbit + // Orbit should not be used concurrenty, lock is used + // to ensure this is the case and avoid race condition if not. + class TOrbit { + private: + TShuttlePtr HeadNoLock; + public: TOrbit() = default; TOrbit(const TOrbit&) = delete; TOrbit(TOrbit&&) = default; @@ -183,135 +183,135 @@ namespace NLWTrace { TOrbit& operator=(const TOrbit&) = delete; TOrbit& operator=(TOrbit&&) = default; - ~TOrbit() { - Reset(); - } - - void Reset() { - NotConcurrent([] (TShuttlePtr& head) { - if (head) { - head->EndOfTrack(); - head.Reset(); - } - }); - } - - // Checks if there is at least one shuttle in orbit - // NOTE: used by every LWTRACK macro check, so keep it optimized - do not lock - bool HasShuttles() const { - return HeadNoLock.Get(); - } - - void AddShuttle(const TShuttlePtr& shuttle) { - NotConcurrent([&] (TShuttlePtr& head) { - Y_VERIFY(!shuttle->GetNext()); - shuttle->SetNext(head); - head = shuttle; - }); - } - - // Moves every shuttle from `orbit' into this - void Take(TOrbit& orbit) { - NotConcurrent([&] (TShuttlePtr& head) { - orbit.NotConcurrent([&] (TShuttlePtr& oHead) { - TShuttlePtr* ref = &oHead; - if (ref->Get()) { - while (TShuttlePtr& next = (*ref)->GetNext()) { - ref = &next; - } - (*ref)->SetNext(head); - head.Swap(oHead); - oHead.Reset(); - } - }); - }); - } - + ~TOrbit() { + Reset(); + } + + void Reset() { + NotConcurrent([] (TShuttlePtr& head) { + if (head) { + head->EndOfTrack(); + head.Reset(); + } + }); + } + + // Checks if there is at least one shuttle in orbit + // NOTE: used by every LWTRACK macro check, so keep it optimized - do not lock + bool HasShuttles() const { + return HeadNoLock.Get(); + } + + void AddShuttle(const TShuttlePtr& shuttle) { + NotConcurrent([&] (TShuttlePtr& head) { + Y_VERIFY(!shuttle->GetNext()); + shuttle->SetNext(head); + head = shuttle; + }); + } + + // Moves every shuttle from `orbit' into this + void Take(TOrbit& orbit) { + NotConcurrent([&] (TShuttlePtr& head) { + orbit.NotConcurrent([&] (TShuttlePtr& oHead) { + TShuttlePtr* ref = &oHead; + if (ref->Get()) { + while (TShuttlePtr& next = (*ref)->GetNext()) { + ref = &next; + } + (*ref)->SetNext(head); + head.Swap(oHead); + oHead.Reset(); + } + }); + }); + } + void AddProbe(TProbe* probe, const TParams& params, ui64 timestamp = 0) { - NotConcurrent([&] (TShuttlePtr& head) { - TShuttlePtr* ref = &head; - while (IShuttle* s = ref->Get()) { - if (!s->AddProbe(probe, params, timestamp)) { // Shuttle self-destructed - *ref = s->Drop(); // May destroy shuttle - } else { - ref = &s->GetNext(); // Keep shuttle - } - } - }); - } - - template <class TFunc> - void ForEachShuttle(ui64 traceIdx, TFunc&& func) { - NotConcurrent([&] (TShuttlePtr& head) { - TShuttlePtr* ref = &head; - while (IShuttle* s = ref->Get()) { - if (s->GetTraceIdx() == traceIdx && !func(s)) { // Shuttle self-destructed - *ref = s->Drop(); // May destroy shuttle - } else { - ref = &s->GetNext(); // Keep shuttle - } - } - }); - } - - void Serialize(ui64 traceIdx, TShuttleTrace& msg) { - ForEachShuttle(traceIdx, [&] (NLWTrace::IShuttle* shuttle) { + NotConcurrent([&] (TShuttlePtr& head) { + TShuttlePtr* ref = &head; + while (IShuttle* s = ref->Get()) { + if (!s->AddProbe(probe, params, timestamp)) { // Shuttle self-destructed + *ref = s->Drop(); // May destroy shuttle + } else { + ref = &s->GetNext(); // Keep shuttle + } + } + }); + } + + template <class TFunc> + void ForEachShuttle(ui64 traceIdx, TFunc&& func) { + NotConcurrent([&] (TShuttlePtr& head) { + TShuttlePtr* ref = &head; + while (IShuttle* s = ref->Get()) { + if (s->GetTraceIdx() == traceIdx && !func(s)) { // Shuttle self-destructed + *ref = s->Drop(); // May destroy shuttle + } else { + ref = &s->GetNext(); // Keep shuttle + } + } + }); + } + + void Serialize(ui64 traceIdx, TShuttleTrace& msg) { + ForEachShuttle(traceIdx, [&] (NLWTrace::IShuttle* shuttle) { shuttle->Serialize(msg); return false; }); } - bool HasShuttle(ui64 traceIdx) { - return NotConcurrent([=] (TShuttlePtr& head) { - TShuttlePtr ref = head; - while (IShuttle* s = ref.Get()) { - if (s->GetTraceIdx() == traceIdx) { - return true; - } else { - ref = s->GetNext(); - } + bool HasShuttle(ui64 traceIdx) { + return NotConcurrent([=] (TShuttlePtr& head) { + TShuttlePtr ref = head; + while (IShuttle* s = ref.Get()) { + if (s->GetTraceIdx() == traceIdx) { + return true; + } else { + ref = s->GetNext(); + } } - return false; - }); + return false; + }); } bool Fork(TOrbit& child) { - return NotConcurrent([&] (TShuttlePtr& head) { - return child.NotConcurrent([&] (TShuttlePtr& cHead) { - bool result = true; - TShuttlePtr* ref = &head; - while (IShuttle* shuttle = ref->Get()) { - if (shuttle->IsDead()) { - *ref = shuttle->Drop(); - } else { - result = result && shuttle->Fork(cHead); - ref = &shuttle->GetNext(); - } - } - return result; - }); - }); + return NotConcurrent([&] (TShuttlePtr& head) { + return child.NotConcurrent([&] (TShuttlePtr& cHead) { + bool result = true; + TShuttlePtr* ref = &head; + while (IShuttle* shuttle = ref->Get()) { + if (shuttle->IsDead()) { + *ref = shuttle->Drop(); + } else { + result = result && shuttle->Fork(cHead); + ref = &shuttle->GetNext(); + } + } + return result; + }); + }); } void Join(TOrbit& child) { - NotConcurrent([&] (TShuttlePtr& head) { - child.NotConcurrent([&] (TShuttlePtr& cHead) { - TShuttlePtr* ref = &head; - while (IShuttle* shuttle = ref->Get()) { - if (shuttle->IsDead()) { - *ref = shuttle->Drop(); - } else { - child.Join(cHead, shuttle); - ref = &shuttle->GetNext(); - } - } - }); - }); - } - - private: - static void Join(TShuttlePtr& head, IShuttle* parent) { - TShuttlePtr* ref = &head; + NotConcurrent([&] (TShuttlePtr& head) { + child.NotConcurrent([&] (TShuttlePtr& cHead) { + TShuttlePtr* ref = &head; + while (IShuttle* shuttle = ref->Get()) { + if (shuttle->IsDead()) { + *ref = shuttle->Drop(); + } else { + child.Join(cHead, shuttle); + ref = &shuttle->GetNext(); + } + } + }); + }); + } + + private: + static void Join(TShuttlePtr& head, IShuttle* parent) { + TShuttlePtr* ref = &head; while (IShuttle* child = ref->Get()) { if (parent->GetTraceIdx() == child->GetTraceIdx() && parent->GetSpanId() == child->GetParentSpanId()) { TShuttlePtr next = child->Detach(); @@ -322,37 +322,37 @@ namespace NLWTrace { } } } - - template <class TFunc> - typename std::invoke_result<TFunc, TShuttlePtr&>::type NotConcurrent(TFunc func) { - // `HeadNoLock` is binary-copied into local `headCopy` and written with special `locked` value - // during not concurrent operations. Not concurrent operations should not work - // with `HeadNoLock` directly. Instead `headCopy` is passed into `func` by reference and - // after `func()` it is binary-copied back into `HeadNoLock`. - static_assert(sizeof(HeadNoLock) == sizeof(TAtomic)); - TAtomic* headPtr = reinterpret_cast<TAtomic*>(&HeadNoLock); - TAtomicBase headCopy = AtomicGet(*headPtr); - static constexpr TAtomicBase locked = 0x1ull; - if (headCopy != locked && AtomicCas(headPtr, locked, headCopy)) { - struct TUnlocker { // to avoid specialization for R=void - TAtomic* HeadPtr; - TAtomicBase* HeadCopy; - ~TUnlocker() { - ATOMIC_COMPILER_BARRIER(); - AtomicSet(*HeadPtr, *HeadCopy); - } - } scoped{headPtr, &headCopy}; - return func(*reinterpret_cast<TShuttlePtr*>(&headCopy)); - } else { - LockFailed(); - return typename std::invoke_result<TFunc, TShuttlePtr&>::type(); - } - } - - void LockFailed(); - }; - - inline size_t HasShuttles(const TOrbit& orbit) { - return orbit.HasShuttles(); - } -} + + template <class TFunc> + typename std::invoke_result<TFunc, TShuttlePtr&>::type NotConcurrent(TFunc func) { + // `HeadNoLock` is binary-copied into local `headCopy` and written with special `locked` value + // during not concurrent operations. Not concurrent operations should not work + // with `HeadNoLock` directly. Instead `headCopy` is passed into `func` by reference and + // after `func()` it is binary-copied back into `HeadNoLock`. + static_assert(sizeof(HeadNoLock) == sizeof(TAtomic)); + TAtomic* headPtr = reinterpret_cast<TAtomic*>(&HeadNoLock); + TAtomicBase headCopy = AtomicGet(*headPtr); + static constexpr TAtomicBase locked = 0x1ull; + if (headCopy != locked && AtomicCas(headPtr, locked, headCopy)) { + struct TUnlocker { // to avoid specialization for R=void + TAtomic* HeadPtr; + TAtomicBase* HeadCopy; + ~TUnlocker() { + ATOMIC_COMPILER_BARRIER(); + AtomicSet(*HeadPtr, *HeadCopy); + } + } scoped{headPtr, &headCopy}; + return func(*reinterpret_cast<TShuttlePtr*>(&headCopy)); + } else { + LockFailed(); + return typename std::invoke_result<TFunc, TShuttlePtr&>::type(); + } + } + + void LockFailed(); + }; + + inline size_t HasShuttles(const TOrbit& orbit) { + return orbit.HasShuttles(); + } +} diff --git a/library/cpp/lwtrace/signature.h b/library/cpp/lwtrace/signature.h index 868bd9bcf2..87ce835228 100644 --- a/library/cpp/lwtrace/signature.h +++ b/library/cpp/lwtrace/signature.h @@ -1,16 +1,16 @@ -#pragma once - +#pragma once + #include "preprocessor.h" #include <library/cpp/lwtrace/protos/lwtrace.pb.h> #include <util/generic/cast.h> #include <util/generic/string.h> -#include <util/generic/typetraits.h> +#include <util/generic/typetraits.h> #include <util/string/builder.h> -#include <util/string/cast.h> -#include <util/string/printf.h> - +#include <util/string/cast.h> +#include <util/string/printf.h> + #include <google/protobuf/descriptor.h> #include <google/protobuf/generated_enum_reflection.h> @@ -18,407 +18,407 @@ #include <type_traits> -namespace NLWTrace { - // Class to hold parameter values parsed from trace query predicate operators - template <class T> - struct TParamConv { - static T FromString(const TString& text) { - return ::FromString<T>(text); - } - static TString ToString(const T& param) { - return ::ToString(param); - } - }; - - template <> - struct TParamConv<TString const*> { - static TString FromString(const TString& text) { - return text; - } - static TString ToString(TString const* param) { - return TString(*param); - } - }; - - template <> - struct TParamConv<ui8> { - static ui8 FromString(const TString& text) { - return (ui8)::FromString<ui16>(text); - } - static TString ToString(ui8 param) { - return ::ToString((ui16)param); - } - }; - - template <> - struct TParamConv<i8> { - static i8 FromString(const TString& text) { - return (i8)::FromString<i16>(text); - } - static TString ToString(i8 param) { - return ::ToString((i16)param); - } - }; - - template <> - struct TParamConv<double> { - static double FromString(const TString& text) { - return ::FromString<double>(text); - } - static TString ToString(double param) { - return Sprintf("%.6lf", param); - } - }; - - // Fake parameter type used as a placeholder for not used parameters (above the number of defined params for a specific probe) - class TNil { - }; - - // Struct that holds and handles a value of parameter of any supported type. - struct TParam { - char Data[LWTRACE_MAX_PARAM_SIZE]; - - template <class T> - const T& Get() const { +namespace NLWTrace { + // Class to hold parameter values parsed from trace query predicate operators + template <class T> + struct TParamConv { + static T FromString(const TString& text) { + return ::FromString<T>(text); + } + static TString ToString(const T& param) { + return ::ToString(param); + } + }; + + template <> + struct TParamConv<TString const*> { + static TString FromString(const TString& text) { + return text; + } + static TString ToString(TString const* param) { + return TString(*param); + } + }; + + template <> + struct TParamConv<ui8> { + static ui8 FromString(const TString& text) { + return (ui8)::FromString<ui16>(text); + } + static TString ToString(ui8 param) { + return ::ToString((ui16)param); + } + }; + + template <> + struct TParamConv<i8> { + static i8 FromString(const TString& text) { + return (i8)::FromString<i16>(text); + } + static TString ToString(i8 param) { + return ::ToString((i16)param); + } + }; + + template <> + struct TParamConv<double> { + static double FromString(const TString& text) { + return ::FromString<double>(text); + } + static TString ToString(double param) { + return Sprintf("%.6lf", param); + } + }; + + // Fake parameter type used as a placeholder for not used parameters (above the number of defined params for a specific probe) + class TNil { + }; + + // Struct that holds and handles a value of parameter of any supported type. + struct TParam { + char Data[LWTRACE_MAX_PARAM_SIZE]; + + template <class T> + const T& Get() const { return *reinterpret_cast<const T*>(Data); - } - - template <class T> - T& Get() { + } + + template <class T> + T& Get() { return *reinterpret_cast<T*>(Data); - } - - template <class T> - void DefaultConstruct() { - new (&Data) T(); - } - - template <class T> - void CopyConstruct(const T& other) { - new (&Data) T(other); - } - - template <class T> - void Destruct() { - Get<T>().~T(); - } - }; - - template <> - inline void TParam::DefaultConstruct<TNil>() { - } - - template <> - inline void TParam::CopyConstruct<TNil>(const TNil&) { - } - - template <> - inline void TParam::Destruct<TNil>() { - } - - class TTypedParam { - private: - EParamTypePb Type; - TParam Param; // Contains garbage if PT_UNKNOWN - public: - TTypedParam() - : Type(PT_UNKNOWN) - { - } - - explicit TTypedParam(EParamTypePb type) - : Type(type) - { - switch (Type) { -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - case PT_##v: \ - Param.DefaultConstruct<t>(); \ - return; - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - case PT_UNKNOWN: - return; - default: - Y_FAIL("unknown param type"); - } - } - - template <class T> - explicit TTypedParam(const T& x, EParamTypePb type = PT_UNKNOWN) - : Type(type) - { - Param.CopyConstruct<T>(x); - } - -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - explicit TTypedParam(const t& x) \ - : Type(PT_##v) { \ - Param.CopyConstruct<t>(x); \ - } - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - - TTypedParam(const TTypedParam& o) { - Assign(o); - } - - TTypedParam& operator=(const TTypedParam& o) { - Reset(); - Assign(o); - return *this; - } - - void Assign(const TTypedParam& o) { - Type = o.Type; - switch (Type) { -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - case PT_##v: \ - Param.CopyConstruct<t>(o.Param.Get<t>()); \ - return; - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - case PT_UNKNOWN: - return; - default: - Y_FAIL("unknown param type"); - } - } - - TTypedParam(TTypedParam&& o) - : Type(o.Type) - , Param(o.Param) - { - o.Type = PT_UNKNOWN; // To avoid Param destroy by source object dtor - } - - TTypedParam(EParamTypePb type, const TParam& param) - : Type(type) - { - Y_UNUSED(param); // for disabled lwtrace - switch (Type) { -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - case PT_##v: \ - Param.CopyConstruct<t>(param.Get<t>()); \ - return; - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - case PT_UNKNOWN: - return; - default: - Y_FAIL("unknown param type"); - } - } - - ~TTypedParam() { - Reset(); - } - - void Reset() { - switch (Type) { -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - case PT_##v: \ - Param.Destruct<t>(); \ - return; - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - case PT_UNKNOWN: - return; - default: - Y_FAIL("unknown param type"); - } - Type = PT_UNKNOWN; - } - - bool operator==(const TTypedParam& rhs) const { - if (Y_LIKELY(Type == rhs.Type)) { - switch (Type) { -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - case PT_##v: \ - return Param.Get<t>() == rhs.Param.Get<t>(); - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - case PT_UNKNOWN: - return false; // All unknowns are equal - default: - Y_FAIL("unknown param type"); - } - } else { - return false; - } - } - bool operator!=(const TTypedParam& rhs) const { - return !operator==(rhs); - } - - bool operator<(const TTypedParam& rhs) const { - if (Y_LIKELY(Type == rhs.Type)) { - switch (Type) { -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - case PT_##v: \ - return Param.Get<t>() < rhs.Param.Get<t>(); - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - case PT_UNKNOWN: - return false; // All unknowns are equal - default: - Y_FAIL("unknown param type"); - } - } else { - return Type < rhs.Type; - } - } - - bool operator<=(const TTypedParam& rhs) const { - if (Y_LIKELY(Type == rhs.Type)) { - switch (Type) { -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - case PT_##v: \ - return Param.Get<t>() <= rhs.Param.Get<t>(); - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - case PT_UNKNOWN: - return true; // All unknowns are equal - default: - Y_FAIL("unknown param type"); - } - } else { - return Type < rhs.Type; - } - } - - bool operator>(const TTypedParam& rhs) const { - return !operator<=(rhs); - } - bool operator>=(const TTypedParam& rhs) const { - return !operator<(rhs); - } - - EParamTypePb GetType() const { - return Type; - } - const TParam& GetParam() const { - return Param; - } - }; - - class TLiteral { - private: - TTypedParam Values[EParamTypePb_ARRAYSIZE]; - - public: - explicit TLiteral(const TString& text) { - Y_UNUSED(text); /* That's for windows, where we have lwtrace disabled. */ - -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - try { \ - Values[PT_##v] = TTypedParam(TParamConv<t>::FromString(text)); \ - } catch (...) { \ - Values[PT_##v] = TTypedParam(); \ - } \ - /**/ - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - } - - TLiteral() { - } - - TLiteral(const TLiteral& o) { - for (size_t i = 0; i < EParamTypePb_ARRAYSIZE; i++) { - Values[i] = o.Values[i]; - } - } - - TLiteral& operator=(const TLiteral& o) { - for (size_t i = 0; i < EParamTypePb_ARRAYSIZE; i++) { - Values[i] = o.Values[i]; - } - return *this; - } - - const TTypedParam& GetValue(EParamTypePb type) const { - return Values[type]; - } - - bool operator==(const TTypedParam& rhs) const { - return Values[rhs.GetType()] == rhs; - } - bool operator!=(const TTypedParam& rhs) const { - return !operator==(rhs); - } - - bool operator<(const TTypedParam& rhs) const { - return Values[rhs.GetType()] < rhs; - } - - bool operator<=(const TTypedParam& rhs) const { - return Values[rhs.GetType()] <= rhs; - } - - bool operator>(const TTypedParam& rhs) const { - return !operator<=(rhs); - } - bool operator>=(const TTypedParam& rhs) const { - return !operator<(rhs); - } - }; - - inline bool operator==(const TTypedParam& lhs, const TLiteral& rhs) { - return lhs == rhs.GetValue(lhs.GetType()); - } - inline bool operator!=(const TTypedParam& lhs, const TLiteral& rhs) { - return !operator==(lhs, rhs); - } - - inline bool operator<(const TTypedParam& lhs, const TLiteral& rhs) { - return lhs < rhs.GetValue(lhs.GetType()); - } - - inline bool operator<=(const TTypedParam& lhs, const TLiteral& rhs) { - return lhs <= rhs.GetValue(lhs.GetType()); - } - - inline bool operator>(const TTypedParam& lhs, const TLiteral& rhs) { - return !operator<=(lhs, rhs); - } - inline bool operator>=(const TTypedParam& lhs, const TLiteral& rhs) { - return !operator<(lhs, rhs); - } - - // Struct that holds and handles all parameter values of different supported types - struct TParams { - TParam Param[LWTRACE_MAX_PARAMS]; - }; - + } + + template <class T> + void DefaultConstruct() { + new (&Data) T(); + } + + template <class T> + void CopyConstruct(const T& other) { + new (&Data) T(other); + } + + template <class T> + void Destruct() { + Get<T>().~T(); + } + }; + + template <> + inline void TParam::DefaultConstruct<TNil>() { + } + + template <> + inline void TParam::CopyConstruct<TNil>(const TNil&) { + } + + template <> + inline void TParam::Destruct<TNil>() { + } + + class TTypedParam { + private: + EParamTypePb Type; + TParam Param; // Contains garbage if PT_UNKNOWN + public: + TTypedParam() + : Type(PT_UNKNOWN) + { + } + + explicit TTypedParam(EParamTypePb type) + : Type(type) + { + switch (Type) { +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + case PT_##v: \ + Param.DefaultConstruct<t>(); \ + return; + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + case PT_UNKNOWN: + return; + default: + Y_FAIL("unknown param type"); + } + } + + template <class T> + explicit TTypedParam(const T& x, EParamTypePb type = PT_UNKNOWN) + : Type(type) + { + Param.CopyConstruct<T>(x); + } + +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + explicit TTypedParam(const t& x) \ + : Type(PT_##v) { \ + Param.CopyConstruct<t>(x); \ + } + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + + TTypedParam(const TTypedParam& o) { + Assign(o); + } + + TTypedParam& operator=(const TTypedParam& o) { + Reset(); + Assign(o); + return *this; + } + + void Assign(const TTypedParam& o) { + Type = o.Type; + switch (Type) { +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + case PT_##v: \ + Param.CopyConstruct<t>(o.Param.Get<t>()); \ + return; + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + case PT_UNKNOWN: + return; + default: + Y_FAIL("unknown param type"); + } + } + + TTypedParam(TTypedParam&& o) + : Type(o.Type) + , Param(o.Param) + { + o.Type = PT_UNKNOWN; // To avoid Param destroy by source object dtor + } + + TTypedParam(EParamTypePb type, const TParam& param) + : Type(type) + { + Y_UNUSED(param); // for disabled lwtrace + switch (Type) { +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + case PT_##v: \ + Param.CopyConstruct<t>(param.Get<t>()); \ + return; + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + case PT_UNKNOWN: + return; + default: + Y_FAIL("unknown param type"); + } + } + + ~TTypedParam() { + Reset(); + } + + void Reset() { + switch (Type) { +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + case PT_##v: \ + Param.Destruct<t>(); \ + return; + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + case PT_UNKNOWN: + return; + default: + Y_FAIL("unknown param type"); + } + Type = PT_UNKNOWN; + } + + bool operator==(const TTypedParam& rhs) const { + if (Y_LIKELY(Type == rhs.Type)) { + switch (Type) { +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + case PT_##v: \ + return Param.Get<t>() == rhs.Param.Get<t>(); + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + case PT_UNKNOWN: + return false; // All unknowns are equal + default: + Y_FAIL("unknown param type"); + } + } else { + return false; + } + } + bool operator!=(const TTypedParam& rhs) const { + return !operator==(rhs); + } + + bool operator<(const TTypedParam& rhs) const { + if (Y_LIKELY(Type == rhs.Type)) { + switch (Type) { +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + case PT_##v: \ + return Param.Get<t>() < rhs.Param.Get<t>(); + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + case PT_UNKNOWN: + return false; // All unknowns are equal + default: + Y_FAIL("unknown param type"); + } + } else { + return Type < rhs.Type; + } + } + + bool operator<=(const TTypedParam& rhs) const { + if (Y_LIKELY(Type == rhs.Type)) { + switch (Type) { +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + case PT_##v: \ + return Param.Get<t>() <= rhs.Param.Get<t>(); + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + case PT_UNKNOWN: + return true; // All unknowns are equal + default: + Y_FAIL("unknown param type"); + } + } else { + return Type < rhs.Type; + } + } + + bool operator>(const TTypedParam& rhs) const { + return !operator<=(rhs); + } + bool operator>=(const TTypedParam& rhs) const { + return !operator<(rhs); + } + + EParamTypePb GetType() const { + return Type; + } + const TParam& GetParam() const { + return Param; + } + }; + + class TLiteral { + private: + TTypedParam Values[EParamTypePb_ARRAYSIZE]; + + public: + explicit TLiteral(const TString& text) { + Y_UNUSED(text); /* That's for windows, where we have lwtrace disabled. */ + +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + try { \ + Values[PT_##v] = TTypedParam(TParamConv<t>::FromString(text)); \ + } catch (...) { \ + Values[PT_##v] = TTypedParam(); \ + } \ + /**/ + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + } + + TLiteral() { + } + + TLiteral(const TLiteral& o) { + for (size_t i = 0; i < EParamTypePb_ARRAYSIZE; i++) { + Values[i] = o.Values[i]; + } + } + + TLiteral& operator=(const TLiteral& o) { + for (size_t i = 0; i < EParamTypePb_ARRAYSIZE; i++) { + Values[i] = o.Values[i]; + } + return *this; + } + + const TTypedParam& GetValue(EParamTypePb type) const { + return Values[type]; + } + + bool operator==(const TTypedParam& rhs) const { + return Values[rhs.GetType()] == rhs; + } + bool operator!=(const TTypedParam& rhs) const { + return !operator==(rhs); + } + + bool operator<(const TTypedParam& rhs) const { + return Values[rhs.GetType()] < rhs; + } + + bool operator<=(const TTypedParam& rhs) const { + return Values[rhs.GetType()] <= rhs; + } + + bool operator>(const TTypedParam& rhs) const { + return !operator<=(rhs); + } + bool operator>=(const TTypedParam& rhs) const { + return !operator<(rhs); + } + }; + + inline bool operator==(const TTypedParam& lhs, const TLiteral& rhs) { + return lhs == rhs.GetValue(lhs.GetType()); + } + inline bool operator!=(const TTypedParam& lhs, const TLiteral& rhs) { + return !operator==(lhs, rhs); + } + + inline bool operator<(const TTypedParam& lhs, const TLiteral& rhs) { + return lhs < rhs.GetValue(lhs.GetType()); + } + + inline bool operator<=(const TTypedParam& lhs, const TLiteral& rhs) { + return lhs <= rhs.GetValue(lhs.GetType()); + } + + inline bool operator>(const TTypedParam& lhs, const TLiteral& rhs) { + return !operator<=(lhs, rhs); + } + inline bool operator>=(const TTypedParam& lhs, const TLiteral& rhs) { + return !operator<(lhs, rhs); + } + + // Struct that holds and handles all parameter values of different supported types + struct TParams { + TParam Param[LWTRACE_MAX_PARAMS]; + }; + using TSerializedParams = google::protobuf::RepeatedPtrField<NLWTrace::TTraceParam>; - // Represents a common class for all function "signatures" (parameter types and names). - // Provides non-virtual interface to handle the signature and (emulated) virtual interface to handle TParams corresponding to the signature - struct TSignature { - const char** ParamTypes; - const char* ParamNames[LWTRACE_MAX_PARAMS + 1]; - size_t ParamCount; - - // Virtual table - void (*SerializeParamsFunc)(const TParams& params, TString* values); - void (*CloneParamsFunc)(TParams& newParams, const TParams& oldParams); - void (*DestroyParamsFunc)(TParams& params); + // Represents a common class for all function "signatures" (parameter types and names). + // Provides non-virtual interface to handle the signature and (emulated) virtual interface to handle TParams corresponding to the signature + struct TSignature { + const char** ParamTypes; + const char* ParamNames[LWTRACE_MAX_PARAMS + 1]; + size_t ParamCount; + + // Virtual table + void (*SerializeParamsFunc)(const TParams& params, TString* values); + void (*CloneParamsFunc)(TParams& newParams, const TParams& oldParams); + void (*DestroyParamsFunc)(TParams& params); void (*SerializeToPbFunc)(const TParams& params, TSerializedParams& arr); bool (*DeserializeFromPbFunc)(TParams& params, const TSerializedParams& arr); - - // Virtual calls emulation - void SerializeParams(const TParams& params, TString* values) const { - (*SerializeParamsFunc)(params, values); - } - - void CloneParams(TParams& newParams, const TParams& oldParams) const { - (*CloneParamsFunc)(newParams, oldParams); - } - - void DestroyParams(TParams& params) const { - (*DestroyParamsFunc)(params); - } - + + // Virtual calls emulation + void SerializeParams(const TParams& params, TString* values) const { + (*SerializeParamsFunc)(params, values); + } + + void CloneParams(TParams& newParams, const TParams& oldParams) const { + (*CloneParamsFunc)(newParams, oldParams); + } + + void DestroyParams(TParams& params) const { + (*DestroyParamsFunc)(params); + } + void SerializeToPb(const TParams& params, TSerializedParams& arr) const { (*SerializeToPbFunc)(params, arr); @@ -429,42 +429,42 @@ namespace NLWTrace { return (*DeserializeFromPbFunc)(params, arr); } - void ToProtobuf(TEventPb& pb) const; - - size_t FindParamIndex(const TString& param) const { - for (size_t i = 0; i < ParamCount; i++) { - if (ParamNames[i] == param) { - return i; - } - } - return size_t(-1); - } - }; - -#ifndef LWTRACE_DISABLE - - // Implementation. Used for compilation error if not all expected parameters passed to a function call - struct ERROR_not_enough_parameters : TNil {}; - - // Struct that holds static string with a name of parameter type - template <class T> - struct TParamType { - enum { Supported = 0 }; - static const char* NameString; - }; - -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - template <> \ - struct TParamType<t> { \ - enum { Supported = 1 }; \ - static const char* NameString; \ - }; \ - /**/ - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) - FOR_NIL_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - - template <class T> + void ToProtobuf(TEventPb& pb) const; + + size_t FindParamIndex(const TString& param) const { + for (size_t i = 0; i < ParamCount; i++) { + if (ParamNames[i] == param) { + return i; + } + } + return size_t(-1); + } + }; + +#ifndef LWTRACE_DISABLE + + // Implementation. Used for compilation error if not all expected parameters passed to a function call + struct ERROR_not_enough_parameters : TNil {}; + + // Struct that holds static string with a name of parameter type + template <class T> + struct TParamType { + enum { Supported = 0 }; + static const char* NameString; + }; + +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + template <> \ + struct TParamType<t> { \ + enum { Supported = 1 }; \ + static const char* NameString; \ + }; \ + /**/ + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) + FOR_NIL_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + + template <class T> struct TParamTraits; // Enum types traits impl. @@ -473,7 +473,7 @@ namespace NLWTrace { using TStoreType = typename TParamTraits<std::underlying_type_t<TEnum>>::TStoreType; using TFuncParam = TEnum; - inline static void ToString(typename TTypeTraits<TStoreType>::TFuncParam stored, TString* out) { + inline static void ToString(typename TTypeTraits<TStoreType>::TFuncParam stored, TString* out) { if constexpr (google::protobuf::is_proto_enum<TEnum>::value) { const google::protobuf::EnumValueDescriptor* valueDescriptor = google::protobuf::GetEnumDescriptor<TEnum>()->FindValueByNumber(stored); if (valueDescriptor) { @@ -484,13 +484,13 @@ namespace NLWTrace { } else { *out = TParamConv<TStoreType>::ToString(stored); } - } + } inline static TStoreType ToStoreType(TFuncParam v) { return static_cast<TStoreType>(v); } - }; - + }; + template <class TCustomType> struct TCustomTraitsImpl { using TStoreType = typename TParamTraits<typename TCustomType::TStoreType>::TStoreType; //see STORE_TYPE_AS @@ -522,48 +522,48 @@ namespace NLWTrace { // Standard stored types traits. -#define STORE_TYPE_AS(input_t, store_as_t) \ - template <> \ - struct TParamTraits<input_t> { \ +#define STORE_TYPE_AS(input_t, store_as_t) \ + template <> \ + struct TParamTraits<input_t> { \ using TStoreType = store_as_t; \ using TFuncParam = typename TTypeTraits<input_t>::TFuncParam; \ \ inline static void ToString(typename TTypeTraits<TStoreType>::TFuncParam stored, TString* out) { \ - *out = TParamConv<TStoreType>::ToString(stored); \ - } \ + *out = TParamConv<TStoreType>::ToString(stored); \ + } \ \ inline static TStoreType ToStoreType(TFuncParam v) { \ return v; \ } \ - }; \ - /**/ - STORE_TYPE_AS(ui8, ui64); - STORE_TYPE_AS(i8, i64); - STORE_TYPE_AS(ui16, ui64); - STORE_TYPE_AS(i16, i64); - STORE_TYPE_AS(ui32, ui64); - STORE_TYPE_AS(i32, i64); - STORE_TYPE_AS(bool, ui64); - STORE_TYPE_AS(float, double); + }; \ + /**/ + STORE_TYPE_AS(ui8, ui64); + STORE_TYPE_AS(i8, i64); + STORE_TYPE_AS(ui16, ui64); + STORE_TYPE_AS(i16, i64); + STORE_TYPE_AS(ui32, ui64); + STORE_TYPE_AS(i32, i64); + STORE_TYPE_AS(bool, ui64); + STORE_TYPE_AS(float, double); #define FOREACH_PARAMTYPE_MACRO(n, t, v) STORE_TYPE_AS(t, t) - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) #undef STORE_TYPE_AS -#undef FOREACH_PARAMTYPE_MACRO - +#undef FOREACH_PARAMTYPE_MACRO + // Nil type staits. - template <> - struct TParamTraits<TNil> { + template <> + struct TParamTraits<TNil> { using TStoreType = TNil; using TFuncParam = TTypeTraits<TNil>::TFuncParam; inline static void ToString(typename TTypeTraits<TNil>::TFuncParam, TString*) { - } + } inline static TNil ToStoreType(TFuncParam v) { return v; } - }; - + }; + inline EParamTypePb ParamTypeToProtobuf(const char* paramType) { #define FOREACH_PARAMTYPE_MACRO(n, t, v) \ if (strcmp(paramType, n) == 0) { \ @@ -676,35 +676,35 @@ namespace NLWTrace { Y_UNUSED(param); } - // Class representing a specific signature - template <LWTRACE_TEMPLATE_PARAMS> - struct TUserSignature { -#define FOREACH_PARAMNUM_MACRO(i) static_assert(TParamType<typename TParamTraits<TP##i>::TStoreType>::Supported == 1, "expect TParamType< typename TParamTraits<TP ## i>::TStoreType >::Supported == 1"); - FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO) // ERROR: unsupported type used as probe/event parameter type -#undef FOREACH_PARAMNUM_MACRO - static const char* ParamTypes[]; - static const int ParamCount = LWTRACE_COUNT_PARAMS; - - // Implementation of virtual function (TSignature derived classes vtable emulation) - inline static void SerializeParams(const TParams& params, TString* values) { -#define FOREACH_PARAMNUM_MACRO(i) TParamTraits<TP##i>::ToString(params.Param[i].Get<typename TParamTraits<TP##i>::TStoreType>(), values + i); - FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO); -#undef FOREACH_PARAMNUM_MACRO - } - - // Implementation of virtual function (TSignature derived classes vtable emulation) - inline static void CloneParams(TParams& newParams, const TParams& oldParams) { -#define FOREACH_PARAMNUM_MACRO(i) newParams.Param[i].CopyConstruct<typename TParamTraits<TP##i>::TStoreType>(oldParams.Param[i].Get<typename TParamTraits<TP##i>::TStoreType>()); - FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO); -#undef FOREACH_PARAMNUM_MACRO - } - - // Implementation of virtual function (TSignature derived classes vtable emulation) - inline static void DestroyParams(TParams& params) { -#define FOREACH_PARAMNUM_MACRO(i) params.Param[i].Destruct<typename TParamTraits<TP##i>::TStoreType>(); - FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO); -#undef FOREACH_PARAMNUM_MACRO - } + // Class representing a specific signature + template <LWTRACE_TEMPLATE_PARAMS> + struct TUserSignature { +#define FOREACH_PARAMNUM_MACRO(i) static_assert(TParamType<typename TParamTraits<TP##i>::TStoreType>::Supported == 1, "expect TParamType< typename TParamTraits<TP ## i>::TStoreType >::Supported == 1"); + FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO) // ERROR: unsupported type used as probe/event parameter type +#undef FOREACH_PARAMNUM_MACRO + static const char* ParamTypes[]; + static const int ParamCount = LWTRACE_COUNT_PARAMS; + + // Implementation of virtual function (TSignature derived classes vtable emulation) + inline static void SerializeParams(const TParams& params, TString* values) { +#define FOREACH_PARAMNUM_MACRO(i) TParamTraits<TP##i>::ToString(params.Param[i].Get<typename TParamTraits<TP##i>::TStoreType>(), values + i); + FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO); +#undef FOREACH_PARAMNUM_MACRO + } + + // Implementation of virtual function (TSignature derived classes vtable emulation) + inline static void CloneParams(TParams& newParams, const TParams& oldParams) { +#define FOREACH_PARAMNUM_MACRO(i) newParams.Param[i].CopyConstruct<typename TParamTraits<TP##i>::TStoreType>(oldParams.Param[i].Get<typename TParamTraits<TP##i>::TStoreType>()); + FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO); +#undef FOREACH_PARAMNUM_MACRO + } + + // Implementation of virtual function (TSignature derived classes vtable emulation) + inline static void DestroyParams(TParams& params) { +#define FOREACH_PARAMNUM_MACRO(i) params.Param[i].Destruct<typename TParamTraits<TP##i>::TStoreType>(); + FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO); +#undef FOREACH_PARAMNUM_MACRO + } // Implementation of virtual function (TSignature derived classes vtable emulation) inline static void SerializeToPb(const TParams& params, TSerializedParams& arr) @@ -741,32 +741,32 @@ namespace NLWTrace { #undef FOREACH_PARAMNUM_MACRO return true; } - }; - - // Array of static strings pointers for names of parameter types in a specific signature - template <LWTRACE_TEMPLATE_PARAMS_NODEF> - const char* TUserSignature<LWTRACE_TEMPLATE_ARGS>::ParamTypes[] = { -#define FOREACH_PARAMNUM_MACRO(i) TParamType<typename TParamTraits<TP##i>::TStoreType>::NameString, - FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO) nullptr -#undef FOREACH_PARAMNUM_MACRO - }; - - inline void TSignature::ToProtobuf(TEventPb& pb) const { - for (size_t i = 0; i < ParamCount; i++) { - pb.AddParamTypes(ParamTypeToProtobuf(ParamTypes[i])); - pb.AddParamNames(ParamNames[i]); - } - } - -#else - - inline void TSignature::ToProtobuf(TEventPb&) const { - } - - inline EParamTypePb ParamTypeToProtobuf(const char*) { - return PT_UNKNOWN; - } - -#endif - -} + }; + + // Array of static strings pointers for names of parameter types in a specific signature + template <LWTRACE_TEMPLATE_PARAMS_NODEF> + const char* TUserSignature<LWTRACE_TEMPLATE_ARGS>::ParamTypes[] = { +#define FOREACH_PARAMNUM_MACRO(i) TParamType<typename TParamTraits<TP##i>::TStoreType>::NameString, + FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO) nullptr +#undef FOREACH_PARAMNUM_MACRO + }; + + inline void TSignature::ToProtobuf(TEventPb& pb) const { + for (size_t i = 0; i < ParamCount; i++) { + pb.AddParamTypes(ParamTypeToProtobuf(ParamTypes[i])); + pb.AddParamNames(ParamNames[i]); + } + } + +#else + + inline void TSignature::ToProtobuf(TEventPb&) const { + } + + inline EParamTypePb ParamTypeToProtobuf(const char*) { + return PT_UNKNOWN; + } + +#endif + +} diff --git a/library/cpp/lwtrace/sleep_action.cpp b/library/cpp/lwtrace/sleep_action.cpp index 74977528db..8e5925be38 100644 --- a/library/cpp/lwtrace/sleep_action.cpp +++ b/library/cpp/lwtrace/sleep_action.cpp @@ -9,7 +9,7 @@ using namespace NLWTrace; using namespace NLWTrace::NPrivate; -bool TSleepActionExecutor::DoExecute(TOrbit&, const TParams&) { +bool TSleepActionExecutor::DoExecute(TOrbit&, const TParams&) { NanoSleep(NanoSeconds); return true; } diff --git a/library/cpp/lwtrace/sleep_action.h b/library/cpp/lwtrace/sleep_action.h index 26f89bd88c..9cece64d40 100644 --- a/library/cpp/lwtrace/sleep_action.h +++ b/library/cpp/lwtrace/sleep_action.h @@ -2,20 +2,20 @@ #include "probe.h" -namespace NLWTrace { - namespace NPrivate { - class TSleepActionExecutor: public IExecutor { - private: - ui64 NanoSeconds; +namespace NLWTrace { + namespace NPrivate { + class TSleepActionExecutor: public IExecutor { + private: + ui64 NanoSeconds; - public: - TSleepActionExecutor(const TProbe*, ui64 nanoSeconds) - : IExecutor() - , NanoSeconds(nanoSeconds) - { - } - bool DoExecute(TOrbit& orbit, const TParams& params) override; - }; + public: + TSleepActionExecutor(const TProbe*, ui64 nanoSeconds) + : IExecutor() + , NanoSeconds(nanoSeconds) + { + } + bool DoExecute(TOrbit& orbit, const TParams& params) override; + }; - } -} + } +} diff --git a/library/cpp/lwtrace/start.cpp b/library/cpp/lwtrace/start.cpp index 121d5472b6..7d17d6c572 100644 --- a/library/cpp/lwtrace/start.cpp +++ b/library/cpp/lwtrace/start.cpp @@ -14,56 +14,56 @@ using namespace NLWTrace; namespace { - struct TTraceManagerHolder { - TManager TraceManager; - TTraceManagerHolder() - : TraceManager(*Singleton<TProbeRegistry>(), true) - { - } - }; - - void TraceFromEnv(TString path) { - TString script = TUnbufferedFileInput(path).ReadAll(); - TQuery query; - bool ok = google::protobuf::TextFormat::ParseFromString(script, &query); - Y_VERIFY(ok, "failed to parse protobuf"); - Singleton<TTraceManagerHolder>()->TraceManager.New("env", query); - } - -} // anonymous namespace - -void NLWTrace::StartLwtraceFromEnv() { - static bool started = false; - if (started) { - return; - } else { - started = true; - } - + struct TTraceManagerHolder { + TManager TraceManager; + TTraceManagerHolder() + : TraceManager(*Singleton<TProbeRegistry>(), true) + { + } + }; + + void TraceFromEnv(TString path) { + TString script = TUnbufferedFileInput(path).ReadAll(); + TQuery query; + bool ok = google::protobuf::TextFormat::ParseFromString(script, &query); + Y_VERIFY(ok, "failed to parse protobuf"); + Singleton<TTraceManagerHolder>()->TraceManager.New("env", query); + } + +} // anonymous namespace + +void NLWTrace::StartLwtraceFromEnv() { + static bool started = false; + if (started) { + return; + } else { + started = true; + } + TString path = GetEnv("LWTRACE"); if (!path) { return; } try { - TraceFromEnv(path); + TraceFromEnv(path); } catch (...) { Cerr << "failed to load lwtrace script: " << CurrentExceptionMessage() << "\n"; abort(); } } - -void NLWTrace::StartLwtraceFromEnv(std::function<void(TManager&)> prepare) { + +void NLWTrace::StartLwtraceFromEnv(std::function<void(TManager&)> prepare) { TString path = GetEnv("LWTRACE"); if (Y_LIKELY(!path)) { - return; - } - - try { - prepare(Singleton<TTraceManagerHolder>()->TraceManager); - TraceFromEnv(path); - } catch (...) { - Cerr << "failed to load lwtrace script: " << CurrentExceptionMessage() << "\n"; - abort(); - } -} + return; + } + + try { + prepare(Singleton<TTraceManagerHolder>()->TraceManager); + TraceFromEnv(path); + } catch (...) { + Cerr << "failed to load lwtrace script: " << CurrentExceptionMessage() << "\n"; + abort(); + } +} diff --git a/library/cpp/lwtrace/start.h b/library/cpp/lwtrace/start.h index 2755212bff..9acb8df15e 100644 --- a/library/cpp/lwtrace/start.h +++ b/library/cpp/lwtrace/start.h @@ -1,11 +1,11 @@ #pragma once -#include <functional> - +#include <functional> + namespace NLWTrace { - class TManager; + class TManager; - void StartLwtraceFromEnv(); - void StartLwtraceFromEnv(std::function<void(TManager&)> prepare); + void StartLwtraceFromEnv(); + void StartLwtraceFromEnv(std::function<void(TManager&)> prepare); } diff --git a/library/cpp/lwtrace/stderr_writer.cpp b/library/cpp/lwtrace/stderr_writer.cpp index 6e5654c338..43bf9c1d02 100644 --- a/library/cpp/lwtrace/stderr_writer.cpp +++ b/library/cpp/lwtrace/stderr_writer.cpp @@ -1,19 +1,19 @@ #include "stderr_writer.h" -#include <util/stream/str.h> +#include <util/stream/str.h> using namespace NLWTrace; -bool TStderrActionExecutor::DoExecute(TOrbit&, const TParams& params) { +bool TStderrActionExecutor::DoExecute(TOrbit&, const TParams& params) { TString ParamValues[LWTRACE_MAX_PARAMS]; Probe->Event.Signature.SerializeParams(params, ParamValues); - TStringStream ss; - ss << Probe->Event.GetProvider() << "." << Probe->Event.Name; + TStringStream ss; + ss << Probe->Event.GetProvider() << "." << Probe->Event.Name; for (ui32 i = 0; i < Probe->Event.Signature.ParamCount; ++i) { - ss << " " << Probe->Event.Signature.ParamNames[i] << "=" << ParamValues[i]; + ss << " " << Probe->Event.Signature.ParamNames[i] << "=" << ParamValues[i]; } - ss << "\n"; - Cerr << ss.Str(); + ss << "\n"; + Cerr << ss.Str(); return true; } diff --git a/library/cpp/lwtrace/stderr_writer.h b/library/cpp/lwtrace/stderr_writer.h index b17fc3136e..17d4789538 100644 --- a/library/cpp/lwtrace/stderr_writer.h +++ b/library/cpp/lwtrace/stderr_writer.h @@ -3,17 +3,17 @@ #include "probe.h" namespace NLWTrace { - class TStderrActionExecutor: public IExecutor { - private: - TProbe* const Probe; + class TStderrActionExecutor: public IExecutor { + private: + TProbe* const Probe; - public: - explicit TStderrActionExecutor(TProbe* probe) - : Probe(probe) - { - } - - bool DoExecute(TOrbit& orbit, const TParams& params) override; - }; + public: + explicit TStderrActionExecutor(TProbe* probe) + : Probe(probe) + { + } + bool DoExecute(TOrbit& orbit, const TParams& params) override; + }; + } diff --git a/library/cpp/lwtrace/symbol.cpp b/library/cpp/lwtrace/symbol.cpp index 456652bcd0..e073772b5e 100644 --- a/library/cpp/lwtrace/symbol.cpp +++ b/library/cpp/lwtrace/symbol.cpp @@ -1,15 +1,15 @@ -#include "symbol.h" +#include "symbol.h" #include <util/stream/output.h> -#include <util/string/cast.h> - -template <> -NLWTrace::TSymbol FromStringImpl(const char*, size_t) { +#include <util/string/cast.h> + +template <> +NLWTrace::TSymbol FromStringImpl(const char*, size_t) { static TString err("ERROR_dynamic_symbol"); - return NLWTrace::TSymbol(&err); -} - -template <> -void Out<NLWTrace::TSymbol>(IOutputStream& o, TTypeTraits<NLWTrace::TSymbol>::TFuncParam t) { + return NLWTrace::TSymbol(&err); +} + +template <> +void Out<NLWTrace::TSymbol>(IOutputStream& o, TTypeTraits<NLWTrace::TSymbol>::TFuncParam t) { Out<TString>(o, *t.Str); -} +} diff --git a/library/cpp/lwtrace/symbol.h b/library/cpp/lwtrace/symbol.h index ef9e6cdf94..2e7d3da745 100644 --- a/library/cpp/lwtrace/symbol.h +++ b/library/cpp/lwtrace/symbol.h @@ -1,68 +1,68 @@ -#pragma once - +#pragma once + #include <util/generic/string.h> -#include <util/string/builder.h> -#include <util/system/src_location.h> - -#define LWTRACE_DEFINE_SYMBOL(variable, text) \ - static TString variable##_holder(text); \ - ::NLWTrace::TSymbol variable(&variable##_holder); \ - /**/ - -#define LWTRACE_INLINE_SYMBOL(text) \ - [&] { \ - static TString _holder(text); \ - return ::NLWTrace::TSymbol(&_holder); \ - }() /**/ - -#define LWTRACE_LOCATION_SYMBOL \ - [](const char* func) { \ +#include <util/string/builder.h> +#include <util/system/src_location.h> + +#define LWTRACE_DEFINE_SYMBOL(variable, text) \ + static TString variable##_holder(text); \ + ::NLWTrace::TSymbol variable(&variable##_holder); \ + /**/ + +#define LWTRACE_INLINE_SYMBOL(text) \ + [&] { \ + static TString _holder(text); \ + return ::NLWTrace::TSymbol(&_holder); \ + }() /**/ + +#define LWTRACE_LOCATION_SYMBOL \ + [](const char* func) { \ static TString _holder(TStringBuilder() << func << " (" << __LOCATION__ << ")"); \ - return ::NLWTrace::TSymbol(&_holder); \ - }(Y_FUNC_SIGNATURE) /**/ - -namespace NLWTrace { - struct TSymbol { - TString* Str; - - TSymbol() - : Str(nullptr) - { - } - - explicit TSymbol(TString* str) - : Str(str) - { - } - - TSymbol& operator=(const TSymbol& o) { - Str = o.Str; - return *this; - } - - TSymbol(const TSymbol& o) - : Str(o.Str) - { - } - - bool operator<(const TSymbol& rhs) const { - return Str < rhs.Str; - } - bool operator>(const TSymbol& rhs) const { - return Str > rhs.Str; - } - bool operator<=(const TSymbol& rhs) const { - return Str <= rhs.Str; - } - bool operator>=(const TSymbol& rhs) const { - return Str >= rhs.Str; - } - bool operator==(const TSymbol& rhs) const { - return Str == rhs.Str; - } - bool operator!=(const TSymbol& rhs) const { - return Str != rhs.Str; - } - }; - -} + return ::NLWTrace::TSymbol(&_holder); \ + }(Y_FUNC_SIGNATURE) /**/ + +namespace NLWTrace { + struct TSymbol { + TString* Str; + + TSymbol() + : Str(nullptr) + { + } + + explicit TSymbol(TString* str) + : Str(str) + { + } + + TSymbol& operator=(const TSymbol& o) { + Str = o.Str; + return *this; + } + + TSymbol(const TSymbol& o) + : Str(o.Str) + { + } + + bool operator<(const TSymbol& rhs) const { + return Str < rhs.Str; + } + bool operator>(const TSymbol& rhs) const { + return Str > rhs.Str; + } + bool operator<=(const TSymbol& rhs) const { + return Str <= rhs.Str; + } + bool operator>=(const TSymbol& rhs) const { + return Str >= rhs.Str; + } + bool operator==(const TSymbol& rhs) const { + return Str == rhs.Str; + } + bool operator!=(const TSymbol& rhs) const { + return Str != rhs.Str; + } + }; + +} diff --git a/library/cpp/lwtrace/tests/trace_tests.cpp b/library/cpp/lwtrace/tests/trace_tests.cpp index 6762e344a7..52f24f3685 100644 --- a/library/cpp/lwtrace/tests/trace_tests.cpp +++ b/library/cpp/lwtrace/tests/trace_tests.cpp @@ -6,710 +6,710 @@ #include <util/system/pipe.h> #include <util/generic/ymath.h> -#include <util/string/printf.h> -#include <util/string/vector.h> - -#define LWTRACE_TESTS_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ - PROBE(Simplest, GROUPS("Group"), TYPES(), NAMES()) \ - PROBE(IntParam, GROUPS("Group"), TYPES(ui32), NAMES("value")) \ - PROBE(StringParam, GROUPS("Group"), TYPES(TString), NAMES("value")) \ - PROBE(SymbolParam, GROUPS("Group"), TYPES(NLWTrace::TSymbol), NAMES("symbol")) \ - PROBE(CheckParam, GROUPS("Group"), TYPES(NLWTrace::TCheck), NAMES("value")) \ - EVENT(TwoParamsEvent, GROUPS("Group"), TYPES(int, TString), NAMES("param1", "param2")) \ +#include <util/string/printf.h> +#include <util/string/vector.h> + +#define LWTRACE_TESTS_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(Simplest, GROUPS("Group"), TYPES(), NAMES()) \ + PROBE(IntParam, GROUPS("Group"), TYPES(ui32), NAMES("value")) \ + PROBE(StringParam, GROUPS("Group"), TYPES(TString), NAMES("value")) \ + PROBE(SymbolParam, GROUPS("Group"), TYPES(NLWTrace::TSymbol), NAMES("symbol")) \ + PROBE(CheckParam, GROUPS("Group"), TYPES(NLWTrace::TCheck), NAMES("value")) \ + EVENT(TwoParamsEvent, GROUPS("Group"), TYPES(int, TString), NAMES("param1", "param2")) \ EVENT(TwoParamsCheckEvent, GROUPS("Group"), TYPES(NLWTrace::TCheck, TString), NAMES("param1", "param2")) \ - /**/ - -LWTRACE_DECLARE_PROVIDER(LWTRACE_TESTS_PROVIDER) -LWTRACE_DEFINE_PROVIDER(LWTRACE_TESTS_PROVIDER) -LWTRACE_USING(LWTRACE_TESTS_PROVIDER) - -namespace NLWTrace { - namespace NTests { - TString gStrValue = "a long string value that can be possible passed as a trace probe string parameter"; - //TString gStrValue = "short"; - - LWTRACE_DEFINE_SYMBOL(gSymbol, "a long symbol value that can be possible passed as a trace probe string parameter"); - - struct TConfig { - size_t Cycles; - size_t Runs; - bool UnsafeLWTrace; - - TConfig() { - Cycles = 100000; - Runs = 10; - UnsafeLWTrace = false; - } - }; - - struct TMeasure { - double Average; - double Sigma; - TMeasure(double a, double s) - : Average(a) - , Sigma(s) - { - } - }; - -#define DEFINE_MEASUREMENT(name, ...) \ - double name##OneRun(const TConfig& cfg) { \ - TInstant t0 = Now(); \ - for (size_t i = 0; i < cfg.Cycles; i++) { \ - HOTSPOT(name, ##__VA_ARGS__); \ - HOTSPOT(name, ##__VA_ARGS__); \ - HOTSPOT(name, ##__VA_ARGS__); \ - HOTSPOT(name, ##__VA_ARGS__); \ - HOTSPOT(name, ##__VA_ARGS__); \ - HOTSPOT(name, ##__VA_ARGS__); \ - HOTSPOT(name, ##__VA_ARGS__); \ - HOTSPOT(name, ##__VA_ARGS__); \ - HOTSPOT(name, ##__VA_ARGS__); \ - HOTSPOT(name, ##__VA_ARGS__); \ - } \ - TInstant t1 = Now(); \ - return double(t1.MicroSeconds() - t0.MicroSeconds()) / (cfg.Cycles * 10); \ - } \ - TMeasure name##Time(const TConfig& cfg) { \ - double v = 0; \ - double vSq = 0; \ - for (size_t i = 0; i < cfg.Runs; i++) { \ - double value = name##OneRun(cfg); \ - v += value; \ - vSq += value * value; \ - } \ - v /= cfg.Runs; \ - vSq /= cfg.Runs; \ - return TMeasure(v, sqrt(vSq - v * v)); \ - } \ - /**/ - - class TProbes: public TProbeRegistry { - public: - TManager Mngr; - - TProbes(bool destructiveActionsAllowed) - : Mngr(*this, destructiveActionsAllowed) - { - AddProbesList(LWTRACE_GET_PROBES(LWTRACE_TESTS_PROVIDER)); - } - -#define HOTSPOT(name, ...) LWPROBE(name, ##__VA_ARGS__); - DEFINE_MEASUREMENT(Simplest); - DEFINE_MEASUREMENT(IntParam, 123); - DEFINE_MEASUREMENT(StringParam, gStrValue); - DEFINE_MEASUREMENT(SymbolParam, gSymbol); - DEFINE_MEASUREMENT(CheckParam, TCheck(13)); -#undef HOTSPOT - }; - - class TInMemoryLogTest { - public: - TInMemoryLog Log; - - TInMemoryLogTest() - : Log(1000) - { - } - -#define HOTSPOT(name, ...) LWEVENT(name, Log, true, ##__VA_ARGS__); - DEFINE_MEASUREMENT(TwoParamsEvent, 666, TString("bla-bla-bla")); -#undef HOTSPOT - }; - - class TInMemoryLogCheckTest { - public: - TInMemoryLog Log; - - TInMemoryLogCheckTest() - : Log(1000) - { - } - -#define HOTSPOT(name, ...) LWEVENT(name, Log, true, ##__VA_ARGS__); - DEFINE_MEASUREMENT(TwoParamsCheckEvent, TCheck(666), TString("bla-bla-bla")); -#undef HOTSPOT - }; - - NLWTrace::TQuery MakeQuery(const TString& queryStr) { - NLWTrace::TQuery query; - google::protobuf::TextFormat::ParseFromString(queryStr, &query); - return query; - } - - void NoExec(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - Cout << "call to probe w/o executor: " << p.SimplestTime(cfg) << Endl; - } - - void Log(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"Simplest\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to probe with logging executor: " << p.SimplestTime(cfg) << Endl; - } - - void LogTs(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"Simplest\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Action {" - " LogAction {" - " LogTimestamp: true" - " }" - " }" - "}")); - Cout << "call to probe with logging (+timestamp) executor: " << p.SimplestTime(cfg) << Endl; - } - - void FalseIntFilter(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"IntParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Predicate {" - " Operators {" - " Type: OT_GT" - " Argument {" - " Param: \"value\"" - " }" - " Argument {" - " Value: \"1000\"" - " }" - " }" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to probe with int filter (always false) executor: " << p.IntParamTime(cfg) << Endl; - } - - void LogIntAfterFilter(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"IntParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Predicate {" - " Operators {" - " Type: OT_GT" - " Argument {" - " Param: \"value\"" - " }" - " Argument {" - " Value: \"0\"" - " }" - " }" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to probe with int filter (always true) and log executors: " << p.IntParamTime(cfg) << Endl; - } - - void LogInt(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"IntParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to int probe with log executor: " << p.IntParamTime(cfg) << Endl; - } - - void FalseStringFilter(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"StringParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Predicate {" - " Operators {" - " Type: OT_EQ" - " Argument {" - " Param: \"value\"" - " }" - " Argument {" - " Value: \"string that never can exist\"" - " }" - " }" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to probe with string filter (always false) executor: " << p.StringParamTime(cfg) << Endl; - } - - void FalseStringFilterPartialMatch(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"StringParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Predicate {" - " Operators {" - " Type: OT_EQ" - " Argument {" - " Param: \"value\"" - " }" - " Argument {" - " Value: \"" + - gStrValue + "-not-full-match\"" - " }" - " }" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to probe with string filter (always false) executor: " << p.StringParamTime(cfg) << Endl; - } - - void LogStringAfterFilter(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"StringParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Predicate {" - " Operators {" - " Type: OT_EQ" - " Argument {" - " Param: \"value\"" - " }" - " Argument {" - " Value: \"" + - gStrValue + "\"" - " }" - " }" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to probe with string filter (always true) and log executors: " << p.StringParamTime(cfg) << Endl; - } - - void LogString(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"StringParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to string probe with log executor: " << p.StringParamTime(cfg) << Endl; - } - - void LogSymbol(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"SymbolParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to symbol probe with log executor: " << p.SymbolParamTime(cfg) << Endl; - } - - void LogCheck(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"CheckParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to check probe with log executor: " << p.CheckParamTime(cfg) << Endl; - } - - void InMemoryLog(const TConfig& cfg) { - TInMemoryLogTest test; - Cout << "log to in-memory log with (int, string) writer: " << test.TwoParamsEventTime(cfg) << Endl; - } - - void InMemoryLogCheck(const TConfig& cfg) { - TInMemoryLogCheckTest test; - Cout << "log to in-memory log with (leak-check, string) writer: " << test.TwoParamsCheckEventTime(cfg) << Endl; - } - - void MultipleActionsCheck(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-multipleActions", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"Simplest\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Predicate {" - " Operators {" - " Type: OT_LT" - " Argument {" - " Variable: \"counter\"" - " }" - " Argument {" - " Value: \"2\"" - " }" - " }" - " }" - " Action {" - " StatementAction {" - " Type: ST_INC" - " Argument {" - " Variable: \"counter\"" - " }" - " }" - " }" - " Action {" - " StatementAction {" - " Type: ST_DEC" - " Argument {" - " Variable: \"counter\"" - " }" - " }" - " }" - " Action {" - " StatementAction {" - " Type: ST_SUB_EQ" - " Argument {" - " Variable: \"counter\"" - " }" - " Argument {" - " Value: \"-1\"" - " }" - " }" - " }" - " Action {" - " SleepAction {" - " NanoSeconds: 25000000" // 25 ms - " }" - " }" - " Action {" - " SleepAction {" - " NanoSeconds: 25000000" // 25 ms - " }" - " }" - "}")); - TInstant t0 = Now(); - for (size_t i = 0; i < 10; i++) { - LWPROBE(Simplest); - } - TInstant t1 = Now(); - ui64 duration = (t1.NanoSeconds() - t0.NanoSeconds()); - Cout << "multiple sleep tested, expected 100000000 ns, measured " << duration << " ns" << Endl; - } - - void SleepCheck(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-sleep", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"Simplest\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Action {" - " SleepAction {" - " NanoSeconds: 100000000" // 100 ms - " }" - " }" - "}")); - TInstant t0 = Now(); - for (size_t i = 0; i < 10; i++) { - LWPROBE(Simplest); - } - TInstant t1 = Now(); - ui64 duration = (t1.NanoSeconds() - t0.NanoSeconds()) / (ui64)10; - Cout << "sleep tested, expected 100000000 ns, measured " << duration << " ns" << Endl; - } - - void KillCheckChild(const TConfig& cfg, TPipeHandle& writer) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-kill", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"Simplest\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Action {" - " KillAction {" - " }" - " }" - "}")); - // Send "i'm alive and ok" to the parent (0) - char buffer = 0; - writer.Write(&buffer, 1); - LWPROBE(Simplest); - // Send "i'm alive and that's not OK" to the parent (1) - buffer = 1; - writer.Write(&buffer, 1); - } - - void KillCheckParent(TPipeHandle& reader) { - char buffer = -1; - reader.Read(&buffer, 1); - reader.Read(&buffer, 1); - if (buffer == -1) - Cerr << "\t\terror: process died before transfering OK message during the KillAction test!" << Endl; - else if (buffer != 0) - Cerr << "\t\terror: process failed to die on time during the KillAction test!" << Endl; - else - Cout << "\t\tkill executor tested OK." << Endl; - } - - void KillCheck(const TConfig& cfg) { + /**/ + +LWTRACE_DECLARE_PROVIDER(LWTRACE_TESTS_PROVIDER) +LWTRACE_DEFINE_PROVIDER(LWTRACE_TESTS_PROVIDER) +LWTRACE_USING(LWTRACE_TESTS_PROVIDER) + +namespace NLWTrace { + namespace NTests { + TString gStrValue = "a long string value that can be possible passed as a trace probe string parameter"; + //TString gStrValue = "short"; + + LWTRACE_DEFINE_SYMBOL(gSymbol, "a long symbol value that can be possible passed as a trace probe string parameter"); + + struct TConfig { + size_t Cycles; + size_t Runs; + bool UnsafeLWTrace; + + TConfig() { + Cycles = 100000; + Runs = 10; + UnsafeLWTrace = false; + } + }; + + struct TMeasure { + double Average; + double Sigma; + TMeasure(double a, double s) + : Average(a) + , Sigma(s) + { + } + }; + +#define DEFINE_MEASUREMENT(name, ...) \ + double name##OneRun(const TConfig& cfg) { \ + TInstant t0 = Now(); \ + for (size_t i = 0; i < cfg.Cycles; i++) { \ + HOTSPOT(name, ##__VA_ARGS__); \ + HOTSPOT(name, ##__VA_ARGS__); \ + HOTSPOT(name, ##__VA_ARGS__); \ + HOTSPOT(name, ##__VA_ARGS__); \ + HOTSPOT(name, ##__VA_ARGS__); \ + HOTSPOT(name, ##__VA_ARGS__); \ + HOTSPOT(name, ##__VA_ARGS__); \ + HOTSPOT(name, ##__VA_ARGS__); \ + HOTSPOT(name, ##__VA_ARGS__); \ + HOTSPOT(name, ##__VA_ARGS__); \ + } \ + TInstant t1 = Now(); \ + return double(t1.MicroSeconds() - t0.MicroSeconds()) / (cfg.Cycles * 10); \ + } \ + TMeasure name##Time(const TConfig& cfg) { \ + double v = 0; \ + double vSq = 0; \ + for (size_t i = 0; i < cfg.Runs; i++) { \ + double value = name##OneRun(cfg); \ + v += value; \ + vSq += value * value; \ + } \ + v /= cfg.Runs; \ + vSq /= cfg.Runs; \ + return TMeasure(v, sqrt(vSq - v * v)); \ + } \ + /**/ + + class TProbes: public TProbeRegistry { + public: + TManager Mngr; + + TProbes(bool destructiveActionsAllowed) + : Mngr(*this, destructiveActionsAllowed) + { + AddProbesList(LWTRACE_GET_PROBES(LWTRACE_TESTS_PROVIDER)); + } + +#define HOTSPOT(name, ...) LWPROBE(name, ##__VA_ARGS__); + DEFINE_MEASUREMENT(Simplest); + DEFINE_MEASUREMENT(IntParam, 123); + DEFINE_MEASUREMENT(StringParam, gStrValue); + DEFINE_MEASUREMENT(SymbolParam, gSymbol); + DEFINE_MEASUREMENT(CheckParam, TCheck(13)); +#undef HOTSPOT + }; + + class TInMemoryLogTest { + public: + TInMemoryLog Log; + + TInMemoryLogTest() + : Log(1000) + { + } + +#define HOTSPOT(name, ...) LWEVENT(name, Log, true, ##__VA_ARGS__); + DEFINE_MEASUREMENT(TwoParamsEvent, 666, TString("bla-bla-bla")); +#undef HOTSPOT + }; + + class TInMemoryLogCheckTest { + public: + TInMemoryLog Log; + + TInMemoryLogCheckTest() + : Log(1000) + { + } + +#define HOTSPOT(name, ...) LWEVENT(name, Log, true, ##__VA_ARGS__); + DEFINE_MEASUREMENT(TwoParamsCheckEvent, TCheck(666), TString("bla-bla-bla")); +#undef HOTSPOT + }; + + NLWTrace::TQuery MakeQuery(const TString& queryStr) { + NLWTrace::TQuery query; + google::protobuf::TextFormat::ParseFromString(queryStr, &query); + return query; + } + + void NoExec(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + Cout << "call to probe w/o executor: " << p.SimplestTime(cfg) << Endl; + } + + void Log(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"Simplest\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to probe with logging executor: " << p.SimplestTime(cfg) << Endl; + } + + void LogTs(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"Simplest\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Action {" + " LogAction {" + " LogTimestamp: true" + " }" + " }" + "}")); + Cout << "call to probe with logging (+timestamp) executor: " << p.SimplestTime(cfg) << Endl; + } + + void FalseIntFilter(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"IntParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Predicate {" + " Operators {" + " Type: OT_GT" + " Argument {" + " Param: \"value\"" + " }" + " Argument {" + " Value: \"1000\"" + " }" + " }" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to probe with int filter (always false) executor: " << p.IntParamTime(cfg) << Endl; + } + + void LogIntAfterFilter(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"IntParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Predicate {" + " Operators {" + " Type: OT_GT" + " Argument {" + " Param: \"value\"" + " }" + " Argument {" + " Value: \"0\"" + " }" + " }" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to probe with int filter (always true) and log executors: " << p.IntParamTime(cfg) << Endl; + } + + void LogInt(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"IntParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to int probe with log executor: " << p.IntParamTime(cfg) << Endl; + } + + void FalseStringFilter(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"StringParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Predicate {" + " Operators {" + " Type: OT_EQ" + " Argument {" + " Param: \"value\"" + " }" + " Argument {" + " Value: \"string that never can exist\"" + " }" + " }" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to probe with string filter (always false) executor: " << p.StringParamTime(cfg) << Endl; + } + + void FalseStringFilterPartialMatch(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"StringParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Predicate {" + " Operators {" + " Type: OT_EQ" + " Argument {" + " Param: \"value\"" + " }" + " Argument {" + " Value: \"" + + gStrValue + "-not-full-match\"" + " }" + " }" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to probe with string filter (always false) executor: " << p.StringParamTime(cfg) << Endl; + } + + void LogStringAfterFilter(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"StringParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Predicate {" + " Operators {" + " Type: OT_EQ" + " Argument {" + " Param: \"value\"" + " }" + " Argument {" + " Value: \"" + + gStrValue + "\"" + " }" + " }" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to probe with string filter (always true) and log executors: " << p.StringParamTime(cfg) << Endl; + } + + void LogString(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"StringParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to string probe with log executor: " << p.StringParamTime(cfg) << Endl; + } + + void LogSymbol(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"SymbolParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to symbol probe with log executor: " << p.SymbolParamTime(cfg) << Endl; + } + + void LogCheck(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"CheckParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to check probe with log executor: " << p.CheckParamTime(cfg) << Endl; + } + + void InMemoryLog(const TConfig& cfg) { + TInMemoryLogTest test; + Cout << "log to in-memory log with (int, string) writer: " << test.TwoParamsEventTime(cfg) << Endl; + } + + void InMemoryLogCheck(const TConfig& cfg) { + TInMemoryLogCheckTest test; + Cout << "log to in-memory log with (leak-check, string) writer: " << test.TwoParamsCheckEventTime(cfg) << Endl; + } + + void MultipleActionsCheck(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-multipleActions", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"Simplest\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Predicate {" + " Operators {" + " Type: OT_LT" + " Argument {" + " Variable: \"counter\"" + " }" + " Argument {" + " Value: \"2\"" + " }" + " }" + " }" + " Action {" + " StatementAction {" + " Type: ST_INC" + " Argument {" + " Variable: \"counter\"" + " }" + " }" + " }" + " Action {" + " StatementAction {" + " Type: ST_DEC" + " Argument {" + " Variable: \"counter\"" + " }" + " }" + " }" + " Action {" + " StatementAction {" + " Type: ST_SUB_EQ" + " Argument {" + " Variable: \"counter\"" + " }" + " Argument {" + " Value: \"-1\"" + " }" + " }" + " }" + " Action {" + " SleepAction {" + " NanoSeconds: 25000000" // 25 ms + " }" + " }" + " Action {" + " SleepAction {" + " NanoSeconds: 25000000" // 25 ms + " }" + " }" + "}")); + TInstant t0 = Now(); + for (size_t i = 0; i < 10; i++) { + LWPROBE(Simplest); + } + TInstant t1 = Now(); + ui64 duration = (t1.NanoSeconds() - t0.NanoSeconds()); + Cout << "multiple sleep tested, expected 100000000 ns, measured " << duration << " ns" << Endl; + } + + void SleepCheck(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-sleep", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"Simplest\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Action {" + " SleepAction {" + " NanoSeconds: 100000000" // 100 ms + " }" + " }" + "}")); + TInstant t0 = Now(); + for (size_t i = 0; i < 10; i++) { + LWPROBE(Simplest); + } + TInstant t1 = Now(); + ui64 duration = (t1.NanoSeconds() - t0.NanoSeconds()) / (ui64)10; + Cout << "sleep tested, expected 100000000 ns, measured " << duration << " ns" << Endl; + } + + void KillCheckChild(const TConfig& cfg, TPipeHandle& writer) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-kill", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"Simplest\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Action {" + " KillAction {" + " }" + " }" + "}")); + // Send "i'm alive and ok" to the parent (0) + char buffer = 0; + writer.Write(&buffer, 1); + LWPROBE(Simplest); + // Send "i'm alive and that's not OK" to the parent (1) + buffer = 1; + writer.Write(&buffer, 1); + } + + void KillCheckParent(TPipeHandle& reader) { + char buffer = -1; + reader.Read(&buffer, 1); + reader.Read(&buffer, 1); + if (buffer == -1) + Cerr << "\t\terror: process died before transfering OK message during the KillAction test!" << Endl; + else if (buffer != 0) + Cerr << "\t\terror: process failed to die on time during the KillAction test!" << Endl; + else + Cout << "\t\tkill executor tested OK." << Endl; + } + + void KillCheck(const TConfig& cfg) { #ifdef _unix_ - TPipeHandle reader; - TPipeHandle writer; - TPipeHandle::Pipe(reader, writer); - Cout << "forking the process..." << Endl; - pid_t cpid = fork(); - if (cpid == -1) { - Cerr << "\t\terror forking for the KillAction test!" << Endl; - } else if (cpid == 0) { - reader.Close(); - KillCheckChild(cfg, writer); - writer.Close(); - exit(EXIT_SUCCESS); - } else { - writer.Close(); - KillCheckParent(reader); - reader.Close(); - } + TPipeHandle reader; + TPipeHandle writer; + TPipeHandle::Pipe(reader, writer); + Cout << "forking the process..." << Endl; + pid_t cpid = fork(); + if (cpid == -1) { + Cerr << "\t\terror forking for the KillAction test!" << Endl; + } else if (cpid == 0) { + reader.Close(); + KillCheckChild(cfg, writer); + writer.Close(); + exit(EXIT_SUCCESS); + } else { + writer.Close(); + KillCheckParent(reader); + reader.Close(); + } #else - Cout << "kill action test for windows is not implemented." << Endl; + Cout << "kill action test for windows is not implemented." << Endl; #endif - } - - void LogIntModFilter(const TConfig& cfg) { - TProbes p(cfg.UnsafeLWTrace); - p.Mngr.New("test-trace", MakeQuery( - "Blocks {" - " ProbeDesc {" - " Name: \"IntParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Predicate {" - " Operators {" - " Type: OT_GT" - " Argument {" - " Param: \"value\"" - " }" - " Argument {" - " Value: \"0\"" - " }" - " }" - " }" - " Action {" - " StatementAction {" - " Type: ST_ADD_EQ" - " Argument {" - " Variable: \"counter\"" - " }" - " Argument {" - " Value: \"1\"" - " }" - " }" - " }" - " Action {" - " StatementAction {" - " Type: ST_ADD" - " Argument {" - " Variable: \"counter\"" - " }" - " Argument {" - " Variable: \"counter\"" - " }" - " Argument {" - " Value: \"1\"" - " }" - " }" - " }" - " Action {" - " StatementAction {" - " Type: ST_MOD" - " Argument {" - " Variable: \"counter\"" - " }" - " Argument {" - " Variable: \"counter\"" - " }" - " Argument {" - " Value: \"20\"" - " }" - " }" - " }" - "}" - "Blocks {" - " ProbeDesc {" - " Name: \"IntParam\"" - " Provider: \"LWTRACE_TESTS_PROVIDER\"" - " }" - " Predicate {" - " Operators {" - " Type: OT_EQ" - " Argument {" - " Variable: \"counter\"" - " }" - " Argument {" - " Value: \"0\"" - " }" - " }" - " Operators {" - " Type: OT_GT" - " Argument {" - " Param: \"value\"" - " }" - " Argument {" - " Value: \"0\"" - " }" - " }" - " }" - " Action {" - " LogAction {" - " LogTimestamp: false" - " }" - " }" - "}")); - Cout << "call to probe with int mod filter (always true, mod 10) and log executors: " << p.IntParamTime(cfg) << Endl; - } - -#define FOR_EACH_TEST() \ - FOR_EACH_TEST_MACRO(LogIntModFilter) \ - FOR_EACH_TEST_MACRO(SleepCheck) \ - FOR_EACH_TEST_MACRO(MultipleActionsCheck) \ - FOR_EACH_TEST_MACRO(KillCheck) \ - FOR_EACH_TEST_MACRO(InMemoryLog) \ - FOR_EACH_TEST_MACRO(InMemoryLogCheck) \ - FOR_EACH_TEST_MACRO(NoExec) \ - FOR_EACH_TEST_MACRO(Log) \ - FOR_EACH_TEST_MACRO(LogTs) \ - FOR_EACH_TEST_MACRO(FalseIntFilter) \ - FOR_EACH_TEST_MACRO(LogIntAfterFilter) \ - FOR_EACH_TEST_MACRO(LogInt) \ - FOR_EACH_TEST_MACRO(FalseStringFilter) \ - FOR_EACH_TEST_MACRO(FalseStringFilterPartialMatch) \ - FOR_EACH_TEST_MACRO(LogStringAfterFilter) \ - FOR_EACH_TEST_MACRO(LogString) \ - FOR_EACH_TEST_MACRO(LogSymbol) \ - FOR_EACH_TEST_MACRO(LogCheck) \ - /**/ - - int Main(int argc, char** argv) { - TConfig cfg; - using namespace NLastGetopt; - TOpts opts = NLastGetopt::TOpts::Default(); - opts.AddLongOption('c', "cycles", "cycles count").RequiredArgument("N").DefaultValue(ToString(cfg.Cycles)).StoreResult(&cfg.Cycles); - opts.AddLongOption('r', "runs", "runs count").RequiredArgument("N").DefaultValue(ToString(cfg.Runs)).StoreResult(&cfg.Runs); - opts.AddLongOption('u', "unsafe-lwtrace", "allow destructive actions").OptionalValue(ToString(true)).DefaultValue(ToString(false)).StoreResult(&cfg.UnsafeLWTrace); - opts.AddHelpOption('h'); - TOptsParseResult res(&opts, argc, argv); - - TVector<TString> tests = res.GetFreeArgs(); - if (tests.empty()) { -#define FOR_EACH_TEST_MACRO(t) tests.push_back(#t); - FOR_EACH_TEST() -#undef FOR_EACH_TEST_MACRO - } - for (size_t i = 0; i < tests.size(); i++) { - const TString& test = tests[i]; -#define FOR_EACH_TEST_MACRO(t) \ - if (test == #t) { \ - Cout << #t ": \t"; \ - t(cfg); \ - } - FOR_EACH_TEST() -#undef FOR_EACH_TEST_MACRO - } - - if (TCheck::ObjCount != 0) { - Cout << ">>>>> THERE IS AN OBJECT LEAK <<<<<" << Endl; - Cout << "NLWTrace::TCheck::ObjCount = " << TCheck::ObjCount << Endl; - } - - Cout << "Done" << Endl; - return 0; - } - - } - -} - -template <> + } + + void LogIntModFilter(const TConfig& cfg) { + TProbes p(cfg.UnsafeLWTrace); + p.Mngr.New("test-trace", MakeQuery( + "Blocks {" + " ProbeDesc {" + " Name: \"IntParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Predicate {" + " Operators {" + " Type: OT_GT" + " Argument {" + " Param: \"value\"" + " }" + " Argument {" + " Value: \"0\"" + " }" + " }" + " }" + " Action {" + " StatementAction {" + " Type: ST_ADD_EQ" + " Argument {" + " Variable: \"counter\"" + " }" + " Argument {" + " Value: \"1\"" + " }" + " }" + " }" + " Action {" + " StatementAction {" + " Type: ST_ADD" + " Argument {" + " Variable: \"counter\"" + " }" + " Argument {" + " Variable: \"counter\"" + " }" + " Argument {" + " Value: \"1\"" + " }" + " }" + " }" + " Action {" + " StatementAction {" + " Type: ST_MOD" + " Argument {" + " Variable: \"counter\"" + " }" + " Argument {" + " Variable: \"counter\"" + " }" + " Argument {" + " Value: \"20\"" + " }" + " }" + " }" + "}" + "Blocks {" + " ProbeDesc {" + " Name: \"IntParam\"" + " Provider: \"LWTRACE_TESTS_PROVIDER\"" + " }" + " Predicate {" + " Operators {" + " Type: OT_EQ" + " Argument {" + " Variable: \"counter\"" + " }" + " Argument {" + " Value: \"0\"" + " }" + " }" + " Operators {" + " Type: OT_GT" + " Argument {" + " Param: \"value\"" + " }" + " Argument {" + " Value: \"0\"" + " }" + " }" + " }" + " Action {" + " LogAction {" + " LogTimestamp: false" + " }" + " }" + "}")); + Cout << "call to probe with int mod filter (always true, mod 10) and log executors: " << p.IntParamTime(cfg) << Endl; + } + +#define FOR_EACH_TEST() \ + FOR_EACH_TEST_MACRO(LogIntModFilter) \ + FOR_EACH_TEST_MACRO(SleepCheck) \ + FOR_EACH_TEST_MACRO(MultipleActionsCheck) \ + FOR_EACH_TEST_MACRO(KillCheck) \ + FOR_EACH_TEST_MACRO(InMemoryLog) \ + FOR_EACH_TEST_MACRO(InMemoryLogCheck) \ + FOR_EACH_TEST_MACRO(NoExec) \ + FOR_EACH_TEST_MACRO(Log) \ + FOR_EACH_TEST_MACRO(LogTs) \ + FOR_EACH_TEST_MACRO(FalseIntFilter) \ + FOR_EACH_TEST_MACRO(LogIntAfterFilter) \ + FOR_EACH_TEST_MACRO(LogInt) \ + FOR_EACH_TEST_MACRO(FalseStringFilter) \ + FOR_EACH_TEST_MACRO(FalseStringFilterPartialMatch) \ + FOR_EACH_TEST_MACRO(LogStringAfterFilter) \ + FOR_EACH_TEST_MACRO(LogString) \ + FOR_EACH_TEST_MACRO(LogSymbol) \ + FOR_EACH_TEST_MACRO(LogCheck) \ + /**/ + + int Main(int argc, char** argv) { + TConfig cfg; + using namespace NLastGetopt; + TOpts opts = NLastGetopt::TOpts::Default(); + opts.AddLongOption('c', "cycles", "cycles count").RequiredArgument("N").DefaultValue(ToString(cfg.Cycles)).StoreResult(&cfg.Cycles); + opts.AddLongOption('r', "runs", "runs count").RequiredArgument("N").DefaultValue(ToString(cfg.Runs)).StoreResult(&cfg.Runs); + opts.AddLongOption('u', "unsafe-lwtrace", "allow destructive actions").OptionalValue(ToString(true)).DefaultValue(ToString(false)).StoreResult(&cfg.UnsafeLWTrace); + opts.AddHelpOption('h'); + TOptsParseResult res(&opts, argc, argv); + + TVector<TString> tests = res.GetFreeArgs(); + if (tests.empty()) { +#define FOR_EACH_TEST_MACRO(t) tests.push_back(#t); + FOR_EACH_TEST() +#undef FOR_EACH_TEST_MACRO + } + for (size_t i = 0; i < tests.size(); i++) { + const TString& test = tests[i]; +#define FOR_EACH_TEST_MACRO(t) \ + if (test == #t) { \ + Cout << #t ": \t"; \ + t(cfg); \ + } + FOR_EACH_TEST() +#undef FOR_EACH_TEST_MACRO + } + + if (TCheck::ObjCount != 0) { + Cout << ">>>>> THERE IS AN OBJECT LEAK <<<<<" << Endl; + Cout << "NLWTrace::TCheck::ObjCount = " << TCheck::ObjCount << Endl; + } + + Cout << "Done" << Endl; + return 0; + } + + } + +} + +template <> void Out<NLWTrace::NTests::TMeasure>(IOutputStream& os, TTypeTraits<NLWTrace::NTests::TMeasure>::TFuncParam measure) { - os << Sprintf("\n\t\t%.6lf +- %.6lf us,\tRPS: %30.3lf (%.1fM)", measure.Average, measure.Sigma, 1000000.0 / measure.Average, 1.0 / measure.Average); -} - -int main(int argc, char** argv) { - try { - return NLWTrace::NTests::Main(argc, argv); - } catch (std::exception& e) { - Cerr << e.what() << Endl; - return 1; - } catch (...) { - Cerr << "Unknown error" << Endl; - return 1; - } -} + os << Sprintf("\n\t\t%.6lf +- %.6lf us,\tRPS: %30.3lf (%.1fM)", measure.Average, measure.Sigma, 1000000.0 / measure.Average, 1.0 / measure.Average); +} + +int main(int argc, char** argv) { + try { + return NLWTrace::NTests::Main(argc, argv); + } catch (std::exception& e) { + Cerr << e.what() << Endl; + return 1; + } catch (...) { + Cerr << "Unknown error" << Endl; + return 1; + } +} diff --git a/library/cpp/lwtrace/tests/ya.make b/library/cpp/lwtrace/tests/ya.make index 6225ab1fa0..072cbba5d4 100644 --- a/library/cpp/lwtrace/tests/ya.make +++ b/library/cpp/lwtrace/tests/ya.make @@ -1,15 +1,15 @@ OWNER(serxa) -PROGRAM() - -SRCS( - trace_tests.cpp -) - -PEERDIR( +PROGRAM() + +SRCS( + trace_tests.cpp +) + +PEERDIR( contrib/libs/protobuf library/cpp/getopt library/cpp/lwtrace -) - -END() +) + +END() diff --git a/library/cpp/lwtrace/trace.cpp b/library/cpp/lwtrace/trace.cpp index 3c974c85a0..c4d30b1796 100644 --- a/library/cpp/lwtrace/trace.cpp +++ b/library/cpp/lwtrace/trace.cpp @@ -6,812 +6,812 @@ #include "stderr_writer.h" #include "google/protobuf/repeated_field.h" -#include <util/generic/map.h> -#include <util/random/random.h> - +#include <util/generic/map.h> +#include <util/random/random.h> + #include <functional> -namespace NLWTrace { -#ifndef LWTRACE_DISABLE - -// Define static strings for name of each parameter type -#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ - const char* TParamType<t>::NameString = n; \ - /**/ - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) - FOR_NIL_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) -#undef FOREACH_PARAMTYPE_MACRO - -#endif - - void TProbeRegistry::AddProbesList(TProbe** reg) { - TGuard<TMutex> g(Mutex); - if (reg == nullptr) { - return; - } - for (TProbe** i = reg; *i != nullptr; i++) { - AddProbeNoLock(new TStaticBox(*i)); - } - } - - void TProbeRegistry::AddProbe(const TBoxPtr& box) { - TGuard<TMutex> g(Mutex); - AddProbeNoLock(box); - } - - void TProbeRegistry::RemoveProbe(TProbe* probe) { - TGuard<TMutex> g(Mutex); - RemoveProbeNoLock(probe); - } - - void TProbeRegistry::AddProbeNoLock(const TBoxPtr& box) { - TProbe* probe = box->GetProbe(); +namespace NLWTrace { +#ifndef LWTRACE_DISABLE + +// Define static strings for name of each parameter type +#define FOREACH_PARAMTYPE_MACRO(n, t, v) \ + const char* TParamType<t>::NameString = n; \ + /**/ + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) + FOR_NIL_PARAMTYPE(FOREACH_PARAMTYPE_MACRO) +#undef FOREACH_PARAMTYPE_MACRO + +#endif + + void TProbeRegistry::AddProbesList(TProbe** reg) { + TGuard<TMutex> g(Mutex); + if (reg == nullptr) { + return; + } + for (TProbe** i = reg; *i != nullptr; i++) { + AddProbeNoLock(new TStaticBox(*i)); + } + } + + void TProbeRegistry::AddProbe(const TBoxPtr& box) { + TGuard<TMutex> g(Mutex); + AddProbeNoLock(box); + } + + void TProbeRegistry::RemoveProbe(TProbe* probe) { + TGuard<TMutex> g(Mutex); + RemoveProbeNoLock(probe); + } + + void TProbeRegistry::AddProbeNoLock(const TBoxPtr& box) { + TProbe* probe = box->GetProbe(); if (Probes.contains(probe)) { - return; // silently skip probe double registration - } - TIds::key_type key(probe->Event.GetProvider(), probe->Event.Name); + return; // silently skip probe double registration + } + TIds::key_type key(probe->Event.GetProvider(), probe->Event.Name); Y_VERIFY(Ids.count(key) == 0, "duplicate provider:probe pair %s:%s", key.first.data(), key.second.data()); - Probes.emplace(probe, box); - Ids.insert(key); - } - - void TProbeRegistry::RemoveProbeNoLock(TProbe* probe) { - auto iter = Probes.find(probe); - if (iter != Probes.end()) { - TIds::key_type key(probe->Event.GetProvider(), probe->Event.Name); - Ids.erase(key); - Probes.erase(iter); - } else { - // silently skip probe double unregistration - } - } - - TAtomic* GetVariablePtr(TSession::TTraceVariables& traceVariables, const TString& name) { - TSession::TTraceVariables::iterator it = traceVariables.find(name); - if (it == traceVariables.end()) { - TAtomicBase zero = 0; - traceVariables[name] = zero; - return &traceVariables[name]; - } - return &((*it).second); - } - - typedef enum { - OT_LITERAL = 0, - OT_PARAMETER = 1, - OT_VARIABLE = 2 - } EOperandType; - - template <class T, EOperandType> - class TOperand; - - template <class T> - class TOperand<T, OT_LITERAL> { - private: - T ImmediateValue; - - public: - TOperand(TSession::TTraceVariables&, const TString&, const TString& value, size_t) { - ImmediateValue = TParamConv<T>::FromString(value); - } - const T& Get(const TParams&) { - return ImmediateValue; - } - }; - - template <class T> - class TOperand<T, OT_PARAMETER> { - private: - size_t Idx; - - public: - TOperand(TSession::TTraceVariables&, const TString&, const TString&, size_t idx) { - Idx = idx; - } - - const T& Get(const TParams& params) { - return params.Param[Idx].template Get<T>(); - } - }; - - template <class T> - class TOperand<T, OT_VARIABLE> { - private: - TAtomic* Variable; - - public: - TOperand(TSession::TTraceVariables& traceVariables, const TString& name, const TString&, size_t) { - Variable = GetVariablePtr(traceVariables, name); - } - - const T Get(const TParams&) { - return (T)AtomicGet(*Variable); - } - - void Set(const T& value) { - AtomicSet(*Variable, value); - } - - void Inc() { - AtomicIncrement(*Variable); - } - - void Dec() { - AtomicDecrement(*Variable); - } - - void Add(const TAtomicBase value) { - AtomicAdd(*Variable, value); - } - - void Sub(const TAtomicBase value) { - AtomicSub(*Variable, value); - } - }; - - template <> - class TOperand<TCheck, OT_VARIABLE> { - private: - TAtomic* Variable; - - public: - TOperand(TSession::TTraceVariables& traceVariables, const TString& name, const TString&, size_t) { - Variable = GetVariablePtr(traceVariables, name); - } - - const TCheck Get(const TParams&) { - return TCheck(AtomicGet(*Variable)); - } - - void Set(const TCheck& value) { - AtomicSet(*Variable, value.Value); - } - - void Add(const TCheck& value) { - AtomicAdd(*Variable, value.Value); - } - - void Sub(const TCheck value) { - AtomicSub(*Variable, value.Value); - } - - void Inc() { - AtomicIncrement(*Variable); - } - - void Dec() { - AtomicDecrement(*Variable); - } - }; - - template <> - class TOperand<TString, OT_VARIABLE> { - private: - TString Dummy; - - public: - TOperand(TSession::TTraceVariables&, const TString&, const TString&, size_t) { - } - - const TString Get(const TParams&) { - return Dummy; - } - - void Set(const TString&) { - } - }; - - template <> - class TOperand<TSymbol, OT_VARIABLE> { - private: - TSymbol Dummy; - - public: - TOperand(TSession::TTraceVariables&, const TString&, const TString&, size_t) { - } - - const TSymbol Get(const TParams&) { - return Dummy; - } - - void Set(const TSymbol&) { - } - }; - - // IOperandGetter: hide concrete EOperandType, to save compilation time - template <class T> - struct IOperandGetter { - virtual const T Get(const TParams& params) = 0; - virtual ~IOperandGetter() { - } - }; - - template <class T, EOperandType TParam> - class TOperandGetter: public IOperandGetter<T> { - private: - TOperand<T, TParam> Op; - - public: - TOperandGetter(const TOperand<T, TParam>& op) - : Op(op) - { - } - - const T Get(const TParams& params) override { - return Op.Get(params); - } - }; - - template <class T> - class TReceiver: public TOperand<T, OT_VARIABLE> { - public: - TReceiver(TSession::TTraceVariables& traceVariables, const TString& name) - : TOperand<T, OT_VARIABLE>(traceVariables, name, nullptr, 0) - { - } - }; - - template <class TP, class TPredicate> - static bool CmpFunc(TP a, TP b) { - return TPredicate()(a, b); + Probes.emplace(probe, box); + Ids.insert(key); + } + + void TProbeRegistry::RemoveProbeNoLock(TProbe* probe) { + auto iter = Probes.find(probe); + if (iter != Probes.end()) { + TIds::key_type key(probe->Event.GetProvider(), probe->Event.Name); + Ids.erase(key); + Probes.erase(iter); + } else { + // silently skip probe double unregistration + } + } + + TAtomic* GetVariablePtr(TSession::TTraceVariables& traceVariables, const TString& name) { + TSession::TTraceVariables::iterator it = traceVariables.find(name); + if (it == traceVariables.end()) { + TAtomicBase zero = 0; + traceVariables[name] = zero; + return &traceVariables[name]; + } + return &((*it).second); } - template <class TP, class TFunc, EOperandType TLhs, EOperandType TRhs> - class TOperatorExecutor: public IExecutor { - private: - bool InvertCompare; - TOperand<TP, TLhs> Lhs; - TOperand<TP, TRhs> Rhs; - - bool DoExecute(TOrbit&, const TParams& params) override { - return TFunc()(Lhs.Get(params), Rhs.Get(params)) != InvertCompare; - } - - public: - TOperatorExecutor(const TOperand<TP, TLhs>& lhs, const TOperand<TP, TRhs>& rhs, bool invertCompare) - : InvertCompare(invertCompare) - , Lhs(lhs) - , Rhs(rhs) - { - } - }; - - template <class TR, class TP> - struct TAddEq { - void operator()(TR& x, TP y) const { - x.Add(y); - } - }; - template <class TR, class TP> - struct TSubEq { - void operator()(TR& x, TP y) const { - x.Sub(y); - } - }; - template <class TR> - struct TInc { - void operator()(TR& x) const { - x.Inc(); - } - }; - template <class TR> - struct TDec { - void operator()(TR& x) const { - x.Dec(); - } - }; - - template <class TP, class TFunc> - class TUnaryInplaceStatementExecutor: public IExecutor { - private: - TFunc Func; - TReceiver<TP> Receiver; - - bool DoExecute(TOrbit&, const TParams&) override { - Func(Receiver); - return true; - } - - public: - TUnaryInplaceStatementExecutor(TReceiver<TP>& receiver) - : Receiver(receiver) - { - } - }; - - template <class TP, class TFunc, EOperandType TParam> - class TBinaryInplaceStatementExecutor: public IExecutor { - private: - TFunc Func; - TReceiver<TP> Receiver; - TOperand<TP, TParam> Param; - - bool DoExecute(TOrbit&, const TParams& params) override { - Func(Receiver, Param.Get(params)); - return true; - } - - public: - TBinaryInplaceStatementExecutor(TReceiver<TP>& receiver, const TOperand<TP, TParam>& param) - : Receiver(receiver) - , Param(param) - { - } - }; - - template <class TP, class TFunc, EOperandType TFirstParam> - class TBinaryStatementExecutor: public IExecutor { - private: - TFunc Func; - TReceiver<TP> Receiver; - TOperand<TP, TFirstParam> FirstParam; - - bool DoExecute(TOrbit&, const TParams& params) override { - Receiver.Set(Func(Receiver.Get(params), FirstParam.Get(params))); - return true; - } - - public: - TBinaryStatementExecutor(TReceiver<TP>& receiver, const TOperand<TP, TFirstParam>& firstParam) - : Receiver(receiver) - , FirstParam(firstParam) - { - } - }; - - template <class TP, class TFunc> - class TTernaryStatementExecutor: public IExecutor { - private: - TFunc Func; - TReceiver<TP> Receiver; - - TAutoPtr<IOperandGetter<TP>> FirstParam; - TAutoPtr<IOperandGetter<TP>> SecondParam; - - bool DoExecute(TOrbit&, const TParams& params) override { - Receiver.Set(Func(FirstParam->Get(params), SecondParam->Get(params))); - return true; - } - - public: - TTernaryStatementExecutor(const TReceiver<TP>& receiver, - TAutoPtr<IOperandGetter<TP>> firstParam, - TAutoPtr<IOperandGetter<TP>> secondParam) - : Receiver(receiver) - , FirstParam(firstParam) - , SecondParam(secondParam) - { - } - }; - - template <class TLog> - class TLogActionExecutor: public IExecutor { - private: - bool LogParams; - bool LogTimestamp; - intptr_t* MaxRecords; - TAtomic Records; - TProbe* Probe; - TLog* Log; - - bool DoExecute(TOrbit&, const TParams& params) override { - if (MaxRecords != nullptr) { - while (true) { - intptr_t a = AtomicGet(Records); - if (a >= *MaxRecords) { - return true; - } - if (AtomicCas(&Records, a + 1, a)) { - Write(params); - return true; - } - } - } else { - Write(params); - return true; - } - } - - void Write(const TParams& params) { - typename TLog::TAccessor la(*Log); - if (typename TLog::TItem* item = la.Add()) { - item->Probe = Probe; - if (LogParams) { - if ((item->SavedParamsCount = Probe->Event.Signature.ParamCount) > 0) { - Probe->Event.Signature.CloneParams(item->Params, params); - } - } else { - item->SavedParamsCount = 0; - } - if (LogTimestamp) { - item->Timestamp = TInstant::Now(); - } - item->TimestampCycles = GetCycleCount(); - } - } - - public: - TLogActionExecutor(TProbe* probe, const TLogAction& action, TLog* log) + typedef enum { + OT_LITERAL = 0, + OT_PARAMETER = 1, + OT_VARIABLE = 2 + } EOperandType; + + template <class T, EOperandType> + class TOperand; + + template <class T> + class TOperand<T, OT_LITERAL> { + private: + T ImmediateValue; + + public: + TOperand(TSession::TTraceVariables&, const TString&, const TString& value, size_t) { + ImmediateValue = TParamConv<T>::FromString(value); + } + const T& Get(const TParams&) { + return ImmediateValue; + } + }; + + template <class T> + class TOperand<T, OT_PARAMETER> { + private: + size_t Idx; + + public: + TOperand(TSession::TTraceVariables&, const TString&, const TString&, size_t idx) { + Idx = idx; + } + + const T& Get(const TParams& params) { + return params.Param[Idx].template Get<T>(); + } + }; + + template <class T> + class TOperand<T, OT_VARIABLE> { + private: + TAtomic* Variable; + + public: + TOperand(TSession::TTraceVariables& traceVariables, const TString& name, const TString&, size_t) { + Variable = GetVariablePtr(traceVariables, name); + } + + const T Get(const TParams&) { + return (T)AtomicGet(*Variable); + } + + void Set(const T& value) { + AtomicSet(*Variable, value); + } + + void Inc() { + AtomicIncrement(*Variable); + } + + void Dec() { + AtomicDecrement(*Variable); + } + + void Add(const TAtomicBase value) { + AtomicAdd(*Variable, value); + } + + void Sub(const TAtomicBase value) { + AtomicSub(*Variable, value); + } + }; + + template <> + class TOperand<TCheck, OT_VARIABLE> { + private: + TAtomic* Variable; + + public: + TOperand(TSession::TTraceVariables& traceVariables, const TString& name, const TString&, size_t) { + Variable = GetVariablePtr(traceVariables, name); + } + + const TCheck Get(const TParams&) { + return TCheck(AtomicGet(*Variable)); + } + + void Set(const TCheck& value) { + AtomicSet(*Variable, value.Value); + } + + void Add(const TCheck& value) { + AtomicAdd(*Variable, value.Value); + } + + void Sub(const TCheck value) { + AtomicSub(*Variable, value.Value); + } + + void Inc() { + AtomicIncrement(*Variable); + } + + void Dec() { + AtomicDecrement(*Variable); + } + }; + + template <> + class TOperand<TString, OT_VARIABLE> { + private: + TString Dummy; + + public: + TOperand(TSession::TTraceVariables&, const TString&, const TString&, size_t) { + } + + const TString Get(const TParams&) { + return Dummy; + } + + void Set(const TString&) { + } + }; + + template <> + class TOperand<TSymbol, OT_VARIABLE> { + private: + TSymbol Dummy; + + public: + TOperand(TSession::TTraceVariables&, const TString&, const TString&, size_t) { + } + + const TSymbol Get(const TParams&) { + return Dummy; + } + + void Set(const TSymbol&) { + } + }; + + // IOperandGetter: hide concrete EOperandType, to save compilation time + template <class T> + struct IOperandGetter { + virtual const T Get(const TParams& params) = 0; + virtual ~IOperandGetter() { + } + }; + + template <class T, EOperandType TParam> + class TOperandGetter: public IOperandGetter<T> { + private: + TOperand<T, TParam> Op; + + public: + TOperandGetter(const TOperand<T, TParam>& op) + : Op(op) + { + } + + const T Get(const TParams& params) override { + return Op.Get(params); + } + }; + + template <class T> + class TReceiver: public TOperand<T, OT_VARIABLE> { + public: + TReceiver(TSession::TTraceVariables& traceVariables, const TString& name) + : TOperand<T, OT_VARIABLE>(traceVariables, name, nullptr, 0) + { + } + }; + + template <class TP, class TPredicate> + static bool CmpFunc(TP a, TP b) { + return TPredicate()(a, b); + } + + template <class TP, class TFunc, EOperandType TLhs, EOperandType TRhs> + class TOperatorExecutor: public IExecutor { + private: + bool InvertCompare; + TOperand<TP, TLhs> Lhs; + TOperand<TP, TRhs> Rhs; + + bool DoExecute(TOrbit&, const TParams& params) override { + return TFunc()(Lhs.Get(params), Rhs.Get(params)) != InvertCompare; + } + + public: + TOperatorExecutor(const TOperand<TP, TLhs>& lhs, const TOperand<TP, TRhs>& rhs, bool invertCompare) + : InvertCompare(invertCompare) + , Lhs(lhs) + , Rhs(rhs) + { + } + }; + + template <class TR, class TP> + struct TAddEq { + void operator()(TR& x, TP y) const { + x.Add(y); + } + }; + template <class TR, class TP> + struct TSubEq { + void operator()(TR& x, TP y) const { + x.Sub(y); + } + }; + template <class TR> + struct TInc { + void operator()(TR& x) const { + x.Inc(); + } + }; + template <class TR> + struct TDec { + void operator()(TR& x) const { + x.Dec(); + } + }; + + template <class TP, class TFunc> + class TUnaryInplaceStatementExecutor: public IExecutor { + private: + TFunc Func; + TReceiver<TP> Receiver; + + bool DoExecute(TOrbit&, const TParams&) override { + Func(Receiver); + return true; + } + + public: + TUnaryInplaceStatementExecutor(TReceiver<TP>& receiver) + : Receiver(receiver) + { + } + }; + + template <class TP, class TFunc, EOperandType TParam> + class TBinaryInplaceStatementExecutor: public IExecutor { + private: + TFunc Func; + TReceiver<TP> Receiver; + TOperand<TP, TParam> Param; + + bool DoExecute(TOrbit&, const TParams& params) override { + Func(Receiver, Param.Get(params)); + return true; + } + + public: + TBinaryInplaceStatementExecutor(TReceiver<TP>& receiver, const TOperand<TP, TParam>& param) + : Receiver(receiver) + , Param(param) + { + } + }; + + template <class TP, class TFunc, EOperandType TFirstParam> + class TBinaryStatementExecutor: public IExecutor { + private: + TFunc Func; + TReceiver<TP> Receiver; + TOperand<TP, TFirstParam> FirstParam; + + bool DoExecute(TOrbit&, const TParams& params) override { + Receiver.Set(Func(Receiver.Get(params), FirstParam.Get(params))); + return true; + } + + public: + TBinaryStatementExecutor(TReceiver<TP>& receiver, const TOperand<TP, TFirstParam>& firstParam) + : Receiver(receiver) + , FirstParam(firstParam) + { + } + }; + + template <class TP, class TFunc> + class TTernaryStatementExecutor: public IExecutor { + private: + TFunc Func; + TReceiver<TP> Receiver; + + TAutoPtr<IOperandGetter<TP>> FirstParam; + TAutoPtr<IOperandGetter<TP>> SecondParam; + + bool DoExecute(TOrbit&, const TParams& params) override { + Receiver.Set(Func(FirstParam->Get(params), SecondParam->Get(params))); + return true; + } + + public: + TTernaryStatementExecutor(const TReceiver<TP>& receiver, + TAutoPtr<IOperandGetter<TP>> firstParam, + TAutoPtr<IOperandGetter<TP>> secondParam) + : Receiver(receiver) + , FirstParam(firstParam) + , SecondParam(secondParam) + { + } + }; + + template <class TLog> + class TLogActionExecutor: public IExecutor { + private: + bool LogParams; + bool LogTimestamp; + intptr_t* MaxRecords; + TAtomic Records; + TProbe* Probe; + TLog* Log; + + bool DoExecute(TOrbit&, const TParams& params) override { + if (MaxRecords != nullptr) { + while (true) { + intptr_t a = AtomicGet(Records); + if (a >= *MaxRecords) { + return true; + } + if (AtomicCas(&Records, a + 1, a)) { + Write(params); + return true; + } + } + } else { + Write(params); + return true; + } + } + + void Write(const TParams& params) { + typename TLog::TAccessor la(*Log); + if (typename TLog::TItem* item = la.Add()) { + item->Probe = Probe; + if (LogParams) { + if ((item->SavedParamsCount = Probe->Event.Signature.ParamCount) > 0) { + Probe->Event.Signature.CloneParams(item->Params, params); + } + } else { + item->SavedParamsCount = 0; + } + if (LogTimestamp) { + item->Timestamp = TInstant::Now(); + } + item->TimestampCycles = GetCycleCount(); + } + } + + public: + TLogActionExecutor(TProbe* probe, const TLogAction& action, TLog* log) : LogParams(!action.GetDoNotLogParams()) - , LogTimestamp(action.GetLogTimestamp()) + , LogTimestamp(action.GetLogTimestamp()) , MaxRecords(action.GetMaxRecords() ? new intptr_t(action.GetMaxRecords()) : nullptr) - , Records(0) - , Probe(probe) - , Log(log) - { - } - - ~TLogActionExecutor() override { - delete MaxRecords; - } - }; - - class TSamplingExecutor: public IExecutor { - private: - double SampleRate; - - public: - explicit TSamplingExecutor(double sampleRate) - : SampleRate(sampleRate) - {} - - bool DoExecute(TOrbit&, const TParams&) override { - return RandomNumber<double>() < SampleRate; - } - }; - - typedef struct { - EOperandType Type; - size_t ParamIdx; - } TArgumentDescription; - - using TArgumentList = TVector<TArgumentDescription>; - - template <class T> - void ParseArguments(const T& op, const TSignature& signature, const TString& exceptionPrefix, size_t expectedArgumentCount, TArgumentList& arguments) { - arguments.clear(); - size_t firstParamIdx = size_t(-1); - for (size_t argumentIdx = 0; argumentIdx < op.ArgumentSize(); ++argumentIdx) { - const TArgument& arg = op.GetArgument(argumentIdx); - TArgumentDescription operand; - operand.ParamIdx = size_t(-1); + , Records(0) + , Probe(probe) + , Log(log) + { + } + + ~TLogActionExecutor() override { + delete MaxRecords; + } + }; + + class TSamplingExecutor: public IExecutor { + private: + double SampleRate; + + public: + explicit TSamplingExecutor(double sampleRate) + : SampleRate(sampleRate) + {} + + bool DoExecute(TOrbit&, const TParams&) override { + return RandomNumber<double>() < SampleRate; + } + }; + + typedef struct { + EOperandType Type; + size_t ParamIdx; + } TArgumentDescription; + + using TArgumentList = TVector<TArgumentDescription>; + + template <class T> + void ParseArguments(const T& op, const TSignature& signature, const TString& exceptionPrefix, size_t expectedArgumentCount, TArgumentList& arguments) { + arguments.clear(); + size_t firstParamIdx = size_t(-1); + for (size_t argumentIdx = 0; argumentIdx < op.ArgumentSize(); ++argumentIdx) { + const TArgument& arg = op.GetArgument(argumentIdx); + TArgumentDescription operand; + operand.ParamIdx = size_t(-1); if (arg.GetVariable()) { - operand.Type = OT_VARIABLE; + operand.Type = OT_VARIABLE; } else if (arg.GetValue()) { - operand.Type = OT_LITERAL; + operand.Type = OT_LITERAL; } else if (arg.GetParam()) { - operand.Type = OT_PARAMETER; - operand.ParamIdx = signature.FindParamIndex(arg.GetParam()); - if (operand.ParamIdx == size_t(-1)) { + operand.Type = OT_PARAMETER; + operand.ParamIdx = signature.FindParamIndex(arg.GetParam()); + if (operand.ParamIdx == size_t(-1)) { ythrow yexception() << exceptionPrefix - << " argument #" << argumentIdx << " param '" << arg.GetParam() - << "' doesn't exist"; + << " argument #" << argumentIdx << " param '" << arg.GetParam() + << "' doesn't exist"; } - if (firstParamIdx == size_t(-1)) { - firstParamIdx = operand.ParamIdx; - } else { - if (strcmp(signature.ParamTypes[firstParamIdx], signature.ParamTypes[operand.ParamIdx]) != 0) { - ythrow yexception() << exceptionPrefix - << " param types do not match"; - } - } - } else { - ythrow yexception() << exceptionPrefix - << " argument #" << argumentIdx - << " is empty"; + if (firstParamIdx == size_t(-1)) { + firstParamIdx = operand.ParamIdx; + } else { + if (strcmp(signature.ParamTypes[firstParamIdx], signature.ParamTypes[operand.ParamIdx]) != 0) { + ythrow yexception() << exceptionPrefix + << " param types do not match"; + } + } + } else { + ythrow yexception() << exceptionPrefix + << " argument #" << argumentIdx + << " is empty"; } - arguments.push_back(operand); - } - if (arguments.size() != expectedArgumentCount) { + arguments.push_back(operand); + } + if (arguments.size() != expectedArgumentCount) { ythrow yexception() << exceptionPrefix - << " incorrect number of arguments (" << arguments.size() - << " present, " << expectedArgumentCount << " expected)"; - } - } - - template <class TArg1, class TArg2> - struct TTraceSecondArg { - // implementation of deprecated std::project2nd - TArg1 operator()(const TArg1&, const TArg2& y) const { - return y; - } - }; - - void TSession::InsertExecutor( - TTraceVariables& traceVariables, size_t bi, const TPredicate* pred, - const NProtoBuf::RepeatedPtrField<TAction>& actions, TProbe* probe, - const bool destructiveActionsAllowed, - const TCustomActionFactory& customActionFactory) { -#ifndef LWTRACE_DISABLE - THolder<IExecutor> exec; - IExecutor* last = nullptr; - TArgumentList arguments; - if (pred) { - double sampleRate = pred->GetSampleRate(); - if (sampleRate != 0.0) { - if (!(0.0 < sampleRate && sampleRate <= 1.0)) { - ythrow yexception() << "probe '" << probe->Event.Name << "' block #" << bi + 1 << " sampling operator" - << " invalid sample rate " << sampleRate << ", expected [0;1]"; - } - exec.Reset(new TSamplingExecutor(sampleRate)); - last = exec.Get(); - } - - for (size_t i = 0; i < pred->OperatorsSize(); i++) { - const TOperator& op = pred->GetOperators(i); - TString exceptionPrefix; - TStringOutput exceptionPrefixOutput(exceptionPrefix); - exceptionPrefixOutput << "probe '" << probe->Event.Name << "' block #" << bi + 1 << " operator #" << i + 1; - ParseArguments<TOperator>(op, probe->Event.Signature, exceptionPrefix, 2, arguments); - THolder<IExecutor> opExec; - - TArgumentDescription arg0 = arguments.at(0); - TArgumentDescription arg1 = arguments.at(1); + << " incorrect number of arguments (" << arguments.size() + << " present, " << expectedArgumentCount << " expected)"; + } + } + + template <class TArg1, class TArg2> + struct TTraceSecondArg { + // implementation of deprecated std::project2nd + TArg1 operator()(const TArg1&, const TArg2& y) const { + return y; + } + }; + + void TSession::InsertExecutor( + TTraceVariables& traceVariables, size_t bi, const TPredicate* pred, + const NProtoBuf::RepeatedPtrField<TAction>& actions, TProbe* probe, + const bool destructiveActionsAllowed, + const TCustomActionFactory& customActionFactory) { +#ifndef LWTRACE_DISABLE + THolder<IExecutor> exec; + IExecutor* last = nullptr; + TArgumentList arguments; + if (pred) { + double sampleRate = pred->GetSampleRate(); + if (sampleRate != 0.0) { + if (!(0.0 < sampleRate && sampleRate <= 1.0)) { + ythrow yexception() << "probe '" << probe->Event.Name << "' block #" << bi + 1 << " sampling operator" + << " invalid sample rate " << sampleRate << ", expected [0;1]"; + } + exec.Reset(new TSamplingExecutor(sampleRate)); + last = exec.Get(); + } + + for (size_t i = 0; i < pred->OperatorsSize(); i++) { + const TOperator& op = pred->GetOperators(i); + TString exceptionPrefix; + TStringOutput exceptionPrefixOutput(exceptionPrefix); + exceptionPrefixOutput << "probe '" << probe->Event.Name << "' block #" << bi + 1 << " operator #" << i + 1; + ParseArguments<TOperator>(op, probe->Event.Signature, exceptionPrefix, 2, arguments); + THolder<IExecutor> opExec; + + TArgumentDescription arg0 = arguments.at(0); + TArgumentDescription arg1 = arguments.at(1); const char* tName0 = arg0.ParamIdx == size_t(-1) ? nullptr : probe->Event.Signature.ParamTypes[arg0.ParamIdx]; const char* tName1 = arg1.ParamIdx == size_t(-1) ? nullptr : probe->Event.Signature.ParamTypes[arg1.ParamIdx]; - TString var0 = op.GetArgument(0).GetVariable(); - TString var1 = op.GetArgument(1).GetVariable(); - - TString val0 = op.GetArgument(0).GetValue(); - TString val1 = op.GetArgument(1).GetValue(); - -#define FOREACH_OPERAND_TYPE_RT(n, t, v, fn, lt, rt) \ - if (rt == arg1.Type) { \ - TOperand<t, rt> rhs(traceVariables, var1, val1, arg1.ParamIdx); \ - opExec.Reset(new TOperatorExecutor<t, fn<t>, lt, rt>(lhs, rhs, invertCompare)); \ - break; \ - } - -#define FOREACH_OPERAND_TYPE_LT(n, t, v, fn, lt) \ - if (lt == arg0.Type) { \ - TOperand<t, lt> lhs(traceVariables, var0, val0, arg0.ParamIdx); \ - FOREACH_RIGHT_TYPE(FOREACH_OPERAND_TYPE_RT, n, t, v, fn, lt) \ - } - -#define FOREACH_PARAMTYPE_MACRO(n, t, v, fn) \ - if ((arg0.ParamIdx == size_t(-1) || strcmp(tName0, n) == 0) && (arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0)) { \ - FOREACH_LEFT_TYPE(FOREACH_OPERAND_TYPE_LT, n, t, v, fn); \ - } - - bool invertCompare = EqualToOneOf(op.GetType(), OT_NE, OT_GE, OT_LE); - - switch (op.GetType()) { - case OT_EQ: - case OT_NE: - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, std::equal_to); - break; - case OT_LT: - case OT_GE: - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, std::less); - break; - case OT_GT: - case OT_LE: - FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, std::greater); - break; - default: - ythrow yexception() << exceptionPrefix - << " has not supported operator type #" << int(op.GetType()); - } - + TString var0 = op.GetArgument(0).GetVariable(); + TString var1 = op.GetArgument(1).GetVariable(); + + TString val0 = op.GetArgument(0).GetValue(); + TString val1 = op.GetArgument(1).GetValue(); + +#define FOREACH_OPERAND_TYPE_RT(n, t, v, fn, lt, rt) \ + if (rt == arg1.Type) { \ + TOperand<t, rt> rhs(traceVariables, var1, val1, arg1.ParamIdx); \ + opExec.Reset(new TOperatorExecutor<t, fn<t>, lt, rt>(lhs, rhs, invertCompare)); \ + break; \ + } + +#define FOREACH_OPERAND_TYPE_LT(n, t, v, fn, lt) \ + if (lt == arg0.Type) { \ + TOperand<t, lt> lhs(traceVariables, var0, val0, arg0.ParamIdx); \ + FOREACH_RIGHT_TYPE(FOREACH_OPERAND_TYPE_RT, n, t, v, fn, lt) \ + } + +#define FOREACH_PARAMTYPE_MACRO(n, t, v, fn) \ + if ((arg0.ParamIdx == size_t(-1) || strcmp(tName0, n) == 0) && (arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0)) { \ + FOREACH_LEFT_TYPE(FOREACH_OPERAND_TYPE_LT, n, t, v, fn); \ + } + + bool invertCompare = EqualToOneOf(op.GetType(), OT_NE, OT_GE, OT_LE); + + switch (op.GetType()) { + case OT_EQ: + case OT_NE: + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, std::equal_to); + break; + case OT_LT: + case OT_GE: + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, std::less); + break; + case OT_GT: + case OT_LE: + FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, std::greater); + break; + default: + ythrow yexception() << exceptionPrefix + << " has not supported operator type #" << int(op.GetType()); + } + #undef FOREACH_OPERAND_TYPE_RT #undef FOREACH_OPERAND_TYPE_LT -#undef FOREACH_PARAMTYPE_MACRO - - if (!opExec) { - ythrow yexception() << exceptionPrefix - << " has not supported left param #" << arg0.ParamIdx + 1 << " type '" - << (arg0.ParamIdx != size_t(-1) ? probe->Event.Signature.ParamTypes[arg0.ParamIdx] : "?") - << "', or right param #" << arg0.ParamIdx + 1 << " type '" - << (arg1.ParamIdx != size_t(-1) ? probe->Event.Signature.ParamTypes[arg1.ParamIdx] : "?") - << "'"; - } - - if (!exec) { - exec.Reset(opExec.Release()); - last = exec.Get(); - } else { - last->SetNext(opExec.Release()); - last = last->GetNext(); - } - } - } - - for (int i = 0; i < actions.size(); ++i) { - const TAction& action = actions.Get(i); - THolder<IExecutor> actExec; - if (action.HasPrintToStderrAction()) { - actExec.Reset(new TStderrActionExecutor(probe)); - } else if (action.HasLogAction()) { - if (Query.GetLogDurationUs()) { - actExec.Reset(new TLogActionExecutor<TDurationLog>(probe, action.GetLogAction(), &DurationLog)); - } else { - actExec.Reset(new TLogActionExecutor<TCyclicLog>(probe, action.GetLogAction(), &CyclicLog)); - } - } else if (action.HasRunLogShuttleAction()) { - if (Query.GetLogDurationUs()) { +#undef FOREACH_PARAMTYPE_MACRO + + if (!opExec) { + ythrow yexception() << exceptionPrefix + << " has not supported left param #" << arg0.ParamIdx + 1 << " type '" + << (arg0.ParamIdx != size_t(-1) ? probe->Event.Signature.ParamTypes[arg0.ParamIdx] : "?") + << "', or right param #" << arg0.ParamIdx + 1 << " type '" + << (arg1.ParamIdx != size_t(-1) ? probe->Event.Signature.ParamTypes[arg1.ParamIdx] : "?") + << "'"; + } + + if (!exec) { + exec.Reset(opExec.Release()); + last = exec.Get(); + } else { + last->SetNext(opExec.Release()); + last = last->GetNext(); + } + } + } + + for (int i = 0; i < actions.size(); ++i) { + const TAction& action = actions.Get(i); + THolder<IExecutor> actExec; + if (action.HasPrintToStderrAction()) { + actExec.Reset(new TStderrActionExecutor(probe)); + } else if (action.HasLogAction()) { + if (Query.GetLogDurationUs()) { + actExec.Reset(new TLogActionExecutor<TDurationLog>(probe, action.GetLogAction(), &DurationLog)); + } else { + actExec.Reset(new TLogActionExecutor<TCyclicLog>(probe, action.GetLogAction(), &CyclicLog)); + } + } else if (action.HasRunLogShuttleAction()) { + if (Query.GetLogDurationUs()) { actExec.Reset(new TRunLogShuttleActionExecutor<TDurationDepot>(TraceIdx, action.GetRunLogShuttleAction(), &DurationDepot, &LastTrackId, &LastSpanId)); - } else { + } else { actExec.Reset(new TRunLogShuttleActionExecutor<TCyclicDepot>(TraceIdx, action.GetRunLogShuttleAction(), &CyclicDepot, &LastTrackId, &LastSpanId)); - } - } else if (action.HasEditLogShuttleAction()) { - if (Query.GetLogDurationUs()) { - actExec.Reset(new TEditLogShuttleActionExecutor<TDurationDepot>(TraceIdx, action.GetEditLogShuttleAction())); - } else { - actExec.Reset(new TEditLogShuttleActionExecutor<TCyclicDepot>(TraceIdx, action.GetEditLogShuttleAction())); - } - } else if (action.HasDropLogShuttleAction()) { - if (Query.GetLogDurationUs()) { - actExec.Reset(new TDropLogShuttleActionExecutor<TDurationDepot>(TraceIdx, action.GetDropLogShuttleAction())); - } else { - actExec.Reset(new TDropLogShuttleActionExecutor<TCyclicDepot>(TraceIdx, action.GetDropLogShuttleAction())); - } - } else if (action.HasCustomAction()) { - THolder<TCustomActionExecutor> customExec(customActionFactory.Create(probe, action.GetCustomAction(), this)); - if (customExec) { - if (!customExec->IsDestructive() || destructiveActionsAllowed) { - actExec.Reset(customExec.Release()); - } else { - ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1 - << " contains destructive CustomAction, but destructive actions are disabled." - << " Please, consider using --unsafe-lwtrace command line parameter."; - } - } else { - ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1 - << " contains unregistered CustomAction '" << action.GetCustomAction().GetName() << "'"; - } - } else if (action.HasKillAction()) { - if (destructiveActionsAllowed) { - actExec.Reset(new NPrivate::TKillActionExecutor(probe)); - } else { - ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1 - << " contains destructive KillAction, but destructive actions are disabled." - << " Please, consider using --unsafe-lwtrace command line parameter."; - } - } else if (action.HasSleepAction()) { - if (destructiveActionsAllowed) { - const TSleepAction& sleepAction = action.GetSleepAction(); + } + } else if (action.HasEditLogShuttleAction()) { + if (Query.GetLogDurationUs()) { + actExec.Reset(new TEditLogShuttleActionExecutor<TDurationDepot>(TraceIdx, action.GetEditLogShuttleAction())); + } else { + actExec.Reset(new TEditLogShuttleActionExecutor<TCyclicDepot>(TraceIdx, action.GetEditLogShuttleAction())); + } + } else if (action.HasDropLogShuttleAction()) { + if (Query.GetLogDurationUs()) { + actExec.Reset(new TDropLogShuttleActionExecutor<TDurationDepot>(TraceIdx, action.GetDropLogShuttleAction())); + } else { + actExec.Reset(new TDropLogShuttleActionExecutor<TCyclicDepot>(TraceIdx, action.GetDropLogShuttleAction())); + } + } else if (action.HasCustomAction()) { + THolder<TCustomActionExecutor> customExec(customActionFactory.Create(probe, action.GetCustomAction(), this)); + if (customExec) { + if (!customExec->IsDestructive() || destructiveActionsAllowed) { + actExec.Reset(customExec.Release()); + } else { + ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1 + << " contains destructive CustomAction, but destructive actions are disabled." + << " Please, consider using --unsafe-lwtrace command line parameter."; + } + } else { + ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1 + << " contains unregistered CustomAction '" << action.GetCustomAction().GetName() << "'"; + } + } else if (action.HasKillAction()) { + if (destructiveActionsAllowed) { + actExec.Reset(new NPrivate::TKillActionExecutor(probe)); + } else { + ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1 + << " contains destructive KillAction, but destructive actions are disabled." + << " Please, consider using --unsafe-lwtrace command line parameter."; + } + } else if (action.HasSleepAction()) { + if (destructiveActionsAllowed) { + const TSleepAction& sleepAction = action.GetSleepAction(); if (sleepAction.GetNanoSeconds()) { - ui64 nanoSeconds = sleepAction.GetNanoSeconds(); - actExec.Reset(new NPrivate::TSleepActionExecutor(probe, nanoSeconds)); - } else { - ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1 - << " SleepAction missing parameter 'NanoSeconds'"; - } - } else { + ui64 nanoSeconds = sleepAction.GetNanoSeconds(); + actExec.Reset(new NPrivate::TSleepActionExecutor(probe, nanoSeconds)); + } else { + ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1 + << " SleepAction missing parameter 'NanoSeconds'"; + } + } else { ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1 - << " contains destructive SleepAction, but destructive actions are disabled." - << " Please, consider using --unsafe-lwtrace command line parameter."; + << " contains destructive SleepAction, but destructive actions are disabled." + << " Please, consider using --unsafe-lwtrace command line parameter."; } - } else if (action.HasStatementAction()) { - const TStatementAction& statement = action.GetStatementAction(); - TString exceptionPrefix; - TStringOutput exceptionPrefixOutput(exceptionPrefix); - exceptionPrefixOutput << "probe '" << probe->Event.Name << "' block #" << bi + 1 << " action #" << i + 1; - size_t expectedArgumentCount = 3; - if (statement.GetType() == ST_MOV || statement.GetType() == ST_ADD_EQ || statement.GetType() == ST_SUB_EQ) { - expectedArgumentCount = 2; - } else if (statement.GetType() == ST_INC || statement.GetType() == ST_DEC) { - expectedArgumentCount = 1; - } - ParseArguments<TStatementAction>(statement, probe->Event.Signature, exceptionPrefix, expectedArgumentCount, arguments); - - TArgumentDescription arg0 = (expectedArgumentCount <= 0) ? TArgumentDescription() : arguments.at(0); - TArgumentDescription arg1 = (expectedArgumentCount <= 1) ? TArgumentDescription() : arguments.at(1); - TArgumentDescription arg2 = (expectedArgumentCount <= 2) ? TArgumentDescription() : arguments.at(2); - - TString var0 = (expectedArgumentCount <= 0) ? "" : statement.GetArgument(0).GetVariable(); - TString var1 = (expectedArgumentCount <= 1) ? "" : statement.GetArgument(1).GetVariable(); - TString var2 = (expectedArgumentCount <= 2) ? "" : statement.GetArgument(2).GetVariable(); - - TString val0 = (expectedArgumentCount <= 0) ? "" : statement.GetArgument(0).GetValue(); - TString val1 = (expectedArgumentCount <= 1) ? "" : statement.GetArgument(1).GetValue(); - TString val2 = (expectedArgumentCount <= 2) ? "" : statement.GetArgument(2).GetValue(); + } else if (action.HasStatementAction()) { + const TStatementAction& statement = action.GetStatementAction(); + TString exceptionPrefix; + TStringOutput exceptionPrefixOutput(exceptionPrefix); + exceptionPrefixOutput << "probe '" << probe->Event.Name << "' block #" << bi + 1 << " action #" << i + 1; + size_t expectedArgumentCount = 3; + if (statement.GetType() == ST_MOV || statement.GetType() == ST_ADD_EQ || statement.GetType() == ST_SUB_EQ) { + expectedArgumentCount = 2; + } else if (statement.GetType() == ST_INC || statement.GetType() == ST_DEC) { + expectedArgumentCount = 1; + } + ParseArguments<TStatementAction>(statement, probe->Event.Signature, exceptionPrefix, expectedArgumentCount, arguments); + + TArgumentDescription arg0 = (expectedArgumentCount <= 0) ? TArgumentDescription() : arguments.at(0); + TArgumentDescription arg1 = (expectedArgumentCount <= 1) ? TArgumentDescription() : arguments.at(1); + TArgumentDescription arg2 = (expectedArgumentCount <= 2) ? TArgumentDescription() : arguments.at(2); + + TString var0 = (expectedArgumentCount <= 0) ? "" : statement.GetArgument(0).GetVariable(); + TString var1 = (expectedArgumentCount <= 1) ? "" : statement.GetArgument(1).GetVariable(); + TString var2 = (expectedArgumentCount <= 2) ? "" : statement.GetArgument(2).GetVariable(); + + TString val0 = (expectedArgumentCount <= 0) ? "" : statement.GetArgument(0).GetValue(); + TString val1 = (expectedArgumentCount <= 1) ? "" : statement.GetArgument(1).GetValue(); + TString val2 = (expectedArgumentCount <= 2) ? "" : statement.GetArgument(2).GetValue(); const char* tName1 = (expectedArgumentCount <= 1 || arg1.ParamIdx == size_t(-1)) ? nullptr : probe->Event.Signature.ParamTypes[arg1.ParamIdx]; const char* tName2 = (expectedArgumentCount <= 2 || arg2.ParamIdx == size_t(-1)) ? nullptr : probe->Event.Signature.ParamTypes[arg2.ParamIdx]; - if (arg0.Type == OT_VARIABLE) { - switch (statement.GetType()) { -#define PARSE_UNARY_INPLACE_STATEMENT_MACRO(n, t, v, fn) \ - { \ - typedef TUnaryInplaceStatementExecutor<t, fn<TReceiver<t>>> TExec; \ - TReceiver<t> receiver(traceVariables, var0); \ - actExec.Reset(new TExec(receiver)); \ - break; \ - } - -#define PARSE_BINARY_INPLACE_STATEMENT_MACRO2(n, t, v, fn, ft) \ - if (arg1.Type == ft) { \ - typedef TBinaryInplaceStatementExecutor<t, fn<TReceiver<t>, t>, ft> TExec; \ - TOperand<t, ft> firstParam(traceVariables, var1, val1, arg1.ParamIdx); \ - actExec.Reset(new TExec(receiver, firstParam)); \ - break; \ - } - -#define PARSE_BINARY_INPLACE_STATEMENT_MACRO(n, t, v, fn) \ - if (arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0) { \ - TReceiver<t> receiver(traceVariables, var0); \ - FOREACH_RIGHT_TYPE(PARSE_BINARY_INPLACE_STATEMENT_MACRO2, n, t, v, fn); \ - } - -#define PARSE_BINARY_STATEMENT_MACRO2(n, t, v, fn, ft) \ - if (arg1.Type == ft) { \ - typedef TBinaryStatementExecutor<t, fn<t, t>, ft> TExec; \ - TOperand<t, ft> firstParam(traceVariables, var1, val1, arg1.ParamIdx); \ - actExec.Reset(new TExec(receiver, firstParam)); \ - break; \ - } - -#define PARSE_BINARY_STATEMENT_MACRO(n, t, v, fn) \ - if (arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0) { \ - TReceiver<t> receiver(traceVariables, var0); \ - FOREACH_RIGHT_TYPE(PARSE_BINARY_STATEMENT_MACRO2, n, t, v, fn); \ - } - -#define CREATE_OPERAND_GETTER_N(N, type, arg_type) \ - if (arg##N.Type == arg_type) { \ + if (arg0.Type == OT_VARIABLE) { + switch (statement.GetType()) { +#define PARSE_UNARY_INPLACE_STATEMENT_MACRO(n, t, v, fn) \ + { \ + typedef TUnaryInplaceStatementExecutor<t, fn<TReceiver<t>>> TExec; \ + TReceiver<t> receiver(traceVariables, var0); \ + actExec.Reset(new TExec(receiver)); \ + break; \ + } + +#define PARSE_BINARY_INPLACE_STATEMENT_MACRO2(n, t, v, fn, ft) \ + if (arg1.Type == ft) { \ + typedef TBinaryInplaceStatementExecutor<t, fn<TReceiver<t>, t>, ft> TExec; \ + TOperand<t, ft> firstParam(traceVariables, var1, val1, arg1.ParamIdx); \ + actExec.Reset(new TExec(receiver, firstParam)); \ + break; \ + } + +#define PARSE_BINARY_INPLACE_STATEMENT_MACRO(n, t, v, fn) \ + if (arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0) { \ + TReceiver<t> receiver(traceVariables, var0); \ + FOREACH_RIGHT_TYPE(PARSE_BINARY_INPLACE_STATEMENT_MACRO2, n, t, v, fn); \ + } + +#define PARSE_BINARY_STATEMENT_MACRO2(n, t, v, fn, ft) \ + if (arg1.Type == ft) { \ + typedef TBinaryStatementExecutor<t, fn<t, t>, ft> TExec; \ + TOperand<t, ft> firstParam(traceVariables, var1, val1, arg1.ParamIdx); \ + actExec.Reset(new TExec(receiver, firstParam)); \ + break; \ + } + +#define PARSE_BINARY_STATEMENT_MACRO(n, t, v, fn) \ + if (arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0) { \ + TReceiver<t> receiver(traceVariables, var0); \ + FOREACH_RIGHT_TYPE(PARSE_BINARY_STATEMENT_MACRO2, n, t, v, fn); \ + } + +#define CREATE_OPERAND_GETTER_N(N, type, arg_type) \ + if (arg##N.Type == arg_type) { \ operand##N.Reset(new TOperandGetter<type, arg_type>(TOperand<type, arg_type>(traceVariables, var##N, val##N, arg##N.ParamIdx))); \ } -#define TERNARY_ON_TYPE(n, t, v, fn) \ +#define TERNARY_ON_TYPE(n, t, v, fn) \ if ((arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0) && (arg2.ParamIdx == size_t(-1) || strcmp(tName2, n) == 0)) { \ - TAutoPtr<IOperandGetter<t>> operand1, operand2; \ - FOREACH_LEFT_TYPE(CREATE_OPERAND_GETTER_N, 1, t); \ - FOREACH_RIGHT_TYPE(CREATE_OPERAND_GETTER_N, 2, t); \ - if (operand1 && operand2) { \ - actExec.Reset(new TTernaryStatementExecutor<t, fn<t>>( \ - TReceiver<t>(traceVariables, var0), \ - operand1, \ - operand2)); \ - } \ - break; \ + TAutoPtr<IOperandGetter<t>> operand1, operand2; \ + FOREACH_LEFT_TYPE(CREATE_OPERAND_GETTER_N, 1, t); \ + FOREACH_RIGHT_TYPE(CREATE_OPERAND_GETTER_N, 2, t); \ + if (operand1 && operand2) { \ + actExec.Reset(new TTernaryStatementExecutor<t, fn<t>>( \ + TReceiver<t>(traceVariables, var0), \ + operand1, \ + operand2)); \ + } \ + break; \ } #define IMPLEMENT_TERNARY_STATEMENT(fn) FOR_MATH_PARAMTYPE(TERNARY_ON_TYPE, fn) - case ST_INC: - FOR_MATH_PARAMTYPE(PARSE_UNARY_INPLACE_STATEMENT_MACRO, TInc); - break; - case ST_DEC: - FOR_MATH_PARAMTYPE(PARSE_UNARY_INPLACE_STATEMENT_MACRO, TDec); - break; - case ST_MOV: - FOR_MATH_PARAMTYPE(PARSE_BINARY_STATEMENT_MACRO, TTraceSecondArg); - break; - case ST_ADD_EQ: - FOR_MATH_PARAMTYPE(PARSE_BINARY_INPLACE_STATEMENT_MACRO, TAddEq); - break; - case ST_SUB_EQ: - FOR_MATH_PARAMTYPE(PARSE_BINARY_INPLACE_STATEMENT_MACRO, TSubEq); - break; - case ST_ADD: - IMPLEMENT_TERNARY_STATEMENT(std::plus) - break; - case ST_SUB: - IMPLEMENT_TERNARY_STATEMENT(std::minus) - break; - case ST_MUL: - IMPLEMENT_TERNARY_STATEMENT(std::multiplies) - break; - case ST_DIV: - IMPLEMENT_TERNARY_STATEMENT(std::divides) - break; - case ST_MOD: - IMPLEMENT_TERNARY_STATEMENT(std::modulus) - break; - default: - ythrow yexception() << "block #" << bi + 1 << " action #" << i + 1 - << " has not supported statement type #" << int(statement.GetType()); - } + case ST_INC: + FOR_MATH_PARAMTYPE(PARSE_UNARY_INPLACE_STATEMENT_MACRO, TInc); + break; + case ST_DEC: + FOR_MATH_PARAMTYPE(PARSE_UNARY_INPLACE_STATEMENT_MACRO, TDec); + break; + case ST_MOV: + FOR_MATH_PARAMTYPE(PARSE_BINARY_STATEMENT_MACRO, TTraceSecondArg); + break; + case ST_ADD_EQ: + FOR_MATH_PARAMTYPE(PARSE_BINARY_INPLACE_STATEMENT_MACRO, TAddEq); + break; + case ST_SUB_EQ: + FOR_MATH_PARAMTYPE(PARSE_BINARY_INPLACE_STATEMENT_MACRO, TSubEq); + break; + case ST_ADD: + IMPLEMENT_TERNARY_STATEMENT(std::plus) + break; + case ST_SUB: + IMPLEMENT_TERNARY_STATEMENT(std::minus) + break; + case ST_MUL: + IMPLEMENT_TERNARY_STATEMENT(std::multiplies) + break; + case ST_DIV: + IMPLEMENT_TERNARY_STATEMENT(std::divides) + break; + case ST_MOD: + IMPLEMENT_TERNARY_STATEMENT(std::modulus) + break; + default: + ythrow yexception() << "block #" << bi + 1 << " action #" << i + 1 + << " has not supported statement type #" << int(statement.GetType()); + } } - if (!actExec) { + if (!actExec) { ythrow yexception() << "block #" << bi + 1 << " action #" << i + 1 << " can't create action"; - } + } #undef CREATE_OPERAND_GETTER_N #undef TERNARY_ON_TYPE #undef IMPLEMENT_TERNARY_STATEMENT @@ -819,233 +819,233 @@ namespace NLWTrace { #undef PARSE_BINARY_STATEMENT_MACRO #undef PARSE_BINARY_INPLACE_STATEMENT_MACRO #undef PARSE_UNARY_INPLACE_STATEMENT_MACRO - } else { - ythrow yexception() << "block #" << bi + 1 << " action #" << i + 1 - << " has not supported action '" << action.ShortDebugString() << "'"; - } - if (!exec) { - exec.Reset(actExec.Release()); - last = exec.Get(); - } else { - last->SetNext(actExec.Release()); - last = last->GetNext(); - } - } - - if (!probe->Attach(exec.Get())) { - ythrow yexception() << "block #" << bi + 1 - << " cannot be attached to probe '" << probe->Event.Name << "': no free slots"; - } - Probes.push_back(std::make_pair(probe, exec.Release())); -#else - Y_UNUSED(bi); - Y_UNUSED(pred); - Y_UNUSED(actions); - Y_UNUSED(probe); - Y_UNUSED(destructiveActionsAllowed); - Y_UNUSED(traceVariables); - Y_UNUSED(customActionFactory); -#endif - } - - TSession::TSession(ui64 traceIdx, - TProbeRegistry& registry, - const TQuery& query, - const bool destructiveActionsAllowed, - const TCustomActionFactory& customActionFactory) - : StartTime(TInstant::Now()) - , TraceIdx(traceIdx) - , Registry(registry) - , StoreDuration(TDuration::MicroSeconds(query.GetLogDurationUs() * 11 / 10)) // +10% to try avoid truncation while reading multiple threads/traces - , ReadDuration(TDuration::MicroSeconds(query.GetLogDurationUs())) + } else { + ythrow yexception() << "block #" << bi + 1 << " action #" << i + 1 + << " has not supported action '" << action.ShortDebugString() << "'"; + } + if (!exec) { + exec.Reset(actExec.Release()); + last = exec.Get(); + } else { + last->SetNext(actExec.Release()); + last = last->GetNext(); + } + } + + if (!probe->Attach(exec.Get())) { + ythrow yexception() << "block #" << bi + 1 + << " cannot be attached to probe '" << probe->Event.Name << "': no free slots"; + } + Probes.push_back(std::make_pair(probe, exec.Release())); +#else + Y_UNUSED(bi); + Y_UNUSED(pred); + Y_UNUSED(actions); + Y_UNUSED(probe); + Y_UNUSED(destructiveActionsAllowed); + Y_UNUSED(traceVariables); + Y_UNUSED(customActionFactory); +#endif + } + + TSession::TSession(ui64 traceIdx, + TProbeRegistry& registry, + const TQuery& query, + const bool destructiveActionsAllowed, + const TCustomActionFactory& customActionFactory) + : StartTime(TInstant::Now()) + , TraceIdx(traceIdx) + , Registry(registry) + , StoreDuration(TDuration::MicroSeconds(query.GetLogDurationUs() * 11 / 10)) // +10% to try avoid truncation while reading multiple threads/traces + , ReadDuration(TDuration::MicroSeconds(query.GetLogDurationUs())) , CyclicLog(query.GetPerThreadLogSize() ? query.GetPerThreadLogSize() : 1000) - , DurationLog(StoreDuration) + , DurationLog(StoreDuration) , CyclicDepot(query.GetPerThreadLogSize() ? query.GetPerThreadLogSize() : 1000) - , DurationDepot(StoreDuration) - , LastTrackId(0) + , DurationDepot(StoreDuration) + , LastTrackId(0) , LastSpanId(0) - , Attached(true) - , Query(query) - { - try { - for (size_t bi = 0; bi < query.BlocksSize(); bi++) { - const TBlock& block = query.GetBlocks(bi); - if (!block.HasProbeDesc()) { - ythrow yexception() << "block #" << bi + 1 << " has no probe description"; - } - const TProbeDesc& pdesc = block.GetProbeDesc(); - const TPredicate* pred = block.HasPredicate() ? &block.GetPredicate() : nullptr; - if (block.ActionSize() < 1) { - ythrow yexception() << "block #" << bi + 1 << " has no action"; - } - const NProtoBuf::RepeatedPtrField<TAction>& actions = block.action(); + , Attached(true) + , Query(query) + { + try { + for (size_t bi = 0; bi < query.BlocksSize(); bi++) { + const TBlock& block = query.GetBlocks(bi); + if (!block.HasProbeDesc()) { + ythrow yexception() << "block #" << bi + 1 << " has no probe description"; + } + const TProbeDesc& pdesc = block.GetProbeDesc(); + const TPredicate* pred = block.HasPredicate() ? &block.GetPredicate() : nullptr; + if (block.ActionSize() < 1) { + ythrow yexception() << "block #" << bi + 1 << " has no action"; + } + const NProtoBuf::RepeatedPtrField<TAction>& actions = block.action(); if (pdesc.GetName() && pdesc.GetProvider()) { - TProbeRegistry::TProbesAccessor probes(Registry); - bool found = false; - for (auto& kv : probes) { - TProbe* probe = kv.first; - if (probe->Event.Name == pdesc.GetName() && probe->Event.GetProvider() == pdesc.GetProvider()) { - InsertExecutor(TraceVariables, bi, pred, actions, probe, destructiveActionsAllowed, customActionFactory); - found = true; - break; - } - } - if (!found) { - ythrow yexception() << "block #" << bi + 1 << " has no matching probe with name '" - << pdesc.GetName() << "' provider '" << pdesc.GetProvider() << "'"; - } + TProbeRegistry::TProbesAccessor probes(Registry); + bool found = false; + for (auto& kv : probes) { + TProbe* probe = kv.first; + if (probe->Event.Name == pdesc.GetName() && probe->Event.GetProvider() == pdesc.GetProvider()) { + InsertExecutor(TraceVariables, bi, pred, actions, probe, destructiveActionsAllowed, customActionFactory); + found = true; + break; + } + } + if (!found) { + ythrow yexception() << "block #" << bi + 1 << " has no matching probe with name '" + << pdesc.GetName() << "' provider '" << pdesc.GetProvider() << "'"; + } } else if (pdesc.GetGroup()) { - bool found = false; - TProbeRegistry::TProbesAccessor probes(Registry); - for (auto& kv : probes) { - TProbe* probe = kv.first; - for (const char* const* gi = probe->Event.Groups; *gi != nullptr; gi++) { - if (*gi == pdesc.GetGroup()) { - InsertExecutor(TraceVariables, bi, pred, actions, probe, destructiveActionsAllowed, customActionFactory); - found = true; - break; - } - } - } - if (!found) { - ythrow yexception() << "block #" << bi + 1 - << " has no matching probes for group '" << pdesc.GetGroup() << "'"; - } - } else { - ythrow yexception() << "block #" << bi + 1 << " has bad probe description: name '" << pdesc.GetName() - << "' provider '" << pdesc.GetProvider() - << "' group '" << pdesc.GetGroup() << "'"; - } - } - } catch (...) { - Destroy(); - throw; - } - } - - void TSession::Destroy() { - Detach(); - for (auto& probe : Probes) { - delete probe.second; - } - } - - TSession::~TSession() { - Destroy(); - } - - void TSession::Detach() { - if (Attached) { - for (auto& p : Probes) { - TProbe* probe = p.first; - IExecutor* exec = p.second; - probe->Detach(exec); - } - Attached = false; - } - } - - size_t TSession::GetEventsCount() const { - return CyclicLog.GetEventsCount() + DurationLog.GetEventsCount() + CyclicDepot.GetEventsCount() + DurationDepot.GetEventsCount(); - } - - size_t TSession::GetThreadsCount() const { - return CyclicLog.GetThreadsCount() + DurationLog.GetThreadsCount() + CyclicDepot.GetThreadsCount() + DurationDepot.GetThreadsCount(); - } - - class TReadToProtobuf { - private: - TMap<TThread::TId, TVector<TLogItem>> Items; - - public: - void ToProtobuf(TLogPb& pb) const { - TSet<TProbe*> probes; - ui64 eventsCount = 0; - for (auto kv : Items) { - TThreadLogPb* tpb = pb.AddThreadLogs(); - tpb->SetThreadId(kv.first); - for (TLogItem& item : kv.second) { - item.ToProtobuf(*tpb->AddLogItems()); - probes.insert(item.Probe); - eventsCount++; - } - } - pb.SetEventsCount(eventsCount); - for (TProbe* probe : probes) { - probe->Event.ToProtobuf(*pb.AddEvents()); - } - } - - void Push(TThread::TId tid, const TLogItem& item) { - // Avoid any expansive operations in Push(), because it executes under lock and blocks program being traced - Items[tid].push_back(item); - } - }; - - void TSession::ToProtobuf(TLogPb& pb) const { - TReadToProtobuf reader; - ReadItems(reader); - reader.ToProtobuf(pb); - pb.MutableQuery()->CopyFrom(Query); - pb.SetCrtTime(TInstant::Now().GetValue()); - } - - TManager::TManager(TProbeRegistry& registry, bool allowDestructiveActions) - : Registry(registry) - , DestructiveActionsAllowed(allowDestructiveActions) + bool found = false; + TProbeRegistry::TProbesAccessor probes(Registry); + for (auto& kv : probes) { + TProbe* probe = kv.first; + for (const char* const* gi = probe->Event.Groups; *gi != nullptr; gi++) { + if (*gi == pdesc.GetGroup()) { + InsertExecutor(TraceVariables, bi, pred, actions, probe, destructiveActionsAllowed, customActionFactory); + found = true; + break; + } + } + } + if (!found) { + ythrow yexception() << "block #" << bi + 1 + << " has no matching probes for group '" << pdesc.GetGroup() << "'"; + } + } else { + ythrow yexception() << "block #" << bi + 1 << " has bad probe description: name '" << pdesc.GetName() + << "' provider '" << pdesc.GetProvider() + << "' group '" << pdesc.GetGroup() << "'"; + } + } + } catch (...) { + Destroy(); + throw; + } + } + + void TSession::Destroy() { + Detach(); + for (auto& probe : Probes) { + delete probe.second; + } + } + + TSession::~TSession() { + Destroy(); + } + + void TSession::Detach() { + if (Attached) { + for (auto& p : Probes) { + TProbe* probe = p.first; + IExecutor* exec = p.second; + probe->Detach(exec); + } + Attached = false; + } + } + + size_t TSession::GetEventsCount() const { + return CyclicLog.GetEventsCount() + DurationLog.GetEventsCount() + CyclicDepot.GetEventsCount() + DurationDepot.GetEventsCount(); + } + + size_t TSession::GetThreadsCount() const { + return CyclicLog.GetThreadsCount() + DurationLog.GetThreadsCount() + CyclicDepot.GetThreadsCount() + DurationDepot.GetThreadsCount(); + } + + class TReadToProtobuf { + private: + TMap<TThread::TId, TVector<TLogItem>> Items; + + public: + void ToProtobuf(TLogPb& pb) const { + TSet<TProbe*> probes; + ui64 eventsCount = 0; + for (auto kv : Items) { + TThreadLogPb* tpb = pb.AddThreadLogs(); + tpb->SetThreadId(kv.first); + for (TLogItem& item : kv.second) { + item.ToProtobuf(*tpb->AddLogItems()); + probes.insert(item.Probe); + eventsCount++; + } + } + pb.SetEventsCount(eventsCount); + for (TProbe* probe : probes) { + probe->Event.ToProtobuf(*pb.AddEvents()); + } + } + + void Push(TThread::TId tid, const TLogItem& item) { + // Avoid any expansive operations in Push(), because it executes under lock and blocks program being traced + Items[tid].push_back(item); + } + }; + + void TSession::ToProtobuf(TLogPb& pb) const { + TReadToProtobuf reader; + ReadItems(reader); + reader.ToProtobuf(pb); + pb.MutableQuery()->CopyFrom(Query); + pb.SetCrtTime(TInstant::Now().GetValue()); + } + + TManager::TManager(TProbeRegistry& registry, bool allowDestructiveActions) + : Registry(registry) + , DestructiveActionsAllowed(allowDestructiveActions) , SerializingExecutor(new TRunLogShuttleActionExecutor<TCyclicDepot>(0, {}, nullptr, nullptr, nullptr)) - { - } - - TManager::~TManager() { - for (auto& trace : Traces) { - delete trace.second; - } - } - - bool TManager::HasTrace(const TString& id) const { - TGuard<TMutex> g(Mtx); + { + } + + TManager::~TManager() { + for (auto& trace : Traces) { + delete trace.second; + } + } + + bool TManager::HasTrace(const TString& id) const { + TGuard<TMutex> g(Mtx); return Traces.contains(id); - } - - const TSession* TManager::GetTrace(const TString& id) const { - TGuard<TMutex> g(Mtx); - TTraces::const_iterator it = Traces.find(id); - if (it == Traces.end()) { - ythrow yexception() << "trace id '" << id << "' is not used"; - } else { - return it->second; - } - } - - void TManager::New(const TString& id, const TQuery& query) { - TGuard<TMutex> g(Mtx); - if (Traces.find(id) == Traces.end()) { - TSession* trace = new TSession(++LastTraceIdx, Registry, query, GetDestructiveActionsAllowed(), CustomActionFactory); - Traces[id] = trace; - } else { - ythrow yexception() << "trace id '" << id << "' is already used"; - } - } - - void TManager::Delete(const TString& id) { - TGuard<TMutex> g(Mtx); - TTraces::iterator it = Traces.find(id); - if (it == Traces.end()) { - ythrow yexception() << "trace id '" << id << "' is not used"; - } else { - delete it->second; - Traces.erase(it); - } - } - - void TManager::Stop(const TString& id) { - TGuard<TMutex> g(Mtx); - TTraces::iterator it = Traces.find(id); - if (it == Traces.end()) { - ythrow yexception() << "trace id '" << id << "' is not used"; - } else { - it->second->Detach(); - } - } -} + } + + const TSession* TManager::GetTrace(const TString& id) const { + TGuard<TMutex> g(Mtx); + TTraces::const_iterator it = Traces.find(id); + if (it == Traces.end()) { + ythrow yexception() << "trace id '" << id << "' is not used"; + } else { + return it->second; + } + } + + void TManager::New(const TString& id, const TQuery& query) { + TGuard<TMutex> g(Mtx); + if (Traces.find(id) == Traces.end()) { + TSession* trace = new TSession(++LastTraceIdx, Registry, query, GetDestructiveActionsAllowed(), CustomActionFactory); + Traces[id] = trace; + } else { + ythrow yexception() << "trace id '" << id << "' is already used"; + } + } + + void TManager::Delete(const TString& id) { + TGuard<TMutex> g(Mtx); + TTraces::iterator it = Traces.find(id); + if (it == Traces.end()) { + ythrow yexception() << "trace id '" << id << "' is not used"; + } else { + delete it->second; + Traces.erase(it); + } + } + + void TManager::Stop(const TString& id) { + TGuard<TMutex> g(Mtx); + TTraces::iterator it = Traces.find(id); + if (it == Traces.end()) { + ythrow yexception() << "trace id '" << id << "' is not used"; + } else { + it->second->Detach(); + } + } +} diff --git a/library/cpp/lwtrace/trace_ut.cpp b/library/cpp/lwtrace/trace_ut.cpp index cb03e4fbde..dd67212ea2 100644 --- a/library/cpp/lwtrace/trace_ut.cpp +++ b/library/cpp/lwtrace/trace_ut.cpp @@ -1,11 +1,11 @@ -#include "all.h" - +#include "all.h" + #include <library/cpp/lwtrace/protos/lwtrace.pb.h> #include <library/cpp/testing/unittest/registar.h> - + #include <google/protobuf/text_format.h> - + enum ESimpleEnum { ValueA, ValueB, @@ -27,53 +27,53 @@ enum class EEnumClass { PROBE(DurationParam, GROUPS("Group"), TYPES(TDuration), NAMES("value")) \ PROBE(ProtoEnum, GROUPS("Group"), TYPES(NLWTrace::EOperatorType), NAMES("value")) \ PROBE(IntIntParams, GROUPS("Group"), TYPES(ui32, ui64), NAMES("value1", "value2")) \ - /**/ - -LWTRACE_DECLARE_PROVIDER(LWTRACE_UT_PROVIDER) -LWTRACE_DEFINE_PROVIDER(LWTRACE_UT_PROVIDER) -LWTRACE_USING(LWTRACE_UT_PROVIDER) - -using namespace NLWTrace; - + /**/ + +LWTRACE_DECLARE_PROVIDER(LWTRACE_UT_PROVIDER) +LWTRACE_DEFINE_PROVIDER(LWTRACE_UT_PROVIDER) +LWTRACE_USING(LWTRACE_UT_PROVIDER) + +using namespace NLWTrace; + Y_UNIT_TEST_SUITE(LWTraceTrace) { #ifndef LWTRACE_DISABLE Y_UNIT_TEST(Smoke) { - TManager mngr(*Singleton<TProbeRegistry>(), true); - TQuery q; - bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END( - Blocks { - ProbeDesc { - Name: "NoParam" - Provider: "LWTRACE_UT_PROVIDER" - } - Action { - LogAction { } - } - } - )END", - &q); - UNIT_ASSERT(parsed); - mngr.New("Query1", q); - LWPROBE(NoParam); - struct { - void Push(TThread::TId, const TLogItem& item) { - UNIT_ASSERT(TString(item.Probe->Event.Name) == "NoParam"); - } - } reader; - mngr.ReadLog("Query1", reader); + TManager mngr(*Singleton<TProbeRegistry>(), true); + TQuery q; + bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END( + Blocks { + ProbeDesc { + Name: "NoParam" + Provider: "LWTRACE_UT_PROVIDER" + } + Action { + LogAction { } + } + } + )END", + &q); + UNIT_ASSERT(parsed); + mngr.New("Query1", q); + LWPROBE(NoParam); + struct { + void Push(TThread::TId, const TLogItem& item) { + UNIT_ASSERT(TString(item.Probe->Event.Name) == "NoParam"); + } + } reader; + mngr.ReadLog("Query1", reader); LWPROBE(EnumParams, ValueA, EEnumClass::ValueC); LWPROBE(InstantParam, TInstant::Seconds(42)); LWPROBE(DurationParam, TDuration::MilliSeconds(146)); LWPROBE(ProtoEnum, OT_EQ); - } + } Y_UNIT_TEST(Predicate) { TManager mngr(*Singleton<TProbeRegistry>(), true); TQuery q; bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END( Blocks { - ProbeDesc { + ProbeDesc { Name: "IntParam" Provider: "LWTRACE_UT_PROVIDER" } @@ -85,7 +85,7 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { } } Action { - LogAction { } + LogAction { } } } )END", &q); @@ -117,7 +117,7 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { TQuery q; bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END( Blocks { - ProbeDesc { + ProbeDesc { Name: "IntParam" Provider: "LWTRACE_UT_PROVIDER" } @@ -203,7 +203,7 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { } } Blocks { - ProbeDesc { + ProbeDesc { Name: "IntParam" Provider: "LWTRACE_UT_PROVIDER" } @@ -216,53 +216,53 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { Operators { Type: OT_EQ Argument { Variable: "varDec" } - Argument { Value: "-1" } + Argument { Value: "-1" } } Operators { Type: OT_EQ Argument { Variable: "varMov" } - Argument { Value: "3" } + Argument { Value: "3" } } Operators { Type: OT_EQ Argument { Variable: "varAddEq" } - Argument { Value: "5" } + Argument { Value: "5" } } Operators { Type: OT_EQ Argument { Variable: "varSubEq" } - Argument { Value: "-5" } + Argument { Value: "-5" } } Operators { Type: OT_EQ Argument { Variable: "varAdd" } - Argument { Value: "5" } + Argument { Value: "5" } } Operators { Type: OT_EQ Argument { Variable: "varSub" } - Argument { Value: "1" } + Argument { Value: "1" } } Operators { Type: OT_EQ Argument { Variable: "varMul" } - Argument { Value: "12" } + Argument { Value: "12" } } Operators { Type: OT_EQ Argument { Variable: "varDiv" } - Argument { Value: "3" } + Argument { Value: "3" } } Operators { Type: OT_EQ Argument { Variable: "varMod" } - Argument { Value: "2" } + Argument { Value: "2" } } } Action { LogAction { } } - } + } )END", &q); UNIT_ASSERT(parsed); mngr.New("QueryName", q); @@ -286,7 +286,7 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { TQuery q; bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END( Blocks { - ProbeDesc { + ProbeDesc { Name: "IntIntParams" Provider: "LWTRACE_UT_PROVIDER" } @@ -353,7 +353,7 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { } } Blocks { - ProbeDesc { + ProbeDesc { Name: "IntIntParams" Provider: "LWTRACE_UT_PROVIDER" } @@ -361,48 +361,48 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { Operators { Type: OT_EQ Argument { Variable: "varMov" } - Argument { Param: "value1" } + Argument { Param: "value1" } } Operators { Type: OT_EQ Argument { Variable: "varAddEq" } - Argument { Param: "value1" } + Argument { Param: "value1" } } Operators { Type: OT_EQ Argument { Variable: "varSubEq" } - Argument { Value: "-22" } + Argument { Value: "-22" } } Operators { Type: OT_EQ Argument { Variable: "varAdd" } - Argument { Value: "25" } + Argument { Value: "25" } } Operators { Type: OT_EQ Argument { Variable: "varSub" } - Argument { Value: "19" } + Argument { Value: "19" } } Operators { Type: OT_EQ Argument { Variable: "varMul" } - Argument { Value: "66" } + Argument { Value: "66" } } Operators { Type: OT_EQ Argument { Variable: "varDiv" } - Argument { Value: "7" } + Argument { Value: "7" } } Operators { Type: OT_EQ Argument { Variable: "varMod" } - Argument { Value: "1" } + Argument { Value: "1" } } } Action { LogAction { } } - } + } )END", &q); UNIT_ASSERT(parsed); mngr.New("QueryName", q); @@ -424,12 +424,12 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END( PerThreadLogSize: 3 Blocks { - ProbeDesc { + ProbeDesc { Name: "IntParam" Provider: "LWTRACE_UT_PROVIDER" } Action { - LogAction { } + LogAction { } } } )END", &q); @@ -501,7 +501,7 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { TQuery q; bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END( Blocks { - ProbeDesc { + ProbeDesc { Name: "NoParam" Provider: "LWTRACE_UT_PROVIDER" } @@ -521,7 +521,7 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { TQuery q; bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END( Blocks { - ProbeDesc { + ProbeDesc { Name: "NoParam" Provider: "LWTRACE_UT_PROVIDER" } @@ -539,7 +539,7 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { TInstant t0 = Now(); LWPROBE(NoParam); TInstant t1 = Now(); - UNIT_ASSERT(t1.NanoSeconds() - t0.NanoSeconds() >= sleepTimeNs); + UNIT_ASSERT(t1.NanoSeconds() - t0.NanoSeconds() >= sleepTimeNs); } Y_UNIT_TEST(ProtoEnumTraits) { @@ -550,37 +550,37 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { } Y_UNIT_TEST(Track) { - TManager mngr(*Singleton<TProbeRegistry>(), true); - TQuery q; - bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END( - Blocks { - ProbeDesc { - Name: "IntParam" - Provider: "LWTRACE_UT_PROVIDER" - } - Action { - RunLogShuttleAction { } - } - } + TManager mngr(*Singleton<TProbeRegistry>(), true); + TQuery q; + bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END( + Blocks { + ProbeDesc { + Name: "IntParam" + Provider: "LWTRACE_UT_PROVIDER" + } + Action { + RunLogShuttleAction { } + } + } )END", &q); - UNIT_ASSERT(parsed); - mngr.New("Query1", q); - - { - TOrbit orbit; - LWTRACK(IntParam, orbit, 1); - LWTRACK(StringParam, orbit, "str"); - } - - struct { - void Push(TThread::TId, const TTrackLog& tl) { - UNIT_ASSERT(tl.Items.size() == 2); - UNIT_ASSERT(TString(tl.Items[0].Probe->Event.Name) == "IntParam"); - UNIT_ASSERT(TString(tl.Items[1].Probe->Event.Name) == "StringParam"); - } - } reader; - mngr.ReadDepot("Query1", reader); - } + UNIT_ASSERT(parsed); + mngr.New("Query1", q); + + { + TOrbit orbit; + LWTRACK(IntParam, orbit, 1); + LWTRACK(StringParam, orbit, "str"); + } + + struct { + void Push(TThread::TId, const TTrackLog& tl) { + UNIT_ASSERT(tl.Items.size() == 2); + UNIT_ASSERT(TString(tl.Items[0].Probe->Event.Name) == "IntParam"); + UNIT_ASSERT(TString(tl.Items[1].Probe->Event.Name) == "StringParam"); + } + } reader; + mngr.ReadDepot("Query1", reader); + } Y_UNIT_TEST(ShouldSerializeTracks) { @@ -877,4 +877,4 @@ Y_UNIT_TEST_SUITE(LWTraceTrace) { mngr.ReadDepot("Query1", reader); } #endif // LWTRACE_DISABLE -} +} diff --git a/library/cpp/lwtrace/ut/ya.make b/library/cpp/lwtrace/ut/ya.make index f43118bab7..03599cad26 100644 --- a/library/cpp/lwtrace/ut/ya.make +++ b/library/cpp/lwtrace/ut/ya.make @@ -1,11 +1,11 @@ UNITTEST_FOR(library/cpp/lwtrace) - -OWNER(serxa) - -FORK_SUBTESTS() - -SRCS( - trace_ut.cpp -) - -END() + +OWNER(serxa) + +FORK_SUBTESTS() + +SRCS( + trace_ut.cpp +) + +END() diff --git a/library/cpp/lwtrace/ya.make b/library/cpp/lwtrace/ya.make index d9accb3006..3f19aa1973 100644 --- a/library/cpp/lwtrace/ya.make +++ b/library/cpp/lwtrace/ya.make @@ -1,25 +1,25 @@ LIBRARY() -OWNER(serxa) +OWNER(serxa) -PEERDIR( +PEERDIR( library/cpp/lwtrace/protos -) - +) + SRCS( - check.cpp + check.cpp control.cpp - custom_action.cpp + custom_action.cpp kill_action.cpp log_shuttle.cpp - perf.cpp - probes.cpp - shuttle.cpp + perf.cpp + probes.cpp + shuttle.cpp sleep_action.cpp - start.cpp - stderr_writer.cpp - symbol.cpp - trace.cpp + start.cpp + stderr_writer.cpp + symbol.cpp + trace.cpp ) END() diff --git a/library/cpp/monlib/counters/counters.cpp b/library/cpp/monlib/counters/counters.cpp index 50dca4c577..6ea370e081 100644 --- a/library/cpp/monlib/counters/counters.cpp +++ b/library/cpp/monlib/counters/counters.cpp @@ -21,7 +21,7 @@ namespace NMonitoring { if (i == 0 || i >= imax) *buf = '\0'; else - snprintf(buf, size, "%" PRId64 ".%" PRId64 "%c", major, minor, shorts[i]); + snprintf(buf, size, "%" PRId64 ".%" PRId64 "%c", major, minor, shorts[i]); return buf; } @@ -32,18 +32,18 @@ namespace NMonitoring { buf[0] = 0; return buf; } - PrettyNumShort(val, buf + 2, size - 3); - if (buf[2] == 0) { - *buf = '\0'; - } else { + PrettyNumShort(val, buf + 2, size - 3); + if (buf[2] == 0) { + *buf = '\0'; + } else { size_t len = 2 + strnlen(buf + 2, size - 4); Y_ASSERT(len < size); - buf[0] = ' '; - buf[1] = '('; - buf[len] = ')'; - buf[len + 1] = '\0'; - } - - return buf; - } + buf[0] = ' '; + buf[1] = '('; + buf[len] = ')'; + buf[len + 1] = '\0'; + } + + return buf; + } } diff --git a/library/cpp/monlib/dynamic_counters/counters.cpp b/library/cpp/monlib/dynamic_counters/counters.cpp index 3635d87d0d..b4ee2942aa 100644 --- a/library/cpp/monlib/dynamic_counters/counters.cpp +++ b/library/cpp/monlib/dynamic_counters/counters.cpp @@ -184,11 +184,11 @@ void TDynamicCounters::RegisterSubgroup(const TString& name, const TString& valu } void TDynamicCounters::OutputHtml(IOutputStream& os) const { - HTML(os) { - PRE() { + HTML(os) { + PRE() { OutputPlainText(os); - } - } + } + } } void TDynamicCounters::EnumerateSubgroups(const std::function<void(const TString& name, const TString& value)>& output) const { diff --git a/library/cpp/monlib/dynamic_counters/page.cpp b/library/cpp/monlib/dynamic_counters/page.cpp index 5124a47bb3..6fc7719a48 100644 --- a/library/cpp/monlib/dynamic_counters/page.cpp +++ b/library/cpp/monlib/dynamic_counters/page.cpp @@ -107,15 +107,15 @@ void TDynamicCountersPage::HandleAbsentSubgroup(IMonHttpRequest& request) { void TDynamicCountersPage::BeforePre(IMonHttpRequest& request) { IOutputStream& out = request.Output(); - HTML(out) { - DIV() { + HTML(out) { + DIV() { out << "<a href='" << request.GetPath() << "/json'>Counters as JSON</a>"; out << " for <a href='https://wiki.yandex-team.ru/solomon/'>Solomon</a>"; - } + } H5() { out << "Counters subgroups"; - } + } UL() { currentCounters->EnumerateSubgroups([&](const TString& name, const TString& value) { LI() { @@ -129,7 +129,7 @@ void TDynamicCountersPage::BeforePre(IMonHttpRequest& request) { H4() { out << "Counters as text"; } - } + } } void TDynamicCountersPage::OutputText(IOutputStream& out, IMonHttpRequest&) { diff --git a/library/cpp/monlib/service/pages/html_mon_page.cpp b/library/cpp/monlib/service/pages/html_mon_page.cpp index eb4eb3b66c..fdb9229f04 100644 --- a/library/cpp/monlib/service/pages/html_mon_page.cpp +++ b/library/cpp/monlib/service/pages/html_mon_page.cpp @@ -8,10 +8,10 @@ void THtmlMonPage::Output(NMonitoring::IMonHttpRequest& request) { IOutputStream& out = request.Output(); out << HTTPOKHTML; - HTML(out) { + HTML(out) { out << "<!DOCTYPE html>\n"; - HTML_TAG() { - HEAD() { + HTML_TAG() { + HEAD() { if (!!Title) { out << "<title>" << Title << "</title>\n"; } @@ -32,19 +32,19 @@ void THtmlMonPage::Output(NMonitoring::IMonHttpRequest& request) { out << ".narrow-line80 {line-height: 80%}\n"; out << ".narrow-line90 {line-height: 90%}\n"; out << "</style>\n"; - } - BODY() { + } + BODY() { OutputNavBar(out); - DIV_CLASS("container") { + DIV_CLASS("container") { if (!!Title) { out << "<h2>" << Title << "</h2>"; } OutputContent(request); - } - } - } - } + } + } + } + } } void THtmlMonPage::NotFound(NMonitoring::IMonHttpRequest& request) const { diff --git a/library/cpp/monlib/service/pages/mon_page.h b/library/cpp/monlib/service/pages/mon_page.h index e396612bb0..4e244b292d 100644 --- a/library/cpp/monlib/service/pages/mon_page.h +++ b/library/cpp/monlib/service/pages/mon_page.h @@ -29,7 +29,7 @@ namespace NMonitoring { // Images static const char HTTPOKPNG[] = "HTTP/1.1 200 Ok\r\nContent-Type: image/png\r\nConnection: Close\r\n\r\n"; static const char HTTPOKSVG[] = "HTTP/1.1 200 Ok\r\nContent-Type: image/svg+xml\r\nConnection: Close\r\n\r\n"; - + class IMonPage; using TMonPagePtr = TIntrusivePtr<IMonPage>; diff --git a/library/cpp/monlib/service/pages/resource_mon_page.cpp b/library/cpp/monlib/service/pages/resource_mon_page.cpp index ec4ac6a1a7..5571b70575 100644 --- a/library/cpp/monlib/service/pages/resource_mon_page.cpp +++ b/library/cpp/monlib/service/pages/resource_mon_page.cpp @@ -17,27 +17,27 @@ void TResourceMonPage::Output(NMonitoring::IMonHttpRequest& request) { case JAVASCRIPT: out << HTTPOKJAVASCRIPT; break; - case FONT_EOT: - out << HTTPOKFONTEOT; - break; - case FONT_TTF: - out << HTTPOKFONTTTF; - break; - case FONT_WOFF: - out << HTTPOKFONTWOFF; - break; - case FONT_WOFF2: - out << HTTPOKFONTWOFF2; - break; - case PNG: - out << HTTPOKPNG; - break; - case SVG: - out << HTTPOKSVG; - break; + case FONT_EOT: + out << HTTPOKFONTEOT; + break; + case FONT_TTF: + out << HTTPOKFONTTTF; + break; + case FONT_WOFF: + out << HTTPOKFONTWOFF; + break; + case FONT_WOFF2: + out << HTTPOKFONTWOFF2; + break; + case PNG: + out << HTTPOKPNG; + break; + case SVG: + out << HTTPOKSVG; + break; default: out << HTTPOKBIN; - break; + break; } out << NResource::Find(ResourceName); } diff --git a/library/cpp/monlib/service/pages/resource_mon_page.h b/library/cpp/monlib/service/pages/resource_mon_page.h index f6ab67200e..aecb83c7be 100644 --- a/library/cpp/monlib/service/pages/resource_mon_page.h +++ b/library/cpp/monlib/service/pages/resource_mon_page.h @@ -18,11 +18,11 @@ namespace NMonitoring { FONT_TTF, FONT_WOFF, FONT_WOFF2, - + PNG, SVG }; - + TResourceMonPage(const TString& path, const TString& resourceName, const EResourceType& resourceType = BINARY) : IMonPage(path, "") diff --git a/library/cpp/monlib/service/pages/templates.h b/library/cpp/monlib/service/pages/templates.h index b4656f059f..4a96171f7c 100644 --- a/library/cpp/monlib/service/pages/templates.h +++ b/library/cpp/monlib/service/pages/templates.h @@ -1,11 +1,11 @@ #pragma once #include <util/stream/output.h> -#include <util/system/defaults.h> +#include <util/system/defaults.h> -#define WITH_SCOPED(var, value) WITH_SCOPED_I(var, value, Y_GENERATE_UNIQUE_ID(WITH_SCOPED_LABEL_)) +#define WITH_SCOPED(var, value) WITH_SCOPED_I(var, value, Y_GENERATE_UNIQUE_ID(WITH_SCOPED_LABEL_)) -#define WITH_SCOPED_I(var, value, label) \ +#define WITH_SCOPED_I(var, value, label) \ if (auto var = (value)) { \ Y_UNUSED(var); \ goto label; \ @@ -27,12 +27,12 @@ #define HTML_TAG() TAG(THtml) #define DIV() TAG(TDiv) #define DIV_CLASS(cls) TAG_CLASS(TDiv, cls) -#define DIV_CLASS_ID(cls, id) TAG_CLASS_ID(TDiv, cls, id) +#define DIV_CLASS_ID(cls, id) TAG_CLASS_ID(TDiv, cls, id) #define PRE() TAG(TPre) #define TABLE() TAG(TTable) #define TABLE_CLASS(cls) TAG_CLASS(TTable, cls) #define TABLE_SORTABLE() TABLE_CLASS("table-sortable") -#define TABLE_SORTABLE_CLASS(cls) TABLE_CLASS(cls " table-sortable") +#define TABLE_SORTABLE_CLASS(cls) TABLE_CLASS(cls " table-sortable") #define TABLEHEAD() TAG(TTableHead) #define TABLEHEAD_CLASS(cls) TAG_CLASS(TTableHead, cls) #define TABLEBODY() TAG(TTableBody) @@ -48,9 +48,9 @@ #define FORM_CLASS(cls) TAG_CLASS(TFormC, cls) #define LABEL() TAG(TLabelC) #define LABEL_CLASS(cls) TAG_CLASS(TLabelC, cls) -#define LABEL_CLASS_FOR(cls, for0) TAG_CLASS_FOR(TLabelC, cls, for0) +#define LABEL_CLASS_FOR(cls, for0) TAG_CLASS_FOR(TLabelC, cls, for0) #define SPAN_CLASS(cls) TAG_CLASS(TSpanC, cls) -#define SPAN_CLASS_STYLE(cls, style) TAG_CLASS_STYLE(TSpanC, cls, style) +#define SPAN_CLASS_STYLE(cls, style) TAG_CLASS_STYLE(TSpanC, cls, style) #define PARA() TAG(TPara) #define PARA_CLASS(cls) TAG_CLASS(TPara, cls) @@ -87,12 +87,12 @@ #define CAPTION() TAG(TCaption) #define CAPTION_CLASS(cls) CAPTION_CLASS(TCaption, cls) - + #define HTML_OUTPUT_PARAM(str, param) str << #param << ": " << param << "<br/>" #define HTML_OUTPUT_TIME_PARAM(str, param) str << #param << ": " << ToStringLocalTimeUpToSeconds(param) << "<br/>" -#define COLLAPSED_BUTTON_CONTENT(targetId, buttonText) \ - WITH_SCOPED(tmp, NMonitoring::TCollapsedButton(__stream, targetId, buttonText)) +#define COLLAPSED_BUTTON_CONTENT(targetId, buttonText) \ + WITH_SCOPED(tmp, NMonitoring::TCollapsedButton(__stream, targetId, buttonText)) #define HREF(path) \ WITH_SCOPED(tmp, NMonitoring::THref(__stream, path)) @@ -156,10 +156,10 @@ namespace NMonitoring { } } - explicit inline operator bool() const noexcept { - return true; // just to work with WITH_SCOPED - } - + explicit inline operator bool() const noexcept { + return true; // just to work with WITH_SCOPED + } + IOutputStream& Str; }; @@ -180,30 +180,30 @@ namespace NMonitoring { } } - explicit inline operator bool() const noexcept { - return true; // just to work with WITH_SCOPED - } - + explicit inline operator bool() const noexcept { + return true; // just to work with WITH_SCOPED + } + IOutputStream& Str; }; - struct TOutputStreamRef { + struct TOutputStreamRef { TOutputStreamRef(IOutputStream& str) - : Str(str) + : Str(str) { } - + inline operator IOutputStream&() noexcept { - return Str; - } - - explicit inline operator bool() const noexcept { - return true; // just to work with WITH_SCOPED - } - + return Str; + } + + explicit inline operator bool() const noexcept { + return true; // just to work with WITH_SCOPED + } + IOutputStream& Str; - }; - + }; + extern const char HtmlTag[5]; extern const char HeadTag[5]; extern const char BodyTag[5]; diff --git a/library/cpp/scheme/scheme.h b/library/cpp/scheme/scheme.h index 3d7c59f3c9..cfbb61580d 100644 --- a/library/cpp/scheme/scheme.h +++ b/library/cpp/scheme/scheme.h @@ -387,7 +387,7 @@ namespace NSc { static TValue From(const ::google::protobuf::Message&, bool mapAsDict = false); - void To(::google::protobuf::Message&, const TProtoOpts& opts = {}) const; + void To(::google::protobuf::Message&, const TProtoOpts& opts = {}) const; public: inline explicit TValue(TPoolPtr&); @@ -421,11 +421,11 @@ namespace NSc { static TValue FromField(const ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*); static TValue FromRepeatedField(const ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, int index); - void ValueToField(const TValue& value, ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; - void ToField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; - void ToEnumField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; - void ToRepeatedField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; - void ToMapField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; + void ValueToField(const TValue& value, ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; + void ToField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; + void ToEnumField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; + void ToRepeatedField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; + void ToMapField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const; }; diff --git a/library/cpp/scheme/scimpl_defs.h b/library/cpp/scheme/scimpl_defs.h index f3dd66b437..8937b75837 100644 --- a/library/cpp/scheme/scimpl_defs.h +++ b/library/cpp/scheme/scimpl_defs.h @@ -117,14 +117,14 @@ namespace NSc { } }; - struct TProtoOpts { - // Serialization throws on unknown enum value if not set, else use default value - bool UnknownEnumValueIsDefault = false; - - // Serialization throws on type mismatch if not set, else leaves protobuf empty - bool SkipTypeMismatch = false; - }; - + struct TProtoOpts { + // Serialization throws on unknown enum value if not set, else use default value + bool UnknownEnumValueIsDefault = false; + + // Serialization throws on type mismatch if not set, else leaves protobuf empty + bool SkipTypeMismatch = false; + }; + namespace NImpl { class TKeySortContext; class TSelfLoopContext; diff --git a/library/cpp/scheme/scimpl_protobuf.cpp b/library/cpp/scheme/scimpl_protobuf.cpp index 0c99122c69..190449effa 100644 --- a/library/cpp/scheme/scimpl_protobuf.cpp +++ b/library/cpp/scheme/scimpl_protobuf.cpp @@ -129,7 +129,7 @@ namespace NSc { return v; } - void TValue::To(Message& msg, const TProtoOpts& opts) const { + void TValue::To(Message& msg, const TProtoOpts& opts) const { msg.Clear(); if (IsNull()) { @@ -144,16 +144,16 @@ namespace NSc { for (int i = 0, count = descriptor->field_count(); i < count; ++i) { const FieldDescriptor* field = descriptor->field(i); if (field->is_map()) { - ToMapField(msg, field, opts); + ToMapField(msg, field, opts); } else if (field->is_repeated()) { - ToRepeatedField(msg, field, opts); + ToRepeatedField(msg, field, opts); } else { - ToField(msg, field, opts); + ToField(msg, field, opts); } } } - void TValue::ValueToField(const TValue& value, Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const { + void TValue::ValueToField(const TValue& value, Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const { const TString& name = field->name(); if (value.IsNull()) { if (field->is_required() && !field->has_default_value()) { @@ -190,10 +190,10 @@ namespace NSc { reflection->SetString(&msg, field, value.ForceString()); break; case FieldDescriptor::CPPTYPE_ENUM: - value.ToEnumField(msg, field, opts); + value.ToEnumField(msg, field, opts); break; case FieldDescriptor::CPPTYPE_MESSAGE: - value.To(*reflection->MutableMessage(&msg, field), opts); + value.To(*reflection->MutableMessage(&msg, field), opts); break; default: ythrow TSchemeException() @@ -202,13 +202,13 @@ namespace NSc { } } - void TValue::ToField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const { + void TValue::ToField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const { const TString& name = field->name(); const TValue& value = Get(name); - ValueToField(value, msg, field, opts); + ValueToField(value, msg, field, opts); } - void TValue::ToEnumField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const { + void TValue::ToEnumField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const { const EnumDescriptor* enumField = field->enum_type(); const EnumValueDescriptor* enumFieldValue = IsString() @@ -216,11 +216,11 @@ namespace NSc { : enumField->FindValueByNumber(ForceIntNumber()); if (!enumFieldValue) { - if (opts.UnknownEnumValueIsDefault) { - enumFieldValue = field->default_value_enum(); - } else { - ythrow TSchemeException() << "invalid value of enum field " << field->name(); - } + if (opts.UnknownEnumValueIsDefault) { + enumFieldValue = field->default_value_enum(); + } else { + ythrow TSchemeException() << "invalid value of enum field " << field->name(); + } } const Reflection* reflection = msg.GetReflection(); @@ -232,7 +232,7 @@ namespace NSc { } } - void TValue::ToRepeatedField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const { + void TValue::ToRepeatedField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const { const TString& name = field->name(); const TValue& fieldValue = Get(name); @@ -241,11 +241,11 @@ namespace NSc { } if (!fieldValue.IsArray()) { - if (opts.SkipTypeMismatch) { - return; // leave repeated field empty - } else { - ythrow TSchemeException() << "invalid type of repeated field " << name << ": not an array"; - } + if (opts.SkipTypeMismatch) { + return; // leave repeated field empty + } else { + ythrow TSchemeException() << "invalid type of repeated field " << name << ": not an array"; + } } const Reflection* reflection = msg.GetReflection(); @@ -277,7 +277,7 @@ namespace NSc { reflection->AddString(&msg, field, value.ForceString()); break; case FieldDescriptor::CPPTYPE_ENUM: - value.ToEnumField(msg, field, opts); + value.ToEnumField(msg, field, opts); break; case FieldDescriptor::CPPTYPE_MESSAGE: value.To(*reflection->AddMessage(&msg, field)); @@ -290,7 +290,7 @@ namespace NSc { } } - void TValue::ToMapField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const { + void TValue::ToMapField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const { const TString& name = field->name(); const TValue& fieldValue = Get(name); @@ -300,16 +300,16 @@ namespace NSc { if (fieldValue.IsArray()) { // read dict from key, value array - ToRepeatedField(msg, field, opts); + ToRepeatedField(msg, field, opts); return; } if (!fieldValue.IsDict()) { - if (opts.SkipTypeMismatch) { - return; // leave map field empty - } else { - ythrow TSchemeException() << "invalid type of map field " << name << ": not dict or array"; - } + if (opts.SkipTypeMismatch) { + return; // leave map field empty + } else { + ythrow TSchemeException() << "invalid type of map field " << name << ": not dict or array"; + } } const Reflection* reflection = msg.GetReflection(); @@ -322,7 +322,7 @@ namespace NSc { auto valueField = entryDesc->FindFieldByNumber(2); auto entryReflection = entry->GetReflection(); entryReflection->SetString(entry.Get(), keyField, TString(value.first)); - ValueToField(value.second, *entry, valueField, opts); + ValueToField(value.second, *entry, valueField, opts); mutableField.Add(*entry); } } diff --git a/ydb/core/base/blobstorage.h b/ydb/core/base/blobstorage.h index a2faee326e..86568f8d47 100644 --- a/ydb/core/base/blobstorage.h +++ b/ydb/core/base/blobstorage.h @@ -538,7 +538,7 @@ struct TEvBlobStorage { EvChunkWrite, EvHarakiri, EvCheckSpace, - EvConfigureScheduler, + EvConfigureScheduler, EvYardControl, EvCutLog, EvIPDiskGet, /// 268 636 170 @@ -588,7 +588,7 @@ struct TEvBlobStorage { EvVDiskRequestCompleted, EvFrontRecoveryStatus, EvPruneQueue, - EvPDiskFairSchedulerWake, + EvPDiskFairSchedulerWake, EvVDiskGuidObtained, EvCompactionFinished, EvKickEmergencyPutQueue, /// 268 636 220 @@ -680,7 +680,7 @@ struct TEvBlobStorage { EvChunkWriteResult, EvHarakiriResult, EvCheckSpaceResult, - EvConfigureSchedulerResult, + EvConfigureSchedulerResult, EvYardControlResult, EvIPDiskGetResult, EvSyncLogSnapshotResult, /// 268 636 682 diff --git a/ydb/core/base/grpc_service_factory.h b/ydb/core/base/grpc_service_factory.h index 0ae4fd9dd8..675a436b0b 100644 --- a/ydb/core/base/grpc_service_factory.h +++ b/ydb/core/base/grpc_service_factory.h @@ -1,13 +1,13 @@ #pragma once -#include <library/cpp/grpc/server/grpc_server.h> - +#include <library/cpp/grpc/server/grpc_server.h> + namespace NKikimr { -// Parameterize YDB binary with grpc services registry -class TGrpcServiceFactory { -private: - using TServicePtr = TIntrusivePtr<NGrpc::IGRpcService>; +// Parameterize YDB binary with grpc services registry +class TGrpcServiceFactory { +private: + using TServicePtr = TIntrusivePtr<NGrpc::IGRpcService>; using TFactoryMethod = std::function< TServicePtr( NActors::TActorSystem*, @@ -31,8 +31,8 @@ private: private: std::unordered_map<TString, std::vector<TServiceParams>> Registry; -public: - template <class TService> +public: + template <class TService> void Register( const TString& name, bool enableByDefault = false, @@ -43,15 +43,15 @@ public: TIntrusivePtr<NMonitoring::TDynamicCounters> counters, NActors::TActorId grpcRequestProxyId ) { - return TServicePtr(new TService(actorSystem, counters, grpcRequestProxyId)); + return TServicePtr(new TService(actorSystem, counters, grpcRequestProxyId)); }; Registry[name].emplace_back( method, enableByDefault, grpcRequestProxyIdForService ); - } - + } + std::vector<TServicePtr> Create( const std::unordered_set<TString>& enabled, const std::unordered_set<TString>& disabled, @@ -59,24 +59,24 @@ public: TIntrusivePtr<NMonitoring::TDynamicCounters> counters, NActors::TActorId grpcRequestProxyId ) { - std::vector<TServicePtr> services; - for (const auto& [name, methods] : Registry) { + std::vector<TServicePtr> services; + for (const auto& [name, methods] : Registry) { for (const auto& [method, enableByDefault, grpcRequestProxyIdForService] : methods) { - if (!disabled.count(name) && (enabled.count(name) || enableByDefault)) { + if (!disabled.count(name) && (enabled.count(name) || enableByDefault)) { services.emplace_back(method( actorSystem, counters, grpcRequestProxyIdForService.value_or(grpcRequestProxyId) )); - } - } - } - return services; - } - - bool Has(const TString& name) const { - return Registry.find(name) != Registry.end(); - } -}; - + } + } + } + return services; + } + + bool Has(const TString& name) const { + return Registry.find(name) != Registry.end(); + } +}; + } // NKikimr diff --git a/ydb/core/base/quoter.h b/ydb/core/base/quoter.h index 41a19775bc..502c4abe96 100644 --- a/ydb/core/base/quoter.h +++ b/ydb/core/base/quoter.h @@ -3,7 +3,7 @@ #include "events.h" #include <library/cpp/actors/core/event_local.h> #include <util/generic/deque.h> -#include <util/generic/vector.h> +#include <util/generic/vector.h> #include <ydb/core/util/time_series_vec.h> namespace NKikimr { @@ -49,7 +49,7 @@ struct TEvQuota { , ResourceId(resourceId) , Amount(amount) , IsUsedAmount(isUsedAmount) - {} + {} TResourceLeaf(const TString "er, const TString &resource, ui64 amount, bool isUsedAmount = false) : QuoterId(0) @@ -58,7 +58,7 @@ struct TEvQuota { , Resource(resource) , Amount(amount) , IsUsedAmount(isUsedAmount) - {} + {} }; enum class EResourceOperator { @@ -146,17 +146,17 @@ struct TEvQuota { const ui64 Tick; const double Consumed; - const TTimeSeriesMap<double> History; + const TTimeSeriesMap<double> History; const ui64 QueueSize; const double QueueWeight; const double ExpectedRate; const double Cap; - TProxyStat(ui64 id, ui64 tick, double consumed, const TTimeSeriesMap<double>& history, ui64 queueSize, double queueWeight, double rate, double cap) + TProxyStat(ui64 id, ui64 tick, double consumed, const TTimeSeriesMap<double>& history, ui64 queueSize, double queueWeight, double rate, double cap) : ResourceId(id) , Tick(tick) , Consumed(consumed) - , History(history) + , History(history) , QueueSize(queueSize) , QueueWeight(queueWeight) , ExpectedRate(rate) @@ -170,7 +170,7 @@ struct TEvQuota { const TDeque<TProxyStat> Stats; TEvProxyStats(TDeque<TProxyStat> &&stats) - : Stats(std::move(stats)) + : Stats(std::move(stats)) {} }; diff --git a/ydb/core/base/statestorage_monitoring.cpp b/ydb/core/base/statestorage_monitoring.cpp index 5bcc3ec67f..6ab657d562 100644 --- a/ydb/core/base/statestorage_monitoring.cpp +++ b/ydb/core/base/statestorage_monitoring.cpp @@ -49,52 +49,52 @@ class TStateStorageMonitoringActor : public TActorBootstrapped<TStateStorageMoni void Reply(const TString &response, const TActorContext &ctx) { TStringStream str; - HTML(str) { - H3() { str << "State Storage";} - DIV_CLASS("container") { - DIV_CLASS("row") {str << "TabletID: " << TabletID;} - DIV_CLASS("row") {str << "Response: " << response;} - - if (ProxyReplyTime.GetValue() != Max<ui64>()) { - DIV_CLASS("row") {str << "Proxy reply time: " << ProxyReplyTime.ToString(); } - } + HTML(str) { + H3() { str << "State Storage";} + DIV_CLASS("container") { + DIV_CLASS("row") {str << "TabletID: " << TabletID;} + DIV_CLASS("row") {str << "Response: " << response;} + + if (ProxyReplyTime.GetValue() != Max<ui64>()) { + DIV_CLASS("row") {str << "Proxy reply time: " << ProxyReplyTime.ToString(); } + } DIV_CLASS("CfgHash") {str << "Config hash: " << SelfConfigContentHash; } - DIV_CLASS("row") {str << " ";} - } + DIV_CLASS("row") {str << " ";} + } - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() { str << "NodeId";} + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() { str << "NodeId";} TABLEH() { str << "Leader";} TABLEH() { str << "Followers"; } - TABLEH() { str << "Locked";} - TABLEH() { str << "Generation";} - TABLEH() { str << "Reply time";} + TABLEH() { str << "Locked";} + TABLEH() { str << "Generation";} + TABLEH() { str << "Reply time";} TABLEH() { str << "CfgHash";} - } - } - TABLEBODY() { - for (auto &replica : ReplicasInfo) { - TABLER() { - TABLED() {str << replica.ActorID.NodeId();} - if (replica.ReplyTime.GetValue() == Max<ui64>()) { // general timeout + } + } + TABLEBODY() { + for (auto &replica : ReplicasInfo) { + TABLER() { + TABLED() {str << replica.ActorID.NodeId();} + if (replica.ReplyTime.GetValue() == Max<ui64>()) { // general timeout TABLED() { str << "timeout";} TABLED() { str << "-"; } TABLED() { str << "-"; } TABLED() { str << "-"; } TABLED() { str << "-"; } TABLED() { str << "-"; } - } else if (replica.CurrentGeneration == Max<ui32>()) { + } else if (replica.CurrentGeneration == Max<ui32>()) { TABLED() { str << "not available";} TABLED() { str << "-"; } TABLED() { str << "-"; } TABLED() { str << "-"; } TABLED() { str << "-"; } TABLED() { str << replica.ConfigContentHash; } - } else { + } else { TABLED() {str << replica.CurrentLeader;} TABLED() { if (replica.Followers) @@ -107,12 +107,12 @@ class TStateStorageMonitoringActor : public TActorBootstrapped<TStateStorageMoni TABLED() { str << replica.CurrentGeneration; } TABLED() { str << (replica.ReplyTime - ReplicasRequestMoment); } TABLED() { str << replica.ConfigContentHash; } - } - } - } - } - } - } + } + } + } + } + } + } ctx.Send(Sender, new NMon::TEvHttpInfoRes(str.Str())); return Die(ctx); diff --git a/ydb/core/blobstorage/base/html.cpp b/ydb/core/blobstorage/base/html.cpp index 6658530a94..a821b3e103 100644 --- a/ydb/core/blobstorage/base/html.cpp +++ b/ydb/core/blobstorage/base/html.cpp @@ -16,11 +16,11 @@ namespace NKikimr { }; void THtmlLightSignalRenderer::Output(IOutputStream &str) const { - HTML(str) { - SPAN_CLASS_STYLE (Lights[Light].first, Lights[Light].second) { + HTML(str) { + SPAN_CLASS_STYLE (Lights[Light].first, Lights[Light].second) { str << Value; - } - } + } + } } } // NKikimr diff --git a/ydb/core/blobstorage/base/vdisk_priorities.h b/ydb/core/blobstorage/base/vdisk_priorities.h index 4c0c9e2ead..6d69b66c00 100644 --- a/ydb/core/blobstorage/base/vdisk_priorities.h +++ b/ydb/core/blobstorage/base/vdisk_priorities.h @@ -5,20 +5,20 @@ namespace NKikimr { // - // Owner scheduler heirarchy: - // + // Owner scheduler heirarchy: + // // Log Fresh Comp // \ | / Sync Fast Other // B y t e s Huge Log Read Read Load Low // \ | | | | | / // P e r - O w n e r - S c h e d u l e r - // + // namespace NPriRead { - constexpr ui8 SyncLog = 0; // SyncLog: Synclog reads - constexpr ui8 HullComp = 1; // Comp: Background (compaction) read - constexpr ui8 HullOnlineRt = 2; // FastRead: Real-time online reads - constexpr ui8 HullOnlineOther = 3; // OtherRead: Other online reads - constexpr ui8 HullLoad = 4; // Load: Load index + constexpr ui8 SyncLog = 0; // SyncLog: Synclog reads + constexpr ui8 HullComp = 1; // Comp: Background (compaction) read + constexpr ui8 HullOnlineRt = 2; // FastRead: Real-time online reads + constexpr ui8 HullOnlineOther = 3; // OtherRead: Other online reads + constexpr ui8 HullLoad = 4; // Load: Load index constexpr ui8 HullLow = 5; // Low: Background User Data reads that 'do not affect other operations' } // TPriRead @@ -31,23 +31,23 @@ namespace NKikimr { } // NPriWrite - // PDisk internal use only (all goes through fair "Log" queue if necessary) - namespace NPriInternal { + // PDisk internal use only (all goes through fair "Log" queue if necessary) + namespace NPriInternal { constexpr ui8 LogRead = 11; constexpr ui8 LogWrite = 12; constexpr ui8 Other = 13; constexpr ui8 Trim = 14; - } // NPriInternal - - constexpr ui64 BytesSchedulerWeightDefault = 1; - constexpr ui64 LogWeightDefault = 1; + } // NPriInternal + + constexpr ui64 BytesSchedulerWeightDefault = 1; + constexpr ui64 LogWeightDefault = 1; constexpr ui64 FreshWeightDefault = 2; - constexpr ui64 CompWeightDefault = 7; - constexpr ui64 SyncLogWeightDefault = 15; - constexpr ui64 HugeWeightDefault = 2; - constexpr ui64 FastReadWeightDefault = 1; - constexpr ui64 OtherReadWeightDefault = 1; - constexpr ui64 LoadWeightDefault = 2; + constexpr ui64 CompWeightDefault = 7; + constexpr ui64 SyncLogWeightDefault = 15; + constexpr ui64 HugeWeightDefault = 2; + constexpr ui64 FastReadWeightDefault = 1; + constexpr ui64 OtherReadWeightDefault = 1; + constexpr ui64 LoadWeightDefault = 2; constexpr ui64 LowWeightDefault = 1; } // NKikimr diff --git a/ydb/core/blobstorage/dsproxy/dsproxy.h b/ydb/core/blobstorage/dsproxy/dsproxy.h index 27592e971f..070f2734c3 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy.h @@ -340,7 +340,7 @@ public: ui64 messageCookie = request->Record.GetCookie(); CountEvent(*request); const ui64 cyclesPerUs = NHPTimer::GetCyclesPerSecond() / 1000000; - request->Record.MutableTimestamps()->SetSentByDSProxyUs(GetCycleCountFast() / cyclesPerUs); + request->Record.MutableTimestamps()->SetSentByDSProxyUs(GetCycleCountFast() / cyclesPerUs); SendToQueue(std::move(request), messageCookie, TraceId.SeparateBranch(), timeStatsEnabled); } } @@ -378,7 +378,7 @@ public: ui64 messageCookie = request->Record.GetCookie(); CountEvent(*request); const ui64 cyclesPerUs = NHPTimer::GetCyclesPerSecond() / 1000000; - request->Record.MutableTimestamps()->SetSentByDSProxyUs(GetCycleCountFast() / cyclesPerUs); + request->Record.MutableTimestamps()->SetSentByDSProxyUs(GetCycleCountFast() / cyclesPerUs); TLogoBlobID id = GetBlobId(request); TVDiskID vDiskId = VDiskIDFromVDiskID(request->Record.GetVDiskID()); LWTRACK(DSProxyPutVPutIsSent, request->Orbit, Info->GetFailDomainOrderNumber(vDiskId), diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.cpp b/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.cpp index eb6d8394f0..ffbaf204bc 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.cpp +++ b/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.cpp @@ -18,7 +18,7 @@ void TBlobState::TState::AddResponseData(ui32 fullSize, ui32 shift, TString &dat void TBlobState::TState::AddPartToPut(TString &data) { Y_VERIFY(data.size()); Data.SetMonolith(data); - Here.Assign(0, data.size()); + Here.Assign(0, data.size()); } @@ -60,7 +60,7 @@ void TBlobState::MarkBlobReadyToPut(ui8 blobIdx) { } bool TBlobState::Restore(const TBlobStorageGroupInfo &info) { - TIntervalVec<i32> fullBlobInterval(0, Id.BlobSize()); + TIntervalVec<i32> fullBlobInterval(0, Id.BlobSize()); if (fullBlobInterval.IsSubsetOf(Whole.Here)) { return true; } @@ -69,7 +69,7 @@ bool TBlobState::Restore(const TBlobStorageGroupInfo &info) { ui32 partsPresent = 0; for (ui32 i = 0; i < parts; ++i) { if (const ui32 partSize = info.Type.PartSize(TLogoBlobID(Id, i + 1))) { - if (TIntervalVec<i32>(0, partSize).IsSubsetOf(Parts[i].Here)) { + if (TIntervalVec<i32>(0, partSize).IsSubsetOf(Parts[i].Here)) { ++partsPresent; } } @@ -82,7 +82,7 @@ bool TBlobState::Restore(const TBlobStorageGroupInfo &info) { partSet.Parts.resize(parts); for (ui32 i = 0; i < parts; ++i) { if (const ui32 partSize = info.Type.PartSize(TLogoBlobID(Id, i + 1))) { - if (TIntervalVec<i32>(0, partSize).IsSubsetOf(Parts[i].Here)) { + if (TIntervalVec<i32>(0, partSize).IsSubsetOf(Parts[i].Here)) { partSet.PartsMask |= (1 << i); TString tmp = TString::Uninitialized(partSize); Parts[i].Data.Read(0, const_cast<char*>(tmp.data()), partSize); @@ -308,16 +308,16 @@ TString TBlobState::TDiskPart::ToString() const { TString TBlobState::TState::ToString() const { TStringStream str; str << "{Data# " << Data.Print(); - str << " Here# " << Here.ToString(); - str << "}"; - return str.Str(); -} - -TString TBlobState::TWholeState::ToString() const { - TStringStream str; - str << "{Data# " << Data.Print(); - str << " Here# " << Here.ToString(); - str << " Needed# " << Needed.ToString(); + str << " Here# " << Here.ToString(); + str << "}"; + return str.Str(); +} + +TString TBlobState::TWholeState::ToString() const { + TStringStream str; + str << "{Data# " << Data.Print(); + str << " Here# " << Here.ToString(); + str << " Needed# " << Needed.ToString(); str << " NotHere# " << NotHere.ToString(); str << "}"; return str.Str(); @@ -331,10 +331,10 @@ TGroupDiskRequests::TGroupDiskRequests(ui32 disks) { DiskRequestsForOrderNumber.resize(disks); } -void TGroupDiskRequests::AddGet(const ui32 diskOrderNumber, const TLogoBlobID &id, const TIntervalSet<i32> &intervalSet) { +void TGroupDiskRequests::AddGet(const ui32 diskOrderNumber, const TLogoBlobID &id, const TIntervalSet<i32> &intervalSet) { Y_VERIFY(diskOrderNumber < DiskRequestsForOrderNumber.size()); auto &requestsToSend = DiskRequestsForOrderNumber[diskOrderNumber].GetsToSend; - for (auto pair: intervalSet) { + for (auto pair: intervalSet) { requestsToSend.emplace_back(id, pair.first, pair.second - pair.first); } } diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h b/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h index fe926648a8..96908f57a0 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h @@ -48,19 +48,19 @@ struct TBlobState { }; struct TState { TFragmentedBuffer Data; - TIntervalSet<i32> Here; // Present in the Data buffer + TIntervalSet<i32> Here; // Present in the Data buffer void AddResponseData(ui32 fullSize, ui32 shift, TString &data); void AddPartToPut(TString &data); TString ToString() const; }; - struct TWholeState : TState { - TIntervalSet<i32> Needed; // Requested by the external user - TIntervalSet<i32> NotHere; // Requested by the external user, but not present in the Data buffer yet - TString ToString() const; - }; + struct TWholeState : TState { + TIntervalSet<i32> Needed; // Requested by the external user + TIntervalSet<i32> NotHere; // Requested by the external user, but not present in the Data buffer yet + TString ToString() const; + }; struct TDiskPart { - TIntervalSet<i32> Requested; + TIntervalSet<i32> Requested; ESituation Situation = ESituation::Unknown; TString ToString() const; }; @@ -72,7 +72,7 @@ struct TBlobState { }; TLogoBlobID Id; - TWholeState Whole; + TWholeState Whole; ESituation WholeSituation = ESituation::Unknown; // TODO(cthulhu): Use a specially tailored enum here TStackVec<TState, TypicalPartsInBlob> Parts; TStackVec<TDisk, TypicalDisksInSubring> Disks; @@ -139,7 +139,7 @@ struct TDiskPutRequest { struct TDiskRequests { TDeque<TDiskGetRequest> GetsToSend; - TStackVec<TDiskPutRequest, TypicalPartsInBlob> PutsToSend; + TStackVec<TDiskPutRequest, TypicalPartsInBlob> PutsToSend; ui32 FirstUnsentRequestIdx = 0; ui32 FirstUnsentPutIdx = 0; }; @@ -148,7 +148,7 @@ struct TGroupDiskRequests { TStackVec<TDiskRequests, TypicalDisksInGroup> DiskRequestsForOrderNumber; TGroupDiskRequests(ui32 disks); - void AddGet(const ui32 diskOrderNumber, const TLogoBlobID &id, const TIntervalSet<i32> &intervalSet); + void AddGet(const ui32 diskOrderNumber, const TLogoBlobID &id, const TIntervalSet<i32> &intervalSet); void AddGet(const ui32 diskOrderNumber, const TLogoBlobID &id, const ui32 shift, const ui32 size); void AddPut(const ui32 diskOrderNumber, const TLogoBlobID &id, TString buffer, TDiskPutRequest::EPutReason putReason, bool isHandoff, ui8 blobIdx = 0); diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_discover.cpp b/ydb/core/blobstorage/dsproxy/dsproxy_discover.cpp index 2605a19a2e..0255d1ccb3 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_discover.cpp +++ b/ydb/core/blobstorage/dsproxy/dsproxy_discover.cpp @@ -300,7 +300,7 @@ class TBlobStorageGroupDiscoverRequest : public TBlobStorageGroupRequestActor<TB Mon->CountDiscoverResponseTime(duration); const bool success = result->Status == NKikimrProto::OK; WILSON_TRACE_FROM_ACTOR(*TlsActivationContext, *this, &TraceId, EvDiscoverResultSent); - LWPROBE(DSProxyRequestDuration, TEvBlobStorage::EvDiscover, 0, duration.SecondsFloat() * 1000.0, + LWPROBE(DSProxyRequestDuration, TEvBlobStorage::EvDiscover, 0, duration.SecondsFloat() * 1000.0, TabletId, Info->GroupID, TLogoBlobID::MaxChannel, "", success); SendResponseAndDie(std::move(result)); } diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_discover_m3dc.cpp b/ydb/core/blobstorage/dsproxy/dsproxy_discover_m3dc.cpp index a4e48dba76..c2dfa36444 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_discover_m3dc.cpp +++ b/ydb/core/blobstorage/dsproxy/dsproxy_discover_m3dc.cpp @@ -655,7 +655,7 @@ public: Y_VERIFY(!Responded); const TDuration duration = TActivationContext::Now() - StartTime; - LWPROBE(DSProxyRequestDuration, TEvBlobStorage::EvDiscover, 0, duration.SecondsFloat() * 1000.0, + LWPROBE(DSProxyRequestDuration, TEvBlobStorage::EvDiscover, 0, duration.SecondsFloat() * 1000.0, TabletId, Info->GroupID, TLogoBlobID::MaxChannel, "", true); SendResponseAndDie(std::move(response)); Responded = true; @@ -668,7 +668,7 @@ public: Y_VERIFY(!Responded); Y_VERIFY(status != NKikimrProto::OK); const TDuration duration = TActivationContext::Now() - StartTime; - LWPROBE(DSProxyRequestDuration, TEvBlobStorage::EvDiscover, 0, duration.SecondsFloat() * 1000.0, + LWPROBE(DSProxyRequestDuration, TEvBlobStorage::EvDiscover, 0, duration.SecondsFloat() * 1000.0, TabletId, Info->GroupID, TLogoBlobID::MaxChannel, "", false); std::unique_ptr<TEvBlobStorage::TEvDiscoverResult> response(new TEvBlobStorage::TEvDiscoverResult( status, MinGeneration, 0U)); diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_get.cpp b/ydb/core/blobstorage/dsproxy/dsproxy_get.cpp index 9b08b41861..98e67315ff 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_get.cpp +++ b/ydb/core/blobstorage/dsproxy/dsproxy_get.cpp @@ -186,7 +186,7 @@ class TBlobStorageGroupGetRequest : public TBlobStorageGroupRequestActor<TBlobSt CountEvent(*ev->Get()); const ui64 cyclesPerUs = NHPTimer::GetCyclesPerSecond() / 1000000; - ev->Get()->Record.MutableTimestamps()->SetReceivedByDSProxyUs(GetCycleCountFast() / cyclesPerUs); + ev->Get()->Record.MutableTimestamps()->SetReceivedByDSProxyUs(GetCycleCountFast() / cyclesPerUs); const NKikimrBlobStorage::TEvVGetResult &record = ev->Get()->Record; Y_VERIFY(record.HasStatus()); @@ -211,10 +211,10 @@ class TBlobStorageGroupGetRequest : public TBlobStorageGroupRequestActor<TBlobSt LWPROBE(DSProxyVDiskRequestDuration, TEvBlobStorage::EvVGet, totalSize, tabletId, vdisk.GroupID, channel, Info->GetFailDomainOrderNumber(shortId), - GetStartTime(record.GetTimestamps()), - GetTotalTimeMs(record.GetTimestamps()), - GetVDiskTimeMs(record.GetTimestamps()), - GetTotalTimeMs(record.GetTimestamps()) - GetVDiskTimeMs(record.GetTimestamps()), + GetStartTime(record.GetTimestamps()), + GetTotalTimeMs(record.GetTimestamps()), + GetVDiskTimeMs(record.GetTimestamps()), + GetTotalTimeMs(record.GetTimestamps()) - GetVDiskTimeMs(record.GetTimestamps()), NKikimrBlobStorage::EGetHandleClass_Name(GetImpl.GetHandleClass()), NKikimrProto::EReplyStatus_Name(record.GetStatus())); Y_VERIFY(record.HasCookie()); @@ -354,7 +354,7 @@ class TBlobStorageGroupGetRequest : public TBlobStorageGroupRequestActor<TBlobSt WILSON_TRACE_FROM_ACTOR(*TlsActivationContext, *this, &TraceId, EvVPutResultReceived, MergedNode = std::move(ev->TraceId)); const ui64 cyclesPerUs = NHPTimer::GetCyclesPerSecond() / 1000000; - ev->Get()->Record.MutableTimestamps()->SetReceivedByDSProxyUs(GetCycleCountFast() / cyclesPerUs); + ev->Get()->Record.MutableTimestamps()->SetReceivedByDSProxyUs(GetCycleCountFast() / cyclesPerUs); const auto &record = ev->Get()->Record; const TVDiskID vDiskId = VDiskIDFromVDiskID(record.GetVDiskID()); TVDiskIdShort shortId(vDiskId); @@ -368,10 +368,10 @@ class TBlobStorageGroupGetRequest : public TBlobStorageGroupRequestActor<TBlobSt ui64 sumBlobSize = SumBlobSize(ev); LWPROBE(DSProxyVDiskRequestDuration, TEvBlobStorage::EvVPut, sumBlobSize, blob.TabletID(), Info->GroupID, blob.Channel(), Info->GetFailDomainOrderNumber(shortId), - GetStartTime(record.GetTimestamps()), - GetTotalTimeMs(record.GetTimestamps()), - GetVDiskTimeMs(record.GetTimestamps()), - GetTotalTimeMs(record.GetTimestamps()) - GetVDiskTimeMs(record.GetTimestamps()), + GetStartTime(record.GetTimestamps()), + GetTotalTimeMs(record.GetTimestamps()), + GetVDiskTimeMs(record.GetTimestamps()), + GetTotalTimeMs(record.GetTimestamps()) - GetVDiskTimeMs(record.GetTimestamps()), NKikimrBlobStorage::EPutHandleClass_Name(GetImpl.GetPutHandleClass()), NKikimrProto::EReplyStatus_Name(status)); @@ -471,7 +471,7 @@ class TBlobStorageGroupGetRequest : public TBlobStorageGroupRequestActor<TBlobSt RootCauseTrack.RenderTrack(Orbit); LWTRACK(DSProxyGetReply, Orbit); evResult->Orbit = std::move(Orbit); - LWPROBE(DSProxyRequestDuration, TEvBlobStorage::EvGet, requestSize, duration.SecondsFloat() * 1000.0, tabletId, + LWPROBE(DSProxyRequestDuration, TEvBlobStorage::EvGet, requestSize, duration.SecondsFloat() * 1000.0, tabletId, evResult->GroupId, channel, NKikimrBlobStorage::EGetHandleClass_Name(GetImpl.GetHandleClass()), success); return SendResponseAndDie(std::unique_ptr<TEvBlobStorage::TEvGetResult>(evResult.Release())); diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_monactor.cpp b/ydb/core/blobstorage/dsproxy/dsproxy_monactor.cpp index 96b492c415..dc0044dfe4 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_monactor.cpp +++ b/ydb/core/blobstorage/dsproxy/dsproxy_monactor.cpp @@ -83,22 +83,22 @@ public: UPDATE_WILSON(Discover) #define COMPONENT(NAME) \ - TABLER() { \ - TABLED() { \ + TABLER() { \ + TABLED() { \ str << #NAME; \ - } \ - TABLED() { \ + } \ + TABLED() { \ TString value = ToString(Mon->NAME ## SamplePPM); \ str << "<input name=\"" #NAME "SamplingRate\" type=\"number\"" \ " value=\"" << value << "\" min=\"0\" max=\"1000000\"/>ppm"; \ - } \ - } + } \ + } TStringStream str; - HTML(str) { - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { + HTML(str) { + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { str << "Group content"; } DIV_CLASS("panel-body") { @@ -162,28 +162,28 @@ public: DIV_CLASS("panel panel-info") { DIV_CLASS("panel-heading") { str << "Blob query service"; - } - DIV_CLASS("panel-body") { - FORM_CLASS("form-horizontal") { - DIV_CLASS("control-group") { - LABEL_CLASS_FOR("control-label", "inputBlob") { str << "Blob ID"; } - DIV_CLASS("controls") { + } + DIV_CLASS("panel-body") { + FORM_CLASS("form-horizontal") { + DIV_CLASS("control-group") { + LABEL_CLASS_FOR("control-label", "inputBlob") { str << "Blob ID"; } + DIV_CLASS("controls") { str << "<input id=\"inputBlob\" name=\"blob\" type=\"text\"/>"; - } - } + } + } str << "<input type=\"hidden\" name=\"groupId\" value=\"" << GroupId << "\">"; str << "<input type=\"hidden\" name=\"debugInfo\" value=\"" << 1 << "\">"; - DIV_CLASS("control-group") { - DIV_CLASS("controls") { + DIV_CLASS("control-group") { + DIV_CLASS("controls") { str << "<button type=\"submit\" formaction=\"/get_blob\" class=\"btn btn-default\">Query</button>"; - } - } - } - } - } - - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { + } + } + } + } + } + + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { str << "Blob range index query service"; } DIV_CLASS("panel-body") { @@ -219,42 +219,42 @@ public: DIV_CLASS("panel panel-info") { DIV_CLASS("panel-heading") { str << "Wilson tuning"; - } - DIV_CLASS("panel-body") { - FORM_CLASS("form-vertical") { - DIV() { + } + DIV_CLASS("panel-body") { + FORM_CLASS("form-vertical") { + DIV() { str << "All sampling rates are provided as integer in range [0, 1000000] measured in ppm " " where 0 means disabled sampling for this kind of request"; - } - DIV() { + } + DIV() { str << "<b>NOTE</b> do not forget to enable WILSON logger at DEBUG level with 100% sampling" " at all nodes of the cluster"; - } - TABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() { + } + TABLE_CLASS ("table table-condensed") { + TABLEHEAD() { + TABLER() { + TABLEH() { str << "Query type"; - } - TABLEH() { + } + TABLEH() { str << "Sampling rate"; - } - } - } - TABLEBODY() { + } + } + } + TABLEBODY() { COMPONENT(Put) COMPONENT(Get) COMPONENT(Discover) - } - } - DIV_CLASS("control-group") { - DIV_CLASS("controls") { + } + } + DIV_CLASS("control-group") { + DIV_CLASS("controls") { str << "<button type=\"submit\" class=\"btn btn-default\">Commit</button>"; - } - } - } - } - } + } + } + } + } + } DIV_CLASS("panel panel-info") { DIV_CLASS("panel-heading") { @@ -311,7 +311,7 @@ public: } } } - } + } Mon->TimeStats.Render(str); diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_put.cpp b/ydb/core/blobstorage/dsproxy/dsproxy_put.cpp index d9e0e2b320..b62ded9586 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_put.cpp +++ b/ydb/core/blobstorage/dsproxy/dsproxy_put.cpp @@ -18,9 +18,9 @@ namespace NKikimr { struct TEvResume : public TEventLocal<TEvResume, TEvBlobStorage::EvResume> { double WilsonSec; double AllocateSec; - double WaitSec; - double SplitSec; - size_t Count; + double WaitSec; + double SplitSec; + size_t Count; TBatchedVec<TDataPartSet> PartSets; }; @@ -147,7 +147,7 @@ class TBlobStorageGroupPutRequest : public TBlobStorageGroupRequestActor<TBlobSt ResponsesReceived++; const ui64 cyclesPerUs = NHPTimer::GetCyclesPerSecond() / 1000000; - ev->Get()->Record.MutableTimestamps()->SetReceivedByDSProxyUs(GetCycleCountFast() / cyclesPerUs); + ev->Get()->Record.MutableTimestamps()->SetReceivedByDSProxyUs(GetCycleCountFast() / cyclesPerUs); const NKikimrBlobStorage::TEvVPutResult &record = ev->Get()->Record; const TLogoBlobID blob = LogoBlobIDFromLogoBlobID(record.GetBlobID()); const TLogoBlobID origBlobId = TLogoBlobID(blob, 0); @@ -175,10 +175,10 @@ class TBlobStorageGroupPutRequest : public TBlobStorageGroupRequestActor<TBlobSt LWPROBE(DSProxyVDiskRequestDuration, TEvBlobStorage::EvVPut, blob.BlobSize(), blob.TabletID(), Info->GroupID, blob.Channel(), Info->GetFailDomainOrderNumber(shortId), - GetStartTime(record.GetTimestamps()), - GetTotalTimeMs(record.GetTimestamps()), - GetVDiskTimeMs(record.GetTimestamps()), - GetTotalTimeMs(record.GetTimestamps()) - GetVDiskTimeMs(record.GetTimestamps()), + GetStartTime(record.GetTimestamps()), + GetTotalTimeMs(record.GetTimestamps()), + GetVDiskTimeMs(record.GetTimestamps()), + GetTotalTimeMs(record.GetTimestamps()) - GetVDiskTimeMs(record.GetTimestamps()), NKikimrBlobStorage::EPutHandleClass_Name(PutImpl.GetPutHandleClass()), NKikimrProto::EReplyStatus_Name(status)); if (RootCauseTrack.IsOn) { @@ -225,11 +225,11 @@ class TBlobStorageGroupPutRequest : public TBlobStorageGroupRequestActor<TBlobSt ResponsesReceived++; const ui64 cyclesPerUs = NHPTimer::GetCyclesPerSecond() / 1000000; - ev->Get()->Record.MutableTimestamps()->SetReceivedByDSProxyUs(GetCycleCountFast() / cyclesPerUs); + ev->Get()->Record.MutableTimestamps()->SetReceivedByDSProxyUs(GetCycleCountFast() / cyclesPerUs); const NKikimrBlobStorage::TEvVMultiPutResult &record = ev->Get()->Record; if (TimeStatsEnabled && record.GetMsgQoS().HasExecTimeStats()) { - TimeStats.ApplyPut(RequestBytes, record.GetMsgQoS().GetExecTimeStats()); + TimeStats.ApplyPut(RequestBytes, record.GetMsgQoS().GetExecTimeStats()); } Y_VERIFY(record.HasVDiskID()); @@ -259,25 +259,25 @@ class TBlobStorageGroupPutRequest : public TBlobStorageGroupRequestActor<TBlobSt } WaitingVDiskResponseCount[vdisk]--; - // Trace put request duration - if (LWPROBE_ENABLED(DSProxyVDiskRequestDuration)) { - for (auto &item : record.GetItems()) { - TLogoBlobID blobId = LogoBlobIDFromLogoBlobID(item.GetBlobID()); - NKikimrProto::EReplyStatus itemStatus = item.GetStatus(); - LWPROBE(DSProxyVDiskRequestDuration, TEvBlobStorage::EvVMultiPut, blobId.BlobSize(), blobId.TabletID(), - Info->GroupID, blobId.Channel(), Info->GetFailDomainOrderNumber(shortId), - GetStartTime(record.GetTimestamps()), - GetTotalTimeMs(record.GetTimestamps()), - GetVDiskTimeMs(record.GetTimestamps()), - GetTotalTimeMs(record.GetTimestamps()) - GetVDiskTimeMs(record.GetTimestamps()), - NKikimrBlobStorage::EPutHandleClass_Name(PutImpl.GetPutHandleClass()), - NKikimrProto::EReplyStatus_Name(itemStatus)); - } - } - - // Handle put results + // Trace put request duration + if (LWPROBE_ENABLED(DSProxyVDiskRequestDuration)) { + for (auto &item : record.GetItems()) { + TLogoBlobID blobId = LogoBlobIDFromLogoBlobID(item.GetBlobID()); + NKikimrProto::EReplyStatus itemStatus = item.GetStatus(); + LWPROBE(DSProxyVDiskRequestDuration, TEvBlobStorage::EvVMultiPut, blobId.BlobSize(), blobId.TabletID(), + Info->GroupID, blobId.Channel(), Info->GetFailDomainOrderNumber(shortId), + GetStartTime(record.GetTimestamps()), + GetTotalTimeMs(record.GetTimestamps()), + GetVDiskTimeMs(record.GetTimestamps()), + GetTotalTimeMs(record.GetTimestamps()) - GetVDiskTimeMs(record.GetTimestamps()), + NKikimrBlobStorage::EPutHandleClass_Name(PutImpl.GetPutHandleClass()), + NKikimrProto::EReplyStatus_Name(itemStatus)); + } + } + + // Handle put results bool isCauseRegistered = !RootCauseTrack.IsOn; - TPutImpl::TPutResultVec putResults; + TPutImpl::TPutResultVec putResults; for (auto &item : record.GetItems()) { if (!isCauseRegistered) { isCauseRegistered = RootCauseTrack.OnReply(cookie.GetCauseIdx(), @@ -288,7 +288,7 @@ class TBlobStorageGroupPutRequest : public TBlobStorageGroupRequestActor<TBlobSt Y_VERIFY(item.HasStatus()); Y_VERIFY(item.HasBlobID()); Y_VERIFY(item.HasCookie()); - ui64 blobIdx = TBlobCookie(item.GetCookie()).GetBlobIdx(); + ui64 blobIdx = TBlobCookie(item.GetCookie()).GetBlobIdx(); NKikimrProto::EReplyStatus itemStatus = item.GetStatus(); TLogoBlobID blobId = LogoBlobIDFromLogoBlobID(item.GetBlobID()); Y_VERIFY(itemStatus != NKikimrProto::RACE); // we should get RACE for the whole request and handle it in CheckForTermErrors @@ -370,9 +370,9 @@ class TBlobStorageGroupPutRequest : public TBlobStorageGroupRequestActor<TBlobSt ++*Mon->HandoffPartsSent[Min(Mon->HandoffPartsSent.size() - 1, (size_t)PutImpl.GetHandoffPartsSent())]; ReportedBytes = 0; const bool success = (status == NKikimrProto::OK); - LWPROBE(DSProxyRequestDuration, TEvBlobStorage::EvPut, + LWPROBE(DSProxyRequestDuration, TEvBlobStorage::EvPut, blobId.BlobSize(), - duration.SecondsFloat() * 1000.0, + duration.SecondsFloat() * 1000.0, blobId.TabletID(), Info->GroupID, blobId.Channel(), NKikimrBlobStorage::EPutHandleClass_Name(HandleClass), success); ResponsesSent++; @@ -474,7 +474,7 @@ public: Tactic, NKikimrBlobStorage::EPutHandleClass_Name(HandleClass)); ReportBytes(ItemsInfo[0].Buffer.capacity() + sizeof(*this)); - RequestBytes = ev->Buffer.size(); + RequestBytes = ev->Buffer.size(); RequestHandleClass = HandleClassToHandleClass(HandleClass); MaxSaneRequests = info->Type.TotalPartCount() * (1ull + info->Type.Handoff()) * 2; } @@ -518,14 +518,14 @@ public: if (ev->Get()->Orbit.HasShuttles()) { RootCauseTrack.IsOn = true; } - ItemsInfo.emplace_back( + ItemsInfo.emplace_back( ev->Get()->Id, ev->Get()->Buffer, ev->Sender, ev->Cookie, std::move(ev->TraceId), std::move(ev->Get()->Orbit) - ); + ); LWPROBE(DSProxyBlobPutTactics, ItemsInfo.back().BlobId.TabletID(), Info->GroupID, ItemsInfo.back().BlobId.ToString(), Tactic, NKikimrBlobStorage::EPutHandleClass_Name(HandleClass)); } @@ -557,7 +557,7 @@ public: << " RestartCounter# " << RestartCounter); for (ui64 blobIdx = 0; blobIdx < ItemsInfo.size(); ++blobIdx) { - LWTRACK(DSProxyPutBootstrapStart, ItemsInfo[blobIdx].Orbit); + LWTRACK(DSProxyPutBootstrapStart, ItemsInfo[blobIdx].Orbit); } Become(&TThis::StateWait); @@ -565,7 +565,7 @@ public: Timer.Reset(); // TODO: how correct rewrite this? - WILSON_TRACE_FROM_ACTOR(*TlsActivationContext, *this, &TraceId, EvPutReceived, Size = RequestBytes, + WILSON_TRACE_FROM_ACTOR(*TlsActivationContext, *this, &TraceId, EvPutReceived, Size = RequestBytes, LogoBlobId = ItemsInfo[0].BlobId); double wilsonSec = Timer.PassedReset(); @@ -579,7 +579,7 @@ public: TLogoBlobID blobId = ItemsInfo[idx].BlobId; const ui64 partSize = Info->Type.PartSize(blobId); - ui64 bufferSize = ItemsInfo[idx].BufferSize; + ui64 bufferSize = ItemsInfo[idx].BufferSize; char *data = ItemsInfo[idx].Buffer.Detach(); Encrypt(data, data, 0, bufferSize, blobId, *Info); @@ -597,11 +597,11 @@ public: resume->WilsonSec = wilsonSec; resume->AllocateSec = allocateSec; - resume->WaitSec = 0.0; - resume->SplitSec = 0.0; - resume->Count = 0; - if (RequestBytes < BufferSizeThreshold) { - ResumeBootstrap(resume); + resume->WaitSec = 0.0; + resume->SplitSec = 0.0; + resume->Count = 0; + if (RequestBytes < BufferSizeThreshold) { + ResumeBootstrap(resume); } else { Send(SelfId(), resume.Release()); for (ui64 blobIdx = 0; blobIdx < ItemsInfo.size(); ++blobIdx) { @@ -614,13 +614,13 @@ public: } void Handle(TEvResume::TPtr &ev) { - if (ev->Get()->Count == 0) { - // Record only the first resume to keep tracks structure simple - for (ui64 blobIdx = 0; blobIdx < ItemsInfo.size(); ++blobIdx) { - LWTRACK(DSProxyPutResumeBootstrap, ItemsInfo[blobIdx].Orbit); - } + if (ev->Get()->Count == 0) { + // Record only the first resume to keep tracks structure simple + for (ui64 blobIdx = 0; blobIdx < ItemsInfo.size(); ++blobIdx) { + LWTRACK(DSProxyPutResumeBootstrap, ItemsInfo[blobIdx].Orbit); + } } - ResumeBootstrap(ev->Release()); + ResumeBootstrap(ev->Release()); SanityCheck(); // May Die } @@ -658,51 +658,51 @@ public: } } - void ResumeBootstrap(TAutoPtr<TEvResume> resume) { + void ResumeBootstrap(TAutoPtr<TEvResume> resume) { double waitSec = Timer.PassedReset(); - resume->WaitSec += waitSec; + resume->WaitSec += waitSec; - Y_VERIFY(ItemsInfo.size() == resume->PartSets.size()); - bool splitDone = true; + Y_VERIFY(ItemsInfo.size() == resume->PartSets.size()); + bool splitDone = true; for (ui64 idx = 0; idx < ItemsInfo.size(); ++idx) { - TDataPartSet &partSet = resume->PartSets[idx]; + TDataPartSet &partSet = resume->PartSets[idx]; TString &buffer = ItemsInfo[idx].Buffer; TLogoBlobID blobId = ItemsInfo[idx].BlobId; - Info->Type.IncrementalSplitData((TErasureType::ECrcMode)blobId.CrcMode(), buffer, partSet); - if (partSet.IsSplitDone()) { - ReportBytes(partSet.MemoryConsumed - ItemsInfo[idx].BufferSize); - } else { - splitDone = false; - } + Info->Type.IncrementalSplitData((TErasureType::ECrcMode)blobId.CrcMode(), buffer, partSet); + if (partSet.IsSplitDone()) { + ReportBytes(partSet.MemoryConsumed - ItemsInfo[idx].BufferSize); + } else { + splitDone = false; + } } double splitSec = Timer.PassedReset(); - resume->SplitSec += splitSec; - resume->Count++; - LWPROBE(ProxyPutBootstrapPart, RequestBytes, waitSec * 1000.0, splitSec * 1000.0, resume->Count, resume->SplitSec * 1000.0); - - if (splitDone) { - for (ui64 blobIdx = 0; blobIdx < ItemsInfo.size(); ++blobIdx) { - LWTRACK(DSProxyPutBootstrapDone, ItemsInfo[blobIdx].Orbit, - RequestBytes, resume->WilsonSec * 1000.0, resume->AllocateSec * 1000.0, - resume->WaitSec * 1000.0, resume->SplitSec * 1000.0, resume->Count, blobIdx); - } - if (IsMultiPutMode) { + resume->SplitSec += splitSec; + resume->Count++; + LWPROBE(ProxyPutBootstrapPart, RequestBytes, waitSec * 1000.0, splitSec * 1000.0, resume->Count, resume->SplitSec * 1000.0); + + if (splitDone) { + for (ui64 blobIdx = 0; blobIdx < ItemsInfo.size(); ++blobIdx) { + LWTRACK(DSProxyPutBootstrapDone, ItemsInfo[blobIdx].Orbit, + RequestBytes, resume->WilsonSec * 1000.0, resume->AllocateSec * 1000.0, + resume->WaitSec * 1000.0, resume->SplitSec * 1000.0, resume->Count, blobIdx); + } + if (IsMultiPutMode) { TDeque<std::unique_ptr<TEvBlobStorage::TEvVMultiPut>> vMultiPuts; - PutImpl.GenerateInitialRequests(LogCtx, resume->PartSets, vMultiPuts); - UpdatePengingVDiskResponseCount<TEvBlobStorage::TEvVMultiPut, TVMultiPutCookie>(vMultiPuts); - RequestsSent += vMultiPuts.size(); - CountPuts(vMultiPuts); - SendToQueues(vMultiPuts, TimeStatsEnabled); - } else { + PutImpl.GenerateInitialRequests(LogCtx, resume->PartSets, vMultiPuts); + UpdatePengingVDiskResponseCount<TEvBlobStorage::TEvVMultiPut, TVMultiPutCookie>(vMultiPuts); + RequestsSent += vMultiPuts.size(); + CountPuts(vMultiPuts); + SendToQueues(vMultiPuts, TimeStatsEnabled); + } else { TDeque<std::unique_ptr<TEvBlobStorage::TEvVPut>> vPuts; - PutImpl.GenerateInitialRequests(LogCtx, resume->PartSets, vPuts); - UpdatePengingVDiskResponseCount<TEvBlobStorage::TEvVPut, TBlobCookie>(vPuts); - RequestsSent += vPuts.size(); - CountPuts(vPuts); - SendToQueues(vPuts, TimeStatsEnabled); - } + PutImpl.GenerateInitialRequests(LogCtx, resume->PartSets, vPuts); + UpdatePengingVDiskResponseCount<TEvBlobStorage::TEvVPut, TBlobCookie>(vPuts); + RequestsSent += vPuts.size(); + CountPuts(vPuts); + SendToQueues(vPuts, TimeStatsEnabled); + } } else { - Send(SelfId(), resume.Release()); + Send(SelfId(), resume.Release()); } } diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_put_impl.cpp b/ydb/core/blobstorage/dsproxy/dsproxy_put_impl.cpp index 70b774636c..e2f9fd8892 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_put_impl.cpp +++ b/ydb/core/blobstorage/dsproxy/dsproxy_put_impl.cpp @@ -69,7 +69,7 @@ void TPutImpl::PrepareReply(NKikimrProto::EReplyStatus status, TLogContext &logC outPutResults.emplace_back(idx, new TEvBlobStorage::TEvPutResult(status, BlobIds[idx], StatusFlags, Info->GroupID, ApproximateFreeSpaceShare)); outPutResults.back().second->ErrorReason = errorReason; - + NLog::EPriority priority = GetPriorityForReply(Info->PutErrorMuteChecker, status); A_LOG_LOG_SX(logCtx, true, priority, "BPP38", "PrepareReply Result# " << outPutResults.back().second->Print(false)); diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_base.cpp b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_base.cpp index c73c20712e..566c819b28 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_base.cpp +++ b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_base.cpp @@ -184,7 +184,7 @@ std::optional<EStrategyOutcome> TStrategyBase::ProcessPessimistic(const TBlobSto } void TStrategyBase::AddGetRequest(TLogContext &logCtx, TGroupDiskRequests &groupDiskRequests, TLogoBlobID &fullId, - ui32 partIdx, TBlobState::TDisk &disk, TIntervalSet<i32> &intervalSet, const char *logMarker) { + ui32 partIdx, TBlobState::TDisk &disk, TIntervalSet<i32> &intervalSet, const char *logMarker) { TLogoBlobID id(fullId, partIdx + 1); R_LOG_DEBUG_SX(logCtx, logMarker, "AddGet disk# " << disk.OrderNumber << " Id# " << id.ToString() @@ -287,8 +287,8 @@ void TStrategyBase::PreparePutsForPartPlacement(TLogContext &logCtx, TBlobState if (!isPartsAvailable) { // Prepare new put request set - TIntervalVec<i32> fullInterval(0, state.Id.BlobSize()); - Y_VERIFY(fullInterval.IsSubsetOf(state.Whole.Here), + TIntervalVec<i32> fullInterval(0, state.Id.BlobSize()); + Y_VERIFY(fullInterval.IsSubsetOf(state.Whole.Here), "Can't put unrestored blob! Unexpected blob state# %s", state.ToString().c_str()); TString wholeBuffer = TString::Uninitialized(state.Id.BlobSize()); diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_base.h b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_base.h index ca005dc936..26a53c71f5 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_base.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_base.h @@ -32,7 +32,7 @@ protected: std::optional<EStrategyOutcome> ProcessPessimistic(const TBlobStorageGroupInfo &info, TBlobStorageGroupInfo::EBlobState pessimisticState, bool doVerify, TBlobState &state); void AddGetRequest(TLogContext &logCtx, TGroupDiskRequests &groupDiskRequests, TLogoBlobID &fullId, ui32 partIdx, - TBlobState::TDisk &disk, TIntervalSet<i32> &intervalSet, const char *logMarker); + TBlobState::TDisk &disk, TIntervalSet<i32> &intervalSet, const char *logMarker); bool VerifyTheWholeSituation(TBlobState &state); void PreparePartLayout(const TBlobState &state, const TBlobStorageGroupInfo &info, TBlobStorageGroupType::TPartLayout *layout, ui32 slowDiskIdx); diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_bold.h b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_bold.h index 0ea411ef72..2e49f7a867 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_bold.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_bold.h @@ -57,7 +57,7 @@ public: TBlobState::ESituation partSituation = disk.DiskParts[partIdx].Situation; if (partSituation == TBlobState::ESituation::Unknown || partSituation == TBlobState::ESituation::Present) { - TIntervalSet<i32> fullPartInterval(0, partSize); + TIntervalSet<i32> fullPartInterval(0, partSize); fullPartInterval.Subtract(state.Parts[partIdx].Here); fullPartInterval.Subtract(disk.DiskParts[partIdx].Requested); if (!fullPartInterval.IsEmpty()) { diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_basic.h b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_basic.h index c6476c941f..4b165fa513 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_basic.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_basic.h @@ -28,7 +28,7 @@ namespace NKikimr { switch (diskPart.Situation) { case TBlobState::ESituation::Unknown: { // get the request -- all the needed parts except already got and already requested - TIntervalSet<i32> request(state.Whole.Needed); + TIntervalSet<i32> request(state.Whole.Needed); request.Subtract(state.Whole.Here); // remove parts that were already requested, but not yet answered request.Subtract(diskPart.Requested); @@ -73,10 +73,10 @@ namespace NKikimr { // check if we can obtain some _new_ data from the part if (!part.Here.IsSubsetOf(state.Whole.Here)) { // scan through all the intervals - for (const auto& range : part.Here) { + for (const auto& range : part.Here) { ui64 begin = range.first; const ui64 end = range.second; - TIntervalVec<i32> interval(begin, end); + TIntervalVec<i32> interval(begin, end); // check if this interval contains some data which is not in state.Whole.Here if (!interval.IsSubsetOf(state.Whole.Here)) { char buffer[4096]; diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_restore.h b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_restore.h index 161a1b3f9f..906e29ca40 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_restore.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_restore.h @@ -71,7 +71,7 @@ namespace NKikimr { private: static void PrepareGets(TLogContext& logCtx, TBlobState& state, TGroupDiskRequests& groupDiskRequests) { - const TIntervalVec<i32> needed(0, state.Id.BlobSize()); // we need to query this interval + const TIntervalVec<i32> needed(0, state.Id.BlobSize()); // we need to query this interval for (ui32 diskIdx = 0; diskIdx < state.Disks.size(); ++diskIdx) { TBlobState::TDisk& disk = state.Disks[diskIdx]; const ui32 partIdx = diskIdx % NumRings; @@ -112,10 +112,10 @@ namespace NKikimr { static void CreateOutputBlob(TBlobState& state) { for (const TBlobState::TState& part : state.Parts) { // calculate the interval of the part buffer we have to copy into the output buffer - TIntervalSet<i32> dataToAdd(part.Here); + TIntervalSet<i32> dataToAdd(part.Here); dataToAdd.Subtract(state.Whole.Here); state.Whole.Here.Add(dataToAdd); - for (const auto& range : dataToAdd) { + for (const auto& range : dataToAdd) { ui32 begin = range.first; const ui32 end = range.second; char buffer[4096]; diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3of4.h b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3of4.h index 30abbb2687..6aaf39a41a 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3of4.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3of4.h @@ -128,7 +128,7 @@ namespace NKikimr { for (ui32 i = 0; i < totalParts; ++i) { if (const ui32 partSize = info.Type.PartSize(TLogoBlobID(state.Id, i + 1))) { TBlobState::TState& part = state.Parts[i]; - if (const TIntervalSet<i32> pending = part.Here & state.Whole.NotHere) { + if (const TIntervalSet<i32> pending = part.Here & state.Whole.NotHere) { state.Whole.Data.CopyFrom(part.Data, pending); state.Whole.Here |= pending; state.Whole.NotHere -= pending; diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_min_iops_block.h b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_min_iops_block.h index d191f11006..7b6d2f375a 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_min_iops_block.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_min_iops_block.h @@ -9,18 +9,18 @@ class TMinIopsBlockStrategy : public TStrategyBase { public: std::optional<EStrategyOutcome> RestoreWholeFromDataParts(TLogContext& /*logCtx*/, TBlobState &state, const TBlobStorageGroupInfo &info) { - TIntervalSet<i32> missing(state.Whole.NotHere); + TIntervalSet<i32> missing(state.Whole.NotHere); TString tmp; - for (auto [begin, end] : missing) { + for (auto [begin, end] : missing) { TBlockSplitRange range; - info.Type.BlockSplitRange((TErasureType::ECrcMode)state.Id.CrcMode(), state.Id.BlobSize(), begin, - end, &range); + info.Type.BlockSplitRange((TErasureType::ECrcMode)state.Id.CrcMode(), state.Id.BlobSize(), begin, + end, &range); for (ui32 partIdx = range.BeginPartIdx; partIdx < range.EndPartIdx; ++partIdx) { TPartOffsetRange &partRange = range.PartRanges[partIdx]; if (partRange.Begin != partRange.End && partRange.WholeBegin < partRange.WholeEnd) { if (!state.Parts[partIdx].Here.IsEmpty()) { - TIntervalVec<i32> partInterval(partRange.Begin, partRange.End); - if (partInterval.IsSubsetOf(state.Parts[partIdx].Here)) { + TIntervalVec<i32> partInterval(partRange.Begin, partRange.End); + if (partInterval.IsSubsetOf(state.Parts[partIdx].Here)) { i64 sizeToCopy = partRange.End - partRange.Begin; if (tmp.size() < (ui64)sizeToCopy) { tmp = TString::Uninitialized(sizeToCopy); @@ -60,7 +60,7 @@ public: ui32 diskIdx = (niche < 0 ? partIdx : totalPartCount + niche); TBlobState::TDisk &disk = state.Disks[diskIdx]; TBlobState::ESituation partSituation = disk.DiskParts[partIdx].Situation; - TIntervalSet<i32> &requested = disk.DiskParts[partIdx].Requested; + TIntervalSet<i32> &requested = disk.DiskParts[partIdx].Requested; if (partSituation == TBlobState::ESituation::Present) { isMissing = false; } @@ -78,11 +78,11 @@ public: } // get intervals needed to restore the requested full data - TIntervalSet<i32> toRestore; - for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { - auto [begin, end] = *it; + TIntervalSet<i32> toRestore; + for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { + auto [begin, end] = *it; TBlockSplitRange range; - info.Type.BlockSplitRange((TErasureType::ECrcMode)state.Id.CrcMode(), state.Id.BlobSize(), begin, end, &range); + info.Type.BlockSplitRange((TErasureType::ECrcMode)state.Id.CrcMode(), state.Id.BlobSize(), begin, end, &range); for (ui32 partIdx = range.BeginPartIdx; partIdx < range.EndPartIdx; ++partIdx) { TPartOffsetRange &partRange = range.PartRanges[partIdx]; if (partRange.Begin != partRange.End) { @@ -106,11 +106,11 @@ public: const ui32 partSize = info.Type.PartSize(state.Id); // Gather part ranges that need to be restored - TIntervalSet<i32> partIntervals; - for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { - auto [begin, end] = *it; // missing + TIntervalSet<i32> partIntervals; + for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { + auto [begin, end] = *it; // missing TBlockSplitRange range; - info.Type.BlockSplitRange((TErasureType::ECrcMode)state.Id.CrcMode(), state.Id.BlobSize(), begin, end, &range); + info.Type.BlockSplitRange((TErasureType::ECrcMode)state.Id.CrcMode(), state.Id.BlobSize(), begin, end, &range); for (ui32 partIdx = range.BeginPartIdx; partIdx < range.EndPartIdx; ++partIdx) { TPartOffsetRange &partRange = range.PartRanges[partIdx]; if (partRange.Begin != partRange.End) { @@ -132,9 +132,9 @@ public: TDataPartSet partSet; partSet.Parts.resize(totalPartCount); i64 maxSize = 0; - for (auto it = partIntervals.begin(); it != partIntervals.end(); ++it) { - auto [begin, end] = *it; - i64 size = end - begin; + for (auto it = partIntervals.begin(); it != partIntervals.end(); ++it) { + auto [begin, end] = *it; + i64 size = end - begin; maxSize = Max(size, maxSize); } for (ui32 i = 0; i < totalPartCount; ++i) { @@ -143,10 +143,10 @@ public: } partSet.FullDataSize = state.Id.BlobSize(); partSet.IsFragment = true; - for (auto it = partIntervals.begin(); it != partIntervals.end(); ++it) { - auto [alignedBegin, alignedEnd] = *it; - TIntervalVec<i32> needRange(alignedBegin, alignedEnd); - i32 needSize = alignedEnd - alignedBegin; + for (auto it = partIntervals.begin(); it != partIntervals.end(); ++it) { + auto [alignedBegin, alignedEnd] = *it; + TIntervalVec<i32> needRange(alignedBegin, alignedEnd); + i32 needSize = alignedEnd - alignedBegin; if (info.Type.ErasureFamily() == TErasureType::ErasureParityBlock) { partSet.PartsMask = 0; for (ui32 i = 0; i < totalPartCount; ++i) { @@ -164,12 +164,12 @@ public: for (ui32 partIdx = wholeRange.BeginPartIdx; partIdx < wholeRange.EndPartIdx; ++partIdx) { TPartOffsetRange &partRange = wholeRange.PartRanges[partIdx]; - i32 begin = Max<i32>(partRange.Begin, alignedBegin); - i32 end = Min<i32>(partRange.End, alignedEnd); + i32 begin = Max<i32>(partRange.Begin, alignedBegin); + i32 end = Min<i32>(partRange.End, alignedEnd); if (begin < end) { - i32 offset = partRange.WholeBegin + begin - partRange.Begin; - TIntervalVec<i32> x(offset, offset + end - begin); - if (!x.IsSubsetOf(state.Whole.Here)) { + i32 offset = partRange.WholeBegin + begin - partRange.Begin; + TIntervalVec<i32> x(offset, offset + end - begin); + if (!x.IsSubsetOf(state.Whole.Here)) { // Cerr << "copy from# " << partRange.WholeBegin << " to# " << partRange.WholeEnd << Endl; state.Whole.Data.Write(offset, partSet.Parts[partIdx].GetDataAt(begin), end - begin); state.Whole.Here.Add(offset, offset + end - begin); @@ -212,10 +212,10 @@ public: if (toRestore.IsSubsetOf(state.Parts[i].Here)) { partSet.PartsMask |= (1 << i); TString tmp = TString::Uninitialized(partSize); - for (auto it = toRestore.begin(); it != toRestore.end(); ++it) { - auto [begin, end] = *it; - i32 offset = begin; - i32 size = end - begin; + for (auto it = toRestore.begin(); it != toRestore.end(); ++it) { + auto [begin, end] = *it; + i32 offset = begin; + i32 size = end - begin; // Cerr << "part# " << i << " partSize# " << partSize << " offset# " << offset << " size# " << size << Endl; state.Parts[i].Data.Read(offset, const_cast<char*>(tmp.data()) + offset, size); } @@ -226,11 +226,11 @@ public: TString whole; info.Type.RestoreData((TErasureType::ECrcMode)state.Id.CrcMode(), partSet, whole, false, true, false); - TIntervalSet<i32> missing(state.Whole.NotHere); - for (auto it = missing.begin(); it != missing.end(); ++it) { - auto [begin, end] = *it; - i32 offset = begin; - i32 size = end - begin; + TIntervalSet<i32> missing(state.Whole.NotHere); + for (auto it = missing.begin(); it != missing.end(); ++it) { + auto [begin, end] = *it; + i32 offset = begin; + i32 size = end - begin; const char *source = whole.data() + offset; // Cerr << "LINE " << __LINE__ << " copy whole [" << offset << ", " << (offset + size) << ")" << Endl; state.Whole.Data.Write(offset, source, size); @@ -247,15 +247,15 @@ public: bool considerSlowAsError, TGroupDiskRequests &groupDiskRequests) { const ui32 totalPartCount = info.Type.TotalPartCount(); const i32 handoff = info.Type.Handoff(); - for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { - auto [begin, end] = *it; + for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { + auto [begin, end] = *it; TBlockSplitRange range; info.Type.BlockSplitRange((TErasureType::ECrcMode)state.Id.CrcMode(), state.Id.BlobSize(), - begin, end, &range); + begin, end, &range); for (ui32 partIdx = range.BeginPartIdx; partIdx < range.EndPartIdx; ++partIdx) { TPartOffsetRange &partRange = range.PartRanges[partIdx]; if (partRange.Begin != partRange.End) { - TIntervalSet<i32> partInterval(partRange.AlignedBegin, partRange.AlignedEnd); + TIntervalSet<i32> partInterval(partRange.AlignedBegin, partRange.AlignedEnd); partInterval.Subtract(state.Parts[partIdx].Here); if (!partInterval.IsEmpty()) { for (i32 niche = -1; niche < handoff; ++niche) { @@ -265,7 +265,7 @@ public: TBlobState::ESituation partSituation = disk.DiskParts[partIdx].Situation; if (partSituation == TBlobState::ESituation::Unknown || partSituation == TBlobState::ESituation::Present) { - TIntervalSet<i32> unrequestedInterval(partInterval); + TIntervalSet<i32> unrequestedInterval(partInterval); unrequestedInterval.Subtract(disk.DiskParts[partIdx].Requested); if (!unrequestedInterval.IsEmpty()) { AddGetRequest(logCtx, groupDiskRequests, state.Id, partIdx, disk, @@ -284,16 +284,16 @@ public: const ui32 totalPartCount = info.Type.TotalPartCount(); const i32 handoff = info.Type.Handoff(); bool isMinimalPossible = true; - for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { - auto [begin, end] = *it; + for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { + auto [begin, end] = *it; TBlockSplitRange range; - info.Type.BlockSplitRange((TErasureType::ECrcMode)state.Id.CrcMode(), state.Id.BlobSize(), begin, - end, &range); + info.Type.BlockSplitRange((TErasureType::ECrcMode)state.Id.CrcMode(), state.Id.BlobSize(), begin, + end, &range); for (ui32 partIdx = range.BeginPartIdx; partIdx < range.EndPartIdx; ++partIdx) { TPartOffsetRange &partRange = range.PartRanges[partIdx]; if (partRange.Begin != partRange.End) { - TIntervalVec<i32> partInterval(partRange.AlignedBegin, partRange.AlignedEnd); - if (!partInterval.IsSubsetOf(state.Parts[partIdx].Here)) { + TIntervalVec<i32> partInterval(partRange.AlignedBegin, partRange.AlignedEnd); + if (!partInterval.IsSubsetOf(state.Parts[partIdx].Here)) { bool isThereAGoodPart = false; for (i32 niche = -1; niche < handoff; ++niche) { ui32 diskIdx = (niche < 0 ? partIdx : totalPartCount + niche); @@ -317,13 +317,13 @@ public: } void FillIntervalsToRestoreRequestedFullData(TBlobState &state, const TBlobStorageGroupInfo &info, - TIntervalSet<i32> &outToRestore) { + TIntervalSet<i32> &outToRestore) { // get intervals needed to restore the requested full data - for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { - auto [begin, end] = *it; + for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { + auto [begin, end] = *it; TBlockSplitRange range; info.Type.BlockSplitRange((TErasureType::ECrcMode)state.Id.CrcMode(), state.Id.BlobSize(), - begin, end, &range); + begin, end, &range); for (ui32 partIdx = range.BeginPartIdx; partIdx < range.EndPartIdx; ++partIdx) { TPartOffsetRange &partRange = range.PartRanges[partIdx]; if (partRange.Begin != partRange.End) { @@ -360,7 +360,7 @@ public: void IssueGetRequestsForRestoration(TLogContext &logCtx, TBlobState &state, const TBlobStorageGroupInfo &info, bool considerSlowAsError, TGroupDiskRequests &groupDiskRequests) { - TIntervalSet<i32> toRestore; + TIntervalSet<i32> toRestore; FillIntervalsToRestoreRequestedFullData(state, info, toRestore); ui32 partsMissing = CountPartsMissing(state, info, considerSlowAsError); @@ -379,7 +379,7 @@ public: TBlobState::ESituation partSituation = disk.DiskParts[partIdx].Situation; if (partSituation == TBlobState::ESituation::Unknown || partSituation == TBlobState::ESituation::Present) { - TIntervalSet<i32> partIntervals(toRestore); + TIntervalSet<i32> partIntervals(toRestore); partIntervals.Subtract(state.Parts[partIdx].Here); partIntervals.Subtract(disk.DiskParts[partIdx].Requested); if (!partIntervals.IsEmpty()) { diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_min_iops_mirror.h b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_min_iops_mirror.h index 4ec3edaf93..510d58d025 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_min_iops_mirror.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_min_iops_mirror.h @@ -9,19 +9,19 @@ class TMinIopsMirrorStrategy : public TStrategyBase { public: std::optional<EStrategyOutcome> RestoreWholeFromDataParts(TLogContext& /*logCtx*/, TBlobState &state, const TBlobStorageGroupInfo &info) { - TIntervalSet<i32> missing(state.Whole.NotHere); + TIntervalSet<i32> missing(state.Whole.NotHere); const ui32 totalPartCount = info.Type.TotalPartCount(); - for (auto it = missing.begin(); it != missing.end(); ++it) { - auto [begin, end] = *it; + for (auto it = missing.begin(); it != missing.end(); ++it) { + auto [begin, end] = *it; for (ui32 partIdx = 0; partIdx < totalPartCount; ++partIdx) { - TIntervalVec<i32> partInterval(begin, end); + TIntervalVec<i32> partInterval(begin, end); if (partInterval.IsSubsetOf(state.Parts[partIdx].Here)) { - TString tmp = TString::Uninitialized(end - begin); + TString tmp = TString::Uninitialized(end - begin); Y_VERIFY(tmp.size()); - state.Parts[partIdx].Data.Read(begin, const_cast<char*>(tmp.data()), tmp.size()); - state.Whole.Data.Write(begin, tmp.data(), end - begin); - state.Whole.Here.Add(begin, end); - state.Whole.NotHere.Subtract(begin, end); + state.Parts[partIdx].Data.Read(begin, const_cast<char*>(tmp.data()), tmp.size()); + state.Whole.Data.Write(begin, tmp.data(), end - begin); + state.Whole.Here.Add(begin, end); + state.Whole.NotHere.Subtract(begin, end); } } } @@ -55,11 +55,11 @@ public: const ui32 totalPartCount = info.Type.TotalPartCount(); const i32 handoff = info.Type.Handoff(); bool isMinimalPossible = true; - for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { - auto [begin, end] = *it; + for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { + auto [begin, end] = *it; bool isThereAGoodPart = false; for (ui32 partIdx = 0; partIdx < totalPartCount; ++partIdx) { - TIntervalSet<i32> partInterval(begin, end); + TIntervalSet<i32> partInterval(begin, end); partInterval.Subtract(state.Parts[partIdx].Here); if (!partInterval.IsEmpty()) { for (i32 niche = -1; niche < handoff; ++niche) { @@ -78,10 +78,10 @@ public: } } if (isMinimalPossible) { - for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { - auto [begin, end] = *it; + for (auto it = state.Whole.NotHere.begin(); it != state.Whole.NotHere.end(); ++it) { + auto [begin, end] = *it; for (ui32 partIdx = 0; partIdx < totalPartCount; ++partIdx) { - TIntervalSet<i32> partInterval(begin, end); + TIntervalSet<i32> partInterval(begin, end); partInterval.Subtract(state.Parts[partIdx].Here); if (!partInterval.IsEmpty()) { for (i32 niche = -1; niche < handoff; ++niche) { @@ -90,7 +90,7 @@ public: TBlobState::ESituation partSituation = disk.DiskParts[partIdx].Situation; if (partSituation == TBlobState::ESituation::Unknown || partSituation == TBlobState::ESituation::Present) { - TIntervalSet<i32> unrequestedInterval(partInterval); + TIntervalSet<i32> unrequestedInterval(partInterval); unrequestedInterval.Subtract(disk.DiskParts[partIdx].Requested); if (!unrequestedInterval.IsEmpty()) { diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_put_m3of4.h b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_put_m3of4.h index b372e891eb..6e2816a575 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_put_m3of4.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_put_m3of4.h @@ -45,8 +45,8 @@ protected: return state.Parts[i].Data.GetMonolith(); } } - const TIntervalVec<i32> interval(0, state.Id.BlobSize()); - Y_VERIFY(interval.IsSubsetOf(state.Whole.Here), "missing blob data State# %s", state.ToString().data()); + const TIntervalVec<i32> interval(0, state.Id.BlobSize()); + Y_VERIFY(interval.IsSubsetOf(state.Whole.Here), "missing blob data State# %s", state.ToString().data()); TString wholeBuffer = TString::Uninitialized(state.Id.BlobSize()); state.Whole.Data.Read(0, const_cast<char*>(wholeBuffer.data()), state.Id.BlobSize()); TDataPartSet partSet; diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_timestats.h b/ydb/core/blobstorage/dsproxy/dsproxy_timestats.h index 943b93858d..98b8c8ebfb 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_timestats.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_timestats.h @@ -138,8 +138,8 @@ public: #define PARAM(NAME, V) \ do { \ - TABLER() { \ - TABLED() { str << "<b>" << #NAME << "</b>"; } \ + TABLER() { \ + TABLED() { str << "<b>" << #NAME << "</b>"; } \ for (auto it = V.begin(); it != V.end(); ++it) { \ auto& series = it->second; \ series.Update(now); \ @@ -151,7 +151,7 @@ public: values.push_back(item.second.NAME); \ } \ std::sort(values.begin(), values.end()); \ - TABLED() { \ + TABLED() { \ if (values) { \ size_t index = perc * values.size(); \ if (index >= values.size()) { \ @@ -161,104 +161,104 @@ public: } else { \ str << "none"; \ } \ - } \ + } \ } \ - } \ + } \ } while (false) double perc = Percentile; - HTML(str) { - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { + HTML(str) { + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { str << "Time accounting setup"; - } - DIV_CLASS("panel-body") { - FORM_CLASS("form-horizontal") { - DIV_CLASS("control-group") { - DIV_CLASS("controls") { - LABEL_CLASS("checkbox") { + } + DIV_CLASS("panel-body") { + FORM_CLASS("form-horizontal") { + DIV_CLASS("control-group") { + DIV_CLASS("controls") { + LABEL_CLASS("checkbox") { str << "<input type=\"checkbox\" name=\"enabled\""; if (Enabled) { str << " checked=\"checked\""; } str << ">Enabled</input>"; - } - } - } - DIV_CLASS("control-group") { - LABEL_CLASS_FOR("control-label", "inputAggrTime") { str << "Aggregation time"; } - DIV_CLASS("controls") { + } + } + } + DIV_CLASS("control-group") { + LABEL_CLASS_FOR("control-label", "inputAggrTime") { str << "Aggregation time"; } + DIV_CLASS("controls") { str << "<input id=\"inputAggrTime\" name=\"aggrTime\" type=\"text\" value=\"" << AggrTime << "\"/>"; - } - } - DIV_CLASS("control-group") { - LABEL_CLASS_FOR("control-label", "inputPercentile") { str << "Percentile"; } - DIV_CLASS("controls") { + } + } + DIV_CLASS("control-group") { + LABEL_CLASS_FOR("control-label", "inputPercentile") { str << "Percentile"; } + DIV_CLASS("controls") { str << "<input id=\"inputPercentile\" name=\"percentile\" type=\"text\" value=\"" << Percentile << "\"/>"; - } - } - DIV_CLASS("control-group") { - DIV_CLASS("controls") { + } + } + DIV_CLASS("control-group") { + DIV_CLASS("controls") { str << "<button type=\"submit\" name=\"submit_timestats\" class=\"btn btn-default\">Submit</button>"; - } - } - } - } - } - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { + } + } + } + } + } + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { str << "Put stats percentile# " << perc; - } - DIV_CLASS("panel-body") { - TABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() { str << "size"; } + } + DIV_CLASS("panel-body") { + TABLE_CLASS ("table table-condensed") { + TABLEHEAD() { + TABLER() { + TABLEH() { str << "size"; } for (auto it = Puts.begin(); it != Puts.end(); ++it) { - TABLEH() { + TABLEH() { str << it->first << "+"; - } + } } - } - } - TABLEBODY() { + } + } + TABLEBODY() { PARAM(InSenderQueue, Puts); PARAM(Total, Puts); PARAM(InQueue, Puts); PARAM(Execution, Puts); PARAM(RTT, Puts); - } - } - } - } - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { + } + } + } + } + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { str << "HugePut stats percentile# " << perc; - } - DIV_CLASS("panel-body") { - TABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() { str << "size"; } + } + DIV_CLASS("panel-body") { + TABLE_CLASS ("table table-condensed") { + TABLEHEAD() { + TABLER() { + TABLEH() { str << "size"; } for (auto it = HugePuts.begin(); it != HugePuts.end(); ++it) { - TABLEH() { + TABLEH() { str << it->first << "+"; - } + } } - } - } - TABLEBODY() { + } + } + TABLEBODY() { PARAM(InSenderQueue, HugePuts); PARAM(Total, HugePuts); PARAM(InQueue, HugePuts); PARAM(Execution, HugePuts); PARAM(RTT, HugePuts); PARAM(HugeWriteTime, HugePuts); - } - } - } - } - } - + } + } + } + } + } + } template<typename TCgiParameters> diff --git a/ydb/core/blobstorage/dsproxy/root_cause.h b/ydb/core/blobstorage/dsproxy/root_cause.h index 5126190cc8..9bddfda825 100644 --- a/ydb/core/blobstorage/dsproxy/root_cause.h +++ b/ydb/core/blobstorage/dsproxy/root_cause.h @@ -62,7 +62,7 @@ struct TRootCause { ui64 RegisterCause() { if (IsOn && Items.size() < InvalidCauseIdx - 1) { - Items.emplace_back(CurrentCauseIdx, GetCycleCountFast(), false); + Items.emplace_back(CurrentCauseIdx, GetCycleCountFast(), false); return Items.size() - 1; } else { return InvalidCauseIdx; @@ -71,7 +71,7 @@ struct TRootCause { ui64 RegisterAccelerate() { if (IsOn && Items.size() < InvalidCauseIdx - 1) { - Items.emplace_back(CurrentCauseIdx, GetCycleCountFast(), true); + Items.emplace_back(CurrentCauseIdx, GetCycleCountFast(), true); return Items.size() - 1; } else { return InvalidCauseIdx; @@ -86,7 +86,7 @@ struct TRootCause { if (causeIdx < Items.size()) { CurrentCauseIdx = causeIdx; TRootCauseItem &item = Items[CurrentCauseIdx]; - item.VDiskReplyCycles = GetCycleCountFast(); + item.VDiskReplyCycles = GetCycleCountFast(); if (transferDuration + vDiskDuration > 0) { ui64 transferCycles = item.StartCycles + ui64((transferDuration / (transferDuration + vDiskDuration)) * (item.VDiskReplyCycles - item.StartCycles)); diff --git a/ydb/core/blobstorage/lwtrace_probes/blobstorage_probes.cpp b/ydb/core/blobstorage/lwtrace_probes/blobstorage_probes.cpp index 0f6a440f57..7d432d4b03 100644 --- a/ydb/core/blobstorage/lwtrace_probes/blobstorage_probes.cpp +++ b/ydb/core/blobstorage/lwtrace_probes/blobstorage_probes.cpp @@ -4,28 +4,28 @@ LWTRACE_DEFINE_PROVIDER(BLOBSTORAGE_PROVIDER); LWTRACE_DEFINE_PROVIDER(FAIL_INJECTION_PROVIDER); - -namespace NKikimr { namespace NPDisk { - - + +namespace NKikimr { namespace NPDisk { + + void TRequestTypeField::ToString(ui32 value, TString *out) { - switch(ERequestType(value)) { - case ERequestType::RequestLogRead: *out = "LogRead"; break; - case ERequestType::RequestLogWrite: *out = "LogWrite"; break; - case ERequestType::RequestChunkRead: *out = "ChunkRead"; break; - case ERequestType::RequestChunkWrite: *out = "ChunkWrite"; break; - case ERequestType::RequestChunkTrim: *out = "ChunkTrim"; break; - case ERequestType::RequestYardInit: *out = "YardInit"; break; - case ERequestType::RequestCheckSpace: *out = "CheckSpace"; break; - case ERequestType::RequestHarakiri: *out = "Harakiri"; break; - case ERequestType::RequestChunkReserve: *out = "ChunkReserve"; break; - case ERequestType::RequestYardControl: *out = "YardControl"; break; - default: *out = "Unknown"; - } - *out += "(" + ::ToString(value) + ")"; -} - -}} + switch(ERequestType(value)) { + case ERequestType::RequestLogRead: *out = "LogRead"; break; + case ERequestType::RequestLogWrite: *out = "LogWrite"; break; + case ERequestType::RequestChunkRead: *out = "ChunkRead"; break; + case ERequestType::RequestChunkWrite: *out = "ChunkWrite"; break; + case ERequestType::RequestChunkTrim: *out = "ChunkTrim"; break; + case ERequestType::RequestYardInit: *out = "YardInit"; break; + case ERequestType::RequestCheckSpace: *out = "CheckSpace"; break; + case ERequestType::RequestHarakiri: *out = "Harakiri"; break; + case ERequestType::RequestChunkReserve: *out = "ChunkReserve"; break; + case ERequestType::RequestYardControl: *out = "YardControl"; break; + default: *out = "Unknown"; + } + *out += "(" + ::ToString(value) + ")"; +} + +}} namespace NKikimr { diff --git a/ydb/core/blobstorage/lwtrace_probes/blobstorage_probes.h b/ydb/core/blobstorage/lwtrace_probes/blobstorage_probes.h index 7e20a7bd81..3277bca37e 100644 --- a/ydb/core/blobstorage/lwtrace_probes/blobstorage_probes.h +++ b/ydb/core/blobstorage/lwtrace_probes/blobstorage_probes.h @@ -4,33 +4,33 @@ #include <library/cpp/lwtrace/all.h> -// Helper class for printing pdisk id in the same was as it done for counters -struct TPDiskIdField { - typedef ui32 TStoreType; +// Helper class for printing pdisk id in the same was as it done for counters +struct TPDiskIdField { + typedef ui32 TStoreType; typedef ui32 TFuncParam; static void ToString(ui32 value, TString* out) { - *out = Sprintf("%09" PRIu32, value); - } + *out = Sprintf("%09" PRIu32, value); + } static ui32 ToStoreType(ui32 value) { return value; } -}; - -namespace NKikimr { namespace NPDisk { - -struct TRequestTypeField { - typedef ui32 TStoreType; +}; + +namespace NKikimr { namespace NPDisk { + +struct TRequestTypeField { + typedef ui32 TStoreType; typedef ui32 TFuncParam; static void ToString(ui32 value, TString* out); static ui32 ToStoreType(ui32 value) { return value; } -}; - -}} - +}; + +}} + namespace NKikimr { struct TBlobPutTactics { @@ -62,16 +62,16 @@ struct TEventTypeField { PROBE(DSProxyBatchedGetRequest, GROUPS("DSProxy"), \ TYPES(ui64, ui32), \ NAMES("count" , "groupId")) \ - PROBE(ProxyPutBootstrapPart, GROUPS("Durations"), \ - TYPES(ui64, double, double, ui64, double), \ - NAMES("size", "waitMs", "splitMs", "splitCount", "splitElapsedMs")) \ + PROBE(ProxyPutBootstrapPart, GROUPS("Durations"), \ + TYPES(ui64, double, double, ui64, double), \ + NAMES("size", "waitMs", "splitMs", "splitCount", "splitElapsedMs")) \ PROBE(DSProxyRequestDuration, GROUPS("DSProxyRequest", "DSProxy"), \ - TYPES(NKikimr::TEventTypeField, ui64, double, ui64, ui32, ui32, TString, bool), \ + TYPES(NKikimr::TEventTypeField, ui64, double, ui64, ui32, ui32, TString, bool), \ NAMES("type", "size", "durationMs", "tabletId", "groupId", "channel", "handleClass", "isOk")) \ PROBE(DSProxyVDiskRequestDuration, GROUPS("VDisk", "DSProxy"), \ - TYPES(NKikimr::TEventTypeField, ui64, ui64, ui32, ui32, ui32, double, double, double, double, TString, TString), \ + TYPES(NKikimr::TEventTypeField, ui64, ui64, ui32, ui32, ui32, double, double, double, double, TString, TString), \ NAMES("type", "size", "tabletId", "groupId", "channel", "vdiskOrderNum", "startTime", "totalDurationMs", \ - "vdiskDurationMs", "transferDurationMs", "handleClass", "status")) \ + "vdiskDurationMs", "transferDurationMs", "handleClass", "status")) \ PROBE(VDiskSkeletonFrontVMovedPatchRecieved, GROUPS("VDisk", "DSProxy"), \ TYPES(ui32, ui32, ui32, ui64, ui64), \ NAMES("nodeId", "groupId", "vdiskOrderNum", "tabletId", "size")) \ @@ -126,18 +126,18 @@ struct TEventTypeField { TYPES(double, ui32, bool), \ NAMES("processingTimeMs", "size", "isDiscarded")) \ PROBE(PDiskNewRequest, GROUPS("PDisk", "PDiskRequest", "LWTrackStart"), \ - TYPES(TPDiskIdField, ui64, double, double, bool, bool, ui64, ui64, NKikimr::NPDisk::TRequestTypeField), \ - NAMES("pdisk", "reqId", "creationTimeSec", "costMs", "isSensitive", "isFast", "owner", "priorityClass", "type")) \ - PROBE(PDiskFairSchedulerPush, GROUPS("PDisk", "PDiskRequest"), \ + TYPES(TPDiskIdField, ui64, double, double, bool, bool, ui64, ui64, NKikimr::NPDisk::TRequestTypeField), \ + NAMES("pdisk", "reqId", "creationTimeSec", "costMs", "isSensitive", "isFast", "owner", "priorityClass", "type")) \ + PROBE(PDiskFairSchedulerPush, GROUPS("PDisk", "PDiskRequest"), \ TYPES(TPDiskIdField, ui64, TString, ui64, ui64, NKikimr::NPDisk::TRequestTypeField, ui64, double), \ - NAMES("pdisk", "reqId", "queueType", "owner", "priorityClass", "type", "fairQLA", "fairQCA")) \ - PROBE(PDiskFairSchedulerPop, GROUPS("PDisk", "PDiskRequest"), \ + NAMES("pdisk", "reqId", "queueType", "owner", "priorityClass", "type", "fairQLA", "fairQCA")) \ + PROBE(PDiskFairSchedulerPop, GROUPS("PDisk", "PDiskRequest"), \ TYPES(TPDiskIdField, ui64, TString, ui64, ui64, NKikimr::NPDisk::TRequestTypeField, ui64, double, bool), \ - NAMES("pdisk", "reqId", "queueType", "owner", "priorityClass", "type", "fairQLD", "fairQCD", "guarantyLost")) \ - PROBE(PDiskInputRequestTimeout, GROUPS("PDisk", "PDiskRequest"), \ - TYPES(TPDiskIdField, ui64, double), \ - NAMES("pdisk", "reqId", "deadlineSec")) \ - PROBE(PDiskInputRequest, GROUPS("PDisk", "PDiskRequest"), \ + NAMES("pdisk", "reqId", "queueType", "owner", "priorityClass", "type", "fairQLD", "fairQCD", "guarantyLost")) \ + PROBE(PDiskInputRequestTimeout, GROUPS("PDisk", "PDiskRequest"), \ + TYPES(TPDiskIdField, ui64, double), \ + NAMES("pdisk", "reqId", "deadlineSec")) \ + PROBE(PDiskInputRequest, GROUPS("PDisk", "PDiskRequest"), \ TYPES(TPDiskIdField, ui64, double, double, ui64, double, double, ui64, bool, ui64, ui64), \ NAMES("pdisk", "reqId", "creationTimeSec", "costMs", "inputQLA", "inputQCA", "deadlineSec", "owner", "isFast", \ "priorityClass", "inputQueueSize")) \ @@ -150,49 +150,49 @@ struct TEventTypeField { PROBE(PDiskLogWriteFlush, GROUPS("PDisk", "PDiskRequest"), \ TYPES(TPDiskIdField, ui64, double, double, double, ui64, bool, ui64), \ NAMES("pdisk", "reqId", "creationTimeSec", "costMs", "deadlineSec", "owner", "isFast", "priorityClass")) \ - PROBE(PDiskBurst, GROUPS("PDisk", "PDiskRequest"), \ - TYPES(TPDiskIdField, ui64, double, bool, double, double), \ - NAMES("pdisk", "reqId", "creationTimeSec", "isSensitive", "costMs", "burstMs")) \ - PROBE(PDiskSchedulerPack, GROUPS("PDisk", "PDiskSchedulerStep"), \ - TYPES(TPDiskIdField, ui64, ui64, double, ui64), \ - NAMES("pdisk", "schedStep", "schedPack", "totalCostMs", "reqCount")) \ - PROBE(PDiskSchedulerAdhesion, GROUPS("PDisk"), \ - TYPES(TPDiskIdField, ui32, double, ui64, ui64), \ - NAMES("pdisk", "chunkIdx", "adhesionCostMs", "adhesionWrites", "adhesionReorderings")) \ - PROBE(PDiskSchedulerAdhesionLookup, GROUPS("PDisk"), \ - TYPES(TPDiskIdField, bool, bool, bool, bool, bool, bool, bool, bool), \ - NAMES("pdisk", "found", "queueEnd", "skipCostLimit", "skipCountLimit", "orderConstraint", "disabled", "adhesionSizeLimit", "interrupted")) \ - PROBE(PDiskSchedulerDispatch, GROUPS("PDisk", "PDiskSchedulerStep", "PDiskSchedulerSubStep", "PDiskRequest"), \ - TYPES(TPDiskIdField, ui64, ui64, ui64, ui64, bool, double), \ - NAMES("pdisk", "schedStep", "schedSubStep", "reqId", "reqDispatched", "isSensitive", "costMs")) \ - PROBE(PDiskSchedulerSlack, GROUPS("PDisk", "PDiskSchedulerStep", "PDiskSchedulerSubStep"), \ - TYPES(TPDiskIdField, ui64, ui64, double, double, double, double), \ - NAMES("pdisk", "schedStep", "schedSubStep", "slackMs", "nonscheduledMs", "burstMs", "reorderingMs")) \ - PROBE(PDiskSchedulerInject, GROUPS("PDisk", "PDiskSchedulerStep"), \ - TYPES(TPDiskIdField, ui64, double, double, double, double), \ - NAMES("pdisk", "schedStep", "sensitiveQueueMs", "bestEffortQueueMs", "unusedBurstMs", "injectedMs")) \ - PROBE(PDiskSchedulerAllocIdleSlack, GROUPS("PDisk", "PDiskSchedulerStep"), \ - TYPES(TPDiskIdField, ui64, double, double, double), \ - NAMES("pdisk", "schedStep", "allocIdleSlackMaxMs", "slackMs", "allocatedIdleSlackMs")) \ - PROBE(PDiskSchedulerStepCost, GROUPS("PDisk", "PDiskSchedulerStep"), \ - TYPES(TPDiskIdField, ui64, ui64, double, ui64, double, ui64, double, ui64), \ - NAMES("pdisk", "schedStep", "schedPacks", "stepSensitiveCost", "stepSensitiveCount", "stepBestEffortCost", "stepBestEffortCount" \ - , "stepCost", "stepCount")) \ - PROBE(PDiskSchedulerStepInjected, GROUPS("PDisk", "PDiskSchedulerStep"), \ - TYPES(TPDiskIdField, ui64, double, ui64), \ - NAMES("pdisk", "schedStep", "stepInjectedCost", "stepInjectedCount")) \ - PROBE(PDiskSchedulerStepBlocks, GROUPS("PDisk", "PDiskSchedulerStep"), \ - TYPES(TPDiskIdField, ui64, ui64, ui64, ui64, ui64), \ - NAMES("pdisk", "schedStep", "bestEffortBlocks", "bestEffortUnblocks", "sensitiveBlocks", "sensitiveUnblocks")) \ - PROBE(PDiskSchedulerStepIdleSlack, GROUPS("PDisk", "PDiskSchedulerStep"), \ - TYPES(TPDiskIdField, ui64, double, ui64), \ - NAMES("pdisk", "schedStep", "stepAllocatedIdleSlackMs", "stepAllocatedIdleSlackCount")) \ - PROBE(PDiskSchedulerSubStep, GROUPS("PDisk", "PDiskSchedulerStep", "PDiskSchedulerSubStep"), \ - TYPES(TPDiskIdField, ui64, ui64, double, double), \ - NAMES("pdisk", "schedStep", "schedSubStep", "subStepCost", "subStepCount")) \ + PROBE(PDiskBurst, GROUPS("PDisk", "PDiskRequest"), \ + TYPES(TPDiskIdField, ui64, double, bool, double, double), \ + NAMES("pdisk", "reqId", "creationTimeSec", "isSensitive", "costMs", "burstMs")) \ + PROBE(PDiskSchedulerPack, GROUPS("PDisk", "PDiskSchedulerStep"), \ + TYPES(TPDiskIdField, ui64, ui64, double, ui64), \ + NAMES("pdisk", "schedStep", "schedPack", "totalCostMs", "reqCount")) \ + PROBE(PDiskSchedulerAdhesion, GROUPS("PDisk"), \ + TYPES(TPDiskIdField, ui32, double, ui64, ui64), \ + NAMES("pdisk", "chunkIdx", "adhesionCostMs", "adhesionWrites", "adhesionReorderings")) \ + PROBE(PDiskSchedulerAdhesionLookup, GROUPS("PDisk"), \ + TYPES(TPDiskIdField, bool, bool, bool, bool, bool, bool, bool, bool), \ + NAMES("pdisk", "found", "queueEnd", "skipCostLimit", "skipCountLimit", "orderConstraint", "disabled", "adhesionSizeLimit", "interrupted")) \ + PROBE(PDiskSchedulerDispatch, GROUPS("PDisk", "PDiskSchedulerStep", "PDiskSchedulerSubStep", "PDiskRequest"), \ + TYPES(TPDiskIdField, ui64, ui64, ui64, ui64, bool, double), \ + NAMES("pdisk", "schedStep", "schedSubStep", "reqId", "reqDispatched", "isSensitive", "costMs")) \ + PROBE(PDiskSchedulerSlack, GROUPS("PDisk", "PDiskSchedulerStep", "PDiskSchedulerSubStep"), \ + TYPES(TPDiskIdField, ui64, ui64, double, double, double, double), \ + NAMES("pdisk", "schedStep", "schedSubStep", "slackMs", "nonscheduledMs", "burstMs", "reorderingMs")) \ + PROBE(PDiskSchedulerInject, GROUPS("PDisk", "PDiskSchedulerStep"), \ + TYPES(TPDiskIdField, ui64, double, double, double, double), \ + NAMES("pdisk", "schedStep", "sensitiveQueueMs", "bestEffortQueueMs", "unusedBurstMs", "injectedMs")) \ + PROBE(PDiskSchedulerAllocIdleSlack, GROUPS("PDisk", "PDiskSchedulerStep"), \ + TYPES(TPDiskIdField, ui64, double, double, double), \ + NAMES("pdisk", "schedStep", "allocIdleSlackMaxMs", "slackMs", "allocatedIdleSlackMs")) \ + PROBE(PDiskSchedulerStepCost, GROUPS("PDisk", "PDiskSchedulerStep"), \ + TYPES(TPDiskIdField, ui64, ui64, double, ui64, double, ui64, double, ui64), \ + NAMES("pdisk", "schedStep", "schedPacks", "stepSensitiveCost", "stepSensitiveCount", "stepBestEffortCost", "stepBestEffortCount" \ + , "stepCost", "stepCount")) \ + PROBE(PDiskSchedulerStepInjected, GROUPS("PDisk", "PDiskSchedulerStep"), \ + TYPES(TPDiskIdField, ui64, double, ui64), \ + NAMES("pdisk", "schedStep", "stepInjectedCost", "stepInjectedCount")) \ + PROBE(PDiskSchedulerStepBlocks, GROUPS("PDisk", "PDiskSchedulerStep"), \ + TYPES(TPDiskIdField, ui64, ui64, ui64, ui64, ui64), \ + NAMES("pdisk", "schedStep", "bestEffortBlocks", "bestEffortUnblocks", "sensitiveBlocks", "sensitiveUnblocks")) \ + PROBE(PDiskSchedulerStepIdleSlack, GROUPS("PDisk", "PDiskSchedulerStep"), \ + TYPES(TPDiskIdField, ui64, double, ui64), \ + NAMES("pdisk", "schedStep", "stepAllocatedIdleSlackMs", "stepAllocatedIdleSlackCount")) \ + PROBE(PDiskSchedulerSubStep, GROUPS("PDisk", "PDiskSchedulerStep", "PDiskSchedulerSubStep"), \ + TYPES(TPDiskIdField, ui64, ui64, double, double), \ + NAMES("pdisk", "schedStep", "schedSubStep", "subStepCost", "subStepCount")) \ PROBE(PDiskSchedulerStartStep, GROUPS("PDisk", "PDiskSchedulerStep", "LWTrackStart"), \ - TYPES(TPDiskIdField, ui64), \ - NAMES("pdisk", "schedStep")) \ + TYPES(TPDiskIdField, ui64), \ + NAMES("pdisk", "schedStep")) \ PROBE(PDiskChunkReadPieceAddToScheduler, GROUPS("PDisk", "PDiskRequest"), \ TYPES(TPDiskIdField, ui32, ui64, ui64), \ NAMES("pdisk", "pieceIdx", "size", "offset")) \ @@ -208,33 +208,33 @@ struct TEventTypeField { PROBE(PDiskChunkWritePieceSendToDevice, GROUPS("PDisk", "PDiskRequest"), \ TYPES(TPDiskIdField, ui64, ui64, ui64, ui64), \ NAMES("pdisk", "owner", "chunkIdx", "pieceOffset", "pieceSize")) \ - PROBE(PDiskLogWriteComplete, GROUPS("PDisk", "PDiskRequest"), \ - TYPES(TPDiskIdField, ui64, double, double, double, double, double, double), \ - NAMES("pdisk", "reqId", "creationTimeSec", "costMs", "responseTimeMs", "inputTimeMs", "scheduleTimeMs", "deviceTotalTimeMs")) \ - PROBE(PDiskChunkResponseTime, GROUPS("PDisk", "PDiskRequest"), \ - TYPES(TPDiskIdField, ui64, ui64, double, ui64), \ - NAMES("pdisk", "reqId", "priorityClass", "responseTimeMs", "sizeBytes")) \ - PROBE(PDiskTrimResponseTime, GROUPS("PDisk", "PDiskRequest"), \ - TYPES(TPDiskIdField, ui64, double, ui64), \ - NAMES("pdisk", "reqId", "responseTimeMs", "sizeBytes")) \ - PROBE(PDiskDeviceReadDuration, GROUPS("PDisk"), \ + PROBE(PDiskLogWriteComplete, GROUPS("PDisk", "PDiskRequest"), \ + TYPES(TPDiskIdField, ui64, double, double, double, double, double, double), \ + NAMES("pdisk", "reqId", "creationTimeSec", "costMs", "responseTimeMs", "inputTimeMs", "scheduleTimeMs", "deviceTotalTimeMs")) \ + PROBE(PDiskChunkResponseTime, GROUPS("PDisk", "PDiskRequest"), \ + TYPES(TPDiskIdField, ui64, ui64, double, ui64), \ + NAMES("pdisk", "reqId", "priorityClass", "responseTimeMs", "sizeBytes")) \ + PROBE(PDiskTrimResponseTime, GROUPS("PDisk", "PDiskRequest"), \ + TYPES(TPDiskIdField, ui64, double, ui64), \ + NAMES("pdisk", "reqId", "responseTimeMs", "sizeBytes")) \ + PROBE(PDiskDeviceReadDuration, GROUPS("PDisk"), \ TYPES(TPDiskIdField, double, ui64), \ NAMES("pdisk", "deviceTimeMs", "size")) \ - PROBE(PDiskDeviceWriteDuration, GROUPS("PDisk"), \ + PROBE(PDiskDeviceWriteDuration, GROUPS("PDisk"), \ TYPES(TPDiskIdField, double, ui64), \ NAMES("pdisk", "deviceTimeMs", "size")) \ - PROBE(PDiskDeviceTrimDuration, GROUPS("PDisk"), \ - TYPES(TPDiskIdField, double, ui64), \ - NAMES("pdisk", "trimTimeMs", "trimOffset")) \ + PROBE(PDiskDeviceTrimDuration, GROUPS("PDisk"), \ + TYPES(TPDiskIdField, double, ui64), \ + NAMES("pdisk", "trimTimeMs", "trimOffset")) \ PROBE(PDiskDeviceOperationSizeAndType, GROUPS("PDisk"), \ TYPES(TPDiskIdField, ui64, ui64), \ NAMES("pdisk", "operationSize", "operationType")) \ - PROBE(PDiskMilliBatchSize, GROUPS("PDisk"), \ - TYPES(TPDiskIdField, ui64, ui64, ui64, ui64), \ - NAMES("pdisk", "milliBatchLogCost", "milliBatchNonLogCost", "milliBatchLogReqs", "milliBatchNonLogReqs")) \ - PROBE(PDiskHandleWakeup, GROUPS("PDisk"), \ - TYPES(TPDiskIdField, double, double, double), \ - NAMES("pdisk", "updatePercentileTrackersMs", "whiteboardReportMs", "updateSchedulerMs")) \ + PROBE(PDiskMilliBatchSize, GROUPS("PDisk"), \ + TYPES(TPDiskIdField, ui64, ui64, ui64, ui64), \ + NAMES("pdisk", "milliBatchLogCost", "milliBatchNonLogCost", "milliBatchLogReqs", "milliBatchNonLogReqs")) \ + PROBE(PDiskHandleWakeup, GROUPS("PDisk"), \ + TYPES(TPDiskIdField, double, double, double), \ + NAMES("pdisk", "updatePercentileTrackersMs", "whiteboardReportMs", "updateSchedulerMs")) \ PROBE(PDiskForsetiCycle, GROUPS("PDisk"), \ TYPES(TPDiskIdField, ui64, ui64, ui64, ui64, ui64, ui64, ui64, ui64, ui64), \ NAMES("pdisk", "realTimeNs", "uncorrectedForsetiTimeNs", "correctedForsetiTimeNs", "timeCorrectionNs", \ @@ -251,10 +251,10 @@ struct TEventTypeField { PROBE(DSProxyGetReply, GROUPS("DSProxy"), TYPES(), NAMES()) \ PROBE(DSProxyPutEnqueue, GROUPS("DSProxy", "LWTrackStart"), TYPES(), NAMES()) \ PROBE(DSProxyPutHandle, GROUPS("DSProxyRequest", "DSProxy", "LWTrackStart"), TYPES(), NAMES()) \ - PROBE(DSProxyPutBootstrapStart, GROUPS("DSProxy"), TYPES(), NAMES()) \ - PROBE(DSProxyPutBootstrapDone, GROUPS("DSProxy","Durations"), \ - TYPES(ui64, double, double, double, double, ui64, ui64), \ - NAMES("size", "wilsonMs", "allocateMs", "waitTotalMs", "splitTotalMs", "splitTotalCount", "blobIdx")) \ + PROBE(DSProxyPutBootstrapStart, GROUPS("DSProxy"), TYPES(), NAMES()) \ + PROBE(DSProxyPutBootstrapDone, GROUPS("DSProxy","Durations"), \ + TYPES(ui64, double, double, double, double, ui64, ui64), \ + NAMES("size", "wilsonMs", "allocateMs", "waitTotalMs", "splitTotalMs", "splitTotalCount", "blobIdx")) \ PROBE(DSProxyPutReply, GROUPS("DSProxy"), TYPES(), NAMES()) \ PROBE(DSProxyPutResumeBootstrap, GROUPS("DSProxy"), TYPES(), NAMES()) \ PROBE(DSProxyPutPauseBootstrap, GROUPS("DSProxy"), TYPES(), NAMES()) \ diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_actor.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_actor.cpp index d92b19c6cc..7a3d151c9b 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_actor.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_actor.cpp @@ -10,7 +10,7 @@ #include "blobstorage_pdisk_thread.h" #include "blobstorage_pdisk_tools.h" #include "blobstorage_pdisk_util_countedqueueoneone.h" -#include "blobstorage_pdisk_util_cputimer.h" +#include "blobstorage_pdisk_util_cputimer.h" #include "blobstorage_pdisk_writer.h" #include <ydb/core/base/appdata.h> @@ -83,73 +83,73 @@ class TPDiskActor : public TActorBootstrapped<TPDiskActor> { THolder<IEventHandle> ControledStartResult; - class TWhiteboardFlag { - private: - class TSource { - private: - const TLightBase& Light; - const ui64 ReportPeriodMs = 15000; - const ui64 GreenRatio = 5; - const ui64 YellowRatio = 25; - const ui64 OrangeRatio = 75; - - ui64 LastCount = 0; - ui64 LastRedMs = 0; - ui64 LastGreenMs = 0; + class TWhiteboardFlag { + private: + class TSource { + private: + const TLightBase& Light; + const ui64 ReportPeriodMs = 15000; + const ui64 GreenRatio = 5; + const ui64 YellowRatio = 25; + const ui64 OrangeRatio = 75; + + ui64 LastCount = 0; + ui64 LastRedMs = 0; + ui64 LastGreenMs = 0; ui64 LastRedMsPs = 0; - NKikimrWhiteboard::EFlag CurrentFlag = NKikimrWhiteboard::Green; - public: - explicit TSource(const TLightBase& light) - : Light(light) - {} - + NKikimrWhiteboard::EFlag CurrentFlag = NKikimrWhiteboard::Green; + public: + explicit TSource(const TLightBase& light) + : Light(light) + {} + ui64 GetRedMsPs() { return LastRedMsPs; } - NKikimrWhiteboard::EFlag GetFlag() { - ui64 count = Light.GetCount(); - ui64 redMs = Light.GetRedMs(); - ui64 greenMs = Light.GetGreenMs(); - - // Init on first pass - if (LastRedMs == 0 && LastGreenMs == 0) { - SaveLast(count, redMs, greenMs); - } - - // Recalculate new flag value if needed - if (greenMs + redMs > LastGreenMs + LastRedMs + ReportPeriodMs) { - ui64 ratio = (redMs - LastRedMs) * 100 / (redMs - LastRedMs + greenMs - LastGreenMs); + NKikimrWhiteboard::EFlag GetFlag() { + ui64 count = Light.GetCount(); + ui64 redMs = Light.GetRedMs(); + ui64 greenMs = Light.GetGreenMs(); + + // Init on first pass + if (LastRedMs == 0 && LastGreenMs == 0) { + SaveLast(count, redMs, greenMs); + } + + // Recalculate new flag value if needed + if (greenMs + redMs > LastGreenMs + LastRedMs + ReportPeriodMs) { + ui64 ratio = (redMs - LastRedMs) * 100 / (redMs - LastRedMs + greenMs - LastGreenMs); LastRedMsPs = (1000ull * (redMs - LastRedMs)) / (redMs - LastRedMs + greenMs - LastGreenMs); - if (ratio < GreenRatio) { - CurrentFlag = NKikimrWhiteboard::Green; - } else if (ratio < YellowRatio) { - CurrentFlag = NKikimrWhiteboard::Yellow; - } else if (ratio < OrangeRatio) { - CurrentFlag = NKikimrWhiteboard::Orange; - } else { - CurrentFlag = NKikimrWhiteboard::Red; - } - SaveLast(count, redMs, greenMs); - } - - return CurrentFlag; - } - private: - void SaveLast(ui64 count, ui64 redMs, ui64 greenMs) { - LastCount = count; - LastRedMs = redMs; - LastGreenMs = greenMs; - } - }; - private: + if (ratio < GreenRatio) { + CurrentFlag = NKikimrWhiteboard::Green; + } else if (ratio < YellowRatio) { + CurrentFlag = NKikimrWhiteboard::Yellow; + } else if (ratio < OrangeRatio) { + CurrentFlag = NKikimrWhiteboard::Orange; + } else { + CurrentFlag = NKikimrWhiteboard::Red; + } + SaveLast(count, redMs, greenMs); + } + + return CurrentFlag; + } + private: + void SaveLast(ui64 count, ui64 redMs, ui64 greenMs) { + LastCount = count; + LastRedMs = redMs; + LastGreenMs = greenMs; + } + }; + private: TVector<TSource> Sources; NKikimrWhiteboard::EFlag LastFlag = NKikimrWhiteboard::Grey; - public: - void AddSource(const TLightBase& light) { - Sources.emplace_back(light); - } - + public: + void AddSource(const TLightBase& light) { + Sources.emplace_back(light); + } + void RemoveSources() { Sources.clear(); } @@ -162,35 +162,35 @@ class TPDiskActor : public TActorBootstrapped<TPDiskActor> { return redMsPs; } - void Update(bool& resendRequired) { - NKikimrWhiteboard::EFlag flag = NKikimrWhiteboard::Green; - for (TSource& source : Sources) { - flag = Max(flag, source.GetFlag()); - } - if (LastFlag != flag) { - LastFlag = flag; - resendRequired = true; - } - } - - NKikimrWhiteboard::EFlag Get() const { - return LastFlag; - } - + void Update(bool& resendRequired) { + NKikimrWhiteboard::EFlag flag = NKikimrWhiteboard::Green; + for (TSource& source : Sources) { + flag = Max(flag, source.GetFlag()); + } + if (LastFlag != flag) { + LastFlag = flag; + resendRequired = true; + } + } + + NKikimrWhiteboard::EFlag Get() const { + return LastFlag; + } + void Render(IOutputStream& os) const { - switch (LastFlag) { + switch (LastFlag) { case NKikimrWhiteboard::Grey: - break; + break; default: THtmlLightSignalRenderer(LastFlag, NKikimrWhiteboard::EFlag_Name(LastFlag)).Output(os); - break; - } - } - }; - - TWhiteboardFlag RealtimeFlag; - TWhiteboardFlag DeviceFlag; - + break; + } + } + }; + + TWhiteboardFlag RealtimeFlag; + TWhiteboardFlag DeviceFlag; + public: static constexpr NKikimrServices::TActivity::EType ActorActivityType() { return NKikimrServices::TActivity::PDISK_ACTOR; @@ -236,8 +236,8 @@ public: RealtimeFlag.RemoveSources(); DeviceFlag.RemoveSources(); - DeviceFlag.AddSource(PDisk->Mon.L6); - + DeviceFlag.AddSource(PDisk->Mon.L6); + bool isOk = PDisk->Initialize(TlsActivationContext->ActorSystem(), SelfId()); if (!isOk) { @@ -788,14 +788,14 @@ public: void HandleWakeup() { Schedule(TDuration::MilliSeconds(Cfg->StatisticsUpdateIntervalMs), new TEvents::TEvWakeup()); - - TCpuTimer timer; + + TCpuTimer timer; PDisk->Mon.UpdatePercentileTrackers(); PDisk->Mon.UpdateLights(); const bool halt = PDisk->Mon.UpdateDeviceHaltCounters(); PDisk->Mon.UpdateStats(); - ui64 updatePercentileTrackersCycles = timer.Elapsed(); - + ui64 updatePercentileTrackersCycles = timer.Elapsed(); + if (halt) { Send(SelfId(), new TEvDeviceError("device halt too long")); } @@ -815,12 +815,12 @@ public: } else { PDisk->WhiteboardReport(*request); // Send TEvWhiteboardReportResult inside } + - - LWPROBE(PDiskHandleWakeup, PDisk->PDiskId, - HPMilliSecondsFloat(updatePercentileTrackersCycles), - HPMilliSecondsFloat(whiteboardReportCycles), - HPMilliSecondsFloat(updateSchedulerCycles)); + LWPROBE(PDiskHandleWakeup, PDisk->PDiskId, + HPMilliSecondsFloat(updatePercentileTrackersCycles), + HPMilliSecondsFloat(whiteboardReportCycles), + HPMilliSecondsFloat(updateSchedulerCycles)); } void Handle(NPDisk::TEvWhiteboardReportResult::TPtr &ev) { @@ -835,15 +835,15 @@ public: if (result->DiskMetrics) { Send(NodeWardenServiceId, result->DiskMetrics.Release()); } - bool sendFlags = false; - RealtimeFlag.Update(sendFlags); - DeviceFlag.Update(sendFlags); + bool sendFlags = false; + RealtimeFlag.Update(sendFlags); + DeviceFlag.Update(sendFlags); AtomicSet(PDisk->NonRealTimeMs, RealtimeFlag.GetRedMsPs()); AtomicSet(PDisk->SlowDeviceMs, DeviceFlag.GetRedMsPs()); - if (sendFlags) { + if (sendFlags) { Send(NodeWhiteboardServiceId, new NNodeWhiteboard::TEvWhiteboard::TEvPDiskStateUpdate( - PDisk->PDiskId, RealtimeFlag.Get(), DeviceFlag.Get())); - } + PDisk->PDiskId, RealtimeFlag.Get(), DeviceFlag.Get())); + } } void Handle(NPDisk::TEvDeviceError::TPtr &ev) { diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_async.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_async.cpp index 34c20999b7..ea4d0bb6a4 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_async.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_async.cpp @@ -33,8 +33,8 @@ namespace NKikimr { namespace NPDisk { -LWTRACE_USING(BLOBSTORAGE_PROVIDER); - +LWTRACE_USING(BLOBSTORAGE_PROVIDER); + constexpr ui64 MaxWaitingNoops = 256; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -305,7 +305,7 @@ class TRealBlockDevice : public IBlockDevice { TAsyncIoOperationResult events[MaxEvents]; - while(!Device.QuitCounter.IsBlocked() || Device.QuitCounter.Get()) { + while(!Device.QuitCounter.IsBlocked() || Device.QuitCounter.Get()) { i64 ret = Device.IoContext->GetEvents(1, MaxEvents, events, TDuration::MilliSeconds(WaitTimeoutMs)); if (ret == -static_cast<i64>(EIoResult::InterruptedSystemCall)) { Device.Mon.DeviceInterruptedSystemCalls->Inc(); @@ -699,7 +699,7 @@ private: bool IsFileOpened; bool IsInitialized; - ui64 Reordering; + ui64 Reordering; ui64 SeekCostNs; bool IsTrimEnabled; ui32 MaxQueuedCompletionActions; @@ -716,7 +716,7 @@ private: ui64 DeviceInFlight; TFlightControl FlightControl; - TAtomicBlockCounter QuitCounter; + TAtomicBlockCounter QuitCounter; TString LastWarning; TDeque<IAsyncIoOperation*> Trash; TMutex TrashMutex; @@ -738,7 +738,7 @@ public: , SubmitThread(nullptr) , IsFileOpened(false) , IsInitialized(false) - , Reordering(reorderingCycles) + , Reordering(reorderingCycles) , SeekCostNs(seekCostNs) , IsTrimEnabled(true) , MaxQueuedCompletionActions(maxQueuedCompletionActions) diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_drivemodel.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_drivemodel.h index 2a0678dbd2..62fdde1ec8 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_drivemodel.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_drivemodel.h @@ -23,7 +23,7 @@ protected: ui64 SeekTimeNsec; ui64 BulkReadBlockSizeBytes; ui64 BulkWriteBlockSizeBytes; - ui64 TrimSpeedBps; + ui64 TrimSpeedBps; ui32 TotalChunksCount; ui64 SpeedBps[OP_TYPE_COUNT]; ui64 SpeedBpsMin[OP_TYPE_COUNT]; @@ -188,14 +188,14 @@ public: return (ui64)bytesToProcess * 1000000000ull / Speed(chunkIdx, type); } - ui64 TrimTimeForSizeNs(ui64 bytesToTrim) const { - return (ui64)bytesToTrim * 1000000000ull / TrimSpeedBps; - } - - bool IsTrimSupported() const { - return TrimSpeedBps > 0; - } - + ui64 TrimTimeForSizeNs(ui64 bytesToTrim) const { + return (ui64)bytesToTrim * 1000000000ull / TrimSpeedBps; + } + + bool IsTrimSupported() const { + return TrimSpeedBps > 0; + } + ui64 SizeForTimeNs(ui64 durationNs, ui32 chunkIdx, EOperationType type) const { return Speed(chunkIdx, type) * durationNs / 1000000000ull; } diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp index d00fc0f220..c0dfb678dd 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp @@ -2982,7 +2982,7 @@ void TPDisk::Update() { ui64 realDuration = HPNanoSeconds(nowCycles - ForsetiRealTimeCycles); ui64 virtualDuration = ForsetiTimeNs - ForsetiPrevTimeNs; ui64 timeCorrection = 0; - + if (virtualDuration < realDuration) { // Correct virtual time to catch up with real time. timeCorrection = realDuration - virtualDuration; @@ -2991,7 +2991,7 @@ void TPDisk::Update() { // Apply correction. ForsetiTimeNs += timeCorrection; } - + // Millibatch size in terms of virtual time ui64 maxDuration = DriveModel.TimeForSizeNs(milliBatchSize, TDriveModel::OP_TYPE_AVG); ui64 virtualDeadline = ForsetiTimeNs + maxDuration; diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.cpp index a514e261ab..7b42f7ac97 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.cpp @@ -7,7 +7,7 @@ namespace NKikimr { TPDiskMon::TPDiskMon(const TIntrusivePtr<NMonitoring::TDynamicCounters>& counters, ui32 pDiskId, TPDiskConfig *cfg) : Counters(counters) - , PDiskId(pDiskId) + , PDiskId(pDiskId) , ChunksGroup(Counters->GetSubgroup("subsystem", "chunks")) , StateGroup(Counters->GetSubgroup("subsystem", "state")) , DeviceGroup(Counters->GetSubgroup("subsystem", "device")) @@ -48,7 +48,7 @@ TPDiskMon::TPDiskMon(const TIntrusivePtr<NMonitoring::TDynamicCounters>& counter AtLeastOneVDiskNotLogged = StateGroup->GetCounter("AtLeastOneVDiskNotLogged"); TooMuchLogChunks = StateGroup->GetCounter("TooMuchLogChunks"); SerialNumberMismatched = StateGroup->GetCounter("SerialNumberMismatched"); - L6. Initialize(StateGroup, "L6"); + L6. Initialize(StateGroup, "L6"); L7. Initialize(StateGroup, "L7"); IdleLight.Initialize(StateGroup, "DeviceBusyPeriods", "DeviceIdleTimeMsPerSec", "DeviceBusyTimeMsPerSec"); @@ -125,12 +125,12 @@ TPDiskMon::TPDiskMon(const TIntrusivePtr<NMonitoring::TDynamicCounters>& counter WriteQueueHullHuge.Initialize(counters, "subsystem", "writeQueueHullHuge", "Time in millisec", percentiles); WriteQueueHullComp.Initialize(counters, "subsystem", "writeQueueHullComp", "Time in millisec", percentiles); - SensitiveBurst.Initialize(counters, "subsystem", "sensitiveBurst", "Time in millisec", percentiles); - BestEffortBurst.Initialize(counters, "subsystem", "bestEffortBurst", "Time in millisec", percentiles); - - InputQLA.Initialize(counters, "subsystem", "inputQLA", "Queue length seen by arrivals", percentiles); - InputQCA.Initialize(counters, "subsystem", "inputQCA", "Queue cost seen by arrivals", percentiles); + SensitiveBurst.Initialize(counters, "subsystem", "sensitiveBurst", "Time in millisec", percentiles); + BestEffortBurst.Initialize(counters, "subsystem", "bestEffortBurst", "Time in millisec", percentiles); + InputQLA.Initialize(counters, "subsystem", "inputQLA", "Queue length seen by arrivals", percentiles); + InputQCA.Initialize(counters, "subsystem", "inputQCA", "Queue cost seen by arrivals", percentiles); + LogOperationSizeBytes.Initialize(counters, "subsystem", "logOperationSize", "Size in bytes", percentiles); GetSyncLogSizeBytes.Initialize(counters, "subsystem", "getSyncLogSize", "Size in bytes", percentiles); @@ -219,7 +219,7 @@ TPDiskMon::TPDiskMon(const TIntrusivePtr<NMonitoring::TDynamicCounters>& counter } NMonitoring::TDynamicCounters::TCounterPtr TPDiskMon::GetBusyPeriod(const TString& owner, const TString& queue) { - return SchedulerGroup->GetCounter("SchedulerBusyPeriod_" + owner + "_" + queue, true); + return SchedulerGroup->GetCounter("SchedulerBusyPeriod_" + owner + "_" + queue, true); } void TPDiskMon::IncrementQueueTime(ui8 priorityClass, size_t timeMs) { @@ -344,11 +344,11 @@ void TPDiskMon::UpdatePercentileTrackers() { WriteQueueHullHuge.Update(); WriteQueueHullComp.Update(); - SensitiveBurst.Update(); - BestEffortBurst.Update(); + SensitiveBurst.Update(); + BestEffortBurst.Update(); - InputQLA.Update(); - InputQCA.Update(); + InputQLA.Update(); + InputQCA.Update(); } void TPDiskMon::UpdateLights() { @@ -357,7 +357,7 @@ void TPDiskMon::UpdateLights() { L6.Set(false, seqnoL6); } - L6. Update(); + L6. Update(); L7. Update(); IdleLight.Update(); } diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.h index 38a0f73b7c..4192679a12 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.h @@ -14,88 +14,88 @@ namespace NKikimr { struct TPDiskConfig; -inline NHPTimer::STime HPNow() { - NHPTimer::STime ret; - GetTimeFast(&ret); - return ret; -} - -inline double HPSecondsFloat(i64 cycles) { - if (cycles > 0) { - return double(cycles) / NHPTimer::GetClockRate(); - } else { - return 0.0; - } -} - +inline NHPTimer::STime HPNow() { + NHPTimer::STime ret; + GetTimeFast(&ret); + return ret; +} + +inline double HPSecondsFloat(i64 cycles) { + if (cycles > 0) { + return double(cycles) / NHPTimer::GetClockRate(); + } else { + return 0.0; + } +} + inline double HPMilliSecondsFloat(i64 cycles) { - if (cycles > 0) { + if (cycles > 0) { return double(cycles) * 1000.0 / NHPTimer::GetClockRate(); - } else { - return 0; - } -} - + } else { + return 0; + } +} + inline ui64 HPMilliSeconds(i64 cycles) { return (ui64)HPMilliSecondsFloat(cycles); } inline ui64 HPMicroSecondsFloat(i64 cycles) { - if (cycles > 0) { + if (cycles > 0) { return double(cycles) * 1000000.0 / NHPTimer::GetClockRate(); - } else { - return 0; - } -} - -inline ui64 HPMicroSeconds(i64 cycles) { + } else { + return 0; + } +} + +inline ui64 HPMicroSeconds(i64 cycles) { return (ui64)HPMicroSecondsFloat(cycles); -} - -inline ui64 HPNanoSeconds(i64 cycles) { - if (cycles > 0) { - return ui64(double(cycles) * 1000000000.0 / NHPTimer::GetClockRate()); - } else { - return 0; - } -} - -inline ui64 HPCyclesNs(ui64 ns) { - return ui64(NHPTimer::GetClockRate() * double(ns) / 1000000000.0); -} - -inline ui64 HPCyclesUs(ui64 us) { - return ui64(NHPTimer::GetClockRate() * double(us) / 1000000.0); -} - -inline ui64 HPCyclesMs(ui64 ms) { - return ui64(NHPTimer::GetClockRate() * double(ms) / 1000.0); -} - -class TLightBase { -protected: +} + +inline ui64 HPNanoSeconds(i64 cycles) { + if (cycles > 0) { + return ui64(double(cycles) * 1000000000.0 / NHPTimer::GetClockRate()); + } else { + return 0; + } +} + +inline ui64 HPCyclesNs(ui64 ns) { + return ui64(NHPTimer::GetClockRate() * double(ns) / 1000000000.0); +} + +inline ui64 HPCyclesUs(ui64 us) { + return ui64(NHPTimer::GetClockRate() * double(us) / 1000000.0); +} + +inline ui64 HPCyclesMs(ui64 ms) { + return ui64(NHPTimer::GetClockRate() * double(ms) / 1000.0); +} + +class TLightBase { +protected: TString Name; - NMonitoring::TDynamicCounters::TCounterPtr State; // Current state (0=OFF=green, 1=ON=red) - NMonitoring::TDynamicCounters::TCounterPtr Count; // Number of switches to ON state - NMonitoring::TDynamicCounters::TCounterPtr RedMs; // Time elapsed in ON state - NMonitoring::TDynamicCounters::TCounterPtr GreenMs; // Time elapsed in OFF state + NMonitoring::TDynamicCounters::TCounterPtr State; // Current state (0=OFF=green, 1=ON=red) + NMonitoring::TDynamicCounters::TCounterPtr Count; // Number of switches to ON state + NMonitoring::TDynamicCounters::TCounterPtr RedMs; // Time elapsed in ON state + NMonitoring::TDynamicCounters::TCounterPtr GreenMs; // Time elapsed in OFF state private: - ui64 RedCycles = 0; - ui64 GreenCycles = 0; - NHPTimer::STime AdvancedTill = 0; - NHPTimer::STime LastNow = 0; - ui64 UpdateThreshold = 0; -public: + ui64 RedCycles = 0; + ui64 GreenCycles = 0; + NHPTimer::STime AdvancedTill = 0; + NHPTimer::STime LastNow = 0; + ui64 UpdateThreshold = 0; +public: void Initialize(TIntrusivePtr<NMonitoring::TDynamicCounters>& counters, const TString& name) { - Name = name; - State = counters->GetCounter(name + "_state"); - Count = counters->GetCounter(name + "_count", true); - RedMs = counters->GetCounter(name + "_redMs", true); - GreenMs = counters->GetCounter(name + "_greenMs", true); - UpdateThreshold = HPCyclesMs(100); - AdvancedTill = Now(); - } - + Name = name; + State = counters->GetCounter(name + "_state"); + Count = counters->GetCounter(name + "_count", true); + RedMs = counters->GetCounter(name + "_redMs", true); + GreenMs = counters->GetCounter(name + "_greenMs", true); + UpdateThreshold = HPCyclesMs(100); + AdvancedTill = Now(); + } + void Initialize(TIntrusivePtr<NMonitoring::TDynamicCounters>& counters, const TString& countName, const TString& redMsName,const TString& greenMsName) { Count = counters->GetCounter(countName, true); @@ -105,205 +105,205 @@ public: AdvancedTill = Now(); } - ui64 GetCount() const { - return *Count; - } - - ui64 GetRedMs() const { - return *RedMs; - } - - ui64 GetGreenMs() const { - return *GreenMs; - } -protected: - void Modify(bool state, bool prevState) { - if (state && !prevState) { // Switched to ON state + ui64 GetCount() const { + return *Count; + } + + ui64 GetRedMs() const { + return *RedMs; + } + + ui64 GetGreenMs() const { + return *GreenMs; + } +protected: + void Modify(bool state, bool prevState) { + if (state && !prevState) { // Switched to ON state if (State) { *State = true; } - (*Count)++; - return; - } - if (!state && prevState) { // Switched to OFF state + (*Count)++; + return; + } + if (!state && prevState) { // Switched to OFF state if (State) { *State = false; } - return; - } - } - - void Advance(bool state, NHPTimer::STime now) { - if (now == AdvancedTill) { - return; - } - Elapsed(state, now - AdvancedTill); - if (RedCycles > UpdateThreshold) { - *RedMs += CutMs(RedCycles); - } - if (GreenCycles > UpdateThreshold) { - *GreenMs += CutMs(GreenCycles); - } - AdvancedTill = now; - } - - NHPTimer::STime Now() { - // Avoid time going backwards - NHPTimer::STime now = HPNow(); - if (now < LastNow) { - now = LastNow; - } - LastNow = now; - return now; - } -private: - void Elapsed(bool state, ui64 cycles) { - if (state) { - RedCycles += cycles; - } else { - GreenCycles += cycles; - } - } - - ui64 CutMs(ui64& src) { - ui64 ms = HPMilliSeconds(src); - ui64 cycles = HPCyclesMs(ms); - src -= cycles; - return ms; - } -}; - -// Thread-safe light -class TLight : public TLightBase { -private: - struct TItem { - bool State; - bool Filled; - TItem(bool state = false, bool filled = false) - : State(state) - , Filled(filled) - {} - }; - - // Cyclic buffer to enforce event ordering by seqno - TSpinLock Lock; - size_t HeadIdx = 0; // Index of current state - size_t FilledCount = 0; - ui16 Seqno = 0; // Current seqno - TStackVec<TItem, 32> Data; // In theory should have not more than thread count items -public: - TLight() { - InitData(); - } - - void Set(bool state, ui16 seqno) { - TGuard<TSpinLock> g(Lock); - Push(state, seqno); - bool prevState; - // Note that 'state' variable is being reused - NHPTimer::STime now = Now(); - while (Pop(state, prevState)) { - Modify(state, prevState); - Advance(prevState, now); - } - } - - void Update() { - TGuard<TSpinLock> g(Lock); - Advance(Data[HeadIdx].State, Now()); - } - -private: - void InitData(bool state = false, bool filled = false) { - Data.clear(); - Data.emplace_back(state, filled); - Data.resize(32); - HeadIdx = 0; - } - - void Push(bool state, ui16 seqno) { - FilledCount++; - if (FilledCount == 1) { // First event must initialize seqno - Seqno = seqno; - InitData(state, true); - if (state) { - Modify(true, false); - } - return; - } - Y_VERIFY(seqno != Seqno, "ordering overflow or duplicate event headSeqno# %d seqno# %d state# %d filled# %d", - (int)Seqno, (int)seqno, (int)state, (int)CountFilled()); - ui16 diff = seqno; - diff -= Seqno; // Underflow is fine - size_t size = Data.size(); - if (size <= diff) { // Buffer is full -- extend and move wrapped part - Data.resize(size * 2); - for (size_t i = 0; i < HeadIdx; i++) { - Data[size + i] = Data[i]; - Data[i].Filled = false; - } - } - TItem& item = Data[(HeadIdx + diff) % Data.size()]; - Y_VERIFY(!item.Filled, "ordering overflow or duplicate event headSeqno# %d seqno# %d state# %d filled# %d", - (int)Seqno, (int)seqno, (int)state, (int)CountFilled()); - item.Filled = true; - item.State = state; - } - - bool Pop(bool& state, bool& prevState) { - size_t nextIdx = (HeadIdx + 1) % Data.size(); - TItem& head = Data[HeadIdx]; - TItem& next = Data[nextIdx]; - if (!head.Filled || !next.Filled) { - return false; - } - state = next.State; - prevState = head.State; - head.Filled = false; - HeadIdx = nextIdx; - Seqno++; // Overflow is fine - FilledCount--; - if (FilledCount == 1 && Data.size() > 32) { + return; + } + } + + void Advance(bool state, NHPTimer::STime now) { + if (now == AdvancedTill) { + return; + } + Elapsed(state, now - AdvancedTill); + if (RedCycles > UpdateThreshold) { + *RedMs += CutMs(RedCycles); + } + if (GreenCycles > UpdateThreshold) { + *GreenMs += CutMs(GreenCycles); + } + AdvancedTill = now; + } + + NHPTimer::STime Now() { + // Avoid time going backwards + NHPTimer::STime now = HPNow(); + if (now < LastNow) { + now = LastNow; + } + LastNow = now; + return now; + } +private: + void Elapsed(bool state, ui64 cycles) { + if (state) { + RedCycles += cycles; + } else { + GreenCycles += cycles; + } + } + + ui64 CutMs(ui64& src) { + ui64 ms = HPMilliSeconds(src); + ui64 cycles = HPCyclesMs(ms); + src -= cycles; + return ms; + } +}; + +// Thread-safe light +class TLight : public TLightBase { +private: + struct TItem { + bool State; + bool Filled; + TItem(bool state = false, bool filled = false) + : State(state) + , Filled(filled) + {} + }; + + // Cyclic buffer to enforce event ordering by seqno + TSpinLock Lock; + size_t HeadIdx = 0; // Index of current state + size_t FilledCount = 0; + ui16 Seqno = 0; // Current seqno + TStackVec<TItem, 32> Data; // In theory should have not more than thread count items +public: + TLight() { + InitData(); + } + + void Set(bool state, ui16 seqno) { + TGuard<TSpinLock> g(Lock); + Push(state, seqno); + bool prevState; + // Note that 'state' variable is being reused + NHPTimer::STime now = Now(); + while (Pop(state, prevState)) { + Modify(state, prevState); + Advance(prevState, now); + } + } + + void Update() { + TGuard<TSpinLock> g(Lock); + Advance(Data[HeadIdx].State, Now()); + } + +private: + void InitData(bool state = false, bool filled = false) { + Data.clear(); + Data.emplace_back(state, filled); + Data.resize(32); + HeadIdx = 0; + } + + void Push(bool state, ui16 seqno) { + FilledCount++; + if (FilledCount == 1) { // First event must initialize seqno + Seqno = seqno; InitData(state, true); - } - return true; - } - - size_t CountFilled() const { - size_t ret = 0; - for (const TItem& item : Data) { - ret += item.Filled; - } - return ret; - } -}; - -class TBurstmeter { -private: - TBucketQuoter<i64, TSpinLock, THPTimerUs> Bucket; + if (state) { + Modify(true, false); + } + return; + } + Y_VERIFY(seqno != Seqno, "ordering overflow or duplicate event headSeqno# %d seqno# %d state# %d filled# %d", + (int)Seqno, (int)seqno, (int)state, (int)CountFilled()); + ui16 diff = seqno; + diff -= Seqno; // Underflow is fine + size_t size = Data.size(); + if (size <= diff) { // Buffer is full -- extend and move wrapped part + Data.resize(size * 2); + for (size_t i = 0; i < HeadIdx; i++) { + Data[size + i] = Data[i]; + Data[i].Filled = false; + } + } + TItem& item = Data[(HeadIdx + diff) % Data.size()]; + Y_VERIFY(!item.Filled, "ordering overflow or duplicate event headSeqno# %d seqno# %d state# %d filled# %d", + (int)Seqno, (int)seqno, (int)state, (int)CountFilled()); + item.Filled = true; + item.State = state; + } + + bool Pop(bool& state, bool& prevState) { + size_t nextIdx = (HeadIdx + 1) % Data.size(); + TItem& head = Data[HeadIdx]; + TItem& next = Data[nextIdx]; + if (!head.Filled || !next.Filled) { + return false; + } + state = next.State; + prevState = head.State; + head.Filled = false; + HeadIdx = nextIdx; + Seqno++; // Overflow is fine + FilledCount--; + if (FilledCount == 1 && Data.size() > 32) { + InitData(state, true); + } + return true; + } + + size_t CountFilled() const { + size_t ret = 0; + for (const TItem& item : Data) { + ret += item.Filled; + } + return ret; + } +}; + +class TBurstmeter { +private: + TBucketQuoter<i64, TSpinLock, THPTimerUs> Bucket; NMonitoring::TPercentileTrackerLg<5, 4, 15> Tracker; -public: - TBurstmeter() - : Bucket(1000ull * 1000ull * 1000ull, 0) - {} - - void Initialize(const TIntrusivePtr<NMonitoring::TDynamicCounters> &counters, +public: + TBurstmeter() + : Bucket(1000ull * 1000ull * 1000ull, 0) + {} + + void Initialize(const TIntrusivePtr<NMonitoring::TDynamicCounters> &counters, const TString& group, const TString& subgroup, const TString& name, const TVector<float> &thresholds) { - Tracker.Initialize(counters, group, subgroup, name, thresholds); - } - - double Increment(ui64 tokens) { - double burst = -double(Bucket.UseAndFill(tokens)) / (1000000ull); - Tracker.Increment(burst); - return burst; - } - - void Update() { - Tracker.Update(); - } -}; - + Tracker.Initialize(counters, group, subgroup, name, thresholds); + } + + double Increment(ui64 tokens) { + double burst = -double(Bucket.UseAndFill(tokens)) / (1000000ull); + Tracker.Increment(burst); + return burst; + } + + void Update() { + Tracker.Update(); + } +}; + class THistogram { private: NMonitoring::THistogramPtr Histo; @@ -475,7 +475,7 @@ struct TPDiskMon { }; TIntrusivePtr<NMonitoring::TDynamicCounters> Counters; - ui32 PDiskId; + ui32 PDiskId; // chunk states subgroup TIntrusivePtr<NMonitoring::TDynamicCounters> ChunksGroup; @@ -578,18 +578,18 @@ struct TPDiskMon { TDurationTracker WriteQueueHullHuge; TDurationTracker WriteQueueHullComp; - // incoming flow burstiness - TBurstmeter SensitiveBurst; - TBurstmeter BestEffortBurst; - - // queue length seen by arriving request in front of it (QLA = Queue Length at Arrival) + // incoming flow burstiness + TBurstmeter SensitiveBurst; + TBurstmeter BestEffortBurst; + + // queue length seen by arriving request in front of it (QLA = Queue Length at Arrival) using TQLATracker = NMonitoring::TPercentileTrackerLg<5, 4, 15>; - TQLATracker InputQLA; // for PDisk.InputQueue - - // queue cost seen by arriving request in front of it (QCA = Queue Cost at Arrival) + TQLATracker InputQLA; // for PDisk.InputQueue + + // queue cost seen by arriving request in front of it (QCA = Queue Cost at Arrival) using TQCATracker = NMonitoring::TPercentileTrackerLg<5, 4, 15>; - TQCATracker InputQCA; // for PDisk.InputQueue - + TQCATracker InputQCA; // for PDisk.InputQueue + // log cumulative size bytes // <BASE_BITS, EXP_BITS, FRAME_COUNT> using TSizeTracker = NMonitoring::TPercentileTrackerLg<5, 4, 15>; @@ -616,7 +616,7 @@ struct TPDiskMon { THistogram GetResponseHullOnlineOther; THistogram GetResponseHullLoad; THistogram GetResponseHullLow; - // write response time + // write response time THistogram WriteResponseSyncLog; THistogram WriteResponseHullFresh; THistogram WriteResponseHullHuge; diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_requestimpl.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_requestimpl.h index 61c0996e08..9147eef353 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_requestimpl.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_requestimpl.h @@ -5,7 +5,7 @@ #include "blobstorage_pdisk_data.h" #include "blobstorage_pdisk_drivemodel.h" #include "blobstorage_pdisk_internal_interface.h" -#include "blobstorage_pdisk_mon.h" +#include "blobstorage_pdisk_mon.h" #include "blobstorage_pdisk_request_id.h" #include <ydb/core/blobstorage/base/vdisk_priorities.h> @@ -29,7 +29,7 @@ enum class EOwnerGroupType { // class TRequestBase : public TThrRefBase { public: - // Identification + // Identification const TActorId Sender; const TReqId ReqId; TOwner Owner; @@ -37,37 +37,37 @@ public: ui8 PriorityClass; EOwnerGroupType OwnerGroupType; - // Classification - ui64 TotalCost = 0; // Total request cost in nanoseconds + // Classification + ui64 TotalCost = 0; // Total request cost in nanoseconds ui8 GateId = 0; - bool IsSensitive = false; // QoS: sensitive or best-effort - bool IsFast = false; // QoS: best-effort with improved latency - - // Scheduling - NHPTimer::STime Deadline = 0; // Deadline from request input to rt-scheduler - ui64 Cost = 0; // Remaining cost in nanoseconds + bool IsSensitive = false; // QoS: sensitive or best-effort + bool IsFast = false; // QoS: best-effort with improved latency + + // Scheduling + NHPTimer::STime Deadline = 0; // Deadline from request input to rt-scheduler + ui64 Cost = 0; // Remaining cost in nanoseconds NSchLab::EJobKind JobKind = NSchLab::EJobKind::JobKindRequest; - - // Monitoring - const NHPTimer::STime CreationTime; - NHPTimer::STime InputTime = 0; // Time of entrance to rt-scheduler + + // Monitoring + const NHPTimer::STime CreationTime; + NHPTimer::STime InputTime = 0; // Time of entrance to rt-scheduler NHPTimer::STime ScheduleTime = 0; - - // Tracing + + // Tracing mutable NWilson::TTraceId TraceId; - mutable NLWTrace::TOrbit Orbit; -public: + mutable NLWTrace::TOrbit Orbit; +public: TRequestBase(const TActorId &sender, TReqId reqId, TOwner owner, TOwnerRound ownerRound, ui8 priorityClass, NWilson::TTraceId traceId = {}) : Sender(sender) - , ReqId(reqId) + , ReqId(reqId) , Owner(owner) , OwnerRound(ownerRound) , PriorityClass(priorityClass) , OwnerGroupType(EOwnerGroupType::Dynamic) - , CreationTime(HPNow()) + , CreationTime(HPNow()) , TraceId(std::move(traceId)) - {} + {} void SetOwnerGroupType(bool isStaticGroupOwner) { OwnerGroupType = (isStaticGroupOwner ? EOwnerGroupType::Static : EOwnerGroupType::Dynamic); @@ -88,26 +88,26 @@ public: return HPMilliSecondsFloat(now - CreationTime); } - ui64 GetCost() const { + ui64 GetCost() const { return Cost; } - ui64 GetCostCycles() const { - return HPCyclesNs(Cost); - } - - // Takes slack (duration free to do non-sensitive requests) - // and reserve it or part of it for this request execution - // On return slack contains: - // - slack duration left after reservation - // - or TDuration::Zero() if all available slack was reserved - // Returns true if reservation has occured, false otherwise - virtual bool TryStealSlack(ui64& slackNs, const TDriveModel &drive, ui64 appendBlockSize, bool adhesion) { - // Default implementation appropriate for all sensitive requests - // Must be overriden for best-effort requests - Y_UNUSED(slackNs); Y_UNUSED(drive); Y_UNUSED(appendBlockSize); Y_UNUSED(adhesion); - return true; - } + ui64 GetCostCycles() const { + return HPCyclesNs(Cost); + } + + // Takes slack (duration free to do non-sensitive requests) + // and reserve it or part of it for this request execution + // On return slack contains: + // - slack duration left after reservation + // - or TDuration::Zero() if all available slack was reserved + // Returns true if reservation has occured, false otherwise + virtual bool TryStealSlack(ui64& slackNs, const TDriveModel &drive, ui64 appendBlockSize, bool adhesion) { + // Default implementation appropriate for all sensitive requests + // Must be overriden for best-effort requests + Y_UNUSED(slackNs); Y_UNUSED(drive); Y_UNUSED(appendBlockSize); Y_UNUSED(adhesion); + return true; + } static void AbortDelete(TRequestBase* request, TActorSystem* actorSystem); }; @@ -257,7 +257,7 @@ public: ui32 EstimatedChunkIdx; TString Data; ui64 LsnSegmentStart; // Additional data, for sanity checks only. - ui64 Lsn; // Log sequence number + ui64 Lsn; // Log sequence number void *Cookie; TCallback LogCallback; NPDisk::TCommitRecord CommitRecord; @@ -331,12 +331,12 @@ public: ui64 RemainingSize; TCompletionChunkRead *FinalCompletion = nullptr; TAtomicBase Index; - bool IsReplied = false; + bool IsReplied = false; ui64 SlackSize; ui64 FirstSector = 0; ui64 LastSector = 0; - + // Request is placed in scheduler's queues as raw pointer. To avoid deletion // in such situation request will take owning to self when pushed to // scheduler and drop owning when poped from scheduler @@ -351,7 +351,7 @@ public: , Size(ev.Size) , Cookie(ev.Cookie) , RemainingSize(ev.Size) - , SlackSize(Max<ui32>()) + , SlackSize(Max<ui32>()) , DoubleFreeCanary(ReferenceCanary) { Index = AtomicIncrement(LastIndex); @@ -378,19 +378,19 @@ public: } bool TryStealSlack(ui64& slackNs, const TDriveModel &drive, ui64 appendBlockSize, bool adhesion) override { - Y_UNUSED(appendBlockSize); Y_UNUSED(adhesion); - // Calculate how many bytes can we read within given slack (with single seek) + Y_UNUSED(appendBlockSize); Y_UNUSED(adhesion); + // Calculate how many bytes can we read within given slack (with single seek) SlackSize = (ui32)drive.SizeForTimeNs(slackNs > drive.SeekTimeNs()? slackNs - drive.SeekTimeNs(): 0, ChunkIdx, TDriveModel::OP_TYPE_READ); if (SlackSize > 0) { // TODO[serxa]: actually there is some lower bound, // because we are not reading less than some number of bytes - SlackSize = Min(SlackSize, RemainingSize); + SlackSize = Min(SlackSize, RemainingSize); ui64 costNs = drive.SeekTimeNs() + drive.TimeForSizeNs((ui64)SlackSize, ChunkIdx, TDriveModel::OP_TYPE_READ); - slackNs -= costNs; - return true; - } else { - return false; - } + slackNs -= costNs; + return true; + } else { + return false; + } } }; @@ -446,15 +446,15 @@ public: bool IsReplied = false; ui32 TotalSize; - ui32 CurrentPart = 0; - ui32 CurrentPartOffset = 0; - ui32 RemainingSize = 0; + ui32 CurrentPart = 0; + ui32 CurrentPartOffset = 0; + ui32 RemainingSize = 0; ui32 UnenqueuedSize; TAtomicBase Index; - ui32 SlackSize; + ui32 SlackSize; ui32 BytesWritten = 0; - + THolder<NPDisk::TCompletionAction> Completion; TChunkWrite(const NPDisk::TEvChunkWrite &ev, const TActorId &sender, TReqId reqId, NWilson::TTraceId traceId) @@ -474,7 +474,7 @@ public: } TotalSize = RemainingSize; UnenqueuedSize = RemainingSize; - SlackSize = Max<ui32>(); + SlackSize = Max<ui32>(); } ERequestType GetType() const override { @@ -485,17 +485,17 @@ public: Cost = drive.SeekTimeNs() + drive.TimeForSizeNs((ui64)UnenqueuedSize, ChunkIdx, TDriveModel::OP_TYPE_WRITE); } - bool IsFinalIteration() { - return UnenqueuedSize <= SlackSize; + bool IsFinalIteration() { + return UnenqueuedSize <= SlackSize; } - + bool IsTotallyEnqueued() { return UnenqueuedSize == 0; } bool TryStealSlack(ui64& slackNs, const TDriveModel &drive, ui64 appendBlockSize, bool adhesion) override { - // Calculate how many bytes can we write within given slack (with single seek) - // TODO[serxa]: use write speed? but there is no write speed in drive model! + // Calculate how many bytes can we write within given slack (with single seek) + // TODO[serxa]: use write speed? but there is no write speed in drive model! SlackSize = (ui32)drive.SizeForTimeNs(slackNs > drive.SeekTimeNs()? slackNs - drive.SeekTimeNs(): 0, ChunkIdx, TDriveModel::OP_TYPE_WRITE); // actually there is some lower bound, because we are not writing less than appendBlockSize bytes @@ -504,15 +504,15 @@ public: SlackSize / appendBlockSize * appendBlockSize, (UnenqueuedSize + appendBlockSize - 1) / appendBlockSize * appendBlockSize); ui64 costNs = (adhesion? 0: drive.SeekTimeNs()) + drive.TimeForSizeNs((ui64)SlackSize, ChunkIdx, TDriveModel::OP_TYPE_WRITE); - slackNs -= costNs; - return true; - } else { - return false; - } - } + slackNs -= costNs; + return true; + } else { + return false; + } + } }; -// +// // TChunkWritePiece // class TChunkWritePiece : public TRequestBase { @@ -539,41 +539,41 @@ public: }; // -// TChunkTrim -// -class TChunkTrim : public TRequestBase { -public: - ui32 ChunkIdx; - ui32 Offset; - ui64 Size; +// TChunkTrim +// +class TChunkTrim : public TRequestBase { +public: + ui32 ChunkIdx; + ui32 Offset; + ui64 Size; TChunkTrim(ui32 chunkIdx, ui32 offset, ui64 size, TAtomicBase reqIdx) : TRequestBase(TActorId(), TReqId(TReqId::ChunkTrim, reqIdx), OwnerUnallocated, TOwnerRound(0), NPriInternal::Trim) - , ChunkIdx(chunkIdx) - , Offset(offset) - , Size(size) - {} - + , ChunkIdx(chunkIdx) + , Offset(offset) + , Size(size) + {} + ERequestType GetType() const override { - return ERequestType::RequestChunkTrim; - } - - void EstimateCost(const TDriveModel &drive) override { - Cost = drive.TrimTimeForSizeNs(Size); - } - + return ERequestType::RequestChunkTrim; + } + + void EstimateCost(const TDriveModel &drive) override { + Cost = drive.TrimTimeForSizeNs(Size); + } + bool TryStealSlack(ui64& slackNs, const TDriveModel &drive, ui64 appendBlockSize, bool adhesion) override { - Y_UNUSED(drive); Y_UNUSED(appendBlockSize); Y_UNUSED(adhesion); - if (slackNs > Cost) { - slackNs -= Cost; - return true; - } else { - return true; - } - } -}; - - + Y_UNUSED(drive); Y_UNUSED(appendBlockSize); Y_UNUSED(adhesion); + if (slackNs > Cost) { + slackNs -= Cost; + return true; + } else { + return true; + } + } +}; + + // // THarakiri // diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_atomicblockcounter.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_atomicblockcounter.cpp index 3ea3033b19..963cd7254c 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_atomicblockcounter.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_atomicblockcounter.cpp @@ -1,40 +1,40 @@ -#include "blobstorage_pdisk_util_atomicblockcounter.h" +#include "blobstorage_pdisk_util_atomicblockcounter.h" namespace NKikimr { namespace NPDisk { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// TAtomicBlockCounter +// TAtomicBlockCounter //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool TAtomicBlockCounter::IsBlocked() const noexcept { - return GetBlocked(AtomicGet(Data)); -} + return GetBlocked(AtomicGet(Data)); +} void TAtomicBlockCounter::Block(ui64 flag, TResult& res) noexcept { - while (true) { - ui64 prevData = AtomicGet(Data); - if (prevData & flag) { - FillResult(prevData, prevData, res); - return; // Already blocked - } - ui64 data = NextSeqno(prevData | flag); - if (AtomicCas(&Data, data, prevData)) { - FillResult(prevData, data, res); - return; - } - } + while (true) { + ui64 prevData = AtomicGet(Data); + if (prevData & flag) { + FillResult(prevData, prevData, res); + return; // Already blocked + } + ui64 data = NextSeqno(prevData | flag); + if (AtomicCas(&Data, data, prevData)) { + FillResult(prevData, data, res); + return; + } + } } void TAtomicBlockCounter::Unblock(ui64 flag, TResult& res) noexcept { - while (true) { + while (true) { ui64 prevData = AtomicGet(Data); - if (!(prevData & flag)) { - FillResult(prevData, prevData, res); - return; // Already unblocked - } - ui64 data = NextSeqno(prevData & ~flag); - if (AtomicCas(&Data, data, prevData)) { - FillResult(prevData, data, res); + if (!(prevData & flag)) { + FillResult(prevData, prevData, res); + return; // Already unblocked + } + ui64 data = NextSeqno(prevData & ~flag); + if (AtomicCas(&Data, data, prevData)) { + FillResult(prevData, data, res); return; } } @@ -42,122 +42,122 @@ void TAtomicBlockCounter::Unblock(ui64 flag, TResult& res) noexcept { ui64 TAtomicBlockCounter::Add(ui64 value) noexcept { Y_VERIFY_S(value > 0, "zero value# " << value); - while (true) { + while (true) { ui64 prevData = AtomicGet(Data); - if (GetBlocked(prevData)) { - return 0; // Add is forbidden iff blocked - } - ui64 data = NextSeqno(CheckedAddCounter(prevData, value)); - if (AtomicCas(&Data, data, prevData)) { - return GetCounter(data); - } - } -} - + if (GetBlocked(prevData)) { + return 0; // Add is forbidden iff blocked + } + ui64 data = NextSeqno(CheckedAddCounter(prevData, value)); + if (AtomicCas(&Data, data, prevData)) { + return GetCounter(data); + } + } +} + ui64 TAtomicBlockCounter::Sub(ui64 value) noexcept { Y_VERIFY_S(value > 0, "zero value# " << value); - while (true) { - ui64 prevData = AtomicGet(Data); - ui64 data = NextSeqno(CheckedSubCounter(prevData, value)); - if (AtomicCas(&Data, data, prevData)) { - return GetCounter(data); - } - } -} - + while (true) { + ui64 prevData = AtomicGet(Data); + ui64 data = NextSeqno(CheckedSubCounter(prevData, value)); + if (AtomicCas(&Data, data, prevData)) { + return GetCounter(data); + } + } +} + ui64 TAtomicBlockCounter::ThresholdAdd(ui64 value, ui64 threshold, TAtomicBlockCounter::TResult& res) noexcept { Y_VERIFY_S(value > 0, "zero value# " << value); - while (true) { - ui64 prevData = AtomicGet(Data); - if (GetBlocked(prevData)) { // Add is forbidden iff blocked - FillResult(prevData, prevData, res); + while (true) { + ui64 prevData = AtomicGet(Data); + if (GetBlocked(prevData)) { // Add is forbidden iff blocked + FillResult(prevData, prevData, res); return 0; } - ui64 data = NextSeqno(ThresholdBlock(CheckedAddCounter(prevData, value), threshold)); - if (AtomicCas(&Data, data, prevData)) { - FillResult(prevData, data, res); - return GetCounter(data); - } + ui64 data = NextSeqno(ThresholdBlock(CheckedAddCounter(prevData, value), threshold)); + if (AtomicCas(&Data, data, prevData)) { + FillResult(prevData, data, res); + return GetCounter(data); + } } } ui64 TAtomicBlockCounter::ThresholdSub(ui64 value, ui64 threshold, TAtomicBlockCounter::TResult& res) noexcept { Y_VERIFY_S(value > 0, "zero value# " << value); - while (true) { + while (true) { ui64 prevData = AtomicGet(Data); - ui64 data = NextSeqno(ThresholdBlock(CheckedSubCounter(prevData, value), threshold)); - if (AtomicCas(&Data, data, prevData)) { - FillResult(prevData, data, res); - return GetCounter(data); - } + ui64 data = NextSeqno(ThresholdBlock(CheckedSubCounter(prevData, value), threshold)); + if (AtomicCas(&Data, data, prevData)) { + FillResult(prevData, data, res); + return GetCounter(data); + } } -} - +} + ui64 TAtomicBlockCounter::ThresholdUpdate(ui64 threshold, TAtomicBlockCounter::TResult& res) noexcept { - while (true) { - ui64 prevData = AtomicGet(Data); - ui64 data = NextSeqno(ThresholdBlock(prevData, threshold)); - if (AtomicCas(&Data, data, prevData)) { - FillResult(prevData, data, res); - return GetCounter(data); - } - } -} - + while (true) { + ui64 prevData = AtomicGet(Data); + ui64 data = NextSeqno(ThresholdBlock(prevData, threshold)); + if (AtomicCas(&Data, data, prevData)) { + FillResult(prevData, data, res); + return GetCounter(data); + } + } +} + ui64 TAtomicBlockCounter::Get() const noexcept { - return GetCounter(AtomicGet(Data)); -} - + return GetCounter(AtomicGet(Data)); +} + ui64 TAtomicBlockCounter::CheckedAddCounter(ui64 prevData, ui64 value) noexcept { Y_VERIFY_S(!(value & ~CounterMask), "invalid value# " << value); Y_VERIFY_S(!((GetCounter(prevData) + value) & ~CounterMask), "overflow value# " << value << " prevData# " << GetCounter(prevData)); - return prevData + value; // No overflow, so higher bits are untouched -} - + return prevData + value; // No overflow, so higher bits are untouched +} + ui64 TAtomicBlockCounter::CheckedSubCounter(ui64 prevData, ui64 value) noexcept { Y_VERIFY_S(!(value & ~CounterMask), "invalid value# " << value); Y_VERIFY_S(!((GetCounter(prevData) - value) & ~CounterMask), "underflow value# " << value << " prevData# " << GetCounter(prevData)); - return prevData - value; // No underflow, so higher bits are untouched -} - + return prevData - value; // No underflow, so higher bits are untouched +} + void TAtomicBlockCounter::FillResult(ui64 prevData, ui64 data, TAtomicBlockCounter::TResult& res) noexcept { - res.PrevA = prevData & BlockAFlag; - res.PrevB = prevData & BlockBFlag; - res.A = data & BlockAFlag; - res.B = data & BlockBFlag; - res.Seqno = GetSeqno(data); - res.PrevSeqno = GetSeqno(prevData); -} - + res.PrevA = prevData & BlockAFlag; + res.PrevB = prevData & BlockBFlag; + res.A = data & BlockAFlag; + res.B = data & BlockBFlag; + res.Seqno = GetSeqno(data); + res.PrevSeqno = GetSeqno(prevData); +} + bool TAtomicBlockCounter::GetBlocked(ui64 data) noexcept { - return data & BlockMask; -} - + return data & BlockMask; +} + ui16 TAtomicBlockCounter::GetSeqno(ui64 data) noexcept { - return (data & SeqnoMask) >> SeqnoShift; -} - + return (data & SeqnoMask) >> SeqnoShift; +} + ui64 TAtomicBlockCounter::GetCounter(ui64 data) noexcept { return data & CounterMask; } ui64 TAtomicBlockCounter::ThresholdBlock(ui64 data, ui64 threshold) noexcept { - if (GetCounter(data) > threshold) { - return data | BlockAFlag; - } else { - return data & ~BlockAFlag; - } + if (GetCounter(data) > threshold) { + return data | BlockAFlag; + } else { + return data & ~BlockAFlag; + } } ui64 TAtomicBlockCounter::NextSeqno(ui64 data) noexcept { - if (GetSeqno(data) == Max<ui16>()) { // Overflow case - return data & ~SeqnoMask; - } else { // No overflow case - return data + (1ull << SeqnoShift); - } -} - + if (GetSeqno(data) == Max<ui16>()) { // Overflow case + return data & ~SeqnoMask; + } else { // No overflow case + return data + (1ull << SeqnoShift); + } +} + } // NPDisk } // NKikimr diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_atomicblockcounter.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_atomicblockcounter.h index 4991facc94..6c16faae5a 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_atomicblockcounter.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_atomicblockcounter.h @@ -5,96 +5,96 @@ namespace NKikimr { namespace NPDisk { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// TAtomicBlockCounter +// TAtomicBlockCounter //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct TAtomicBlockCounter { - TAtomic Data = 0; - - static constexpr ui64 BlockAFlag = (1ull << 63ull); - static constexpr ui64 BlockBFlag = (1ull << 62ull); - static constexpr ui64 BlockMask = BlockAFlag | BlockBFlag; - static constexpr ui64 SeqnoShift = 46ull; - static constexpr ui64 SeqnoMask = (0xFFFFull << SeqnoShift); - static constexpr ui64 CounterMask = ~(BlockMask|SeqnoMask); - - struct TResult { - bool PrevA = false; // Block A state before operation - bool PrevB = false; // Block B state before operation - bool A = false; // Block A state after operation - bool B = false; // Block B state after operation - ui16 Seqno = 0; - ui16 PrevSeqno = 0; +struct TAtomicBlockCounter { + TAtomic Data = 0; + + static constexpr ui64 BlockAFlag = (1ull << 63ull); + static constexpr ui64 BlockBFlag = (1ull << 62ull); + static constexpr ui64 BlockMask = BlockAFlag | BlockBFlag; + static constexpr ui64 SeqnoShift = 46ull; + static constexpr ui64 SeqnoMask = (0xFFFFull << SeqnoShift); + static constexpr ui64 CounterMask = ~(BlockMask|SeqnoMask); + + struct TResult { + bool PrevA = false; // Block A state before operation + bool PrevB = false; // Block B state before operation + bool A = false; // Block A state after operation + bool B = false; // Block B state after operation + ui16 Seqno = 0; + ui16 PrevSeqno = 0; bool Toggled() const noexcept { - return WasBlocked() ^ IsBlocked(); - } - + return WasBlocked() ^ IsBlocked(); + } + bool WasBlocked() const noexcept { - return PrevA || PrevB; - } - + return PrevA || PrevB; + } + bool IsBlocked() const noexcept { - return A || B; - } - }; - + return A || B; + } + }; + TAtomicBlockCounter() noexcept {} - + bool IsBlocked() const noexcept; - - // Blocking + + // Blocking void Block(ui64 flag, TResult& res) noexcept; void BlockA() noexcept { - TResult res; - Block(BlockAFlag, res); - } + TResult res; + Block(BlockAFlag, res); + } void BlockB() noexcept { - TResult res; - Block(BlockBFlag, res); - } + TResult res; + Block(BlockBFlag, res); + } void BlockA(TResult& res) noexcept { - Block(BlockAFlag, res); - } + Block(BlockAFlag, res); + } void BlockB(TResult& res) noexcept { - Block(BlockBFlag, res); - } - - // Unblocking + Block(BlockBFlag, res); + } + + // Unblocking void Unblock(ui64 flag, TResult& res) noexcept; void UnblockA() noexcept { - TResult res; - Unblock(BlockAFlag, res); - } + TResult res; + Unblock(BlockAFlag, res); + } void UnblockB() noexcept { - TResult res; - Unblock(BlockBFlag, res); - } + TResult res; + Unblock(BlockBFlag, res); + } void UnblockA(TResult& res) noexcept { - Unblock(BlockAFlag, res); - } + Unblock(BlockAFlag, res); + } void UnblockB(TResult& res) noexcept { - Unblock(BlockBFlag, res); - } - - // Returns counter on success, 0 iff is blocked + Unblock(BlockBFlag, res); + } + + // Returns counter on success, 0 iff is blocked ui64 Add(ui64 value) noexcept; ui64 Increment() noexcept { - return Add(1); - } - + return Add(1); + } + ui64 Sub(ui64 value) noexcept; ui64 Decrement() noexcept { - return Sub(1); - } - - // Operations with BlockA attached to Counter overflow over specified threshold + return Sub(1); + } + + // Operations with BlockA attached to Counter overflow over specified threshold ui64 ThresholdAdd(ui64 value, ui64 threshold, TResult& res) noexcept; ui64 ThresholdSub(ui64 value, ui64 threshold, TResult& res) noexcept; ui64 ThresholdUpdate(ui64 threshold, TResult& res) noexcept; - + ui64 Get() const noexcept; - -private: + +private: inline static ui64 CheckedAddCounter(ui64 prevData, ui64 value) noexcept; inline static ui64 CheckedSubCounter(ui64 prevData, ui64 value) noexcept; inline static void FillResult(ui64 prevData, ui64 data, TResult& res) noexcept; diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_countedqueueoneone.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_countedqueueoneone.h index fc2951466c..ef745da2d4 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_countedqueueoneone.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_countedqueueoneone.h @@ -35,10 +35,10 @@ public: return Queue.Pop(); } - T Head() { - return Queue.Head(); - } - + T Head() { + return Queue.Head(); + } + TAtomicBase GetWaitingSize() { return AtomicLoad(&SizeLowerEstimate); } diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_cputimer.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_cputimer.h index 03d7d1ffe6..6e32cd43d5 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_cputimer.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_cputimer.h @@ -1,24 +1,24 @@ -#pragma once -#include "defs.h" - -#include <library/cpp/actors/util/datetime.h> - -namespace NKikimr { -namespace NPDisk { - -struct TCpuTimer: private TNonCopyable { - ui64 Timestamp; - - explicit TCpuTimer(ui64 ts = GetCycleCountFast()) { - Timestamp = ts; - } - - ui64 Elapsed() { - ui64 ts = GetCycleCountFast(); - DoSwap(Timestamp, ts); - return Timestamp - ts; - } -}; - -} // NPDisk -} // NKikimr +#pragma once +#include "defs.h" + +#include <library/cpp/actors/util/datetime.h> + +namespace NKikimr { +namespace NPDisk { + +struct TCpuTimer: private TNonCopyable { + ui64 Timestamp; + + explicit TCpuTimer(ui64 ts = GetCycleCountFast()) { + Timestamp = ts; + } + + ui64 Elapsed() { + ui64 ts = GetCycleCountFast(); + DoSwap(Timestamp, ts); + return Timestamp - ts; + } +}; + +} // NPDisk +} // NKikimr diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_ut.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_ut.cpp index 97938cfcdc..edfb33b89e 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_ut.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_ut.cpp @@ -1,5 +1,5 @@ -#include "defs.h" - +#include "defs.h" + #include "blobstorage_pdisk_chunk_id_formatter.h" #include "blobstorage_pdisk_data.h" #include "blobstorage_pdisk_driveestimator.h" @@ -12,7 +12,7 @@ #include "blobstorage_pdisk_util_atomicblockcounter.h" #include "blobstorage_pdisk_util_sector.h" #include "blobstorage_pdisk_util_wcache.h" - + #include <ydb/core/blobstorage/crypto/default.h> #include <ydb/library/pdisk_io/aio.h> @@ -20,203 +20,203 @@ #include <util/stream/null.h> #include <util/system/tempfile.h> #include <cstring> - -namespace NKikimr { namespace NPDisk { - + +namespace NKikimr { namespace NPDisk { + Y_UNIT_TEST_SUITE(TPDiskUtil) { - + Y_UNIT_TEST(AtomicBlockCounterFunctional) { - TAtomicBlockCounter counter; - UNIT_ASSERT_EQUAL(counter.Get(), 0); - UNIT_ASSERT_EQUAL(counter.Increment(), 1); - UNIT_ASSERT_EQUAL(counter.Add(20), 21); - UNIT_ASSERT_EQUAL(counter.Decrement(), 20); - UNIT_ASSERT_EQUAL(counter.Sub(10), 10); - counter.BlockA(); - UNIT_ASSERT_EQUAL(counter.IsBlocked(), true); - UNIT_ASSERT_EQUAL(counter.Sub(5), 5); - UNIT_ASSERT_EQUAL(counter.Increment(), 0); - UNIT_ASSERT_EQUAL(counter.Add(5), 0); - counter.UnblockB(); - UNIT_ASSERT_EQUAL(counter.Add(5), 0); - counter.BlockB(); - UNIT_ASSERT_EQUAL(counter.Add(5), 0); - counter.UnblockA(); - UNIT_ASSERT_EQUAL(counter.Add(5), 0); - counter.UnblockB(); - UNIT_ASSERT_EQUAL(counter.Add(5), 10); - } - + TAtomicBlockCounter counter; + UNIT_ASSERT_EQUAL(counter.Get(), 0); + UNIT_ASSERT_EQUAL(counter.Increment(), 1); + UNIT_ASSERT_EQUAL(counter.Add(20), 21); + UNIT_ASSERT_EQUAL(counter.Decrement(), 20); + UNIT_ASSERT_EQUAL(counter.Sub(10), 10); + counter.BlockA(); + UNIT_ASSERT_EQUAL(counter.IsBlocked(), true); + UNIT_ASSERT_EQUAL(counter.Sub(5), 5); + UNIT_ASSERT_EQUAL(counter.Increment(), 0); + UNIT_ASSERT_EQUAL(counter.Add(5), 0); + counter.UnblockB(); + UNIT_ASSERT_EQUAL(counter.Add(5), 0); + counter.BlockB(); + UNIT_ASSERT_EQUAL(counter.Add(5), 0); + counter.UnblockA(); + UNIT_ASSERT_EQUAL(counter.Add(5), 0); + counter.UnblockB(); + UNIT_ASSERT_EQUAL(counter.Add(5), 10); + } + Y_UNIT_TEST(AtomicBlockCounterSeqno) { - TAtomicBlockCounter counter; - TAtomicBlockCounter::TResult res; - counter.BlockA(res); - ui16 s = res.Seqno; - - // Block functional - counter.BlockA(res); - UNIT_ASSERT_EQUAL(res.Seqno, s); - counter.UnblockA(res); - UNIT_ASSERT_EQUAL(res.Seqno, ++s); - counter.UnblockA(res); - UNIT_ASSERT_EQUAL(res.Seqno, s); - counter.UnblockB(res); - UNIT_ASSERT_EQUAL(res.Seqno, s); - counter.BlockB(res); - UNIT_ASSERT_EQUAL(res.Seqno, ++s); - counter.BlockB(res); - UNIT_ASSERT_EQUAL(res.Seqno, s); - counter.UnblockB(res); - UNIT_ASSERT_EQUAL(res.Seqno, ++s); - - // Threshold Ops functional - counter.ThresholdAdd(10, 100, res); - UNIT_ASSERT_EQUAL(res.Seqno, ++s); - counter.ThresholdSub(2, 100, res); - UNIT_ASSERT_EQUAL(res.Seqno, ++s); - - // Seqno overflow - ui16 se = s - 2; - int i = 0; - while (s != se) { - if (i % 2 == 0) { - counter.BlockB(res); - } else { - counter.UnblockB(res); - } - UNIT_ASSERT_EQUAL(res.Seqno, ++s); - i++; - } - } - + TAtomicBlockCounter counter; + TAtomicBlockCounter::TResult res; + counter.BlockA(res); + ui16 s = res.Seqno; + + // Block functional + counter.BlockA(res); + UNIT_ASSERT_EQUAL(res.Seqno, s); + counter.UnblockA(res); + UNIT_ASSERT_EQUAL(res.Seqno, ++s); + counter.UnblockA(res); + UNIT_ASSERT_EQUAL(res.Seqno, s); + counter.UnblockB(res); + UNIT_ASSERT_EQUAL(res.Seqno, s); + counter.BlockB(res); + UNIT_ASSERT_EQUAL(res.Seqno, ++s); + counter.BlockB(res); + UNIT_ASSERT_EQUAL(res.Seqno, s); + counter.UnblockB(res); + UNIT_ASSERT_EQUAL(res.Seqno, ++s); + + // Threshold Ops functional + counter.ThresholdAdd(10, 100, res); + UNIT_ASSERT_EQUAL(res.Seqno, ++s); + counter.ThresholdSub(2, 100, res); + UNIT_ASSERT_EQUAL(res.Seqno, ++s); + + // Seqno overflow + ui16 se = s - 2; + int i = 0; + while (s != se) { + if (i % 2 == 0) { + counter.BlockB(res); + } else { + counter.UnblockB(res); + } + UNIT_ASSERT_EQUAL(res.Seqno, ++s); + i++; + } + } + Y_UNIT_TEST(Light) { - TLight l; - TIntrusivePtr<NMonitoring::TDynamicCounters> c(new NMonitoring::TDynamicCounters()); - l.Initialize(c, "l"); - auto state = c->GetCounter("l_state"); - auto count = c->GetCounter("l_count"); - - // functional - l.Set(true, 1); - UNIT_ASSERT_EQUAL(state->Val(), 1); - UNIT_ASSERT_EQUAL(count->Val(), 1); - l.Set(false, 2); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 1); - l.Set(false, 3); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 1); - l.Set(true, 4); - UNIT_ASSERT_EQUAL(state->Val(), 1); - UNIT_ASSERT_EQUAL(count->Val(), 2); - l.Set(true, 5); - UNIT_ASSERT_EQUAL(state->Val(), 1); - UNIT_ASSERT_EQUAL(count->Val(), 2); - - // Single reordering - l.Set(true, 7); - UNIT_ASSERT_EQUAL(state->Val(), 1); - UNIT_ASSERT_EQUAL(count->Val(), 2); - l.Set(false, 6); - UNIT_ASSERT_EQUAL(state->Val(), 1); - UNIT_ASSERT_EQUAL(count->Val(), 3); - - // Multiple reorderings - l.Set(false, 8); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 3); - l.Set(true, 12); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 3); - l.Set(false, 13); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 3); - l.Set(true, 14); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 3); - l.Set(false, 11); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 3); - l.Set(true, 10); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 3); - l.Set(true, 9); - UNIT_ASSERT_EQUAL(state->Val(), 1); - UNIT_ASSERT_EQUAL(count->Val(), 6); - - // Multiple reorderings with pause - l.Set(false, 15); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 6); - l.Set(false, 17); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 6); - l.Set(true, 18); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 6); - l.Set(true, 20); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 6); - l.Set(true, 22); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 6); - l.Set(false, 21); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 6); - l.Set(true, 16); - UNIT_ASSERT_EQUAL(state->Val(), 1); - UNIT_ASSERT_EQUAL(count->Val(), 8); - l.Set(false, 19); - UNIT_ASSERT_EQUAL(state->Val(), 1); - UNIT_ASSERT_EQUAL(count->Val(), 10); - - // Resizing - l.Set(false, 23); - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 10); - ui16 seqno = 24; // skip one - for (int i = 0; i < 199; i++) { - l.Set(i % 2 == 1 , ++seqno); - UNIT_ASSERT_EQUAL(count->Val(), 10); - } - l.Set(true, 24); // place missed one - UNIT_ASSERT_EQUAL(state->Val(), 0); - UNIT_ASSERT_EQUAL(count->Val(), 110); - - { // Seqno overflow - ui64 N = 3ull << 16ull; - i64 cnt = count->Val(); - for (ui64 i = 0; i < N; i++) { - bool st = (i % 3 == 0); - l.Set(st, ++seqno); - if (st) { - cnt++; - } - UNIT_ASSERT_EQUAL(count->Val(), cnt); - } - UNIT_ASSERT_EQUAL(state->Val(), 0); - } - - { // Seqno overflow and reorderings with max possible size - i64 cnt = count->Val(); - i64 cntStart = cnt; - ui16 missedSeqno = ++seqno; - bool st = false; - UNIT_ASSERT(missedSeqno > 10); - while (seqno != missedSeqno - 2) { // one for missed and one for initial - bool stPrev = st; - st = (seqno % 5 == 0); - l.Set(st, ++seqno); - if (st && !stPrev) { - cnt++; - } - UNIT_ASSERT_EQUAL(count->Val(), cntStart); - } - l.Set(false, missedSeqno); // place missed one + TLight l; + TIntrusivePtr<NMonitoring::TDynamicCounters> c(new NMonitoring::TDynamicCounters()); + l.Initialize(c, "l"); + auto state = c->GetCounter("l_state"); + auto count = c->GetCounter("l_count"); + + // functional + l.Set(true, 1); + UNIT_ASSERT_EQUAL(state->Val(), 1); + UNIT_ASSERT_EQUAL(count->Val(), 1); + l.Set(false, 2); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 1); + l.Set(false, 3); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 1); + l.Set(true, 4); + UNIT_ASSERT_EQUAL(state->Val(), 1); + UNIT_ASSERT_EQUAL(count->Val(), 2); + l.Set(true, 5); + UNIT_ASSERT_EQUAL(state->Val(), 1); + UNIT_ASSERT_EQUAL(count->Val(), 2); + + // Single reordering + l.Set(true, 7); + UNIT_ASSERT_EQUAL(state->Val(), 1); + UNIT_ASSERT_EQUAL(count->Val(), 2); + l.Set(false, 6); + UNIT_ASSERT_EQUAL(state->Val(), 1); + UNIT_ASSERT_EQUAL(count->Val(), 3); + + // Multiple reorderings + l.Set(false, 8); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 3); + l.Set(true, 12); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 3); + l.Set(false, 13); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 3); + l.Set(true, 14); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 3); + l.Set(false, 11); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 3); + l.Set(true, 10); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 3); + l.Set(true, 9); + UNIT_ASSERT_EQUAL(state->Val(), 1); + UNIT_ASSERT_EQUAL(count->Val(), 6); + + // Multiple reorderings with pause + l.Set(false, 15); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 6); + l.Set(false, 17); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 6); + l.Set(true, 18); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 6); + l.Set(true, 20); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 6); + l.Set(true, 22); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 6); + l.Set(false, 21); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 6); + l.Set(true, 16); + UNIT_ASSERT_EQUAL(state->Val(), 1); + UNIT_ASSERT_EQUAL(count->Val(), 8); + l.Set(false, 19); + UNIT_ASSERT_EQUAL(state->Val(), 1); + UNIT_ASSERT_EQUAL(count->Val(), 10); + + // Resizing + l.Set(false, 23); + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 10); + ui16 seqno = 24; // skip one + for (int i = 0; i < 199; i++) { + l.Set(i % 2 == 1 , ++seqno); + UNIT_ASSERT_EQUAL(count->Val(), 10); + } + l.Set(true, 24); // place missed one + UNIT_ASSERT_EQUAL(state->Val(), 0); + UNIT_ASSERT_EQUAL(count->Val(), 110); + + { // Seqno overflow + ui64 N = 3ull << 16ull; + i64 cnt = count->Val(); + for (ui64 i = 0; i < N; i++) { + bool st = (i % 3 == 0); + l.Set(st, ++seqno); + if (st) { + cnt++; + } + UNIT_ASSERT_EQUAL(count->Val(), cnt); + } + UNIT_ASSERT_EQUAL(state->Val(), 0); + } + + { // Seqno overflow and reorderings with max possible size + i64 cnt = count->Val(); + i64 cntStart = cnt; + ui16 missedSeqno = ++seqno; + bool st = false; + UNIT_ASSERT(missedSeqno > 10); + while (seqno != missedSeqno - 2) { // one for missed and one for initial + bool stPrev = st; + st = (seqno % 5 == 0); + l.Set(st, ++seqno); + if (st && !stPrev) { + cnt++; + } + UNIT_ASSERT_EQUAL(count->Val(), cntStart); + } + l.Set(false, missedSeqno); // place missed one UNIT_ASSERT_EQUAL((bool)state->Val(), st); - UNIT_ASSERT_EQUAL(count->Val(), cnt); - } - } + UNIT_ASSERT_EQUAL(count->Val(), cnt); + } + } Y_UNIT_TEST(LightOverflow) { TLight l; @@ -264,8 +264,8 @@ void TestOffset(ui64 offset, ui64 size, ui64 expectedFirstSector, ui64 expectedL "lastSector# " << lastSector << " expectedLastSector# " << expectedLastSector << "\n" "sectorOffset# " << sectorOffset << " expectedSectorOffset# " << expectedSectorOffset << "\n" ); -} - +} + Y_UNIT_TEST(OffsetParsingCorrectness) { TDiskFormat format; format.Clear(); @@ -521,4 +521,4 @@ void TestPayloadOffset(ui64 firstSector, ui64 lastSector, ui64 currentSector, ui } } -}} // namespace NKikimr // namespace NPDisk +}} // namespace NKikimr // namespace NPDisk diff --git a/ydb/core/blobstorage/pdisk/mock/pdisk_mock.cpp b/ydb/core/blobstorage/pdisk/mock/pdisk_mock.cpp index 1e84f5d8f6..b6f603e3cf 100644 --- a/ydb/core/blobstorage/pdisk/mock/pdisk_mock.cpp +++ b/ydb/core/blobstorage/pdisk/mock/pdisk_mock.cpp @@ -177,8 +177,8 @@ struct TPDiskMockState::TImpl { return ChunkSize; } - TIntervalSet<i64> GetWrittenAreas(ui32 chunkIdx) const { - TIntervalSet<i64> res; + TIntervalSet<i64> GetWrittenAreas(ui32 chunkIdx) const { + TIntervalSet<i64> res; for (auto& [ownerId, owner] : Owners) { if (const auto it = owner.ChunkData.find(chunkIdx); it != owner.ChunkData.end()) { for (const auto& [idx, data] : it->second.Blocks) { @@ -224,7 +224,7 @@ ui32 TPDiskMockState::GetChunkSize() const { return Impl->GetChunkSize(); } -TIntervalSet<i64> TPDiskMockState::GetWrittenAreas(ui32 chunkIdx) const { +TIntervalSet<i64> TPDiskMockState::GetWrittenAreas(ui32 chunkIdx) const { return Impl->GetWrittenAreas(chunkIdx); } diff --git a/ydb/core/blobstorage/pdisk/mock/pdisk_mock.h b/ydb/core/blobstorage/pdisk/mock/pdisk_mock.h index a09441f4ab..80b7293b45 100644 --- a/ydb/core/blobstorage/pdisk/mock/pdisk_mock.h +++ b/ydb/core/blobstorage/pdisk/mock/pdisk_mock.h @@ -23,7 +23,7 @@ namespace NKikimr { void SetCorruptedArea(ui32 chunkIdx, ui32 begin, ui32 end, bool enabled); std::set<ui32> GetChunks(); ui32 GetChunkSize() const; - TIntervalSet<i64> GetWrittenAreas(ui32 chunkIdx) const; + TIntervalSet<i64> GetWrittenAreas(ui32 chunkIdx) const; void TrimQuery(); TPtr Snapshot(); // create a copy of PDisk whole state diff --git a/ydb/core/blobstorage/testload/test_load_actor.cpp b/ydb/core/blobstorage/testload/test_load_actor.cpp index c8788b1310..6088abc3d7 100644 --- a/ydb/core/blobstorage/testload/test_load_actor.cpp +++ b/ydb/core/blobstorage/testload/test_load_actor.cpp @@ -337,11 +337,11 @@ public: str << "<option value=\"" << ui32(NKikimrBlobStorage::NAME) << "\">" << #NAME << "</option>"; TStringStream str; - HTML(str) { + HTML(str) { if (info.ErrorMessage) { - DIV() { + DIV() { str << "<h1>" << info.ErrorMessage << "</h1>"; - } + } } if (!nodata) { @@ -350,12 +350,12 @@ public: DIV_CLASS("panel panel-info") { DIV_CLASS("panel-heading") { str << "Tag# " << perActorInfo.Tag; - } + } DIV_CLASS("panel-body") { str << perActorInfo.Data; - } - } - } + } + } + } COLLAPSED_BUTTON_CONTENT("finished_tests_info", "Finished tests") { for (const auto& req : FinishedTests) { @@ -373,8 +373,8 @@ public: } } } - } - + } + ctx.Send(info.Origin, new NMon::TEvHttpInfoRes(str.Str(), info.SubRequestId)); InfoRequests.erase(it); diff --git a/ydb/core/blobstorage/testload/test_load_actor.h b/ydb/core/blobstorage/testload/test_load_actor.h index 38b7fb3d30..c90e2141fd 100644 --- a/ydb/core/blobstorage/testload/test_load_actor.h +++ b/ydb/core/blobstorage/testload/test_load_actor.h @@ -72,7 +72,7 @@ namespace NKikimr { ui32 InFlight; TVector<ui64> RwSpeedBps; ELoadType LoadType; - NMonitoring::TPercentileTrackerLg<10, 4, 1> LatencyUs; // Upper threshold of this tracker is ~134 seconds, size is 256kB + NMonitoring::TPercentileTrackerLg<10, 4, 1> LatencyUs; // Upper threshold of this tracker is ~134 seconds, size is 256kB TMap<double, ui64> DeviceLatency; double GetAverageSpeed() const { diff --git a/ydb/core/blobstorage/testload/test_load_pdisk_read.cpp b/ydb/core/blobstorage/testload/test_load_pdisk_read.cpp index 3b446a74c2..9a63ad1364 100644 --- a/ydb/core/blobstorage/testload/test_load_pdisk_read.cpp +++ b/ydb/core/blobstorage/testload/test_load_pdisk_read.cpp @@ -463,7 +463,7 @@ public: TRequestInfo *request = &RequestInfo[requestIdx]; if (now > MeasurementStartTime) { - Report->LatencyUs.Increment((now - request->StartTime).MicroSeconds()); + Report->LatencyUs.Increment((now - request->StartTime).MicroSeconds()); for(const auto& perc : DevicePercentiles) { Report->DeviceLatency[perc.first] = Max(Report->DeviceLatency[perc.first], (ui64)*perc.second); } @@ -554,7 +554,7 @@ public: PARAM("Average speed since start, MB/s", Report->GetAverageSpeed() / 1e6); PARAM("Speed standard deviation since start, MB/s", Report->GetSpeedDeviation() / 1e6); for (double percentile : {0.5, 0.9, 0.95, 0.99, 0.999, 1.0}) { - size_t value = Report->LatencyUs.GetPercentile(percentile); + size_t value = Report->LatencyUs.GetPercentile(percentile); PARAM(Sprintf("percentile# %.3f since start, ms", percentile), value / 1000.0); } for(const auto& perc : DevicePercentiles) { diff --git a/ydb/core/blobstorage/testload/test_load_pdisk_write.cpp b/ydb/core/blobstorage/testload/test_load_pdisk_write.cpp index 8ea16e014c..5e4c145e2e 100644 --- a/ydb/core/blobstorage/testload/test_load_pdisk_write.cpp +++ b/ydb/core/blobstorage/testload/test_load_pdisk_write.cpp @@ -78,13 +78,13 @@ class TPDiskWriterTestLoadActor : public TActorBootstrapped<TPDiskWriterTestLoad const TActorId Parent; ui64 Tag; ui32 DurationSeconds; - ui32 IntervalMsMin = 0; - ui32 IntervalMsMax = 0; + ui32 IntervalMsMin = 0; + ui32 IntervalMsMax = 0; TControlWrapper MaxInFlight; ui32 InFlight = 0; ui32 LogInFlight = 0; - TInstant LastRequest; - ui32 IntervalMs = 0; + TInstant LastRequest; + ui32 IntervalMs = 0; ui32 PDiskId; TVDiskID VDiskId; NPDisk::TOwnerRound OwnerRound; @@ -146,9 +146,9 @@ public: Y_ASSERT(DurationSeconds > DelayBeforeMeasurements.Seconds()); Report->Duration = TDuration::Seconds(DurationSeconds); - IntervalMsMin = cmd.GetIntervalMsMin(); - IntervalMsMax = cmd.GetIntervalMsMax(); - + IntervalMsMin = cmd.GetIntervalMsMin(); + IntervalMsMax = cmd.GetIntervalMsMax(); + VERIFY_PARAM(InFlightWrites); MaxInFlight = cmd.GetInFlightWrites(); Report->InFlight = MaxInFlight; @@ -213,7 +213,7 @@ public: void Bootstrap(const TActorContext& ctx) { Become(&TPDiskWriterTestLoadActor::StateFunc); - ctx.Schedule(TDuration::Seconds(DurationSeconds), new TEvents::TEvPoisonPill); + ctx.Schedule(TDuration::Seconds(DurationSeconds), new TEvents::TEvPoisonPill); ctx.Schedule(TDuration::MilliSeconds(MonitoringUpdateCycleMs), new TEvUpdateMonitoring); AppData(ctx)->Icb->RegisterLocalControl(MaxInFlight, Sprintf("PDiskWriteLoadActor_MaxInFlight_%4" PRIu64, Tag).c_str()); if (IsWardenlessTest) { @@ -311,18 +311,18 @@ public: } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Rate management - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - void HandleWakeup(const TActorContext& ctx) { - SendWriteRequests(ctx); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Rate management + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void HandleWakeup(const TActorContext& ctx) { + SendWriteRequests(ctx); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Death management //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void HandlePoisonPill(const TActorContext& ctx) { + void HandlePoisonPill(const TActorContext& ctx) { Report->LoadType = TLoadReport::LOAD_WRITE; MaxInFlight = 0; CheckDie(ctx); @@ -377,28 +377,28 @@ public: void SendWriteRequests(const TActorContext& ctx) { while (InFlight < MaxInFlight) { - // Randomize interval (if required) - if (!IntervalMs && IntervalMsMax && IntervalMsMin) { - IntervalMs = IntervalMsMin; - if (ui32 delta = (IntervalMsMax > IntervalMsMin? IntervalMsMax - IntervalMsMin: 0)) { - IntervalMs += Rng() % delta; - } - } - - if (IntervalMs) { - // Enforce intervals between requests + // Randomize interval (if required) + if (!IntervalMs && IntervalMsMax && IntervalMsMin) { + IntervalMs = IntervalMsMin; + if (ui32 delta = (IntervalMsMax > IntervalMsMin? IntervalMsMax - IntervalMsMin: 0)) { + IntervalMs += Rng() % delta; + } + } + + if (IntervalMs) { + // Enforce intervals between requests TInstant now = TAppData::TimeProvider->Now(); - TInstant nextRequest = LastRequest + TDuration::MilliSeconds(IntervalMs); - if (now < nextRequest) { - // Suspend sending until interval will elapse - ctx.Schedule(nextRequest - now, new TEvents::TEvWakeup); - break; - } - LastRequest = now; - IntervalMs = 0; // To enforce regeneration of new random interval - } - - // Prepare to send request + TInstant nextRequest = LastRequest + TDuration::MilliSeconds(IntervalMs); + if (now < nextRequest) { + // Suspend sending until interval will elapse + ctx.Schedule(nextRequest - now, new TEvents::TEvWakeup); + break; + } + LastRequest = now; + IntervalMs = 0; // To enforce regeneration of new random interval + } + + // Prepare to send request ui64 accumWeight = 0; for (TChunkInfo& chunkInfo : Chunks) { chunkInfo.AccumWeight = accumWeight; @@ -513,7 +513,7 @@ public: TRequestInfo *request = &RequestInfo[requestIdx]; if (now > MeasurementStartTime) { - Report->LatencyUs.Increment((now - request->StartTime).MicroSeconds()); + Report->LatencyUs.Increment((now - request->StartTime).MicroSeconds()); for(const auto& perc : DevicePercentiles) { Report->DeviceLatency[perc.first] = Max(Report->DeviceLatency[perc.first], (ui64)*perc.second); } @@ -552,24 +552,24 @@ public: void Handle(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx) { TStringStream str; #define PARAM(NAME, VALUE) \ - TABLER() { \ - TABLED() { str << NAME; } \ - TABLED() { str << VALUE; } \ - } + TABLER() { \ + TABLED() { str << NAME; } \ + TABLED() { str << VALUE; } \ + } TMap<ui32, TVector<TDuration>> latmap; for (const auto& pair : TimeSeries) { const TRequestStat& stat = pair.second; latmap[stat.Size].push_back(stat.Latency); } - HTML(str) { - TABLE() { - TABLEHEAD() { - TABLER() { - TABLEH() { str << "Parameter"; } - TABLEH() { str << "Value"; } - } - } - TABLEBODY() { + HTML(str) { + TABLE() { + TABLEHEAD() { + TABLER() { + TABLEH() { str << "Parameter"; } + TABLEH() { str << "Value"; } + } + } + TABLEBODY() { PARAM("Elapsed time / Duration", (TAppData::TimeProvider->Now() - TestStartTime).Seconds() << "s / " << DurationSeconds << "s"); @@ -614,13 +614,13 @@ public: PARAM("Average speed since start, MB/s", Report->GetAverageSpeed() / 1e6); PARAM("Speed standard deviation since start, MB/s", Report->GetSpeedDeviation() / 1e6); for (double percentile : {0.5, 0.9, 0.95, 0.99, 0.999, 1.0}) { - size_t value = Report->LatencyUs.GetPercentile(percentile); + size_t value = Report->LatencyUs.GetPercentile(percentile); PARAM(Sprintf("percentile# %.3f since start, ms", percentile), value / 1000.0); } - } - } - } - + } + } + } + ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str(), ev->Get()->SubRequestId)); } diff --git a/ydb/core/blobstorage/testload/test_load_vdisk_write.cpp b/ydb/core/blobstorage/testload/test_load_vdisk_write.cpp index 39ecca9dbd..0eca8811b5 100644 --- a/ydb/core/blobstorage/testload/test_load_vdisk_write.cpp +++ b/ydb/core/blobstorage/testload/test_load_vdisk_write.cpp @@ -276,29 +276,29 @@ namespace NKikimr { } \ } -#define PARAM(NAME) \ - TABLER() { \ - TABLED() { \ - str << #NAME; \ - } \ - TABLED() { \ - str << NAME; \ - } \ - } - - HTML(str) { - TABLE() { - TABLEHEAD() { - TABLER() { - TABLEH() { +#define PARAM(NAME) \ + TABLER() { \ + TABLED() { \ + str << #NAME; \ + } \ + TABLED() { \ + str << NAME; \ + } \ + } + + HTML(str) { + TABLE() { + TABLEHEAD() { + TABLER() { + TABLEH() { str << "Parameter"; - } - TABLEH() { + } + TABLEH() { str << "Value"; - } - } - } - TABLEBODY() { + } + } + } + TABLEBODY() { NAMED_PARAM("Elapsed time / Duration", (TAppData::TimeProvider->Now() - StartTime).Seconds() << "s / " << DurationSeconds << "s"); PARAM(TabletId) @@ -320,9 +320,9 @@ namespace NKikimr { TString avgSpeed = Sprintf("%.3lf %s", (double) BytesWritten / (1 << 20) / (TAppData::TimeProvider->Now() - StartTime).Seconds(), "MB/s"); NAMED_PARAM("Average speed", avgSpeed); - } - } - } + } + } + } ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str(), ev->Get()->SubRequestId)); } diff --git a/ydb/core/blobstorage/testload/test_load_write.cpp b/ydb/core/blobstorage/testload/test_load_write.cpp index 3169c1609e..1bf2bbe67d 100644 --- a/ydb/core/blobstorage/testload/test_load_write.cpp +++ b/ydb/core/blobstorage/testload/test_load_write.cpp @@ -387,7 +387,7 @@ class TLogWriterTestLoadActor : public TActorBootstrapped<TLogWriterTestLoadActo ResponseQT.Update(); ReadResponseQT.Update(); if (WritesInFlightTimestamps) { - const auto& maxLatency = CyclesToDuration(GetCycleCountFast() - WritesInFlightTimestamps.front().second); + const auto& maxLatency = CyclesToDuration(GetCycleCountFast() - WritesInFlightTimestamps.front().second); *MaxInFlightLatency = maxLatency.MicroSeconds(); } } @@ -419,7 +419,7 @@ class TLogWriterTestLoadActor : public TActorBootstrapped<TLogWriterTestLoadActo } HTML(str) { TDuration EarliestTimestamp = TDuration::Zero(); - const ui64 nowCycles = GetCycleCountFast(); + const ui64 nowCycles = GetCycleCountFast(); for (const auto& [writeId, issued] : WritesInFlightTimestamps) { EarliestTimestamp = Max(EarliestTimestamp, CyclesToDuration(nowCycles - issued)); } @@ -562,7 +562,7 @@ class TLogWriterTestLoadActor : public TActorBootstrapped<TLogWriterTestLoadActo auto it = SentTimestamp.find(writeQueryId); const auto sendCycles = it->second; Y_VERIFY(it != SentTimestamp.end()); - const TDuration response = CyclesToDuration(GetCycleCountFast() - sendCycles); + const TDuration response = CyclesToDuration(GetCycleCountFast() - sendCycles); SentTimestamp.erase(it); // It's very likely that "writeQueryId" will be found at the start @@ -581,7 +581,7 @@ class TLogWriterTestLoadActor : public TActorBootstrapped<TLogWriterTestLoadActo } }; SendToBSProxy(ctx, GroupId, ev.release(), QueryDispatcher.ObtainCookie(std::move(writeCallback))); - const auto nowCycles = GetCycleCountFast(); + const auto nowCycles = GetCycleCountFast(); WritesInFlightTimestamps.emplace_back(writeQueryId, nowCycles); SentTimestamp.emplace(writeQueryId, nowCycles); IssuedWriteTimestamp.push_back(TAppData::TimeProvider->Now()); @@ -714,7 +714,7 @@ class TLogWriterTestLoadActor : public TActorBootstrapped<TLogWriterTestLoadActo auto it = ReadSentTimestamp.find(readQueryId); Y_VERIFY(it != ReadSentTimestamp.end()); - const TDuration response = CyclesToDuration(GetCycleCountFast() - it->second); + const TDuration response = CyclesToDuration(GetCycleCountFast() - it->second); ReadSentTimestamp.erase(it); ReadResponseQT.Increment(response.MicroSeconds()); @@ -722,7 +722,7 @@ class TLogWriterTestLoadActor : public TActorBootstrapped<TLogWriterTestLoadActo }; SendToBSProxy(ctx, GroupId, ev.release(), QueryDispatcher.ObtainCookie(std::move(readCallback))); - ReadSentTimestamp.emplace(readQueryId, GetCycleCountFast()); + ReadSentTimestamp.emplace(readQueryId, GetCycleCountFast()); ++ReadsInFlight; ReadBytesInFlight += size; @@ -925,29 +925,29 @@ public: void Handle(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx) { TStringStream str; - HTML(str) { + HTML(str) { TABLE_CLASS("table table-condensed") { - TABLEHEAD() { - TABLER() { + TABLEHEAD() { + TABLER() { TABLEH() { str << "Parameter"; } TABLEH() { str << "Value"; } - } - } - TABLEBODY() { + } + } + TABLEBODY() { for (auto& writer : TabletWriters) { str << "<tr><td colspan=\"2\">" << "<b>Tablet</b>" << "</td></tr>"; writer.DumpState(str); } - } - } + } + } COLLAPSED_BUTTON_CONTENT(Sprintf("configProtobuf%" PRIu64, Tag), "Config") { str << "<pre>" << ConfingString << "</pre>"; } - } + } ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str(), ev->Get()->SubRequestId)); } diff --git a/ydb/core/blobstorage/ut_pdiskfit/lib/fail_injection_test.h b/ydb/core/blobstorage/ut_pdiskfit/lib/fail_injection_test.h index 7e0bfa05e0..067c014083 100644 --- a/ydb/core/blobstorage/ut_pdiskfit/lib/fail_injection_test.h +++ b/ydb/core/blobstorage/ut_pdiskfit/lib/fail_injection_test.h @@ -71,7 +71,7 @@ public: {} private: - bool DoExecute(NLWTrace::TOrbit&, const NLWTrace::TParams& params) override { + bool DoExecute(NLWTrace::TOrbit&, const NLWTrace::TParams& params) override { Injector->Inject(params.Param[0].Get<ui64>()); return true; } @@ -118,7 +118,7 @@ struct TPDiskFailureInjectionTest { TAutoEvent StopEvent; - NLWTrace::TManager TraceManager; + NLWTrace::TManager TraceManager; TMaybe<TDuration> TestDuration; @@ -154,7 +154,7 @@ struct TPDiskFailureInjectionTest { auto& custom = *action.MutableCustomAction(); custom.SetName(name); - auto factory = [=](NLWTrace::TProbe *probe, const NLWTrace::TCustomAction& /*action*/, NLWTrace::TSession* /*session*/) { + auto factory = [=](NLWTrace::TProbe *probe, const NLWTrace::TCustomAction& /*action*/, NLWTrace::TSession* /*session*/) { return new TFailInjectionActionExecutor(probe, injector); }; diff --git a/ydb/core/blobstorage/ut_vdisk/mon_reregister_ut.cpp b/ydb/core/blobstorage/ut_vdisk/mon_reregister_ut.cpp index 36a2eca81f..10c09b2d4d 100644 --- a/ydb/core/blobstorage/ut_vdisk/mon_reregister_ut.cpp +++ b/ydb/core/blobstorage/ut_vdisk/mon_reregister_ut.cpp @@ -59,9 +59,9 @@ Y_UNIT_TEST_SUITE(TMonitoring) { void Handle(NMon::TEvHttpInfo::TPtr &ev, const TActorContext &ctx) { TStringStream str; - HTML(str) { - DIV_CLASS("alert alert-error") {str << "Incarnation: " << Incarnation;} - } + HTML(str) { + DIV_CLASS("alert alert-error") {str << "Incarnation: " << Incarnation;} + } ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str())); diff --git a/ydb/core/blobstorage/vdisk/common/blobstorage_dblogcutter.cpp b/ydb/core/blobstorage/vdisk/common/blobstorage_dblogcutter.cpp index 5f176b61b7..cdb29280b5 100644 --- a/ydb/core/blobstorage/vdisk/common/blobstorage_dblogcutter.cpp +++ b/ydb/core/blobstorage/vdisk/common/blobstorage_dblogcutter.cpp @@ -150,10 +150,10 @@ namespace NKikimr { TStringStream str; str << "\n"; - HTML(str) { - DIV_CLASS("panel panel-default") { - DIV_CLASS("panel-heading") {str << "LogCutter";} - DIV_CLASS("panel-body") { + HTML(str) { + DIV_CLASS("panel panel-default") { + DIV_CLASS("panel-heading") {str << "LogCutter";} + DIV_CLASS("panel-body") { str << "Hull: [LsnToKeep=" << HullLsnToKeep << ", LastUpdate=" << ToStringLocalTimeUpToSeconds(HullLastTime) << "]<br>"; str << "SyncLog: [LsnToKeep=" << SyncLogLsnToKeep @@ -172,9 +172,9 @@ namespace NKikimr { str << "FirstDuration: " << FirstDuration << "<br>"; str << "RegularDuration: " << RegularDuration << "<br>"; - } - } - } + } + } + } str << "\n"; ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str(), TDbMon::LogCutterId)); diff --git a/ydb/core/blobstorage/vdisk/common/vdisk_response.cpp b/ydb/core/blobstorage/vdisk/common/vdisk_response.cpp index 384931d305..922a85e852 100644 --- a/ydb/core/blobstorage/vdisk/common/vdisk_response.cpp +++ b/ydb/core/blobstorage/vdisk/common/vdisk_response.cpp @@ -25,8 +25,8 @@ void SendVDiskResponse(const TActorContext &ctx, const TActorId &recipient, IEve TEvBlobStorage::T *event = static_cast<TEvBlobStorage::T *>(ev); \ traceId = std::move(event->TraceId); \ WILSON_TRACE_FROM_ACTOR(ctx, actor, &traceId, EV); \ - const double usPerCycle = 1000000.0 / NHPTimer::GetCyclesPerSecond(); \ - event->Record.MutableTimestamps()->SetSentByVDiskUs(GetCycleCountFast() * usPerCycle); \ + const double usPerCycle = 1000000.0 / NHPTimer::GetCyclesPerSecond(); \ + event->Record.MutableTimestamps()->SetSentByVDiskUs(GetCycleCountFast() * usPerCycle); \ break; \ } diff --git a/ydb/core/blobstorage/vdisk/common/vdisk_syncneighbors.h b/ydb/core/blobstorage/vdisk/common/vdisk_syncneighbors.h index b014da97b0..b2a5671caf 100644 --- a/ydb/core/blobstorage/vdisk/common/vdisk_syncneighbors.h +++ b/ydb/core/blobstorage/vdisk/common/vdisk_syncneighbors.h @@ -342,38 +342,38 @@ namespace NKikimr { template <class TPrinter> void OutputHtml(IOutputStream &str, TPrinter &printer, const TString &name, const TString &divClass) const { str << "\n"; - HTML(str) { - DIV_CLASS (divClass) { - DIV_CLASS("panel-heading") {str << name;} - DIV_CLASS("panel-body") { - DIV_CLASS("row") { + HTML(str) { + DIV_CLASS (divClass) { + DIV_CLASS("panel-heading") {str << name;} + DIV_CLASS("panel-body") { + DIV_CLASS("row") { OutputHtmlTable<TPrinter>(str, printer); - } - } - } - } + } + } + } + } str << "\n"; } template <class TPrinter> void OutputHtmlTable(IOutputStream &str, TPrinter &printer) const { TVector<TConstIterator> its; - HTML(str) { - TABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { + HTML(str) { + TABLE_CLASS ("table table-condensed") { + TABLEHEAD() { + TABLER() { const auto& domains = GetFailDomains(); for (auto it = domains.begin(); it != domains.end(); ++it) { - TABLEH() {str << "Domain";} + TABLEH() {str << "Domain";} const auto& vdisks = *it; its.emplace_back(vdisks.begin()); } - } - } + } + } OutputHtmlTableBody<TPrinter>(str, printer, its); - } - } + } + } } public: @@ -418,26 +418,26 @@ namespace NKikimr { template <class TPrinter> void OutputHtmlTableBody(IOutputStream &str, TPrinter &printer, TVector<TConstIterator> &its) const { - HTML(str) { - TABLEBODY() { + HTML(str) { + TABLEBODY() { for (ui32 row = 0; row < DisksInDomain; ++row) { - TABLER() { + TABLER() { // column iterator -- one entry for each domain in "its" typename TVector<TConstIterator>::iterator colIt = its.begin(); for (const auto& vdisks : GetFailDomains()) { - TABLED() { + TABLED() { TConstIterator& x = *colIt++; printer(str, x++); if (row + 1 == DisksInDomain) { Y_VERIFY(x == vdisks.end()); } - } + } } - } + } } - } - } + } + } } }; //////////////////////////////////////////////////////////////////////////// diff --git a/ydb/core/blobstorage/vdisk/handoff/handoff_basic.cpp b/ydb/core/blobstorage/vdisk/handoff/handoff_basic.cpp index da29a8822b..563018f762 100644 --- a/ydb/core/blobstorage/vdisk/handoff/handoff_basic.cpp +++ b/ydb/core/blobstorage/vdisk/handoff/handoff_basic.cpp @@ -40,7 +40,7 @@ namespace NKikimr { HTML(str) { DIV_CLASS(".narrow-line70") { SMALL() { - SMALL() { + SMALL() { HTML_OUTPUT_PARAM(str, LocalHandoffSendRightAway); HTML_OUTPUT_PARAM(str, LocalHandoffPostpone); HTML_OUTPUT_PARAM(str, LocalHandoffDiscard); @@ -54,9 +54,9 @@ namespace NKikimr { HTML_OUTPUT_PARAM(str, WakeupsStillBad); HTML_OUTPUT_PARAM(str, StateGoodToBadTransition); HTML_OUTPUT_PARAM(str, StateBadToGoodTransition); - } - } - } + } + } + } } str << "\n"; } @@ -147,7 +147,7 @@ namespace NKikimr { HTML(str) { DIV_CLASS(".narrow-line70") { SMALL() { - SMALL() { + SMALL() { HTML_OUTPUT_PARAM(str, WaitQueueSize); HTML_OUTPUT_PARAM(str, WaitQueueByteSize); HTML_OUTPUT_PARAM(str, InFlightQueueSize); @@ -156,9 +156,9 @@ namespace NKikimr { HTML_OUTPUT_TIME_PARAM(str, LastSendTime); HTML_OUTPUT_PARAM(str, WaitQueueSize); HTML_OUTPUT_PARAM(str, WakeupCounter); - } - } - } + } + } + } } str << "\n"; } diff --git a/ydb/core/blobstorage/vdisk/handoff/handoff_mon.cpp b/ydb/core/blobstorage/vdisk/handoff/handoff_mon.cpp index 5aa0e92348..1e7f119631 100644 --- a/ydb/core/blobstorage/vdisk/handoff/handoff_mon.cpp +++ b/ydb/core/blobstorage/vdisk/handoff/handoff_mon.cpp @@ -98,10 +98,10 @@ namespace NKikimr { struct TPrinter { void operator() (IOutputStream &str, TCells::TConstIterator it) { if (it->Myself) { - HTML(str) { - PARA_CLASS("text-info") {str << "Self";} - SMALL() {str << it->VDiskIdShort.ToString();} - } + HTML(str) { + PARA_CLASS("text-info") {str << "Self";} + SMALL() {str << it->VDiskIdShort.ToString();} + } } else { it->Get().PrState->OutputHtml(str); it->Get().Cntr->OutputHtml(str); diff --git a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhuge.cpp b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhuge.cpp index 30d2aeece4..1b07a17e7d 100644 --- a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhuge.cpp +++ b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhuge.cpp @@ -893,12 +893,12 @@ namespace NKikimr { void Handle(NMon::TEvHttpInfo::TPtr &ev, const TActorContext &ctx) { Y_VERIFY_DEBUG(ev->Get()->SubRequestId == TDbMon::HugeKeeperId); TStringStream str; - HTML(str) { - DIV_CLASS("panel panel-default") { - DIV_CLASS("panel-heading") {str << "Huge Blob Keeper";} - DIV_CLASS("panel-body") {State.RenderHtml(str);} - } - } + HTML(str) { + DIV_CLASS("panel panel-default") { + DIV_CLASS("panel-heading") {str << "Huge Blob Keeper";} + DIV_CLASS("panel-body") {State.RenderHtml(str);} + } + } ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str(), TDbMon::HugeKeeperId)); } diff --git a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.cpp b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.cpp index e60200de98..c94054ad0b 100644 --- a/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.cpp +++ b/ydb/core/blobstorage/vdisk/huge/blobstorage_hullhugeheap.cpp @@ -376,22 +376,22 @@ namespace NKikimr { } void TChainDelegator::RenderHtml(IOutputStream &str) const { - HTML(str) { - TABLER() { - TABLED() {str << SlotSize << " / " << SlotsInChunk;} - TABLED() {ChainPtr->RenderHtml(str);} - } - } + HTML(str) { + TABLER() { + TABLED() {str << SlotSize << " / " << SlotsInChunk;} + TABLED() {ChainPtr->RenderHtml(str);} + } + } } void TChainDelegator::RenderHtmlForUsage(IOutputStream &str) const { - HTML(str) { - TABLER() { - TABLED() {str << SlotSize;} - TABLED() {str << SlotsInChunk;} - TABLED() {str << ChainPtr->GetAllocatedSlots();} - } - } + HTML(str) { + TABLER() { + TABLED() {str << SlotSize;} + TABLED() {str << SlotsInChunk;} + TABLED() {str << ChainPtr->GetAllocatedSlots();} + } + } } @@ -560,38 +560,38 @@ namespace NKikimr { } void TAllChains::RenderHtml(IOutputStream &str) const { - HTML(str) { - TABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "Chain";} + HTML(str) { + TABLE_CLASS ("table table-condensed") { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "Chain";} TABLEH() {str << "Reserved: [ChunkIdx, FreeSlotsInChunk]";} - } - } - TABLEBODY() { + } + } + TABLEBODY() { for (const auto & x : ChainDelegators) x.RenderHtml(str); - } - } - } + } + } + } } void TAllChains::RenderHtmlForUsage(IOutputStream &str) const { - HTML(str) { - TABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "Slot Size";} - TABLEH() {str << "Slots in Chunk";} - TABLEH() {str << "Allocated";} - } - } - TABLEBODY() { + HTML(str) { + TABLE_CLASS ("table table-condensed") { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "Slot Size";} + TABLEH() {str << "Slots in Chunk";} + TABLEH() {str << "Allocated";} + } + } + TABLEBODY() { for (const auto & x : ChainDelegators) x.RenderHtmlForUsage(str); - } - } - } + } + } + } } TVector<NPrivate::TChainLayoutBuilder::TSeg> TAllChains::GetLayout() const { @@ -854,12 +854,12 @@ namespace NKikimr { ////////////////////////////////////////////////////////////////////////////////////////// void THeap::RenderHtml(IOutputStream &str) const { str << "\n"; - HTML(str) { - COLLAPSED_BUTTON_CONTENT("hugeheapusageid", "Heap Usage") { + HTML(str) { + COLLAPSED_BUTTON_CONTENT("hugeheapusageid", "Heap Usage") { Chains.RenderHtmlForUsage(str); - } + } str << "<br/>"; - COLLAPSED_BUTTON_CONTENT("hugeheapstateid", "Heap State") { + COLLAPSED_BUTTON_CONTENT("hugeheapstateid", "Heap State") { str << "FreeChunks: "; if (FreeChunks.empty()) { str << "empty"; @@ -870,8 +870,8 @@ namespace NKikimr { } str << "<br>"; Chains.RenderHtml(str); - } - } + } + } str << "\n"; } diff --git a/ydb/core/blobstorage/vdisk/hulldb/base/blobstorage_hullsatisfactionrank.cpp b/ydb/core/blobstorage/vdisk/hulldb/base/blobstorage_hullsatisfactionrank.cpp index 74ed554356..0609d0dc6b 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/base/blobstorage_hullsatisfactionrank.cpp +++ b/ydb/core/blobstorage/vdisk/hulldb/base/blobstorage_hullsatisfactionrank.cpp @@ -98,26 +98,26 @@ namespace NKikimr { } void TDynamicPDiskWeightsManager::RenderHtml(IOutputStream &str) const { - HTML(str) { - TABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() { str << "Component"; } - TABLEH() { str << "Status"; } - } - } - TABLEBODY() { - TABLER() { - TABLED() { str << "FreshRank"; } - TABLED() { FreshWeight.RenderHtml(str); } - } - TABLER() { - TABLED() { str << "LevelRank"; } - TABLED() { LevelWeight.RenderHtml(str); } - } - } - } - } + HTML(str) { + TABLE_CLASS ("table table-condensed") { + TABLEHEAD() { + TABLER() { + TABLEH() { str << "Component"; } + TABLEH() { str << "Status"; } + } + } + TABLEBODY() { + TABLER() { + TABLED() { str << "FreshRank"; } + TABLED() { FreshWeight.RenderHtml(str); } + } + TABLER() { + TABLED() { str << "LevelRank"; } + TABLED() { LevelWeight.RenderHtml(str); } + } + } + } + } } void TDynamicPDiskWeightsManager::ToWhiteboard( diff --git a/ydb/core/blobstorage/vdisk/localrecovery/localrecovery_defs.cpp b/ydb/core/blobstorage/vdisk/localrecovery/localrecovery_defs.cpp index f75654db66..4fc51e1ba3 100644 --- a/ydb/core/blobstorage/vdisk/localrecovery/localrecovery_defs.cpp +++ b/ydb/core/blobstorage/vdisk/localrecovery/localrecovery_defs.cpp @@ -181,10 +181,10 @@ namespace NKikimr { void TLocalRecoveryInfo::OutputHtml(IOutputStream &str) const { str << "\n"; - HTML(str) { - DIV_CLASS("panel panel-default") { - DIV_CLASS("panel-heading") {str << "Local Recovery Info";} - DIV_CLASS("panel-body") { + HTML(str) { + DIV_CLASS("panel panel-default") { + DIV_CLASS("panel-heading") {str << "Local Recovery Info";} + DIV_CLASS("panel-body") { str << "LocalRecoveryStartTime: " << LocalRecoveryStartTime << "<br>"; if (LocalRecoveryFinishTime.GetValue() == 0) { // recovery is in progress @@ -196,9 +196,9 @@ namespace NKikimr { str << "LocalRecoveryDuration: " << duration << "<br>"; } OutputCounters(str, "", "<br>", "<hr>\n"); - } - } - } + } + } + } str << "\n"; } diff --git a/ydb/core/blobstorage/vdisk/query/query_statdb.cpp b/ydb/core/blobstorage/vdisk/query/query_statdb.cpp index 65bded589f..377bd452c0 100644 --- a/ydb/core/blobstorage/vdisk/query/query_statdb.cpp +++ b/ydb/core/blobstorage/vdisk/query/query_statdb.cpp @@ -46,7 +46,7 @@ namespace NKikimr { void Finish(IOutputStream &str, bool pretty) { - HTML(str) { + HTML(str) { if (pretty) { TABLED_ATTRS({{"data-text", Sprintf("%" PRIu64, Num)}, {"align", "right"}}) { SMALL() { FormatHumanReadable(str, Num, 1000, 2, ItemSuffix); @@ -58,9 +58,9 @@ namespace NKikimr { TABLED() {SMALL() {str << Num;}} TABLED() {SMALL() {str << DataSize;}} } - TABLED() {SMALL() {str << MinId.ToString();}} - TABLED() {SMALL() {str << MaxId.ToString();}} - } + TABLED() {SMALL() {str << MinId.ToString();}} + TABLED() {SMALL() {str << MaxId.ToString();}} + } } }; @@ -82,7 +82,7 @@ namespace NKikimr { void Finish(IOutputStream &str, ui64 tabletID, bool pretty) { auto tabletIDOutputer = [tabletID] (IOutputStream &str) { - HTML(str) { + HTML(str) { TABLED() { SMALL() { // tabletId and hyperlink to per tablet stat @@ -90,7 +90,7 @@ namespace NKikimr { << "\">" << tabletID << "</a>"; } } - } + } }; Finish(str, tabletIDOutputer, pretty); } @@ -107,17 +107,17 @@ namespace NKikimr { std::function<void (IOutputStream &)> t, bool pretty) { - HTML(str) { + HTML(str) { for (auto &c : Channels) { if (!c.Empty()) { - TABLER() { + TABLER() { t(str); - TABLED() {SMALL() {str << (&c - &Channels.front());}} + TABLED() {SMALL() {str << (&c - &Channels.front());}} c.Finish(str, pretty); - } + } } } - } + } } }; @@ -171,53 +171,53 @@ namespace NKikimr { } void Finish(IOutputStream &str, bool pretty) { - HTML(str) { - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { + HTML(str) { + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { str << "Per (Tablet, Channel) LogoBlobs DB Statistics " << "(raw data w/o garbage collection)"; - } - DIV_CLASS("panel-body") { + } + DIV_CLASS("panel-body") { TABLE_SORTABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "TabletID";} - TABLEH() {str << "Channel";} - TABLEH() {str << "Blobs";} - TABLEH() {str << "DataSize";} - TABLEH() {str << "MinId";} - TABLEH() {str << "MaxId";} - } - } - TABLEBODY() { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "TabletID";} + TABLEH() {str << "Channel";} + TABLEH() {str << "Blobs";} + TABLEH() {str << "DataSize";} + TABLEH() {str << "MinId";} + TABLEH() {str << "MaxId";} + } + } + TABLEBODY() { for (const auto &x : Hash) x.second->Finish(str, pretty); - } - } - } - } - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { + } + } + } + } + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { str << "Per Channel (all tablets) LogoBlobs DB Statistics"; - } - DIV_CLASS("panel-body") { + } + DIV_CLASS("panel-body") { TABLE_SORTABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "Channel";} - TABLEH() {str << "Blobs";} - TABLEH() {str << "DataSize";} - TABLEH() {str << "MinId";} - TABLEH() {str << "MaxId";} - } - } - TABLEBODY() { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "Channel";} + TABLEH() {str << "Blobs";} + TABLEH() {str << "DataSize";} + TABLEH() {str << "MinId";} + TABLEH() {str << "MaxId";} + } + } + TABLEBODY() { AllChannels.Finish(str, pretty); - } - } - } - } - } + } + } + } + } + } } }; } diff --git a/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp b/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp index 34be219abc..8db9509b85 100644 --- a/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp +++ b/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp @@ -41,25 +41,25 @@ namespace NKikimr { } void TEvReplFinished::TInfo::OutputHtml(IOutputStream &str) const { -#define PARAM(NAME, VALUE) TABLER() { \ - TABLED() { str << #NAME; } \ - TABLED() { str << VALUE; } \ - } +#define PARAM(NAME, VALUE) TABLER() { \ + TABLED() { str << #NAME; } \ + TABLED() { str << VALUE; } \ + } #define PARAM_V(NAME) PARAM(NAME, NAME) -#define GROUP(NAME) TABLER() TABLED_ATTRS({{"colspan", "2"}}) COLLAPSED_BUTTON_CONTENT(CreateGuidAsString(), NAME) TABLE() +#define GROUP(NAME) TABLER() TABLED_ATTRS({{"colspan", "2"}}) COLLAPSED_BUTTON_CONTENT(CreateGuidAsString(), NAME) TABLE() - HTML(str) { - SMALL() { - TABLE() { - TABLER() { - TABLEH() { str << "Parameter"; } - TABLEH() { str << "Value"; } - } - STRONG() { + HTML(str) { + SMALL() { + TABLE() { + TABLER() { + TABLEH() { str << "Parameter"; } + TABLEH() { str << "Value"; } + } + STRONG() { PARAM(Summary, DataRecoverySuccess << "/" << RecoveryScheduled << "/" << (ReplicaOk + RecoveryScheduled)); - } + } PARAM(Start, ToStringLocalTimeUpToSeconds(Start)); PARAM(End, ToStringLocalTimeUpToSeconds(End)); PARAM(Duration, End - Start); @@ -67,19 +67,19 @@ namespace NKikimr { PARAM_V(Eof); PARAM_V(DonorVDiskId); PARAM_V(DropDonor); - GROUP("Plan Generation Stats") { + GROUP("Plan Generation Stats") { PARAM_V(ReplicaOk); PARAM_V(RecoveryScheduled); PARAM_V(IgnoredDueToGC); - } - GROUP("Plan Execution Stats") { + } + GROUP("Plan Execution Stats") { PARAM_V(DataRecoverySuccess); PARAM_V(DataRecoveryFailure); PARAM_V(DataRecoveryNoParts); PARAM_V(DataRecoverySkip); PARAM_V(DataRecoveryPhantomCheck); - } - GROUP("Detailed Stats") { + } + GROUP("Detailed Stats") { PARAM_V(BytesRecovered); PARAM_V(LogoBlobsRecovered); PARAM_V(HugeLogoBlobsRecovered); @@ -91,8 +91,8 @@ namespace NKikimr { PARAM_V(PartsExact); PARAM_V(PartsRestored); PARAM_V(PartsMissing); - } - GROUP("Durations") { + } + GROUP("Durations") { PARAM_V(PreparePlanDuration); PARAM_V(TokenWaitDuration); PARAM_V(ProxyWaitDuration); @@ -101,8 +101,8 @@ namespace NKikimr { PARAM_V(CommitDuration); PARAM_V(OtherDuration); PARAM_V(PhantomDuration); - } - GROUP("VDisk Stats") { + } + GROUP("VDisk Stats") { PARAM_V(ProxyStat->VDiskReqs); PARAM_V(ProxyStat->VDiskRespOK); PARAM_V(ProxyStat->VDiskRespRACE); @@ -114,10 +114,10 @@ namespace NKikimr { PARAM_V(ProxyStat->LogoBlobNotOK); PARAM_V(ProxyStat->LogoBlobDataSize); PARAM_V(ProxyStat->OverflowedMsgs); - } - } - } - } + } + } + } + } #undef GROUP #undef PARAM_V #undef PARAM @@ -413,13 +413,13 @@ namespace NKikimr { template<typename Iter> void OutputRow(IOutputStream &str, Iter &it, Iter &e) { - HTML(str) { - TABLER() { + HTML(str) { + TABLER() { for (unsigned i = 0; i < 3 && it != e; i++, ++it) { - TABLED() { (*it)->OutputHtml(str); } + TABLED() { (*it)->OutputHtml(str); } } - } - } + } + } } template<typename Iter> @@ -427,18 +427,18 @@ namespace NKikimr { if (it != e) { OutputRow(str, it, e); if (it != e) { - HTML(str) { - TABLER() { + HTML(str) { + TABLER() { str << "<td colspan=3>"; TString id = CreateGuidAsString(); - COLLAPSED_BUTTON_CONTENT(id, "More") { - TABLE() { + COLLAPSED_BUTTON_CONTENT(id, "More") { + TABLE() { OutputQuantums(str, it, e); - } - } + } + } str << "</td>"; - } - } + } + } } } } @@ -449,10 +449,10 @@ namespace NKikimr { TStringStream str; unsigned historySize = HistorySize; str << "\n"; - HTML(str) { - DIV_CLASS("panel panel-success") { - DIV_CLASS("panel-heading") {str << "Repl";} - DIV_CLASS("panel-body") { + HTML(str) { + DIV_CLASS("panel panel-success") { + DIV_CLASS("panel-heading") {str << "Repl";} + DIV_CLASS("panel-body") { auto makeConnectedDonorDisks = [&]() -> TString { TStringBuilder s; s << "["; @@ -472,19 +472,19 @@ namespace NKikimr { << "NumConnectedPeerDisks: " << ConnectedPeerDisks.size() << "<br>" << "ConnectedDonorDisks: " << makeConnectedDonorDisks() << "<br>"; - TABLE_CLASS ("table table-condensed") { - CAPTION() STRONG() {str << "Last " << historySize << " replication quantums"; } - TABLEBODY() { + TABLE_CLASS ("table table-condensed") { + CAPTION() STRONG() {str << "Last " << historySize << " replication quantums"; } + TABLEBODY() { TVector<TEvReplFinished::TInfoPtr> quantums; for (auto it = History.Begin(); it != History.End(); ++it) { quantums.push_back(*it); } OutputQuantums(str, quantums.rbegin(), quantums.rend()); - } - } - } - } - } + } + } + } + } + } str << "\n"; Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str(), TDbMon::ReplId)); diff --git a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_monactors.cpp b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_monactors.cpp index 44b3c58c9c..0a5111cbd3 100644 --- a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_monactors.cpp +++ b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_monactors.cpp @@ -146,25 +146,25 @@ namespace NKikimr { void Finish(const TActorContext &ctx) { TStringStream str; - HTML(str) { - DIV_CLASS("row") { + HTML(str) { + DIV_CLASS("row") { DIV_CLASS("col-md-6") {Db->VCtx->VDiskCounters->OutputHtml(str);} - DIV_CLASS("col-md-6") {Output(SkeletonState, str, "Skeleton State");} - DIV_CLASS("col-md-6") {Output(LogCutterInfo, str, "Log Cutter");} - DIV_CLASS("col-md-6") {Output(HugeKeeperInfo, str, "Huge Blob Keeper");} - DIV_CLASS("col-md-6") {Output(DskSpaceTrackerInfo, str, "Disk Space Tracker");} - DIV_CLASS("col-md-6") {Output(LocalRecovInfo, str, "Local Recovery Info");} + DIV_CLASS("col-md-6") {Output(SkeletonState, str, "Skeleton State");} + DIV_CLASS("col-md-6") {Output(LogCutterInfo, str, "Log Cutter");} + DIV_CLASS("col-md-6") {Output(HugeKeeperInfo, str, "Huge Blob Keeper");} + DIV_CLASS("col-md-6") {Output(DskSpaceTrackerInfo, str, "Disk Space Tracker");} + DIV_CLASS("col-md-6") {Output(LocalRecovInfo, str, "Local Recovery Info");} DIV_CLASS("col-md-6") {Output(DelayedHugeBlobDeleterInfo, str, "Delayed Huge Blob Deleter Info");} DIV_CLASS("col-md-6") {Output(ScrubInfo, str, "Scrub Info");} // uses column wrapping (sum is greater than 12) - } + } Output(HullInfo, str, "Hull"); Output(SyncLogInfo, str, "Sync Log"); Output(SyncerInfo, str, "Syncer"); Output(ReplInfo, str, "Repl"); Output(AnubisRunnerInfo, str, "Anubis"); Output(HandoffInfo, str, "Handoff"); - } + } ctx.Send(NotifyId, new TEvents::TEvActorDied); ctx.Send(Ev->Sender, new NMon::TEvHttpInfoRes(str.Str())); @@ -250,45 +250,45 @@ namespace NKikimr { TString BuildForm(const TString &dbnameParam, const TString &itemName, const TString &placeholder, bool index) { TStringStream str; - HTML(str) { - FORM_CLASS("form-horizontal") { + HTML(str) { + FORM_CLASS("form-horizontal") { // hidden forms to pass current cgi params str << "<input type=\"hidden\" name=\"type\" value=\"query\">"; str << "<input type=\"hidden\" name=\"dbname\" value=\"" << dbnameParam << "\">"; - DIV_CLASS("control-group") { - LABEL_CLASS_FOR("control-label", "inputFrom") {str << "From (" << itemName << ")";} - DIV_CLASS("controls") { + DIV_CLASS("control-group") { + LABEL_CLASS_FOR("control-label", "inputFrom") {str << "From (" << itemName << ")";} + DIV_CLASS("controls") { str << "<input type=\"text\" id=\"inputFrom\" " "placeholder=\"" << placeholder << "\" name=\"from\">"; - } - } + } + } - DIV_CLASS("control-group") { - LABEL_CLASS_FOR("control-label", "inputTo") {str << "To (" << itemName << ")";} - DIV_CLASS("controls") { + DIV_CLASS("control-group") { + LABEL_CLASS_FOR("control-label", "inputTo") {str << "To (" << itemName << ")";} + DIV_CLASS("controls") { str << "<input type=\"text\" id=\"inputTo\" " "placeholder=\"" << placeholder << "\" name=\"to\">"; - } - } + } + } - DIV_CLASS("control-group") { - DIV_CLASS("controls") { + DIV_CLASS("control-group") { + DIV_CLASS("controls") { if (index) { - LABEL_CLASS("checkbox") { + LABEL_CLASS("checkbox") { str << "<input type=\"checkbox\" name=\"IndexOnly\" checked>Index Only</input>"; - } + } } - LABEL_CLASS("checkbox") { + LABEL_CLASS("checkbox") { str << "<input type=\"checkbox\" name=\"Internals\" checked>Show Internals</input>"; - } + } str << "<button type=\"submit\" name=\"submit\" class=\"btn btn-default\">Submit</button>"; str << "<strong>or</strong>"; str << "<button type=\"submit\" name=\"all\" class=\"btn btn-default\">Browse DB</button>"; - } - } - } - } + } + } + } + } return str.Str(); } @@ -402,8 +402,8 @@ namespace NKikimr { } void OutputOneQueryResult(IOutputStream &str, const NKikimrBlobStorage::TQueryResult &q) { - HTML(str) { - DIV_CLASS("well well-small") { + HTML(str) { + DIV_CLASS("well well-small") { const TLogoBlobID id = LogoBlobIDFromLogoBlobID(q.GetBlobID()); const TIngress ingress(q.GetIngress()); str << "Status: " << NKikimrProto::EReplyStatus_Name(q.GetStatus()) << "<br>"; @@ -415,8 +415,8 @@ namespace NKikimr { str << "FullDataSize: " << q.GetFullDataSize() << "<br>"; str << "Data: " << q.GetBuffer() << "<br>"; } - } - } + } + } } void Handle(TEvBlobStorage::TEvVGetResult::TPtr &ev, const TActorContext &ctx) { @@ -425,9 +425,9 @@ namespace NKikimr { ui32 size = rec.ResultSize(); TStringStream str; - HTML(str) { - DIV_CLASS("row") { - STRONG() { + HTML(str) { + DIV_CLASS("row") { + STRONG() { str << "From: " << From.ToString() << "<br>"; if (IsRangeQuery) str << "To: " << To.ToString() << "<br>"; @@ -436,15 +436,15 @@ namespace NKikimr { str << "Status: " << NKikimrProto::EReplyStatus_Name(rec.GetStatus()) << "<br>"; str << "VDisk: " << vdisk.ToString() << "<br>"; str << "Result size: " << size << "<br>"; - } - } - DIV_CLASS("row") { + } + } + DIV_CLASS("row") { for (ui32 i = 0; i < size; i++) { const NKikimrBlobStorage::TQueryResult &q = rec.GetResult(i); OutputOneQueryResult(str, q); } - } - } + } + } Finish(ctx, new NMon::TEvHttpInfoRes(str.Str())); } @@ -593,8 +593,8 @@ namespace NKikimr { void OutputOneResult(IOutputStream &str, const NKikimrBlobStorage::TBarrierKey &k, const NKikimrBlobStorage::TBarrierVal &v) { TIngressCachePtr ingressCache = TIngressCache::Create(Top, SelfVDiskId); - HTML(str) { - DIV_CLASS("well well-small") { + HTML(str) { + DIV_CLASS("well well-small") { str << "TabletId: " << k.GetTabletId() << "<br>"; str << "Channel: " << k.GetChannel() << "<br>"; str << "RecordGeneration: " << k.GetRecordGeneration() << "<br>"; @@ -605,8 +605,8 @@ namespace NKikimr { const TBarrierIngress ingress(TBarrierIngress::CreateFromRaw(v.GetIngress())); str << "Ingress: " << ingress.ToString(ingressCache.Get()) << "<br>"; } - } - } + } + } } void Handle(TEvBlobStorage::TEvVGetBarrierResult::TPtr &ev, const TActorContext &ctx) { @@ -621,20 +621,20 @@ namespace NKikimr { const ui32 size = rec.KeysSize();; TStringStream str; - HTML(str) { - DIV_CLASS("row") { - STRONG() { + HTML(str) { + DIV_CLASS("row") { + STRONG() { str << "Status: " << NKikimrProto::EReplyStatus_Name(rec.GetStatus()) << "<br>"; str << "VDisk: " << vdisk.ToString() << "<br>"; str << "Result size: " << size << "<br>"; - } - } - DIV_CLASS("row") { + } + } + DIV_CLASS("row") { for (ui32 i = 0; i < size; i++) { OutputOneResult(str, rec.GetKeys(i), rec.GetValues(i)); } - } - } + } + } Finish(ctx, new NMon::TEvHttpInfoRes(str.Str())); } @@ -928,10 +928,10 @@ namespace NKikimr { void Finish(const TActorContext &ctx) { TStringStream str; - HTML(str) { + HTML(str) { Output(SkeletonFrontAnswer, str, "SkeletonFront"); Output(SkeletonAnswer, str, "Skeleton"); - } + } ctx.Send(NotifyId, new TEvents::TEvActorDied); ctx.Send(Ev->Sender, new NMon::TEvHttpInfoRes(str.Str())); diff --git a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp index 96b813d317..51ed3ebab7 100644 --- a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp +++ b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp @@ -1921,66 +1921,66 @@ namespace NKikimr { constexpr ui32 threshold = 10000u; std::pair<ui32, ui32> actorQueues = ctx.CountMailboxEvents(threshold); - HTML(str) { - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { + HTML(str) { + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { str << "Skeleton"; - } - DIV_CLASS("panel-body") { + } + DIV_CLASS("panel-body") { if (OverloadHandler) { OverloadHandler->RenderHtml(str); } - TABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "Queues";} - TABLEH() {str << "Size";} - } - } - TABLEBODY() { - TABLER() { - TABLED() {str << "ActorQueue";} - TABLED() { + TABLE_CLASS ("table table-condensed") { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "Queues";} + TABLEH() {str << "Size";} + } + } + TABLEBODY() { + TABLER() { + TABLED() {str << "ActorQueue";} + TABLED() { if (actorQueues.first >= threshold) str << "More than " << threshold; else str << actorQueues.first; - } - } - TABLER() { - TABLED() {str << "MailboxQueue";} - TABLED() { + } + } + TABLER() { + TABLED() {str << "MailboxQueue";} + TABLED() { if (actorQueues.second >= threshold) str << "More than " << threshold; else str << actorQueues.second; - } - } - TABLER() { - TABLED() {str << "ElapsedTicksAsSeconds";} - TABLED() {str << GetElapsedTicksAsSeconds();} - } - TABLER() { - TABLED() {str << "HandledEvents";} - TABLED() {str << GetHandledEvents();} - } - } - } - - TABLE_CLASS("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "Setting";} - TABLEH() {str << "Value";} - } - } - TABLEBODY() { - TABLER() { - TABLED() {str << "SelfVDiskID";} - TABLED() {str << SelfVDiskId.ToString();} - } - TABLER() { + } + } + TABLER() { + TABLED() {str << "ElapsedTicksAsSeconds";} + TABLED() {str << GetElapsedTicksAsSeconds();} + } + TABLER() { + TABLED() {str << "HandledEvents";} + TABLED() {str << GetHandledEvents();} + } + } + } + + TABLE_CLASS("table table-condensed") { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "Setting";} + TABLEH() {str << "Value";} + } + } + TABLEBODY() { + TABLER() { + TABLED() {str << "SelfVDiskID";} + TABLED() {str << SelfVDiskId.ToString();} + } + TABLER() { TABLED() {str << "StoragePoolName";} TABLED() {str << Config->BaseInfo.StoragePoolName;} } @@ -1989,7 +1989,7 @@ namespace NKikimr { TABLED() {str << Db->GType.GetErasure();} } TABLER() { - TABLED() {str << "OrderNum/TotalVDisks";} + TABLED() {str << "OrderNum/TotalVDisks";} TABLED() { if (HullCtx && HullCtx->IngressCache) { str << ui32(HullCtx->IngressCache->VDiskOrderNum) << "/" @@ -1998,25 +1998,25 @@ namespace NKikimr { str << "Unknown/Unknown"; } } - } - TABLER() { - TABLED() {str << "VDiskKind";} + } + TABLER() { + TABLED() {str << "VDiskKind";} TABLED() {str << Config->BaseInfo.Kind;} - } - TABLER() { - TABLED() {str << "PDiskId";} + } + TABLER() { + TABLED() {str << "PDiskId";} TABLED() {str << Config->BaseInfo.PDiskId;} - } - TABLER() { - TABLED() {str << "BlobStorage GroupId (decimal)";} - TABLED() {str << GInfo->GroupID;} - } + } + TABLER() { + TABLED() {str << "BlobStorage GroupId (decimal)";} + TABLED() {str << GInfo->GroupID;} + } TABLER() { TABLED() {str << "VDiskIncarnationGuid";} TABLED() {str << Db->GetVDiskIncarnationGuid();} } - } - } + } + } if (PDiskCtx && PDiskCtx->Dsk) PDiskCtx->Dsk->OutputHtml(str); @@ -2027,10 +2027,10 @@ namespace NKikimr { OutOfSpaceLogic->RenderHtml(str); } } - } - } - } - + } + } + } + } //////////////////////////////////////////////////////////////////////// diff --git a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeletonfront.cpp b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeletonfront.cpp index 08c32a8921..05498d3efc 100644 --- a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeletonfront.cpp +++ b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeletonfront.cpp @@ -373,23 +373,23 @@ namespace NKikimr { // are different from zero TStringStream str; str << "\n"; - HTML(str) { - DIV_CLASS("panel panel-default") { - DIV_CLASS("panel-heading") { - SMALL() { - STRONG() {str << "INT: ";} - str << Name; - } - } - DIV_CLASS("panel-body") { + HTML(str) { + DIV_CLASS("panel panel-default") { + DIV_CLASS("panel-heading") { + SMALL() { + STRONG() {str << "INT: ";} + str << Name; + } + } + DIV_CLASS("panel-body") { OutputRecord("InFlightCount", str, InFlightCount, GetLight(EInFlightCount)); OutputRecord("InFlightCost", str, InFlightCost, GetLight(EInFlightCost)); OutputRecord("InFlightBytes", str, InFlightBytes, GetLight(EInFlightBytes)); OutputRecord("DelayedCount", str, DelayedCount, GetLight(EDelayedCount)); OutputRecord("DelayedBytes", str, DelayedBytes, GetLight(EDelayedBytes)); - } - } - } + } + } + } str << "\n"; return str.Str(); } @@ -538,21 +538,21 @@ namespace NKikimr { TString GenerateHtmlState() const { TStringStream str; str << "\n"; - HTML(str) { - DIV_CLASS("panel panel-default") { - DIV_CLASS("panel-heading") { - SMALL() { - STRONG() {str << "EXT: ";} - str << Name; - } - } - DIV_CLASS("panel-body") { + HTML(str) { + DIV_CLASS("panel panel-default") { + DIV_CLASS("panel-heading") { + SMALL() { + STRONG() {str << "EXT: ";} + str << Name; + } + } + DIV_CLASS("panel-body") { str << "Deadline: " << SkeletonFrontDeadline->Val() << "<br>"; str << "Overflow: " << SkeletonFrontOverflow->Val() << "<br>"; str << "IncorrectMsgId: " << SkeletonFrontIncorrectMsgId->Val() << "<br>"; - } - } - } + } + } + } str << "\n"; @@ -804,48 +804,48 @@ namespace NKikimr { std::pair<ui32, ui32> actorQueues = ctx.CountMailboxEvents(threshold); TStringStream str; - HTML(str) { + HTML(str) { DIV_CLASS("panel panel-default") { - DIV_CLASS("panel-heading") { + DIV_CLASS("panel-heading") { str << "SkeletonFront Actor"; - } - DIV_CLASS("panel-body") { - TABLE_CLASS ("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "Queues";} - TABLEH() {str << "Size";} - } - } - TABLEBODY() { - TABLER() { - TABLED() {str << "ActorQueue";} - TABLED() { + } + DIV_CLASS("panel-body") { + TABLE_CLASS ("table table-condensed") { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "Queues";} + TABLEH() {str << "Size";} + } + } + TABLEBODY() { + TABLER() { + TABLED() {str << "ActorQueue";} + TABLED() { if (actorQueues.first >= threshold) str << "More than " << threshold; else str << actorQueues.first; - } - } - TABLER() { - TABLED() {str << "MailboxQueue";} - TABLED() { + } + } + TABLER() { + TABLED() {str << "MailboxQueue";} + TABLED() { if (actorQueues.second >= threshold) str << "More than " << threshold; else str << actorQueues.second; - } - } - TABLER() { - TABLED() {str << "ElapsedTicksAsSeconds";} - TABLED() {str << GetElapsedTicksAsSeconds();} - } - TABLER() { - TABLED() {str << "HandledEvents";} - TABLED() {str << GetHandledEvents();} - } - } - } + } + } + TABLER() { + TABLED() {str << "ElapsedTicksAsSeconds";} + TABLED() {str << GetElapsedTicksAsSeconds();} + } + TABLER() { + TABLED() {str << "HandledEvents";} + TABLED() {str << GetHandledEvents();} + } + } + } } } } @@ -861,7 +861,7 @@ namespace NKikimr { str << "SkeletonFront"; } DIV_CLASS("panel-body") { - DIV_CLASS("row") { + DIV_CLASS("row") { // global VDisk state and SkeletonFront State DIV_CLASS("col-md-6") {str << GenerateHtmlStateForGlobalVDiskState(); } DIV_CLASS("col-md-6") {str << GenerateHtmlStateForSkeletonFrontActor(ctx); } @@ -875,21 +875,21 @@ namespace NKikimr { DIV_CLASS("col-md-2") {str << IntQueueFastGets->GenerateHtmlState();} DIV_CLASS("col-md-2") {str << IntQueueDiscover->GenerateHtmlState();} DIV_CLASS("col-md-2") {str << IntQueueLowGets->GenerateHtmlState();} - } - DIV_CLASS("row") { + } + DIV_CLASS("row") { // ext queues - DIV_CLASS("col-md-2") {str << ExtQueueTabletLogPuts.GenerateHtmlState();} - DIV_CLASS("col-md-2") {str << ExtQueueAsyncBlobPuts.GenerateHtmlState();} - DIV_CLASS("col-md-2") {str << ExtQueueUserDataPuts.GenerateHtmlState();} - DIV_CLASS("col-md-2") {str << ExtQueueAsyncGets.GenerateHtmlState();} - DIV_CLASS("col-md-2") {str << ExtQueueFastGets.GenerateHtmlState();} - DIV_CLASS("col-md-2") {str << ExtQueueDiscoverGets.GenerateHtmlState();} + DIV_CLASS("col-md-2") {str << ExtQueueTabletLogPuts.GenerateHtmlState();} + DIV_CLASS("col-md-2") {str << ExtQueueAsyncBlobPuts.GenerateHtmlState();} + DIV_CLASS("col-md-2") {str << ExtQueueUserDataPuts.GenerateHtmlState();} + DIV_CLASS("col-md-2") {str << ExtQueueAsyncGets.GenerateHtmlState();} + DIV_CLASS("col-md-2") {str << ExtQueueFastGets.GenerateHtmlState();} + DIV_CLASS("col-md-2") {str << ExtQueueDiscoverGets.GenerateHtmlState();} DIV_CLASS("col-md-2") {str << ExtQueueLowGets.GenerateHtmlState();} // uses column wrapping (sum is greater than 12) - } - } - } - } + } + } + } + } return str.Str(); } @@ -1268,19 +1268,19 @@ namespace NKikimr { // Set receiving time //////////////////////////////////////////////////////////////////////////// template <typename TPtr> - void SetReceivedTime(TPtr& ev) { - using TRecord = decltype(ev->Get()->Record); + void SetReceivedTime(TPtr& ev) { + using TRecord = decltype(ev->Get()->Record); if constexpr (std::is_convertible_v<TRecord, NKikimrBlobStorage::TEvVMovedPatch> || std::is_convertible_v<TRecord, NKikimrBlobStorage::TEvVPatchStart> || std::is_convertible_v<TRecord, NKikimrBlobStorage::TEvVPatchDiff> || std::is_convertible_v<TRecord, NKikimrBlobStorage::TEvVPatchXorDiff> || std::is_convertible_v<TRecord, NKikimrBlobStorage::TEvVPut> - || std::is_convertible_v<TRecord, NKikimrBlobStorage::TEvVMultiPut> - || std::is_convertible_v<TRecord, NKikimrBlobStorage::TEvVGet>) - { - const double usPerCycle = 1000000.0 / NHPTimer::GetCyclesPerSecond(); - ev->Get()->Record.MutableTimestamps()->SetReceivedByVDiskUs(GetCycleCountFast() * usPerCycle); - } + || std::is_convertible_v<TRecord, NKikimrBlobStorage::TEvVMultiPut> + || std::is_convertible_v<TRecord, NKikimrBlobStorage::TEvVGet>) + { + const double usPerCycle = 1000000.0 / NHPTimer::GetCyclesPerSecond(); + ev->Get()->Record.MutableTimestamps()->SetReceivedByVDiskUs(GetCycleCountFast() * usPerCycle); + } } //////////////////////////////////////////////////////////////////////////// @@ -1400,7 +1400,7 @@ namespace NKikimr { // update GroupInfo-related fields GInfo = info; const auto& prevVDiskId = std::exchange(SelfVDiskId, vdiskId); - + // forward message to Skeleton ctx.Send(SkeletonId, new TEvVGenerationChange(vdiskId, info)); diff --git a/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer.cpp b/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer.cpp index bf0179b4ed..13585fe5b2 100644 --- a/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer.cpp +++ b/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer.cpp @@ -98,15 +98,15 @@ namespace NKikimr { void RenderHtmlAndReply(const TActorContext &ctx, const TString &schedulerInfo) { TStringStream str; str << "\n"; - HTML(str) { - DIV_CLASS("panel panel-warning") { - DIV_CLASS("panel-heading") {str << "Syncer";} - DIV_CLASS("panel-body") { + HTML(str) { + DIV_CLASS("panel panel-warning") { + DIV_CLASS("panel-heading") {str << "Syncer";} + DIV_CLASS("panel-body") { str << LogAndPhase; str << schedulerInfo; - } - } - } + } + } + } str << "\n"; ctx.Send(ReplyId, new NMon::TEvHttpInfoRes(str.Str(), TDbMon::SyncerInfoId)); @@ -418,15 +418,15 @@ namespace NKikimr { } void LogAndPhaseToHtml(IOutputStream &str) const { - HTML(str) { - DIV_CLASS("row") { + HTML(str) { + DIV_CLASS("row") { str << "Phase: "; THtmlLightSignalRenderer(ToSignalLight(Phase), ToString(Phase)).Output(str); - } - COLLAPSED_BUTTON_CONTENT("syncerlogid", "Log") { - PRE() {str << Sublog.Get();} - } - } + } + COLLAPSED_BUTTON_CONTENT("syncerlogid", "Log") { + PRE() {str << Sublog.Get();} + } + } } void Handle(NMon::TEvHttpInfo::TPtr &ev, const TActorContext &ctx) { diff --git a/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer_data.cpp b/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer_data.cpp index 4de7b60fbe..8368bc1527 100644 --- a/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer_data.cpp +++ b/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer_data.cpp @@ -67,15 +67,15 @@ namespace NKikimr { } void TPeerSyncState::OutputHtml(IOutputStream &str) const { - HTML(str) { + HTML(str) { ESyncStatus state = LastSyncStatus; if (NSyncer::TPeerSyncState::Good(state)) { - PARA_CLASS("text-success") {str << state;} + PARA_CLASS("text-success") {str << state;} } else { - PARA_CLASS("text-warning") {str << state;} + PARA_CLASS("text-warning") {str << state;} } - SMALL() { - SMALL() { + SMALL() { + SMALL() { str << "SchTime: " << ToStringLocalTimeUpToSeconds(SchTime); str << "<br>"; str << "LastTry: " << ToStringLocalTimeUpToSeconds(LastTry); @@ -84,9 +84,9 @@ namespace NKikimr { str << "<br>"; str << "[Guid, SyncedLsn]: " << SyncState.ToString(); str << "<br>"; - } - } - } + } + } + } } @@ -108,15 +108,15 @@ namespace NKikimr { } void TPeerGuidInfo::OutputHtml(IOutputStream &str) const { - HTML(str) { - SMALL() { - SMALL() { + HTML(str) { + SMALL() { + SMALL() { str << "Guid: " << Info.GetGuid(); str << "<br>"; str << "State: " << Info.GetState(); - } - } - } + } + } + } } diff --git a/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer_scheduler.cpp b/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer_scheduler.cpp index 92ae94e89f..dd9c7d2445 100644 --- a/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer_scheduler.cpp +++ b/ydb/core/blobstorage/vdisk/syncer/blobstorage_syncer_scheduler.cpp @@ -42,9 +42,9 @@ namespace NKikimr { {} void operator() (IOutputStream &str, TSyncNeighbors::TConstIterator it) { - HTML(str) { - SMALL() { - STRONG() { + HTML(str) { + SMALL() { + STRONG() { // output VDiskID auto vd = GInfo.GetVDiskId(it->VDiskIdShort); str << "VDiskId: " << vd.ToStringWOGeneration() << "<br>"; @@ -58,16 +58,16 @@ namespace NKikimr { } else { str << "Node: " << info->Host << ":" << info->Port << "<br>"; } - } - } + } + } if (it->Myself) { - PARA_CLASS("text-info") {str << "Self";} + PARA_CLASS("text-info") {str << "Self";} } else { const NSyncer::TPeer &peer = it->Get(); peer.OutputHtml(str); } - } + } } }; diff --git a/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogdsk.cpp b/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogdsk.cpp index 1a2fb95e1c..e7005cfee1 100644 --- a/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogdsk.cpp +++ b/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogdsk.cpp @@ -214,9 +214,9 @@ namespace NKikimr { {} void TDiskRecLogSnapshot::OutputHtml(IOutputStream &str) const { - HTML(str) { - DIV_CLASS("well well-sm") { - STRONG() {str << "TDiskRecLog<br>";} + HTML(str) { + DIV_CLASS("well well-sm") { + STRONG() {str << "TDiskRecLog<br>";} if (Empty()) { str << "Log is empty<br>"; } else { @@ -225,9 +225,9 @@ namespace NKikimr { } str << "ChunksUsed: " << ManyIdxChunks.size() << "<br>"; // print out Index - PARA() { + PARA() { if (!ManyIdxChunks.empty()) { - str << "Index {Lsn, ChunkIdx, OffsetInPages, PagesNum}:"; + str << "Index {Lsn, ChunkIdx, OffsetInPages, PagesNum}:"; unsigned counter = 0; for (const auto &i: ManyIdxChunks) { if (++counter > 10) { @@ -238,9 +238,9 @@ namespace NKikimr { i->OutputHtml(str); } } - } - } - } + } + } + } } TString TDiskRecLogSnapshot::BoundariesToString() const { diff --git a/ydb/core/blobstorage/vdisk/synclog/blobstorage_syncloghttp.cpp b/ydb/core/blobstorage/vdisk/synclog/blobstorage_syncloghttp.cpp index cc10f0ceed..b4aa797f67 100644 --- a/ydb/core/blobstorage/vdisk/synclog/blobstorage_syncloghttp.cpp +++ b/ydb/core/blobstorage/vdisk/synclog/blobstorage_syncloghttp.cpp @@ -63,29 +63,29 @@ namespace NKikimr { void Finish(const TActorContext &ctx) { TStringStream str; str << "\n"; - HTML(str) { - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { + HTML(str) { + DIV_CLASS("panel panel-info") { + DIV_CLASS("panel-heading") { str << "SyncLog (LogStartLsn=" << SnapPtr->LogStartLsn << "; " << "EntryPointDbgInfo=" << SnapPtr->LastEntryPointDbgInfo.ToString() << ")"; - } - DIV_CLASS("panel-body") { - DIV_CLASS("row") { - DIV_CLASS("col-md-6") {SnapPtr->MemSnapPtr->OutputHtml(str);} - DIV_CLASS("col-md-6") {SnapPtr->DiskSnapPtr->OutputHtml(str);} - } - DIV_CLASS("row") { - DIV_CLASS("col-md-12") { + } + DIV_CLASS("panel-body") { + DIV_CLASS("row") { + DIV_CLASS("col-md-6") {SnapPtr->MemSnapPtr->OutputHtml(str);} + DIV_CLASS("col-md-6") {SnapPtr->DiskSnapPtr->OutputHtml(str);} + } + DIV_CLASS("row") { + DIV_CLASS("col-md-12") { NeighborsPtr->OutputHtml(str, *GInfo, NodesInfoMsg); - } - } + } + } COLLAPSED_BUTTON_CONTENT("synclog_logcontent", "Log") { PRE() {str << SublogContent;} } - } - } - } + } + } + } str << "\n"; ctx.Send(Ev->Sender, new NMon::TEvHttpInfoRes(str.Str(), TDbMon::SyncLogId)); diff --git a/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogmem.cpp b/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogmem.cpp index 75d6349b82..088c826969 100644 --- a/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogmem.cpp +++ b/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogmem.cpp @@ -61,9 +61,9 @@ namespace NKikimr { } void TMemRecLogSnapshot::OutputHtml(IOutputStream &str) const { - HTML(str) { - DIV_CLASS("well well-sm") { - STRONG() {str << "TMemRecLog<br>";} + HTML(str) { + DIV_CLASS("well well-sm") { + STRONG() {str << "TMemRecLog<br>";} if (Empty()) { str << "Log is empty<br>"; } else { @@ -73,7 +73,7 @@ namespace NKikimr { str << "RecsNum: " << RecsNum << "<br>"; str << "PagesNum: " << Size() << "<br>"; - PARA() { + PARA() { TMemRecLogSnapshot::TIterator it(this); it.SeekToFirst(); if (it.Valid()) { @@ -87,9 +87,9 @@ namespace NKikimr { if (it.Valid()) str << " <was cut>"; } - } - } - } + } + } + } } TString TMemRecLogSnapshot::BoundariesToString() const { diff --git a/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogneighbors.cpp b/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogneighbors.cpp index b9cf5c78ee..72ae5e98a4 100644 --- a/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogneighbors.cpp +++ b/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogneighbors.cpp @@ -22,9 +22,9 @@ namespace NKikimr { {} void operator() (IOutputStream &str, TNeighbors::TConstIterator it) { - HTML(str) { - SMALL() { - STRONG() { + HTML(str) { + SMALL() { + STRONG() { // output VDiskID auto vd = GInfo.GetVDiskId(it->VDiskIdShort); str << "VDiskId: " << vd.ToStringWOGeneration() << "<br>"; @@ -38,24 +38,24 @@ namespace NKikimr { } else { str << "Node: " << info->Host << ":" << info->Port << "<br>"; } - } - } + } + } if (it->Myself) { - PARA_CLASS("text-info") {str << "Self";} + PARA_CLASS("text-info") {str << "Self";} } else { - SMALL() { - SMALL() { + SMALL() { + SMALL() { str << "SyncedLsn: " << it->Get().SyncedLsn << "<br>"; ui64 lockedLsn = it->Get().LockedLsn; if (lockedLsn == ui64(-1)) str << "LockedLsn: no<br>"; else str << "LockedLsn: " << lockedLsn << "<br>"; - } - } + } + } } - } + } } }; diff --git a/ydb/core/driver_lib/run/config.h b/ydb/core/driver_lib/run/config.h index faf1797413..2792993f0a 100644 --- a/ydb/core/driver_lib/run/config.h +++ b/ydb/core/driver_lib/run/config.h @@ -29,7 +29,7 @@ union TBasicKikimrServicesMask { bool EnableTabletCountersAggregator:1; bool EnableRestartsCountPublisher:1; bool EnableBootstrapper:1; - bool EnableMediatorTimeCastProxy:1; + bool EnableMediatorTimeCastProxy:1; bool EnableTxProxy:1; bool EnableMiniKQLCompileService:1; bool EnableMessageBusServices:1; diff --git a/ydb/core/driver_lib/run/factories.h b/ydb/core/driver_lib/run/factories.h index 41a45b44e0..3457f688a7 100644 --- a/ydb/core/driver_lib/run/factories.h +++ b/ydb/core/driver_lib/run/factories.h @@ -16,15 +16,15 @@ #include <ydb/library/yql/providers/pq/cm_client/interface/client.h> -#include <library/cpp/actors/core/actorsystem.h> - +#include <library/cpp/actors/core/actorsystem.h> + #include <ydb/library/security/ydb_credentials_provider_factory.h> -#include <functional> -#include <unordered_map> -#include <unordered_set> -#include <vector> - +#include <functional> +#include <unordered_map> +#include <unordered_set> +#include <vector> + namespace NKikimr { // A way to parameterize YDB binary, we do it via a set of factories @@ -47,8 +47,8 @@ struct TModuleFactories { std::function<IActor*(const NYq::NConfig::TAuditConfig& auditConfig)> YqAuditServiceFactory; NKikimr::TYdbCredentialsProviderFactory YdbCredentialProviderFactory; - // Factory for grpc services - TGrpcServiceFactory GrpcServiceFactory; + // Factory for grpc services + TGrpcServiceFactory GrpcServiceFactory; std::shared_ptr<NPQ::IPersQueueMirrorReaderFactory> PersQueueMirrorReaderFactory; /// Factory for pdisk's aio engines diff --git a/ydb/core/driver_lib/run/kikimr_services_initializers.cpp b/ydb/core/driver_lib/run/kikimr_services_initializers.cpp index 819c1478d1..1853bfe4e0 100644 --- a/ydb/core/driver_lib/run/kikimr_services_initializers.cpp +++ b/ydb/core/driver_lib/run/kikimr_services_initializers.cpp @@ -149,12 +149,12 @@ #include <library/cpp/actors/core/events.h> #include <library/cpp/actors/core/executor_pool_basic.h> #include <library/cpp/actors/core/executor_pool_io.h> -#include <library/cpp/actors/core/executor_pool_united.h> +#include <library/cpp/actors/core/executor_pool_united.h> #include <library/cpp/actors/core/log.h> #include <library/cpp/actors/core/log_settings.h> #include <library/cpp/actors/core/mon.h> #include <library/cpp/actors/core/mon_stats.h> -#include <library/cpp/actors/core/probes.h> +#include <library/cpp/actors/core/probes.h> #include <library/cpp/actors/core/process_stats.h> #include <library/cpp/actors/core/scheduler_basic.h> #include <library/cpp/actors/core/io_dispatcher.h> @@ -169,7 +169,7 @@ #include <library/cpp/actors/interconnect/load.h> #include <library/cpp/actors/interconnect/poller_actor.h> #include <library/cpp/actors/interconnect/poller_tcp.h> -#include <library/cpp/actors/util/affinity.h> +#include <library/cpp/actors/util/affinity.h> #include <library/cpp/logger/global/global.h> #include <library/cpp/logger/log.h> @@ -178,8 +178,8 @@ #include <library/cpp/svnversion/svnversion.h> -#include <library/cpp/lwtrace/mon/mon_lwtrace.h> - +#include <library/cpp/lwtrace/mon/mon_lwtrace.h> + #include <util/digest/city.h> #include <util/generic/algorithm.h> #include <util/generic/size_literals.h> @@ -200,148 +200,148 @@ IKikimrServicesInitializer::IKikimrServicesInitializer(const TKikimrRunConfig& r // TBasicServicesInitializer -template <class TConfig> -static TCpuMask ParseAffinity(const TConfig& cfg) { - TCpuMask result; - if (cfg.GetCpuList()) { - result = TCpuMask(cfg.GetCpuList()); - } else if (cfg.GetX().size() > 0) { - result = TCpuMask(cfg.GetX().begin(), cfg.GetX().size()); - } else { // use all processors - TAffinity available; - available.Current(); - result = available; - } - if (cfg.GetExcludeCpuList()) { - result = result - TCpuMask(cfg.GetExcludeCpuList()); - } - return result; -} - -void AddExecutorPool( - TCpuManagerConfig& cpuManager, - const NKikimrConfig::TActorSystemConfig::TExecutor& poolConfig, - const NKikimrConfig::TActorSystemConfig& systemConfig, - ui32 poolId, - ui32 maxActivityType, - ui32& unitedThreads) +template <class TConfig> +static TCpuMask ParseAffinity(const TConfig& cfg) { + TCpuMask result; + if (cfg.GetCpuList()) { + result = TCpuMask(cfg.GetCpuList()); + } else if (cfg.GetX().size() > 0) { + result = TCpuMask(cfg.GetX().begin(), cfg.GetX().size()); + } else { // use all processors + TAffinity available; + available.Current(); + result = available; + } + if (cfg.GetExcludeCpuList()) { + result = result - TCpuMask(cfg.GetExcludeCpuList()); + } + return result; +} + +void AddExecutorPool( + TCpuManagerConfig& cpuManager, + const NKikimrConfig::TActorSystemConfig::TExecutor& poolConfig, + const NKikimrConfig::TActorSystemConfig& systemConfig, + ui32 poolId, + ui32 maxActivityType, + ui32& unitedThreads) { switch (poolConfig.GetType()) { case NKikimrConfig::TActorSystemConfig::TExecutor::BASIC: { - TBasicExecutorPoolConfig basic; - basic.PoolId = poolId; - basic.PoolName = poolConfig.GetName(); - basic.Threads = poolConfig.GetThreads(); - basic.SpinThreshold = poolConfig.GetSpinThreshold(); - basic.Affinity = ParseAffinity(poolConfig.GetAffinity()); - basic.RealtimePriority = poolConfig.GetRealtimePriority(); - basic.MaxActivityType = maxActivityType; + TBasicExecutorPoolConfig basic; + basic.PoolId = poolId; + basic.PoolName = poolConfig.GetName(); + basic.Threads = poolConfig.GetThreads(); + basic.SpinThreshold = poolConfig.GetSpinThreshold(); + basic.Affinity = ParseAffinity(poolConfig.GetAffinity()); + basic.RealtimePriority = poolConfig.GetRealtimePriority(); + basic.MaxActivityType = maxActivityType; if (poolConfig.HasTimePerMailboxMicroSecs()) { - basic.TimePerMailbox = TDuration::MicroSeconds(poolConfig.GetTimePerMailboxMicroSecs()); + basic.TimePerMailbox = TDuration::MicroSeconds(poolConfig.GetTimePerMailboxMicroSecs()); } else if (systemConfig.HasTimePerMailboxMicroSecs()) { - basic.TimePerMailbox = TDuration::MicroSeconds(systemConfig.GetTimePerMailboxMicroSecs()); + basic.TimePerMailbox = TDuration::MicroSeconds(systemConfig.GetTimePerMailboxMicroSecs()); } if (poolConfig.HasEventsPerMailbox()) { - basic.EventsPerMailbox = poolConfig.GetEventsPerMailbox(); + basic.EventsPerMailbox = poolConfig.GetEventsPerMailbox(); } else if (systemConfig.HasEventsPerMailbox()) { - basic.EventsPerMailbox = systemConfig.GetEventsPerMailbox(); + basic.EventsPerMailbox = systemConfig.GetEventsPerMailbox(); } - Y_VERIFY(basic.EventsPerMailbox != 0); - cpuManager.Basic.emplace_back(std::move(basic)); - break; - } - case NKikimrConfig::TActorSystemConfig::TExecutor::IO: { - TIOExecutorPoolConfig io; - io.PoolId = poolId; - io.PoolName = poolConfig.GetName(); - io.Threads = poolConfig.GetThreads(); - io.Affinity = ParseAffinity(poolConfig.GetAffinity()); - io.MaxActivityType = maxActivityType; - cpuManager.IO.emplace_back(std::move(io)); - break; - } - case NKikimrConfig::TActorSystemConfig::TExecutor::UNITED: { - TUnitedExecutorPoolConfig united; - united.PoolId = poolId; - united.PoolName = poolConfig.GetName(); - united.Concurrency = poolConfig.GetConcurrency(); - united.Weight = (NActors::TPoolWeight)poolConfig.GetWeight(); - united.Allowed = ParseAffinity(poolConfig.GetAffinity()); - united.MaxActivityType = maxActivityType; - if (poolConfig.HasTimePerMailboxMicroSecs()) { - united.TimePerMailbox = TDuration::MicroSeconds(poolConfig.GetTimePerMailboxMicroSecs()); - } else if (systemConfig.HasTimePerMailboxMicroSecs()) { - united.TimePerMailbox = TDuration::MicroSeconds(systemConfig.GetTimePerMailboxMicroSecs()); - } - if (poolConfig.HasEventsPerMailbox()) { - united.EventsPerMailbox = poolConfig.GetEventsPerMailbox(); - } else if (systemConfig.HasEventsPerMailbox()) { - united.EventsPerMailbox = systemConfig.GetEventsPerMailbox(); - } - Y_VERIFY(united.EventsPerMailbox != 0); - united.Balancing.Cpus = poolConfig.GetThreads(); - united.Balancing.MinCpus = poolConfig.GetMinThreads(); - united.Balancing.MaxCpus = poolConfig.GetMaxThreads(); - united.Balancing.Priority = poolConfig.GetBalancingPriority(); - united.Balancing.ToleratedLatencyUs = poolConfig.GetToleratedLatencyUs(); - unitedThreads += united.Balancing.Cpus; - cpuManager.United.emplace_back(std::move(united)); - break; - } + Y_VERIFY(basic.EventsPerMailbox != 0); + cpuManager.Basic.emplace_back(std::move(basic)); + break; + } + case NKikimrConfig::TActorSystemConfig::TExecutor::IO: { + TIOExecutorPoolConfig io; + io.PoolId = poolId; + io.PoolName = poolConfig.GetName(); + io.Threads = poolConfig.GetThreads(); + io.Affinity = ParseAffinity(poolConfig.GetAffinity()); + io.MaxActivityType = maxActivityType; + cpuManager.IO.emplace_back(std::move(io)); + break; + } + case NKikimrConfig::TActorSystemConfig::TExecutor::UNITED: { + TUnitedExecutorPoolConfig united; + united.PoolId = poolId; + united.PoolName = poolConfig.GetName(); + united.Concurrency = poolConfig.GetConcurrency(); + united.Weight = (NActors::TPoolWeight)poolConfig.GetWeight(); + united.Allowed = ParseAffinity(poolConfig.GetAffinity()); + united.MaxActivityType = maxActivityType; + if (poolConfig.HasTimePerMailboxMicroSecs()) { + united.TimePerMailbox = TDuration::MicroSeconds(poolConfig.GetTimePerMailboxMicroSecs()); + } else if (systemConfig.HasTimePerMailboxMicroSecs()) { + united.TimePerMailbox = TDuration::MicroSeconds(systemConfig.GetTimePerMailboxMicroSecs()); + } + if (poolConfig.HasEventsPerMailbox()) { + united.EventsPerMailbox = poolConfig.GetEventsPerMailbox(); + } else if (systemConfig.HasEventsPerMailbox()) { + united.EventsPerMailbox = systemConfig.GetEventsPerMailbox(); + } + Y_VERIFY(united.EventsPerMailbox != 0); + united.Balancing.Cpus = poolConfig.GetThreads(); + united.Balancing.MinCpus = poolConfig.GetMinThreads(); + united.Balancing.MaxCpus = poolConfig.GetMaxThreads(); + united.Balancing.Priority = poolConfig.GetBalancingPriority(); + united.Balancing.ToleratedLatencyUs = poolConfig.GetToleratedLatencyUs(); + unitedThreads += united.Balancing.Cpus; + cpuManager.United.emplace_back(std::move(united)); + break; + } default: Y_FAIL(); } } -static TUnitedWorkersConfig CreateUnitedWorkersConfig(const NKikimrConfig::TActorSystemConfig::TUnitedWorkers& config, ui32 unitedThreads) { - TUnitedWorkersConfig result; - result.CpuCount = unitedThreads; - if (config.HasCpuCount()) { - result.CpuCount = config.GetCpuCount(); - } - if (config.HasSpinThresholdUs()) { - result.SpinThresholdUs = config.GetSpinThresholdUs(); - } - if (config.HasPoolLimitUs()) { - result.PoolLimitUs = config.GetPoolLimitUs(); - } - if (config.HasEventLimitUs()) { - result.EventLimitUs = config.GetEventLimitUs(); - } - if (config.HasLimitPrecisionUs()) { - result.LimitPrecisionUs = config.GetLimitPrecisionUs(); - } - if (config.HasFastWorkerPriority()) { - result.FastWorkerPriority = config.GetFastWorkerPriority(); - } - if (config.HasIdleWorkerPriority()) { - result.IdleWorkerPriority = config.GetIdleWorkerPriority(); - } - if (config.HasAffinity()) { - result.Allowed = ParseAffinity(config.GetAffinity()); - } - if (config.HasNoRealtime()) { - result.NoRealtime = config.GetNoRealtime(); - } - if (config.HasNoAffinity()) { - result.NoAffinity = config.GetNoAffinity(); - } - if (config.HasBalancerPeriodUs()) { - result.Balancer.PeriodUs = config.GetBalancerPeriodUs(); - } - return result; -} - -static TCpuManagerConfig CreateCpuManagerConfig(const NKikimrConfig::TActorSystemConfig& config, ui32 maxActivityType) { - TCpuManagerConfig cpuManager; - ui32 unitedThreads = 0; - for (int poolId = 0; poolId < config.GetExecutor().size(); poolId++) { - AddExecutorPool(cpuManager, config.GetExecutor(poolId), config, poolId, maxActivityType, unitedThreads); - } - cpuManager.UnitedWorkers = CreateUnitedWorkersConfig(config.GetUnitedWorkers(), unitedThreads); - return cpuManager; -} - +static TUnitedWorkersConfig CreateUnitedWorkersConfig(const NKikimrConfig::TActorSystemConfig::TUnitedWorkers& config, ui32 unitedThreads) { + TUnitedWorkersConfig result; + result.CpuCount = unitedThreads; + if (config.HasCpuCount()) { + result.CpuCount = config.GetCpuCount(); + } + if (config.HasSpinThresholdUs()) { + result.SpinThresholdUs = config.GetSpinThresholdUs(); + } + if (config.HasPoolLimitUs()) { + result.PoolLimitUs = config.GetPoolLimitUs(); + } + if (config.HasEventLimitUs()) { + result.EventLimitUs = config.GetEventLimitUs(); + } + if (config.HasLimitPrecisionUs()) { + result.LimitPrecisionUs = config.GetLimitPrecisionUs(); + } + if (config.HasFastWorkerPriority()) { + result.FastWorkerPriority = config.GetFastWorkerPriority(); + } + if (config.HasIdleWorkerPriority()) { + result.IdleWorkerPriority = config.GetIdleWorkerPriority(); + } + if (config.HasAffinity()) { + result.Allowed = ParseAffinity(config.GetAffinity()); + } + if (config.HasNoRealtime()) { + result.NoRealtime = config.GetNoRealtime(); + } + if (config.HasNoAffinity()) { + result.NoAffinity = config.GetNoAffinity(); + } + if (config.HasBalancerPeriodUs()) { + result.Balancer.PeriodUs = config.GetBalancerPeriodUs(); + } + return result; +} + +static TCpuManagerConfig CreateCpuManagerConfig(const NKikimrConfig::TActorSystemConfig& config, ui32 maxActivityType) { + TCpuManagerConfig cpuManager; + ui32 unitedThreads = 0; + for (int poolId = 0; poolId < config.GetExecutor().size(); poolId++) { + AddExecutorPool(cpuManager, config.GetExecutor(poolId), config, poolId, maxActivityType, unitedThreads); + } + cpuManager.UnitedWorkers = CreateUnitedWorkersConfig(config.GetUnitedWorkers(), unitedThreads); + return cpuManager; +} + static TSchedulerConfig CreateSchedulerConfig(const NKikimrConfig::TActorSystemConfig::TScheduler &config) { const ui64 resolution = config.HasResolution() ? config.GetResolution() : 1024; Y_VERIFY_DEBUG((resolution & (resolution - 1)) == 0); // resolution must be power of 2 @@ -517,24 +517,24 @@ void TBasicServicesInitializer::InitializeServices(NActors::TActorSystemSetup* s setup->NodeId = NodeId; setup->MaxActivityType = GetActivityTypeCount(); - setup->CpuManager = CreateCpuManagerConfig(systemConfig, setup->MaxActivityType); - for (ui32 poolId = 0; poolId != setup->GetExecutorsCount(); ++poolId) { + setup->CpuManager = CreateCpuManagerConfig(systemConfig, setup->MaxActivityType); + for (ui32 poolId = 0; poolId != setup->GetExecutorsCount(); ++poolId) { const auto &execConfig = systemConfig.GetExecutor(poolId); - if (execConfig.HasInjectMadSquirrels()) { - for (ui32 i = execConfig.GetInjectMadSquirrels(); i > 0; --i) { + if (execConfig.HasInjectMadSquirrels()) { + for (ui32 i = execConfig.GetInjectMadSquirrels(); i > 0; --i) { setup->LocalServices.push_back(std::pair<TActorId, TActorSetupCmd>(TActorId(), TActorSetupCmd(CreateMadSquirrel(), TMailboxType::HTSwap, poolId))); - } - } + } + } } - + auto schedulerConfig = CreateSchedulerConfig(systemConfig.GetScheduler()); schedulerConfig.MonCounters = GetServiceCounters(counters, "utils"); setup->Scheduler.Reset(CreateSchedulerThread(schedulerConfig)); setup->LocalServices.emplace_back(MakeIoDispatcherActorId(), TActorSetupCmd(CreateIoDispatcherActor( schedulerConfig.MonCounters->GetSubgroup("subsystem", "io_dispatcher")), TMailboxType::HTSwap, systemPoolId)); - NLwTraceMonPage::DashboardRegistry().Register(NActors::LWTraceDashboards(setup)); - + NLwTraceMonPage::DashboardRegistry().Register(NActors::LWTraceDashboards(setup)); + if (Config.HasNameserviceConfig()) { const auto& nsConfig = Config.GetNameserviceConfig(); const TActorId resolverId = NDnsResolver::MakeDnsResolverActorId(); @@ -1374,13 +1374,13 @@ void TTabletsInitializer::InitializeServices( } } -// TMediatorTimeCastProxyInitializer +// TMediatorTimeCastProxyInitializer -TMediatorTimeCastProxyInitializer::TMediatorTimeCastProxyInitializer(const TKikimrRunConfig& runConfig) +TMediatorTimeCastProxyInitializer::TMediatorTimeCastProxyInitializer(const TKikimrRunConfig& runConfig) : IKikimrServicesInitializer(runConfig) { } -void TMediatorTimeCastProxyInitializer::InitializeServices( +void TMediatorTimeCastProxyInitializer::InitializeServices( NActors::TActorSystemSetup* setup, const NKikimr::TAppData* appData) { setup->LocalServices.push_back(std::pair<TActorId, TActorSetupCmd>( @@ -1684,8 +1684,8 @@ void TSelfPingInitializer::InitializeServices( const auto counters = GetServiceCounters(appData->Counters, "utils"); - for (size_t poolId = 0; poolId < setup->GetExecutorsCount(); ++poolId) { - const auto& poolName = setup->GetPoolName(poolId); + for (size_t poolId = 0; poolId < setup->GetExecutorsCount(); ++poolId) { + const auto& poolName = setup->GetPoolName(poolId); auto poolGroup = counters->GetSubgroup("execpool", poolName); auto counter = poolGroup->GetCounter("SelfPingMaxUs", false); auto cpuTimeCounter = poolGroup->GetCounter("CpuMatBenchNs", false); @@ -2172,10 +2172,10 @@ TSysViewServiceInitializer::TSysViewServiceInitializer(const TKikimrRunConfig& r void TSysViewServiceInitializer::InitializeServices(NActors::TActorSystemSetup* setup, const NKikimr::TAppData* appData) { NSysView::TExtCountersConfig config; - for (ui32 i = 0; i < setup->GetExecutorsCount(); ++i) { + for (ui32 i = 0; i < setup->GetExecutorsCount(); ++i) { config.Pools.push_back(NSysView::TExtCountersConfig::TPool{ - setup->GetPoolName(i), - setup->GetThreads(i)}); + setup->GetPoolName(i), + setup->GetThreads(i)}); } // external counters only for dynamic nodes diff --git a/ydb/core/driver_lib/run/kikimr_services_initializers.h b/ydb/core/driver_lib/run/kikimr_services_initializers.h index 407ce1bb7b..ae7477a227 100644 --- a/ydb/core/driver_lib/run/kikimr_services_initializers.h +++ b/ydb/core/driver_lib/run/kikimr_services_initializers.h @@ -197,7 +197,7 @@ public: class TMediatorTimeCastProxyInitializer : public IKikimrServicesInitializer { public: - TMediatorTimeCastProxyInitializer(const TKikimrRunConfig& runConfig); + TMediatorTimeCastProxyInitializer(const TKikimrRunConfig& runConfig); void InitializeServices(NActors::TActorSystemSetup *setup, const NKikimr::TAppData *appData) override; }; diff --git a/ydb/core/driver_lib/run/run.cpp b/ydb/core/driver_lib/run/run.cpp index a4f74aa4e0..f566c4829a 100644 --- a/ydb/core/driver_lib/run/run.cpp +++ b/ydb/core/driver_lib/run/run.cpp @@ -540,33 +540,33 @@ void TKikimrRunner::InitializeGRpc(const TKikimrRunConfig& runConfig) { bool hasAuth = services.empty(); names["auth"] = &hasAuth; - std::unordered_set<TString> enabled; + std::unordered_set<TString> enabled; for (const auto& name : services) { - enabled.insert(name); - } - for (const auto& name : grpcConfig.GetServicesEnabled()) { - enabled.insert(name); - } - - std::unordered_set<TString> disabled; - for (const auto& name : grpcConfig.GetServicesDisabled()) { - disabled.insert(name); - } - - for (const auto& name : enabled) { + enabled.insert(name); + } + for (const auto& name : grpcConfig.GetServicesEnabled()) { + enabled.insert(name); + } + + std::unordered_set<TString> disabled; + for (const auto& name : grpcConfig.GetServicesDisabled()) { + disabled.insert(name); + } + + for (const auto& name : enabled) { auto itName = names.find(name); if (itName != names.end()) { *(itName->second) = true; - } else if (!ModuleFactories || !ModuleFactories->GrpcServiceFactory.Has(name)) { + } else if (!ModuleFactories || !ModuleFactories->GrpcServiceFactory.Has(name)) { Cerr << "Unknown grpc service \"" << name << "\" was not enabled!" << Endl; } } - for (const auto& name : disabled) { + for (const auto& name : disabled) { auto itName = names.find(name); if (itName != names.end()) { *(itName->second) = false; - } else if (!ModuleFactories || !ModuleFactories->GrpcServiceFactory.Has(name)) { + } else if (!ModuleFactories || !ModuleFactories->GrpcServiceFactory.Has(name)) { Cerr << "Unknown grpc service \"" << name << "\" was not disabled!" << Endl; } } @@ -593,14 +593,14 @@ void TKikimrRunner::InitializeGRpc(const TKikimrRunConfig& runConfig) { hasImport = true; } - for (const auto& [name, isEnabled] : names) { - if (*isEnabled) { - enabled.insert(name); - } else { - disabled.insert(name); - } - } - + for (const auto& [name, isEnabled] : names) { + if (*isEnabled) { + enabled.insert(name); + } else { + disabled.insert(name); + } + } + const auto grpcRequestProxyId = NGRpcService::CreateGRpcRequestProxyId(); if (hasLegacy) { @@ -697,8 +697,8 @@ void TKikimrRunner::InitializeGRpc(const TKikimrRunConfig& runConfig) { server.AddService(new NGRpcService::TGRpcDiscoveryService(ActorSystem.Get(), Counters, grpcRequestProxyId)); } - if (hasRateLimiter) { - server.AddService(new NQuoter::TRateLimiterGRpcService(ActorSystem.Get(), Counters, grpcRequestProxyId)); + if (hasRateLimiter) { + server.AddService(new NQuoter::TRateLimiterGRpcService(ActorSystem.Get(), Counters, grpcRequestProxyId)); } if (hasMonitoring) { @@ -721,12 +721,12 @@ void TKikimrRunner::InitializeGRpc(const TKikimrRunConfig& runConfig) { if (hasLogStore) { server.AddService(new NGRpcService::TGRpcYdbLogStoreService(ActorSystem.Get(), Counters, grpcRequestProxyId)); } - - if (ModuleFactories) { - for (const auto& service : ModuleFactories->GrpcServiceFactory.Create(enabled, disabled, ActorSystem.Get(), Counters, grpcRequestProxyId)) { - server.AddService(service); - } - } + + if (ModuleFactories) { + for (const auto& service : ModuleFactories->GrpcServiceFactory.Create(enabled, disabled, ActorSystem.Get(), Counters, grpcRequestProxyId)) { + server.AddService(service); + } + } }; if (appConfig.HasGRpcConfig() && appConfig.GetGRpcConfig().GetStartGRpcProxy()) { @@ -1199,8 +1199,8 @@ TIntrusivePtr<TServiceInitializersList> TKikimrRunner::CreateServiceInitializers if (serviceMask.EnableBootstrapper) { sil->AddServiceInitializer(new TBootstrapperInitializer(runConfig)); } - if (serviceMask.EnableMediatorTimeCastProxy) { - sil->AddServiceInitializer(new TMediatorTimeCastProxyInitializer(runConfig)); + if (serviceMask.EnableMediatorTimeCastProxy) { + sil->AddServiceInitializer(new TMediatorTimeCastProxyInitializer(runConfig)); } if (serviceMask.EnableTxProxy) { sil->AddServiceInitializer(new TTxProxyInitializer(runConfig)); diff --git a/ydb/core/engine/minikql/minikql_engine_host.cpp b/ydb/core/engine/minikql/minikql_engine_host.cpp index 36c35f32cc..a3aede0501 100644 --- a/ydb/core/engine/minikql/minikql_engine_host.cpp +++ b/ydb/core/engine/minikql/minikql_engine_host.cpp @@ -1,5 +1,5 @@ -#include "minikql_engine_host.h" - +#include "minikql_engine_host.h" + #include <ydb/core/tablet_flat/flat_dbase_sz_env.h> #include <ydb/core/tablet_flat/flat_row_state.h> #include <ydb/core/tablet_flat/flat_table_stats.h> @@ -9,9 +9,9 @@ #include <library/cpp/containers/stack_vector/stack_vec.h> -namespace NKikimr { +namespace NKikimr { namespace NMiniKQL { - + using TScheme = NTable::TScheme; void ConvertTableKeys(const TScheme& scheme, const TScheme::TTableInfo* tableInfo, @@ -36,89 +36,89 @@ void ConvertTableKeys(const TScheme& scheme, const TScheme::TTableInfo* tableInf } TEngineHost::TEngineHost(NTable::TDatabase& db, TEngineHostCounters& counters, const TEngineHostSettings& settings) - : Db(db) + : Db(db) , Scheme(db.GetScheme()) , Settings(settings) , Counters(counters) -{} - -ui64 TEngineHost::GetShardId() const { +{} + +ui64 TEngineHost::GetShardId() const { return Settings.ShardId; -} - +} + const TScheme::TTableInfo* TEngineHost::GetTableInfo(const TTableId& tableId) const { return Scheme.GetTableInfo(LocalTableId(tableId)); } -bool TEngineHost::IsReadonly() const { +bool TEngineHost::IsReadonly() const { return Settings.IsReadonly; -} - - -bool TEngineHost::IsValidKey(TKeyDesc& key, std::pair<ui64, ui64>& maxSnapshotTime) const { +} + + +bool TEngineHost::IsValidKey(TKeyDesc& key, std::pair<ui64, ui64>& maxSnapshotTime) const { Y_UNUSED(maxSnapshotTime); - auto* tableInfo = Scheme.GetTableInfo(LocalTableId(key.TableId)); - -#define EH_VALIDATE(cond, err_status) \ - do { \ - if (!(cond)) { \ - key.Status = TKeyDesc::EStatus::err_status; \ - return false; \ - } \ - } while(false) \ - /**/ - - EH_VALIDATE(tableInfo, NotExists); // Table does not exist - EH_VALIDATE(key.KeyColumnTypes.size() <= tableInfo->KeyColumns.size(), TypeCheckFailed); - - // Specified keys types should be valid for any operation - for (size_t keyIdx = 0; keyIdx < key.KeyColumnTypes.size(); keyIdx++) { - ui32 keyCol = tableInfo->KeyColumns[keyIdx]; - NScheme::TTypeId vtype = Scheme.GetColumnInfo(tableInfo, keyCol)->PType; - EH_VALIDATE(key.KeyColumnTypes[keyIdx] == vtype, TypeCheckFailed); - } - - if (key.RowOperation == TKeyDesc::ERowOperation::Read) { + auto* tableInfo = Scheme.GetTableInfo(LocalTableId(key.TableId)); + +#define EH_VALIDATE(cond, err_status) \ + do { \ + if (!(cond)) { \ + key.Status = TKeyDesc::EStatus::err_status; \ + return false; \ + } \ + } while(false) \ + /**/ + + EH_VALIDATE(tableInfo, NotExists); // Table does not exist + EH_VALIDATE(key.KeyColumnTypes.size() <= tableInfo->KeyColumns.size(), TypeCheckFailed); + + // Specified keys types should be valid for any operation + for (size_t keyIdx = 0; keyIdx < key.KeyColumnTypes.size(); keyIdx++) { + ui32 keyCol = tableInfo->KeyColumns[keyIdx]; + NScheme::TTypeId vtype = Scheme.GetColumnInfo(tableInfo, keyCol)->PType; + EH_VALIDATE(key.KeyColumnTypes[keyIdx] == vtype, TypeCheckFailed); + } + + if (key.RowOperation == TKeyDesc::ERowOperation::Read) { if (key.Range.Point) { EH_VALIDATE(key.KeyColumnTypes.size() == tableInfo->KeyColumns.size(), TypeCheckFailed); } else { EH_VALIDATE(key.KeyColumnTypes.size() <= tableInfo->KeyColumns.size(), TypeCheckFailed); } - - for (size_t i = 0; i < key.Columns.size(); i++) { - const TKeyDesc::TColumnOp& cop = key.Columns[i]; + + for (size_t i = 0; i < key.Columns.size(); i++) { + const TKeyDesc::TColumnOp& cop = key.Columns[i]; if (IsSystemColumn(cop.Column)) { continue; } - auto* cinfo = Scheme.GetColumnInfo(tableInfo, cop.Column); - EH_VALIDATE(cinfo, TypeCheckFailed); // Unknown column - NScheme::TTypeId vtype = cinfo->PType; - EH_VALIDATE(cop.ExpectedType == vtype, TypeCheckFailed); - EH_VALIDATE(cop.Operation == TKeyDesc::EColumnOperation::Read, OperationNotSupported); - } - } else if (key.RowOperation == TKeyDesc::ERowOperation::Update) { - EH_VALIDATE(key.KeyColumnTypes.size() == tableInfo->KeyColumns.size(), TypeCheckFailed); // Key must be full for updates - for (size_t i = 0; i < key.Columns.size(); i++) { - const TKeyDesc::TColumnOp& cop = key.Columns[i]; - auto* cinfo = Scheme.GetColumnInfo(tableInfo, cop.Column); - EH_VALIDATE(cinfo, TypeCheckFailed); // Unknown column - NScheme::TTypeId vtype = cinfo->PType; + auto* cinfo = Scheme.GetColumnInfo(tableInfo, cop.Column); + EH_VALIDATE(cinfo, TypeCheckFailed); // Unknown column + NScheme::TTypeId vtype = cinfo->PType; + EH_VALIDATE(cop.ExpectedType == vtype, TypeCheckFailed); + EH_VALIDATE(cop.Operation == TKeyDesc::EColumnOperation::Read, OperationNotSupported); + } + } else if (key.RowOperation == TKeyDesc::ERowOperation::Update) { + EH_VALIDATE(key.KeyColumnTypes.size() == tableInfo->KeyColumns.size(), TypeCheckFailed); // Key must be full for updates + for (size_t i = 0; i < key.Columns.size(); i++) { + const TKeyDesc::TColumnOp& cop = key.Columns[i]; + auto* cinfo = Scheme.GetColumnInfo(tableInfo, cop.Column); + EH_VALIDATE(cinfo, TypeCheckFailed); // Unknown column + NScheme::TTypeId vtype = cinfo->PType; EH_VALIDATE(!cop.ExpectedType || cop.ExpectedType == vtype, TypeCheckFailed); - EH_VALIDATE(cop.Operation == TKeyDesc::EColumnOperation::Set, OperationNotSupported); // TODO[serxa]: support inplace operations in IsValidKey - } - } else if (key.RowOperation == TKeyDesc::ERowOperation::Erase) { - EH_VALIDATE(key.KeyColumnTypes.size() == tableInfo->KeyColumns.size(), TypeCheckFailed); - } else { - EH_VALIDATE(false, OperationNotSupported); - } - -#undef EH_VALIDATE - - key.Status = TKeyDesc::EStatus::Ok; - return true; -} - + EH_VALIDATE(cop.Operation == TKeyDesc::EColumnOperation::Set, OperationNotSupported); // TODO[serxa]: support inplace operations in IsValidKey + } + } else if (key.RowOperation == TKeyDesc::ERowOperation::Erase) { + EH_VALIDATE(key.KeyColumnTypes.size() == tableInfo->KeyColumns.size(), TypeCheckFailed); + } else { + EH_VALIDATE(false, OperationNotSupported); + } + +#undef EH_VALIDATE + + key.Status = TKeyDesc::EStatus::Ok; + return true; +} + ui64 TEngineHost::CalculateReadSize(const TVector<const TKeyDesc*>& keys) const { NTable::TSizeEnv env; @@ -127,8 +127,8 @@ ui64 TEngineHost::CalculateReadSize(const TVector<const TKeyDesc*>& keys) const } return env.GetSize(); -} - +} + void TEngineHost::DoCalculateReadSize(const TKeyDesc& key, NTable::TSizeEnv& env) const { if (TSysTables::IsSystemTable(key.TableId)) return; @@ -262,26 +262,26 @@ void TEngineHost::PinPages(const TVector<THolder<TKeyDesc>>& keys, ui64 pageFaul NUdf::TUnboxedValue TEngineHost::SelectRow(const TTableId& tableId, const TArrayRef<const TCell>& row, TStructLiteral* columnIds, TOptionalType* returnType, const TReadTarget& readTarget, const THolderFactory& holderFactory) -{ - // It is assumed that returnType has form: - // optinal<struct<optional<data>, - // ... - // optional<data>>> +{ + // It is assumed that returnType has form: + // optinal<struct<optional<data>, + // ... + // optional<data>>> // And that struct type has column tags stored inside it's member names as numbers Y_UNUSED(returnType); Y_UNUSED(readTarget); - - ui64 localTid = LocalTableId(tableId); + + ui64 localTid = LocalTableId(tableId); Y_VERIFY(localTid, "table not exist"); - const TScheme::TTableInfo* tableInfo = Scheme.GetTableInfo(localTid); + const TScheme::TTableInfo* tableInfo = Scheme.GetTableInfo(localTid); TSmallVec<TRawTypeValue> key; - ConvertKeys(tableInfo, row, key); - + ConvertKeys(tableInfo, row, key); + TSmallVec<NTable::TTag> tags; TSmallVec<NTable::TTag> systemColumnTags; AnalyzeRowType(columnIds, tags, systemColumnTags); - + TSmallVec<NScheme::TTypeId> cellTypes; cellTypes.reserve(tags.size()); for (size_t i = 0; i < tags.size(); ++i) @@ -290,8 +290,8 @@ NUdf::TUnboxedValue TEngineHost::SelectRow(const TTableId& tableId, const TArray NTable::TRowState dbRow; if (key.size() != Db.GetScheme().GetTableInfo(localTid)->KeyColumns.size()) - throw TSchemeErrorTabletException(); - + throw TSchemeErrorTabletException(); + Counters.NSelectRow++; Settings.KeyAccessSampler->AddSample(tableId, row); @@ -787,28 +787,28 @@ NUdf::TUnboxedValue TEngineHost::SelectRange(const TTableId& tableId, const TTab TStructLiteral* columnIds, TListLiteral* skipNullKeys, TStructType* returnType, const TReadTarget& readTarget, ui64 itemsLimit, ui64 bytesLimit, bool reverse, std::pair<const TListLiteral*, const TListLiteral*> forbidNullArgs, const THolderFactory& holderFactory) -{ - // It is assumed that returnType has form: - // struct< - // list< // named 'List' - // struct<optional<data>, - // ... - // optional<data>> - // > - // , data // named 'Truncated' (boolean showing that itemsLimit or bytesLimit striked) - // > - // And that struct type has column tags stored inside it's member names (ugly hack) +{ + // It is assumed that returnType has form: + // struct< + // list< // named 'List' + // struct<optional<data>, + // ... + // optional<data>> + // > + // , data // named 'Truncated' (boolean showing that itemsLimit or bytesLimit striked) + // > + // And that struct type has column tags stored inside it's member names (ugly hack) Y_UNUSED(readTarget); - + // TODO[serxa]: support for Point in SelectRange() Y_VERIFY(!range.Point, "point request in TEngineHost::SelectRange"); - - ui64 localTid = LocalTableId(tableId); + + ui64 localTid = LocalTableId(tableId); Y_VERIFY(localTid, "table not exist"); - - // Analyze resultType - TStructType* outerStructType = AS_TYPE(TStructType, returnType); + + // Analyze resultType + TStructType* outerStructType = AS_TYPE(TStructType, returnType); Y_VERIFY_DEBUG(outerStructType->GetMembersCount() == 2, "Unexpected type structure of returnType in TEngineHost::SelectRange()"); Y_VERIFY_DEBUG(outerStructType->GetMemberName(0) == "List", @@ -819,7 +819,7 @@ NUdf::TUnboxedValue TEngineHost::SelectRange(const TTableId& tableId, const TTab TSmallVec<NTable::TTag> tags; TSmallVec<NTable::TTag> systemColumnTags; AnalyzeRowType(columnIds, tags, systemColumnTags); - + TSmallVec<bool> skipNullKeysFlags = CreateBoolVec(skipNullKeys); TSmallVec<bool> forbidNullArgsFrom = CreateBoolVec(forbidNullArgs.first); TSmallVec<bool> forbidNullArgsTo = CreateBoolVec(forbidNullArgs.second); @@ -847,28 +847,28 @@ NUdf::TUnboxedValue TEngineHost::SelectRange(const TTableId& tableId, const TTab return NUdf::TUnboxedValuePod(new TSelectRangeResult(Db, Scheme, holderFactory, tableId, localTid, tags, skipNullKeysFlags, range, itemsLimit, bytesLimit, reverse, *this, systemColumnTags, GetShardId(), Settings.KeyAccessSampler)); -} - -// Updates the single row. Column in commands must be unique. +} + +// Updates the single row. Column in commands must be unique. void TEngineHost::UpdateRow(const TTableId& tableId, const TArrayRef<const TCell>& row, const TArrayRef<const TUpdateCommand>& commands) { - ui64 localTid = LocalTableId(tableId); + ui64 localTid = LocalTableId(tableId); Y_VERIFY(localTid, "table not exist"); - const TScheme::TTableInfo* tableInfo = Scheme.GetTableInfo(localTid); + const TScheme::TTableInfo* tableInfo = Scheme.GetTableInfo(localTid); TSmallVec<TRawTypeValue> key; ui64 keyBytes = 0; ConvertTableKeys(Scheme, tableInfo, row, key, &keyBytes); - + ui64 valueBytes = 0; TSmallVec<NTable::TUpdateOp> ops; - for (size_t i = 0; i < commands.size(); i++) { - const TUpdateCommand& upd = commands[i]; + for (size_t i = 0; i < commands.size(); i++) { + const TUpdateCommand& upd = commands[i]; Y_VERIFY(upd.Operation == TKeyDesc::EColumnOperation::Set); // TODO[serxa]: support inplace update in update row - NScheme::TTypeId vtype = Scheme.GetColumnInfo(tableInfo, upd.Column)->PType; + NScheme::TTypeId vtype = Scheme.GetColumnInfo(tableInfo, upd.Column)->PType; ops.emplace_back(upd.Column, NTable::ECellOp::Set, upd.Value.IsNull() ? TRawTypeValue() : TRawTypeValue(upd.Value.Data(), upd.Value.Size(), vtype)); valueBytes += upd.Value.IsNull() ? 1 : upd.Value.Size(); - } - + } + if (auto collector = GetChangeCollector(tableId)) { collector->SetWriteVersion(GetWriteVersion(tableId)); if (collector->NeedToReadKeys()) { @@ -886,13 +886,13 @@ void TEngineHost::UpdateRow(const TTableId& tableId, const TArrayRef<const TCell Settings.KeyAccessSampler->AddSample(tableId, row); Counters.NUpdateRow++; Counters.UpdateRowBytes += keyBytes + valueBytes; -} - -// Erases the single row. +} + +// Erases the single row. void TEngineHost::EraseRow(const TTableId& tableId, const TArrayRef<const TCell>& row) { - ui64 localTid = LocalTableId(tableId); + ui64 localTid = LocalTableId(tableId); Y_VERIFY(localTid, "table not exist"); - const TScheme::TTableInfo* tableInfo = Scheme.GetTableInfo(localTid); + const TScheme::TTableInfo* tableInfo = Scheme.GetTableInfo(localTid); TSmallVec<TRawTypeValue> key; ui64 keyBytes = 0; ConvertTableKeys(Scheme, tableInfo, row, key, &keyBytes); @@ -914,40 +914,40 @@ void TEngineHost::EraseRow(const TTableId& tableId, const TArrayRef<const TCell> Settings.KeyAccessSampler->AddSample(tableId, row); Counters.NEraseRow++; Counters.EraseRowBytes += keyBytes + 8; -} - -// Check that table is erased -bool TEngineHost::IsPathErased(const TTableId& tableId) const { - ui64 localTid = LocalTableId(tableId); - return (localTid? !Scheme.GetTableInfo(localTid): true); -} - -// Returns whether row belong this shard. +} + +// Check that table is erased +bool TEngineHost::IsPathErased(const TTableId& tableId) const { + ui64 localTid = LocalTableId(tableId); + return (localTid? !Scheme.GetTableInfo(localTid): true); +} + +// Returns whether row belong this shard. bool TEngineHost::IsMyKey(const TTableId& tableId, const TArrayRef<const TCell>& row) const { Y_UNUSED(tableId); Y_UNUSED(row); - return true; -} - + return true; +} + ui64 TEngineHost::GetTableSchemaVersion(const TTableId&) const { return 0; } -ui64 TEngineHost::LocalTableId(const TTableId& tableId) const { +ui64 TEngineHost::LocalTableId(const TTableId& tableId) const { return tableId.PathId.LocalPathId; -} - +} + void TEngineHost::ConvertKeys(const TScheme::TTableInfo* tableInfo, const TArrayRef<const TCell>& row, TSmallVec<TRawTypeValue>& key) const -{ +{ ConvertTableKeys(Scheme, tableInfo, row, key, nullptr); -} - +} + void TEngineHost::SetPeriodicCallback(TPeriodicCallback&& callback) { PeriodicCallback = std::move(callback); } void AnalyzeRowType(TStructLiteral* columnIds, TSmallVec<NTable::TTag>& tags, TSmallVec<NTable::TTag>& systemColumnTags) { - // Find out tags that should be read in Select*() functions + // Find out tags that should be read in Select*() functions tags.reserve(columnIds->GetValuesCount()); for (ui32 i = 0; i < columnIds->GetValuesCount(); i++) { NTable::TTag columnId = AS_VALUE(TDataLiteral, columnIds->GetValue(i))->AsValue().Get<ui32>(); @@ -956,9 +956,9 @@ void AnalyzeRowType(TStructLiteral* columnIds, TSmallVec<NTable::TTag>& tags, TS } else { tags.push_back(columnId); } - } -} - + } +} + NUdf::TUnboxedValue GetCellValue(const TCell& cell, NScheme::TTypeId type) { if (cell.IsNull()) { return NUdf::TUnboxedValue(); @@ -1033,4 +1033,4 @@ NUdf::TUnboxedValue GetCellValue(const TCell& cell, NScheme::TTypeId type) { } } -}} +}} diff --git a/ydb/core/engine/minikql/minikql_engine_host.h b/ydb/core/engine/minikql/minikql_engine_host.h index 012ee6891b..9f9cce8465 100644 --- a/ydb/core/engine/minikql/minikql_engine_host.h +++ b/ydb/core/engine/minikql/minikql_engine_host.h @@ -1,17 +1,17 @@ -#pragma once - +#pragma once + #include "change_collector_iface.h" -#include <util/generic/cast.h> +#include <util/generic/cast.h> #include <ydb/core/tablet/tablet_exception.h> #include <ydb/library/yql/minikql/mkql_function_registry.h> #include <ydb/library/yql/minikql/mkql_node_cast.h> #include <ydb/library/yql/minikql/mkql_program_builder.h> #include <ydb/core/engine/mkql_engine_flat_host.h> - -namespace NKikimr { + +namespace NKikimr { namespace NMiniKQL { - + struct TEngineHostCounters { ui64 NSelectRow = 0; ui64 NSelectRange = 0; @@ -90,15 +90,15 @@ struct TEngineHostSettings { }; class TEngineHost : public IEngineFlatHost { -public: +public: using TScheme = NTable::TScheme; explicit TEngineHost(NTable::TDatabase& db, TEngineHostCounters& counters, const TEngineHostSettings& settings = TEngineHostSettings()); - ui64 GetShardId() const override; + ui64 GetShardId() const override; const TScheme::TTableInfo* GetTableInfo(const TTableId& tableId) const override; - bool IsReadonly() const override; - bool IsValidKey(TKeyDesc& key, std::pair<ui64, ui64>& maxSnapshotTime) const override; + bool IsReadonly() const override; + bool IsValidKey(TKeyDesc& key, std::pair<ui64, ui64>& maxSnapshotTime) const override; ui64 CalculateReadSize(const TVector<const TKeyDesc*>& keys) const override; ui64 CalculateResultSize(const TKeyDesc& key) const override; void PinPages(const TVector<THolder<TKeyDesc>>& keys, ui64 pageFaultCount) override; @@ -115,10 +115,10 @@ public: void UpdateRow(const TTableId& tableId, const TArrayRef<const TCell>& row, const TArrayRef<const TUpdateCommand>& commands) override; void EraseRow(const TTableId& tableId, const TArrayRef<const TCell>& row) override; - bool IsPathErased(const TTableId& tableId) const override; + bool IsPathErased(const TTableId& tableId) const override; bool IsMyKey(const TTableId& tableId, const TArrayRef<const TCell>& row) const override; ui64 GetTableSchemaVersion(const TTableId&) const override; - + void SetPeriodicCallback(TPeriodicCallback&& callback) override; void ExecPeriodicCallback() { if (PeriodicCallback) { PeriodicCallback();} } @@ -129,20 +129,20 @@ public: virtual IChangeCollector* GetChangeCollector(const TTableId& tableId) const = 0; -protected: - virtual ui64 LocalTableId(const TTableId& tableId) const; +protected: + virtual ui64 LocalTableId(const TTableId& tableId) const; void ConvertKeys(const TScheme::TTableInfo* tableInfo, const TArrayRef<const TCell>& row, TSmallVec<TRawTypeValue>& key) const; void DoCalculateReadSize(const TKeyDesc& key, NTable::TSizeEnv& env) const; -protected: +protected: NTable::TDatabase& Db; - const TScheme& Scheme; + const TScheme& Scheme; const TEngineHostSettings Settings; TEngineHostCounters& Counters; TPeriodicCallback PeriodicCallback; -}; - +}; + class TUnversionedEngineHost : public TEngineHost { public: using TEngineHost::TEngineHost; @@ -173,4 +173,4 @@ NUdf::TUnboxedValue CreateSelectRangeLazyRowsList(NTable::TDatabase& db, const N void ConvertTableKeys(const NTable::TScheme& scheme, const NTable::TScheme::TTableInfo* tableInfo, const TArrayRef<const TCell>& row, TSmallVec<TRawTypeValue>& key, ui64* keyDataBytes); -}} +}} diff --git a/ydb/core/engine/mkql_engine_flat_host_ut.cpp b/ydb/core/engine/mkql_engine_flat_host_ut.cpp index 68679f168d..58a099e138 100644 --- a/ydb/core/engine/mkql_engine_flat_host_ut.cpp +++ b/ydb/core/engine/mkql_engine_flat_host_ut.cpp @@ -1,4 +1,4 @@ -#include "mkql_engine_flat_host.h" +#include "mkql_engine_flat_host.h" #include <ydb/core/engine/minikql/minikql_engine_host.h> #include <ydb/core/tablet_flat/flat_cxx_database.h> #include <ydb/library/yql/minikql/mkql_function_registry.h> @@ -8,16 +8,16 @@ #include <library/cpp/testing/unittest/registar.h> #include <ydb/core/tablet_flat/test/libs/table/test_dummy.h> - + namespace NKikimr { namespace NMiniKQL { -using namespace NTabletFlatExecutor; +using namespace NTabletFlatExecutor; Y_UNIT_TEST_SUITE(TMiniKQLEngineFlatHostTest) { struct Schema : NIceDb::Schema { - struct TestTable : Table<1> { + struct TestTable : Table<1> { struct ID : Column<1, NUdf::TDataType<ui64>::Id> {}; struct Value : Column<2, NUdf::TDataType<ui64>::Id> {}; struct Name : Column<3, NUdf::TDataType<NUdf::TUtf8>::Id> {}; @@ -25,78 +25,78 @@ Y_UNIT_TEST_SUITE(TMiniKQLEngineFlatHostTest) { using TKey = TableKey<ID>; using TColumns = TableColumns<ID, Value, Name, BoolValue>; - }; + }; - struct TestTable2 : Table<2> { + struct TestTable2 : Table<2> { struct ID1 : Column<1, NUdf::TDataType<ui64>::Id> {}; struct ID2 : Column<2, NUdf::TDataType<ui64>::Id> {}; using TKey = TableKey<ID1, ID2>; using TColumns = TableColumns<ID1, ID2>; - }; + }; using TTables = SchemaTables<TestTable, TestTable2>; - }; + }; Y_UNIT_TEST(ShardId) { NTable::TDatabase DB; TEngineHostCounters hostCounters; TUnversionedEngineHost host(DB, hostCounters, TEngineHostSettings(100)); - UNIT_ASSERT_VALUES_EQUAL(host.GetShardId(), 100); + UNIT_ASSERT_VALUES_EQUAL(host.GetShardId(), 100); } Y_UNIT_TEST(Basic) { NTable::TDatabase DB; NIceDb::TNiceDb db(DB); - { // Create tables + { // Create tables NTable::TDummyEnv env; DB.Begin(1, env); db.Materialize<Schema>(); DB.Commit(1, true); - } + } - { // Fill tables with some stuff + { // Fill tables with some stuff NTable::TDummyEnv env; DB.Begin(2, env); - for (ui64 i = 0; i < 1000; ++i) { - db.Table<Schema::TestTable>().Key(i).Update(NIceDb::TUpdate<Schema::TestTable::Value>(i), - NIceDb::TUpdate<Schema::TestTable::Name>(ToString(i)), - NIceDb::TUpdate<Schema::TestTable::BoolValue>(i % 2 == 0)); - } + for (ui64 i = 0; i < 1000; ++i) { + db.Table<Schema::TestTable>().Key(i).Update(NIceDb::TUpdate<Schema::TestTable::Value>(i), + NIceDb::TUpdate<Schema::TestTable::Name>(ToString(i)), + NIceDb::TUpdate<Schema::TestTable::BoolValue>(i % 2 == 0)); + } DB.Commit(2, true); - } + } - { // Execute some minikql + { // Execute some minikql NTable::TDummyEnv env; DB.Begin(3, env); TEngineHostCounters hostCounters; TUnversionedEngineHost host(DB, hostCounters); - // TODO: ... MINIKQL ... + // TODO: ... MINIKQL ... Y_UNUSED(host); DB.Commit(3, true); - } + } - { // Check data + { // Check data NTable::TDummyEnv env; DB.Begin(4, env); - for (ui64 i = 0; i < 1000; ++i) { + for (ui64 i = 0; i < 1000; ++i) { auto row = db.Table<Schema::TestTable>().Key(i).Select<Schema::TestTable::Value, Schema::TestTable::Name, Schema::TestTable::BoolValue>(); UNIT_ASSERT(row.IsReady()); UNIT_ASSERT(row.IsValid()); ui64 value = row.GetValue<Schema::TestTable::Value>(); TString name = row.GetValue<Schema::TestTable::Name>(); bool boolValue = row.GetValue<Schema::TestTable::BoolValue>(); - UNIT_ASSERT(value == i); - UNIT_ASSERT(ToString(value) == name); - UNIT_ASSERT(boolValue == (i % 2 == 0)); - } + UNIT_ASSERT(value == i); + UNIT_ASSERT(ToString(value) == name); + UNIT_ASSERT(boolValue == (i % 2 == 0)); + } DB.Commit(4, true); - } + } } } -}} +}} diff --git a/ydb/core/engine/ut/ya.make b/ydb/core/engine/ut/ya.make index 02810813ab..826dd7f38e 100644 --- a/ydb/core/engine/ut/ya.make +++ b/ydb/core/engine/ut/ya.make @@ -14,20 +14,20 @@ TIMEOUT(150) SIZE(MEDIUM) SRCS( - mkql_engine_flat_host_ut.cpp + mkql_engine_flat_host_ut.cpp mkql_engine_flat_ut.cpp kikimr_program_builder_ut.cpp mkql_proto_ut.cpp ) -PEERDIR( +PEERDIR( ydb/core/engine/minikql ydb/core/kqp/ut/common ydb/core/tablet_flat/test/libs/table ydb/library/mkql_proto/ut/helpers ydb/library/yql/public/udf/service/exception_policy -) - +) + YQL_LAST_ABI_VERSION() END() diff --git a/ydb/core/erasure/erasure.cpp b/ydb/core/erasure/erasure.cpp index a41b027932..963cfc6158 100644 --- a/ydb/core/erasure/erasure.cpp +++ b/ydb/core/erasure/erasure.cpp @@ -161,7 +161,7 @@ public: ui32 FirstSmallPartIdx; ui32 TotalParts; - ui64 WholeBlocks; // Data consists of (WholeBlocks * BlockSize + TailSize) bytes + ui64 WholeBlocks; // Data consists of (WholeBlocks * BlockSize + TailSize) bytes ui32 TailSize; ui32 Prime; @@ -171,9 +171,9 @@ public: TBufferDataPart BufferDataPart; char *Data; - // Maximum blocks to be split during one run in incremental mode - static constexpr ui64 IncrementalSplitMaxBlocks = 1024; - + // Maximum blocks to be split during one run in incremental mode + static constexpr ui64 IncrementalSplitMaxBlocks = 1024; + TBlockParams(TErasureType::ECrcMode crcMode, const TErasureType &type, ui64 dataSize) { DataSize = dataSize; PartUserSize = type.PartUserSize(dataSize); @@ -210,22 +210,22 @@ public: if (isStripe) { Data = data; } else { - // - // All data is a matrix. Matrix cell is ColumnSize bytes. - // Each part is a matrix column (continuous in memory). - // Each block is a matrix row (not continuous in memory). - // Cells are numerated as they appear in memory. - // - // 1 5 9 C <-- 4 required pointers (beginning of each data part) - // 2 6 A D - // 3 7 B E - // 4 8 * - // - // There are two large parts (1st and 2nd), followed by two small parts (3rd and 4th). - // Large part is exactly ColumnSize bytes larger than small part. - // The last part is special, it can contain tail less than ColumnSize bytes (shown as *) - // - + // + // All data is a matrix. Matrix cell is ColumnSize bytes. + // Each part is a matrix column (continuous in memory). + // Each block is a matrix row (not continuous in memory). + // Cells are numerated as they appear in memory. + // + // 1 5 9 C <-- 4 required pointers (beginning of each data part) + // 2 6 A D + // 3 7 B E + // 4 8 * + // + // There are two large parts (1st and 2nd), followed by two small parts (3rd and 4th). + // Large part is exactly ColumnSize bytes larger than small part. + // The last part is special, it can contain tail less than ColumnSize bytes (shown as *) + // + BufferDataPart.resize(DataParts); for (ui32 i = 0; i < FirstSmallPartIdx; ++i) { BufferDataPart[i] = (ui64*)(data + i * LargePartSize); @@ -330,10 +330,10 @@ public: template <bool isStripe, bool isFromDataParts> - void EoSplitWhole(char *data, TBufferDataPart &bufferDataPart, TDataPartSet &outPartSet, ui64 writePosition, ui64 firstBlock, ui64 lastBlock) { + void EoSplitWhole(char *data, TBufferDataPart &bufferDataPart, TDataPartSet &outPartSet, ui64 writePosition, ui64 firstBlock, ui64 lastBlock) { const ui32 lastPartIdx = DataParts + 1; const ui32 m = Prime; - for (ui64 blockIdx = firstBlock; blockIdx != lastBlock; ++blockIdx) { + for (ui64 blockIdx = firstBlock; blockIdx != lastBlock; ++blockIdx) { #define IN_EL_STRIPE(row, column) *((ui64*)data + (blockIdx * LineCount + (row)) * DataParts + (column)) #define IN_EL_BLOCK(row, column) bufferDataPart[column][blockIdx * LineCount + (row)] @@ -544,18 +544,18 @@ public: } } - template <bool isStripe, bool isFromDataParts, bool isIncremental = false> + template <bool isStripe, bool isFromDataParts, bool isIncremental = false> void EoSplit(TDataPartSet &outPartSet) { - ui64 readPosition = isIncremental? ColumnSize * outPartSet.CurBlockIdx: 0; - ui64 firstBlock = isIncremental? outPartSet.CurBlockIdx: 0; - ui64 lastBlock = isIncremental? Min(WholeBlocks, firstBlock + IncrementalSplitMaxBlocks): WholeBlocks; - outPartSet.CurBlockIdx = lastBlock; + ui64 readPosition = isIncremental? ColumnSize * outPartSet.CurBlockIdx: 0; + ui64 firstBlock = isIncremental? outPartSet.CurBlockIdx: 0; + ui64 lastBlock = isIncremental? Min(WholeBlocks, firstBlock + IncrementalSplitMaxBlocks): WholeBlocks; + outPartSet.CurBlockIdx = lastBlock; bool hasTail = TailSize; - + if (isFromDataParts) { Y_VERIFY(outPartSet.Parts[0].Offset % ColumnSize == 0); readPosition = outPartSet.Parts[0].Offset; - lastBlock = Min(WholeBlocks - readPosition / ColumnSize, outPartSet.Parts[0].Size / ColumnSize); + lastBlock = Min(WholeBlocks - readPosition / ColumnSize, outPartSet.Parts[0].Size / ColumnSize); hasTail = TailSize && (outPartSet.Parts[0].Size + readPosition > WholeBlocks * ColumnSize); } TRACE(__LINE__ << " EoSplit readPosition# " << readPosition @@ -564,11 +564,11 @@ public: << " fullDataSize# " << outPartSet.FullDataSize << Endl); // Use all whole columns of all the parts - EoSplitWhole<isStripe, isFromDataParts>(Data, BufferDataPart, outPartSet, readPosition, firstBlock, lastBlock); + EoSplitWhole<isStripe, isFromDataParts>(Data, BufferDataPart, outPartSet, readPosition, firstBlock, lastBlock); // Use the remaining parts to fill in the last block // Write the tail of the data - if (hasTail && outPartSet.IsSplitDone()) { + if (hasTail && outPartSet.IsSplitDone()) { char lastBlockSource[MAX_TOTAL_PARTS * (MAX_TOTAL_PARTS - 2) * sizeof(ui64)] = {}; TBufferDataPart bufferDataPart; if (!isFromDataParts) { @@ -576,7 +576,7 @@ public: } EoSplitWhole<isStripe, isFromDataParts>(lastBlockSource, bufferDataPart, outPartSet, - WholeBlocks * ColumnSize, 0, 1); + WholeBlocks * ColumnSize, 0, 1); } } @@ -1406,26 +1406,26 @@ void EoBlockSplit(TErasureType::ECrcMode crcMode, const TErasureType &type, cons // Prepare input data pointers p.PrepareInputDataPointers<isStripe>(const_cast<char*>(buffer.data())); - // Prepare if not yet - if (!outPartSet.IsSplitStarted()) { - outPartSet.StartSplit(p.WholeBlocks); - - outPartSet.FullDataSize = buffer.size(); - outPartSet.PartsMask = ~((~(ui32)0) << p.TotalParts); - outPartSet.Parts.resize(p.TotalParts); - for (ui32 i = 0; i < p.TotalParts; ++i) { - TRACE("Line# " << __LINE__ << Endl); - Refurbish(outPartSet.Parts[i], p.PartContainerSize); - } - outPartSet.MemoryConsumed = p.TotalParts * outPartSet.Parts[0].MemoryConsumed(); - } - - p.EoSplit<isStripe, false, true>(outPartSet); - - // Finalize if split has been done to completion - if (outPartSet.IsSplitDone()) { - PadAndCrcParts(crcMode, p, outPartSet); - } + // Prepare if not yet + if (!outPartSet.IsSplitStarted()) { + outPartSet.StartSplit(p.WholeBlocks); + + outPartSet.FullDataSize = buffer.size(); + outPartSet.PartsMask = ~((~(ui32)0) << p.TotalParts); + outPartSet.Parts.resize(p.TotalParts); + for (ui32 i = 0; i < p.TotalParts; ++i) { + TRACE("Line# " << __LINE__ << Endl); + Refurbish(outPartSet.Parts[i], p.PartContainerSize); + } + outPartSet.MemoryConsumed = p.TotalParts * outPartSet.Parts[0].MemoryConsumed(); + } + + p.EoSplit<isStripe, false, true>(outPartSet); + + // Finalize if split has been done to completion + if (outPartSet.IsSplitDone()) { + PadAndCrcParts(crcMode, p, outPartSet); + } } template <bool isStripe> @@ -2587,13 +2587,13 @@ static void VerifyPartSizes(TDataPartSet& partSet, size_t definedPartEndIdx) { } void TErasureType::SplitData(ECrcMode crcMode, const TString& buffer, TDataPartSet& outPartSet) const { - outPartSet.ResetSplit(); - do { - IncrementalSplitData(crcMode, buffer, outPartSet); - } while (!outPartSet.IsSplitDone()); -} - -void TErasureType::IncrementalSplitData(ECrcMode crcMode, const TString& buffer, TDataPartSet& outPartSet) const { + outPartSet.ResetSplit(); + do { + IncrementalSplitData(crcMode, buffer, outPartSet); + } while (!outPartSet.IsSplitDone()); +} + +void TErasureType::IncrementalSplitData(ECrcMode crcMode, const TString& buffer, TDataPartSet& outPartSet) const { const TErasureParameters& erasure = ErasureSpeciesParameters[ErasureSpecies]; switch (erasure.ErasureFamily) { case TErasureType::ErasureMirror: @@ -2601,7 +2601,7 @@ void TErasureType::IncrementalSplitData(ECrcMode crcMode, const TString& buffer, break; case TErasureType::ErasureParityStripe: switch (erasure.ParityParts) { - case 1: + case 1: XorBlockSplit<true>(crcMode ,*this, buffer, outPartSet); break; case 2: @@ -2637,9 +2637,9 @@ void TErasureType::IncrementalSplitData(ECrcMode crcMode, const TString& buffer, ythrow TWithBackTrace<yexception>() << "Unknown ErasureFamily = " << (i32)erasure.ErasureFamily; break; } - if (outPartSet.IsSplitDone()) { - VerifyPartSizes(outPartSet, Max<size_t>()); - } + if (outPartSet.IsSplitDone()) { + VerifyPartSizes(outPartSet, Max<size_t>()); + } } void MirrorSplitDiff(const TErasureType &type, const TVector<TDiff> &diffs, TPartDiffSet& outDiffSet) { diff --git a/ydb/core/erasure/erasure.h b/ydb/core/erasure/erasure.h index 35bd68c2d2..0d9222c614 100644 --- a/ydb/core/erasure/erasure.h +++ b/ydb/core/erasure/erasure.h @@ -147,16 +147,16 @@ struct TPartFragment { }; struct TDataPartSet { - ui64 FullDataSize = 0; - ui32 PartsMask = 0; + ui64 FullDataSize = 0; + ui32 PartsMask = 0; TStackVec<TPartFragment, 8> Parts; TPartFragment FullDataFragment; - ui64 MemoryConsumed = 0; - bool IsFragment = false; + ui64 MemoryConsumed = 0; + bool IsFragment = false; - // Incremental split KIKIMR-10794 - ui64 WholeBlocks = 0; // Blocks to be split (not including tail) - ui64 CurBlockIdx = 0; // Blocks have been already split + // Incremental split KIKIMR-10794 + ui64 WholeBlocks = 0; // Blocks to be split (not including tail) + ui64 CurBlockIdx = 0; // Blocks have been already split void Detach() { for (size_t i = 0; i < Parts.size(); ++i) { @@ -164,26 +164,26 @@ struct TDataPartSet { } FullDataFragment.Detach(); } - - void StartSplit(ui64 wholeBlocks) { - WholeBlocks = wholeBlocks; - } - - bool IsSplitStarted() const { - return WholeBlocks != 0; - } - - bool IsSplitDone() const { - // True if either: - // - split is not started - // - split is done - return CurBlockIdx >= WholeBlocks; - } - - void ResetSplit() { - WholeBlocks = 0; - CurBlockIdx = 0; - } + + void StartSplit(ui64 wholeBlocks) { + WholeBlocks = wholeBlocks; + } + + bool IsSplitStarted() const { + return WholeBlocks != 0; + } + + bool IsSplitDone() const { + // True if either: + // - split is not started + // - split is done + return CurBlockIdx >= WholeBlocks; + } + + void ResetSplit() { + WholeBlocks = 0; + CurBlockIdx = 0; + } }; struct TPartOffsetRange { // [Begin, End) @@ -318,7 +318,7 @@ struct TErasureType { ui32 Prime() const; void SplitData(ECrcMode crcMode, const TString& buffer, TDataPartSet& outPartSet) const; - void IncrementalSplitData(ECrcMode crcMode, const TString& buffer, TDataPartSet& outPartSet) const; + void IncrementalSplitData(ECrcMode crcMode, const TString& buffer, TDataPartSet& outPartSet) const; void SplitDiffs(ECrcMode crcMode, ui32 dataSize, const TVector<TDiff> &diffs, TPartDiffSet& outDiffSet) const; void ApplyDiff(ECrcMode crcMode, ui8 *dst, const TVector<TDiff> &diffs) const; diff --git a/ydb/core/grpc_services/base/base.h b/ydb/core/grpc_services/base/base.h index 44b25c4a5f..fbc945daca 100644 --- a/ydb/core/grpc_services/base/base.h +++ b/ydb/core/grpc_services/base/base.h @@ -4,7 +4,7 @@ #include <grpc++/support/slice.h> #include <library/cpp/grpc/server/grpc_request_base.h> -#include <library/cpp/string_utils/quote/quote.h> +#include <library/cpp/string_utils/quote/quote.h> #include <ydb/public/api/protos/ydb_issue_message.pb.h> #include <ydb/public/api/protos/ydb_status_codes.pb.h> @@ -26,20 +26,20 @@ class TAppConfig; } namespace NKikimr { - + namespace NSchemeCache { struct TSchemeCacheNavigate; } -namespace NRpcService { - -struct TRlPath { - TString CoordinationNode; - TString ResourcePath; -}; - -} - +namespace NRpcService { + +struct TRlPath { + TString CoordinationNode; + TString ResourcePath; +}; + +} + namespace NGRpcService { using TYdbIssueMessageType = Ydb::Issue::IssueMessage; @@ -202,12 +202,12 @@ struct TRpcServices { EvAnalyticsInternalGetTask, EvAnalyticsInternalWriteTaskResult, EvAnalyticsInternalNodesHealthCheck, - EvCreateYndxRateLimiterResource, - EvAlterYndxRateLimiterResource, - EvDropYndxRateLimiterResource, - EvListYndxRateLimiterResources, - EvDescribeYndxRateLimiterResource, - EvAcquireYndxRateLimiterResource, + EvCreateYndxRateLimiterResource, + EvAlterYndxRateLimiterResource, + EvDropYndxRateLimiterResource, + EvListYndxRateLimiterResources, + EvDescribeYndxRateLimiterResource, + EvAcquireYndxRateLimiterResource, EvGrpcRuntimeRequest // !!! DO NOT ADD NEW REQUEST !!! }; @@ -222,9 +222,9 @@ struct TRpcServices { struct TEvForgetOperation : public TEventLocal<TEvForgetOperation, TRpcServices::EvForgetOperation> {}; }; -// Should be specialized for real responses -template <class T> -void FillYdbStatus(T& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status); +// Should be specialized for real responses +template <class T> +void FillYdbStatus(T& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status); class TProtoResponseHelper { public: diff --git a/ydb/core/grpc_services/base/ya.make b/ydb/core/grpc_services/base/ya.make index 49d94693f0..4454c652d4 100644 --- a/ydb/core/grpc_services/base/ya.make +++ b/ydb/core/grpc_services/base/ya.make @@ -1,24 +1,24 @@ -LIBRARY() - -OWNER( - dcherednik - g:kikimr -) - -SRCS( - base.h -) - -PEERDIR( - library/cpp/grpc/server - library/cpp/string_utils/quote +LIBRARY() + +OWNER( + dcherednik + g:kikimr +) + +SRCS( + base.h +) + +PEERDIR( + library/cpp/grpc/server + library/cpp/string_utils/quote ydb/core/base ydb/core/grpc_streaming ydb/public/api/protos ydb/public/sdk/cpp/client/resources ydb/library/yql/public/issue -) - -YQL_LAST_ABI_VERSION() - -END() +) + +YQL_LAST_ABI_VERSION() + +END() diff --git a/ydb/core/grpc_services/local_rate_limiter.cpp b/ydb/core/grpc_services/local_rate_limiter.cpp index 3a2fcb78cb..f0cffca3a6 100644 --- a/ydb/core/grpc_services/local_rate_limiter.cpp +++ b/ydb/core/grpc_services/local_rate_limiter.cpp @@ -2,7 +2,7 @@ #include "rpc_common.h" #include <ydb/core/grpc_services/local_rpc/local_rpc.h> - + namespace NKikimr { namespace NRpcService { diff --git a/ydb/core/grpc_services/local_rpc/local_rpc.h b/ydb/core/grpc_services/local_rpc/local_rpc.h index 23c3b6c803..c196172564 100644 --- a/ydb/core/grpc_services/local_rpc/local_rpc.h +++ b/ydb/core/grpc_services/local_rpc/local_rpc.h @@ -1,7 +1,7 @@ #pragma once #include <ydb/core/grpc_services/base/base.h> - + #include <ydb/core/base/appdata.h> #include <library/cpp/threading/future/future.h> diff --git a/ydb/core/grpc_services/local_rpc/ya.make b/ydb/core/grpc_services/local_rpc/ya.make index 59a7db6083..5562857002 100644 --- a/ydb/core/grpc_services/local_rpc/ya.make +++ b/ydb/core/grpc_services/local_rpc/ya.make @@ -1,19 +1,19 @@ -LIBRARY() - -OWNER( - dcherednik - g:kikimr -) - -SRCS( - local_rpc.h -) - -PEERDIR( +LIBRARY() + +OWNER( + dcherednik + g:kikimr +) + +SRCS( + local_rpc.h +) + +PEERDIR( ydb/core/base ydb/core/grpc_services/base -) - -YQL_LAST_ABI_VERSION() - -END() +) + +YQL_LAST_ABI_VERSION() + +END() diff --git a/ydb/core/grpc_services/rpc_calls.cpp b/ydb/core/grpc_services/rpc_calls.cpp index b94d168147..ea93f27f2c 100644 --- a/ydb/core/grpc_services/rpc_calls.cpp +++ b/ydb/core/grpc_services/rpc_calls.cpp @@ -6,26 +6,26 @@ namespace NKikimr { namespace NGRpcService { -template <> +template <> void FillYdbStatus(Ydb::PersQueue::V1::StreamingWriteServerMessage& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status) { resp.set_status(status); NYql::IssuesToMessage(issues, resp.mutable_issues()); } -template <> +template <> void FillYdbStatus(Ydb::PersQueue::V1::MigrationStreamingReadServerMessage& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status) { resp.set_status(status); NYql::IssuesToMessage(issues, resp.mutable_issues()); } -template <> +template <> void FillYdbStatus(Draft::Dummy::PingResponse& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status) { Y_UNUSED(resp); Y_UNUSED(issues); Y_UNUSED(status); } -template <> +template <> void FillYdbStatus(Ydb::Coordination::SessionResponse& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status) { auto* failure = resp.mutable_failure(); failure->set_status(status); diff --git a/ydb/core/grpc_services/rpc_calls.h b/ydb/core/grpc_services/rpc_calls.h index 43136c2f4a..169e2fcdc2 100644 --- a/ydb/core/grpc_services/rpc_calls.h +++ b/ydb/core/grpc_services/rpc_calls.h @@ -33,16 +33,16 @@ namespace NKikimr { namespace NGRpcService { -template <> -void FillYdbStatus(Ydb::PersQueue::V1::StreamingWriteServerMessage& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status); +template <> +void FillYdbStatus(Ydb::PersQueue::V1::StreamingWriteServerMessage& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status); -template <> -void FillYdbStatus(Ydb::PersQueue::V1::MigrationStreamingReadServerMessage& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status); +template <> +void FillYdbStatus(Ydb::PersQueue::V1::MigrationStreamingReadServerMessage& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status); -template <> -void FillYdbStatus(Draft::Dummy::PingResponse& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status); +template <> +void FillYdbStatus(Draft::Dummy::PingResponse& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status); -template <> +template <> void FillYdbStatus(Ydb::Coordination::SessionResponse& resp, const NYql::TIssues& issues, Ydb::StatusIds::StatusCode status); using TEvAlterTableRequest = TGRpcRequestValidationWrapper<TRpcServices::EvAlterTable, Ydb::Table::AlterTableRequest, Ydb::Table::AlterTableResponse, true, TRateLimiterMode::Rps>; diff --git a/ydb/core/grpc_services/rpc_create_session.cpp b/ydb/core/grpc_services/rpc_create_session.cpp index 2f6e9fae26..7f745d62cd 100644 --- a/ydb/core/grpc_services/rpc_create_session.cpp +++ b/ydb/core/grpc_services/rpc_create_session.cpp @@ -5,7 +5,7 @@ #include "rpc_kqp_base.h" #include <ydb/core/grpc_services/local_rpc/local_rpc.h> - + #include <ydb/library/yql/public/issue/yql_issue_message.h> #include <ydb/library/yql/public/issue/yql_issue.h> diff --git a/ydb/core/grpc_services/rpc_rate_limiter_api.cpp b/ydb/core/grpc_services/rpc_rate_limiter_api.cpp index 5579be8bdb..22e4fff62a 100644 --- a/ydb/core/grpc_services/rpc_rate_limiter_api.cpp +++ b/ydb/core/grpc_services/rpc_rate_limiter_api.cpp @@ -205,8 +205,8 @@ static void CopyProps(const Ydb::RateLimiter::Resource& src, NKikimrKesus::TStre auto& props = *dst.MutableHierarhicalDRRResourceConfig(); props.SetMaxUnitsPerSecond(srcProps.max_units_per_second()); props.SetMaxBurstSizeCoefficient(srcProps.max_burst_size_coefficient()); - props.SetPrefetchCoefficient(srcProps.prefetch_coefficient()); - props.SetPrefetchWatermark(srcProps.prefetch_watermark()); + props.SetPrefetchCoefficient(srcProps.prefetch_coefficient()); + props.SetPrefetchWatermark(srcProps.prefetch_watermark()); } static void CopyProps(const NKikimrKesus::TStreamingQuoterResource& src, Ydb::RateLimiter::Resource& dst) { @@ -215,8 +215,8 @@ static void CopyProps(const NKikimrKesus::TStreamingQuoterResource& src, Ydb::Ra auto& props = *dst.mutable_hierarchical_drr(); props.set_max_units_per_second(srcProps.GetMaxUnitsPerSecond()); props.set_max_burst_size_coefficient(srcProps.GetMaxBurstSizeCoefficient()); - props.set_prefetch_coefficient(srcProps.GetPrefetchCoefficient()); - props.set_prefetch_watermark(srcProps.GetPrefetchWatermark()); + props.set_prefetch_coefficient(srcProps.GetPrefetchCoefficient()); + props.set_prefetch_watermark(srcProps.GetPrefetchWatermark()); } class TCreateRateLimiterResourceRPC : public TRateLimiterControlRequest<TEvCreateRateLimiterResource> { diff --git a/ydb/core/kesus/tablet/events.h b/ydb/core/kesus/tablet/events.h index 872f0149c9..bbfe875232 100644 --- a/ydb/core/kesus/tablet/events.h +++ b/ydb/core/kesus/tablet/events.h @@ -87,8 +87,8 @@ struct TEvKesus { EvAggregatedResourceConsumptionStatistics, EvGetQuoterResourceCounters, EvGetQuoterResourceCountersResult, - EvAccountResources, - EvAccountResourcesAck, + EvAccountResources, + EvAccountResourcesAck, EvEnd }; @@ -530,16 +530,16 @@ struct TEvKesus { using TBaseEvent = TEventPBWithArena<TEvGetQuoterResourceCountersResult, NKikimrKesus::TEvGetQuoterResourceCountersResult, EvGetQuoterResourceCountersResult>; using TBaseEvent::TBaseEvent; }; - - struct TEvAccountResources : public TEventPBWithArena<TEvAccountResources, NKikimrKesus::TEvAccountResources, EvAccountResources> { - using TBaseEvent = TEventPBWithArena<TEvAccountResources, NKikimrKesus::TEvAccountResources, EvAccountResources>; - using TBaseEvent::TBaseEvent; - }; - - struct TEvAccountResourcesAck : public TEventPBWithArena<TEvAccountResourcesAck, NKikimrKesus::TEvAccountResourcesAck, EvAccountResourcesAck> { - using TBaseEvent = TEventPBWithArena<TEvAccountResourcesAck, NKikimrKesus::TEvAccountResourcesAck, EvAccountResourcesAck>; - using TBaseEvent::TBaseEvent; - }; + + struct TEvAccountResources : public TEventPBWithArena<TEvAccountResources, NKikimrKesus::TEvAccountResources, EvAccountResources> { + using TBaseEvent = TEventPBWithArena<TEvAccountResources, NKikimrKesus::TEvAccountResources, EvAccountResources>; + using TBaseEvent::TBaseEvent; + }; + + struct TEvAccountResourcesAck : public TEventPBWithArena<TEvAccountResourcesAck, NKikimrKesus::TEvAccountResourcesAck, EvAccountResourcesAck> { + using TBaseEvent = TEventPBWithArena<TEvAccountResourcesAck, NKikimrKesus::TEvAccountResourcesAck, EvAccountResourcesAck>; + using TBaseEvent::TBaseEvent; + }; }; } diff --git a/ydb/core/kesus/tablet/probes.h b/ydb/core/kesus/tablet/probes.h index 077375fb36..226d1a9fd0 100644 --- a/ydb/core/kesus/tablet/probes.h +++ b/ydb/core/kesus/tablet/probes.h @@ -37,37 +37,37 @@ struct TActorIdParam { TYPES(TString, TString, TInstant, double, ui32), \ NAMES("quoter", "resource", "timestampSec", "giveAmount", "childWeight")) \ \ - PROBE(ResourceBillSend, GROUPS("QuoterResource", "RateAccounting"), \ - TYPES(TString, TString, TString, ui64, TInstant, TInstant, TString, TString, TString, TString, TString, TString), \ - NAMES("quoter", "resource", "category", "quantity", "billStartSec", "billEndSec", "version", "schema", "cloudId", "folderId", "resourceId", "sourceId")) \ - PROBE(ResourceBillAdd, GROUPS("QuoterResource", "RateAccounting"), \ - TYPES(TString, TString, TString, TInstant, TInstant, TDuration, double, double), \ - NAMES("quoter", "resource", "category", "accumulatedSec", "accountSec", "accDeltaMs", "quantity", "value")) \ - PROBE(ResourceAccountConfigure, GROUPS("QuoterResource", "RateAccounting"), \ - TYPES(TString, TString, double, double, double, TInstant, double, double, double, TInstant), \ - NAMES("quoter", "resource", "provisionedRate", "provisionedBurst", "provisionedAvail", "provisionedLastSec", "onDemandRate", "onDemandBurst", "onDemandAvail", "onDemandLastSec")) \ - PROBE(ResourceAccount, GROUPS("QuoterResource", "RateAccounting"), \ - TYPES(TString, TString, TInstant, double, double, double, double, double, double, double, double, double, double), \ - NAMES("quoter", "resource", "accountSec", "provisionedAndOnDemand", "provisioned", "onDemand", "overshoot", "provisionedRate", "provisionedBurst", "provisionedAvail", "onDemandRate", "onDemandBurst", "onDemandAvail")) \ - PROBE(ResourceReportDedup, GROUPS("QuoterResource", "RateAccounting", "RateAccountingReport"), \ - TYPES(TString, TString, ui64, ui64, TInstant), \ - NAMES("quoter", "resource", "skip", "size", "reportSec")) \ - PROBE(ResourceReportDedupFull, GROUPS("QuoterResource", "RateAccounting", "RateAccountingReport"), \ - TYPES(TString, TString, ui64, ui64, TInstant), \ - NAMES("quoter", "resource", "skip", "size", "reportSec")) \ - PROBE(ResourceReportAdd, GROUPS("QuoterResource", "RateAccounting", "RateAccountingReport"), \ - TYPES(TString, TString, ui64, ui64, TInstant, TInstant), \ - NAMES("quoter", "resource", "added", "size", "reportSec", "accountedSec")) \ - PROBE(ResourceAccountingTooEarly, GROUPS("QuoterResource", "RateAccounting"), \ - TYPES(TString, TString, TInstant, TInstant, TDuration), \ - NAMES("quoter", "resource", "accountTillSec", "accountedSec", "accountPeriodMs")) \ - PROBE(ResourceAccountingNoData, GROUPS("QuoterResource", "RateAccounting"), \ - TYPES(TString, TString, TInstant, TInstant, TDuration), \ - NAMES("quoter", "resource", "historyEndSec", "accountedSec", "maxBillingPeriodMs")) \ - PROBE(ResourceAccountingSend, GROUPS("QuoterResource", "RateAccounting"), \ - TYPES(TString, TString, TInstant, TInstant), \ - NAMES("quoter", "resource", "accountTillSec", "accountedSec")) \ - \ + PROBE(ResourceBillSend, GROUPS("QuoterResource", "RateAccounting"), \ + TYPES(TString, TString, TString, ui64, TInstant, TInstant, TString, TString, TString, TString, TString, TString), \ + NAMES("quoter", "resource", "category", "quantity", "billStartSec", "billEndSec", "version", "schema", "cloudId", "folderId", "resourceId", "sourceId")) \ + PROBE(ResourceBillAdd, GROUPS("QuoterResource", "RateAccounting"), \ + TYPES(TString, TString, TString, TInstant, TInstant, TDuration, double, double), \ + NAMES("quoter", "resource", "category", "accumulatedSec", "accountSec", "accDeltaMs", "quantity", "value")) \ + PROBE(ResourceAccountConfigure, GROUPS("QuoterResource", "RateAccounting"), \ + TYPES(TString, TString, double, double, double, TInstant, double, double, double, TInstant), \ + NAMES("quoter", "resource", "provisionedRate", "provisionedBurst", "provisionedAvail", "provisionedLastSec", "onDemandRate", "onDemandBurst", "onDemandAvail", "onDemandLastSec")) \ + PROBE(ResourceAccount, GROUPS("QuoterResource", "RateAccounting"), \ + TYPES(TString, TString, TInstant, double, double, double, double, double, double, double, double, double, double), \ + NAMES("quoter", "resource", "accountSec", "provisionedAndOnDemand", "provisioned", "onDemand", "overshoot", "provisionedRate", "provisionedBurst", "provisionedAvail", "onDemandRate", "onDemandBurst", "onDemandAvail")) \ + PROBE(ResourceReportDedup, GROUPS("QuoterResource", "RateAccounting", "RateAccountingReport"), \ + TYPES(TString, TString, ui64, ui64, TInstant), \ + NAMES("quoter", "resource", "skip", "size", "reportSec")) \ + PROBE(ResourceReportDedupFull, GROUPS("QuoterResource", "RateAccounting", "RateAccountingReport"), \ + TYPES(TString, TString, ui64, ui64, TInstant), \ + NAMES("quoter", "resource", "skip", "size", "reportSec")) \ + PROBE(ResourceReportAdd, GROUPS("QuoterResource", "RateAccounting", "RateAccountingReport"), \ + TYPES(TString, TString, ui64, ui64, TInstant, TInstant), \ + NAMES("quoter", "resource", "added", "size", "reportSec", "accountedSec")) \ + PROBE(ResourceAccountingTooEarly, GROUPS("QuoterResource", "RateAccounting"), \ + TYPES(TString, TString, TInstant, TInstant, TDuration), \ + NAMES("quoter", "resource", "accountTillSec", "accountedSec", "accountPeriodMs")) \ + PROBE(ResourceAccountingNoData, GROUPS("QuoterResource", "RateAccounting"), \ + TYPES(TString, TString, TInstant, TInstant, TDuration), \ + NAMES("quoter", "resource", "historyEndSec", "accountedSec", "maxBillingPeriodMs")) \ + PROBE(ResourceAccountingSend, GROUPS("QuoterResource", "RateAccounting"), \ + TYPES(TString, TString, TInstant, TInstant), \ + NAMES("quoter", "resource", "accountTillSec", "accountedSec")) \ + \ PROBE(SessionProcess, GROUPS("QuoterSession"), \ TYPES(TString, TString, TActorIdParam, TInstant, bool), \ NAMES("quoter", "resource", "session", "timestampSec", "active")) \ diff --git a/ydb/core/kesus/tablet/quoter_resource_tree.cpp b/ydb/core/kesus/tablet/quoter_resource_tree.cpp index 3f9d6e5653..a23302841e 100644 --- a/ydb/core/kesus/tablet/quoter_resource_tree.cpp +++ b/ydb/core/kesus/tablet/quoter_resource_tree.cpp @@ -1,5 +1,5 @@ #include "quoter_resource_tree.h" - + #include "probes.h" #include <ydb/core/base/path.h> @@ -160,7 +160,7 @@ public: bool ValidateProps(const NKikimrKesus::TStreamingQuoterResource& props, TString& errorMessage) override; void CalcParameters() override; - void CalcParametersForAccounting(); + void CalcParametersForAccounting(); THolder<TQuoterSession> DoCreateSession(const NActors::TActorId& clientId) override; @@ -212,13 +212,13 @@ public: void RemoveChild(TQuoterResourceTree* child) override; - TInstant Report(const NActors::TActorId& clientId, ui64 resourceId, TInstant start, TDuration interval, const double* values, size_t size, TTickProcessorQueue& queue, TInstant now); - void RunAccounting(); - + TInstant Report(const NActors::TActorId& clientId, ui64 resourceId, TInstant start, TDuration interval, const double* values, size_t size, TTickProcessorQueue& queue, TInstant now); + void RunAccounting(); + private: double MaxUnitsPerSecond = 0.0; - double PrefetchCoefficient = 0.0; - double PrefetchWatermark = 0.0; + double PrefetchCoefficient = 0.0; + double PrefetchWatermark = 0.0; ui32 Weight = 1; TDuration TickSize; ui64 ActiveChildrenWeight = 0; @@ -233,14 +233,14 @@ private: bool Active = false; THierarchicalDRRResourceConsumer* CurrentActiveChild = nullptr; size_t ActiveChildrenCount = 0; - - THolder<TRateAccounting> RateAccounting; - bool ActiveAccounting = false; + + THolder<TRateAccounting> RateAccounting; + bool ActiveAccounting = false; }; -THolder<TQuoterResourceTree> CreateResource(ui64 resourceId, ui64 parentId, NActors::TActorId kesus, const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props) { +THolder<TQuoterResourceTree> CreateResource(ui64 resourceId, ui64 parentId, NActors::TActorId kesus, const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props) { Y_VERIFY(resourceId != parentId); - return MakeHolder<THierarhicalDRRQuoterResourceTree>(resourceId, parentId, kesus, billSink, props); + return MakeHolder<THierarhicalDRRQuoterResourceTree>(resourceId, parentId, kesus, billSink, props); } // Session in case of hierarchical DRR algorithm. @@ -260,7 +260,7 @@ public: } void UpdateConsumptionState(bool consume, double amount, TTickProcessorQueue& queue, TInstant now) override; - TInstant Account(TInstant start, TDuration interval, const double* values, size_t size, TTickProcessorQueue& queue, TInstant now) override; + TInstant Account(TInstant start, TDuration interval, const double* values, size_t size, TTickProcessorQueue& queue, TInstant now) override; void DoProcess(TTickProcessorQueue& queue, TInstant now) override; void ScheduleNextTick(TTickProcessorQueue& queue, TInstant now); @@ -383,10 +383,10 @@ void THierarhicalDRRQuoterSession::UpdateConsumptionState(bool consume, double a } } -TInstant THierarhicalDRRQuoterSession::Account(TInstant start, TDuration interval, const double* values, size_t size, TTickProcessorQueue& queue, TInstant now) { - return GetResource()->Report(ClientId, GetResource()->GetResourceId(), start, interval, values, size, queue, now); -} - +TInstant THierarhicalDRRQuoterSession::Account(TInstant start, TDuration interval, const double* values, size_t size, TTickProcessorQueue& queue, TInstant now) { + return GetResource()->Report(ClientId, GetResource()->GetResourceId(), start, interval, values, size, queue, now); +} + void THierarhicalDRRQuoterSession::SendAvailableResource() { if (FreeResource >= GetResource()->GetResourceFillingEpsilon()) { if (AmountRequested >= GetResource()->GetResourceFillingEpsilon()) { @@ -462,11 +462,11 @@ void TQuoterSession::AddAllocatedCounter(double spent) { } while (resource != nullptr); } -TQuoterResourceTree::TQuoterResourceTree(ui64 resourceId, ui64 parentId, NActors::TActorId kesus, const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props) +TQuoterResourceTree::TQuoterResourceTree(ui64 resourceId, ui64 parentId, NActors::TActorId kesus, const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props) : ResourceId(resourceId) , ParentId(parentId) - , Kesus(kesus) - , BillSink(billSink) + , Kesus(kesus) + , BillSink(billSink) , Props(props) , EffectiveProps(props) { @@ -501,7 +501,7 @@ bool TQuoterResourceTree::Update(const NKikimrKesus::TStreamingQuoterResource& p } bool TQuoterResourceTree::ValidateProps(const NKikimrKesus::TStreamingQuoterResource& props, TString& errorMessage) { - Y_UNUSED(props, errorMessage); + Y_UNUSED(props, errorMessage); return true; } @@ -511,7 +511,7 @@ void TQuoterResourceTree::CalcParameters() { ResourceLevel = Parent->ResourceLevel + 1; } - // Recurse into children + // Recurse into children for (TQuoterResourceTree* child : Children) { child->CalcParameters(); } @@ -579,45 +579,45 @@ bool THierarhicalDRRQuoterResourceTree::ValidateProps(const NKikimrKesus::TStrea const auto& hdrrConfig = props.GetHierarhicalDRRResourceConfig(); const double maxUnitsPerSecond = hdrrConfig.GetMaxUnitsPerSecond() ? hdrrConfig.GetMaxUnitsPerSecond() : hdrrConfig.GetSpeedSettings().GetMaxUnitsPerSecond(); - if (!std::isfinite(maxUnitsPerSecond)) { - errorMessage = "MaxUnitsPerSecond must be finite."; - return false; - } + if (!std::isfinite(maxUnitsPerSecond)) { + errorMessage = "MaxUnitsPerSecond must be finite."; + return false; + } if (maxUnitsPerSecond < 0.0) { errorMessage = "MaxUnitsPerSecond can't be less than 0."; return false; } - // Validate prefetch settings - const double prefetchCoefficient = hdrrConfig.GetPrefetchCoefficient(); - if (!std::isfinite(prefetchCoefficient)) { - errorMessage = "PrefetchCoefficient must be finite."; - return false; - } - const double prefetchWatermark = hdrrConfig.GetPrefetchWatermark(); - if (!std::isfinite(prefetchWatermark)) { - errorMessage = "PrefetchWatermark must be finite."; - return false; - } - if (prefetchWatermark < 0.0) { - errorMessage = "PrefetchWatermark can't be less than 0."; - return false; - } - if (prefetchWatermark > 1.0) { - errorMessage = "PrefetchWatermark can't be greater than 1."; - return false; - } - + // Validate prefetch settings + const double prefetchCoefficient = hdrrConfig.GetPrefetchCoefficient(); + if (!std::isfinite(prefetchCoefficient)) { + errorMessage = "PrefetchCoefficient must be finite."; + return false; + } + const double prefetchWatermark = hdrrConfig.GetPrefetchWatermark(); + if (!std::isfinite(prefetchWatermark)) { + errorMessage = "PrefetchWatermark must be finite."; + return false; + } + if (prefetchWatermark < 0.0) { + errorMessage = "PrefetchWatermark can't be less than 0."; + return false; + } + if (prefetchWatermark > 1.0) { + errorMessage = "PrefetchWatermark can't be greater than 1."; + return false; + } + if (!ParentId && !maxUnitsPerSecond) { errorMessage = "No MaxUnitsPerSecond parameter in root resource."; return false; } - - if (!TRateAccounting::ValidateProps(props, errorMessage)) { - return false; - } - - return TQuoterResourceTree::ValidateProps(props, errorMessage); + + if (!TRateAccounting::ValidateProps(props, errorMessage)) { + return false; + } + + return TQuoterResourceTree::ValidateProps(props, errorMessage); } void THierarhicalDRRQuoterResourceTree::CalcParameters() { @@ -626,7 +626,7 @@ void THierarhicalDRRQuoterResourceTree::CalcParameters() { Props.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(Props.GetHierarhicalDRRResourceConfig().GetSpeedSettings().GetMaxUnitsPerSecond()); } - // speed settings + // speed settings THierarhicalDRRQuoterResourceTree* const parent = GetParent(); const auto& config = GetProps().GetHierarhicalDRRResourceConfig(); if (config.GetMaxUnitsPerSecond()) { @@ -639,18 +639,18 @@ void THierarhicalDRRQuoterResourceTree::CalcParameters() { MaxUnitsPerSecond = parent->MaxUnitsPerSecond; } - // prefetch settings - if (config.GetPrefetchCoefficient()) { - PrefetchCoefficient = config.GetPrefetchCoefficient(); - } else if (parent) { - PrefetchCoefficient = parent->PrefetchCoefficient; - } - if (config.GetPrefetchWatermark()) { - PrefetchWatermark = config.GetPrefetchWatermark(); - } else if (parent) { - PrefetchWatermark = parent->PrefetchWatermark; - } - + // prefetch settings + if (config.GetPrefetchCoefficient()) { + PrefetchCoefficient = config.GetPrefetchCoefficient(); + } else if (parent) { + PrefetchCoefficient = parent->PrefetchCoefficient; + } + if (config.GetPrefetchWatermark()) { + PrefetchWatermark = config.GetPrefetchWatermark(); + } else if (parent) { + PrefetchWatermark = parent->PrefetchWatermark; + } + ResourceTickQuantum = MaxUnitsPerSecond >= 0.0 ? MaxUnitsPerSecond / TICKS_PER_SECOND : 0.0; ResourceFillingEpsilon = ResourceTickQuantum * EPSILON_COEFFICIENT; TickSize = TDuration::Seconds(1) / TICKS_PER_SECOND; @@ -671,72 +671,72 @@ void THierarhicalDRRQuoterResourceTree::CalcParameters() { effectiveConfig->SetMaxUnitsPerSecond(MaxUnitsPerSecond); effectiveConfig->SetWeight(Weight); effectiveConfig->SetMaxBurstSizeCoefficient(1); - effectiveConfig->SetPrefetchCoefficient(PrefetchCoefficient); - effectiveConfig->SetPrefetchWatermark(PrefetchWatermark); + effectiveConfig->SetPrefetchCoefficient(PrefetchCoefficient); + effectiveConfig->SetPrefetchWatermark(PrefetchWatermark); SetLimitCounter(); - CalcParametersForAccounting(); - + CalcParametersForAccounting(); + TQuoterResourceTree::CalcParameters(); // recalc for children } -void THierarhicalDRRQuoterResourceTree::CalcParametersForAccounting() { - const auto* accCfgParent = Parent ? &Parent->GetEffectiveProps().GetAccountingConfig() : nullptr; - auto* accCfg = EffectiveProps.MutableAccountingConfig(); - - // Calc rate accouting effective props - if (!accCfg->GetReportPeriodMs()) { - accCfg->SetReportPeriodMs(accCfgParent ? accCfgParent->GetReportPeriodMs() : 5000); - } - - if (!accCfg->GetAccountPeriodMs()) { - accCfg->SetAccountPeriodMs(accCfgParent ? accCfgParent->GetAccountPeriodMs() : 1000); - } - - if (!accCfg->GetCollectPeriodSec()) { - accCfg->SetCollectPeriodSec(accCfgParent ? accCfgParent->GetCollectPeriodSec() : 30); - } - - if (!accCfg->GetProvisionedCoefficient()) { - accCfg->SetProvisionedCoefficient(accCfgParent ? accCfgParent->GetProvisionedCoefficient() : 60); - } - - if (!accCfg->GetOvershootCoefficient()) { - accCfg->SetOvershootCoefficient(accCfgParent ? accCfgParent->GetOvershootCoefficient() : 1.1); - } - - auto calcMetricsParams = [] (auto* cfg, const auto* parent) { - // NOTE: `Enabled` is not inherited, skipped here - if (!cfg->GetBillingPeriodSec()) { - cfg->SetBillingPeriodSec(parent ? parent->GetBillingPeriodSec() : 60); - } - if (!cfg->GetVersion() && parent) { cfg->SetVersion(parent->GetVersion()); } - if (!cfg->GetSchema() && parent) { cfg->SetSchema(parent->GetSchema()); } - if (!cfg->GetCloudId() && parent) { cfg->SetCloudId(parent->GetCloudId()); } - if (!cfg->GetFolderId() && parent) { cfg->SetFolderId(parent->GetFolderId()); } - if (!cfg->GetResourceId() && parent) { cfg->SetResourceId(parent->GetResourceId()); } - if (!cfg->GetSourceId() && parent) { cfg->SetSourceId(parent->GetSourceId()); } - if (cfg->GetTags().empty() && parent) { *cfg->MutableTags() = parent->GetTags(); } - }; - calcMetricsParams(accCfg->MutableProvisioned(), accCfgParent ? &accCfgParent->GetProvisioned() : nullptr); - calcMetricsParams(accCfg->MutableOnDemand(), accCfgParent ? &accCfgParent->GetOnDemand() : nullptr); - calcMetricsParams(accCfg->MutableOvershoot(), accCfgParent ? &accCfgParent->GetOvershoot() : nullptr); - - // Create/update/delete rate accounting - if (accCfg->GetEnabled()) { - if (!RateAccounting) { // create - RateAccounting.Reset(new TRateAccounting(Kesus, BillSink, EffectiveProps, QuoterPath)); - RateAccounting->SetResourceCounters(Counters.ResourceCounters); - } else { // update - RateAccounting->Configure(EffectiveProps); - } - } else if (RateAccounting) { // delete - RateAccounting->Stop(); - RateAccounting.Destroy(); - } -} - +void THierarhicalDRRQuoterResourceTree::CalcParametersForAccounting() { + const auto* accCfgParent = Parent ? &Parent->GetEffectiveProps().GetAccountingConfig() : nullptr; + auto* accCfg = EffectiveProps.MutableAccountingConfig(); + + // Calc rate accouting effective props + if (!accCfg->GetReportPeriodMs()) { + accCfg->SetReportPeriodMs(accCfgParent ? accCfgParent->GetReportPeriodMs() : 5000); + } + + if (!accCfg->GetAccountPeriodMs()) { + accCfg->SetAccountPeriodMs(accCfgParent ? accCfgParent->GetAccountPeriodMs() : 1000); + } + + if (!accCfg->GetCollectPeriodSec()) { + accCfg->SetCollectPeriodSec(accCfgParent ? accCfgParent->GetCollectPeriodSec() : 30); + } + + if (!accCfg->GetProvisionedCoefficient()) { + accCfg->SetProvisionedCoefficient(accCfgParent ? accCfgParent->GetProvisionedCoefficient() : 60); + } + + if (!accCfg->GetOvershootCoefficient()) { + accCfg->SetOvershootCoefficient(accCfgParent ? accCfgParent->GetOvershootCoefficient() : 1.1); + } + + auto calcMetricsParams = [] (auto* cfg, const auto* parent) { + // NOTE: `Enabled` is not inherited, skipped here + if (!cfg->GetBillingPeriodSec()) { + cfg->SetBillingPeriodSec(parent ? parent->GetBillingPeriodSec() : 60); + } + if (!cfg->GetVersion() && parent) { cfg->SetVersion(parent->GetVersion()); } + if (!cfg->GetSchema() && parent) { cfg->SetSchema(parent->GetSchema()); } + if (!cfg->GetCloudId() && parent) { cfg->SetCloudId(parent->GetCloudId()); } + if (!cfg->GetFolderId() && parent) { cfg->SetFolderId(parent->GetFolderId()); } + if (!cfg->GetResourceId() && parent) { cfg->SetResourceId(parent->GetResourceId()); } + if (!cfg->GetSourceId() && parent) { cfg->SetSourceId(parent->GetSourceId()); } + if (cfg->GetTags().empty() && parent) { *cfg->MutableTags() = parent->GetTags(); } + }; + calcMetricsParams(accCfg->MutableProvisioned(), accCfgParent ? &accCfgParent->GetProvisioned() : nullptr); + calcMetricsParams(accCfg->MutableOnDemand(), accCfgParent ? &accCfgParent->GetOnDemand() : nullptr); + calcMetricsParams(accCfg->MutableOvershoot(), accCfgParent ? &accCfgParent->GetOvershoot() : nullptr); + + // Create/update/delete rate accounting + if (accCfg->GetEnabled()) { + if (!RateAccounting) { // create + RateAccounting.Reset(new TRateAccounting(Kesus, BillSink, EffectiveProps, QuoterPath)); + RateAccounting->SetResourceCounters(Counters.ResourceCounters); + } else { // update + RateAccounting->Configure(EffectiveProps); + } + } else if (RateAccounting) { // delete + RateAccounting->Stop(); + RateAccounting.Destroy(); + } +} + void THierarhicalDRRQuoterResourceTree::RemoveChild(TQuoterResourceTree* childBase) { THierarhicalDRRQuoterResourceTree* child = static_cast<THierarhicalDRRQuoterResourceTree*>(childBase); if (child->Active) { @@ -829,48 +829,48 @@ void THierarhicalDRRQuoterResourceTree::DoProcess(TTickProcessorQueue& queue, TI } DeactivateIfFull(now); - } - - if (ActiveAccounting) { - RunAccounting(); - } - - if (Active || ActiveAccounting) { - ScheduleNextTick(queue, now); - } -} - -TInstant THierarhicalDRRQuoterResourceTree::Report( - const NActors::TActorId& clientId, - ui64 resourceId, - TInstant start, - TDuration interval, - const double* values, - size_t size, - TTickProcessorQueue& queue, - TInstant now) -{ - if (RateAccounting) { - TInstant result = RateAccounting->Report(clientId, resourceId, start, interval, values, size); - ActiveAccounting = true; - ScheduleNextTick(queue, now); - return result; - } else if (GetParent()) { - return GetParent()->Report(clientId, resourceId, start, interval, values, size, queue, now); - } else { - // We have no rate accounting enabled -- skip data - return TInstant::Zero(); - } -} - -void THierarhicalDRRQuoterResourceTree::RunAccounting() { - if (RateAccounting) { - ActiveAccounting = RateAccounting->RunAccounting(); - } else { - ActiveAccounting = false; - } -} - + } + + if (ActiveAccounting) { + RunAccounting(); + } + + if (Active || ActiveAccounting) { + ScheduleNextTick(queue, now); + } +} + +TInstant THierarhicalDRRQuoterResourceTree::Report( + const NActors::TActorId& clientId, + ui64 resourceId, + TInstant start, + TDuration interval, + const double* values, + size_t size, + TTickProcessorQueue& queue, + TInstant now) +{ + if (RateAccounting) { + TInstant result = RateAccounting->Report(clientId, resourceId, start, interval, values, size); + ActiveAccounting = true; + ScheduleNextTick(queue, now); + return result; + } else if (GetParent()) { + return GetParent()->Report(clientId, resourceId, start, interval, values, size, queue, now); + } else { + // We have no rate accounting enabled -- skip data + return TInstant::Zero(); + } +} + +void THierarhicalDRRQuoterResourceTree::RunAccounting() { + if (RateAccounting) { + ActiveAccounting = RateAccounting->RunAccounting(); + } else { + ActiveAccounting = false; + } +} + void THierarhicalDRRQuoterResourceTree::AddActiveChild(THierarchicalDRRResourceConsumer* child, TTickProcessorQueue& queue, TInstant now) { UpdateActiveTime(now); if (!HasActiveChildren()) { @@ -931,9 +931,9 @@ THolder<TQuoterSession> THierarhicalDRRQuoterResourceTree::DoCreateSession(const void THierarhicalDRRQuoterResourceTree::SetResourceCounters(TIntrusivePtr<NMonitoring::TDynamicCounters> resourceCounters) { TQuoterResourceTree::SetResourceCounters(std::move(resourceCounters)); - if (RateAccounting) { - RateAccounting->SetResourceCounters(Counters.ResourceCounters); - } + if (RateAccounting) { + RateAccounting->SetResourceCounters(Counters.ResourceCounters); + } SetLimitCounter(); } @@ -951,7 +951,7 @@ bool TQuoterResources::Exists(ui64 resourceId) const { } TQuoterResourceTree* TQuoterResources::LoadResource(ui64 resourceId, ui64 parentId, const NKikimrKesus::TStreamingQuoterResource& props) { - auto resource = CreateResource(resourceId, parentId, Kesus, BillSink, props); + auto resource = CreateResource(resourceId, parentId, Kesus, BillSink, props); Y_VERIFY(!Exists(resource->GetResourceId()), "Resource \"%s\" has duplicated id: %" PRIu64, resource->GetPath().c_str(), resourceId); Y_VERIFY(!props.GetResourcePath().empty(), @@ -1000,7 +1000,7 @@ TQuoterResourceTree* TQuoterResources::AddResource(ui64 resourceId, const NKikim resProps.SetResourceId(resourceId); resProps.SetResourcePath(canonPath); const ui64 parentId = parent ? parent->GetResourceId() : 0; - THolder<TQuoterResourceTree> resource = CreateResource(resourceId, parentId, Kesus, BillSink, resProps); + THolder<TQuoterResourceTree> resource = CreateResource(resourceId, parentId, Kesus, BillSink, resProps); if (!resource->ValidateProps(resProps, errorMessage)) { return nullptr; } @@ -1055,11 +1055,11 @@ bool TQuoterResources::DeleteResource(TQuoterResourceTree* resource, TString& er return true; } -void TQuoterResources::SetupBilling(NActors::TActorId kesus, const IBillSink::TPtr& billSink) { - Kesus = kesus; - BillSink = billSink; -} - +void TQuoterResources::SetupBilling(NActors::TActorId kesus, const IBillSink::TPtr& billSink) { + Kesus = kesus; + BillSink = billSink; +} + void TQuoterResources::ConstructTrees() { // connect with parents std::vector<TQuoterResourceTree*> roots; diff --git a/ydb/core/kesus/tablet/quoter_resource_tree.h b/ydb/core/kesus/tablet/quoter_resource_tree.h index bc28e518c3..7104b09a12 100644 --- a/ydb/core/kesus/tablet/quoter_resource_tree.h +++ b/ydb/core/kesus/tablet/quoter_resource_tree.h @@ -1,10 +1,10 @@ #pragma once - -#include "rate_accounting.h" - + +#include "rate_accounting.h" + #include <ydb/core/protos/kesus.pb.h> -#include <library/cpp/actors/core/actor.h> +#include <library/cpp/actors/core/actor.h> #include <library/cpp/monlib/dynamic_counters/counters.h> #include <util/datetime/base.h> @@ -17,7 +17,7 @@ #include <queue> namespace NKikimr { - + namespace NKesus { using TQuoterSessionId = std::pair<NActors::TActorId, ui64>; // client id, resource id @@ -143,9 +143,9 @@ public: // Reaction for quoter runtime events: TEvSubscribeOnResources and TEvUpdateConsumptionState. virtual void UpdateConsumptionState(bool consume, double amount, TTickProcessorQueue& queue, TInstant now) = 0; - // Reaction for quoter runtime event TEvAccountResources. - virtual TInstant Account(TInstant start, TDuration interval, const double* values, size_t size, TTickProcessorQueue& queue, TInstant now) = 0; - + // Reaction for quoter runtime event TEvAccountResources. + virtual TInstant Account(TInstant start, TDuration interval, const double* values, size_t size, TTickProcessorQueue& queue, TInstant now) = 0; + // Close session when resource is deleted. virtual void CloseSession(Ydb::StatusIds::StatusCode status, const TString& reason); @@ -194,7 +194,7 @@ protected: // Common interface for hierarchical quoter resource. class TQuoterResourceTree : public TTickProcessor { public: - TQuoterResourceTree(ui64 resourceId, ui64 parentId, NActors::TActorId kesus, const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props); + TQuoterResourceTree(ui64 resourceId, ui64 parentId, NActors::TActorId kesus, const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props); TQuoterResourceTree(TQuoterResourceTree&&) = delete; TQuoterResourceTree(const TQuoterResourceTree&) = delete; @@ -313,8 +313,8 @@ public: protected: const ui64 ResourceId; const ui64 ParentId; - NActors::TActorId Kesus; - IBillSink::TPtr BillSink; + NActors::TActorId Kesus; + IBillSink::TPtr BillSink; TString QuoterPath; size_t ResourceLevel = 0; TQuoterResourceTree* Parent = nullptr; @@ -358,7 +358,7 @@ public: void EnableDetailedCountersMode(bool enable = true); void FillCounters(NKikimrKesus::TEvGetQuoterResourceCountersResult& counters); - void SetupBilling(NActors::TActorId kesus, const IBillSink::TPtr& billSink); + void SetupBilling(NActors::TActorId kesus, const IBillSink::TPtr& billSink); void ConstructTrees(); // Constructs all trees during initialization. size_t GetResourcesCount() const { @@ -384,7 +384,7 @@ public: void SetQuoterPath(const TString& quoterPath); - + private: TQuoterResourceTree* FindPathImpl(const TString& resourcePath); // doesn't canonize path @@ -393,8 +393,8 @@ private: private: TString QuoterPath; - NActors::TActorId Kesus; - IBillSink::TPtr BillSink; + NActors::TActorId Kesus; + IBillSink::TPtr BillSink; THashMap<ui64, THolder<TQuoterResourceTree>> ResourcesById; THashMap<TString, TQuoterResourceTree*> ResourcesByPath; diff --git a/ydb/core/kesus/tablet/quoter_runtime.cpp b/ydb/core/kesus/tablet/quoter_runtime.cpp index d00c10739d..3932e94f0b 100644 --- a/ydb/core/kesus/tablet/quoter_runtime.cpp +++ b/ydb/core/kesus/tablet/quoter_runtime.cpp @@ -165,37 +165,37 @@ void TKesusTablet::Handle(TEvKesus::TEvUpdateConsumptionState::TPtr& ev) { HandleQuoterTick(); } -void TKesusTablet::Handle(TEvKesus::TEvAccountResources::TPtr& ev) { - auto ack = MakeHolder<TEvKesus::TEvAccountResourcesAck>(); - const TActorId clientId = ActorIdFromProto(ev->Get()->Record.GetActorID()); - const TInstant now = TActivationContext::Now(); - TTickProcessorQueue queue; - for (const NKikimrKesus::TEvAccountResources::TResourceInfo& resource : ev->Get()->Record.GetResourcesInfo()) { - auto* result = ack->Record.AddResourcesInfo(); - result->SetResourceId(resource.GetResourceId()); - if (TQuoterSession* session = QuoterResources.FindSession(clientId, resource.GetResourceId())) { - TInstant accepted = session->Account( - TInstant::MicroSeconds(resource.GetStartUs()), - TDuration::MicroSeconds(resource.GetIntervalUs()), - resource.GetAmount().data(), - resource.GetAmount().size(), - queue, now); - result->SetAcceptedUs(accepted.MicroSeconds()); - } else { - TEvKesus::FillError(result->MutableStateNotification(), Ydb::StatusIds::BAD_SESSION, "No such session exists."); - } - } - QuoterTickProcessorQueue.Merge(std::move(queue)); - TRACE_LOG_EVENT(TabletID(), "TEvAccountResourcesAck", ack->Record, ev->Sender, ev->Cookie); - Send(ev->Sender, std::move(ack), 0, ev->Cookie); - - LOG_DEBUG_S(TActivationContext::AsActorContext(), NKikimrServices::KESUS_TABLET, - "[" << TabletID() << "] Account quoter resources (sender=" << ev->Sender - << ", cookie=" << ev->Cookie << ")"); - - HandleQuoterTick(); -} - +void TKesusTablet::Handle(TEvKesus::TEvAccountResources::TPtr& ev) { + auto ack = MakeHolder<TEvKesus::TEvAccountResourcesAck>(); + const TActorId clientId = ActorIdFromProto(ev->Get()->Record.GetActorID()); + const TInstant now = TActivationContext::Now(); + TTickProcessorQueue queue; + for (const NKikimrKesus::TEvAccountResources::TResourceInfo& resource : ev->Get()->Record.GetResourcesInfo()) { + auto* result = ack->Record.AddResourcesInfo(); + result->SetResourceId(resource.GetResourceId()); + if (TQuoterSession* session = QuoterResources.FindSession(clientId, resource.GetResourceId())) { + TInstant accepted = session->Account( + TInstant::MicroSeconds(resource.GetStartUs()), + TDuration::MicroSeconds(resource.GetIntervalUs()), + resource.GetAmount().data(), + resource.GetAmount().size(), + queue, now); + result->SetAcceptedUs(accepted.MicroSeconds()); + } else { + TEvKesus::FillError(result->MutableStateNotification(), Ydb::StatusIds::BAD_SESSION, "No such session exists."); + } + } + QuoterTickProcessorQueue.Merge(std::move(queue)); + TRACE_LOG_EVENT(TabletID(), "TEvAccountResourcesAck", ack->Record, ev->Sender, ev->Cookie); + Send(ev->Sender, std::move(ack), 0, ev->Cookie); + + LOG_DEBUG_S(TActivationContext::AsActorContext(), NKikimrServices::KESUS_TABLET, + "[" << TabletID() << "] Account quoter resources (sender=" << ev->Sender + << ", cookie=" << ev->Cookie << ")"); + + HandleQuoterTick(); +} + void TKesusTablet::Handle(TEvKesus::TEvResourcesAllocatedAck::TPtr& ev) { Y_UNUSED(ev); } @@ -213,7 +213,7 @@ void TKesusTablet::ScheduleQuoterTick() { } void TKesusTablet::HandleQuoterTick() { - const NHPTimer::STime hpprev = GetCycleCountFast(); + const NHPTimer::STime hpprev = GetCycleCountFast(); NextQuoterTickTime = TInstant::Max(); i64 processedTasks = 0; while (!QuoterTickProcessorQueue.Empty()) { @@ -240,7 +240,7 @@ void TKesusTablet::HandleQuoterTick() { } ScheduleQuoterTick(); QuoterResourceSessionsAccumulator.SendAll(TActivationContext::AsActorContext(), TabletID()); - const NHPTimer::STime hpnow = GetCycleCountFast(); + const NHPTimer::STime hpnow = GetCycleCountFast(); *QuoterResources.GetCounters().ElapsedMicrosecOnResourceAllocation += NHPTimer::GetSeconds(hpnow - hpprev) * 1000000; if (processedTasks) { *QuoterResources.GetCounters().TickProcessorTasksProcessed += processedTasks; diff --git a/ydb/core/kesus/tablet/rate_accounting.cpp b/ydb/core/kesus/tablet/rate_accounting.cpp index 1459eafbc0..a9530eab7c 100644 --- a/ydb/core/kesus/tablet/rate_accounting.cpp +++ b/ydb/core/kesus/tablet/rate_accounting.cpp @@ -1,498 +1,498 @@ -#include "rate_accounting.h" - -#include "probes.h" - +#include "rate_accounting.h" + +#include "probes.h" + #include <ydb/core/metering/metering.h> #include <ydb/core/util/token_bucket.h> #include <ydb/core/metering/time_grid.h> #include <ydb/core/metering/bill_record.h> - -#include <library/cpp/actors/core/hfunc.h> - -#include <util/string/builder.h> -#include <util/generic/deque.h> - -LWTRACE_USING(KESUS_QUOTER_PROVIDER); - -namespace NKikimr { -namespace NKesus { - -namespace { - -using namespace NActors; - -//////////////////////////////////////////////////////////////////////////////// -struct TEvPrivate { - enum EEv { - EvRunAccounting = EventSpaceBegin(TEvents::ES_PRIVATE), - EvConfigure, - EvCounters, - EvEnd - }; - - static_assert(EvEnd <= EventSpaceEnd(TKikimrEvents::ES_PRIVATE), - "expected EvEnd <= EventSpaceEnd(TKikimrEvents::ES_PRIVATE)"); - - struct TEvRunAccounting : public TEventLocal<TEvRunAccounting, EvRunAccounting> { - TInstant Time; - TConsumptionHistory History; - - TEvRunAccounting(TInstant time, TConsumptionHistory&& history) - : Time(time) - , History(std::move(history)) - {} - }; - - struct TEvConfigure : public TEventLocal<TEvConfigure, EvConfigure> { - TInstant ApplyAt; - NKikimrKesus::TStreamingQuoterResource Props; - - TEvConfigure(TInstant applyAt, const NKikimrKesus::TStreamingQuoterResource& props) - : ApplyAt(applyAt) - , Props(props) - {} - }; - - struct TEvCounters : public TEventLocal<TEvCounters, EvCounters> { - TRateAccountingCounters Counters; - - TEvCounters(const TRateAccountingCounters& counters) - : Counters(counters) - {} - }; -}; - -//////////////////////////////////////////////////////////////////////////////// -inline NJson::TJsonMap ToJsonMap(const google::protobuf::Map<TString, TString>& o) { - NJson::TJsonMap m; - for (auto& [k, v] : o) { - m[k] = v; - } - return m; -} - -//////////////////////////////////////////////////////////////////////////////// -class TBillingMetric { - double Quantity = 0; // total consumption - TInstant LastBillTime; // start of last billing period - TInstant Accumulated; // start of accumulation `Quantity` - - // Monitoring - NMonitoring::TDynamicCounters::TCounterPtr Billed; - - // Configuration - NKikimrKesus::TAccountingConfig::TMetric Cfg; - TTimeGrid TimeGrid; // billing metric time grid - TString QuoterPath; - TString ResourcePath; - TString Category; - IBillSink::TPtr BillSink; - -public: - explicit TBillingMetric() - : TimeGrid(TDuration::Minutes(1)) - {} - - static TTimeGrid TimeGridForPeriod(int seconds) { - // Period must be in [2, 3600] seconds interval and be divisor of an hour - seconds = std::clamp(seconds, 2, 3600); - for (; 3600 % seconds != 0; seconds--) {} - return TTimeGrid(TDuration::Seconds(seconds)); - } - - void SetResourceCounters(const NMonitoring::TDynamicCounters::TCounterPtr& billed) { - Billed = billed; - } - - void Configure(const NKikimrKesus::TAccountingConfig::TMetric& cfg, - const TString& quoterPath, - const TString& resourcePath, - const TString& category, - const IBillSink::TPtr& billSink) - { - if (cfg.GetBillingPeriodSec() != Cfg.GetBillingPeriodSec()) { - TimeGrid = TimeGridForPeriod(cfg.GetBillingPeriodSec()); - ResetAccumulated(); // just reset data aligned with old grid (underbill is better than overbill) - } - Cfg = cfg; - QuoterPath = quoterPath; - ResourcePath = resourcePath; - Category = category; - BillSink = billSink; - } - - void Add(double value, TInstant t, const NActors::TActorContext& ctx) { - SendBill(t, ctx); - if (!Accumulated) { - Accumulated = t; - } - Quantity += value; - LWPROBE(ResourceBillAdd, - QuoterPath, - ResourcePath, - Category, - Accumulated, - t, - t - Accumulated, - Quantity, - value); - } - -private: - void SendBill(TInstant t, const NActors::TActorContext& ctx) { - auto curr = TimeGrid.Get(t); - auto bill = TimeGrid.Get(Accumulated); - auto last = TimeGrid.Get(LastBillTime); - if ((LastBillTime && bill.Start <= last.End) || curr.Start <= bill.End) { - return; // too early to bill - } - - LastBillTime = bill.Start; - ui64 BillQuantity = std::ceil(Quantity); - if (Billed) { - *Billed += BillQuantity; - } - if (Cfg.GetEnabled() && BillQuantity > 0) { - const TString id = TStringBuilder() - << ResourcePath - << "-" << Category - << "-" << bill.Start.Seconds() - << "-" << bill.End.Seconds(); - - const TBillRecord billRecord = TBillRecord() - .Id(id) - .SourceWt(TActivationContext::Now()) - .Usage(TBillRecord::RequestUnits(BillQuantity, bill.Start, bill.End)) - .Version(Cfg.GetVersion()) - .Schema(Cfg.GetSchema()) - .CloudId(Cfg.GetCloudId()) - .FolderId(Cfg.GetFolderId()) - .ResourceId(Cfg.GetResourceId()) - .SourceId(Cfg.GetSourceId()) - .Tags(ToJsonMap(Cfg.GetTags())); - - LWPROBE(ResourceBillSend, - QuoterPath, - ResourcePath, - Category, - BillQuantity, - bill.Start, - bill.End, - billRecord.Version_, - billRecord.Schema_, - billRecord.CloudId_, - billRecord.FolderId_, - billRecord.ResourceId_, - billRecord.SourceId_); - BillSink->Send(ctx, billRecord); - } - - ResetAccumulated(); - } - - void ResetAccumulated() { - Quantity = 0; - Accumulated = TInstant::Zero(); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -class TAccountingActor final: public TActor<TAccountingActor> { -private: - // Accounting (aggregate history intervals and split consumption into billing categories) - TInstant Time; // current history replay time for token buckets - TTokenBucket ProvisionedBucket; - TTokenBucket OnDemandBucket; - TDeque<TAutoPtr<TEvPrivate::TEvConfigure>> ConfigQueue; - - // Billing (actually make bill records and send'em to metering actor) - IBillSink::TPtr BillSink; - TString QuoterPath; - TString ResourcePath; - TBillingMetric Provisioned; - TBillingMetric OnDemand; - TBillingMetric Overshoot; - - // Monitoring - TRateAccountingCounters Counters; -public: - explicit TAccountingActor(const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props, const TString& quoterPath) - : TActor(&TThis::StateWork) - , BillSink(billSink) - , QuoterPath(quoterPath) - , ResourcePath(props.GetResourcePath()) - { - Configure(props); - } - - static constexpr NKikimrServices::TActivity::EType ActorActivityType() { - return NKikimrServices::TActivity::KESUS_ACCOUNTING_ACTOR; - } - -private: - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvPrivate::TEvConfigure, Handle); - hFunc(TEvPrivate::TEvCounters, Handle); - HFunc(TEvPrivate::TEvRunAccounting, Handle); - cFunc(TEvents::TEvPoisonPill::EventType, PassAway); - } - } - - void Handle(const TEvPrivate::TEvConfigure::TPtr& ev) { - // Delay config apply since we work with history here - ConfigQueue.emplace_back(ev.Get()->Release()); - } - - void Handle(const TEvPrivate::TEvCounters::TPtr& ev) { - auto* e = ev->Get(); - Counters = e->Counters; - Provisioned.SetResourceCounters(Counters.Provisioned); - OnDemand.SetResourceCounters(Counters.OnDemand); - Overshoot.SetResourceCounters(Counters.Overshoot); - } - - void ProcessConfigQueue() { - while (!ConfigQueue.empty() && ConfigQueue.front()->ApplyAt <= Time) { - Configure(ConfigQueue.front()->Props); - ConfigQueue.pop_front(); - } - } - - void Configure(const NKikimrKesus::TStreamingQuoterResource& props) { - const auto& accCfg = props.GetAccountingConfig(); - const auto& resCfg = props.GetHierarhicalDRRResourceConfig(); - ProvisionedBucket.SetRate(accCfg.GetProvisionedUnitsPerSecond()); - ProvisionedBucket.SetCapacity(accCfg.GetProvisionedUnitsPerSecond() * accCfg.GetProvisionedCoefficient()); - OnDemandBucket.SetRate(resCfg.GetMaxUnitsPerSecond()); - OnDemandBucket.SetCapacity(accCfg.GetOvershootCoefficient() * resCfg.GetMaxUnitsPerSecond() * resCfg.GetPrefetchCoefficient()); - Provisioned.Configure(accCfg.GetProvisioned(), QuoterPath, props.GetResourcePath(), "provisioned", BillSink); - OnDemand.Configure(accCfg.GetOnDemand(), QuoterPath, props.GetResourcePath(), "ondemand", BillSink); - Overshoot.Configure(accCfg.GetOvershoot(), QuoterPath, props.GetResourcePath(), "overshoot", BillSink); - LWPROBE(ResourceAccountConfigure, - QuoterPath, - ResourcePath, - ProvisionedBucket.GetRate(), ProvisionedBucket.GetCapacity(), ProvisionedBucket.Available(), ProvisionedBucket.GetLastFill(), - OnDemandBucket.GetRate(), OnDemandBucket.GetCapacity(), OnDemandBucket.Available(), OnDemandBucket.GetLastFill()); - - } - - void Handle(const TEvPrivate::TEvRunAccounting::TPtr& ev, const NActors::TActorContext& ctx) { - auto* e = ev->Get(); - - // Aggregate consumption over history - for (TInstant t = e->History.Begin(); t != e->History.End(); t = e->History.Next(t)) { - AddValue(t, e->History.Get(t), ctx); - } - - // Propagate time to the last accounted instant - // NOTE: required to report zero consumption not saved in history - // NOTE: may coincide with the last point and therefore ignored - AddValue(e->Time, 0, ctx); - } - - void AddValue(TInstant t, double consumed, const NActors::TActorContext& ctx) { - if (Y_UNLIKELY(t <= Time)) { - return; // ignore data from past - } - Time = t; - ProcessConfigQueue(); - - // Classify consumption into 3 categories - double provisionedAndOnDemand = OnDemandBucket.FillAndTryTake(t, consumed); - double provisioned = ProvisionedBucket.FillAndTryTake(t, consumed); - double onDemand = Max(0.0, provisionedAndOnDemand - provisioned); - double overshoot = Max(0.0, consumed - provisioned - onDemand); - - LWPROBE(ResourceAccount, - QuoterPath, - ResourcePath, - t, provisionedAndOnDemand, provisioned, onDemand, overshoot, - ProvisionedBucket.GetRate(), ProvisionedBucket.GetCapacity(), ProvisionedBucket.Available(), - OnDemandBucket.GetRate(), OnDemandBucket.GetCapacity(), OnDemandBucket.Available()); - - Provisioned.Add(provisioned, t, ctx); - OnDemand.Add(onDemand, t, ctx); - Overshoot.Add(overshoot, t, ctx); - } -}; - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// - -TRateAccounting::TRateAccounting(NActors::TActorId kesus, const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props, const TString& quoterPath) - : Props(props) - , QuoterPath(quoterPath) - , History(HistorySize()) - , Kesus(kesus) -{ - AccountingActor = TActivationContext::Register(new TAccountingActor(billSink, Props, QuoterPath), Kesus); - ConfigureImpl(); -} - -void TRateAccounting::Stop() { - TActivationContext::Send(new IEventHandle(AccountingActor, Kesus, - new TEvents::TEvPoisonPill())); -} - -bool TRateAccounting::ValidateProps(const NKikimrKesus::TStreamingQuoterResource& props, TString& errorMessage) { - // NOTE: ValidateProps() is called with NOT effective props, so some fields can be unset, see CalcParameters() - const auto& cfg = props.GetAccountingConfig(); - if (cfg.GetCollectPeriodSec() > 3600) { - errorMessage = "CollectPeriodSec must be less than an hour."; - return false; - } - if (!std::isfinite(cfg.GetProvisionedUnitsPerSecond())) { - errorMessage = "ProvisionedUnitsPerSecond must be finite."; - return false; - } - if (!std::isfinite(cfg.GetProvisionedCoefficient())) { - errorMessage = "ProvisionedCoefficient must be finite."; - return false; - } - if (!std::isfinite(cfg.GetOvershootCoefficient())) { - errorMessage = "OvershootCoefficient must be finite."; - return false; - } - if (cfg.GetProvisionedUnitsPerSecond() < 0.0) { - errorMessage = "ProvisionedUnitsPerSecond must be greater or equal to 0."; - return false; - } - if (cfg.GetProvisionedCoefficient() < 0.0) { - errorMessage = "ProvisionedCoefficient must be greater or equal to 0."; - return false; - } - if (cfg.GetOvershootCoefficient() != 0.0 && cfg.GetOvershootCoefficient() < 1.0) { - errorMessage = "OvershootCoefficient must be greater or equal to 1 or not set (zero)."; - return false; - } - return true; -} - -void TRateAccounting::Configure(const NKikimrKesus::TStreamingQuoterResource& props) { - // NOTE: Configure is called with effective props - Props = props; - ConfigureImpl(); - TActivationContext::Send(new NActors::IEventHandle(AccountingActor, Kesus, - new TEvPrivate::TEvConfigure(TActivationContext::Now(), props))); -} - -void TRateAccounting::ConfigureImpl() { - size_t newHistorySize = HistorySize(); - if (History.Size() != newHistorySize) { - TConsumptionHistory newHistory(newHistorySize); - newHistory.Add(History, Accounted); // Note that data loss is possible on size decrease - History = std::move(newHistory); - } - const auto& accCfg = Props.GetAccountingConfig(); - MaxBillingPeriod = TDuration::Seconds(Max( - accCfg.GetProvisioned().GetBillingPeriodSec(), - accCfg.GetOnDemand().GetBillingPeriodSec(), - accCfg.GetOvershoot().GetBillingPeriodSec())); -} - -TInstant TRateAccounting::Report( - const NActors::TActorId& clientId, - ui64 resourceId, - TInstant start, - TDuration interval, - const double* values, - size_t size) -{ - // Deduplicate - TDedupId dedupId(clientId, resourceId); - auto [iter, isNew] = ClientToReported.emplace(dedupId, TInstant::Zero()); - TInstant& reported = iter->second; - if (start < reported) { - ui64 skip = ((reported - start).MicroSeconds() + interval.MicroSeconds() - 1) / interval.MicroSeconds(); - LWPROBE(ResourceReportDedup, QuoterPath, Props.GetResourcePath(), skip, size, start); - if (skip >= size) { // all values are deduplicated - LWPROBE(ResourceReportDedupFull, QuoterPath, Props.GetResourcePath(), skip, size, start); - return reported; - } - values += skip; - size -= skip; - start += interval * skip; - Y_VERIFY(start >= reported, "rate accounting report deduplication error"); - } - - // Accept values and add them into history - // Note that data from distant future can be left unaccepted - size_t added = History.Add(interval, start, values, size, Accounted); - LWPROBE(ResourceReportAdd, QuoterPath, Props.GetResourcePath(), added, size, start, Accounted); - - // Propagate deduplication timestamp - if (!isNew) { - SortedClients.erase(std::make_pair(reported, dedupId)); - } - reported = start + added * interval; - SortedClients.emplace(reported, dedupId); - TInstant result = reported; - - // Clean is delayed till this moment to avoid `iter` invalidation - RemoveOldClients(); - return result; -} - -void TRateAccounting::RemoveOldClients() { - while (!SortedClients.empty() && SortedClients.begin()->first <= Accounted) { - ClientToReported.erase(SortedClients.begin()->second); - SortedClients.erase(SortedClients.begin()); - Y_VERIFY_DEBUG(SortedClients.size() == ClientToReported.size()); - } -} - -bool TRateAccounting::RunAccounting() { - bool accountingRequired = RunAccountingNoClean(); - RemoveOldClients(); - bool cleaningRequried = !SortedClients.empty(); - return accountingRequired || cleaningRequried; -} - -void TRateAccounting::SetResourceCounters(const TIntrusivePtr<NMonitoring::TDynamicCounters>& resourceCounters) { - Counters.SetResourceCounters(resourceCounters); - TActivationContext::Send(new NActors::IEventHandle(AccountingActor, Kesus, - new TEvPrivate::TEvCounters(Counters))); -} - -bool TRateAccounting::RunAccountingNoClean() { - // Check if we have enough values for at least one account period - TInstant accountTill = History.Align(TActivationContext::Now() - CollectPeriod()); - if (accountTill - Accounted < AccountPeriod()) { - LWPROBE(ResourceAccountingTooEarly, QuoterPath, Props.GetResourcePath(), accountTill, Accounted, AccountPeriod()); - return true; - } - - // Check if we have data to send - if (History.End() + MaxBillingPeriod <= Accounted) { - LWPROBE(ResourceAccountingNoData, QuoterPath, Props.GetResourcePath(), History.End(), Accounted, MaxBillingPeriod); - return false; - } - - // Offload hard work into accounting actor - TActivationContext::Send(new NActors::IEventHandle(AccountingActor, Kesus, - new TEvPrivate::TEvRunAccounting( - accountTill - History.Interval(), - TConsumptionHistory(History, Accounted, accountTill)))); - LWPROBE(ResourceAccountingSend, QuoterPath, Props.GetResourcePath(), accountTill, Accounted); - Accounted = accountTill; - return true; -} - -//////////////////////////////////////////////////////////////////////////////// - -class TMeteringSink : public IBillSink { -public: - void Send(const NActors::TActorContext& ctx, const TBillRecord& billRecord) override { - ctx.Send(NMetering::MakeMeteringServiceID(), - new NMetering::TEvMetering::TEvWriteMeteringJson(billRecord.ToString())); - } -}; - -IBillSink::TPtr MakeMeteringSink() { - return IBillSink::TPtr(new TMeteringSink()); -} - -} // namespace NKesus -} // namespace NKikimr + +#include <library/cpp/actors/core/hfunc.h> + +#include <util/string/builder.h> +#include <util/generic/deque.h> + +LWTRACE_USING(KESUS_QUOTER_PROVIDER); + +namespace NKikimr { +namespace NKesus { + +namespace { + +using namespace NActors; + +//////////////////////////////////////////////////////////////////////////////// +struct TEvPrivate { + enum EEv { + EvRunAccounting = EventSpaceBegin(TEvents::ES_PRIVATE), + EvConfigure, + EvCounters, + EvEnd + }; + + static_assert(EvEnd <= EventSpaceEnd(TKikimrEvents::ES_PRIVATE), + "expected EvEnd <= EventSpaceEnd(TKikimrEvents::ES_PRIVATE)"); + + struct TEvRunAccounting : public TEventLocal<TEvRunAccounting, EvRunAccounting> { + TInstant Time; + TConsumptionHistory History; + + TEvRunAccounting(TInstant time, TConsumptionHistory&& history) + : Time(time) + , History(std::move(history)) + {} + }; + + struct TEvConfigure : public TEventLocal<TEvConfigure, EvConfigure> { + TInstant ApplyAt; + NKikimrKesus::TStreamingQuoterResource Props; + + TEvConfigure(TInstant applyAt, const NKikimrKesus::TStreamingQuoterResource& props) + : ApplyAt(applyAt) + , Props(props) + {} + }; + + struct TEvCounters : public TEventLocal<TEvCounters, EvCounters> { + TRateAccountingCounters Counters; + + TEvCounters(const TRateAccountingCounters& counters) + : Counters(counters) + {} + }; +}; + +//////////////////////////////////////////////////////////////////////////////// +inline NJson::TJsonMap ToJsonMap(const google::protobuf::Map<TString, TString>& o) { + NJson::TJsonMap m; + for (auto& [k, v] : o) { + m[k] = v; + } + return m; +} + +//////////////////////////////////////////////////////////////////////////////// +class TBillingMetric { + double Quantity = 0; // total consumption + TInstant LastBillTime; // start of last billing period + TInstant Accumulated; // start of accumulation `Quantity` + + // Monitoring + NMonitoring::TDynamicCounters::TCounterPtr Billed; + + // Configuration + NKikimrKesus::TAccountingConfig::TMetric Cfg; + TTimeGrid TimeGrid; // billing metric time grid + TString QuoterPath; + TString ResourcePath; + TString Category; + IBillSink::TPtr BillSink; + +public: + explicit TBillingMetric() + : TimeGrid(TDuration::Minutes(1)) + {} + + static TTimeGrid TimeGridForPeriod(int seconds) { + // Period must be in [2, 3600] seconds interval and be divisor of an hour + seconds = std::clamp(seconds, 2, 3600); + for (; 3600 % seconds != 0; seconds--) {} + return TTimeGrid(TDuration::Seconds(seconds)); + } + + void SetResourceCounters(const NMonitoring::TDynamicCounters::TCounterPtr& billed) { + Billed = billed; + } + + void Configure(const NKikimrKesus::TAccountingConfig::TMetric& cfg, + const TString& quoterPath, + const TString& resourcePath, + const TString& category, + const IBillSink::TPtr& billSink) + { + if (cfg.GetBillingPeriodSec() != Cfg.GetBillingPeriodSec()) { + TimeGrid = TimeGridForPeriod(cfg.GetBillingPeriodSec()); + ResetAccumulated(); // just reset data aligned with old grid (underbill is better than overbill) + } + Cfg = cfg; + QuoterPath = quoterPath; + ResourcePath = resourcePath; + Category = category; + BillSink = billSink; + } + + void Add(double value, TInstant t, const NActors::TActorContext& ctx) { + SendBill(t, ctx); + if (!Accumulated) { + Accumulated = t; + } + Quantity += value; + LWPROBE(ResourceBillAdd, + QuoterPath, + ResourcePath, + Category, + Accumulated, + t, + t - Accumulated, + Quantity, + value); + } + +private: + void SendBill(TInstant t, const NActors::TActorContext& ctx) { + auto curr = TimeGrid.Get(t); + auto bill = TimeGrid.Get(Accumulated); + auto last = TimeGrid.Get(LastBillTime); + if ((LastBillTime && bill.Start <= last.End) || curr.Start <= bill.End) { + return; // too early to bill + } + + LastBillTime = bill.Start; + ui64 BillQuantity = std::ceil(Quantity); + if (Billed) { + *Billed += BillQuantity; + } + if (Cfg.GetEnabled() && BillQuantity > 0) { + const TString id = TStringBuilder() + << ResourcePath + << "-" << Category + << "-" << bill.Start.Seconds() + << "-" << bill.End.Seconds(); + + const TBillRecord billRecord = TBillRecord() + .Id(id) + .SourceWt(TActivationContext::Now()) + .Usage(TBillRecord::RequestUnits(BillQuantity, bill.Start, bill.End)) + .Version(Cfg.GetVersion()) + .Schema(Cfg.GetSchema()) + .CloudId(Cfg.GetCloudId()) + .FolderId(Cfg.GetFolderId()) + .ResourceId(Cfg.GetResourceId()) + .SourceId(Cfg.GetSourceId()) + .Tags(ToJsonMap(Cfg.GetTags())); + + LWPROBE(ResourceBillSend, + QuoterPath, + ResourcePath, + Category, + BillQuantity, + bill.Start, + bill.End, + billRecord.Version_, + billRecord.Schema_, + billRecord.CloudId_, + billRecord.FolderId_, + billRecord.ResourceId_, + billRecord.SourceId_); + BillSink->Send(ctx, billRecord); + } + + ResetAccumulated(); + } + + void ResetAccumulated() { + Quantity = 0; + Accumulated = TInstant::Zero(); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +class TAccountingActor final: public TActor<TAccountingActor> { +private: + // Accounting (aggregate history intervals and split consumption into billing categories) + TInstant Time; // current history replay time for token buckets + TTokenBucket ProvisionedBucket; + TTokenBucket OnDemandBucket; + TDeque<TAutoPtr<TEvPrivate::TEvConfigure>> ConfigQueue; + + // Billing (actually make bill records and send'em to metering actor) + IBillSink::TPtr BillSink; + TString QuoterPath; + TString ResourcePath; + TBillingMetric Provisioned; + TBillingMetric OnDemand; + TBillingMetric Overshoot; + + // Monitoring + TRateAccountingCounters Counters; +public: + explicit TAccountingActor(const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props, const TString& quoterPath) + : TActor(&TThis::StateWork) + , BillSink(billSink) + , QuoterPath(quoterPath) + , ResourcePath(props.GetResourcePath()) + { + Configure(props); + } + + static constexpr NKikimrServices::TActivity::EType ActorActivityType() { + return NKikimrServices::TActivity::KESUS_ACCOUNTING_ACTOR; + } + +private: + STFUNC(StateWork) { + switch (ev->GetTypeRewrite()) { + hFunc(TEvPrivate::TEvConfigure, Handle); + hFunc(TEvPrivate::TEvCounters, Handle); + HFunc(TEvPrivate::TEvRunAccounting, Handle); + cFunc(TEvents::TEvPoisonPill::EventType, PassAway); + } + } + + void Handle(const TEvPrivate::TEvConfigure::TPtr& ev) { + // Delay config apply since we work with history here + ConfigQueue.emplace_back(ev.Get()->Release()); + } + + void Handle(const TEvPrivate::TEvCounters::TPtr& ev) { + auto* e = ev->Get(); + Counters = e->Counters; + Provisioned.SetResourceCounters(Counters.Provisioned); + OnDemand.SetResourceCounters(Counters.OnDemand); + Overshoot.SetResourceCounters(Counters.Overshoot); + } + + void ProcessConfigQueue() { + while (!ConfigQueue.empty() && ConfigQueue.front()->ApplyAt <= Time) { + Configure(ConfigQueue.front()->Props); + ConfigQueue.pop_front(); + } + } + + void Configure(const NKikimrKesus::TStreamingQuoterResource& props) { + const auto& accCfg = props.GetAccountingConfig(); + const auto& resCfg = props.GetHierarhicalDRRResourceConfig(); + ProvisionedBucket.SetRate(accCfg.GetProvisionedUnitsPerSecond()); + ProvisionedBucket.SetCapacity(accCfg.GetProvisionedUnitsPerSecond() * accCfg.GetProvisionedCoefficient()); + OnDemandBucket.SetRate(resCfg.GetMaxUnitsPerSecond()); + OnDemandBucket.SetCapacity(accCfg.GetOvershootCoefficient() * resCfg.GetMaxUnitsPerSecond() * resCfg.GetPrefetchCoefficient()); + Provisioned.Configure(accCfg.GetProvisioned(), QuoterPath, props.GetResourcePath(), "provisioned", BillSink); + OnDemand.Configure(accCfg.GetOnDemand(), QuoterPath, props.GetResourcePath(), "ondemand", BillSink); + Overshoot.Configure(accCfg.GetOvershoot(), QuoterPath, props.GetResourcePath(), "overshoot", BillSink); + LWPROBE(ResourceAccountConfigure, + QuoterPath, + ResourcePath, + ProvisionedBucket.GetRate(), ProvisionedBucket.GetCapacity(), ProvisionedBucket.Available(), ProvisionedBucket.GetLastFill(), + OnDemandBucket.GetRate(), OnDemandBucket.GetCapacity(), OnDemandBucket.Available(), OnDemandBucket.GetLastFill()); + + } + + void Handle(const TEvPrivate::TEvRunAccounting::TPtr& ev, const NActors::TActorContext& ctx) { + auto* e = ev->Get(); + + // Aggregate consumption over history + for (TInstant t = e->History.Begin(); t != e->History.End(); t = e->History.Next(t)) { + AddValue(t, e->History.Get(t), ctx); + } + + // Propagate time to the last accounted instant + // NOTE: required to report zero consumption not saved in history + // NOTE: may coincide with the last point and therefore ignored + AddValue(e->Time, 0, ctx); + } + + void AddValue(TInstant t, double consumed, const NActors::TActorContext& ctx) { + if (Y_UNLIKELY(t <= Time)) { + return; // ignore data from past + } + Time = t; + ProcessConfigQueue(); + + // Classify consumption into 3 categories + double provisionedAndOnDemand = OnDemandBucket.FillAndTryTake(t, consumed); + double provisioned = ProvisionedBucket.FillAndTryTake(t, consumed); + double onDemand = Max(0.0, provisionedAndOnDemand - provisioned); + double overshoot = Max(0.0, consumed - provisioned - onDemand); + + LWPROBE(ResourceAccount, + QuoterPath, + ResourcePath, + t, provisionedAndOnDemand, provisioned, onDemand, overshoot, + ProvisionedBucket.GetRate(), ProvisionedBucket.GetCapacity(), ProvisionedBucket.Available(), + OnDemandBucket.GetRate(), OnDemandBucket.GetCapacity(), OnDemandBucket.Available()); + + Provisioned.Add(provisioned, t, ctx); + OnDemand.Add(onDemand, t, ctx); + Overshoot.Add(overshoot, t, ctx); + } +}; + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// + +TRateAccounting::TRateAccounting(NActors::TActorId kesus, const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props, const TString& quoterPath) + : Props(props) + , QuoterPath(quoterPath) + , History(HistorySize()) + , Kesus(kesus) +{ + AccountingActor = TActivationContext::Register(new TAccountingActor(billSink, Props, QuoterPath), Kesus); + ConfigureImpl(); +} + +void TRateAccounting::Stop() { + TActivationContext::Send(new IEventHandle(AccountingActor, Kesus, + new TEvents::TEvPoisonPill())); +} + +bool TRateAccounting::ValidateProps(const NKikimrKesus::TStreamingQuoterResource& props, TString& errorMessage) { + // NOTE: ValidateProps() is called with NOT effective props, so some fields can be unset, see CalcParameters() + const auto& cfg = props.GetAccountingConfig(); + if (cfg.GetCollectPeriodSec() > 3600) { + errorMessage = "CollectPeriodSec must be less than an hour."; + return false; + } + if (!std::isfinite(cfg.GetProvisionedUnitsPerSecond())) { + errorMessage = "ProvisionedUnitsPerSecond must be finite."; + return false; + } + if (!std::isfinite(cfg.GetProvisionedCoefficient())) { + errorMessage = "ProvisionedCoefficient must be finite."; + return false; + } + if (!std::isfinite(cfg.GetOvershootCoefficient())) { + errorMessage = "OvershootCoefficient must be finite."; + return false; + } + if (cfg.GetProvisionedUnitsPerSecond() < 0.0) { + errorMessage = "ProvisionedUnitsPerSecond must be greater or equal to 0."; + return false; + } + if (cfg.GetProvisionedCoefficient() < 0.0) { + errorMessage = "ProvisionedCoefficient must be greater or equal to 0."; + return false; + } + if (cfg.GetOvershootCoefficient() != 0.0 && cfg.GetOvershootCoefficient() < 1.0) { + errorMessage = "OvershootCoefficient must be greater or equal to 1 or not set (zero)."; + return false; + } + return true; +} + +void TRateAccounting::Configure(const NKikimrKesus::TStreamingQuoterResource& props) { + // NOTE: Configure is called with effective props + Props = props; + ConfigureImpl(); + TActivationContext::Send(new NActors::IEventHandle(AccountingActor, Kesus, + new TEvPrivate::TEvConfigure(TActivationContext::Now(), props))); +} + +void TRateAccounting::ConfigureImpl() { + size_t newHistorySize = HistorySize(); + if (History.Size() != newHistorySize) { + TConsumptionHistory newHistory(newHistorySize); + newHistory.Add(History, Accounted); // Note that data loss is possible on size decrease + History = std::move(newHistory); + } + const auto& accCfg = Props.GetAccountingConfig(); + MaxBillingPeriod = TDuration::Seconds(Max( + accCfg.GetProvisioned().GetBillingPeriodSec(), + accCfg.GetOnDemand().GetBillingPeriodSec(), + accCfg.GetOvershoot().GetBillingPeriodSec())); +} + +TInstant TRateAccounting::Report( + const NActors::TActorId& clientId, + ui64 resourceId, + TInstant start, + TDuration interval, + const double* values, + size_t size) +{ + // Deduplicate + TDedupId dedupId(clientId, resourceId); + auto [iter, isNew] = ClientToReported.emplace(dedupId, TInstant::Zero()); + TInstant& reported = iter->second; + if (start < reported) { + ui64 skip = ((reported - start).MicroSeconds() + interval.MicroSeconds() - 1) / interval.MicroSeconds(); + LWPROBE(ResourceReportDedup, QuoterPath, Props.GetResourcePath(), skip, size, start); + if (skip >= size) { // all values are deduplicated + LWPROBE(ResourceReportDedupFull, QuoterPath, Props.GetResourcePath(), skip, size, start); + return reported; + } + values += skip; + size -= skip; + start += interval * skip; + Y_VERIFY(start >= reported, "rate accounting report deduplication error"); + } + + // Accept values and add them into history + // Note that data from distant future can be left unaccepted + size_t added = History.Add(interval, start, values, size, Accounted); + LWPROBE(ResourceReportAdd, QuoterPath, Props.GetResourcePath(), added, size, start, Accounted); + + // Propagate deduplication timestamp + if (!isNew) { + SortedClients.erase(std::make_pair(reported, dedupId)); + } + reported = start + added * interval; + SortedClients.emplace(reported, dedupId); + TInstant result = reported; + + // Clean is delayed till this moment to avoid `iter` invalidation + RemoveOldClients(); + return result; +} + +void TRateAccounting::RemoveOldClients() { + while (!SortedClients.empty() && SortedClients.begin()->first <= Accounted) { + ClientToReported.erase(SortedClients.begin()->second); + SortedClients.erase(SortedClients.begin()); + Y_VERIFY_DEBUG(SortedClients.size() == ClientToReported.size()); + } +} + +bool TRateAccounting::RunAccounting() { + bool accountingRequired = RunAccountingNoClean(); + RemoveOldClients(); + bool cleaningRequried = !SortedClients.empty(); + return accountingRequired || cleaningRequried; +} + +void TRateAccounting::SetResourceCounters(const TIntrusivePtr<NMonitoring::TDynamicCounters>& resourceCounters) { + Counters.SetResourceCounters(resourceCounters); + TActivationContext::Send(new NActors::IEventHandle(AccountingActor, Kesus, + new TEvPrivate::TEvCounters(Counters))); +} + +bool TRateAccounting::RunAccountingNoClean() { + // Check if we have enough values for at least one account period + TInstant accountTill = History.Align(TActivationContext::Now() - CollectPeriod()); + if (accountTill - Accounted < AccountPeriod()) { + LWPROBE(ResourceAccountingTooEarly, QuoterPath, Props.GetResourcePath(), accountTill, Accounted, AccountPeriod()); + return true; + } + + // Check if we have data to send + if (History.End() + MaxBillingPeriod <= Accounted) { + LWPROBE(ResourceAccountingNoData, QuoterPath, Props.GetResourcePath(), History.End(), Accounted, MaxBillingPeriod); + return false; + } + + // Offload hard work into accounting actor + TActivationContext::Send(new NActors::IEventHandle(AccountingActor, Kesus, + new TEvPrivate::TEvRunAccounting( + accountTill - History.Interval(), + TConsumptionHistory(History, Accounted, accountTill)))); + LWPROBE(ResourceAccountingSend, QuoterPath, Props.GetResourcePath(), accountTill, Accounted); + Accounted = accountTill; + return true; +} + +//////////////////////////////////////////////////////////////////////////////// + +class TMeteringSink : public IBillSink { +public: + void Send(const NActors::TActorContext& ctx, const TBillRecord& billRecord) override { + ctx.Send(NMetering::MakeMeteringServiceID(), + new NMetering::TEvMetering::TEvWriteMeteringJson(billRecord.ToString())); + } +}; + +IBillSink::TPtr MakeMeteringSink() { + return IBillSink::TPtr(new TMeteringSink()); +} + +} // namespace NKesus +} // namespace NKikimr diff --git a/ydb/core/kesus/tablet/rate_accounting.h b/ydb/core/kesus/tablet/rate_accounting.h index 4faa1ea114..3984650d90 100644 --- a/ydb/core/kesus/tablet/rate_accounting.h +++ b/ydb/core/kesus/tablet/rate_accounting.h @@ -1,107 +1,107 @@ -#pragma once - +#pragma once + #include <ydb/core/protos/kesus.pb.h> #include <ydb/core/util/time_series_vec.h> - -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> - -#include <util/generic/noncopyable.h> -#include <util/generic/hash.h> -#include <util/generic/set.h> - -namespace NKikimr { - -struct TBillRecord; - -namespace NKesus { - -// NOTE: IntervalUs is better to be the same on quoter proxy and kesus tablet -using TConsumptionHistory = TTimeSeriesVec<double>; - -// Bill sink - encapsulates send method to metering actor -// Actually implements dependency injection for testing purpose -class IBillSink : public TThrRefBase { -public: - using TPtr = TIntrusivePtr<IBillSink>; - virtual void Send(const NActors::TActorContext& ctx, const TBillRecord& billRecord) = 0; -}; - -IBillSink::TPtr MakeMeteringSink(); - -struct TRateAccountingCounters { - TIntrusivePtr<NMonitoring::TDynamicCounters> ResourceCounters; - NMonitoring::TDynamicCounters::TCounterPtr Provisioned; - NMonitoring::TDynamicCounters::TCounterPtr OnDemand; - NMonitoring::TDynamicCounters::TCounterPtr Overshoot; - - void SetResourceCounters(const TIntrusivePtr<NMonitoring::TDynamicCounters>& resourceCounters) { - ResourceCounters = resourceCounters; - if (ResourceCounters) { - Provisioned = ResourceCounters->GetCounter("Provisioned", true); - OnDemand = ResourceCounters->GetCounter("OnDemand", true); - Overshoot = ResourceCounters->GetCounter("Overshoot", true); - } else { - Provisioned = MakeIntrusive<NMonitoring::TCounterForPtr>(true); - OnDemand = MakeIntrusive<NMonitoring::TCounterForPtr>(true); - Overshoot = MakeIntrusive<NMonitoring::TCounterForPtr>(true); - } - } -}; - - -// Consumption aggregation logic and bill making -class TRateAccounting : public TNonCopyable { - NKikimrKesus::TStreamingQuoterResource Props; - TString QuoterPath; - using TDedupId = std::pair<NActors::TActorId, ui64>; // clientId, resourceId - THashMap<TDedupId, TInstant> ClientToReported; // Most recent reported time by client - TSet<std::pair<TInstant, TDedupId>> SortedClients; // for fast cleanup - TInstant Accounted; // Next accounting period begining - TConsumptionHistory History; - NActors::TActorId Kesus; - NActors::TActorId AccountingActor; - TDuration MaxBillingPeriod; - TRateAccountingCounters Counters; -public: - // Init and create accounting actor - TRateAccounting(NActors::TActorId kesus, const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props, const TString& quoterPath); - - // Destroy accounting actor - void Stop(); - - // Configuration - static bool ValidateProps(const NKikimrKesus::TStreamingQuoterResource& props, TString& errorMessage); - void Configure(const NKikimrKesus::TStreamingQuoterResource& props); - - // Deduplicate and merge client's data into consumption history - TInstant Report(const NActors::TActorId& clientId, ui64 resourceId, TInstant start, TDuration interval, const double* values, size_t size); - - // Check timings and send message to accounting actor if required - // Should be called periodically to account tail if there is no reports any longer - // Returns true iff there are unsent reports (retry on next tick is required) - bool RunAccounting(); - - void SetResourceCounters(const TIntrusivePtr<NMonitoring::TDynamicCounters>& resourceCounters); - -private: - void ConfigureImpl(); - void RemoveOldClients(); - bool RunAccountingNoClean(); - - TDuration CollectPeriod() const { - return TDuration::Seconds(Props.GetAccountingConfig().GetCollectPeriodSec()); - } - - TDuration AccountPeriod() const { - return TDuration::MilliSeconds(Props.GetAccountingConfig().GetAccountPeriodMs()); - } - - size_t HistorySize() const { - // One collect period into future and one into past plus window for accounting - return (2 * CollectPeriod() + AccountPeriod()) / History.Interval(); - } -}; - -} // namespace NKesus -} // namespace NKikimr + +#include <library/cpp/actors/core/actorsystem.h> +#include <library/cpp/monlib/dynamic_counters/counters.h> + +#include <util/generic/noncopyable.h> +#include <util/generic/hash.h> +#include <util/generic/set.h> + +namespace NKikimr { + +struct TBillRecord; + +namespace NKesus { + +// NOTE: IntervalUs is better to be the same on quoter proxy and kesus tablet +using TConsumptionHistory = TTimeSeriesVec<double>; + +// Bill sink - encapsulates send method to metering actor +// Actually implements dependency injection for testing purpose +class IBillSink : public TThrRefBase { +public: + using TPtr = TIntrusivePtr<IBillSink>; + virtual void Send(const NActors::TActorContext& ctx, const TBillRecord& billRecord) = 0; +}; + +IBillSink::TPtr MakeMeteringSink(); + +struct TRateAccountingCounters { + TIntrusivePtr<NMonitoring::TDynamicCounters> ResourceCounters; + NMonitoring::TDynamicCounters::TCounterPtr Provisioned; + NMonitoring::TDynamicCounters::TCounterPtr OnDemand; + NMonitoring::TDynamicCounters::TCounterPtr Overshoot; + + void SetResourceCounters(const TIntrusivePtr<NMonitoring::TDynamicCounters>& resourceCounters) { + ResourceCounters = resourceCounters; + if (ResourceCounters) { + Provisioned = ResourceCounters->GetCounter("Provisioned", true); + OnDemand = ResourceCounters->GetCounter("OnDemand", true); + Overshoot = ResourceCounters->GetCounter("Overshoot", true); + } else { + Provisioned = MakeIntrusive<NMonitoring::TCounterForPtr>(true); + OnDemand = MakeIntrusive<NMonitoring::TCounterForPtr>(true); + Overshoot = MakeIntrusive<NMonitoring::TCounterForPtr>(true); + } + } +}; + + +// Consumption aggregation logic and bill making +class TRateAccounting : public TNonCopyable { + NKikimrKesus::TStreamingQuoterResource Props; + TString QuoterPath; + using TDedupId = std::pair<NActors::TActorId, ui64>; // clientId, resourceId + THashMap<TDedupId, TInstant> ClientToReported; // Most recent reported time by client + TSet<std::pair<TInstant, TDedupId>> SortedClients; // for fast cleanup + TInstant Accounted; // Next accounting period begining + TConsumptionHistory History; + NActors::TActorId Kesus; + NActors::TActorId AccountingActor; + TDuration MaxBillingPeriod; + TRateAccountingCounters Counters; +public: + // Init and create accounting actor + TRateAccounting(NActors::TActorId kesus, const IBillSink::TPtr& billSink, const NKikimrKesus::TStreamingQuoterResource& props, const TString& quoterPath); + + // Destroy accounting actor + void Stop(); + + // Configuration + static bool ValidateProps(const NKikimrKesus::TStreamingQuoterResource& props, TString& errorMessage); + void Configure(const NKikimrKesus::TStreamingQuoterResource& props); + + // Deduplicate and merge client's data into consumption history + TInstant Report(const NActors::TActorId& clientId, ui64 resourceId, TInstant start, TDuration interval, const double* values, size_t size); + + // Check timings and send message to accounting actor if required + // Should be called periodically to account tail if there is no reports any longer + // Returns true iff there are unsent reports (retry on next tick is required) + bool RunAccounting(); + + void SetResourceCounters(const TIntrusivePtr<NMonitoring::TDynamicCounters>& resourceCounters); + +private: + void ConfigureImpl(); + void RemoveOldClients(); + bool RunAccountingNoClean(); + + TDuration CollectPeriod() const { + return TDuration::Seconds(Props.GetAccountingConfig().GetCollectPeriodSec()); + } + + TDuration AccountPeriod() const { + return TDuration::MilliSeconds(Props.GetAccountingConfig().GetAccountPeriodMs()); + } + + size_t HistorySize() const { + // One collect period into future and one into past plus window for accounting + return (2 * CollectPeriod() + AccountPeriod()) / History.Interval(); + } +}; + +} // namespace NKesus +} // namespace NKikimr diff --git a/ydb/core/kesus/tablet/tablet_impl.cpp b/ydb/core/kesus/tablet/tablet_impl.cpp index 245c4b91b8..425abffc41 100644 --- a/ydb/core/kesus/tablet/tablet_impl.cpp +++ b/ydb/core/kesus/tablet/tablet_impl.cpp @@ -296,7 +296,7 @@ STFUNC(TKesusTablet::StateWork) { hFunc(TEvKesus::TEvDeleteQuoterResource, Handle); hFunc(TEvKesus::TEvSubscribeOnResources, Handle); hFunc(TEvKesus::TEvUpdateConsumptionState, Handle); - hFunc(TEvKesus::TEvAccountResources, Handle); + hFunc(TEvKesus::TEvAccountResources, Handle); hFunc(TEvKesus::TEvResourcesAllocatedAck, Handle); hFunc(TEvKesus::TEvGetQuoterResourceCounters, Handle); hFunc(TEvTabletPipe::TEvServerDisconnected, Handle); diff --git a/ydb/core/kesus/tablet/tablet_impl.h b/ydb/core/kesus/tablet/tablet_impl.h index 1607e352d0..613d28a977 100644 --- a/ydb/core/kesus/tablet/tablet_impl.h +++ b/ydb/core/kesus/tablet/tablet_impl.h @@ -407,7 +407,7 @@ private: // Quoter runtime void Handle(TEvKesus::TEvSubscribeOnResources::TPtr& ev); void Handle(TEvKesus::TEvUpdateConsumptionState::TPtr& ev); - void Handle(TEvKesus::TEvAccountResources::TPtr& ev); + void Handle(TEvKesus::TEvAccountResources::TPtr& ev); void Handle(TEvKesus::TEvResourcesAllocatedAck::TPtr& ev); void Handle(TEvKesus::TEvGetQuoterResourceCounters::TPtr& ev); void Handle(TEvTabletPipe::TEvServerDisconnected::TPtr& ev); diff --git a/ydb/core/kesus/tablet/tablet_ut.cpp b/ydb/core/kesus/tablet/tablet_ut.cpp index 1cf1a80ca8..e0470089d8 100644 --- a/ydb/core/kesus/tablet/tablet_ut.cpp +++ b/ydb/core/kesus/tablet/tablet_ut.cpp @@ -1,10 +1,10 @@ #include "tablet.h" #include "events.h" #include "ut_helpers.h" -#include "rate_accounting.h" +#include "rate_accounting.h" #include <ydb/core/metering/metering.h> - + #include <library/cpp/actors/interconnect/interconnect_impl.h> #include <util/random/random.h> @@ -1675,415 +1675,415 @@ Y_UNIT_TEST_SUITE(TKesusTest) { } while (allocated < 49.99); } - Y_UNIT_TEST(TestQuoterAccountResourcesOnDemand) { - TTestContext ctx; - ctx.Setup(); - - TString billRecord; - ctx.Runtime->SetObserverFunc([&billRecord](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { - if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { - billRecord = ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson; - } - return TTestActorRuntime::EEventAction::PROCESS; - }); - - NKikimrKesus::TStreamingQuoterResource cfg; - cfg.SetResourcePath("/Root"); - cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(100.0); - cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(300.0); - cfg.MutableAccountingConfig()->SetEnabled(true); - cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); - cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); - cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetVersion("version"); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetSchema("schema"); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetCloudId("cloud"); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetFolderId("folder"); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetResourceId("resource"); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetSourceId("source"); - cfg.MutableAccountingConfig()->MutableOnDemand()->MutableTags()->insert({"key", "value"}); - ctx.AddQuoterResource(cfg); - ctx.AddQuoterResource("/Root/Res"); // With inherited settings. - - auto edge = ctx.Runtime->AllocateEdgeActor(); - auto client = ctx.Runtime->AllocateEdgeActor(); - const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult = ctx.SubscribeOnResource(client, edge, "/Root/Res", false, 0); - - TInstant start = ctx.Runtime->GetCurrentTime(); - TDuration interval = TConsumptionHistory::Interval(); - ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), start, interval, {50.0}); - - if (billRecord.empty()) { - TDispatchOptions opts; - opts.FinalEvents.emplace_back([&billRecord](IEventHandle&) -> bool { - return !billRecord.empty(); - }); - ctx.Runtime->DispatchEvents(opts); - } - - const TString expectedBillRecord = R"({"usage":{"start":0,"quantity":50,"finish":1,"unit":"request_unit","type":"delta"},"tags":{"key":"value"},"id":"Root-ondemand-0-1","cloud_id":"cloud","source_wt":5,"source_id":"source","resource_id":"resource","schema":"schema","folder_id":"folder","version":"version"})"; - - UNIT_ASSERT_NO_DIFF(billRecord, expectedBillRecord + "\n"); - } - - Y_UNIT_TEST(TestQuoterAccountResourcesBurst) { - TTestContext ctx; - ctx.Setup(); - - std::vector<TString> bills; - ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { - if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { - bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); - } - return TTestActorRuntime::EEventAction::PROCESS; - }); - - NKikimrKesus::TStreamingQuoterResource cfg; - cfg.SetResourcePath("/Root"); - cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); - cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); - cfg.MutableAccountingConfig()->SetEnabled(true); - cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); - cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); - cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); - cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); - cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); - cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); - ctx.AddQuoterResource(cfg); - ctx.AddQuoterResource("/Root/Res"); // With inherited settings. - - auto edge = ctx.Runtime->AllocateEdgeActor(); - auto client = ctx.Runtime->AllocateEdgeActor(); - const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult = ctx.SubscribeOnResource(client, edge, "/Root/Res", false, 0); - - TInstant start = ctx.Runtime->GetCurrentTime(); - TDuration interval = TConsumptionHistory::Interval(); - ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), start, interval, {600.0}); - - if (bills.size() < 3) { - TDispatchOptions opts; - opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { - return bills.size() >= 3; - }); - ctx.Runtime->DispatchEvents(opts); - } - - UNIT_ASSERT_NO_DIFF(bills[0], TString(R"({"usage":{"start":0,"quantity":100,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - UNIT_ASSERT_NO_DIFF(bills[1], TString(R"({"usage":{"start":0,"quantity":200,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - UNIT_ASSERT_NO_DIFF(bills[2], TString(R"({"usage":{"start":0,"quantity":300,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - } - - Y_UNIT_TEST(TestQuoterAccountResourcesPaced) { - TTestContext ctx; - ctx.Setup(); - - std::vector<TString> bills; - ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { - if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { - bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); - } - return TTestActorRuntime::EEventAction::PROCESS; - }); - - NKikimrKesus::TStreamingQuoterResource cfg; - cfg.SetResourcePath("/Root"); - cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); - cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); - cfg.MutableAccountingConfig()->SetEnabled(true); - cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); - cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); - cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); - cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); - cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); - cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); - ctx.AddQuoterResource(cfg); - ctx.AddQuoterResource("/Root/Res"); // With inherited settings. - - auto edge = ctx.Runtime->AllocateEdgeActor(); - auto client = ctx.Runtime->AllocateEdgeActor(); - const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult = ctx.SubscribeOnResource(client, edge, "/Root/Res", false, 0); - - TInstant start = ctx.Runtime->GetCurrentTime(); - TDuration interval = TConsumptionHistory::Interval(); - std::vector<double> values; - for (int i = 0; i < 100; i++) { - values.push_back(6); - } - ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), start, interval, std::move(values)); - - if (bills.size() < 3) { - TDispatchOptions opts; - opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { - return bills.size() >= 3; - }); - ctx.Runtime->DispatchEvents(opts); - } - - UNIT_ASSERT_NO_DIFF(bills[0], TString(R"({"usage":{"start":0,"quantity":199,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - UNIT_ASSERT_NO_DIFF(bills[1], TString(R"({"usage":{"start":0,"quantity":398,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - UNIT_ASSERT_NO_DIFF(bills[2], TString(R"({"usage":{"start":0,"quantity":3,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - } - - Y_UNIT_TEST(TestQuoterAccountResourcesAggregateClients) { - TTestContext ctx; - ctx.Setup(); - - std::vector<TString> bills; - ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { - if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { - bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); - } - return TTestActorRuntime::EEventAction::PROCESS; - }); - - NKikimrKesus::TStreamingQuoterResource cfg; - cfg.SetResourcePath("/Root"); - cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); - cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); - cfg.MutableAccountingConfig()->SetEnabled(true); - cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); - cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); - cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); - cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); - cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); - cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); - ctx.AddQuoterResource(cfg); - - auto edge = ctx.Runtime->AllocateEdgeActor(); - auto client1 = ctx.Runtime->AllocateEdgeActor(); - auto client2 = ctx.Runtime->AllocateEdgeActor(); - const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult1 = ctx.SubscribeOnResource(client1, edge, "/Root", false, 0); - const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult2 = ctx.SubscribeOnResource(client2, edge, "/Root", false, 0); - - TInstant start = ctx.Runtime->GetCurrentTime(); - TDuration interval = TConsumptionHistory::Interval(); - std::vector<double> values1; - std::vector<double> values2; - for (int i = 0; i < 100; i++) { - values1.push_back(3); - values2.push_back(3); - } - ctx.AccountResources(client1, edge, subscribeResult1.GetResults(0).GetResourceId(), start, interval, std::move(values1)); - ctx.AccountResources(client2, edge, subscribeResult2.GetResults(0).GetResourceId(), start, interval, std::move(values2)); - - if (bills.size() < 3) { - TDispatchOptions opts; - opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { - return bills.size() >= 3; - }); - ctx.Runtime->DispatchEvents(opts); - } - - UNIT_ASSERT_NO_DIFF(bills[0], TString(R"({"usage":{"start":0,"quantity":199,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - UNIT_ASSERT_NO_DIFF(bills[1], TString(R"({"usage":{"start":0,"quantity":398,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - UNIT_ASSERT_NO_DIFF(bills[2], TString(R"({"usage":{"start":0,"quantity":3,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - } - - Y_UNIT_TEST(TestQuoterAccountResourcesAggregateResources) { - TTestContext ctx; - ctx.Setup(); - - std::vector<TString> bills; - ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { - if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { - bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); - } - return TTestActorRuntime::EEventAction::PROCESS; - }); - - NKikimrKesus::TStreamingQuoterResource cfg; - cfg.SetResourcePath("/Root"); - cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); - cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); - cfg.MutableAccountingConfig()->SetEnabled(true); - cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); - cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); - cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); - cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); - cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); - cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); - ctx.AddQuoterResource(cfg); - ctx.AddQuoterResource("/Root/Res1"); // With inherited settings. - ctx.AddQuoterResource("/Root/Res2"); // With inherited settings. - - auto edge = ctx.Runtime->AllocateEdgeActor(); - auto client = ctx.Runtime->AllocateEdgeActor(); - const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult1 = ctx.SubscribeOnResource(client, edge, "/Root/Res1", false, 0); - const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult2 = ctx.SubscribeOnResource(client, edge, "/Root/Res2", false, 0); - - TInstant start = ctx.Runtime->GetCurrentTime(); - TDuration interval = TConsumptionHistory::Interval(); - std::vector<double> values1; - std::vector<double> values2; - for (int i = 0; i < 100; i++) { - values1.push_back(3); - values2.push_back(3); - } - ctx.AccountResources(client, edge, { - {subscribeResult1.GetResults(0).GetResourceId(), start, interval, std::move(values1)}, - {subscribeResult2.GetResults(0).GetResourceId(), start, interval, std::move(values2)} - }); - - if (bills.size() < 3) { - TDispatchOptions opts; - opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { - return bills.size() >= 3; - }); - ctx.Runtime->DispatchEvents(opts); - } - - UNIT_ASSERT_NO_DIFF(bills[0], TString(R"({"usage":{"start":0,"quantity":199,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - UNIT_ASSERT_NO_DIFF(bills[1], TString(R"({"usage":{"start":0,"quantity":398,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - UNIT_ASSERT_NO_DIFF(bills[2], TString(R"({"usage":{"start":0,"quantity":3,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - } - - Y_UNIT_TEST(TestQuoterAccountResourcesDeduplicateClient) { - TTestContext ctx; - ctx.Setup(); - - std::vector<TString> bills; - ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { - if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { - bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); - } - return TTestActorRuntime::EEventAction::PROCESS; - }); - - NKikimrKesus::TStreamingQuoterResource cfg; - cfg.SetResourcePath("/Root"); - cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); - cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); - cfg.MutableAccountingConfig()->SetEnabled(true); - cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); - cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); - cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); - cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); - cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); - cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); - ctx.AddQuoterResource(cfg); - - auto edge = ctx.Runtime->AllocateEdgeActor(); - auto client = ctx.Runtime->AllocateEdgeActor(); - const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult = ctx.SubscribeOnResource(client, edge, "/Root", false, 0); - - TInstant start = ctx.Runtime->GetCurrentTime(); - TDuration interval = TConsumptionHistory::Interval(); - std::vector<double> values1; - std::vector<double> values2; - for (int i = 0; i < 100; i++) { - values1.push_back(6); - values2.push_back(6); - } - ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), start, interval, std::move(values1)); - ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), start, interval, std::move(values2)); - - if (bills.size() < 3) { - TDispatchOptions opts; - opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { - return bills.size() >= 3; - }); - ctx.Runtime->DispatchEvents(opts); - } - - UNIT_ASSERT_NO_DIFF(bills[0], TString(R"({"usage":{"start":0,"quantity":199,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - UNIT_ASSERT_NO_DIFF(bills[1], TString(R"({"usage":{"start":0,"quantity":398,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - UNIT_ASSERT_NO_DIFF(bills[2], TString(R"({"usage":{"start":0,"quantity":3,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); - } - - Y_UNIT_TEST(TestQuoterAccountResourcesForgetClient) { - TTestContext ctx; - ctx.Setup(); - - std::vector<TString> bills; - ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { - if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { - bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); - } - return TTestActorRuntime::EEventAction::PROCESS; - }); - - NKikimrKesus::TStreamingQuoterResource cfg; - cfg.SetResourcePath("/Root"); - cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); - cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); - cfg.MutableAccountingConfig()->SetEnabled(true); - cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); - cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); - cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); - cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); - cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); - cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); - cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); - ctx.AddQuoterResource(cfg); - - for (int i = 0; i < 3; i++) { - auto edge = ctx.Runtime->AllocateEdgeActor(); - auto client = ctx.Runtime->AllocateEdgeActor(); - const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult = ctx.SubscribeOnResource(client, edge, "/Root", false, 0); - - TInstant begin = TInstant::Seconds(2) + i * TDuration::Seconds(6); - TDuration interval = TConsumptionHistory::Interval(); - std::vector<double> values; - for (int i = 0; i < 100; i++) { - values.push_back(6); - } - ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), begin, interval, std::move(values)); - - if (bills.size() < 3) { - TDispatchOptions opts; - opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { - return bills.size() >= 3; - }); - ctx.Runtime->DispatchEvents(opts); - } - - int start = 2 + i * 6; - int finish = start + 1; - int source_wt = start + 5; - UNIT_ASSERT_NO_DIFF(bills[0], Sprintf(R"({"usage":{"start":%d,"quantity":199,"finish":%d,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-%d-%d","cloud_id":"","source_wt":%d,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})", start, finish, start, finish, source_wt) + "\n"); - UNIT_ASSERT_NO_DIFF(bills[1], Sprintf(R"({"usage":{"start":%d,"quantity":398,"finish":%d,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-%d-%d","cloud_id":"","source_wt":%d,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})", start, finish, start, finish, source_wt) + "\n"); - UNIT_ASSERT_NO_DIFF(bills[2], Sprintf(R"({"usage":{"start":%d,"quantity":3,"finish":%d,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-%d-%d","cloud_id":"","source_wt":%d,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})", start, finish, start, finish, source_wt) + "\n"); - bills.clear(); - } - } - + Y_UNIT_TEST(TestQuoterAccountResourcesOnDemand) { + TTestContext ctx; + ctx.Setup(); + + TString billRecord; + ctx.Runtime->SetObserverFunc([&billRecord](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { + if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { + billRecord = ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson; + } + return TTestActorRuntime::EEventAction::PROCESS; + }); + + NKikimrKesus::TStreamingQuoterResource cfg; + cfg.SetResourcePath("/Root"); + cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(100.0); + cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(300.0); + cfg.MutableAccountingConfig()->SetEnabled(true); + cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); + cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); + cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetVersion("version"); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetSchema("schema"); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetCloudId("cloud"); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetFolderId("folder"); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetResourceId("resource"); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetSourceId("source"); + cfg.MutableAccountingConfig()->MutableOnDemand()->MutableTags()->insert({"key", "value"}); + ctx.AddQuoterResource(cfg); + ctx.AddQuoterResource("/Root/Res"); // With inherited settings. + + auto edge = ctx.Runtime->AllocateEdgeActor(); + auto client = ctx.Runtime->AllocateEdgeActor(); + const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult = ctx.SubscribeOnResource(client, edge, "/Root/Res", false, 0); + + TInstant start = ctx.Runtime->GetCurrentTime(); + TDuration interval = TConsumptionHistory::Interval(); + ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), start, interval, {50.0}); + + if (billRecord.empty()) { + TDispatchOptions opts; + opts.FinalEvents.emplace_back([&billRecord](IEventHandle&) -> bool { + return !billRecord.empty(); + }); + ctx.Runtime->DispatchEvents(opts); + } + + const TString expectedBillRecord = R"({"usage":{"start":0,"quantity":50,"finish":1,"unit":"request_unit","type":"delta"},"tags":{"key":"value"},"id":"Root-ondemand-0-1","cloud_id":"cloud","source_wt":5,"source_id":"source","resource_id":"resource","schema":"schema","folder_id":"folder","version":"version"})"; + + UNIT_ASSERT_NO_DIFF(billRecord, expectedBillRecord + "\n"); + } + + Y_UNIT_TEST(TestQuoterAccountResourcesBurst) { + TTestContext ctx; + ctx.Setup(); + + std::vector<TString> bills; + ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { + if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { + bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); + } + return TTestActorRuntime::EEventAction::PROCESS; + }); + + NKikimrKesus::TStreamingQuoterResource cfg; + cfg.SetResourcePath("/Root"); + cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); + cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); + cfg.MutableAccountingConfig()->SetEnabled(true); + cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); + cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); + cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); + cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); + cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); + cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); + ctx.AddQuoterResource(cfg); + ctx.AddQuoterResource("/Root/Res"); // With inherited settings. + + auto edge = ctx.Runtime->AllocateEdgeActor(); + auto client = ctx.Runtime->AllocateEdgeActor(); + const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult = ctx.SubscribeOnResource(client, edge, "/Root/Res", false, 0); + + TInstant start = ctx.Runtime->GetCurrentTime(); + TDuration interval = TConsumptionHistory::Interval(); + ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), start, interval, {600.0}); + + if (bills.size() < 3) { + TDispatchOptions opts; + opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { + return bills.size() >= 3; + }); + ctx.Runtime->DispatchEvents(opts); + } + + UNIT_ASSERT_NO_DIFF(bills[0], TString(R"({"usage":{"start":0,"quantity":100,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + UNIT_ASSERT_NO_DIFF(bills[1], TString(R"({"usage":{"start":0,"quantity":200,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + UNIT_ASSERT_NO_DIFF(bills[2], TString(R"({"usage":{"start":0,"quantity":300,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + } + + Y_UNIT_TEST(TestQuoterAccountResourcesPaced) { + TTestContext ctx; + ctx.Setup(); + + std::vector<TString> bills; + ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { + if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { + bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); + } + return TTestActorRuntime::EEventAction::PROCESS; + }); + + NKikimrKesus::TStreamingQuoterResource cfg; + cfg.SetResourcePath("/Root"); + cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); + cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); + cfg.MutableAccountingConfig()->SetEnabled(true); + cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); + cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); + cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); + cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); + cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); + cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); + ctx.AddQuoterResource(cfg); + ctx.AddQuoterResource("/Root/Res"); // With inherited settings. + + auto edge = ctx.Runtime->AllocateEdgeActor(); + auto client = ctx.Runtime->AllocateEdgeActor(); + const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult = ctx.SubscribeOnResource(client, edge, "/Root/Res", false, 0); + + TInstant start = ctx.Runtime->GetCurrentTime(); + TDuration interval = TConsumptionHistory::Interval(); + std::vector<double> values; + for (int i = 0; i < 100; i++) { + values.push_back(6); + } + ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), start, interval, std::move(values)); + + if (bills.size() < 3) { + TDispatchOptions opts; + opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { + return bills.size() >= 3; + }); + ctx.Runtime->DispatchEvents(opts); + } + + UNIT_ASSERT_NO_DIFF(bills[0], TString(R"({"usage":{"start":0,"quantity":199,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + UNIT_ASSERT_NO_DIFF(bills[1], TString(R"({"usage":{"start":0,"quantity":398,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + UNIT_ASSERT_NO_DIFF(bills[2], TString(R"({"usage":{"start":0,"quantity":3,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + } + + Y_UNIT_TEST(TestQuoterAccountResourcesAggregateClients) { + TTestContext ctx; + ctx.Setup(); + + std::vector<TString> bills; + ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { + if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { + bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); + } + return TTestActorRuntime::EEventAction::PROCESS; + }); + + NKikimrKesus::TStreamingQuoterResource cfg; + cfg.SetResourcePath("/Root"); + cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); + cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); + cfg.MutableAccountingConfig()->SetEnabled(true); + cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); + cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); + cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); + cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); + cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); + cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); + ctx.AddQuoterResource(cfg); + + auto edge = ctx.Runtime->AllocateEdgeActor(); + auto client1 = ctx.Runtime->AllocateEdgeActor(); + auto client2 = ctx.Runtime->AllocateEdgeActor(); + const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult1 = ctx.SubscribeOnResource(client1, edge, "/Root", false, 0); + const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult2 = ctx.SubscribeOnResource(client2, edge, "/Root", false, 0); + + TInstant start = ctx.Runtime->GetCurrentTime(); + TDuration interval = TConsumptionHistory::Interval(); + std::vector<double> values1; + std::vector<double> values2; + for (int i = 0; i < 100; i++) { + values1.push_back(3); + values2.push_back(3); + } + ctx.AccountResources(client1, edge, subscribeResult1.GetResults(0).GetResourceId(), start, interval, std::move(values1)); + ctx.AccountResources(client2, edge, subscribeResult2.GetResults(0).GetResourceId(), start, interval, std::move(values2)); + + if (bills.size() < 3) { + TDispatchOptions opts; + opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { + return bills.size() >= 3; + }); + ctx.Runtime->DispatchEvents(opts); + } + + UNIT_ASSERT_NO_DIFF(bills[0], TString(R"({"usage":{"start":0,"quantity":199,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + UNIT_ASSERT_NO_DIFF(bills[1], TString(R"({"usage":{"start":0,"quantity":398,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + UNIT_ASSERT_NO_DIFF(bills[2], TString(R"({"usage":{"start":0,"quantity":3,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + } + + Y_UNIT_TEST(TestQuoterAccountResourcesAggregateResources) { + TTestContext ctx; + ctx.Setup(); + + std::vector<TString> bills; + ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { + if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { + bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); + } + return TTestActorRuntime::EEventAction::PROCESS; + }); + + NKikimrKesus::TStreamingQuoterResource cfg; + cfg.SetResourcePath("/Root"); + cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); + cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); + cfg.MutableAccountingConfig()->SetEnabled(true); + cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); + cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); + cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); + cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); + cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); + cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); + ctx.AddQuoterResource(cfg); + ctx.AddQuoterResource("/Root/Res1"); // With inherited settings. + ctx.AddQuoterResource("/Root/Res2"); // With inherited settings. + + auto edge = ctx.Runtime->AllocateEdgeActor(); + auto client = ctx.Runtime->AllocateEdgeActor(); + const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult1 = ctx.SubscribeOnResource(client, edge, "/Root/Res1", false, 0); + const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult2 = ctx.SubscribeOnResource(client, edge, "/Root/Res2", false, 0); + + TInstant start = ctx.Runtime->GetCurrentTime(); + TDuration interval = TConsumptionHistory::Interval(); + std::vector<double> values1; + std::vector<double> values2; + for (int i = 0; i < 100; i++) { + values1.push_back(3); + values2.push_back(3); + } + ctx.AccountResources(client, edge, { + {subscribeResult1.GetResults(0).GetResourceId(), start, interval, std::move(values1)}, + {subscribeResult2.GetResults(0).GetResourceId(), start, interval, std::move(values2)} + }); + + if (bills.size() < 3) { + TDispatchOptions opts; + opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { + return bills.size() >= 3; + }); + ctx.Runtime->DispatchEvents(opts); + } + + UNIT_ASSERT_NO_DIFF(bills[0], TString(R"({"usage":{"start":0,"quantity":199,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + UNIT_ASSERT_NO_DIFF(bills[1], TString(R"({"usage":{"start":0,"quantity":398,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + UNIT_ASSERT_NO_DIFF(bills[2], TString(R"({"usage":{"start":0,"quantity":3,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + } + + Y_UNIT_TEST(TestQuoterAccountResourcesDeduplicateClient) { + TTestContext ctx; + ctx.Setup(); + + std::vector<TString> bills; + ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { + if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { + bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); + } + return TTestActorRuntime::EEventAction::PROCESS; + }); + + NKikimrKesus::TStreamingQuoterResource cfg; + cfg.SetResourcePath("/Root"); + cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); + cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); + cfg.MutableAccountingConfig()->SetEnabled(true); + cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); + cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); + cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); + cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); + cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); + cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); + ctx.AddQuoterResource(cfg); + + auto edge = ctx.Runtime->AllocateEdgeActor(); + auto client = ctx.Runtime->AllocateEdgeActor(); + const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult = ctx.SubscribeOnResource(client, edge, "/Root", false, 0); + + TInstant start = ctx.Runtime->GetCurrentTime(); + TDuration interval = TConsumptionHistory::Interval(); + std::vector<double> values1; + std::vector<double> values2; + for (int i = 0; i < 100; i++) { + values1.push_back(6); + values2.push_back(6); + } + ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), start, interval, std::move(values1)); + ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), start, interval, std::move(values2)); + + if (bills.size() < 3) { + TDispatchOptions opts; + opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { + return bills.size() >= 3; + }); + ctx.Runtime->DispatchEvents(opts); + } + + UNIT_ASSERT_NO_DIFF(bills[0], TString(R"({"usage":{"start":0,"quantity":199,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + UNIT_ASSERT_NO_DIFF(bills[1], TString(R"({"usage":{"start":0,"quantity":398,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + UNIT_ASSERT_NO_DIFF(bills[2], TString(R"({"usage":{"start":0,"quantity":3,"finish":1,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-0-1","cloud_id":"","source_wt":5,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})") + "\n"); + } + + Y_UNIT_TEST(TestQuoterAccountResourcesForgetClient) { + TTestContext ctx; + ctx.Setup(); + + std::vector<TString> bills; + ctx.Runtime->SetObserverFunc([&bills](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& ev) { + if (ev->GetTypeRewrite() == NMetering::TEvMetering::EvWriteMeteringJson) { + bills.push_back(ev->Get<NMetering::TEvMetering::TEvWriteMeteringJson>()->MeteringJson); + } + return TTestActorRuntime::EEventAction::PROCESS; + }); + + NKikimrKesus::TStreamingQuoterResource cfg; + cfg.SetResourcePath("/Root"); + cfg.MutableHierarhicalDRRResourceConfig()->SetMaxUnitsPerSecond(300.0); + cfg.MutableHierarhicalDRRResourceConfig()->SetPrefetchCoefficient(1.0); + cfg.MutableAccountingConfig()->SetEnabled(true); + cfg.MutableAccountingConfig()->SetReportPeriodMs(1000); + cfg.MutableAccountingConfig()->SetAccountPeriodMs(1000); + cfg.MutableAccountingConfig()->SetCollectPeriodSec(2); + cfg.MutableAccountingConfig()->SetProvisionedUnitsPerSecond(100.0); + cfg.MutableAccountingConfig()->SetProvisionedCoefficient(1.0); + cfg.MutableAccountingConfig()->SetOvershootCoefficient(1.0); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableProvisioned()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOnDemand()->SetBillingPeriodSec(2); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetEnabled(true); + cfg.MutableAccountingConfig()->MutableOvershoot()->SetBillingPeriodSec(2); + ctx.AddQuoterResource(cfg); + + for (int i = 0; i < 3; i++) { + auto edge = ctx.Runtime->AllocateEdgeActor(); + auto client = ctx.Runtime->AllocateEdgeActor(); + const NKikimrKesus::TEvSubscribeOnResourcesResult subscribeResult = ctx.SubscribeOnResource(client, edge, "/Root", false, 0); + + TInstant begin = TInstant::Seconds(2) + i * TDuration::Seconds(6); + TDuration interval = TConsumptionHistory::Interval(); + std::vector<double> values; + for (int i = 0; i < 100; i++) { + values.push_back(6); + } + ctx.AccountResources(client, edge, subscribeResult.GetResults(0).GetResourceId(), begin, interval, std::move(values)); + + if (bills.size() < 3) { + TDispatchOptions opts; + opts.FinalEvents.emplace_back([&bills](IEventHandle&) -> bool { + return bills.size() >= 3; + }); + ctx.Runtime->DispatchEvents(opts); + } + + int start = 2 + i * 6; + int finish = start + 1; + int source_wt = start + 5; + UNIT_ASSERT_NO_DIFF(bills[0], Sprintf(R"({"usage":{"start":%d,"quantity":199,"finish":%d,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-provisioned-%d-%d","cloud_id":"","source_wt":%d,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})", start, finish, start, finish, source_wt) + "\n"); + UNIT_ASSERT_NO_DIFF(bills[1], Sprintf(R"({"usage":{"start":%d,"quantity":398,"finish":%d,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-ondemand-%d-%d","cloud_id":"","source_wt":%d,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})", start, finish, start, finish, source_wt) + "\n"); + UNIT_ASSERT_NO_DIFF(bills[2], Sprintf(R"({"usage":{"start":%d,"quantity":3,"finish":%d,"unit":"request_unit","type":"delta"},"tags":{},"id":"Root-overshoot-%d-%d","cloud_id":"","source_wt":%d,"source_id":"","resource_id":"","schema":"","folder_id":"","version":""})", start, finish, start, finish, source_wt) + "\n"); + bills.clear(); + } + } + Y_UNIT_TEST(TestPassesUpdatedPropsToSession) { TTestContext ctx; ctx.Setup(); diff --git a/ydb/core/kesus/tablet/tx_init.cpp b/ydb/core/kesus/tablet/tx_init.cpp index 1f3f96ff9f..2f958bcbaf 100644 --- a/ydb/core/kesus/tablet/tx_init.cpp +++ b/ydb/core/kesus/tablet/tx_init.cpp @@ -217,7 +217,7 @@ struct TKesusTablet::TTxInit : public TTxBase { } { - Self->QuoterResources.SetupBilling(ctx.SelfID, MakeMeteringSink()); + Self->QuoterResources.SetupBilling(ctx.SelfID, MakeMeteringSink()); auto quoterResourcesRowset = db.Table<Schema::QuoterResources>().Range().Select(); if (!quoterResourcesRowset.IsReady()) return false; diff --git a/ydb/core/kesus/tablet/ut_helpers.cpp b/ydb/core/kesus/tablet/ut_helpers.cpp index f559800a76..32ca0e65dc 100644 --- a/ydb/core/kesus/tablet/ut_helpers.cpp +++ b/ydb/core/kesus/tablet/ut_helpers.cpp @@ -1,7 +1,7 @@ #include "ut_helpers.h" #include <ydb/core/metering/metering.h> - + #include <library/cpp/actors/core/event_pb.h> #include <algorithm> @@ -9,62 +9,62 @@ namespace NKikimr { namespace NKesus { -// Write metering events into memory only -class TFakeMetering : public TActor<TFakeMetering> { - std::vector<TString> Jsons; - -public: - explicit TFakeMetering() - : TActor<TFakeMetering>(&TFakeMetering::StateWork) - {} - -private: - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - HFunc(TEvents::TEvPoisonPill, HandlePoisonPill); - HFunc(NMetering::TEvMetering::TEvWriteMeteringJson, HandleWriteMeteringJson); - default: - HandleUnexpectedEvent(ev, ctx); - break; - } - } - - void HandlePoisonPill(const TEvents::TEvPoisonPill::TPtr& ev, const TActorContext& ctx) { - Y_UNUSED(ev); - Die(ctx); - } - - void HandleWriteMeteringJson( - const NMetering::TEvMetering::TEvWriteMeteringJson::TPtr& ev, - const TActorContext& ctx) - { - Y_UNUSED(ctx); - - LOG_DEBUG_S(ctx, NKikimrServices::KESUS_PROXY, - "tests -- TFakeMetering got TEvMetering::TEvWriteMeteringJson"); - - const auto* msg = ev->Get(); - - Jsons.push_back(msg->MeteringJson); - } - - void HandleUnexpectedEvent(STFUNC_SIG) - { - Y_UNUSED(ctx); - - LOG_DEBUG_S(ctx, NKikimrServices::KESUS_PROXY, - "TFakeMetering:" - << " unhandled event type: " << ev->GetTypeRewrite() - << " event: " << (ev->HasEvent() ? ev->GetBase()->ToString().data() : "serialized?")); - } -}; - -NActors::TActorId CreateFakeMetering(NActors::TTestActorRuntime &runtime) { - NActors::TActorId actorId = runtime.Register(new TFakeMetering()); - runtime.RegisterService(NMetering::MakeMeteringServiceID(), actorId); - return NMetering::MakeMeteringServiceID(); -} - +// Write metering events into memory only +class TFakeMetering : public TActor<TFakeMetering> { + std::vector<TString> Jsons; + +public: + explicit TFakeMetering() + : TActor<TFakeMetering>(&TFakeMetering::StateWork) + {} + +private: + STFUNC(StateWork) { + switch (ev->GetTypeRewrite()) { + HFunc(TEvents::TEvPoisonPill, HandlePoisonPill); + HFunc(NMetering::TEvMetering::TEvWriteMeteringJson, HandleWriteMeteringJson); + default: + HandleUnexpectedEvent(ev, ctx); + break; + } + } + + void HandlePoisonPill(const TEvents::TEvPoisonPill::TPtr& ev, const TActorContext& ctx) { + Y_UNUSED(ev); + Die(ctx); + } + + void HandleWriteMeteringJson( + const NMetering::TEvMetering::TEvWriteMeteringJson::TPtr& ev, + const TActorContext& ctx) + { + Y_UNUSED(ctx); + + LOG_DEBUG_S(ctx, NKikimrServices::KESUS_PROXY, + "tests -- TFakeMetering got TEvMetering::TEvWriteMeteringJson"); + + const auto* msg = ev->Get(); + + Jsons.push_back(msg->MeteringJson); + } + + void HandleUnexpectedEvent(STFUNC_SIG) + { + Y_UNUSED(ctx); + + LOG_DEBUG_S(ctx, NKikimrServices::KESUS_PROXY, + "TFakeMetering:" + << " unhandled event type: " << ev->GetTypeRewrite() + << " event: " << (ev->HasEvent() ? ev->GetBase()->ToString().data() : "serialized?")); + } +}; + +NActors::TActorId CreateFakeMetering(NActors::TTestActorRuntime &runtime) { + NActors::TActorId actorId = runtime.Register(new TFakeMetering()); + runtime.RegisterService(NMetering::MakeMeteringServiceID(), actorId); + return NMetering::MakeMeteringServiceID(); +} + TTestContext::TTestContext() : TabletType(TTabletTypes::KESUS) , TabletId(MakeTabletID(0, 0, 1)) @@ -86,8 +86,8 @@ void TTestContext::Setup(ui32 nodeCount, bool useRealThreads) { options.FinalEvents.emplace_back(TEvTablet::EvBoot); Runtime->DispatchEvents(options); } - - CreateFakeMetering(*Runtime); + + CreateFakeMetering(*Runtime); } void TTestContext::Finalize() { @@ -854,29 +854,29 @@ void TTestContext::UpdateConsumptionState(const TActorId& client, const TActorId UpdateConsumptionState(client, edge, {TResourceConsumingInfo(id, consume, amount, status)}); } -void TTestContext::AccountResources(const TActorId& client, const TActorId& edge, const std::vector<TResourceAccountInfo>& info) { - const ui64 cookie = RandomNumber<ui64>(); - auto req = MakeHolder<TEvKesus::TEvAccountResources>(); - ActorIdToProto(client, req->Record.MutableActorID()); - req->Record.MutableResourcesInfo()->Reserve(info.size()); - for (const TResourceAccountInfo& res : info) { - auto* reqRes = req->Record.AddResourcesInfo(); - reqRes->SetResourceId(res.Id); - reqRes->SetStartUs(res.Start.MicroSeconds()); - reqRes->SetIntervalUs(res.Interval.MicroSeconds()); - for (double value : res.Amount) { - reqRes->AddAmount(value); - } - } - - SendFromEdge(edge, std::move(req), cookie); - ExpectEdgeEvent<TEvKesus::TEvAccountResourcesAck>(edge, cookie); -} - -void TTestContext::AccountResources(const TActorId& client, const TActorId& edge, ui64 id, TInstant start, TDuration interval, std::vector<double>&& amount) { - AccountResources(client, edge, {TResourceAccountInfo(id, start, interval, std::move(amount))}); -} - +void TTestContext::AccountResources(const TActorId& client, const TActorId& edge, const std::vector<TResourceAccountInfo>& info) { + const ui64 cookie = RandomNumber<ui64>(); + auto req = MakeHolder<TEvKesus::TEvAccountResources>(); + ActorIdToProto(client, req->Record.MutableActorID()); + req->Record.MutableResourcesInfo()->Reserve(info.size()); + for (const TResourceAccountInfo& res : info) { + auto* reqRes = req->Record.AddResourcesInfo(); + reqRes->SetResourceId(res.Id); + reqRes->SetStartUs(res.Start.MicroSeconds()); + reqRes->SetIntervalUs(res.Interval.MicroSeconds()); + for (double value : res.Amount) { + reqRes->AddAmount(value); + } + } + + SendFromEdge(edge, std::move(req), cookie); + ExpectEdgeEvent<TEvKesus::TEvAccountResourcesAck>(edge, cookie); +} + +void TTestContext::AccountResources(const TActorId& client, const TActorId& edge, ui64 id, TInstant start, TDuration interval, std::vector<double>&& amount) { + AccountResources(client, edge, {TResourceAccountInfo(id, start, interval, std::move(amount))}); +} + NKikimrKesus::TEvGetQuoterResourceCountersResult TTestContext::GetQuoterResourceCounters() { const ui64 cookie = RandomNumber<ui64>(); const auto edge = Runtime->AllocateEdgeActor(); diff --git a/ydb/core/kesus/tablet/ut_helpers.h b/ydb/core/kesus/tablet/ut_helpers.h index 8f487a3033..ca1cbfbf71 100644 --- a/ydb/core/kesus/tablet/ut_helpers.h +++ b/ydb/core/kesus/tablet/ut_helpers.h @@ -291,29 +291,29 @@ struct TTestContext { Ydb::StatusIds::StatusCode ExpectedStatus; }; - struct TResourceAccountInfo { - ui64 Id = 0; - TInstant Start; - TDuration Interval; - std::vector<double> Amount; - - TResourceAccountInfo(ui64 id, TInstant start, TDuration interval, std::vector<double>&& amount) - : Id(id) - , Start(start) - , Interval(interval) - , Amount(std::move(amount)) - {} - }; - + struct TResourceAccountInfo { + ui64 Id = 0; + TInstant Start; + TDuration Interval; + std::vector<double> Amount; + + TResourceAccountInfo(ui64 id, TInstant start, TDuration interval, std::vector<double>&& amount) + : Id(id) + , Start(start) + , Interval(interval) + , Amount(std::move(amount)) + {} + }; + NKikimrKesus::TEvSubscribeOnResourcesResult SubscribeOnResources(const TActorId& client, const TActorId& edge, const std::vector<TResourceConsumingInfo>& info); NKikimrKesus::TEvSubscribeOnResourcesResult SubscribeOnResource(const TActorId& client, const TActorId& edge, const TString& path, bool startConsuming, double amount = 0.0, Ydb::StatusIds::StatusCode status = Ydb::StatusIds::SUCCESS); void UpdateConsumptionState(const TActorId& client, const TActorId& edge, const std::vector<TResourceConsumingInfo>& info); void UpdateConsumptionState(const TActorId& client, const TActorId& edge, ui64 id, bool consume, double amount = 0.0, Ydb::StatusIds::StatusCode status = Ydb::StatusIds::SUCCESS); - void AccountResources(const TActorId& client, const TActorId& edge, const std::vector<TResourceAccountInfo>& info); - void AccountResources(const TActorId& client, const TActorId& edge, ui64 id, TInstant start, TDuration interval, std::vector<double>&& amount); - + void AccountResources(const TActorId& client, const TActorId& edge, const std::vector<TResourceAccountInfo>& info); + void AccountResources(const TActorId& client, const TActorId& edge, ui64 id, TInstant start, TDuration interval, std::vector<double>&& amount); + NKikimrKesus::TEvGetQuoterResourceCountersResult GetQuoterResourceCounters(); }; diff --git a/ydb/core/kesus/tablet/ya.make b/ydb/core/kesus/tablet/ya.make index 02c34c7fce..d80425dfff 100644 --- a/ydb/core/kesus/tablet/ya.make +++ b/ydb/core/kesus/tablet/ya.make @@ -10,7 +10,7 @@ SRCS( probes.cpp quoter_resource_tree.cpp quoter_runtime.cpp - rate_accounting.cpp + rate_accounting.cpp schema.cpp tablet_db.cpp tablet_html.cpp diff --git a/ydb/core/keyvalue/keyvalue_flat_impl.h b/ydb/core/keyvalue/keyvalue_flat_impl.h index 292f2feff9..af1702921c 100644 --- a/ydb/core/keyvalue/keyvalue_flat_impl.h +++ b/ydb/core/keyvalue/keyvalue_flat_impl.h @@ -26,9 +26,9 @@ #include <ydb/core/protos/counters_keyvalue.pb.h> #include <util/string/escape.h> -// Uncomment the following macro to enable consistency check before every transactions in TTxRequest -//#define KIKIMR_KEYVALUE_CONSISTENCY_CHECKS - +// Uncomment the following macro to enable consistency check before every transactions in TTxRequest +//#define KIKIMR_KEYVALUE_CONSISTENCY_CHECKS + namespace NKikimr { namespace NKeyValue { @@ -76,29 +76,29 @@ protected: return true; } Self.State.UpdateResourceMetrics(ctx); - } + } Self.State.InitExecute(Self.TabletID(), KeyValueActorId, txc.Generation, db, ctx, Self.Info()); LOG_DEBUG_S(ctx, NKikimrServices::KEYVALUE, "KeyValue# " << txc.Tablet << " TTxInit flat Execute returns true"); - return true; - } + return true; + } static bool LoadStateFromDB(TKeyValueState& state, NTable::TDatabase& db) { state.Clear(); - // Just walk through the DB and read all the keys and values + // Just walk through the DB and read all the keys and values const std::array<ui32, 2> tags {{ KEY_TAG, VALUE_TAG }}; auto mode = NTable::ELookup::GreaterOrEqualThan; auto iter = db.Iterate(TABLE_ID, {}, tags, mode); if (!db.Precharge(TABLE_ID, {}, {}, tags, 0, -1, -1)) - return false; + return false; while (iter->Next(NTable::ENext::Data) == NTable::EReady::Data) { const auto &row = iter->Row(); - + TString key(row.Get(0).AsBuf()); TString value(row.Get(1).AsBuf()); - + state.Load(key, value); if (state.GetIsDamaged()) { return true; @@ -130,7 +130,7 @@ protected: bool Execute(NTabletFlatExecutor::TTransactionContext &txc, const TActorContext &ctx) override { LOG_DEBUG_S(ctx, NKikimrServices::KEYVALUE, "KeyValue# " << txc.Tablet << " TTxRequest Execute"); if (!CheckConsistency(txc)) { - return false; + return false; } if (Self->State.GetIsDamaged()) { return true; @@ -147,22 +147,22 @@ protected: LOG_DEBUG_S(ctx, NKikimrServices::KEYVALUE, "KeyValue# " << Self->TabletID() << " TTxRequest Complete"); Self->State.RequestComplete(Intermediate, ctx, Self->Info()); } - - bool CheckConsistency(NTabletFlatExecutor::TTransactionContext &txc) { -#ifdef KIKIMR_KEYVALUE_CONSISTENCY_CHECKS - TKeyValueState state; + + bool CheckConsistency(NTabletFlatExecutor::TTransactionContext &txc) { +#ifdef KIKIMR_KEYVALUE_CONSISTENCY_CHECKS + TKeyValueState state; if (!TTxInit::LoadStateFromDB(state, txc.DB)) { - return false; - } + return false; + } Y_VERIFY(!state.IsDamaged()); - state.VerifyEqualIndex(Self->State); - txc.DB.NoMoreReadsForTx(); - return true; -#else + state.VerifyEqualIndex(Self->State); + txc.DB.NoMoreReadsForTx(); + return true; +#else Y_UNUSED(txc); - return true; -#endif - } + return true; +#endif + } }; struct TTxMonitoring : public NTabletFlatExecutor::ITransaction { diff --git a/ydb/core/keyvalue/keyvalue_state.cpp b/ydb/core/keyvalue/keyvalue_state.cpp index 6b31c463f8..2b3472d4c3 100644 --- a/ydb/core/keyvalue/keyvalue_state.cpp +++ b/ydb/core/keyvalue/keyvalue_state.cpp @@ -3182,76 +3182,76 @@ bool TKeyValueState::ConvertRange(const NKikimrClient::TKeyValueRequest::TKeyRan } TString TKeyValueState::Dump() const { - TStringStream ss; - ss << "=== INDEX ===\n"; - for (auto& x : Index) { + TStringStream ss; + ss << "=== INDEX ===\n"; + for (auto& x : Index) { const TString& k = x.first; - const TIndexRecord& v = x.second; - ss << k << "=== ctime:" << v.CreationUnixTime; - for (const TIndexRecord::TChainItem& y : v.Chain) { - ss << " -> " << y.LogoBlobId << ":" << y.Offset; - } - ss << "\n"; - } - ss << "=== END ===\n"; - return ss.Str(); -} - -void TKeyValueState::VerifyEqualIndex(const TKeyValueState& state) const { - auto i2 = state.Index.cbegin(), e2 = state.Index.cend(); - int i = 0; - for (auto i1 = Index.cbegin(), e1 = Index.cend(); i1 != e1; ++i, ++i1, ++i2) { + const TIndexRecord& v = x.second; + ss << k << "=== ctime:" << v.CreationUnixTime; + for (const TIndexRecord::TChainItem& y : v.Chain) { + ss << " -> " << y.LogoBlobId << ":" << y.Offset; + } + ss << "\n"; + } + ss << "=== END ===\n"; + return ss.Str(); +} + +void TKeyValueState::VerifyEqualIndex(const TKeyValueState& state) const { + auto i2 = state.Index.cbegin(), e2 = state.Index.cend(); + int i = 0; + for (auto i1 = Index.cbegin(), e1 = Index.cend(); i1 != e1; ++i, ++i1, ++i2) { Y_VERIFY(i2 != e2, "index length differs. Dump:\n%s\n%s\n", Dump().data(), state.Dump().data()); const TString& k1 = i1->first; const TString& k2 = i2->first; Y_VERIFY(k1 == k2, "index key #%d differs. Dump:\n%s\n%s\n", i, Dump().data(), state.Dump().data()); - const TIndexRecord& v1 = i1->second; - const TIndexRecord& v2 = i2->second; + const TIndexRecord& v1 = i1->second; + const TIndexRecord& v2 = i2->second; Y_VERIFY(v1 == v2, "index value #%d differs. Dump:\n%s\n%s\n", i, Dump().data(), state.Dump().data()); - } + } Y_VERIFY(i2 == e2, "index length differs. Dump:\n%s\n%s\n", Dump().data(), state.Dump().data()); -} - +} + void TKeyValueState::RenderHTMLPage(IOutputStream &out) const { - HTML(out) { - H2() {out << "KeyValue Tablet";} - UL_CLASS("nav nav-tabs") { - LI_CLASS("active") { + HTML(out) { + H2() {out << "KeyValue Tablet";} + UL_CLASS("nav nav-tabs") { + LI_CLASS("active") { out << "<a href=\"#database\" data-toggle=\"tab\">Database</a>"; - } - LI() { + } + LI() { out << "<a href=\"#refcounts\" data-toggle=\"tab\">RefCounts</a>"; - } - LI() { + } + LI() { out << "<a href=\"#trash\" data-toggle=\"tab\">Trash</a>"; - } + } LI() { out << "<a href=\"#channelstat\" data-toggle=\"tab\">Channel Stat</a>"; } - } - DIV_CLASS("tab-content") { - DIV_CLASS_ID("tab-pane fade in active", "database") { - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {out << "Idx";} - TABLEH() {out << "Key";} - TABLEH() {out << "Value Size";} - TABLEH() {out << "Creation UnixTime";} - TABLEH() {out << "Storage Channel";} - TABLEH() {out << "LogoBlobIds";} - } - } - TABLEBODY() { + } + DIV_CLASS("tab-content") { + DIV_CLASS_ID("tab-pane fade in active", "database") { + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {out << "Idx";} + TABLEH() {out << "Key";} + TABLEH() {out << "Value Size";} + TABLEH() {out << "Creation UnixTime";} + TABLEH() {out << "Storage Channel";} + TABLEH() {out << "LogoBlobIds";} + } + } + TABLEBODY() { ui64 idx = 1; for (auto it = Index.begin(); it != Index.end(); ++it) { - TABLER() { - TABLED() {out << idx;} + TABLER() { + TABLED() {out << idx;} ++idx; TABLED() {out << EscapeC(it->first);} - TABLED() {out << it->second.GetFullValueSize();} - TABLED() {out << it->second.CreationUnixTime;} - TABLED() { + TABLED() {out << it->second.GetFullValueSize();} + TABLED() {out << it->second.CreationUnixTime;} + TABLED() { NKikimrClient::TKeyValueRequest::EStorageChannel storageChannel = NKikimrClient::TKeyValueRequest::MAIN; if (it->second.Chain.size()) { @@ -3266,9 +3266,9 @@ void TKeyValueState::RenderHTMLPage(IOutputStream &out) const { } out << NKikimrClient::TKeyValueRequest::EStorageChannel_Name( storageChannel); - } + } - TABLED() { + TABLED() { for (ui32 i = 0; i < it->second.Chain.size(); ++i) { if (i > 0) { out << "<br/>"; @@ -3279,54 +3279,54 @@ void TKeyValueState::RenderHTMLPage(IOutputStream &out) const { out << it->second.Chain[i].LogoBlobId.ToString(); } } - } - } - } - } - } - } - DIV_CLASS_ID("tab-pane fade", "refcounts") { - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {out << "Idx";} - TABLEH() {out << "LogoBlobId";} - TABLEH() {out << "RefCount";} + } + } } - } - TABLEBODY() { + } + } + } + DIV_CLASS_ID("tab-pane fade", "refcounts") { + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {out << "Idx";} + TABLEH() {out << "LogoBlobId";} + TABLEH() {out << "RefCount";} + } + } + TABLEBODY() { ui32 idx = 1; for (const auto& kv : RefCounts) { - TABLER() { - TABLED() {out << idx;} - TABLED() {out << kv.first.ToString();} - TABLED() {out << kv.second;} - } + TABLER() { + TABLED() {out << idx;} + TABLED() {out << kv.first.ToString();} + TABLED() {out << kv.second;} + } ++idx; } - } - } - } - DIV_CLASS_ID("tab-pane fade", "trash") { - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {out << "Idx";} - TABLEH() {out << "LogoBlobId";} - } - } - TABLEBODY() { + } + } + } + DIV_CLASS_ID("tab-pane fade", "trash") { + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {out << "Idx";} + TABLEH() {out << "LogoBlobId";} + } + } + TABLEBODY() { ui64 idx = 1; for (auto it = Trash.begin(); it != Trash.end(); ++it) { - TABLER() { - TABLED() {out << idx;} + TABLER() { + TABLED() {out << idx;} ++idx; - TABLED() {out << *it;} - } + TABLED() {out << *it;} + } } - } - } - } + } + } + } DIV_CLASS_ID("tab-pane fade", "channelstat") { TABLE_SORTABLE_CLASS("table") { TABLEHEAD() { @@ -3362,10 +3362,10 @@ void TKeyValueState::RenderHTMLPage(IOutputStream &out) const { } } - } - } + } + } } - + void TKeyValueState::MonChannelStat(NJson::TJsonValue& out) const { for (size_t i = 0; i < ChannelDataUsage.size(); ++i) { if (UsedChannels[i]) { diff --git a/ydb/core/keyvalue/keyvalue_state.h b/ydb/core/keyvalue/keyvalue_state.h index f57a69d35d..dd09dd3728 100644 --- a/ydb/core/keyvalue/keyvalue_state.h +++ b/ydb/core/keyvalue/keyvalue_state.h @@ -712,9 +712,9 @@ public: return res; } -public: // For testing +public: // For testing TString Dump() const; - void VerifyEqualIndex(const TKeyValueState& state) const; + void VerifyEqualIndex(const TKeyValueState& state) const; }; } // NKeyValue diff --git a/ydb/core/kqp/kqp_ic_gateway.cpp b/ydb/core/kqp/kqp_ic_gateway.cpp index 47489a9bd5..47c1318032 100644 --- a/ydb/core/kqp/kqp_ic_gateway.cpp +++ b/ydb/core/kqp/kqp_ic_gateway.cpp @@ -1219,12 +1219,12 @@ public: if (!CheckCluster(cluster)) { return InvalidCluster<TGenericResult>(cluster); } - - // FIXME: should be defined in grpc_services/rpc_calls.h, but cause cyclic dependency - using namespace NGRpcService; - using TEvAlterTableRequest = TGRpcRequestValidationWrapper<TRpcServices::EvAlterTable, Ydb::Table::AlterTableRequest, Ydb::Table::AlterTableResponse, true, TRateLimiterMode::Rps>; - - return SendLocalRpcRequestNoResult<TEvAlterTableRequest>(std::move(req), Database, GetTokenCompat()); + + // FIXME: should be defined in grpc_services/rpc_calls.h, but cause cyclic dependency + using namespace NGRpcService; + using TEvAlterTableRequest = TGRpcRequestValidationWrapper<TRpcServices::EvAlterTable, Ydb::Table::AlterTableRequest, Ydb::Table::AlterTableResponse, true, TRateLimiterMode::Rps>; + + return SendLocalRpcRequestNoResult<TEvAlterTableRequest>(std::move(req), Database, GetTokenCompat()); } catch (yexception& e) { return MakeFuture(ResultFromException<TGenericResult>(e)); @@ -1273,12 +1273,12 @@ public: Ydb::Table::DropTableRequest dropTable; dropTable.set_path(table); - - // FIXME: should be defined in grpc_services/rpc_calls.h, but cause cyclic dependency - using namespace NGRpcService; - using TEvDropTableRequest = TGRpcRequestWrapper<TRpcServices::EvDropTable, Ydb::Table::DropTableRequest, Ydb::Table::DropTableResponse, true, TRateLimiterMode::Rps>; - - return SendLocalRpcRequestNoResult<TEvDropTableRequest>(std::move(dropTable), Database, GetTokenCompat()); + + // FIXME: should be defined in grpc_services/rpc_calls.h, but cause cyclic dependency + using namespace NGRpcService; + using TEvDropTableRequest = TGRpcRequestWrapper<TRpcServices::EvDropTable, Ydb::Table::DropTableRequest, Ydb::Table::DropTableResponse, true, TRateLimiterMode::Rps>; + + return SendLocalRpcRequestNoResult<TEvDropTableRequest>(std::move(dropTable), Database, GetTokenCompat()); } catch (yexception& e) { return MakeFuture(ResultFromException<TGenericResult>(e)); diff --git a/ydb/core/metering/bill_record.cpp b/ydb/core/metering/bill_record.cpp index 04776d5ea0..eb1a4cd109 100644 --- a/ydb/core/metering/bill_record.cpp +++ b/ydb/core/metering/bill_record.cpp @@ -1,4 +1,4 @@ -#include "bill_record.h" +#include "bill_record.h" #include <library/cpp/json/json_writer.h> @@ -59,4 +59,4 @@ TBillRecord::TUsage TBillRecord::RequestUnits(ui64 quantity, TInstant now) { return RequestUnits(quantity, now, now); } -} // NKikimr +} // NKikimr diff --git a/ydb/core/metering/bill_record.h b/ydb/core/metering/bill_record.h index 2959f7f29b..1144c74c18 100644 --- a/ydb/core/metering/bill_record.h +++ b/ydb/core/metering/bill_record.h @@ -65,6 +65,6 @@ struct TBillRecord { #undef BILL_RECORD_FIELD_DEFAULT #undef BILL_RECORD_FIELD #undef BILL_RECORD_FIELD_SETTER -}; +}; -} // NKikimr +} // NKikimr diff --git a/ydb/core/metering/time_grid.h b/ydb/core/metering/time_grid.h index ce1630d02d..0c4bedd0d4 100644 --- a/ydb/core/metering/time_grid.h +++ b/ydb/core/metering/time_grid.h @@ -4,7 +4,7 @@ namespace NKikimr { - // Time grid taking into account the features of billing slots + // Time grid taking into account the features of billing slots struct TTimeGrid { struct TSlot { TInstant Start; @@ -16,14 +16,14 @@ namespace NKikimr { {} }; - TDuration Period; + TDuration Period; TTimeGrid(TDuration period) : Period(period) { Y_VERIFY(Period >= TDuration::Seconds(1)); - Y_VERIFY(Period <= TDuration::Hours(1)); - Y_VERIFY(TDuration::Hours(1).MicroSeconds() % Period.MicroSeconds() == 0); + Y_VERIFY(Period <= TDuration::Hours(1)); + Y_VERIFY(TDuration::Hours(1).MicroSeconds() % Period.MicroSeconds() == 0); } const TSlot Get(TInstant now) const { @@ -45,4 +45,4 @@ namespace NKikimr { } }; -} // namespace NKikimr +} // namespace NKikimr diff --git a/ydb/core/metering/time_grid_ut.cpp b/ydb/core/metering/time_grid_ut.cpp index 756a934e09..9d16067a8e 100644 --- a/ydb/core/metering/time_grid_ut.cpp +++ b/ydb/core/metering/time_grid_ut.cpp @@ -1,57 +1,57 @@ -#include <library/cpp/testing/unittest/registar.h> -#include "time_grid.h" - -namespace NKikimr { - -Y_UNIT_TEST_SUITE(TTimeGridTest) { - Y_UNIT_TEST(TimeGrid) { - { - TTimeGrid grid(TDuration::Seconds(5)); - - for (ui32 shift = 0; shift < 5; ++shift) { - TInstant curTime = TInstant::Hours(100) + TDuration::Seconds(shift); - auto slot = grid.Get(curTime); - - UNIT_ASSERT_VALUES_EQUAL(slot.Start, TInstant::Hours(100)); - UNIT_ASSERT_VALUES_EQUAL(slot.End, TInstant::Hours(100) + TDuration::Seconds(4)); - - UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).Start, TInstant::Hours(100) + TDuration::Seconds(5)); - UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).End, TInstant::Hours(100) + TDuration::Seconds(9)); - - UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).Start, TInstant::Hours(100) - TDuration::Seconds(5)); - UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).End, TInstant::Hours(100) - TDuration::Seconds(1)); - } - - for (ui32 shift = 5; shift < 10; ++shift) { - TInstant curTime = TInstant::Hours(100) + TDuration::Seconds(shift); - auto slot = grid.Get(curTime); - - UNIT_ASSERT_VALUES_EQUAL(slot.Start, TInstant::Hours(100) + TDuration::Seconds(5)); - UNIT_ASSERT_VALUES_EQUAL(slot.End, TInstant::Hours(100) + TDuration::Seconds(9)); - - UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).Start, TInstant::Hours(100) + TDuration::Seconds(10)); - UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).End, TInstant::Hours(100) + TDuration::Seconds(14)); - - UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).Start, TInstant::Hours(100)); - UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).End, TInstant::Hours(100) + TDuration::Seconds(4)); - } - - for (ui32 shift = 55; shift < 60; ++shift) { - TInstant curTime = TInstant::Hours(100) + TDuration::Seconds(shift); - auto slot = grid.Get(curTime); - - UNIT_ASSERT_VALUES_EQUAL(slot.Start, TInstant::Hours(100) + TDuration::Seconds(55)); - UNIT_ASSERT_VALUES_EQUAL(slot.End, TInstant::Hours(100) + TDuration::Seconds(59)); - - UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).Start, TInstant::Hours(100) + TDuration::Seconds(60)); - UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).End, TInstant::Hours(100) + TDuration::Seconds(64)); - - UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).Start, TInstant::Hours(100) + TDuration::Seconds(50)); - UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).End, TInstant::Hours(100) + TDuration::Seconds(54)); - } - } - } - -} - -} // namespace NKikimr +#include <library/cpp/testing/unittest/registar.h> +#include "time_grid.h" + +namespace NKikimr { + +Y_UNIT_TEST_SUITE(TTimeGridTest) { + Y_UNIT_TEST(TimeGrid) { + { + TTimeGrid grid(TDuration::Seconds(5)); + + for (ui32 shift = 0; shift < 5; ++shift) { + TInstant curTime = TInstant::Hours(100) + TDuration::Seconds(shift); + auto slot = grid.Get(curTime); + + UNIT_ASSERT_VALUES_EQUAL(slot.Start, TInstant::Hours(100)); + UNIT_ASSERT_VALUES_EQUAL(slot.End, TInstant::Hours(100) + TDuration::Seconds(4)); + + UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).Start, TInstant::Hours(100) + TDuration::Seconds(5)); + UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).End, TInstant::Hours(100) + TDuration::Seconds(9)); + + UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).Start, TInstant::Hours(100) - TDuration::Seconds(5)); + UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).End, TInstant::Hours(100) - TDuration::Seconds(1)); + } + + for (ui32 shift = 5; shift < 10; ++shift) { + TInstant curTime = TInstant::Hours(100) + TDuration::Seconds(shift); + auto slot = grid.Get(curTime); + + UNIT_ASSERT_VALUES_EQUAL(slot.Start, TInstant::Hours(100) + TDuration::Seconds(5)); + UNIT_ASSERT_VALUES_EQUAL(slot.End, TInstant::Hours(100) + TDuration::Seconds(9)); + + UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).Start, TInstant::Hours(100) + TDuration::Seconds(10)); + UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).End, TInstant::Hours(100) + TDuration::Seconds(14)); + + UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).Start, TInstant::Hours(100)); + UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).End, TInstant::Hours(100) + TDuration::Seconds(4)); + } + + for (ui32 shift = 55; shift < 60; ++shift) { + TInstant curTime = TInstant::Hours(100) + TDuration::Seconds(shift); + auto slot = grid.Get(curTime); + + UNIT_ASSERT_VALUES_EQUAL(slot.Start, TInstant::Hours(100) + TDuration::Seconds(55)); + UNIT_ASSERT_VALUES_EQUAL(slot.End, TInstant::Hours(100) + TDuration::Seconds(59)); + + UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).Start, TInstant::Hours(100) + TDuration::Seconds(60)); + UNIT_ASSERT_VALUES_EQUAL(grid.GetNext(slot).End, TInstant::Hours(100) + TDuration::Seconds(64)); + + UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).Start, TInstant::Hours(100) + TDuration::Seconds(50)); + UNIT_ASSERT_VALUES_EQUAL(grid.GetPrev(slot).End, TInstant::Hours(100) + TDuration::Seconds(54)); + } + } + } + +} + +} // namespace NKikimr diff --git a/ydb/core/metering/ut/ya.make b/ydb/core/metering/ut/ya.make index c619715354..2d1b0f80bd 100644 --- a/ydb/core/metering/ut/ya.make +++ b/ydb/core/metering/ut/ya.make @@ -1,14 +1,14 @@ UNITTEST_FOR(ydb/core/metering) - -OWNER( - svc - g:kikimr -) - -SIZE(SMALL) - -SRCS( - time_grid_ut.cpp -) - -END() + +OWNER( + svc + g:kikimr +) + +SIZE(SMALL) + +SRCS( + time_grid_ut.cpp +) + +END() diff --git a/ydb/core/metering/ya.make b/ydb/core/metering/ya.make index a1e9a4d339..5babf9a62e 100644 --- a/ydb/core/metering/ya.make +++ b/ydb/core/metering/ya.make @@ -1,7 +1,7 @@ RECURSE_FOR_TESTS( ut ) - + LIBRARY() OWNER( @@ -10,18 +10,18 @@ OWNER( ) SRCS( - bill_record.cpp - bill_record.h + bill_record.cpp + bill_record.h metering.cpp metering.h - time_grid.h + time_grid.h ) GENERATE_ENUM_SERIALIZATION(bill_record.h) - + PEERDIR( library/cpp/actors/core - library/cpp/json + library/cpp/json library/cpp/logger ydb/core/base ) diff --git a/ydb/core/mind/hive/hive_impl.cpp b/ydb/core/mind/hive/hive_impl.cpp index 58ca2ac3e4..2c9d88db3f 100644 --- a/ydb/core/mind/hive/hive_impl.cpp +++ b/ydb/core/mind/hive/hive_impl.cpp @@ -836,7 +836,7 @@ void THive::OnActivateExecutor(const TActorContext&) { HiveGeneration = Executor()->Generation(); RootDomainKey = TSubDomainKey(domain.SchemeRoot, 1); RootDomainName = "/" + domain.Name; - Executor()->RegisterExternalTabletCounters(TabletCountersPtr); + Executor()->RegisterExternalTabletCounters(TabletCountersPtr); ResourceProfiles = AppData()->ResourceProfiles ? AppData()->ResourceProfiles : new TResourceProfiles; BuildLocalConfig(); ClusterConfig = AppData()->HiveConfig; @@ -1448,7 +1448,7 @@ void THive::SetCounterTabletsTotal(ui64 tabletsTotal) { void THive::UpdateCounterTabletsTotal(i64 tabletsTotalDiff) { if (TabletCounters != nullptr) { - auto& counter = TabletCounters->Simple()[NHive::COUNTER_TABLETS_TOTAL]; + auto& counter = TabletCounters->Simple()[NHive::COUNTER_TABLETS_TOTAL]; TabletsTotal = counter.Get() + tabletsTotalDiff; counter.Set(TabletsTotal); TabletCounters->Simple()[NHive::COUNTER_STATE_DONE].Set(TabletsTotal == TabletsAlive ? 1 : 0); @@ -1457,7 +1457,7 @@ void THive::UpdateCounterTabletsTotal(i64 tabletsTotalDiff) { void THive::UpdateCounterTabletsAlive(i64 tabletsAliveDiff) { if (TabletCounters != nullptr) { - auto& counter = TabletCounters->Simple()[NHive::COUNTER_TABLETS_ALIVE]; + auto& counter = TabletCounters->Simple()[NHive::COUNTER_TABLETS_ALIVE]; TabletsAlive = counter.Get() + tabletsAliveDiff; counter.Set(TabletsAlive); TabletCounters->Simple()[NHive::COUNTER_STATE_DONE].Set(TabletsTotal == TabletsAlive ? 1 : 0); @@ -1466,7 +1466,7 @@ void THive::UpdateCounterTabletsAlive(i64 tabletsAliveDiff) { void THive::UpdateCounterBootQueueSize(ui64 bootQueueSize) { if (TabletCounters != nullptr) { - auto& counter = TabletCounters->Simple()[NHive::COUNTER_BOOTQUEUE_SIZE]; + auto& counter = TabletCounters->Simple()[NHive::COUNTER_BOOTQUEUE_SIZE]; counter.Set(bootQueueSize); } } diff --git a/ydb/core/mind/hive/hive_impl.h b/ydb/core/mind/hive/hive_impl.h index 70c4530fee..c88fcab233 100644 --- a/ydb/core/mind/hive/hive_impl.h +++ b/ydb/core/mind/hive/hive_impl.h @@ -359,7 +359,7 @@ protected: THashMap<ui32, TEvInterconnect::TNodeInfo> NodesInfo; TTabletCountersBase* TabletCounters; - TAutoPtr<TTabletCountersBase> TabletCountersPtr; + TAutoPtr<TTabletCountersBase> TabletCountersPtr; i32 BalancerProgress; // all values below 0 mean that balancer is not active (-1 = dead, -2 = starting) std::unordered_set<TNodeId> BalancerNodes; // all nodes, affected by running balancers diff --git a/ydb/core/mind/hive/monitoring.cpp b/ydb/core/mind/hive/monitoring.cpp index 7e9a83b354..0ea5eb3c49 100644 --- a/ydb/core/mind/hive/monitoring.cpp +++ b/ydb/core/mind/hive/monitoring.cpp @@ -92,86 +92,86 @@ public: } void RenderHTMLPage(IOutputStream &out) { - HTML(out) { - UL_CLASS("nav nav-tabs") { - LI_CLASS("active") { + HTML(out) { + UL_CLASS("nav nav-tabs") { + LI_CLASS("active") { out << "<a href=\"#known-tablets\" data-toggle=\"tab\">Tablets</a>"; - } - LI() { + } + LI() { out << "<a href=\"#per-node-stats\" data-toggle=\"tab\">Nodes</a>"; - } - } - DIV_CLASS("tab-content") { - DIV_CLASS_ID("tab-pane fade in active", "known-tablets") { - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {out << "Tablet";} - TABLEH() {out << "ID";} - TABLEH() {out << "KnownGeneration";} + } + } + DIV_CLASS("tab-content") { + DIV_CLASS_ID("tab-pane fade in active", "known-tablets") { + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {out << "Tablet";} + TABLEH() {out << "ID";} + TABLEH() {out << "KnownGeneration";} TABLEH() {out << "LeaderNode";} - TABLEH() {out << "State";} - TABLEH_CLASS("sorter-false") {} - } - } - TABLEBODY() { + TABLEH() {out << "State";} + TABLEH_CLASS("sorter-false") {} + } + } + TABLEBODY() { ui64 index = 0; for (const auto &tabletPair : TabletInfo) { const ui64 tabletId = tabletPair.first; const auto &x = tabletPair.second; - TABLER() { + TABLER() { out << "<td data-text='" << index << "'>" << "<a href=\"../tablets?TabletID=" << tabletId << "\">" << TTabletTypes::TypeToStr((TTabletTypes::EType)x.TabletType) << "</a></td>"; - TABLED() {out << tabletId;} - TABLED() {out << x.KnownGeneration;} + TABLED() {out << tabletId;} + TABLED() {out << x.KnownGeneration;} TABLED_CLASS(x.LeaderNode ? "" : "warning") {out << x.LeaderNode;} - TABLED() {out << ETabletStateName(x.TabletState);} - TABLED() {out << " <a href=\"../tablets?SsId=" + TABLED() {out << ETabletStateName(x.TabletState);} + TABLED() {out << " <a href=\"../tablets?SsId=" << tabletId << "\">" << "<span class=\"glyphicon glyphicon-tasks\"" << " title=\"State Storage\"/>" - << "</a>";} - } + << "</a>";} + } ++index; } - } - } - } - DIV_CLASS_ID("tab-pane fade", "per-node-stats") { - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {out << "NodeId";} - TABLEH() {out << "Count";} - } - } - TABLEBODY() { + } + } + } + DIV_CLASS_ID("tab-pane fade", "per-node-stats") { + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {out << "NodeId";} + TABLEH() {out << "Count";} + } + } + TABLEBODY() { for (const auto &nodePair : NodeInfo) { const ui32 nodeId = nodePair.first; const auto &x = nodePair.second; if (nodeId != 0 || x.Local) { - TABLER() { + TABLER() { if (nodeId == 0) { TABLED_CLASS("danger") {out << "w/o leader node"; } } else { - TABLED() {out << nodeId; } + TABLED() {out << nodeId; } } if (x.Local) { - TABLED() {out << x.TabletsOn;} + TABLED() {out << x.TabletsOn;} } else { - TABLED_CLASS("danger") {out << "down";} + TABLED_CLASS("danger") {out << "down";} } - } + } } } - } - } - } - } - } + } + } + } + } + } } }; diff --git a/ydb/core/mon/mon.cpp b/ydb/core/mon/mon.cpp index d4722266f3..0c3411297e 100644 --- a/ydb/core/mon/mon.cpp +++ b/ydb/core/mon/mon.cpp @@ -399,9 +399,9 @@ namespace NActors { TBase::Register(new NMonitoring::TVersionMonPage); TBase::Register(new NMonitoring::TTablesorterCssMonPage); TBase::Register(new NMonitoring::TTablesorterJsMonPage); - - NLwTraceMonPage::RegisterPages((TBase*)this); - NLwTraceMonPage::ProbeRegistry().AddProbesList(LWTRACE_GET_PROBES(ACTORLIB_PROVIDER)); + + NLwTraceMonPage::RegisterPages((TBase*)this); + NLwTraceMonPage::ProbeRegistry().AddProbesList(LWTRACE_GET_PROBES(ACTORLIB_PROVIDER)); NLwTraceMonPage::ProbeRegistry().AddProbesList(LWTRACE_GET_PROBES(MONITORING_PROVIDER)); TBase::Start(); } diff --git a/ydb/core/node_whiteboard/node_whiteboard.h b/ydb/core/node_whiteboard/node_whiteboard.h index cdf7601807..f9dadf5747 100644 --- a/ydb/core/node_whiteboard/node_whiteboard.h +++ b/ydb/core/node_whiteboard/node_whiteboard.h @@ -127,12 +127,12 @@ struct TEvWhiteboard{ Record.SetTotalSize(totalSize); Record.SetState(static_cast<NKikimrBlobStorage::TPDiskState::E>(state)); } - - TEvPDiskStateUpdate(ui32 pDiskId, NKikimrWhiteboard::EFlag realtime, NKikimrWhiteboard::EFlag device) { - Record.SetPDiskId(pDiskId); - Record.SetRealtime(realtime); - Record.SetDevice(device); - } + + TEvPDiskStateUpdate(ui32 pDiskId, NKikimrWhiteboard::EFlag realtime, NKikimrWhiteboard::EFlag device) { + Record.SetPDiskId(pDiskId); + Record.SetRealtime(realtime); + Record.SetDevice(device); + } }; struct TEvPDiskStateRequest : public TEventPB<TEvPDiskStateRequest, NKikimrWhiteboard::TEvPDiskStateRequest, EvPDiskStateRequest> {}; diff --git a/ydb/core/persqueue/partition.cpp b/ydb/core/persqueue/partition.cpp index cc8e2419cf..85d8bc80e5 100644 --- a/ydb/core/persqueue/partition.cpp +++ b/ydb/core/persqueue/partition.cpp @@ -175,35 +175,35 @@ private: void HtmlOutput(IOutputStream& out, const TString& line, const std::deque<std::pair<TKey, ui32>>& keys) { - HTML(out) { - TABLE() { - TABLEHEAD() { - TABLER() { - TABLEH() {out << line;} - } - } - TABLEBODY() { - TABLER() { - TABLEH() {out << "offset";} + HTML(out) { + TABLE() { + TABLEHEAD() { + TABLER() { + TABLEH() {out << line;} + } + } + TABLEBODY() { + TABLER() { + TABLEH() {out << "offset";} for (auto& p: keys) { - TABLED() {out << p.first.GetOffset();} + TABLED() {out << p.first.GetOffset();} } - } - TABLER() { - TABLEH() {out << "partNo";} + } + TABLER() { + TABLEH() {out << "partNo";} for (auto& p: keys) { - TABLED() {out << p.first.GetPartNo();} + TABLED() {out << p.first.GetPartNo();} } - } - TABLER() { - TABLEH() {out << "size";} + } + TABLER() { + TABLEH() {out << "size";} for (auto& p: keys) { - TABLED() {out << p.second;} + TABLED() {out << p.second;} } - } - } - } - } + } + } + } + } } @@ -566,35 +566,35 @@ void TPartition::HandleMonitoring(TEvPQ::TEvMonRequest::TPtr& ev, const TActorCo res.push_back(out.Str()); out.Clear(); } out << Config.DebugString(); res.push_back(out.Str()); out.Clear(); - HTML(out) + HTML(out) { - DIV_CLASS_ID("tab-pane fade", Sprintf("partition_%u", ui32(Partition))) { - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {out << "Type";} - TABLEH() {out << "Pos";} - TABLEH() {out << "timestamp";} - TABLEH() {out << "Offset";} - TABLEH() {out << "PartNo";} - TABLEH() {out << "Count";} - TABLEH() {out << "InternalPartsCount";} - TABLEH() {out << "Size";} - } - } - TABLEBODY() { + DIV_CLASS_ID("tab-pane fade", Sprintf("partition_%u", ui32(Partition))) { + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {out << "Type";} + TABLEH() {out << "Pos";} + TABLEH() {out << "timestamp";} + TABLEH() {out << "Offset";} + TABLEH() {out << "PartNo";} + TABLEH() {out << "Count";} + TABLEH() {out << "InternalPartsCount";} + TABLEH() {out << "Size";} + } + } + TABLEBODY() { ui32 i = 0; for (auto& d: DataKeysBody) { - TABLER() { - TABLED() {out << "DataBody";} - TABLED() {out << i++;} + TABLER() { + TABLED() {out << "DataBody";} + TABLED() {out << i++;} TABLED() {out << ToStringLocalTimeUpToSeconds(d.Timestamp);} - TABLED() {out << d.Key.GetOffset();} - TABLED() {out << d.Key.GetPartNo();} - TABLED() {out << d.Key.GetCount();} - TABLED() {out << d.Key.GetInternalPartsCount();} - TABLED() {out << d.Size;} - } + TABLED() {out << d.Key.GetOffset();} + TABLED() {out << d.Key.GetPartNo();} + TABLED() {out << d.Key.GetCount();} + TABLED() {out << d.Key.GetInternalPartsCount();} + TABLED() {out << d.Size;} + } } ui32 currentLevel = 0; for (ui32 p = 0; p < HeadKeys.size(); ++p) { @@ -602,67 +602,67 @@ void TPartition::HandleMonitoring(TEvPQ::TEvMonRequest::TPtr& ev, const TActorCo while (currentLevel + 1 < TotalLevels && size < CompactLevelBorder[currentLevel + 1]) ++currentLevel; Y_VERIFY(size < CompactLevelBorder[currentLevel]); - TABLER() { - TABLED() {out << "DataHead[" << currentLevel << "]";} - TABLED() {out << i++;} + TABLER() { + TABLED() {out << "DataHead[" << currentLevel << "]";} + TABLED() {out << i++;} TABLED() {out << ToStringLocalTimeUpToSeconds(HeadKeys[p].Timestamp);} - TABLED() {out << HeadKeys[p].Key.GetOffset();} - TABLED() {out << HeadKeys[p].Key.GetPartNo();} - TABLED() {out << HeadKeys[p].Key.GetCount();} - TABLED() {out << HeadKeys[p].Key.GetInternalPartsCount();} - TABLED() {out << size;} - } - } - } - } - - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {out << "GapStartOffset";} - TABLEH() {out << "GapEndOffset";} - TABLEH() {out << "GapSize";} - TABLEH() {out << "id";} + TABLED() {out << HeadKeys[p].Key.GetOffset();} + TABLED() {out << HeadKeys[p].Key.GetPartNo();} + TABLED() {out << HeadKeys[p].Key.GetCount();} + TABLED() {out << HeadKeys[p].Key.GetInternalPartsCount();} + TABLED() {out << size;} + } } - } + } + } + + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {out << "GapStartOffset";} + TABLEH() {out << "GapEndOffset";} + TABLEH() {out << "GapSize";} + TABLEH() {out << "id";} + } + } ui32 i = 0; - TABLEBODY() { + TABLEBODY() { for (auto& d: GapOffsets) { - TABLER() { - TABLED() {out << d.first;} - TABLED() {out << d.second;} - TABLED() {out << (d.second - d.first);} - TABLED() {out << (i++);} - } + TABLER() { + TABLED() {out << d.first;} + TABLED() {out << d.second;} + TABLED() {out << (d.second - d.first);} + TABLED() {out << (i++);} + } } if (!DataKeysBody.empty() && DataKeysBody.back().Key.GetOffset() + DataKeysBody.back().Key.GetCount() < Head.Offset) { - TABLER() { - TABLED() {out << (DataKeysBody.back().Key.GetOffset() + DataKeysBody.back().Key.GetCount());} - TABLED() {out << Head.Offset;} - TABLED() {out << (Head.Offset - (DataKeysBody.back().Key.GetOffset() + DataKeysBody.back().Key.GetCount()));} - TABLED() {out << (i++);} - } + TABLER() { + TABLED() {out << (DataKeysBody.back().Key.GetOffset() + DataKeysBody.back().Key.GetCount());} + TABLED() {out << Head.Offset;} + TABLED() {out << (Head.Offset - (DataKeysBody.back().Key.GetOffset() + DataKeysBody.back().Key.GetCount()));} + TABLED() {out << (i++);} + } } - } - } + } + } - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {out << "SourceId";} - TABLEH() {out << "SeqNo";} - TABLEH() {out << "Offset";} - TABLEH() {out << "WriteTimestamp";} + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {out << "SourceId";} + TABLEH() {out << "SeqNo";} + TABLEH() {out << "Offset";} + TABLEH() {out << "WriteTimestamp";} TABLEH() {out << "CreateTimestamp";} TABLEH() {out << "Explicit";} TABLEH() {out << "State";} - } - } - TABLEBODY() { + } + } + TABLEBODY() { for (const auto& [sourceId, sourceIdInfo]: SourceIdStorage.GetInMemorySourceIds()) { - TABLER() { + TABLER() { TABLED() {out << EncodeHtmlPcdata(EscapeC(sourceId));} TABLED() {out << sourceIdInfo.SeqNo;} TABLED() {out << sourceIdInfo.Offset;} @@ -670,33 +670,33 @@ void TPartition::HandleMonitoring(TEvPQ::TEvMonRequest::TPtr& ev, const TActorCo TABLED() {out << ToStringLocalTimeUpToSeconds(sourceIdInfo.CreateTimestamp);} TABLED() {out << (sourceIdInfo.Explicit ? "true" : "false");} TABLED() {out << sourceIdInfo.State;} - } + } } - } - } - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {out << "user";} - TABLEH() {out << "offset";} - TABLEH() {out << "lag";} + } + } + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {out << "user";} + TABLEH() {out << "offset";} + TABLEH() {out << "lag";} TABLEH() {out << "ReadFromTimestamp";} - TABLEH() {out << "WriteTimestamp";} - TABLEH() {out << "CreateTimestamp";} + TABLEH() {out << "WriteTimestamp";} + TABLEH() {out << "CreateTimestamp";} TABLEH() {out << "ReadOffset";} TABLEH() {out << "ReadWriteTimestamp";} TABLEH() {out << "ReadCreateTimestamp";} TABLEH() {out << "ReadOffsetRewindSum";} TABLEH() {out << "ActiveReads";} TABLEH() {out << "Subscriptions";} - } - } - TABLEBODY() { + } + } + TABLEBODY() { for (auto& d: UsersInfoStorage.GetAll()) { - TABLER() { - TABLED() {out << EncodeHtmlPcdata(d.first);} - TABLED() {out << d.second.Offset;} - TABLED() {out << (EndOffset - d.second.Offset);} + TABLER() { + TABLED() {out << EncodeHtmlPcdata(d.first);} + TABLED() {out << d.second.Offset;} + TABLED() {out << (EndOffset - d.second.Offset);} TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.ReadFromTimestamp);} TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.WriteTimestamp);} TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.CreateTimestamp);} @@ -706,12 +706,12 @@ void TPartition::HandleMonitoring(TEvPQ::TEvMonRequest::TPtr& ev, const TActorCo TABLED() {out << (d.second.ReadOffsetRewindSum);} TABLED() {out << d.second.ActiveReads;} TABLED() {out << d.second.Subscriptions;} - } + } } - } - } - } - } + } + } + } + } ctx.Send(ev->Sender, new TEvPQ::TEvMonResponse(Partition, res, out.Str())); } diff --git a/ydb/core/persqueue/pq_impl.cpp b/ydb/core/persqueue/pq_impl.cpp index 9937dbe561..25d9db450d 100644 --- a/ydb/core/persqueue/pq_impl.cpp +++ b/ydb/core/persqueue/pq_impl.cpp @@ -451,44 +451,44 @@ private: ui32 mx = 0; for (auto& r: Results) mx = Max<ui32>(mx, r.second.size()); - HTML(str) { - H2() {str << "PersQueue Tablet";} - H3() {str << "Topic: " << TopicName;} + HTML(str) { + H2() {str << "PersQueue Tablet";} + H3() {str << "Topic: " << TopicName;} H4() {str << "inflight: " << Inflight;} - UL_CLASS("nav nav-tabs") { - LI_CLASS("active") { + UL_CLASS("nav nav-tabs") { + LI_CLASS("active") { str << "<a href=\"#main\" data-toggle=\"tab\">main</a>"; - } - LI() { + } + LI() { str << "<a href=\"#cache\" data-toggle=\"tab\">cache</a>"; - } + } for (auto& r: Results) { - LI() { + LI() { str << "<a href=\"#partition_" << r.first << "\" data-toggle=\"tab\">" << r.first << "</a>"; - } + } } - } - DIV_CLASS("tab-content") { - DIV_CLASS_ID("tab-pane fade in active", "main") { - TABLE() { + } + DIV_CLASS("tab-content") { + DIV_CLASS_ID("tab-pane fade in active", "main") { + TABLE() { for (ui32 i = 0; i < mx; ++i) { - TABLER() { + TABLER() { for (auto& r : Results) { - TABLED() { + TABLED() { if (r.second.size() > i) str << r.second[i]; - } + } } - } + } } - } - } + } + } for (auto& s: Str) { str << s; } - } - H3() {str << "<a href=\"app?TabletID=" << TabletID << "&kv=1\">KV-tablet internals</a>";} - } + } + H3() {str << "<a href=\"app?TabletID=" << TabletID << "&kv=1\">KV-tablet internals</a>";} + } LOG_DEBUG_S(ctx, NKikimrServices::PERSQUEUE, "Answer TEvRemoteHttpInfoRes: to " << Sender << " self " << ctx.SelfID); ctx.Send(Sender, new NMon::TEvRemoteHttpInfoRes(str.Str())); Die(ctx); diff --git a/ydb/core/persqueue/pq_l2_cache.cpp b/ydb/core/persqueue/pq_l2_cache.cpp index e56642c39a..9f355e50c9 100644 --- a/ydb/core/persqueue/pq_l2_cache.cpp +++ b/ydb/core/persqueue/pq_l2_cache.cpp @@ -214,30 +214,30 @@ void TPersQueueCacheL2::Handle(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& TString TPersQueueCacheL2::HttpForm() const { TStringStream str; - HTML(str) { - FORM_CLASS("form-horizontal") { - DIV_CLASS("row") { - PRE() { + HTML(str) { + FORM_CLASS("form-horizontal") { + DIV_CLASS("row") { + PRE() { str << "CacheLimit (MB): " << (MaxSize>>20) << Endl; str << "CacheSize (MB): " << (CurrentSize>>20) << Endl; str << "Count of blobs: " << Cache.Size() << Endl; str << "Min RetentionTime: " << KeepTime << Endl; str << "RetentionTime: " << RetentionTime << Endl; - } - } - DIV_CLASS("control-group") { - LABEL_CLASS_FOR("control-label", "inputTo") {str << "New Chache Limit";} - DIV_CLASS("controls") { + } + } + DIV_CLASS("control-group") { + LABEL_CLASS_FOR("control-label", "inputTo") {str << "New Chache Limit";} + DIV_CLASS("controls") { str << "<input type=\"number\" id=\"inputTo\" placeholder=\"CacheLimit (MB)\" name=\"newCacheLimit\">"; - } - } - DIV_CLASS("control-group") { - DIV_CLASS("controls") { + } + } + DIV_CLASS("control-group") { + DIV_CLASS("controls") { str << "<button type=\"submit\" name=\"submit\" class=\"btn btn-primary\">Change</button>"; - } - } - } - } + } + } + } + } return str.Str(); } diff --git a/ydb/core/persqueue/read.h b/ydb/core/persqueue/read.h index d0bc79c692..58bbea4bfd 100644 --- a/ydb/core/persqueue/read.h +++ b/ydb/core/persqueue/read.h @@ -312,37 +312,37 @@ namespace NPQ { void HandleMonitoring(TEvPQ::TEvMonRequest::TPtr& ev, const TActorContext& ctx) { TStringStream out; - HTML(out) + HTML(out) { - DIV_CLASS_ID("tab-pane fade", "cache") { - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {out << "Partition";} - TABLEH() {out << "Offset";} - TABLEH() {out << "Count";} - TABLEH() {out << "Size";} - TABLEH() {out << "Time";} - } - } - TABLEBODY() { + DIV_CLASS_ID("tab-pane fade", "cache") { + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {out << "Partition";} + TABLEH() {out << "Offset";} + TABLEH() {out << "Count";} + TABLEH() {out << "Size";} + TABLEH() {out << "Time";} + } + } + TABLEBODY() { for (const auto& c: Cache.CachedMap()) { const TCacheValue::TPtr data = c.second.GetBlob(); if (!data) continue; - TABLER() { - TABLED() {out << int(c.first.Partition);} - TABLED() {out << c.first.Offset;} - TABLED() {out << c.first.Count;} - TABLED() {out << data->GetValue().size();} - TABLED() {out << ToStringLocalTimeUpToSeconds(data->GetAccessTime());} - } + TABLER() { + TABLED() {out << int(c.first.Partition);} + TABLED() {out << c.first.Offset;} + TABLED() {out << c.first.Count;} + TABLED() {out << data->GetValue().size();} + TABLED() {out << ToStringLocalTimeUpToSeconds(data->GetAccessTime());} + } } - } - } - } - } + } + } + } + } ctx.Send(ev->Sender, new TEvPQ::TEvMonResponse(Max<ui32>(), TVector<TString>(), out.Str())); } diff --git a/ydb/core/protos/blobstorage_pdisk_config.proto b/ydb/core/protos/blobstorage_pdisk_config.proto index 00ea5c7e22..0b34228e09 100644 --- a/ydb/core/protos/blobstorage_pdisk_config.proto +++ b/ydb/core/protos/blobstorage_pdisk_config.proto @@ -64,7 +64,7 @@ message TPDiskConfig { // Once SortFreeChunksPerItems chunks are released, free chuks are sorted optional uint64 SortFreeChunksPerItems = 4; - + optional uint32 SectorSize = 6; optional uint32 ChunkSize = 7; diff --git a/ydb/core/protos/config.proto b/ydb/core/protos/config.proto index d64169d4fc..2f74931236 100644 --- a/ydb/core/protos/config.proto +++ b/ydb/core/protos/config.proto @@ -31,11 +31,11 @@ package NKikimrConfig; option java_package = "ru.yandex.kikimr.proto"; message TAffinity { - repeated uint32 X = 1; // DEPRECATED: Use `CpuList` instead - - // Numerical list of processors. The numbers are separated by commas and may include ranges. For example: 0,5,7,9-11 - optional string CpuList = 2; // Processors to include. Use all processor if not set. - optional string ExcludeCpuList = 3; // Exclude specified processors from `CpuList` (or all processors if not set) + repeated uint32 X = 1; // DEPRECATED: Use `CpuList` instead + + // Numerical list of processors. The numbers are separated by commas and may include ranges. For example: 0,5,7,9-11 + optional string CpuList = 2; // Processors to include. Use all processor if not set. + optional string ExcludeCpuList = 3; // Exclude specified processors from `CpuList` (or all processors if not set) } message TActorSystemConfig { @@ -43,11 +43,11 @@ message TActorSystemConfig { enum EType { BASIC = 1; IO = 2; - UNITED = 3; + UNITED = 3; }; optional EType Type = 1; - optional uint32 Threads = 2; + optional uint32 Threads = 2; optional uint64 SpinThreshold = 3; optional TAffinity Affinity = 4; optional uint32 InjectMadSquirrels = 5; @@ -55,16 +55,16 @@ message TActorSystemConfig { optional uint32 TimePerMailboxMicroSecs = 7; optional uint32 EventsPerMailbox = 8; optional uint32 RealtimePriority = 9; - - // Actorsystem 2.0: cpu sharing by different pools with preemption - optional uint32 Concurrency = 10; // Limits simultaneously running mailboxes of UNITED pool - optional uint32 Weight = 11; // Weight of UNITED pool in cpu-local scheduler (default value is NActors::DefPoolWeight) - - // Actorsystem 1.5: cpu balancing between pools - optional uint32 MinThreads = 12; // Lower balancing bound, should be at least 1, and not greater than `Threads` - optional uint32 MaxThreads = 13; // Higher balancing bound, should be not lower than `Threads` - optional uint32 BalancingPriority = 14; // Priority of pool to obtain cpu due to balancing (higher is better) - optional uint64 ToleratedLatencyUs = 15; // p100-latency threshold indicating that more cpus are required by pool + + // Actorsystem 2.0: cpu sharing by different pools with preemption + optional uint32 Concurrency = 10; // Limits simultaneously running mailboxes of UNITED pool + optional uint32 Weight = 11; // Weight of UNITED pool in cpu-local scheduler (default value is NActors::DefPoolWeight) + + // Actorsystem 1.5: cpu balancing between pools + optional uint32 MinThreads = 12; // Lower balancing bound, should be at least 1, and not greater than `Threads` + optional uint32 MaxThreads = 13; // Higher balancing bound, should be not lower than `Threads` + optional uint32 BalancingPriority = 14; // Priority of pool to obtain cpu due to balancing (higher is better) + optional uint64 ToleratedLatencyUs = 15; // p100-latency threshold indicating that more cpus are required by pool } message TScheduler { @@ -92,22 +92,22 @@ message TActorSystemConfig { optional uint32 TimePerMailboxMicroSecs = 8; optional uint32 EventsPerMailbox = 9; optional uint32 SelfPingInterval = 10; // in microseconds - - message TUnitedWorkers { - optional uint32 CpuCount = 1; // Total CPUs running united workers (TExecutor.Threads analog), should be set to zero to use actorsystem 1.5, and >0 for actorsystem 2.0 - optional uint64 SpinThresholdUs = 2; // Limit for active spinning in case all pools became idle - optional uint64 PoolLimitUs = 3; // Soft limit on pool execution - optional uint64 EventLimitUs = 4; // Hard limit on last event execution exceeding pool limit - optional uint64 LimitPrecisionUs = 5; // Maximum delay of timer on limit excess (delay needed to avoid settimer syscall on every pool switch) - optional uint64 FastWorkerPriority = 6; // Real-time priority of workers not exceeding hard limits - optional uint64 IdleWorkerPriority = 7; // Real-time priority of standby workers waiting for hard preemption on timers (should be greater than FastWorkerPriority) - optional TAffinity Affinity = 8; // Cpu set for workers (every worker has affinity for exactly one cpu) - optional bool NoRealtime = 9; // Do not use RT-priority for worker threads - optional bool NoAffinity = 10; // Do not use affinity for worker threads - optional uint64 BalancerPeriodUs = 11; // Time between balancer steps (see default in NActors::TBalancerConfig) - } - - optional TUnitedWorkers UnitedWorkers = 11; + + message TUnitedWorkers { + optional uint32 CpuCount = 1; // Total CPUs running united workers (TExecutor.Threads analog), should be set to zero to use actorsystem 1.5, and >0 for actorsystem 2.0 + optional uint64 SpinThresholdUs = 2; // Limit for active spinning in case all pools became idle + optional uint64 PoolLimitUs = 3; // Soft limit on pool execution + optional uint64 EventLimitUs = 4; // Hard limit on last event execution exceeding pool limit + optional uint64 LimitPrecisionUs = 5; // Maximum delay of timer on limit excess (delay needed to avoid settimer syscall on every pool switch) + optional uint64 FastWorkerPriority = 6; // Real-time priority of workers not exceeding hard limits + optional uint64 IdleWorkerPriority = 7; // Real-time priority of standby workers waiting for hard preemption on timers (should be greater than FastWorkerPriority) + optional TAffinity Affinity = 8; // Cpu set for workers (every worker has affinity for exactly one cpu) + optional bool NoRealtime = 9; // Do not use RT-priority for worker threads + optional bool NoAffinity = 10; // Do not use affinity for worker threads + optional uint64 BalancerPeriodUs = 11; // Time between balancer steps (see default in NActors::TBalancerConfig) + } + + optional TUnitedWorkers UnitedWorkers = 11; } message TStaticNameserviceConfig { diff --git a/ydb/core/protos/counters.proto b/ydb/core/protos/counters.proto index 05a8c93d90..5ca9b39198 100644 --- a/ydb/core/protos/counters.proto +++ b/ydb/core/protos/counters.proto @@ -1,27 +1,27 @@ import "google/protobuf/descriptor.proto"; - -package NKikimr; - -option java_package = "ru.yandex.kikimr.proto"; - -// -// Custom options to describe counters -// -message TRange { - optional uint64 Value = 1; - optional string Name = 2; -} - -message TCounterOptions { - optional string Name = 1; - repeated TRange Ranges = 2; + +package NKikimr; + +option java_package = "ru.yandex.kikimr.proto"; + +// +// Custom options to describe counters +// +message TRange { + optional uint64 Value = 1; + optional string Name = 2; +} + +message TCounterOptions { + optional string Name = 1; + repeated TRange Ranges = 2; optional bool Integral = 3; -} - -message TTxTypeOptions { - optional string Name = 1; -} - +} + +message TTxTypeOptions { + optional string Name = 1; +} + message TLabeledCounterOptions { enum ECounterType { CT_SIMPLE = 1; @@ -44,49 +44,49 @@ message TLabeledCounterGroupNamesOptions { repeated string Names = 1; } -extend google.protobuf.EnumValueOptions { - optional TCounterOptions CounterOpts = 56672; - optional TTxTypeOptions TxTypeOpts = 56673; +extend google.protobuf.EnumValueOptions { + optional TCounterOptions CounterOpts = 56672; + optional TTxTypeOptions TxTypeOpts = 56673; optional TLabeledCounterOptions LabeledCounterOpts = 56676; -} - -extend google.protobuf.EnumOptions { - optional TCounterOptions GlobalCounterOpts = 56674; +} + +extend google.protobuf.EnumOptions { + optional TCounterOptions GlobalCounterOpts = 56674; optional TLabeledCounterGroupNamesOptions GlobalGroupNamesOpts = 56677; -} - -extend google.protobuf.FileOptions { - optional string TabletTypeName = 56675; -} - -// -// Counters common for every transaction type -// -enum ETxTypeSimpleCounters { +} + +extend google.protobuf.FileOptions { + optional string TabletTypeName = 56675; +} + +// +// Counters common for every transaction type +// +enum ETxTypeSimpleCounters { COUNTER_TT_SIMPLE_IGNORE = 0; -} - -enum ETxTypeCumulativeCounters { +} + +enum ETxTypeCumulativeCounters { COUNTER_TT_CULUMATIVE_IGNORE = 0; COUNTER_TT_POSTPONED = 1 [(CounterOpts) = {Name: "Postponed"}]; // Total restarts - COUNTER_TT_RO_COMPLETED = 2 [(CounterOpts) = {Name: "RoCompleted"}]; - COUNTER_TT_RW_COMPLETED = 3 [(CounterOpts) = {Name: "RwCompleted"}]; - COUNTER_TT_WRITES = 4 [(CounterOpts) = {Name: "Writes"}]; - COUNTER_TT_BYTES_WRITTEN = 5 [(CounterOpts) = {Name: "WrittenBytes"}]; - COUNTER_TT_BYTES_READ = 6 [(CounterOpts) = {Name: "ReadBytes"}]; - COUNTER_TT_EXECUTE_CPUTIME = 7 [(CounterOpts) = {Name: "ExecuteCPUTime"}]; - COUNTER_TT_BOOKKEEPING_CPUTIME = 8 [(CounterOpts) = {Name: "BookkeepingCPUTime"}]; - COUNTER_TT_COMMITED_CPUTIME = 9 [(CounterOpts) = {Name: "CommitedCPUTime"}]; - COUNTER_TT_TOUCHED_BLOCKS = 10 [(CounterOpts) = {Name: "TouchedBlocks"}]; + COUNTER_TT_RO_COMPLETED = 2 [(CounterOpts) = {Name: "RoCompleted"}]; + COUNTER_TT_RW_COMPLETED = 3 [(CounterOpts) = {Name: "RwCompleted"}]; + COUNTER_TT_WRITES = 4 [(CounterOpts) = {Name: "Writes"}]; + COUNTER_TT_BYTES_WRITTEN = 5 [(CounterOpts) = {Name: "WrittenBytes"}]; + COUNTER_TT_BYTES_READ = 6 [(CounterOpts) = {Name: "ReadBytes"}]; + COUNTER_TT_EXECUTE_CPUTIME = 7 [(CounterOpts) = {Name: "ExecuteCPUTime"}]; + COUNTER_TT_BOOKKEEPING_CPUTIME = 8 [(CounterOpts) = {Name: "BookkeepingCPUTime"}]; + COUNTER_TT_COMMITED_CPUTIME = 9 [(CounterOpts) = {Name: "CommitedCPUTime"}]; + COUNTER_TT_TOUCHED_BLOCKS = 10 [(CounterOpts) = {Name: "TouchedBlocks"}]; COUNTER_TT_LOADED_BLOCKS = 11 [(CounterOpts) = {Name: "LoadedBlocks"}]; COUNTER_TT_TERMINATED = 12 [(CounterOpts) = {Name: "Terminated"}]; COUNTER_TT_REDO_WRITTEN_BYTES = 13 [(CounterOpts) = {Name: "RedoWrittenBytes"}]; COUNTER_TT_ANNEX_WRITTEN_BYTES = 14 [(CounterOpts) = {Name: "AnnexWrittenBytes"}]; -} - -enum ETxTypePercentileCounters { - option (GlobalCounterOpts) = { +} + +enum ETxTypePercentileCounters { + option (GlobalCounterOpts) = { Ranges { Value: 0 Name: "(1) < 500 us" } Ranges { Value: 500 Name: "(2) 0.5-1 ms" } Ranges { Value: 1000 Name: "(3) 1-2 ms" } @@ -105,7 +105,7 @@ enum ETxTypePercentileCounters { Ranges { Value: 8000000 Name: "(16) 8-16 s" } Ranges { Value: 16000000 Name: "(17) 16-32 s" } Ranges { Value: 32000000 Name: "(18) 32 < s" } - }; + }; COUNTER_TT_PERCENTILE_IGNORE = 0; -} +} diff --git a/ydb/core/protos/counters_coordinator.proto b/ydb/core/protos/counters_coordinator.proto index 0357a80220..aee12b2d7c 100644 --- a/ydb/core/protos/counters_coordinator.proto +++ b/ydb/core/protos/counters_coordinator.proto @@ -1,33 +1,33 @@ import "ydb/core/protos/counters.proto"; - -package NKikimr.NFlatTxCoordinator; - -option java_package = "ru.yandex.kikimr.proto"; - -option (TabletTypeName) = "Coordinator"; // Used as prefix for all counters - -// Real coordinator counters are dynamic. Probably we should fix this? -enum ESimpleCounters { + +package NKikimr.NFlatTxCoordinator; + +option java_package = "ru.yandex.kikimr.proto"; + +option (TabletTypeName) = "Coordinator"; // Used as prefix for all counters + +// Real coordinator counters are dynamic. Probably we should fix this? +enum ESimpleCounters { COUNTER_SIMPLE_IGNORE = 0; -} - -enum ECumulativeCounters { +} + +enum ECumulativeCounters { COUNTER_CUMULATIVE_IGNORE = 0; -} - -enum EPercentileCounters { - option (GlobalCounterOpts) = { - Ranges { Value: 0 Name: "0 ms" } - Ranges { Value: 1 Name: "1 ms" } - }; - +} + +enum EPercentileCounters { + option (GlobalCounterOpts) = { + Ranges { Value: 0 Name: "0 ms" } + Ranges { Value: 1 Name: "1 ms" } + }; + COUNTER_PERCENTILE_IGNORE = 0; -} - -enum ETxTypes { - TXTYPE_INIT = 0 [(TxTypeOpts) = {Name: "TxInit"}]; - TXTYPE_STEP = 1 [(TxTypeOpts) = {Name: "TxStep"}]; - TXTYPE_MEDIATOR_CONFIRMATIONS = 2 [(TxTypeOpts) = {Name: "TxMediatorConfirmations"}]; - TXTYPE_RESTART_MEDIATOR = 3 [(TxTypeOpts) = {Name: "TxRestartMediator"}]; +} + +enum ETxTypes { + TXTYPE_INIT = 0 [(TxTypeOpts) = {Name: "TxInit"}]; + TXTYPE_STEP = 1 [(TxTypeOpts) = {Name: "TxStep"}]; + TXTYPE_MEDIATOR_CONFIRMATIONS = 2 [(TxTypeOpts) = {Name: "TxMediatorConfirmations"}]; + TXTYPE_RESTART_MEDIATOR = 3 [(TxTypeOpts) = {Name: "TxRestartMediator"}]; TXTYPE_ACQUIRE_READ_STEP = 4 [(TxTypeOpts) = {Name: "TxAcquireReadStep"}]; -} +} diff --git a/ydb/core/protos/counters_datashard.proto b/ydb/core/protos/counters_datashard.proto index 956a136937..79d9957303 100644 --- a/ydb/core/protos/counters_datashard.proto +++ b/ydb/core/protos/counters_datashard.proto @@ -1,12 +1,12 @@ import "ydb/core/protos/counters.proto"; - + package NKikimr.NDataShard; - -option java_package = "ru.yandex.kikimr.proto"; - -option (TabletTypeName) = "DataShard"; // Used as prefix for all counters - -enum ESimpleCounters { + +option java_package = "ru.yandex.kikimr.proto"; + +option (TabletTypeName) = "DataShard"; // Used as prefix for all counters + +enum ESimpleCounters { COUNTER_TX_IN_FLY = 0 [(CounterOpts) = {Name: "TxInFly"}]; COUNTER_STATE_WORK = 1 [(CounterOpts) = {Name: "StateWork"}]; COUNTER_TX_COMPLETE_LAG = 2 [(CounterOpts) = {Name: "TxCompleteLag"}]; @@ -20,32 +20,32 @@ enum ESimpleCounters { COUNTER_MVCC_STATE_CHANGE_WAIT_TX_IN_FLY = 10 [(CounterOpts) = {Name: "MvccStateChangeWaitTxInFly"}]; COUNTER_MVCC_STATE_CHANGE_WAIT_IMMEDIATE_TX_IN_FLY = 11 [(CounterOpts) = {Name: "MvccStateChangeWaitImmediateTxInFly"}]; COUNTER_MVCC_ENABLED = 12 [(CounterOpts) = {Name: "MvccEnabled"}]; -} - -enum ECumulativeCounters { - COUNTER_REQ_RO = 0 [(CounterOpts) = {Name: "ReqRo"}]; - COUNTER_PREPARE_REQUEST = 1 [(CounterOpts) = {Name: "PrepareRequests"}]; - COUNTER_PREPARE_ERROR = 2 [(CounterOpts) = {Name: "PrepareErrors"}]; - COUNTER_PREPARE_IMMEDIATE = 3 [(CounterOpts) = {Name: "PrepareImmediate"}]; - COUNTER_PREPARE_SUCCESS = 4 [(CounterOpts) = {Name: "PrepareSuccess"}]; - COUNTER_PREPARE_COMPLETE = 5 [(CounterOpts) = {Name: "PrepareComplete"}]; - COUNTER_PREPARE_DIRTY = 6 [(CounterOpts) = {Name: "PrepareDirty"}]; - COUNTER_PREPARE_OVERLOADED = 7 [(CounterOpts) = {Name: "PrepareOverloaded"}]; - COUNTER_PLAN_STEP_IGNORED = 8 [(CounterOpts) = {Name: "PlanStepIgnored"}]; - COUNTER_PLAN_STEP_ACCEPTED = 9 [(CounterOpts) = {Name: "PlanStepAccepted"}]; - COUNTER_TX_PROGRESS_SHARD_INACTIVE = 10 [(CounterOpts) = {Name: "TxProgressShardInactive"}]; - COUNTER_TX_PROGRESS_QUEUE_EMPTY = 11 [(CounterOpts) = {Name: "TxProgressQueueEmpty"}]; +} + +enum ECumulativeCounters { + COUNTER_REQ_RO = 0 [(CounterOpts) = {Name: "ReqRo"}]; + COUNTER_PREPARE_REQUEST = 1 [(CounterOpts) = {Name: "PrepareRequests"}]; + COUNTER_PREPARE_ERROR = 2 [(CounterOpts) = {Name: "PrepareErrors"}]; + COUNTER_PREPARE_IMMEDIATE = 3 [(CounterOpts) = {Name: "PrepareImmediate"}]; + COUNTER_PREPARE_SUCCESS = 4 [(CounterOpts) = {Name: "PrepareSuccess"}]; + COUNTER_PREPARE_COMPLETE = 5 [(CounterOpts) = {Name: "PrepareComplete"}]; + COUNTER_PREPARE_DIRTY = 6 [(CounterOpts) = {Name: "PrepareDirty"}]; + COUNTER_PREPARE_OVERLOADED = 7 [(CounterOpts) = {Name: "PrepareOverloaded"}]; + COUNTER_PLAN_STEP_IGNORED = 8 [(CounterOpts) = {Name: "PlanStepIgnored"}]; + COUNTER_PLAN_STEP_ACCEPTED = 9 [(CounterOpts) = {Name: "PlanStepAccepted"}]; + COUNTER_TX_PROGRESS_SHARD_INACTIVE = 10 [(CounterOpts) = {Name: "TxProgressShardInactive"}]; + COUNTER_TX_PROGRESS_QUEUE_EMPTY = 11 [(CounterOpts) = {Name: "TxProgressQueueEmpty"}]; COUNTER_TX_PROGRESS_CLEANUP = 12 [(CounterOpts) = {Name: "TxProgressCleanup"}]; - COUNTER_TX_PROGRESS_OUTDATED = 13 [(CounterOpts) = {Name: "TxProgressOutdated"}]; - COUNTER_TX_PROGRESS_DUPLICATE = 14 [(CounterOpts) = {Name: "TxProgressDuplicate"}]; - COUNTER_TX_PROGRESS_DIRTY = 15 [(CounterOpts) = {Name: "TxProgressDirty"}]; - COUNTER_TX_PROGRESS_EV = 16 [(CounterOpts) = {Name: "TxProgressEvents"}]; + COUNTER_TX_PROGRESS_OUTDATED = 13 [(CounterOpts) = {Name: "TxProgressOutdated"}]; + COUNTER_TX_PROGRESS_DUPLICATE = 14 [(CounterOpts) = {Name: "TxProgressDuplicate"}]; + COUNTER_TX_PROGRESS_DIRTY = 15 [(CounterOpts) = {Name: "TxProgressDirty"}]; + COUNTER_TX_PROGRESS_EV = 16 [(CounterOpts) = {Name: "TxProgressEvents"}]; COUNTER_TX_CLEANUP_SCHEDULED = 17 [(CounterOpts) = {Name: "TxCleanupScheduled"}]; COUNTER_TX_PROGRESS_IDLE = 18 [(CounterOpts) = {Name: "TxProgressIdle"}]; - COUNTER_ACK_SENT = 19 [(CounterOpts) = {Name: "AckSent"}]; - COUNTER_ACK_SENT_DELAYED = 20 [(CounterOpts) = {Name: "AckSentDelayed"}]; - COUNTER_CANCEL_TX_NOTFOUND = 21 [(CounterOpts) = {Name: "CancelTxNotFound"}]; - COUNTER_MINIKQL_PROGRAM_SIZE = 22 [(CounterOpts) = {Name: "MiniKQLProgramSize"}]; + COUNTER_ACK_SENT = 19 [(CounterOpts) = {Name: "AckSent"}]; + COUNTER_ACK_SENT_DELAYED = 20 [(CounterOpts) = {Name: "AckSentDelayed"}]; + COUNTER_CANCEL_TX_NOTFOUND = 21 [(CounterOpts) = {Name: "CancelTxNotFound"}]; + COUNTER_MINIKQL_PROGRAM_SIZE = 22 [(CounterOpts) = {Name: "MiniKQLProgramSize"}]; COUNTER_ENGINE_HOST_SELECT_ROW = 23 [(CounterOpts) = {Name: "EngineHostRowReads"}]; COUNTER_ENGINE_HOST_SELECT_RANGE = 24 [(CounterOpts) = {Name: "EngineHostRangeReads"}]; COUNTER_ENGINE_HOST_UPDATE_ROW = 25 [(CounterOpts) = {Name: "EngineHostRowUpdates"}]; @@ -108,10 +108,10 @@ enum ECumulativeCounters { COUNTER_TX_BACKGROUND_COMPACTION_NOT_NEEDED = 82 [(CounterOpts) = {Name: "TxCompactTableNotNeeded"}]; COUNTER_TX_BACKGROUND_COMPACTION_FAILED_BORROWED = 83 [(CounterOpts) = {Name: "TxCompactTableFailedBorrowed"}]; COUNTER_TX_BACKGROUND_COMPACTION_FAILED_START = 84 [(CounterOpts) = {Name: "TxCompactTableFailedStart"}]; -} - -enum EPercentileCounters { - option (GlobalCounterOpts) = { +} + +enum EPercentileCounters { + option (GlobalCounterOpts) = { Ranges { Value: 0 Name: "(1) < 500 us" } Ranges { Value: 500 Name: "(2) 0.5-1 ms" } Ranges { Value: 1000 Name: "(3) 1-2 ms" } @@ -130,14 +130,14 @@ enum EPercentileCounters { Ranges { Value: 8000000 Name: "(16) 8-16 s" } Ranges { Value: 16000000 Name: "(17) 16-32 s" } Ranges { Value: 32000000 Name: "(18) 32 < s" } - }; - - COUNTER_PREPARE_SUCCESS_COMPLETE_LATENCY = 0 [(CounterOpts) = {Name: "PrepareSuccessCompleteLatency"}]; - COUNTER_ACCEPTED_PLAN_STEP_COMPLETE_LATENCY = 1 [(CounterOpts) = {Name: "AcceptedPlanStepCompleteLatency"}]; - COUNTER_TX_PROGRESS_COMPLETE_LATENCY = 2 [(CounterOpts) = {Name: "TxProgressCompleteLatency"}]; - COUNTER_PLAN_TO_EXECUTE_LATENCY = 3 [(CounterOpts) = {Name: "PlanToExecuteLatency"}]; - COUNTER_PREPARE_EXEC_LATENCY = 4 [(CounterOpts) = {Name: "PrepareExecLatency"}]; - COUNTER_TX_PROGRESS_EXEC_LATENCY = 5 [(CounterOpts) = {Name: "TxProgressExecLatency"}]; + }; + + COUNTER_PREPARE_SUCCESS_COMPLETE_LATENCY = 0 [(CounterOpts) = {Name: "PrepareSuccessCompleteLatency"}]; + COUNTER_ACCEPTED_PLAN_STEP_COMPLETE_LATENCY = 1 [(CounterOpts) = {Name: "AcceptedPlanStepCompleteLatency"}]; + COUNTER_TX_PROGRESS_COMPLETE_LATENCY = 2 [(CounterOpts) = {Name: "TxProgressCompleteLatency"}]; + COUNTER_PLAN_TO_EXECUTE_LATENCY = 3 [(CounterOpts) = {Name: "PlanToExecuteLatency"}]; + COUNTER_PREPARE_EXEC_LATENCY = 4 [(CounterOpts) = {Name: "PrepareExecLatency"}]; + COUNTER_TX_PROGRESS_EXEC_LATENCY = 5 [(CounterOpts) = {Name: "TxProgressExecLatency"}]; COUNTER_LOCKS_ACTIVE_PER_SHARD = 6 [(CounterOpts) = {Name: "LocksActivePerShard", Ranges: { Value: 0 Name: "0"}, @@ -343,17 +343,17 @@ enum EPercentileCounters { Ranges: { Value: 72 Name: "72"}, Ranges: { Value: 168 Name: "inf"}, }]; -} - -enum ETxTypes { - TXTYPE_INIT = 0 [(TxTypeOpts) = {Name: "TxInit"}]; - TXTYPE_READSET = 1 [(TxTypeOpts) = {Name: "TxReadSet"}]; - TXTYPE_PLAN_STEP = 2 [(TxTypeOpts) = {Name: "TxPlanStep"}]; - TXTYPE_PROPOSE_DATA = 3 [(TxTypeOpts) = {Name: "TxProposeData"}]; - TXTYPE_PROPOSE_SCHEME = 4 [(TxTypeOpts) = {Name: "TxProposeScheme"}]; - TXTYPE_PROGRESS_START = 5 [(TxTypeOpts) = {Name: "TxProgressStart"}]; - TXTYPE_PROGRESS_WAIT = 6 [(TxTypeOpts) = {Name: "TxProgressWait"}]; - TXTYPE_PROGRESS_COMPLETE = 7 [(TxTypeOpts) = {Name: "TxProgressComplete"}]; +} + +enum ETxTypes { + TXTYPE_INIT = 0 [(TxTypeOpts) = {Name: "TxInit"}]; + TXTYPE_READSET = 1 [(TxTypeOpts) = {Name: "TxReadSet"}]; + TXTYPE_PLAN_STEP = 2 [(TxTypeOpts) = {Name: "TxPlanStep"}]; + TXTYPE_PROPOSE_DATA = 3 [(TxTypeOpts) = {Name: "TxProposeData"}]; + TXTYPE_PROPOSE_SCHEME = 4 [(TxTypeOpts) = {Name: "TxProposeScheme"}]; + TXTYPE_PROGRESS_START = 5 [(TxTypeOpts) = {Name: "TxProgressStart"}]; + TXTYPE_PROGRESS_WAIT = 6 [(TxTypeOpts) = {Name: "TxProgressWait"}]; + TXTYPE_PROGRESS_COMPLETE = 7 [(TxTypeOpts) = {Name: "TxProgressComplete"}]; TXTYPE_GET_STARD_STATE = 8 [(TxTypeOpts) = {Name: "TxGetShardState"}]; TXTYPE_PROGRESS_RESEND_RS = 9 [(TxTypeOpts) = {Name: "TxProgressResendRS"}]; TXTYPE_CANCEL_TX_PROPOSAL = 10 [(TxTypeOpts) = {Name: "TxCancelTxProposal"}]; @@ -417,4 +417,4 @@ enum ETxTypes { TXTYPE_APPLY_REPLICATION_CHANGES = 68 [(TxTypeOpts) = {Name: "TxApplyReplicationChanges"}]; TXTYPE_READ = 69 [(TxTypeOpts) = {Name: "TxRead"}]; TXTYPE_SPLIT_REPLICATION_SOURCE_OFFSETS = 70 [(TxTypeOpts) = {Name: "TxSplitReplicationSourceOffsets"}]; -} +} diff --git a/ydb/core/protos/counters_hive.proto b/ydb/core/protos/counters_hive.proto index 952f4e99e3..ee9fd4d501 100644 --- a/ydb/core/protos/counters_hive.proto +++ b/ydb/core/protos/counters_hive.proto @@ -1,12 +1,12 @@ import "ydb/core/protos/counters.proto"; - -package NKikimr.NHive; - -option java_package = "ru.yandex.kikimr.proto"; - -option (TabletTypeName) = "Hive"; // Used as prefix for all counters - -enum ESimpleCounters { + +package NKikimr.NHive; + +option java_package = "ru.yandex.kikimr.proto"; + +option (TabletTypeName) = "Hive"; // Used as prefix for all counters + +enum ESimpleCounters { COUNTER_TABLETS_TOTAL = 0 [(CounterOpts) = {Name: "TabletsTotal"}]; COUNTER_TABLETS_ALIVE = 1 [(CounterOpts) = {Name: "TabletsAlive"}]; COUNTER_BOOTQUEUE_SIZE = 2 [(CounterOpts) = {Name: "BootQueueSize"}]; @@ -20,9 +20,9 @@ enum ESimpleCounters { COUNTER_WAITQUEUE_SIZE = 10 [(CounterOpts) = {Name: "WaitQueueSize"}]; COUNTER_BALANCE_USAGE_MIN = 11 [(CounterOpts) = {Name: "BalanceUsageMin"}]; COUNTER_BALANCE_USAGE_MAX = 12 [(CounterOpts) = {Name: "BalanceUsageMax"}]; -} - -enum ECumulativeCounters { +} + +enum ECumulativeCounters { COUNTER_BOOTQUEUE_PROCESSED = 0 [(CounterOpts) = {Name: "BootQueueProcessed"}]; COUNTER_BOOTQUEUE_TIME = 1 [(CounterOpts) = {Name: "BootQueueTime"}]; COUNTER_AUTOKICK_EXECUTED = 2 [(CounterOpts) = {Name: "AutokickExecuted"}]; // obsolete @@ -35,25 +35,25 @@ enum ECumulativeCounters { COUNTER_TABLETS_MOVED = 9 [(CounterOpts) = {Name: "TabletsMoved"}]; COUNTER_SUGGESTED_SCALE_UP = 10 [(CounterOpts) = {Name: "SuggestedScaleUp"}]; COUNTER_SUGGESTED_SCALE_DOWN = 11 [(CounterOpts) = {Name: "SuggestedScaleDown"}]; -} - -enum EPercentileCounters { - option (GlobalCounterOpts) = { - Ranges { Value: 0 Name: "0 ms" } - Ranges { Value: 1 Name: "1 ms" } - }; - +} + +enum EPercentileCounters { + option (GlobalCounterOpts) = { + Ranges { Value: 0 Name: "0 ms" } + Ranges { Value: 1 Name: "1 ms" } + }; + COUNTER_PERCENTILE_IGNORE = 0; -} - -enum ETxTypes { - TXTYPE_CREATE_TABLET = 0 [(TxTypeOpts) = {Name: "TxCreateTablet"}]; - TXTYPE_SYNC_TABLETS = 1 [(TxTypeOpts) = {Name: "TxSyncTablets"}]; - TXTYPE_KILL_TABLET = 2 [(TxTypeOpts) = {Name: "TxKillTablet"}]; - TXTYPE_UPDATE_TABLET_GROUP = 3 [(TxTypeOpts) = {Name: "TxUpdateTabletGroup"}]; - TXTYPE_UPDATE_TABLET_STATUS = 4 [(TxTypeOpts) = {Name: "TxUpdateTabletStatus"}]; - TXTYPE_REGISTER_NODE = 5 [(TxTypeOpts) = {Name: "TxRegisterNode"}]; - TXTYPE_KILL_NODE = 6 [(TxTypeOpts) = {Name: "TxKillNode"}]; +} + +enum ETxTypes { + TXTYPE_CREATE_TABLET = 0 [(TxTypeOpts) = {Name: "TxCreateTablet"}]; + TXTYPE_SYNC_TABLETS = 1 [(TxTypeOpts) = {Name: "TxSyncTablets"}]; + TXTYPE_KILL_TABLET = 2 [(TxTypeOpts) = {Name: "TxKillTablet"}]; + TXTYPE_UPDATE_TABLET_GROUP = 3 [(TxTypeOpts) = {Name: "TxUpdateTabletGroup"}]; + TXTYPE_UPDATE_TABLET_STATUS = 4 [(TxTypeOpts) = {Name: "TxUpdateTabletStatus"}]; + TXTYPE_REGISTER_NODE = 5 [(TxTypeOpts) = {Name: "TxRegisterNode"}]; + TXTYPE_KILL_NODE = 6 [(TxTypeOpts) = {Name: "TxKillNode"}]; TXTYPE_ADOPT_TABLET = 7 [(TxTypeOpts) = {Name: "TxAdoptTablet"}]; TXTYPE_UPDATE_TABLET_METRIC = 8 [(TxTypeOpts) = {Name: "TxUpdateTabletMetric"}]; TXTYPE_UPDATE_TABLET_GROUPS = 9 [(TxTypeOpts) = {Name: "TxUpdateTabletGroups"}]; @@ -104,4 +104,4 @@ enum ETxTypes { TXTYPE_STOP_TABLET = 54 [(TxTypeOpts) = {Name: "TxStopTablet"}]; TXTYPE_RESUME_TABLET = 55 [(TxTypeOpts) = {Name: "TxResumeTablet"}]; TXTYPE_RESTART_TABLET = 56 [(TxTypeOpts) = {Name: "TxRestartTablet"}]; -} +} diff --git a/ydb/core/protos/counters_keyvalue.proto b/ydb/core/protos/counters_keyvalue.proto index 973df1d569..3e7655a072 100644 --- a/ydb/core/protos/counters_keyvalue.proto +++ b/ydb/core/protos/counters_keyvalue.proto @@ -1,78 +1,78 @@ import "ydb/core/protos/counters.proto"; - -package NKikimr.NKeyValue; - -option java_package = "ru.yandex.kikimr.proto"; - -option (TabletTypeName) = "KV"; // Used as prefix for all counters - -enum ECumulativeCounters { - COUNTER_REQ_RO = 0 [(CounterOpts) = {Name: "ReqRo"}]; - COUNTER_REQ_RO_OK = 1 [(CounterOpts) = {Name: "ReqRoOk"}]; - COUNTER_REQ_RO_TIMEOUT = 2 [(CounterOpts) = {Name: "ReqRoTimeout"}]; - COUNTER_REQ_RO_OTHER_ERROR = 3 [(CounterOpts) = {Name: "ReqRoOtherError"}]; - - COUNTER_REQ_WO = 4 [(CounterOpts) = {Name: "ReqWo"}]; - COUNTER_REQ_WO_OK = 5 [(CounterOpts) = {Name: "ReqWoOk"}]; - COUNTER_REQ_WO_TIMEOUT = 6 [(CounterOpts) = {Name: "ReqWoTimeout"}]; - COUNTER_REQ_WO_OTHER_ERROR = 7 [(CounterOpts) = {Name: "ReqWoOtherError"}]; - - COUNTER_REQ_RW = 8 [(CounterOpts) = {Name: "ReqRw"}]; - COUNTER_REQ_RW_OK = 9 [(CounterOpts) = {Name: "ReqRwOk"}]; - COUNTER_REQ_RW_TIMEOUT = 10 [(CounterOpts) = {Name: "ReqRwTimeout"}]; - COUNTER_REQ_RW_OTHER_ERROR = 11 [(CounterOpts) = {Name: "ReqRwOtherError"}]; - - COUNTER_REQ_OVERRUN = 12 [(CounterOpts) = {Name: "ReqOverrun"}]; - - COUNTER_CMD_READ_BYTES_OK = 13 [(CounterOpts) = {Name: "CmdReadBytesOk"}]; - COUNTER_CMD_READ_BYTES_TIMEOUT = 14 [(CounterOpts) = {Name: "CmdReadBytesTimeout"}]; - COUNTER_CMD_READ_BYTES_OTHER_ERROR = 15 [(CounterOpts) = {Name: "CmdReadBytesOtherError"}]; - - COUNTER_CMD_READ_OK = 16 [(CounterOpts) = {Name: "CmdReadOk"}]; - COUNTER_CMD_READ_TIMEOUT = 17 [(CounterOpts) = {Name: "CmdReadTimeout"}]; - COUNTER_CMD_READ_OTHER_ERROR = 18 [(CounterOpts) = {Name: "CmdReadOtherError"}]; - COUNTER_CMD_READ_NODATA = 19 [(CounterOpts) = {Name: "CmdReadNodata"}]; - - COUNTER_CMD_DATA_RANGE_READ_BYTES_OK = 20 [(CounterOpts) = {Name: "CmdDataRangeReadBytesOk"}]; - COUNTER_CMD_DATA_RANGE_READ_BYTES_TIMEOUT = 21 [(CounterOpts) = {Name: "CmdDataRangeReadBytesTimeout"}]; - COUNTER_CMD_DATA_RANGE_READ_BYTES_OTHER_ERROR = 22 [(CounterOpts) = {Name: "CmdDataRangeReadBytesOtherError"}]; - - COUNTER_CMD_INDEX_RANGE_READ_OK = 23 [(CounterOpts) = {Name: "CmdIndexRangeReadOk"}]; - COUNTER_CMD_INDEX_RANGE_READ_TIMEOUT = 24 [(CounterOpts) = {Name: "CmdIndexRangeReadTimeout"}]; - COUNTER_CMD_INDEX_RANGE_READ_OTHER_ERROR = 25 [(CounterOpts) = {Name: "CmdIndexRangeReadOtherError"}]; - - COUNTER_CMD_DATA_RANGE_READ_ITEMS_OK = 26 [(CounterOpts) = {Name: "CmdDataRangeReadItemsOk"}]; - COUNTER_CMD_DATA_RANGE_READ_ITEMS_TIMEOUT = 27 [(CounterOpts) = {Name: "CmdDataRangeReadItemsTimeout"}]; - COUNTER_CMD_DATA_RANGE_READ_ITEMS_OTHER_ERROR = 28 [(CounterOpts) = {Name: "CmdDataRangeReadItemsOtherError"}]; - COUNTER_CMD_DATA_RANGE_READ_ITEMS_NODATA = 29 [(CounterOpts) = {Name: "CmdDataRangeReadItemsNodata"}]; - - COUNTER_CMD_DELETE_OK = 30 [(CounterOpts) = {Name: "CmdDeleteOk"}]; - COUNTER_CMD_DELETE_TIMEOUT = 31 [(CounterOpts) = {Name: "CmdDeleteTimeout"}]; - COUNTER_CMD_DELETE_OTHER_ERROR = 32 [(CounterOpts) = {Name: "CmdDeleteOtherError"}]; - - COUNTER_CMD_DELETE_BYTES_OK = 33 [(CounterOpts) = {Name: "CmdDeleteBytesOk"}]; - COUNTER_CMD_DELETE_BYTES_TIMEOUT = 34 [(CounterOpts) = {Name: "CmdDeleteBytesTimeout"}]; - COUNTER_CMD_DELETE_BYTES_OTHER_ERROR = 35 [(CounterOpts) = {Name: "CmdDeleteBytesOtherError"}]; - - COUNTER_CMD_RENAME_OK = 36 [(CounterOpts) = {Name: "CmdRenameOk"}]; - COUNTER_CMD_RENAME_TIMEOUT = 37 [(CounterOpts) = {Name: "CmdRenameTimeout"}]; - COUNTER_CMD_RENAME_OTHER_ERROR = 38 [(CounterOpts) = {Name: "CmdRenameOtherError"}]; - - COUNTER_CMD_WRITE_BYTES_OK = 39 [(CounterOpts) = {Name: "CmdWriteBytesOk"}]; - COUNTER_CMD_WRITE_BYTES_TIMEOUT = 40 [(CounterOpts) = {Name: "CmdWriteBytesTimeout"}]; - COUNTER_CMD_WRITE_BYTES_OTHER_ERROR = 41 [(CounterOpts) = {Name: "CmdWriteBytesOtherError"}]; - - COUNTER_CMD_WRITE_OK = 42 [(CounterOpts) = {Name: "CmdWriteOk"}]; - COUNTER_CMD_WRITE_TIMEOUT = 43 [(CounterOpts) = {Name: "CmdWriteTimeout"}]; - COUNTER_CMD_WRITE_OTHER_ERROR = 44 [(CounterOpts) = {Name: "CmdWriteOtherError"}]; - - COUNTER_CMD_COPY_RANGE_OK = 45 [(CounterOpts) = {Name: "CmdCopyRangeOk"}]; - COUNTER_CMD_COPY_RANGE_TIMEOUT = 46 [(CounterOpts) = {Name: "CmdCopyRangeTimeout"}]; - COUNTER_CMD_COPY_RANGE_OTHER_ERROR = 47 [(CounterOpts) = {Name: "CmdCopyRangeOtherError"}]; - - COUNTER_CMD_GUM_OK = 48 [(CounterOpts) = {Name: "ConcatOk"}]; - COUNTER_CMD_GUM_TIMEOUT = 49 [(CounterOpts) = {Name: "ConcatTimeout"}]; - COUNTER_CMD_GUM_OTHER_ERROR = 50 [(CounterOpts) = {Name: "ConcatOtherError"}]; + +package NKikimr.NKeyValue; + +option java_package = "ru.yandex.kikimr.proto"; + +option (TabletTypeName) = "KV"; // Used as prefix for all counters + +enum ECumulativeCounters { + COUNTER_REQ_RO = 0 [(CounterOpts) = {Name: "ReqRo"}]; + COUNTER_REQ_RO_OK = 1 [(CounterOpts) = {Name: "ReqRoOk"}]; + COUNTER_REQ_RO_TIMEOUT = 2 [(CounterOpts) = {Name: "ReqRoTimeout"}]; + COUNTER_REQ_RO_OTHER_ERROR = 3 [(CounterOpts) = {Name: "ReqRoOtherError"}]; + + COUNTER_REQ_WO = 4 [(CounterOpts) = {Name: "ReqWo"}]; + COUNTER_REQ_WO_OK = 5 [(CounterOpts) = {Name: "ReqWoOk"}]; + COUNTER_REQ_WO_TIMEOUT = 6 [(CounterOpts) = {Name: "ReqWoTimeout"}]; + COUNTER_REQ_WO_OTHER_ERROR = 7 [(CounterOpts) = {Name: "ReqWoOtherError"}]; + + COUNTER_REQ_RW = 8 [(CounterOpts) = {Name: "ReqRw"}]; + COUNTER_REQ_RW_OK = 9 [(CounterOpts) = {Name: "ReqRwOk"}]; + COUNTER_REQ_RW_TIMEOUT = 10 [(CounterOpts) = {Name: "ReqRwTimeout"}]; + COUNTER_REQ_RW_OTHER_ERROR = 11 [(CounterOpts) = {Name: "ReqRwOtherError"}]; + + COUNTER_REQ_OVERRUN = 12 [(CounterOpts) = {Name: "ReqOverrun"}]; + + COUNTER_CMD_READ_BYTES_OK = 13 [(CounterOpts) = {Name: "CmdReadBytesOk"}]; + COUNTER_CMD_READ_BYTES_TIMEOUT = 14 [(CounterOpts) = {Name: "CmdReadBytesTimeout"}]; + COUNTER_CMD_READ_BYTES_OTHER_ERROR = 15 [(CounterOpts) = {Name: "CmdReadBytesOtherError"}]; + + COUNTER_CMD_READ_OK = 16 [(CounterOpts) = {Name: "CmdReadOk"}]; + COUNTER_CMD_READ_TIMEOUT = 17 [(CounterOpts) = {Name: "CmdReadTimeout"}]; + COUNTER_CMD_READ_OTHER_ERROR = 18 [(CounterOpts) = {Name: "CmdReadOtherError"}]; + COUNTER_CMD_READ_NODATA = 19 [(CounterOpts) = {Name: "CmdReadNodata"}]; + + COUNTER_CMD_DATA_RANGE_READ_BYTES_OK = 20 [(CounterOpts) = {Name: "CmdDataRangeReadBytesOk"}]; + COUNTER_CMD_DATA_RANGE_READ_BYTES_TIMEOUT = 21 [(CounterOpts) = {Name: "CmdDataRangeReadBytesTimeout"}]; + COUNTER_CMD_DATA_RANGE_READ_BYTES_OTHER_ERROR = 22 [(CounterOpts) = {Name: "CmdDataRangeReadBytesOtherError"}]; + + COUNTER_CMD_INDEX_RANGE_READ_OK = 23 [(CounterOpts) = {Name: "CmdIndexRangeReadOk"}]; + COUNTER_CMD_INDEX_RANGE_READ_TIMEOUT = 24 [(CounterOpts) = {Name: "CmdIndexRangeReadTimeout"}]; + COUNTER_CMD_INDEX_RANGE_READ_OTHER_ERROR = 25 [(CounterOpts) = {Name: "CmdIndexRangeReadOtherError"}]; + + COUNTER_CMD_DATA_RANGE_READ_ITEMS_OK = 26 [(CounterOpts) = {Name: "CmdDataRangeReadItemsOk"}]; + COUNTER_CMD_DATA_RANGE_READ_ITEMS_TIMEOUT = 27 [(CounterOpts) = {Name: "CmdDataRangeReadItemsTimeout"}]; + COUNTER_CMD_DATA_RANGE_READ_ITEMS_OTHER_ERROR = 28 [(CounterOpts) = {Name: "CmdDataRangeReadItemsOtherError"}]; + COUNTER_CMD_DATA_RANGE_READ_ITEMS_NODATA = 29 [(CounterOpts) = {Name: "CmdDataRangeReadItemsNodata"}]; + + COUNTER_CMD_DELETE_OK = 30 [(CounterOpts) = {Name: "CmdDeleteOk"}]; + COUNTER_CMD_DELETE_TIMEOUT = 31 [(CounterOpts) = {Name: "CmdDeleteTimeout"}]; + COUNTER_CMD_DELETE_OTHER_ERROR = 32 [(CounterOpts) = {Name: "CmdDeleteOtherError"}]; + + COUNTER_CMD_DELETE_BYTES_OK = 33 [(CounterOpts) = {Name: "CmdDeleteBytesOk"}]; + COUNTER_CMD_DELETE_BYTES_TIMEOUT = 34 [(CounterOpts) = {Name: "CmdDeleteBytesTimeout"}]; + COUNTER_CMD_DELETE_BYTES_OTHER_ERROR = 35 [(CounterOpts) = {Name: "CmdDeleteBytesOtherError"}]; + + COUNTER_CMD_RENAME_OK = 36 [(CounterOpts) = {Name: "CmdRenameOk"}]; + COUNTER_CMD_RENAME_TIMEOUT = 37 [(CounterOpts) = {Name: "CmdRenameTimeout"}]; + COUNTER_CMD_RENAME_OTHER_ERROR = 38 [(CounterOpts) = {Name: "CmdRenameOtherError"}]; + + COUNTER_CMD_WRITE_BYTES_OK = 39 [(CounterOpts) = {Name: "CmdWriteBytesOk"}]; + COUNTER_CMD_WRITE_BYTES_TIMEOUT = 40 [(CounterOpts) = {Name: "CmdWriteBytesTimeout"}]; + COUNTER_CMD_WRITE_BYTES_OTHER_ERROR = 41 [(CounterOpts) = {Name: "CmdWriteBytesOtherError"}]; + + COUNTER_CMD_WRITE_OK = 42 [(CounterOpts) = {Name: "CmdWriteOk"}]; + COUNTER_CMD_WRITE_TIMEOUT = 43 [(CounterOpts) = {Name: "CmdWriteTimeout"}]; + COUNTER_CMD_WRITE_OTHER_ERROR = 44 [(CounterOpts) = {Name: "CmdWriteOtherError"}]; + + COUNTER_CMD_COPY_RANGE_OK = 45 [(CounterOpts) = {Name: "CmdCopyRangeOk"}]; + COUNTER_CMD_COPY_RANGE_TIMEOUT = 46 [(CounterOpts) = {Name: "CmdCopyRangeTimeout"}]; + COUNTER_CMD_COPY_RANGE_OTHER_ERROR = 47 [(CounterOpts) = {Name: "CmdCopyRangeOtherError"}]; + + COUNTER_CMD_GUM_OK = 48 [(CounterOpts) = {Name: "ConcatOk"}]; + COUNTER_CMD_GUM_TIMEOUT = 49 [(CounterOpts) = {Name: "ConcatTimeout"}]; + COUNTER_CMD_GUM_OTHER_ERROR = 50 [(CounterOpts) = {Name: "ConcatOtherError"}]; COUNTER_READ_BYTES_CHANNEL_0 = 51 [(CounterOpts) = {Name: "ReadBytesChannel0"}]; COUNTER_READ_BYTES_CHANNEL_1 = 52 [(CounterOpts) = {Name: "ReadBytesChannel1"}]; @@ -107,65 +107,65 @@ enum ECumulativeCounters { COUNTER_WRITE_BYTES_CHANNEL_13 = 80 [(CounterOpts) = {Name: "WriteBytesChannel13"}]; COUNTER_WRITE_BYTES_CHANNEL_14 = 81 [(CounterOpts) = {Name: "WriteBytesChannel14"}]; COUNTER_WRITE_BYTES_CHANNEL_15 = 82 [(CounterOpts) = {Name: "WriteBytesChannel15"}]; -} - -enum ESimpleCounters { - COUNTER_RECORD_COUNT = 0 [(CounterOpts) = {Name: "RecordCount"}]; - COUNTER_RECORD_BYTES = 1 [(CounterOpts) = {Name: "RecordBytes"}]; - COUNTER_TRASH_COUNT = 2 [(CounterOpts) = {Name: "TrashCount"}]; - COUNTER_TRASH_BYTES = 3 [(CounterOpts) = {Name: "TrashBytes"}]; - - COUNTER_REQ_WO_IN_FLY = 4 [(CounterOpts) = {Name: "ReqWoInFly"}]; - COUNTER_REQ_WO_QUEUED = 5 [(CounterOpts) = {Name: "ReqWoQueued"}]; - - COUNTER_REQ_RO_RW_IN_FLY = 6 [(CounterOpts) = {Name: "ReqRoRwInFly"}]; - COUNTER_REQ_RO_RW_QUEUED = 7 [(CounterOpts) = {Name: "ReqRoRwQueued"}]; - - COUNTER_STATE_STARTING = 8 [(CounterOpts) = {Name: "StateStarting"}]; - COUNTER_STATE_PROCESSING_INIT_QUEUE = 9 [(CounterOpts) = {Name: "StateProcessingInitQueue"}]; - COUNTER_STATE_ONLINE = 10 [(CounterOpts) = {Name: "StateOnline"}]; +} + +enum ESimpleCounters { + COUNTER_RECORD_COUNT = 0 [(CounterOpts) = {Name: "RecordCount"}]; + COUNTER_RECORD_BYTES = 1 [(CounterOpts) = {Name: "RecordBytes"}]; + COUNTER_TRASH_COUNT = 2 [(CounterOpts) = {Name: "TrashCount"}]; + COUNTER_TRASH_BYTES = 3 [(CounterOpts) = {Name: "TrashBytes"}]; + + COUNTER_REQ_WO_IN_FLY = 4 [(CounterOpts) = {Name: "ReqWoInFly"}]; + COUNTER_REQ_WO_QUEUED = 5 [(CounterOpts) = {Name: "ReqWoQueued"}]; + + COUNTER_REQ_RO_RW_IN_FLY = 6 [(CounterOpts) = {Name: "ReqRoRwInFly"}]; + COUNTER_REQ_RO_RW_QUEUED = 7 [(CounterOpts) = {Name: "ReqRoRwQueued"}]; + + COUNTER_STATE_STARTING = 8 [(CounterOpts) = {Name: "StateStarting"}]; + COUNTER_STATE_PROCESSING_INIT_QUEUE = 9 [(CounterOpts) = {Name: "StateProcessingInitQueue"}]; + COUNTER_STATE_ONLINE = 10 [(CounterOpts) = {Name: "StateOnline"}]; COUNTER_REQ_RO_INLINE_IN_FLY = 11 [(CounterOpts) = {Name: "ReqRoInlineInFly"}]; COUNTER_REQ_AGE_MS = 12 [(CounterOpts) = {Name: "ReqAgeMs"}]; -} - -enum EPercentileCounters { - option (GlobalCounterOpts) = { - Ranges { Value: 0 Name: "0 ms" } - Ranges { Value: 50 Name: "50 ms" } - Ranges { Value: 100 Name: "100 ms" } - Ranges { Value: 200 Name: "200 ms" } - Ranges { Value: 300 Name: "300 ms" } - Ranges { Value: 400 Name: "400 ms" } - Ranges { Value: 500 Name: "500 ms" } - Ranges { Value: 750 Name: "750 ms" } - Ranges { Value: 1000 Name: "1000 ms" } - Ranges { Value: 1500 Name: "1500 ms" } - Ranges { Value: 2000 Name: "2000 ms" } - Ranges { Value: 5000 Name: "5000 ms" } - Ranges { Value: 10000 Name: "10000 ms" } - Ranges { Value: 20000 Name: "20000 ms" } - Ranges { Value: 30000 Name: "30000 ms" } - Ranges { Value: 60000 Name: "60000 ms" } - Ranges { Value: 120000 Name: "120000 ms" } - }; - - COUNTER_LATENCY_BS_GET = 0 [(CounterOpts) = {Name: "LatencyBsGet"}]; - COUNTER_LATENCY_BS_PUT = 1 [(CounterOpts) = {Name: "LatencyBsPut"}]; - COUNTER_LATENCY_BS_COLLECT = 2 [(CounterOpts) = {Name: "LatencyBsCollect"}]; - - COUNTER_LATENCY_BS_OPS = 3 [(CounterOpts) = {Name: "LatencyBsOps"}]; - - COUNTER_LATENCY_LOCAL_BASE_WO = 4 [(CounterOpts) = {Name: "LatencyLocalBaseWo"}]; - COUNTER_LATENCY_LOCAL_BASE_RW = 5 [(CounterOpts) = {Name: "LatencyLocalBaseRw"}]; - - COUNTER_LATENCY_QUEUE_WO = 6 [(CounterOpts) = {Name: "LatencyQueueWo"}]; - COUNTER_LATENCY_QUEUE_RO_RW = 7 [(CounterOpts) = {Name: "LatencyQueueRoRw"}]; - - COUNTER_LATENCY_FULL_RO = 8 [(CounterOpts) = {Name: "LatencyFullRo"}]; - COUNTER_LATENCY_FULL_WO = 9 [(CounterOpts) = {Name: "LatencyFullWo"}]; - COUNTER_LATENCY_FULL_RW = 10 [(CounterOpts) = {Name: "LatencyFullRw"}]; +} + +enum EPercentileCounters { + option (GlobalCounterOpts) = { + Ranges { Value: 0 Name: "0 ms" } + Ranges { Value: 50 Name: "50 ms" } + Ranges { Value: 100 Name: "100 ms" } + Ranges { Value: 200 Name: "200 ms" } + Ranges { Value: 300 Name: "300 ms" } + Ranges { Value: 400 Name: "400 ms" } + Ranges { Value: 500 Name: "500 ms" } + Ranges { Value: 750 Name: "750 ms" } + Ranges { Value: 1000 Name: "1000 ms" } + Ranges { Value: 1500 Name: "1500 ms" } + Ranges { Value: 2000 Name: "2000 ms" } + Ranges { Value: 5000 Name: "5000 ms" } + Ranges { Value: 10000 Name: "10000 ms" } + Ranges { Value: 20000 Name: "20000 ms" } + Ranges { Value: 30000 Name: "30000 ms" } + Ranges { Value: 60000 Name: "60000 ms" } + Ranges { Value: 120000 Name: "120000 ms" } + }; + + COUNTER_LATENCY_BS_GET = 0 [(CounterOpts) = {Name: "LatencyBsGet"}]; + COUNTER_LATENCY_BS_PUT = 1 [(CounterOpts) = {Name: "LatencyBsPut"}]; + COUNTER_LATENCY_BS_COLLECT = 2 [(CounterOpts) = {Name: "LatencyBsCollect"}]; + + COUNTER_LATENCY_BS_OPS = 3 [(CounterOpts) = {Name: "LatencyBsOps"}]; + + COUNTER_LATENCY_LOCAL_BASE_WO = 4 [(CounterOpts) = {Name: "LatencyLocalBaseWo"}]; + COUNTER_LATENCY_LOCAL_BASE_RW = 5 [(CounterOpts) = {Name: "LatencyLocalBaseRw"}]; + + COUNTER_LATENCY_QUEUE_WO = 6 [(CounterOpts) = {Name: "LatencyQueueWo"}]; + COUNTER_LATENCY_QUEUE_RO_RW = 7 [(CounterOpts) = {Name: "LatencyQueueRoRw"}]; + + COUNTER_LATENCY_FULL_RO = 8 [(CounterOpts) = {Name: "LatencyFullRo"}]; + COUNTER_LATENCY_FULL_WO = 9 [(CounterOpts) = {Name: "LatencyFullWo"}]; + COUNTER_LATENCY_FULL_RW = 10 [(CounterOpts) = {Name: "LatencyFullRw"}]; COUNTER_LATENCY_FULL_RO_INLINE = 11 [(CounterOpts) = {Name: "LatencyFullRoInline"}]; COUNTER_HIST_READ_BYTES_CHANNEL_0 = 12 [(CounterOpts) = {Name: "HIST(KV/ReadBytesChannel0)" @@ -968,10 +968,10 @@ enum EPercentileCounters { } ]; -} - -enum ETxTypes { - TXTYPE_INIT = 0 [(TxTypeOpts) = {Name: "TxInit"}]; - TXTYPE_REQUEST = 1 [(TxTypeOpts) = {Name: "TxRequest"}]; -} - +} + +enum ETxTypes { + TXTYPE_INIT = 0 [(TxTypeOpts) = {Name: "TxInit"}]; + TXTYPE_REQUEST = 1 [(TxTypeOpts) = {Name: "TxRequest"}]; +} + diff --git a/ydb/core/protos/counters_schemeshard.proto b/ydb/core/protos/counters_schemeshard.proto index a839915c98..24114c1c25 100644 --- a/ydb/core/protos/counters_schemeshard.proto +++ b/ydb/core/protos/counters_schemeshard.proto @@ -1,12 +1,12 @@ import "ydb/core/protos/counters.proto"; - + package NKikimr.NSchemeShard; - -option java_package = "ru.yandex.kikimr.proto"; - -option (TabletTypeName) = "SchemeShard"; // Used as prefix for all counters - -enum ESimpleCounters { + +option java_package = "ru.yandex.kikimr.proto"; + +option (TabletTypeName) = "SchemeShard"; // Used as prefix for all counters + +enum ESimpleCounters { COUNTER_SIMPLE_IGNORE = 0; COUNTER_RESPONSE_TIME_USEC = 1 [(CounterOpts) = {Name: "ResponseTimeMicrosec"}]; @@ -148,9 +148,9 @@ enum ESimpleCounters { COUNTER_IN_FLIGHT_OPS_TxCreateReplication = 120 [(CounterOpts) = {Name: "InFlightOps/CreateReplication"}]; COUNTER_IN_FLIGHT_OPS_TxAlterReplication = 121 [(CounterOpts) = {Name: "InFlightOps/AlterReplication"}]; COUNTER_IN_FLIGHT_OPS_TxDropReplication = 122 [(CounterOpts) = {Name: "InFlightOps/DropReplication"}]; -} - -enum ECumulativeCounters { +} + +enum ECumulativeCounters { COUNTER_CUMULATIVE_IGNORE = 0; COUNTER_FINISHED_OPS_TxInvalid = 1 [(CounterOpts) = {Name: "FinishedOps/Invalid"}]; @@ -235,10 +235,10 @@ enum ECumulativeCounters { COUNTER_FINISHED_OPS_TxCreateReplication = 70 [(CounterOpts) = {Name: "FinishedOps/CreateReplication"}]; COUNTER_FINISHED_OPS_TxAlterReplication = 71 [(CounterOpts) = {Name: "FinishedOps/AlterReplication"}]; COUNTER_FINISHED_OPS_TxDropReplication = 72 [(CounterOpts) = {Name: "FinishedOps/DropReplication"}]; -} - -enum EPercentileCounters { - option (GlobalCounterOpts) = { +} + +enum EPercentileCounters { + option (GlobalCounterOpts) = { Ranges { Value: 0 Name: "(1) < 500 us" } Ranges { Value: 500 Name: "(2) 0.5-1 ms" } Ranges { Value: 1000 Name: "(3) 1-2 ms" } @@ -257,8 +257,8 @@ enum EPercentileCounters { Ranges { Value: 8000000 Name: "(16) 8-16 s" } Ranges { Value: 16000000 Name: "(17) 16-32 s" } Ranges { Value: 32000000 Name: "(18) 32 < s" } - }; - + }; + COUNTER_BACKGROUND_COMPACTION_OK_LATENCY = 0 [(CounterOpts) = {Name: "BackgroundCompactionOkLatency"}]; COUNTER_NUM_SHARDS_BY_TTL_LAG = 1 [(CounterOpts) = { @@ -274,12 +274,12 @@ enum EPercentileCounters { Ranges { Value: 57600 Name: "57600" } Ranges { Value: 86400 Name: "inf" } }]; -} - -enum ETxTypes { - TXTYPE_INIT = 0 [(TxTypeOpts) = {Name: "TxInit"}]; - TXTYPE_INIT_ROOT = 1 [(TxTypeOpts) = {Name: "TxInitRoot"}]; - TXTYPE_PLAN_STEP = 2 [(TxTypeOpts) = {Name: "TxPlanStep"}]; +} + +enum ETxTypes { + TXTYPE_INIT = 0 [(TxTypeOpts) = {Name: "TxInit"}]; + TXTYPE_INIT_ROOT = 1 [(TxTypeOpts) = {Name: "TxInitRoot"}]; + TXTYPE_PLAN_STEP = 2 [(TxTypeOpts) = {Name: "TxPlanStep"}]; TXTYPE_DESCRIBE_SCHEME = 3 [(TxTypeOpts) = {Name: "TxDescribeScheme"}]; TXTYPE_DATASHARD_PROPOSE_RESULT = 4 [(TxTypeOpts) = {Name: "TxDataShardProposeResult"}]; TXTYPE_CREATE_TABLET_REPLY = 5 [(TxTypeOpts) = {Name: "TxCreateTabletReply"}]; @@ -369,4 +369,4 @@ enum ETxTypes { TXTYPE_CREATE_REPLICATION_RESULT = 74 [(TxTypeOpts) = {Name: "TxCreateReplicationResult"}]; TXTYPE_ALTER_REPLICATION_RESULT = 75 [(TxTypeOpts) = {Name: "TxAlterReplicationResult"}]; TXTYPE_DROP_REPLICATION_RESULT = 76 [(TxTypeOpts) = {Name: "TxDropReplicationResult"}]; -} +} diff --git a/ydb/core/protos/counters_tx_proxy.proto b/ydb/core/protos/counters_tx_proxy.proto index 476321f88a..35beb13dd3 100644 --- a/ydb/core/protos/counters_tx_proxy.proto +++ b/ydb/core/protos/counters_tx_proxy.proto @@ -1,29 +1,29 @@ import "ydb/core/protos/counters.proto"; - -package NKikimr.NTxProxy; - -option java_package = "ru.yandex.kikimr.proto"; - -option (TabletTypeName) = "TxProxy"; // Used as prefix for all counters - -enum ESimpleCounters { + +package NKikimr.NTxProxy; + +option java_package = "ru.yandex.kikimr.proto"; + +option (TabletTypeName) = "TxProxy"; // Used as prefix for all counters + +enum ESimpleCounters { COUNTER_SIMPLE_IGNORE = 0; -} - -enum ECumulativeCounters { +} + +enum ECumulativeCounters { COUNTER_CUMULATIVE_IGNORE = 0; -} - -enum EPercentileCounters { - option (GlobalCounterOpts) = { - Ranges { Value: 0 Name: "0 ms" } - Ranges { Value: 1 Name: "1 ms" } - }; - +} + +enum EPercentileCounters { + option (GlobalCounterOpts) = { + Ranges { Value: 0 Name: "0 ms" } + Ranges { Value: 1 Name: "1 ms" } + }; + COUNTER_PERCENTILE_IGNORE = 0; -} - -enum ETxTypes { - TXTYPE_INIT = 0 [(TxTypeOpts) = {Name: "TxInit"}]; - TXTYPE_RESERVE_IDS = 1 [(TxTypeOpts) = {Name: "TxReserveIds"}]; -} +} + +enum ETxTypes { + TXTYPE_INIT = 0 [(TxTypeOpts) = {Name: "TxInit"}]; + TXTYPE_RESERVE_IDS = 1 [(TxTypeOpts) = {Name: "TxReserveIds"}]; +} diff --git a/ydb/core/protos/kesus.proto b/ydb/core/protos/kesus.proto index 7c03a3ccd9..68eac744ee 100644 --- a/ydb/core/protos/kesus.proto +++ b/ydb/core/protos/kesus.proto @@ -247,75 +247,75 @@ message TEvSessionStolen { // // Quoter control API. // -message TAccountingConfig { - // Account consumed resources and send billing metrics. - // Default value is false (not inherited). - bool Enabled = 1; - - // Period to report consumption history from clients to kesus - // Default value is inherited from parent or equals 5000 ms for root. - uint64 ReportPeriodMs = 2; - - // Consumption history period that is sent in one message to accounting actor. - // Default value is inherited from parent or equals 1000 ms for root. - uint64 AccountPeriodMs = 3; - - // Time window to collect data from every client. - // Any client account message that is `CollectPeriod` late is discarded (not accounted or billed). - // Default value is inherited from parent or equals 30 seconds for root. - uint64 CollectPeriodSec = 4; - - // Provisioned consumption limit in units per second. - // Effective value is limited by corresponding MaxUnitsPerSecond. - // Default value is 0 (not inherited). - double ProvisionedUnitsPerSecond = 5; - - // Provisioned allowed burst equals ProvisionedCoefficient*ProvisionedUnitsPerSecond units. - // Effective value is limited by corresponding PrefetchCoefficient. - // Default value is inherited from parent or equals 60 for root. - double ProvisionedCoefficient = 6; - - // On-demand allowed burst equals OvershootCoefficient*PrefetchCoefficient*MaxUnitsPerSecond units. - // Should be greater or equal to 1.0 - // Default value is inherited from parent or equals 1.1 for root - double OvershootCoefficient = 7; - - // Billing metric description. - message TMetric { - // Send this metric to billing. - // Default value is false (not inherited). - bool Enabled = 1; - - // Billing metric period (aligned to hour boundary). - // Default value is inherited from parent or equals 60 seconds for root. - uint64 BillingPeriodSec = 2; - - // Billing metric JSON fields (inherited from parent if not set) - string Version = 3; - string Schema = 5; - string CloudId = 6; - string FolderId = 7; - string ResourceId = 8; - string SourceId = 9; - map<string, string> Tags = 10; - } - - // Consumption within provisioned limit. - // Informative metric that should be sent to billing (not billed). - TMetric Provisioned = 8; - - // Consumption that exceeds provisioned limit is billed as on-demand. - TMetric OnDemand = 9; - - // Consumption that exceeds even on-demand limit. - // Normally it is free and should not be billed. - TMetric Overshoot = 10; -} - +message TAccountingConfig { + // Account consumed resources and send billing metrics. + // Default value is false (not inherited). + bool Enabled = 1; + + // Period to report consumption history from clients to kesus + // Default value is inherited from parent or equals 5000 ms for root. + uint64 ReportPeriodMs = 2; + + // Consumption history period that is sent in one message to accounting actor. + // Default value is inherited from parent or equals 1000 ms for root. + uint64 AccountPeriodMs = 3; + + // Time window to collect data from every client. + // Any client account message that is `CollectPeriod` late is discarded (not accounted or billed). + // Default value is inherited from parent or equals 30 seconds for root. + uint64 CollectPeriodSec = 4; + + // Provisioned consumption limit in units per second. + // Effective value is limited by corresponding MaxUnitsPerSecond. + // Default value is 0 (not inherited). + double ProvisionedUnitsPerSecond = 5; + + // Provisioned allowed burst equals ProvisionedCoefficient*ProvisionedUnitsPerSecond units. + // Effective value is limited by corresponding PrefetchCoefficient. + // Default value is inherited from parent or equals 60 for root. + double ProvisionedCoefficient = 6; + + // On-demand allowed burst equals OvershootCoefficient*PrefetchCoefficient*MaxUnitsPerSecond units. + // Should be greater or equal to 1.0 + // Default value is inherited from parent or equals 1.1 for root + double OvershootCoefficient = 7; + + // Billing metric description. + message TMetric { + // Send this metric to billing. + // Default value is false (not inherited). + bool Enabled = 1; + + // Billing metric period (aligned to hour boundary). + // Default value is inherited from parent or equals 60 seconds for root. + uint64 BillingPeriodSec = 2; + + // Billing metric JSON fields (inherited from parent if not set) + string Version = 3; + string Schema = 5; + string CloudId = 6; + string FolderId = 7; + string ResourceId = 8; + string SourceId = 9; + map<string, string> Tags = 10; + } + + // Consumption within provisioned limit. + // Informative metric that should be sent to billing (not billed). + TMetric Provisioned = 8; + + // Consumption that exceeds provisioned limit is billed as on-demand. + TMetric OnDemand = 9; + + // Consumption that exceeds even on-demand limit. + // Normally it is free and should not be billed. + TMetric Overshoot = 10; +} + message THierarchicalDRRResourceConfig { // Resource consumption speed limit. // Value is required for root resource. - // 0 is equivalent to not set (inherit value from parent). + // 0 is equivalent to not set (inherit value from parent). // Must be nonnegative. double MaxUnitsPerSecond = 3; @@ -332,16 +332,16 @@ message THierarchicalDRRResourceConfig { // Default value is 1. uint32 Weight = 5; - // Prefetch in local bucket up to PrefetchCoefficient*MaxUnitsPerSecond units (full size). - // Default value is inherited from parent or equals 0.2 for root. - // Disables prefetching if any negative value is set - // (It is useful to avoid bursts in case of large number of local buckets). - double PrefetchCoefficient = 6; + // Prefetch in local bucket up to PrefetchCoefficient*MaxUnitsPerSecond units (full size). + // Default value is inherited from parent or equals 0.2 for root. + // Disables prefetching if any negative value is set + // (It is useful to avoid bursts in case of large number of local buckets). + double PrefetchCoefficient = 6; - // Prefetching starts if there is less than PrefetchWatermark fraction of full local bucket left. - // Default value is inherited from parent or equals 0.75 for root. - // Must be nonnegative and less than or equal to 1. - double PrefetchWatermark = 7; + // Prefetching starts if there is less than PrefetchWatermark fraction of full local bucket left. + // Default value is inherited from parent or equals 0.75 for root. + // Must be nonnegative and less than or equal to 1. + double PrefetchWatermark = 7; // deprecated settings { message TSpeedSettings { @@ -364,7 +364,7 @@ message TStreamingQuoterResource { // For Hierarhical DRR algorithm. THierarchicalDRRResourceConfig HierarhicalDRRResourceConfig = 3; } - TAccountingConfig AccountingConfig = 4; + TAccountingConfig AccountingConfig = 4; } message TEvDescribeQuoterResources { @@ -430,7 +430,7 @@ message TEvSubscribeOnResourcesResult { TKesusError Error = 2; TStreamingQuoterResource EffectiveProps = 3; } - repeated TResourceSubscribeResult Results = 1; // Resources are in the same order that they were specified in request. + repeated TResourceSubscribeResult Results = 1; // Resources are in the same order that they were specified in request. } // Notification about resources consumption state update. @@ -478,26 +478,26 @@ message TEvGetQuoterResourceCountersResult { repeated TResourceCounters ResourceCounters = 1; } - -// Account consumed resources into metering. -// Event is sent from client to Kesus. -message TEvAccountResources { - message TResourceInfo { - uint64 ResourceId = 1; - uint64 StartUs = 2; // The first interval start time in microseconds since epoch - uint64 IntervalUs = 3; // Intervals duration in microseconds - repeated double Amount = 4; // Amounts of resources consumed during intervals - } - repeated TResourceInfo ResourcesInfo = 1; - NActorsProto.TActorId ActorID = 2; -} - -// Ack for TEvAccountResources event. -message TEvAccountResourcesAck { - message TResourceInfo { - uint64 ResourceId = 1; - uint64 AcceptedUs = 2; // Timestamp to drop client's data before (i.e. StartUs for the next request) - TKesusError StateNotification = 4; // Resource can be deleted before accounting. In this case Kesus will send an error for resource. - } - repeated TResourceInfo ResourcesInfo = 1; -} + +// Account consumed resources into metering. +// Event is sent from client to Kesus. +message TEvAccountResources { + message TResourceInfo { + uint64 ResourceId = 1; + uint64 StartUs = 2; // The first interval start time in microseconds since epoch + uint64 IntervalUs = 3; // Intervals duration in microseconds + repeated double Amount = 4; // Amounts of resources consumed during intervals + } + repeated TResourceInfo ResourcesInfo = 1; + NActorsProto.TActorId ActorID = 2; +} + +// Ack for TEvAccountResources event. +message TEvAccountResourcesAck { + message TResourceInfo { + uint64 ResourceId = 1; + uint64 AcceptedUs = 2; // Timestamp to drop client's data before (i.e. StartUs for the next request) + TKesusError StateNotification = 4; // Resource can be deleted before accounting. In this case Kesus will send an error for resource. + } + repeated TResourceInfo ResourcesInfo = 1; +} diff --git a/ydb/core/protos/node_whiteboard.proto b/ydb/core/protos/node_whiteboard.proto index b96713ca29..91a4da73dc 100644 --- a/ydb/core/protos/node_whiteboard.proto +++ b/ydb/core/protos/node_whiteboard.proto @@ -108,8 +108,8 @@ message TPDiskStateInfo { optional NKikimrBlobStorage.TPDiskState.E State = 9; optional uint32 NodeId = 10; // filled during merge optional uint32 Count = 13; // filled during group count - optional EFlag Device = 14; - optional EFlag Realtime = 15; + optional EFlag Device = 14; + optional EFlag Realtime = 15; // State as flag - to be filled optional EFlag StateFlag = 16; // overall state - to be filled diff --git a/ydb/core/protos/services.proto b/ydb/core/protos/services.proto index c17c8a7dc3..730c47e0a9 100644 --- a/ydb/core/protos/services.proto +++ b/ydb/core/protos/services.proto @@ -847,7 +847,7 @@ message TActivity { YQL_PRIVATE_GET_TASK_ACTOR = 541; YQL_PRIVATE_WRITE_TASK_ACTOR = 542; YQL_NODES_MANAGER_ACTOR = 543; - KESUS_ACCOUNTING_ACTOR = 544; + KESUS_ACCOUNTING_ACTOR = 544; BLOCKSTORE_PARTITION_COMMON = 545; INTERCONNECT_PROXY_WRAPPER = 546; CLOUD_STORAGE_HIVE_PROXY = 547; diff --git a/ydb/core/protos/ya.make b/ydb/core/protos/ya.make index 70bb65514c..4ec5eb2259 100644 --- a/ydb/core/protos/ya.make +++ b/ydb/core/protos/ya.make @@ -38,22 +38,22 @@ SRCS( console_tenant.proto counters_tx_allocator.proto counters_bs_controller.proto - counters_coordinator.proto + counters_coordinator.proto counters_columnshard.proto - counters_datashard.proto - counters_hive.proto + counters_datashard.proto + counters_hive.proto counters_kesus.proto - counters_keyvalue.proto + counters_keyvalue.proto counters_olapshard.proto counters_pq.proto counters_replication.proto - counters_schemeshard.proto + counters_schemeshard.proto counters_sequenceshard.proto counters_sysview_processor.proto counters_testshard.proto - counters_tx_proxy.proto + counters_tx_proxy.proto counters_mediator.proto - counters.proto + counters.proto database_basic_sausage_metainfo.proto drivemodel.proto export.proto diff --git a/ydb/core/quoter/kesus_quoter_proxy.cpp b/ydb/core/quoter/kesus_quoter_proxy.cpp index 4d2d20691e..f9993cd19e 100644 --- a/ydb/core/quoter/kesus_quoter_proxy.cpp +++ b/ydb/core/quoter/kesus_quoter_proxy.cpp @@ -41,8 +41,8 @@ namespace NKikimr { namespace NQuoter { static constexpr double FADING_ALLOCATION_COEFFICIENT = 0.999; -static constexpr double PREFETCH_COEFFICIENT_DEFAULT = 0.20; -static constexpr double PREFETCH_WATERMARK_DEFAULT = 0.75; +static constexpr double PREFETCH_COEFFICIENT_DEFAULT = 0.20; +static constexpr double PREFETCH_WATERMARK_DEFAULT = 0.75; using NKesus::TEvKesus; @@ -65,12 +65,12 @@ class TKesusQuoterProxy : public TActorBootstrapped<TKesusQuoterProxy> { TKesusResourceAllocationStatistics AllocStats; - THolder<TTimeSeriesVec<double>> History; - bool PendingReport = false; // History contains data to send - TInstant HistoryAccepted; // Do not report history before this instant - TInstant LastReport; // Aligned to `ReportPeriod` grid timestamp of last sent report - TDuration ReportPeriod = TDuration::Max(); - + THolder<TTimeSeriesVec<double>> History; + bool PendingReport = false; // History contains data to send + TInstant HistoryAccepted; // Do not report history before this instant + TInstant LastReport; // Aligned to `ReportPeriod` grid timestamp of last sent report + TDuration ReportPeriod = TDuration::Max(); + struct TCounters { class TDoubleCounter { public: @@ -163,19 +163,19 @@ class TKesusQuoterProxy : public TActorBootstrapped<TKesusQuoterProxy> { void SetProps(const NKikimrKesus::TStreamingQuoterResource& props) { Props = props; - const auto& cfg = Props.GetHierarhicalDRRResourceConfig(); - const double speed = cfg.GetMaxUnitsPerSecond(); - const double prefetch = cfg.GetPrefetchCoefficient() ? cfg.GetPrefetchCoefficient() : PREFETCH_COEFFICIENT_DEFAULT; - const double watermark = std::clamp(cfg.GetPrefetchWatermark() ? cfg.GetPrefetchWatermark() : PREFETCH_WATERMARK_DEFAULT, 0.0, 1.0); - - const double prevBucketMaxSize = ResourceBucketMaxSize; - ResourceBucketMaxSize = Max(0.0, speed * prefetch); - ResourceBucketMinSize = ResourceBucketMaxSize * watermark; - Y_VERIFY(ResourceBucketMinSize <= ResourceBucketMaxSize); - - // Decrease available resource if speed or prefetch settings have been changed. - if (prefetch > 0.0) { // https://st.yandex-team.ru/RTMR-3774 - if (InitedProps && ResourceBucketMaxSize < prevBucketMaxSize) { + const auto& cfg = Props.GetHierarhicalDRRResourceConfig(); + const double speed = cfg.GetMaxUnitsPerSecond(); + const double prefetch = cfg.GetPrefetchCoefficient() ? cfg.GetPrefetchCoefficient() : PREFETCH_COEFFICIENT_DEFAULT; + const double watermark = std::clamp(cfg.GetPrefetchWatermark() ? cfg.GetPrefetchWatermark() : PREFETCH_WATERMARK_DEFAULT, 0.0, 1.0); + + const double prevBucketMaxSize = ResourceBucketMaxSize; + ResourceBucketMaxSize = Max(0.0, speed * prefetch); + ResourceBucketMinSize = ResourceBucketMaxSize * watermark; + Y_VERIFY(ResourceBucketMinSize <= ResourceBucketMaxSize); + + // Decrease available resource if speed or prefetch settings have been changed. + if (prefetch > 0.0) { // https://st.yandex-team.ru/RTMR-3774 + if (InitedProps && ResourceBucketMaxSize < prevBucketMaxSize) { if (const double maxAvailable = ResourceBucketMaxSize + QueueWeight; Available > maxAvailable) { if (Counters.Dropped) { const double dropped = Available - maxAvailable; @@ -186,18 +186,18 @@ class TKesusQuoterProxy : public TActorBootstrapped<TKesusQuoterProxy> { } } - if (Props.GetAccountingConfig().GetEnabled()) { - ReportPeriod = TDuration::MilliSeconds(Props.GetAccountingConfig().GetReportPeriodMs()); - THolder<TTimeSeriesVec<double>> history(new TTimeSeriesVec<double>(Props.GetAccountingConfig().GetCollectPeriodSec())); - if (History) { - history->Add(*History.Get()); - } - History.Reset(history.Release()); - } else { - ReportPeriod = TDuration::Max(); - History.Destroy(); - } - + if (Props.GetAccountingConfig().GetEnabled()) { + ReportPeriod = TDuration::MilliSeconds(Props.GetAccountingConfig().GetReportPeriodMs()); + THolder<TTimeSeriesVec<double>> history(new TTimeSeriesVec<double>(Props.GetAccountingConfig().GetCollectPeriodSec())); + if (History) { + history->Add(*History.Get()); + } + History.Reset(history.Release()); + } else { + ReportPeriod = TDuration::Max(); + History.Destroy(); + } + if (!InitedProps) { InitedProps = true; SetAvailable(ResourceBucketMaxSize); @@ -260,7 +260,7 @@ class TKesusQuoterProxy : public TActorBootstrapped<TKesusQuoterProxy> { ui64 NextCookie = 1; THolder<NKesus::TEvKesus::TEvUpdateConsumptionState> UpdateEv; - THolder<NKesus::TEvKesus::TEvAccountResources> AccountEv; + THolder<NKesus::TEvKesus::TEvAccountResources> AccountEv; THolder<TEvQuota::TEvProxyUpdate> ProxyUpdateEv; THashMap<TDuration, THolder<TEvPrivate::TEvOfflineResourceAllocation>> OfflineAllocationEvSchedule; @@ -438,13 +438,13 @@ private: } } - void InitAccountEv() { - if (!AccountEv) { - AccountEv = MakeHolder<NKesus::TEvKesus::TEvAccountResources>(); - ActorIdToProto(SelfId(), AccountEv->Record.MutableActorID()); - } - } - + void InitAccountEv() { + if (!AccountEv) { + AccountEv = MakeHolder<NKesus::TEvKesus::TEvAccountResources>(); + ActorIdToProto(SelfId(), AccountEv->Record.MutableActorID()); + } + } + void SendDeferredEvents() { if (Connected && UpdateEv) { KESUS_PROXY_LOG_TRACE("UpdateConsumptionState(" << UpdateEv->Record << ")"); @@ -452,12 +452,12 @@ private: } UpdateEv.Reset(); - if (Connected && AccountEv && AccountEv->Record.GetResourcesInfo().size() > 0) { - KESUS_PROXY_LOG_TRACE("AccountResources(" << AccountEv->Record << ")"); - NTabletPipe::SendData(SelfId(), KesusPipeClient, AccountEv.Release()); - } - AccountEv.Reset(); - + if (Connected && AccountEv && AccountEv->Record.GetResourcesInfo().size() > 0) { + KESUS_PROXY_LOG_TRACE("AccountResources(" << AccountEv->Record << ")"); + NTabletPipe::SendData(SelfId(), KesusPipeClient, AccountEv.Release()); + } + AccountEv.Reset(); + if (ProxyUpdateEv && ProxyUpdateEv->Resources) { SendToService(std::move(ProxyUpdateEv)); } @@ -537,39 +537,39 @@ private: } } - void ReportSession(TResourceState& res) { - if (Connected && res.History) { - InitAccountEv(); - auto* resInfo = AccountEv->Record.AddResourcesInfo(); - bool hasNonZeroAmount = false; - TInstant start; - double totalAmount = 0; - for (TInstant i = res.History->Begin(), e = res.History->End(); i != e; i = res.History->Next(i)) { - if (i >= res.HistoryAccepted) { - if (!start) { - start = i; - } - double amount = res.History->Get(i); - if (amount > 0) { - hasNonZeroAmount = true; - totalAmount += amount; - } - resInfo->AddAmount(amount); - } - } - KESUS_PROXY_LOG_INFO("Report session to \"" << res.Resource << "\". Total amount: " << totalAmount); - if (hasNonZeroAmount) { - resInfo->SetResourceId(res.ResId); - resInfo->SetStartUs(start.MicroSeconds()); - resInfo->SetIntervalUs(res.History->Interval().MicroSeconds()); - } else { - // We have no useful data to report - res.PendingReport = false; - AccountEv->Record.MutableResourcesInfo()->RemoveLast(); // undo AddResourcesInfo() - } - } - } - + void ReportSession(TResourceState& res) { + if (Connected && res.History) { + InitAccountEv(); + auto* resInfo = AccountEv->Record.AddResourcesInfo(); + bool hasNonZeroAmount = false; + TInstant start; + double totalAmount = 0; + for (TInstant i = res.History->Begin(), e = res.History->End(); i != e; i = res.History->Next(i)) { + if (i >= res.HistoryAccepted) { + if (!start) { + start = i; + } + double amount = res.History->Get(i); + if (amount > 0) { + hasNonZeroAmount = true; + totalAmount += amount; + } + resInfo->AddAmount(amount); + } + } + KESUS_PROXY_LOG_INFO("Report session to \"" << res.Resource << "\". Total amount: " << totalAmount); + if (hasNonZeroAmount) { + resInfo->SetResourceId(res.ResId); + resInfo->SetStartUs(start.MicroSeconds()); + resInfo->SetIntervalUs(res.History->Interval().MicroSeconds()); + } else { + // We have no useful data to report + res.PendingReport = false; + AccountEv->Record.MutableResourcesInfo()->RemoveLast(); // undo AddResourcesInfo() + } + } + } + void Handle(TEvQuota::TEvProxyStats::TPtr& ev) { TEvQuota::TEvProxyStats* msg = ev->Get(); KESUS_PROXY_LOG_TRACE("ProxyStats(" << PrintResources(*ev->Get()) << ")"); @@ -580,11 +580,11 @@ private: res.SetAvailable(res.Available - stat.Consumed); res.QueueWeight = stat.QueueWeight; res.Counters.AddConsumed(stat.Consumed); - if (res.History) { - res.History->Add(stat.History); - res.PendingReport = true; - CheckReport(res, TActivationContext::Now()); - } + if (res.History) { + res.History->Add(stat.History); + res.PendingReport = true; + CheckReport(res, TActivationContext::Now()); + } if (res.Counters.QueueSize) { *res.Counters.QueueSize = static_cast<i64>(stat.QueueSize); *res.Counters.QueueWeight = static_cast<i64>(stat.QueueWeight); @@ -753,17 +753,17 @@ private: void Handle(NKesus::TEvKesus::TEvUpdateConsumptionStateAck::TPtr&) { } - void Handle(NKesus::TEvKesus::TEvAccountResourcesAck::TPtr& ev) { - const auto& result = ev->Get()->Record; - KESUS_PROXY_LOG_TRACE("AccountResourcesAck(" << result << ")"); - for (int i = 0; i < result.GetResourcesInfo().size(); ++i) { - const auto& resInfo = result.GetResourcesInfo(i); - if (TResourceState* res = FindResource(resInfo.GetResourceId())) { - res->HistoryAccepted = Max(res->HistoryAccepted, TInstant::MicroSeconds(resInfo.GetAcceptedUs())); - } - } - } - + void Handle(NKesus::TEvKesus::TEvAccountResourcesAck::TPtr& ev) { + const auto& result = ev->Get()->Record; + KESUS_PROXY_LOG_TRACE("AccountResourcesAck(" << result << ")"); + for (int i = 0; i < result.GetResourcesInfo().size(); ++i) { + const auto& resInfo = result.GetResourcesInfo(i); + if (TResourceState* res = FindResource(resInfo.GetResourceId())) { + res->HistoryAccepted = Max(res->HistoryAccepted, TInstant::MicroSeconds(resInfo.GetAcceptedUs())); + } + } + } + THolder<TEvQuota::TEvProxyUpdate> CreateUpdateEvent(TEvQuota::EUpdateState state = TEvQuota::EUpdateState::Normal) const { return MakeHolder<TEvQuota::TEvProxyUpdate>(QuoterId, state); } @@ -840,17 +840,17 @@ private: } } - void CheckReport(TResourceState& res, TInstant now) { - if (res.LastReport + res.ReportPeriod < now && res.PendingReport) { - ReportSession(res); - // `LastReport` must be aligned to send resources' stats in one message - // in case they have the same `ReportPeriod` - Y_ASSERT(res.ReportPeriod < TDuration::Max()); - ui64 periodUs = res.ReportPeriod.MicroSeconds(); - res.LastReport = TInstant::MicroSeconds(res.ReportPeriod.MicroSeconds() / periodUs * periodUs); - } - } - + void CheckReport(TResourceState& res, TInstant now) { + if (res.LastReport + res.ReportPeriod < now && res.PendingReport) { + ReportSession(res); + // `LastReport` must be aligned to send resources' stats in one message + // in case they have the same `ReportPeriod` + Y_ASSERT(res.ReportPeriod < TDuration::Max()); + ui64 periodUs = res.ReportPeriod.MicroSeconds(); + res.LastReport = TInstant::MicroSeconds(res.ReportPeriod.MicroSeconds() / periodUs * periodUs); + } + } + static TString GetLogPrefix(const TVector<TString>& path) { return TStringBuilder() << "[" << CanonizePath(path) << "]: "; } @@ -899,7 +899,7 @@ public: hFunc(NKesus::TEvKesus::TEvSubscribeOnResourcesResult, Handle); hFunc(NKesus::TEvKesus::TEvResourcesAllocated, Handle); hFunc(NKesus::TEvKesus::TEvUpdateConsumptionStateAck, Handle); - hFunc(NKesus::TEvKesus::TEvAccountResourcesAck, Handle); + hFunc(NKesus::TEvKesus::TEvAccountResourcesAck, Handle); hFunc(TEvPrivate::TEvOfflineResourceAllocation, Handle); default: KESUS_PROXY_LOG_WARN("TKesusQuoterProxy::StateFunc unexpected event type# " diff --git a/ydb/core/quoter/kesus_quoter_ut.cpp b/ydb/core/quoter/kesus_quoter_ut.cpp index 430db7db48..b44d55c5de 100644 --- a/ydb/core/quoter/kesus_quoter_ut.cpp +++ b/ydb/core/quoter/kesus_quoter_ut.cpp @@ -70,25 +70,25 @@ Y_UNIT_TEST_SUITE(QuoterWithKesusTest) { setup.GetQuota(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, TKesusQuoterTestSetup::DEFAULT_KESUS_RESOURCE, 40, TDuration::MilliSeconds(500), TEvQuota::TEvClearance::EResult::Deadline); // default rate is 10 } - Y_UNIT_TEST(PrefetchCoefficient) { - TKesusQuoterTestSetup setup; - NKikimrKesus::THierarchicalDRRResourceConfig cfg; - double rate = 100.0; - double prefetch = 1000.0; - cfg.SetMaxUnitsPerSecond(rate); - cfg.SetPrefetchCoefficient(prefetch); - setup.CreateKesusResource(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root", cfg); - - cfg.ClearMaxUnitsPerSecond(); - cfg.ClearPrefetchCoefficient(); // should be inherited from root - setup.CreateKesusResource(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root/leaf", cfg); - - setup.GetQuota(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root/leaf"); // stabilization - setup.GetQuota(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root/leaf", rate * prefetch * 0.9, TDuration::MilliSeconds(500)); - setup.GetQuota(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root/leaf", rate * prefetch * 0.2, TDuration::MilliSeconds(500)); - setup.GetQuota(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root/leaf", 1, TDuration::MilliSeconds(500), TEvQuota::TEvClearance::EResult::Deadline); - } - + Y_UNIT_TEST(PrefetchCoefficient) { + TKesusQuoterTestSetup setup; + NKikimrKesus::THierarchicalDRRResourceConfig cfg; + double rate = 100.0; + double prefetch = 1000.0; + cfg.SetMaxUnitsPerSecond(rate); + cfg.SetPrefetchCoefficient(prefetch); + setup.CreateKesusResource(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root", cfg); + + cfg.ClearMaxUnitsPerSecond(); + cfg.ClearPrefetchCoefficient(); // should be inherited from root + setup.CreateKesusResource(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root/leaf", cfg); + + setup.GetQuota(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root/leaf"); // stabilization + setup.GetQuota(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root/leaf", rate * prefetch * 0.9, TDuration::MilliSeconds(500)); + setup.GetQuota(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root/leaf", rate * prefetch * 0.2, TDuration::MilliSeconds(500)); + setup.GetQuota(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, "root/leaf", 1, TDuration::MilliSeconds(500), TEvQuota::TEvClearance::EResult::Deadline); + } + Y_UNIT_TEST(GetsQuotaAfterPause) { TKesusQuoterTestSetup setup; setup.GetQuota(TKesusQuoterTestSetup::DEFAULT_KESUS_PATH, TKesusQuoterTestSetup::DEFAULT_KESUS_RESOURCE, 12); @@ -305,7 +305,7 @@ Y_UNIT_TEST_SUITE(KesusProxyTest) { UNIT_ASSERT(record.GetResourcesInfo(0).GetConsumeResource()); })); - setup.SendProxyStats({TEvQuota::TProxyStat(43, 1, 0, {}, 3, 5.0, 0, 0)}); + setup.SendProxyStats({TEvQuota::TProxyStat(43, 1, 0, {}, 3, 5.0, 0, 0)}); setup.WaitEvent<NKesus::TEvKesus::TEvUpdateConsumptionState>(); // Disconnected @@ -370,7 +370,7 @@ Y_UNIT_TEST_SUITE(KesusProxyTest) { auto session = setup.ProxyRequest("res"); UNIT_ASSERT_VALUES_EQUAL(session->Get()->ResourceId, 42); - setup.SendProxyStats({TEvQuota::TProxyStat(42, 1, 0, {}, 1, 25.0, 0, 0)}); + setup.SendProxyStats({TEvQuota::TProxyStat(42, 1, 0, {}, 1, 25.0, 0, 0)}); auto& startSession = EXPECT_CALL(*pipe, OnUpdateConsumptionState(_, _)) @@ -416,7 +416,7 @@ Y_UNIT_TEST_SUITE(KesusProxyTest) { UNIT_ASSERT(record.GetResourcesInfo(0).GetConsumeResource()); })); - setup.SendProxyStats({TEvQuota::TProxyStat(42, 1, 0, {}, 3, 5.0, 0, 0)}); + setup.SendProxyStats({TEvQuota::TProxyStat(42, 1, 0, {}, 3, 5.0, 0, 0)}); setup.WaitEvent<NKesus::TEvKesus::TEvUpdateConsumptionState>(); // Disconnected diff --git a/ydb/core/quoter/quoter_service.cpp b/ydb/core/quoter/quoter_service.cpp index b9a1b629f5..fa195def2a 100644 --- a/ydb/core/quoter/quoter_service.cpp +++ b/ydb/core/quoter/quoter_service.cpp @@ -254,7 +254,7 @@ void TResource::ChargeUsedAmount(double amount, TInstant now) { FreeBalance -= amount; Balance -= amount; AmountConsumed += amount; - History.Add(now, amount); + History.Add(now, amount); Counters.Consumed->Add(static_cast<i64>(amount)); if (Balance >= 0.0) { StopStarvation(now); @@ -291,7 +291,7 @@ TDuration TResource::Charge(double amount, TInstant now) { LastAllocated = Max(now - QuoterServiceConfig.ScheduleTickSize * 2, timeToFullfill); Balance -= amount; AmountConsumed += amount; - History.Add(now, amount); + History.Add(now, amount); if (FreeBalance > Balance) FreeBalance = Balance; @@ -306,7 +306,7 @@ TDuration TResource::Charge(double amount, TInstant now) { FreeBalance -= amount; Balance -= amount; AmountConsumed += amount; - History.Add(now, amount); + History.Add(now, amount); Counters.Consumed->Add(static_cast<i64>(amount)); StopStarvation(now); @@ -518,7 +518,7 @@ TQuoterService::EInitLeafStatus TQuoterService::InitSystemLeaf(const TEvQuota::T quores.LastAllocated = TInstant::Zero(); quores.AmountConsumed = 0.0; - // NOTE: do not change `History`: we dont need it for static rate + // NOTE: do not change `History`: we dont need it for static rate quores.FreeBalance = 0.0; quores.TickRate = static_cast<double>(rate); @@ -1171,9 +1171,9 @@ void TQuoterService::FillStats(TResource &quores) { auto &dq = StatsToPublish[quores.QuoterId]; const double expectedRate = -1.0; const double cap = -1.0; - dq.emplace_back(quores.ResourceId, 0, quores.AmountConsumed, quores.History, quores.QueueSize, quores.QueueWeight, expectedRate, cap); + dq.emplace_back(quores.ResourceId, 0, quores.AmountConsumed, quores.History, quores.QueueSize, quores.QueueWeight, expectedRate, cap); quores.AmountConsumed = 0.0; - quores.History.Clear(); + quores.History.Clear(); } void TQuoterService::FeedResource(TResource &quores) { diff --git a/ydb/core/quoter/quoter_service_impl.h b/ydb/core/quoter/quoter_service_impl.h index d27ea134e1..049a2aa3ca 100644 --- a/ydb/core/quoter/quoter_service_impl.h +++ b/ydb/core/quoter/quoter_service_impl.h @@ -146,7 +146,7 @@ struct TResource { // stats block TEvQuota::EStatUpdatePolicy StatUpdatePolicy = TEvQuota::EStatUpdatePolicy::Never; double AmountConsumed = 0.0; // consumed from last stats notification - TTimeSeriesMap<double> History; // consumption history from last stats notification + TTimeSeriesMap<double> History; // consumption history from last stats notification TInstant StartStarvationTime = TInstant::Zero(); struct { @@ -175,9 +175,9 @@ struct TResource { } void ApplyQuotaChannel(const TEvQuota::TUpdateTick &tick); - TDuration Charge(double amount, TInstant now); // Zero - fullfiled, Max - not in current tick, Duration - in current tick, but not right now due to pace limit + TDuration Charge(double amount, TInstant now); // Zero - fullfiled, Max - not in current tick, Duration - in current tick, but not right now due to pace limit TDuration Charge(TRequest& request, TResourceLeaf& leaf, TInstant now); - void ChargeUsedAmount(double amount, TInstant now); + void ChargeUsedAmount(double amount, TInstant now); void MarkStartedCharging(TRequest& request, TResourceLeaf& leaf, TInstant now); void StartStarvation(TInstant now); diff --git a/ydb/core/quoter/ut_helpers.cpp b/ydb/core/quoter/ut_helpers.cpp index e57a073d74..0b06206989 100644 --- a/ydb/core/quoter/ut_helpers.cpp +++ b/ydb/core/quoter/ut_helpers.cpp @@ -344,7 +344,7 @@ bool TKesusProxyTestSetup::ConsumeResource(ui64 resId, double amount, TDuration const TInstant start = Runtime->GetCurrentTime(); while (updatesGot < maxUpdates) { ++updatesGot; - SendProxyStats({TEvQuota::TProxyStat(resId, 1, 0, {}, 1, amount, 0, 0)}); + SendProxyStats({TEvQuota::TProxyStat(resId, 1, 0, {}, 1, amount, 0, 0)}); WaitEvent<TEvQuota::TEvProxyStats>(); // wait event to be processed afterStat(); @@ -374,7 +374,7 @@ bool TKesusProxyTestSetup::ConsumeResource(ui64 resId, double amount, TDuration const TDuration timeToCharge = amount / updateTick.Rate * tickSize; if (Runtime->GetCurrentTime() - start >= timeToCharge || amount <= updateTick.Rate) { // spend and exit - SendProxyStats({TEvQuota::TProxyStat(resId, 1, amount, {}, 0, 0, 0, 0)}); + SendProxyStats({TEvQuota::TProxyStat(resId, 1, amount, {}, 0, 0, 0, 0)}); return true; } } diff --git a/ydb/core/scheme/scheme_tablecell.h b/ydb/core/scheme/scheme_tablecell.h index bccfdca97d..fe1f1c52ec 100644 --- a/ydb/core/scheme/scheme_tablecell.h +++ b/ydb/core/scheme/scheme_tablecell.h @@ -58,10 +58,10 @@ public: } } - explicit TCell(const TRawTypeValue* v) - : TCell((const char*)v->Data(), v->Size()) - {} - + explicit TCell(const TRawTypeValue* v) + : TCell((const char*)v->Data(), v->Size()) + {} + explicit operator bool() const { return !IsNull(); @@ -102,7 +102,7 @@ public: static constexpr bool CanInline(ui32 sz) { return sz <= 8; } static constexpr size_t MaxInlineSize() { return 8; } const char* InlineData() const { Y_VERIFY_DEBUG(IsInline_); return IsNull_ ? nullptr : (char*)&IntVal; } - const char* Data() const { return IsNull_ ? nullptr : (IsInline_ ? (char*)&IntVal : Ptr); } + const char* Data() const { return IsNull_ ? nullptr : (IsInline_ ? (char*)&IntVal : Ptr); } #else // Non-inlinable version for perf comparisons static bool CanInline(ui32) { return false; } @@ -117,7 +117,7 @@ static_assert(sizeof(TCell) == 12, "TCell must be 12 bytes"); using TCellsRef = TConstArrayRef<const TCell>; -// NULL is considered equal to another NULL and less than non-NULL +// NULL is considered equal to another NULL and less than non-NULL // ATTENTION!!! return value is int!! (NOT just -1,0,1) inline int CompareTypedCells(const TCell& a, const TCell& b, NScheme::TTypeIdOrder type) { using TPair = std::pair<ui64, ui64>; diff --git a/ydb/core/scheme_types/scheme_type_registry.cpp b/ydb/core/scheme_types/scheme_type_registry.cpp index d737254361..1287c5cd64 100644 --- a/ydb/core/scheme_types/scheme_type_registry.cpp +++ b/ydb/core/scheme_types/scheme_type_registry.cpp @@ -6,7 +6,7 @@ #include <util/generic/algorithm.h> -#define REGISTER_TYPE(name, size, ...) RegisterType<T##name>(); +#define REGISTER_TYPE(name, size, ...) RegisterType<T##name>(); namespace NKikimr { namespace NScheme { diff --git a/ydb/core/scheme_types/scheme_types_defs.h b/ydb/core/scheme_types/scheme_types_defs.h index bb06b09702..b7f789899e 100644 --- a/ydb/core/scheme_types/scheme_types_defs.h +++ b/ydb/core/scheme_types/scheme_types_defs.h @@ -44,9 +44,9 @@ public: return Name_; } - static constexpr ui32 GetFixedSize() { - return sizeof(T); - } + static constexpr ui32 GetFixedSize() { + return sizeof(T); + } TTypeId GetTypeId() const override { return TypeId; } static TRawTypeValue ToRawTypeValue(const T& value) { return TRawTypeValue((void*)&value, sizeof(T), TypeId); @@ -146,10 +146,10 @@ template <typename TDerived, TTypeId TypeId, const char* Name> class TStringBase : public TTypedType<::TString, TDerived, TypeId, Name> { public: - static constexpr ui32 GetFixedSize() { - return 0; - } - + static constexpr ui32 GetFixedSize() { + return 0; + } + static TRawTypeValue ToRawTypeValue(const ::TString& value) { return TRawTypeValue((const void*)value.data(), value.size(), TypeId); } @@ -192,10 +192,10 @@ template <ui32 TMaxSize, TTypeId TypeId, const char* Name> class TBoundedString : public TStringBase<TBoundedString<TMaxSize, TypeId, Name>, TypeId, Name> { public: static constexpr ui32 MaxSize = TMaxSize; - static constexpr ui32 GetFixedSize() { - return 0; - } - + static constexpr ui32 GetFixedSize() { + return 0; + } + static TRawTypeValue ToRawTypeValue(const ::TString& value) { Y_VERIFY(value.size() <= MaxSize); return TRawTypeValue((const void*)value.data(), value.size(), TypeId); diff --git a/ydb/core/tablet/node_tablet_monitor.cpp b/ydb/core/tablet/node_tablet_monitor.cpp index 8bb34e7ea0..71032b73e3 100644 --- a/ydb/core/tablet/node_tablet_monitor.cpp +++ b/ydb/core/tablet/node_tablet_monitor.cpp @@ -54,59 +54,59 @@ public: void RenderResponse(const TActorContext &ctx) { Sort(NodesInfo->Nodes.begin(), NodesInfo->Nodes.end()); TStringStream str; - HTML(str) { - H3() { + HTML(str) { + H3() { str << "Nodes"; - } - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "NodeId";} - TABLEH() {str << "Host";} - TABLEH() {str << "Address";} - TABLEH() {str << "Port";} - } - } - TABLEBODY() { + } + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "NodeId";} + TABLEH() {str << "Host";} + TABLEH() {str << "Address";} + TABLEH() {str << "Port";} + } + } + TABLEBODY() { for (const auto& ni : NodesInfo->Nodes) { const TEvInterconnect::TNodeInfo &nodeInfo = ni; - TABLER() { - TABLED() {str << "<a href=\"nodetabmon?action=browse_tablets&node_id=" << nodeInfo.NodeId << "\">" - << nodeInfo.NodeId << "</a>";} - TABLED() {str << "<a href=\"nodetabmon?action=browse_tablets&node_id=" << nodeInfo.NodeId << "\">" - << nodeInfo.Host << "</a>";} - TABLED() {str << nodeInfo.Address;} - TABLED() {str << nodeInfo.Port;} - } - } + TABLER() { + TABLED() {str << "<a href=\"nodetabmon?action=browse_tablets&node_id=" << nodeInfo.NodeId << "\">" + << nodeInfo.NodeId << "</a>";} + TABLED() {str << "<a href=\"nodetabmon?action=browse_tablets&node_id=" << nodeInfo.NodeId << "\">" + << nodeInfo.Host << "</a>";} + TABLED() {str << nodeInfo.Address;} + TABLED() {str << nodeInfo.Port;} + } } - } - HTML_TAG() {str << "<a href=\"nodetabmon?action=browse_tablets\">All tablets of the cluster</a>";} - H3() { + } + } + HTML_TAG() {str << "<a href=\"nodetabmon?action=browse_tablets\">All tablets of the cluster</a>";} + H3() { str << "State Storages"; - } - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "StateStorageId";} - TABLEH() {str << "Domain";} - } - } - TABLEBODY() { + } + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "StateStorageId";} + TABLEH() {str << "Domain";} + } + } + TABLEBODY() { for (const auto& ni : AppData(ctx)->DomainsInfo->Domains) { const TDomainsInfo::TDomain &domain = *ni.second; for (const auto ssId : domain.StateStorageGroups) { - TABLER() { - TABLED() {str << "<a href=\"nodetabmon?action=browse_ss&ss_id=" << ssId << "\">" - << ssId << "</a>";} - TABLED() {str << domain.Name;} + TABLER() { + TABLED() {str << "<a href=\"nodetabmon?action=browse_ss&ss_id=" << ssId << "\">" + << ssId << "</a>";} + TABLED() {str << domain.Name;} } - } + } } - } - } - } + } + } + } ctx.Send(Sender, new NMon::TEvHttpInfoRes(str.Str())); Die(ctx); } @@ -254,7 +254,7 @@ public: } } TStringStream str; - HTML(str) { + HTML(str) { Renderer->RenderPageHeader(str); for(ui32 cls = 0; cls < StateClassifier->GetMaxTabletStateClass(); cls++) { auto filter = StateClassifier->GetTabletStateClassFilter(cls); @@ -264,7 +264,7 @@ public: Renderer->RenderTabletList(str, listName, tablets, {FilterNodeId, filterNodeHost}); } Renderer->RenderPageFooter(str); - } + } ctx.Send(Sender, new NMon::TEvHttpInfoRes(str.Str())); Die(ctx); } @@ -338,53 +338,53 @@ public: } } TStringStream str; - HTML(str) { - H3() { + HTML(str) { + H3() { str << "Tablets of StateStorage " << StateStorageId; - } - TABLE_CLASS("table table-bordered") { - TABLEHEAD() { - HTML_TAG() {str << "<tr style='background-color:#eee'>"; - TABLEH() {str << "<span data-toggle='tooltip' title='Tablet Identifier'>TabletID</span>";} - TABLEH() {str << "<span data-toggle='tooltip' title='Node from which SS Replica has responded'>Replica Node ID / Hostname</span>";} - TABLEH() {str << "<span data-toggle='tooltip' title='Tablet Generation'>Gen</span>";} - TABLEH() {str << "<span data-toggle='tooltip' title='Amount of time tablet has been locked in SS (seconds)'>Locked For</span>";} - TABLEH() {str << "<span data-toggle='tooltip' title='Node where tablet has been started'>Tablet Node ID / Hostname</span>";} - TABLEH() {str << "<span data-toggle='tooltip' title='Is user part (actor) of the tablet started?'>Active</span>";} + } + TABLE_CLASS("table table-bordered") { + TABLEHEAD() { + HTML_TAG() {str << "<tr style='background-color:#eee'>"; + TABLEH() {str << "<span data-toggle='tooltip' title='Tablet Identifier'>TabletID</span>";} + TABLEH() {str << "<span data-toggle='tooltip' title='Node from which SS Replica has responded'>Replica Node ID / Hostname</span>";} + TABLEH() {str << "<span data-toggle='tooltip' title='Tablet Generation'>Gen</span>";} + TABLEH() {str << "<span data-toggle='tooltip' title='Amount of time tablet has been locked in SS (seconds)'>Locked For</span>";} + TABLEH() {str << "<span data-toggle='tooltip' title='Node where tablet has been started'>Tablet Node ID / Hostname</span>";} + TABLEH() {str << "<span data-toggle='tooltip' title='Is user part (actor) of the tablet started?'>Active</span>";} str << "</tr>"; - } - } - TABLEBODY() { + } + } + TABLEBODY() { for (auto iit = indexByTabletId.begin(); iit != indexByTabletId.end(); ++iit) { for (auto iptr = iit->second.begin(); iptr != iit->second.end(); ++iptr) { const NKikimrStateStorage::TEvInfo &ei = *iptr->second; ui32 replicaNodeId = iptr->first; - TABLER() { + TABLER() { if (iptr == iit->second.begin()) { - HTML_TAG() {str << "<td rowspan='" << iit->second.size() << "'>" - << "<a href='tablets?TabletID=" << ei.GetTabletID() << "'>" << ei.GetTabletID() << "</a></td>";} + HTML_TAG() {str << "<td rowspan='" << iit->second.size() << "'>" + << "<a href='tablets?TabletID=" << ei.GetTabletID() << "'>" << ei.GetTabletID() << "</a></td>";} } - TABLED() { + TABLED() { str << replicaNodeId; auto eq_it = EqualRange(NodesInfo->Nodes.begin(), NodesInfo->Nodes.end(), replicaNodeId); if (eq_it.first != NodesInfo->Nodes.end() && eq_it.first->Host) str << " / " << eq_it.first->Host; - } - TABLED() {str << ei.GetCurrentGeneration();} - TABLED() {if (ei.HasLockedFor()) str << TDuration::MicroSeconds(ei.GetLockedFor()).Seconds();} - TABLED() { + } + TABLED() {str << ei.GetCurrentGeneration();} + TABLED() {if (ei.HasLockedFor()) str << TDuration::MicroSeconds(ei.GetLockedFor()).Seconds();} + TABLED() { ui32 nodeId = ActorIdFromProto(ei.GetCurrentLeader()).NodeId(); str << nodeId; auto eq_it = EqualRange(NodesInfo->Nodes.begin(), NodesInfo->Nodes.end(), nodeId); if (eq_it.first != NodesInfo->Nodes.end() && eq_it.first->Host) str << " / " << eq_it.first->Host; - } + } TABLED() {if (ActorIdFromProto(ei.GetCurrentLeaderTablet())) str << "<span class='glyphicon glyphicon-ok' title='User Actor present'/>";} - } + } } } - } - } - HTML_TAG() {str << "<script>$(document).ready(function(){$('[data-toggle=\"tooltip\"]').tooltip();}</script>";} - } + } + } + HTML_TAG() {str << "<script>$(document).ready(function(){$('[data-toggle=\"tooltip\"]').tooltip();}</script>";} + } ctx.Send(Sender, new NMon::TEvHttpInfoRes(str.Str())); Die(ctx); } diff --git a/ydb/core/tablet/tablet_counters.cpp b/ydb/core/tablet/tablet_counters.cpp index b2ef0d4ad7..64903d31ce 100644 --- a/ydb/core/tablet/tablet_counters.cpp +++ b/ydb/core/tablet/tablet_counters.cpp @@ -64,53 +64,53 @@ TTabletCountersBase::operator = (const TTabletCountersBase& rp) { } void TTabletSimpleCounterBase::OutputHtml(IOutputStream &os, const char* name) const { - HTML(os) {PRE() {os << name << ": " << Value;}} + HTML(os) {PRE() {os << name << ": " << Value;}} } void TTabletPercentileCounter::OutputHtml(IOutputStream &os, const char* name) const { - HTML(os) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {H4() {os << name;}} - } + HTML(os) { + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {H4() {os << name;}} + } - DIV_CLASS("row") { + DIV_CLASS("row") { for (ui32 i = 0; i < RangeCount; ++i) { - DIV_CLASS("col-md-3") { - PRE() { + DIV_CLASS("col-md-3") { + PRE() { os << Ranges[i].RangeName << ": " << Values[i]; - } - } + } + } } - } - } + } + } } void TTabletCountersBase::OutputHtml(IOutputStream &os) const { - HTML(os) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {OutputHtml(os, "Simple", SimpleCountersMetaInfo, "col-md-3", SimpleCounters);} - DIV_CLASS("col-md-12") {OutputHtml(os, "Cumulative", CumulativeCountersMetaInfo, "col-md-3", CumulativeCounters);} - DIV_CLASS("col-md-12") {OutputHtml(os, "Percentile", PercentileCountersMetaInfo, "col-md-12", PercentileCounters);} - - } - } + HTML(os) { + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {OutputHtml(os, "Simple", SimpleCountersMetaInfo, "col-md-3", SimpleCounters);} + DIV_CLASS("col-md-12") {OutputHtml(os, "Cumulative", CumulativeCountersMetaInfo, "col-md-3", CumulativeCounters);} + DIV_CLASS("col-md-12") {OutputHtml(os, "Percentile", PercentileCountersMetaInfo, "col-md-12", PercentileCounters);} + + } + } } //////////////////////////////////////////// template<typename T> void TTabletCountersBase::OutputHtml(IOutputStream &os, const char* sectionName, const char* const* counterNames, const char* counterClass, const TCountersArray<T>& counters) const { - HTML(os) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {H3() {os << sectionName; }} - } - DIV_CLASS("row") { + HTML(os) { + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {H3() {os << sectionName; }} + } + DIV_CLASS("row") { for (ui32 i = 0, e = counters.Size(); i < e; ++i) { if (counterNames[i]) { DIV_CLASS(counterClass) {counters[i].OutputHtml(os, counterNames[i]);} } } - } - } + } + } } void TTabletCountersBase::OutputProto(NKikimrTabletBase::TTabletCountersBase& op) const { @@ -179,20 +179,20 @@ TTabletLabeledCountersBase::operator = (const TTabletLabeledCountersBase& rp) { } void TTabletLabeledCountersBase::OutputHtml(IOutputStream &os) const { - HTML(os) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {H3() {os << Group; }} + HTML(os) { + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {H3() {os << Group; }} - } - DIV_CLASS("row") { + } + DIV_CLASS("row") { for (ui32 i = 0, e = Counters.Size(); i < e; ++i) { if (MetaInfo[i]) { DIV_CLASS("col-md-3") {Counters[i].OutputHtml(os, MetaInfo[i]);} DIV_CLASS("col-md-3") {Ids[i].OutputHtml(os, "id");} } } - } - } + } + } } void TTabletLabeledCountersBase::AggregateWith(const TTabletLabeledCountersBase& rp) { diff --git a/ydb/core/tablet/tablet_counters.h b/ydb/core/tablet/tablet_counters.h index a8cc27e9ed..5b43882e71 100644 --- a/ydb/core/tablet/tablet_counters.h +++ b/ydb/core/tablet/tablet_counters.h @@ -1,7 +1,7 @@ #pragma once #include "defs.h" -#include <util/generic/singleton.h> -#include <util/generic/vector.h> +#include <util/generic/singleton.h> +#include <util/generic/vector.h> #include <library/cpp/deprecated/enum_codegen/enum_codegen.h> #include <library/cpp/monlib/service/pages/templates.h> #include <google/protobuf/descriptor.pb.h> @@ -236,7 +236,7 @@ private: } } -public: +public: void Initialize(ui32 rangeCount, const TRangeDef* ranges, bool integral) { Y_VERIFY_DEBUG(!Ranges); Y_VERIFY_DEBUG(!Values); @@ -258,7 +258,7 @@ public: } } -private: +private: // ui32 FindSlot(ui64 what) const { return Max<ssize_t>(0, std::upper_bound(Ranges, Ranges + RangeCount, what) - Ranges - 1); diff --git a/ydb/core/tablet/tablet_counters_protobuf.h b/ydb/core/tablet/tablet_counters_protobuf.h index 11d3a334de..640c1ec565 100644 --- a/ydb/core/tablet/tablet_counters_protobuf.h +++ b/ydb/core/tablet/tablet_counters_protobuf.h @@ -1,38 +1,38 @@ -#pragma once - -#include "tablet_counters.h" +#pragma once + +#include "tablet_counters.h" #include "tablet_counters_aggregator.h" #include <ydb/core/tablet_flat/defs.h> #include <util/string/vector.h> #include <util/string/split.h> - -namespace NKikimr { - -namespace NAux { - + +namespace NKikimr { + +namespace NAux { + // Class that incapsulates protobuf options parsing for app counters template <const NProtoBuf::EnumDescriptor* AppCountersDesc()> struct TAppParsedOpts { -public: - const size_t Size; +public: + const size_t Size; protected: TVector<TString> NamesStrings; TVector<const char*> Names; TVector<TVector<TTabletPercentileCounter::TRangeDef>> Ranges; TVector<TTabletPercentileCounter::TRangeDef> AppGlobalRanges; TVector<bool> Integral; -public: +public: explicit TAppParsedOpts(const size_t diff = 0) : Size(AppCountersDesc()->value_count() + diff) - { + { const NProtoBuf::EnumDescriptor* appDesc = AppCountersDesc(); - NamesStrings.reserve(Size); - Names.reserve(Size); - Ranges.reserve(Size); - - // Parse protobuf options for enum values for app counters - for (int i = 0; i < appDesc->value_count(); i++) { - const NProtoBuf::EnumValueDescriptor* vdesc = appDesc->value(i); + NamesStrings.reserve(Size); + Names.reserve(Size); + Ranges.reserve(Size); + + // Parse protobuf options for enum values for app counters + for (int i = 0; i < appDesc->value_count(); i++) { + const NProtoBuf::EnumValueDescriptor* vdesc = appDesc->value(i); Y_VERIFY(vdesc->number() == vdesc->index(), "counter '%s' number (%d) != index (%d)", vdesc->full_name().c_str(), vdesc->number(), vdesc->index()); if (!vdesc->options().HasExtension(CounterOpts)) { @@ -41,7 +41,7 @@ public: Integral.push_back(false); continue; } - const TCounterOptions& co = vdesc->options().GetExtension(CounterOpts); + const TCounterOptions& co = vdesc->options().GetExtension(CounterOpts); TString cntName = co.GetName(); Y_VERIFY(!cntName.empty(), "counter '%s' number (%d) cannot have an empty counter name", vdesc->full_name().c_str(), vdesc->number()); @@ -52,10 +52,10 @@ public: nameString = GetFilePrefix(appDesc->file()) + cntName; } NamesStrings.emplace_back(nameString); - Ranges.push_back(ParseRanges(co)); + Ranges.push_back(ParseRanges(co)); Integral.push_back(co.GetIntegral()); - } - + } + // Make plain strings out of Strokas to fullfil interface of TTabletCountersBase for (const TString& s : NamesStrings) { Names.push_back(s.empty() ? nullptr : s.c_str()); @@ -136,19 +136,19 @@ public: const NProtoBuf::EnumDescriptor* txDesc = TxCountersDesc(); const NProtoBuf::EnumDescriptor* typesDesc = TxTypesDesc(); - // Parse protobuf options for enum values for tx counters - // Create a group of tx counters for each tx type - for (int j = 0; j < typesDesc->value_count(); j++) { - const NProtoBuf::EnumValueDescriptor* tt = typesDesc->value(j); - TTxType txType = tt->number(); + // Parse protobuf options for enum values for tx counters + // Create a group of tx counters for each tx type + for (int j = 0; j < typesDesc->value_count(); j++) { + const NProtoBuf::EnumValueDescriptor* tt = typesDesc->value(j); + TTxType txType = tt->number(); Y_VERIFY((int)txType == tt->index(), "tx type '%s' number (%d) != index (%d)", tt->full_name().c_str(), txType, tt->index()); Y_VERIFY(tt->options().HasExtension(TxTypeOpts), "tx type '%s' number (%d) is missing TxTypeOpts", tt->full_name().c_str(), txType); - const TTxTypeOptions& tto = tt->options().GetExtension(TxTypeOpts); + const TTxTypeOptions& tto = tt->options().GetExtension(TxTypeOpts); TString txPrefix = tto.GetName() + "/"; - for (int i = 0; i < txDesc->value_count(); i++) { - const NProtoBuf::EnumValueDescriptor* v = txDesc->value(i); + for (int i = 0; i < txDesc->value_count(); i++) { + const NProtoBuf::EnumValueDescriptor* v = txDesc->value(i); Y_VERIFY(v->number() == v->index(), "counter '%s' number (%d) != index (%d)", v->full_name().c_str(), v->number(), v->index()); if (!v->options().HasExtension(CounterOpts)) { @@ -157,54 +157,54 @@ public: Integral.push_back(false); continue; } - const TCounterOptions& co = v->options().GetExtension(CounterOpts); + const TCounterOptions& co = v->options().GetExtension(CounterOpts); Y_VERIFY(!co.GetName().empty(), "counter '%s' number (%d) has an empty name", v->full_name().c_str(), v->number()); TVector<TTabletPercentileCounter::TRangeDef> ranges = TBase::ParseRanges(co); NamesStrings.push_back(TBase::GetFilePrefix(typesDesc->file()) + txPrefix + co.GetName()); Ranges.push_back(TBase::ParseRanges(co)); Integral.push_back(co.GetIntegral()); - } - } - // Make plain strings out of Strokas to fullfil interface of TTabletCountersBase + } + } + // Make plain strings out of Strokas to fullfil interface of TTabletCountersBase for (size_t i = TxOffset; i < Size; ++i) { const TString& s = NamesStrings[i]; Names.push_back(s.empty() ? nullptr : s.c_str()); - } - - // Parse protobuf options for enums itself + } + + // Parse protobuf options for enums itself TxGlobalRanges = TBase::ParseRanges(txDesc->options().GetExtension(GlobalCounterOpts)); - } - + } + virtual ~TParsedOpts() {} - + virtual const TVector<TTabletPercentileCounter::TRangeDef>& GetRanges(size_t idx) const - { + { Y_VERIFY(idx < Size); - if (!Ranges[idx].empty()) { - return Ranges[idx]; - } else { - if (idx < TxOffset) { + if (!Ranges[idx].empty()) { + return Ranges[idx]; + } else { + if (idx < TxOffset) { if (!AppGlobalRanges.empty()) - return AppGlobalRanges; + return AppGlobalRanges; } else if (!TxGlobalRanges.empty()) { - return TxGlobalRanges; - } - } - if (idx < TxOffset) { + return TxGlobalRanges; + } + } + if (idx < TxOffset) { Y_FAIL("Ranges for percentile counter '%s' are not defined", AppCountersDesc()->value(idx)->full_name().c_str()); - } else { - size_t idx2 = (idx - TxOffset) % TxCountersSize; + } else { + size_t idx2 = (idx - TxOffset) % TxCountersSize; Y_FAIL("Ranges for percentile counter '%s' are not defined", TxCountersDesc()->value(idx2)->full_name().c_str()); - } - } + } + } }; - + template <class T1, class T2> struct TParsedOptsPair { -private: +private: T1 Opts1; T2 Opts2; TVector<const char*> Names; @@ -219,16 +219,16 @@ public: Names.reserve(Size); for (size_t i = 0; i < Opts1.Size; ++i) { Names.push_back(Opts1.GetNames()[i]); - } + } for (size_t i = 0; i < Opts2.Size; ++i) { Names.push_back(Opts2.GetNames()[i]); } - } - + } + const char* const * GetNames() const - { + { return Names.begin(); - } + } const TVector<TTabletPercentileCounter::TRangeDef>& GetRanges(size_t idx) const { @@ -237,22 +237,22 @@ public: return Opts1.GetRanges(idx); return Opts2.GetRanges(idx - Opts1.Size); } -}; - -template <const NProtoBuf::EnumDescriptor* AppCountersDesc(), - const NProtoBuf::EnumDescriptor* TxCountersDesc(), - const NProtoBuf::EnumDescriptor* TxTypesDesc()> -TParsedOpts<AppCountersDesc, TxCountersDesc, TxTypesDesc>* GetOpts() { - // Use singleton to avoid thread-safety issues and parse enum descriptor once - return Singleton<TParsedOpts<AppCountersDesc, TxCountersDesc, TxTypesDesc>>(); -} +}; + +template <const NProtoBuf::EnumDescriptor* AppCountersDesc(), + const NProtoBuf::EnumDescriptor* TxCountersDesc(), + const NProtoBuf::EnumDescriptor* TxTypesDesc()> +TParsedOpts<AppCountersDesc, TxCountersDesc, TxTypesDesc>* GetOpts() { + // Use singleton to avoid thread-safety issues and parse enum descriptor once + return Singleton<TParsedOpts<AppCountersDesc, TxCountersDesc, TxTypesDesc>>(); +} template <const NProtoBuf::EnumDescriptor* AppCountersDesc()> TAppParsedOpts<AppCountersDesc>* GetAppOpts() { // Use singleton to avoid thread-safety issues and parse enum descriptor once return Singleton<TAppParsedOpts<AppCountersDesc>>(); } - + template <class T1, class T2> TParsedOptsPair<T1,T2>* GetOptsPair() { // Use singleton to avoid thread-safety issues and parse enum descriptor once @@ -357,93 +357,93 @@ TLabeledCounterParsedOpts<LabeledCountersDesc>* GetLabeledCounterOpts() { return Singleton<TLabeledCounterParsedOpts<LabeledCountersDesc>>(); } -} // NAux - -// Base class for all tablet counters classes with tx type counters -// (Needed just to distinguish them in executor code using dynamic_cast) -class TTabletCountersWithTxTypes : public TTabletCountersBase { -protected: - enum ECounterType { - CT_SIMPLE, - CT_CUMULATIVE, - CT_PERCENTILE, - CT_MAX - }; - size_t Size[CT_MAX]; - size_t TxOffset[CT_MAX]; - size_t TxCountersSize[CT_MAX]; -public: - TTabletCountersWithTxTypes() {} - - template <class... TArgs> - explicit TTabletCountersWithTxTypes(TArgs... args) - : TTabletCountersBase(args...) - {} - - TTabletSimpleCounter& TxSimple(TTxType txType, ui32 txCounter) { - return Simple()[IndexOf<CT_SIMPLE>(txType, txCounter)]; - } - - const TTabletSimpleCounter& TxSimple(TTxType txType, ui32 txCounter) const { - return Simple()[IndexOf<CT_SIMPLE>(txType, txCounter)]; - } - - TTabletCumulativeCounter& TxCumulative(TTxType txType, ui32 txCounter) { - return Cumulative()[IndexOf<CT_CUMULATIVE>(txType, txCounter)]; - } - - const TTabletCumulativeCounter& TxCumulative(TTxType txType, ui32 txCounter) const { - return Cumulative()[IndexOf<CT_CUMULATIVE>(txType, txCounter)]; - } - - TTabletPercentileCounter& TxPercentile(TTxType txType, ui32 txCounter) { - return Percentile()[IndexOf<CT_PERCENTILE>(txType, txCounter)]; - } - - const TTabletPercentileCounter& TxPercentile(TTxType txType, ui32 txCounter) const { - return Percentile()[IndexOf<CT_PERCENTILE>(txType, txCounter)]; - } -protected: - template <ECounterType counterType> - size_t IndexOf(TTxType txType, ui32 txCounter) const { - // Note that enum values are used only inside a process, not on disc/messages - // so there are no backward compatibility issues +} // NAux + +// Base class for all tablet counters classes with tx type counters +// (Needed just to distinguish them in executor code using dynamic_cast) +class TTabletCountersWithTxTypes : public TTabletCountersBase { +protected: + enum ECounterType { + CT_SIMPLE, + CT_CUMULATIVE, + CT_PERCENTILE, + CT_MAX + }; + size_t Size[CT_MAX]; + size_t TxOffset[CT_MAX]; + size_t TxCountersSize[CT_MAX]; +public: + TTabletCountersWithTxTypes() {} + + template <class... TArgs> + explicit TTabletCountersWithTxTypes(TArgs... args) + : TTabletCountersBase(args...) + {} + + TTabletSimpleCounter& TxSimple(TTxType txType, ui32 txCounter) { + return Simple()[IndexOf<CT_SIMPLE>(txType, txCounter)]; + } + + const TTabletSimpleCounter& TxSimple(TTxType txType, ui32 txCounter) const { + return Simple()[IndexOf<CT_SIMPLE>(txType, txCounter)]; + } + + TTabletCumulativeCounter& TxCumulative(TTxType txType, ui32 txCounter) { + return Cumulative()[IndexOf<CT_CUMULATIVE>(txType, txCounter)]; + } + + const TTabletCumulativeCounter& TxCumulative(TTxType txType, ui32 txCounter) const { + return Cumulative()[IndexOf<CT_CUMULATIVE>(txType, txCounter)]; + } + + TTabletPercentileCounter& TxPercentile(TTxType txType, ui32 txCounter) { + return Percentile()[IndexOf<CT_PERCENTILE>(txType, txCounter)]; + } + + const TTabletPercentileCounter& TxPercentile(TTxType txType, ui32 txCounter) const { + return Percentile()[IndexOf<CT_PERCENTILE>(txType, txCounter)]; + } +protected: + template <ECounterType counterType> + size_t IndexOf(TTxType txType, ui32 txCounter) const { + // Note that enum values are used only inside a process, not on disc/messages + // so there are no backward compatibility issues Y_VERIFY(txCounter < TxCountersSize[counterType]); - size_t ret = TxOffset[counterType] + txType * TxCountersSize[counterType] + txCounter; + size_t ret = TxOffset[counterType] + txType * TxCountersSize[counterType] + txCounter; Y_VERIFY(ret < Size[counterType]); - return ret; - } -}; - -// Tablet counters with app counters (SimpleDesc, CumulativeDesc, PercentileDesc) and counters per each tx type (TxTypeDesc) -template <const NProtoBuf::EnumDescriptor* SimpleDesc(), - const NProtoBuf::EnumDescriptor* CumulativeDesc(), - const NProtoBuf::EnumDescriptor* PercentileDesc(), - const NProtoBuf::EnumDescriptor* TxTypeDesc()> -class TProtobufTabletCounters : public TTabletCountersWithTxTypes { + return ret; + } +}; + +// Tablet counters with app counters (SimpleDesc, CumulativeDesc, PercentileDesc) and counters per each tx type (TxTypeDesc) +template <const NProtoBuf::EnumDescriptor* SimpleDesc(), + const NProtoBuf::EnumDescriptor* CumulativeDesc(), + const NProtoBuf::EnumDescriptor* PercentileDesc(), + const NProtoBuf::EnumDescriptor* TxTypeDesc()> +class TProtobufTabletCounters : public TTabletCountersWithTxTypes { public: typedef NAux::TParsedOpts<SimpleDesc, ETxTypeSimpleCounters_descriptor, TxTypeDesc> TSimpleOpts; typedef NAux::TParsedOpts<CumulativeDesc, ETxTypeCumulativeCounters_descriptor, TxTypeDesc> TCumulativeOpts; typedef NAux::TParsedOpts<PercentileDesc, ETxTypePercentileCounters_descriptor, TxTypeDesc> TPercentileOpts; static TSimpleOpts* SimpleOpts() { - return NAux::GetOpts<SimpleDesc, ETxTypeSimpleCounters_descriptor, TxTypeDesc>(); - } - + return NAux::GetOpts<SimpleDesc, ETxTypeSimpleCounters_descriptor, TxTypeDesc>(); + } + static TCumulativeOpts* CumulativeOpts() { - return NAux::GetOpts<CumulativeDesc, ETxTypeCumulativeCounters_descriptor, TxTypeDesc>(); - } - + return NAux::GetOpts<CumulativeDesc, ETxTypeCumulativeCounters_descriptor, TxTypeDesc>(); + } + static TPercentileOpts* PercentileOpts() { - return NAux::GetOpts<PercentileDesc, ETxTypePercentileCounters_descriptor, TxTypeDesc>(); - } - - TProtobufTabletCounters() - : TTabletCountersWithTxTypes( - SimpleOpts()->Size, CumulativeOpts()->Size, PercentileOpts()->Size, - SimpleOpts()->GetNames(), CumulativeOpts()->GetNames(), PercentileOpts()->GetNames() - ) - { + return NAux::GetOpts<PercentileDesc, ETxTypePercentileCounters_descriptor, TxTypeDesc>(); + } + + TProtobufTabletCounters() + : TTabletCountersWithTxTypes( + SimpleOpts()->Size, CumulativeOpts()->Size, PercentileOpts()->Size, + SimpleOpts()->GetNames(), CumulativeOpts()->GetNames(), PercentileOpts()->GetNames() + ) + { FillOffsets(); InitCounters(); } @@ -459,32 +459,32 @@ public: private: void FillOffsets() { - // Initialize stuff for counter addressing - Size[CT_SIMPLE] = SimpleOpts()->Size; - TxOffset[CT_SIMPLE] = SimpleOpts()->TxOffset; - TxCountersSize[CT_SIMPLE] = SimpleOpts()->TxCountersSize; - Size[CT_CUMULATIVE] = CumulativeOpts()->Size; - TxOffset[CT_CUMULATIVE] = CumulativeOpts()->TxOffset; - TxCountersSize[CT_CUMULATIVE] = CumulativeOpts()->TxCountersSize; - Size[CT_PERCENTILE] = PercentileOpts()->Size; - TxOffset[CT_PERCENTILE] = PercentileOpts()->TxOffset; - TxCountersSize[CT_PERCENTILE] = PercentileOpts()->TxCountersSize; - } - + // Initialize stuff for counter addressing + Size[CT_SIMPLE] = SimpleOpts()->Size; + TxOffset[CT_SIMPLE] = SimpleOpts()->TxOffset; + TxCountersSize[CT_SIMPLE] = SimpleOpts()->TxCountersSize; + Size[CT_CUMULATIVE] = CumulativeOpts()->Size; + TxOffset[CT_CUMULATIVE] = CumulativeOpts()->TxOffset; + TxCountersSize[CT_CUMULATIVE] = CumulativeOpts()->TxCountersSize; + Size[CT_PERCENTILE] = PercentileOpts()->Size; + TxOffset[CT_PERCENTILE] = PercentileOpts()->TxOffset; + TxCountersSize[CT_PERCENTILE] = PercentileOpts()->TxCountersSize; + } + void InitCounters() { - // Initialize percentile counters - const auto* opts = PercentileOpts(); - for (size_t i = 0; i < opts->Size; i++) { + // Initialize percentile counters + const auto* opts = PercentileOpts(); + for (size_t i = 0; i < opts->Size; i++) { if (!opts->GetNames()[i]) { continue; } - const auto& vec = opts->GetRanges(i); + const auto& vec = opts->GetRanges(i); Percentile()[i].Initialize(vec.size(), vec.begin(), opts->GetIntegral(i)); - } - } -}; - + } + } +}; + // Tablet counters with app counters (SimpleDesc, CumulativeDesc, PercentileDesc) only template <const NProtoBuf::EnumDescriptor* SimpleDesc(), const NProtoBuf::EnumDescriptor* CumulativeDesc(), @@ -638,4 +638,4 @@ private: -} // end of NKikimr +} // end of NKikimr diff --git a/ydb/core/tablet/tablet_list_renderer.cpp b/ydb/core/tablet/tablet_list_renderer.cpp index ad36f12a29..874de85e9c 100644 --- a/ydb/core/tablet/tablet_list_renderer.cpp +++ b/ydb/core/tablet/tablet_list_renderer.cpp @@ -62,14 +62,14 @@ void TTabletListRenderer::RenderHeader(TStringStream& str, { Y_UNUSED(tabletsToRender); IOutputStream &__stream(str); - H3() { + H3() { str << listName; if (filterInfo.FilterNodeId != 0) { str << " of Node " << filterInfo.FilterNodeId; if (!filterInfo.FilterNodeHost.empty()) str << " (" << filterInfo.FilterNodeHost << ")"; } - } + } } void TTabletListRenderer::RenderTableHeader(TStringStream& str, @@ -80,22 +80,22 @@ void TTabletListRenderer::RenderTableHeader(TStringStream& str, Y_UNUSED(listName); Y_UNUSED(tabletsToRender); IOutputStream &__stream(str); - TABLEHEAD() { - TABLER() { + TABLEHEAD() { + TABLER() { if (filterInfo.FilterNodeId == 0) { - TABLEH() {str << "<span data-toggle='tooltip' title='NodeId'>#</span>";} - TABLEH() {str << "NodeName";} + TABLEH() {str << "<span data-toggle='tooltip' title='NodeId'>#</span>";} + TABLEH() {str << "NodeName";} } - TABLEH() {str << "TabletType";} - TABLEH() {str << "TabletID";} - TABLEH_CLASS("sorter-text") {str << "CreateTime";} - TABLEH_CLASS("sorter-text") {str << "ChangeTime";} - TABLEH() {str << "Core state";} - TABLEH() {str << "User state";} - TABLEH() {str << "Gen";} - TABLEH_CLASS("sorter-false") {str << "Kill";} - } - } + TABLEH() {str << "TabletType";} + TABLEH() {str << "TabletID";} + TABLEH_CLASS("sorter-text") {str << "CreateTime";} + TABLEH_CLASS("sorter-text") {str << "ChangeTime";} + TABLEH() {str << "Core state";} + TABLEH() {str << "User state";} + TABLEH() {str << "Gen";} + TABLEH_CLASS("sorter-false") {str << "Kill";} + } + } } TString TTabletListRenderer::MakeTabletMonURL(const TTabletListElement& elem, @@ -124,7 +124,7 @@ void TTabletListRenderer::RenderTableBody(TStringStream& str, { Y_UNUSED(listName); IOutputStream &__stream(str); - TABLEBODY() { + TABLEBODY() { for (const auto& elem : tabletsToRender) { const auto& ti = *elem.TabletStateInfo; const auto& nodeInfo = *elem.NodeInfo; @@ -133,33 +133,33 @@ void TTabletListRenderer::RenderTableBody(TStringStream& str, TString tabletTypeStr = TTabletTypes::TypeToStr(tabletType); TString nodeName = ToString(nodeInfo.NodeId); - TABLER() { + TABLER() { if (filterInfo.FilterNodeId == 0) { TString nodeName = nodeInfo.Host.empty() ? nodeInfo.Address : nodeInfo.Host; TString tooltip = nodeInfo.Address; - TABLED() {str << ToString(nodeInfo.NodeId);} - TABLED() {str << "<span data-html='true' data-toggle='tooltip' title='" + tooltip + "'>" << nodeName << "</span>";} + TABLED() {str << ToString(nodeInfo.NodeId);} + TABLED() {str << "<span data-html='true' data-toggle='tooltip' title='" + tooltip + "'>" << nodeName << "</span>";} } - TABLED() {str << tabletTypeStr;} + TABLED() {str << tabletTypeStr;} str << "<td data-text='" << index << "'>" << "<a href=\"" << MakeTabletMonURL(elem, filterInfo) << "\">" << ti.tabletid() << "</a>" << "</td>"; - TABLED() {str << TInstant::MilliSeconds(ti.GetCreateTime()).ToStringUpToSeconds();} - TABLED() {str << TInstant::MilliSeconds(ti.GetChangeTime()).ToStringUpToSeconds();} - TABLED() {str << GetStateName((ETabletState)ti.GetState());} - TABLED() {str << GetUserStateName(elem);} - TABLED() {str << ti.generation();} - TABLED() { + TABLED() {str << TInstant::MilliSeconds(ti.GetCreateTime()).ToStringUpToSeconds();} + TABLED() {str << TInstant::MilliSeconds(ti.GetChangeTime()).ToStringUpToSeconds();} + TABLED() {str << GetStateName((ETabletState)ti.GetState());} + TABLED() {str << GetUserStateName(elem);} + TABLED() {str << ti.generation();} + TABLED() { str << "<a href=\"nodetabmon?action=kill_tablet&tablet_id=" << ti.tabletid() << "&node_id=" << nodeInfo.NodeId; if (filterInfo.FilterNodeId != 0) str << "&filter_node_id=" << filterInfo.FilterNodeId; str << "\">" << "<span class=\"glyphicon glyphicon-remove\" title=\"Kill Tablet\"/>" << "</span></a>"; - } - } - } + } + } } + } } TString TTabletListRenderer::GetStateName(ETabletState state) { @@ -184,10 +184,10 @@ void TTabletListRenderer::RenderTabletList(TStringStream& str, IOutputStream &__stream(str); RenderHeader(str, listName, tabletsToRender, filterInfo); - TABLE_SORTABLE_CLASS("table") { + TABLE_SORTABLE_CLASS("table") { RenderTableHeader(str, listName, tabletsToRender, filterInfo); RenderTableBody(str, listName, tabletsToRender, filterInfo); - } + } } } // namespace NNodeTabletMonitor diff --git a/ydb/core/tablet/tablet_monitoring_proxy.cpp b/ydb/core/tablet/tablet_monitoring_proxy.cpp index a61a43b7e5..4857fd81d4 100644 --- a/ydb/core/tablet/tablet_monitoring_proxy.cpp +++ b/ydb/core/tablet/tablet_monitoring_proxy.cpp @@ -238,59 +238,59 @@ TTabletMonitoringProxyActor::Handle(NMon::TEvHttpInfo::TPtr &ev, const TActorCon const NKikimr::TDomainsInfo* domainsInfo = AppData(ctx)->DomainsInfo.Get(); auto& domains = domainsInfo->Domains; - HTML(str) { - for (auto di: domains) { - ui32 domainId = di.first; - H3() { - str << "Domain \"" << di.second->Name << "\" (id: " << domainId << ")"; - } - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "Tablet";} - TABLEH() {str << "ID";} - TABLEH_CLASS("sorter-false") {} - TABLEH_CLASS("sorter-false") {} - } + HTML(str) { + for (auto di: domains) { + ui32 domainId = di.first; + H3() { + str << "Domain \"" << di.second->Name << "\" (id: " << domainId << ")"; + } + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "Tablet";} + TABLEH() {str << "ID";} + TABLEH_CLASS("sorter-false") {} + TABLEH_CLASS("sorter-false") {} + } } - TABLEBODY() { - if (const ui64 schemeRootTabletId = di.second->SchemeRoot) { - TABLER() { + TABLEBODY() { + if (const ui64 schemeRootTabletId = di.second->SchemeRoot) { + TABLER() { TABLED() {str << "<a href=\"tablets?TabletID=" << schemeRootTabletId << "\">SCHEMESHARD</a>";} - TABLED() {str << schemeRootTabletId;} - TABLED() {str << " <a href=\"tablets?SsId=" - << schemeRootTabletId << "\">" - << "<span class=\"glyphicon glyphicon-tasks\"" - << " title=\"State Storage\"/>" - << "</a>";} - TABLED() {str << "<a href='tablets?KillTabletID=" << schemeRootTabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} - } - } - for (auto hi : di.second->HiveUids) { - ui64 tabletId = domainsInfo->GetHive(hi); - TABLER() { - TABLED() {str << "<a href=\"tablets?TabletID=" << tabletId << "\">HIVE</a>";} - TABLED() {str << tabletId;} - TABLED() {str << " <a href=\"tablets?SsId=" - << tabletId << "\">" - << "<span class=\"glyphicon glyphicon-tasks\"" - << " title=\"State Storage\" />" - << "</a>";} - TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} - } - } - for (auto si : di.second->StateStorageGroups) { - ui64 tabletId = NKikimr::MakeBSControllerID(si); - TABLER() { - TABLED() {str << "<a href=\"tablets?TabletID=" << tabletId << "\">BS_CONTROLLER</a>";} - TABLED() {str << tabletId;} - TABLED() {str << " <a href=\"tablets?SsId=" - << tabletId << "\">" - << "<span class=\"glyphicon glyphicon-tasks\"" - << " title=\"State Storage\" />" - << "</a>";} - TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} - } + TABLED() {str << schemeRootTabletId;} + TABLED() {str << " <a href=\"tablets?SsId=" + << schemeRootTabletId << "\">" + << "<span class=\"glyphicon glyphicon-tasks\"" + << " title=\"State Storage\"/>" + << "</a>";} + TABLED() {str << "<a href='tablets?KillTabletID=" << schemeRootTabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} + } + } + for (auto hi : di.second->HiveUids) { + ui64 tabletId = domainsInfo->GetHive(hi); + TABLER() { + TABLED() {str << "<a href=\"tablets?TabletID=" << tabletId << "\">HIVE</a>";} + TABLED() {str << tabletId;} + TABLED() {str << " <a href=\"tablets?SsId=" + << tabletId << "\">" + << "<span class=\"glyphicon glyphicon-tasks\"" + << " title=\"State Storage\" />" + << "</a>";} + TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} + } + } + for (auto si : di.second->StateStorageGroups) { + ui64 tabletId = NKikimr::MakeBSControllerID(si); + TABLER() { + TABLED() {str << "<a href=\"tablets?TabletID=" << tabletId << "\">BS_CONTROLLER</a>";} + TABLED() {str << tabletId;} + TABLED() {str << " <a href=\"tablets?SsId=" + << tabletId << "\">" + << "<span class=\"glyphicon glyphicon-tasks\"" + << " title=\"State Storage\" />" + << "</a>";} + TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} + } tabletId = NKikimr::MakeCmsID(si); TABLER() { TABLED() {str << "<a href=\"tablets?TabletID=" << tabletId << "\">CMS</a>";} @@ -335,52 +335,52 @@ TTabletMonitoringProxyActor::Handle(NMon::TEvHttpInfo::TPtr &ev, const TActorCon << "</a>";} TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} } - } + } for (auto tabletId : di.second->Coordinators) { - TABLER() { - TABLED() {str << "<a href=\"tablets?TabletID=" << tabletId << "\">TX_COORDINATOR</a>";} - TABLED() {str << tabletId;} - TABLED() {str << " <a href=\"tablets?SsId=" - << tabletId << "\">" - << "<span class=\"glyphicon glyphicon-tasks\"" - << " title=\"State Storage\" />" - << "</a>";} - TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} - } - } + TABLER() { + TABLED() {str << "<a href=\"tablets?TabletID=" << tabletId << "\">TX_COORDINATOR</a>";} + TABLED() {str << tabletId;} + TABLED() {str << " <a href=\"tablets?SsId=" + << tabletId << "\">" + << "<span class=\"glyphicon glyphicon-tasks\"" + << " title=\"State Storage\" />" + << "</a>";} + TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} + } + } for (auto tabletId : di.second->Mediators) { - TABLER() { - TABLED() {str << "<a href=\"tablets?TabletID=" << tabletId << "\">TX_MEDIATOR</a>";} - TABLED() {str << tabletId;} - TABLED() {str << " <a href=\"tablets?SsId=" - << tabletId << "\">" - << "<span class=\"glyphicon glyphicon-tasks\"" - << " title=\"State Storage\" />" - << "</a>";} - TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} - } - } + TABLER() { + TABLED() {str << "<a href=\"tablets?TabletID=" << tabletId << "\">TX_MEDIATOR</a>";} + TABLED() {str << tabletId;} + TABLED() {str << " <a href=\"tablets?SsId=" + << tabletId << "\">" + << "<span class=\"glyphicon glyphicon-tasks\"" + << " title=\"State Storage\" />" + << "</a>";} + TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} + } + } for (auto tabletId : di.second->TxAllocators) { - TABLER() { + TABLER() { TABLED() {str << "<a href=\"tablets?TabletID=" << tabletId << "\">TX_ALLOCATOR</a>";} - TABLED() {str << tabletId;} - TABLED() {str << " <a href=\"tablets?SsId=" - << tabletId << "\">" - << "<span class=\"glyphicon glyphicon-tasks\"" - << " title=\"State Storage\" />" - << "</a>";} - TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} - } - } - } - } - } - str << "<form method=\"GET\" id=\"tblMonPrxFrm\" name=\"tblMonPrxFrm\">" << Endl; - str << "<h2>Lookup</h2>" << Endl; - str << "TabletID: <input type=\"text\" id=\"TabletID\" name=\"TabletID\"/>" << Endl; - str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"Watch\"/>" << Endl; - str << "</form>" << Endl; - } + TABLED() {str << tabletId;} + TABLED() {str << " <a href=\"tablets?SsId=" + << tabletId << "\">" + << "<span class=\"glyphicon glyphicon-tasks\"" + << " title=\"State Storage\" />" + << "</a>";} + TABLED() {str << "<a href='tablets?KillTabletID=" << tabletId << "'><span class='glyphicon glyphicon-remove' title='Kill Tablet'/></a>";} + } + } + } + } + } + str << "<form method=\"GET\" id=\"tblMonPrxFrm\" name=\"tblMonPrxFrm\">" << Endl; + str << "<h2>Lookup</h2>" << Endl; + str << "TabletID: <input type=\"text\" id=\"TabletID\" name=\"TabletID\"/>" << Endl; + str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"Watch\"/>" << Endl; + str << "</form>" << Endl; + } ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str())); } diff --git a/ydb/core/tablet/ya.make b/ydb/core/tablet/ya.make index 25e611b408..ef4678f777 100644 --- a/ydb/core/tablet/ya.make +++ b/ydb/core/tablet/ya.make @@ -22,7 +22,7 @@ SRCS( tablet_counters_aggregator.h tablet_counters_app.cpp tablet_counters_app.h - tablet_counters_protobuf.h + tablet_counters_protobuf.h tablet_exception.h tablet_impl.h tablet_tracing_signals.cpp diff --git a/ydb/core/tablet_flat/defs.h b/ydb/core/tablet_flat/defs.h index 166674c3ff..a6fdb61a19 100644 --- a/ydb/core/tablet_flat/defs.h +++ b/ydb/core/tablet_flat/defs.h @@ -14,9 +14,9 @@ namespace NKikimr { -using TTxType = ui32; // App-specific transaction type number (protobuf enum values like TXTYPE_*) -constexpr TTxType UnknownTxType = TTxType(-1); - +using TTxType = ui32; // App-specific transaction type number (protobuf enum values like TXTYPE_*) +constexpr TTxType UnknownTxType = TTxType(-1); + namespace NScheme { class TTypeRegistry; diff --git a/ydb/core/tablet_flat/flat_cxx_database.h b/ydb/core/tablet_flat/flat_cxx_database.h index 27a260bcb2..ccd38621e1 100644 --- a/ydb/core/tablet_flat/flat_cxx_database.h +++ b/ydb/core/tablet_flat/flat_cxx_database.h @@ -465,7 +465,7 @@ struct TConvertValueFromRawTypeValueToPod { return static_cast<TargetType>(static_cast<typename NSchemeTypeMapper<TColumnType::ColumnType>::Type>(Value)); } }; - + template <typename ColumnType, typename VectorType> struct TConvertValue<ColumnType, TVector<VectorType>, TRawTypeValue> { TVector<VectorType> Value; diff --git a/ydb/core/tablet_flat/flat_database.cpp b/ydb/core/tablet_flat/flat_database.cpp index c459119515..e86ae0ac8a 100644 --- a/ydb/core/tablet_flat/flat_database.cpp +++ b/ydb/core/tablet_flat/flat_database.cpp @@ -297,8 +297,8 @@ ui64 TDatabase::EstimateRowSize(ui32 tableId) const { const TDbStats& TDatabase::Counters() const noexcept { return DatabaseImpl->Stats; -} - +} + TDatabase::TChg TDatabase::Head(ui32 table) const noexcept { if (table == Max<ui32>()) { diff --git a/ydb/core/tablet_flat/flat_dbase_scheme.h b/ydb/core/tablet_flat/flat_dbase_scheme.h index 1fd5ed2b48..57a040bcf8 100644 --- a/ydb/core/tablet_flat/flat_dbase_scheme.h +++ b/ydb/core/tablet_flat/flat_dbase_scheme.h @@ -147,8 +147,8 @@ public: inline const TColumn* GetColumnInfo(const TTableInfo* ptable, ui32 id) const { return ptable ? ptable->Columns.FindPtr(id) : nullptr; - } - + } + bool IsEmpty() const { return Tables.empty(); } diff --git a/ydb/core/tablet_flat/flat_executor.cpp b/ydb/core/tablet_flat/flat_executor.cpp index 59afc46215..9929e6f142 100644 --- a/ydb/core/tablet_flat/flat_executor.cpp +++ b/ydb/core/tablet_flat/flat_executor.cpp @@ -1741,7 +1741,7 @@ void TExecutor::PostponeTransaction(TAutoPtr<TSeat> seat, TPageCollectionTxEnv & if (pad->Seat->Retries == 1) { Counters->Cumulative()[TExecutorCounters::TX_RETRIED].Increment(1); Counters->Cumulative()[TExecutorCounters::TX_CACHE_HITS].Increment(touchedPages); - } + } Counters->Cumulative()[TExecutorCounters::TX_BYTES_READ].Increment(loadBytes); Counters->Cumulative()[TExecutorCounters::TX_CACHE_MISSES].Increment(loadPages); @@ -1768,8 +1768,8 @@ void TExecutor::CommitTransactionLog(TAutoPtr<TSeat> seat, TPageCollectionTxEnv PrivatePageCache->Touch(blockId, pageCollectionInfo); } Counters->Percentile()[TExecutorCounters::TX_PERCENTILE_TOUCHED_BLOCKS].IncrementFor(touchedBlocks); - if (AppTxCounters && txType != UnknownTxType) - AppTxCounters->TxCumulative(txType, COUNTER_TT_TOUCHED_BLOCKS).Increment(touchedBlocks); + if (AppTxCounters && txType != UnknownTxType) + AppTxCounters->TxCumulative(txType, COUNTER_TT_TOUCHED_BLOCKS).Increment(touchedBlocks); if (seat->Retries == 1) { Counters->Cumulative()[TExecutorCounters::TX_CACHE_HITS].Increment(touchedBlocks); @@ -2275,10 +2275,10 @@ void TExecutor::CommitTransactionLog(TAutoPtr<TSeat> seat, TPageCollectionTxEnv Counters->Percentile()[TExecutorCounters::TX_PERCENTILE_EXECUTE_CPUTIME].IncrementFor(execTimeuS); Counters->Percentile()[TExecutorCounters::TX_PERCENTILE_BOOKKEEPING_CPUTIME].IncrementFor(bookkeepingTimeuS); Counters->Cumulative()[TExecutorCounters::CONSUMED_CPU].Increment(execTimeuS + bookkeepingTimeuS); - if (AppTxCounters && txType != UnknownTxType) { - AppTxCounters->TxCumulative(txType, COUNTER_TT_EXECUTE_CPUTIME).Increment(execTimeuS); - AppTxCounters->TxCumulative(txType, COUNTER_TT_BOOKKEEPING_CPUTIME).Increment(bookkeepingTimeuS); - } + if (AppTxCounters && txType != UnknownTxType) { + AppTxCounters->TxCumulative(txType, COUNTER_TT_EXECUTE_CPUTIME).Increment(execTimeuS); + AppTxCounters->TxCumulative(txType, COUNTER_TT_BOOKKEEPING_CPUTIME).Increment(bookkeepingTimeuS); + } if (ResourceMetrics) { ResourceMetrics->CPU.Increment(bookkeepingTimeuS + execTimeuS, Time->Now()); @@ -3632,28 +3632,28 @@ void TExecutor::RenderHtmlCounters(NMon::TEvRemoteHttpInfo::TPtr &ev) const { TStringStream str; if (Database) { - HTML(str) { + HTML(str) { str << "<style>"; str << "table.metrics { margin-bottom: 20px; }"; str << "table.metrics td { text-align: right; padding-right: 10px; }"; str << "table.metrics td:nth-child(3) { text-align: left; }"; str << "</style>"; if (Counters) { - H3() {str << "Executor counters";} + H3() {str << "Executor counters";} Counters->OutputHtml(str); } if (AppCounters) { - H3() {str << "App counters";} + H3() {str << "App counters";} AppCounters->OutputHtml(str); } if (ResourceMetrics) { str << NMetrics::AsHTML(*ResourceMetrics); } - } + } } else { - HTML(str) {str << "loading...";} // todo: populate from bootlogic + HTML(str) {str << "loading...";} // todo: populate from bootlogic } Send(ev->Sender, new NMon::TEvRemoteHttpInfoRes(str.Str())); @@ -3690,7 +3690,7 @@ void TExecutor::RenderHtmlPage(NMon::TEvRemoteHttpInfo::TPtr &ev) const { } else { message = "ERROR: cannot parse table id"; } - HTML(str) { + HTML(str) { DIV_CLASS("row") { DIV_CLASS("col-md-12") {str << message; } } @@ -3722,24 +3722,24 @@ void TExecutor::RenderHtmlPage(NMon::TEvRemoteHttpInfo::TPtr &ev) const { DIV_CLASS("row") { str << "Booted tablet without dbase"; } } - H3() {str << "Scheme:";} + H3() {str << "Scheme:";} TVector<ui32> tables; for (const auto &xtable : scheme->Tables) tables.push_back(xtable.first); Sort(tables); for (auto itable : tables) { const auto &tinfo = scheme->Tables.find(itable)->second; - H4() {str << "<a href='db?TabletID=" << Owner->TabletID() << "&TableID=" << tinfo.Id << "'>Table: \"" << tinfo.Name << "\" id: " << tinfo.Id << "</a>";} - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() {str << "Name";} - TABLEH() {str << "Id";} - TABLEH() {str << "Type";} - TABLEH() {str << "Key order";} - } - } - TABLEBODY() { + H4() {str << "<a href='db?TabletID=" << Owner->TabletID() << "&TableID=" << tinfo.Id << "'>Table: \"" << tinfo.Name << "\" id: " << tinfo.Id << "</a>";} + TABLE_SORTABLE_CLASS("table") { + TABLEHEAD() { + TABLER() { + TABLEH() {str << "Name";} + TABLEH() {str << "Id";} + TABLEH() {str << "Type";} + TABLEH() {str << "Key order";} + } + } + TABLEBODY() { TVector<ui32> columns; for (const auto &xcol : tinfo.Columns) columns.push_back(xcol.first); @@ -3747,18 +3747,18 @@ void TExecutor::RenderHtmlPage(NMon::TEvRemoteHttpInfo::TPtr &ev) const { for (auto icol : columns) { const auto &col = tinfo.Columns.find(icol)->second; const bool isKey = (tinfo.KeyColumns.end() != std::find(tinfo.KeyColumns.begin(), tinfo.KeyColumns.end(), col.Id)); - TABLER() { - TABLED() {str << col.Name;} - TABLED() {str << col.Id;} - TABLED() {str << tr.GetTypeName(col.PType);} - TABLED() {str << (isKey ? ToString(col.KeyOrder) : "");} - } + TABLER() { + TABLED() {str << col.Name;} + TABLED() {str << col.Id;} + TABLED() {str << tr.GetTypeName(col.PType);} + TABLED() {str << (isKey ? ToString(col.KeyOrder) : "");} + } } - } - } + } + } } - H3() {str << "Storage:";} + H3() {str << "Storage:";} DIV_CLASS("row") {str << "Bytes pinned in cache: " << PrivatePageCache->GetStats().PinnedSetSize << Endl; } DIV_CLASS("row") {str << "Bytes pinned to load: " << PrivatePageCache->GetStats().PinnedLoadSize << Endl; } @@ -3770,8 +3770,8 @@ void TExecutor::RenderHtmlPage(NMon::TEvRemoteHttpInfo::TPtr &ev) const { CompactionLogic->OutputHtml(str, *scheme, cgi); H3() {str << "Page collection cache:";} - DIV_CLASS("row") {str << "fresh bytes: " << CounterCacheFresh->Val(); } - DIV_CLASS("row") {str << "staging bytes: " << CounterCacheStaging->Val(); } + DIV_CLASS("row") {str << "fresh bytes: " << CounterCacheFresh->Val(); } + DIV_CLASS("row") {str << "staging bytes: " << CounterCacheStaging->Val(); } DIV_CLASS("row") {str << "memTable bytes: " << CounterCacheMemTable->Val(); } DIV_CLASS("row") {str << "Total collections: " << PrivatePageCache->GetStats().TotalCollections; } DIV_CLASS("row") {str << "Total bytes in shared cache: " << PrivatePageCache->GetStats().TotalSharedBody; } @@ -3781,26 +3781,26 @@ void TExecutor::RenderHtmlPage(NMon::TEvRemoteHttpInfo::TPtr &ev) const { DIV_CLASS("row") {str << "Total bytes marked as sticky: " << PrivatePageCache->GetStats().TotalSticky; } if (GcLogic) { - H3() {str << "Gc logic:";} + H3() {str << "Gc logic:";} auto gcInfo = GcLogic->IntrospectStateSize(); - DIV_CLASS("row") {str << "uncommited entries: " << gcInfo.UncommitedEntries;} - DIV_CLASS("row") {str << "uncommited blob ids: " << gcInfo.UncommitedBlobIds; } - DIV_CLASS("row") {str << "uncommited entries bytes: " << gcInfo.UncommitedEntriesBytes;} - DIV_CLASS("row") {str << "commited entries: " << gcInfo.CommitedEntries;} - DIV_CLASS("row") {str << "commited blob ids known: " << gcInfo.CommitedBlobIdsKnown;} - DIV_CLASS("row") {str << "commited blob ids left: " << gcInfo.CommitedBlobIdsLeft;} - DIV_CLASS("row") {str << "commited entries bytes: " << gcInfo.CommitedEntriesBytes; } - DIV_CLASS("row") {str << "active collect barriers: " << gcInfo.BarriersSetSize; } + DIV_CLASS("row") {str << "uncommited entries: " << gcInfo.UncommitedEntries;} + DIV_CLASS("row") {str << "uncommited blob ids: " << gcInfo.UncommitedBlobIds; } + DIV_CLASS("row") {str << "uncommited entries bytes: " << gcInfo.UncommitedEntriesBytes;} + DIV_CLASS("row") {str << "commited entries: " << gcInfo.CommitedEntries;} + DIV_CLASS("row") {str << "commited blob ids known: " << gcInfo.CommitedBlobIdsKnown;} + DIV_CLASS("row") {str << "commited blob ids left: " << gcInfo.CommitedBlobIdsLeft;} + DIV_CLASS("row") {str << "commited entries bytes: " << gcInfo.CommitedEntriesBytes; } + DIV_CLASS("row") {str << "active collect barriers: " << gcInfo.BarriersSetSize; } } if (BorrowLogic) { - H3() {str << "Borrow logic:";} + H3() {str << "Borrow logic:";} BorrowLogic->OutputHtml(str); } - } + } } else { - HTML(str) {str << "loading...";} // todo: populate from bootlogic + HTML(str) {str << "loading...";} // todo: populate from bootlogic } Send(ev->Sender, new NMon::TEvRemoteHttpInfoRes(str.Str())); @@ -3815,7 +3815,7 @@ void TExecutor::RegisterExternalTabletCounters(TAutoPtr<TTabletCountersBase> app AppCounters = appCounters; AppCountersBaseline = MakeHolder<TTabletCountersBase>(); AppCounters->RememberCurrentStateAsBaseline(*AppCountersBaseline); - + if (LogicRedo) { AppTxCounters = dynamic_cast<TTabletCountersWithTxTypes*>(AppCounters.Get()); LogicRedo->InstallCounters(Counters.Get(), AppTxCounters); diff --git a/ydb/core/tablet_flat/flat_executor.h b/ydb/core/tablet_flat/flat_executor.h index df08b3a338..7c71830f4b 100644 --- a/ydb/core/tablet_flat/flat_executor.h +++ b/ydb/core/tablet_flat/flat_executor.h @@ -406,8 +406,8 @@ class TExecutor // Used control number of in flight events to the counter aggregator TIntrusivePtr<TEvTabletCounters::TInFlightCookie> CounterEventsInFlight; - TTabletCountersWithTxTypes* AppTxCounters = nullptr; - + TTabletCountersWithTxTypes* AppTxCounters = nullptr; + TActorId Launcher; THashMap<TPrivatePageCacheWaitPad*, THolder<TTransactionWaitPad>> TransactionWaitPads; @@ -609,7 +609,7 @@ public: const TExecutorStats& GetStats() const override; NMetrics::TResourceMetrics* GetResourceMetrics() const override; - void RegisterExternalTabletCounters(TAutoPtr<TTabletCountersBase> appCounters) override; + void RegisterExternalTabletCounters(TAutoPtr<TTabletCountersBase> appCounters) override; static constexpr NKikimrServices::TActivity::EType ActorActivityType() { return NKikimrServices::TActivity::FLAT_EXECUTOR; diff --git a/ydb/core/tablet_flat/flat_executor_borrowlogic.cpp b/ydb/core/tablet_flat/flat_executor_borrowlogic.cpp index bd52264b10..d57dabc230 100644 --- a/ydb/core/tablet_flat/flat_executor_borrowlogic.cpp +++ b/ydb/core/tablet_flat/flat_executor_borrowlogic.cpp @@ -526,9 +526,9 @@ void TExecutorBorrowLogic::RestoreBorrowedInfo(const TLogoBlobID &blobId, const } void TExecutorBorrowLogic::OutputHtml(IOutputStream &out) { - HTML(out) { - H4() {out << "Borrowed parts";} - PRE() { + HTML(out) { + H4() {out << "Borrowed parts";} + PRE() { for (const auto &xpair : BorrowedInfo) { if (xpair.second.BorrowInfo.FullBorrow) { out << xpair.first << ":"; @@ -537,10 +537,10 @@ void TExecutorBorrowLogic::OutputHtml(IOutputStream &out) { out << Endl; } } - } + } - H4() {out << "Loaned parts";} - PRE() { + H4() {out << "Loaned parts";} + PRE() { for (const auto &xpair : BorrowedInfo) { if (xpair.second.LoanInfo.Lender) out << xpair.first << ": " << xpair.second.LoanInfo.Lender; @@ -548,8 +548,8 @@ void TExecutorBorrowLogic::OutputHtml(IOutputStream &out) { out << " - collected"; out << Endl; } - } - } + } + } } TString TExecutorBorrowLogic::DebugCheckBorrowConsistency(THashSet<TLogoBlobID> &knownBundles) { diff --git a/ydb/core/tablet_flat/flat_executor_compaction_logic.cpp b/ydb/core/tablet_flat/flat_executor_compaction_logic.cpp index 3d699e8f87..deaec5d7dc 100644 --- a/ydb/core/tablet_flat/flat_executor_compaction_logic.cpp +++ b/ydb/core/tablet_flat/flat_executor_compaction_logic.cpp @@ -737,11 +737,11 @@ ui64 TCompactionLogic::GetBackingSize(ui64 ownerTabletId) const { } void TCompactionLogic::OutputHtml(IOutputStream &out, const NTable::TScheme &scheme, const TCgiParameters& cgi) { - HTML(out) { + HTML(out) { for (const auto &xtable : State->Tables) { - H4() {out << scheme.GetTableInfo(xtable.first)->Name;} + H4() {out << scheme.GetTableInfo(xtable.first)->Name;} - DIV_CLASS("row") { out + DIV_CLASS("row") { out << "InMem Size: " << xtable.second.InMem.EstimatedSize << ", Changes: " << xtable.second.InMem.Steps << ", Compaction state: " << xtable.second.InMem.State @@ -760,11 +760,11 @@ void TCompactionLogic::OutputHtml(IOutputStream &out, const NTable::TScheme &sch << " (priority " << xtable.second.InMem.CompactionTask.Priority << ") submitted " << xtable.second.InMem.CompactionTask.SubmissionTimestamp.ToStringLocal(); } - } + } xtable.second.Strategy->OutputHtml(out); } - } + } } }} diff --git a/ydb/core/tablet_flat/flat_executor_txloglogic.cpp b/ydb/core/tablet_flat/flat_executor_txloglogic.cpp index df59ddc245..9f6d4f6021 100644 --- a/ydb/core/tablet_flat/flat_executor_txloglogic.cpp +++ b/ydb/core/tablet_flat/flat_executor_txloglogic.cpp @@ -42,7 +42,7 @@ void TLogicRedo::Describe(IOutputStream &out) const noexcept void TLogicRedo::InstallCounters(TExecutorCounters *counters, TTabletCountersWithTxTypes *appTxCounters) { Counters = counters; - AppTxCounters = appTxCounters; + AppTxCounters = appTxCounters; } NRedo::TStats TLogicRedo::LogStats() const noexcept @@ -72,7 +72,7 @@ bool TLogicRedo::TerminateTransaction(TAutoPtr<TSeat> seat, const TActorContext void CompleteRoTransaction(TAutoPtr<TSeat> seat, const TActorContext &ownerCtx, TExecutorCounters *counters, TTabletCountersWithTxTypes *appTxCounters ) { const TTxType txType = seat->Self->GetTxType(); - + const ui64 latencyus = ui64(1000000. * seat->LatencyTimer.Passed()); counters->Percentile()[TExecutorCounters::TX_PERCENTILE_LATENCY_RO].IncrementFor(latencyus); diff --git a/ydb/core/tablet_flat/flat_executor_txloglogic.h b/ydb/core/tablet_flat/flat_executor_txloglogic.h index 1272c4f947..e11e996e08 100644 --- a/ydb/core/tablet_flat/flat_executor_txloglogic.h +++ b/ydb/core/tablet_flat/flat_executor_txloglogic.h @@ -58,7 +58,7 @@ public: ~TLogicRedo(); void Describe(IOutputStream &out) const noexcept; - void InstallCounters(TExecutorCounters *counters, TTabletCountersWithTxTypes* appTxCounters); + void InstallCounters(TExecutorCounters *counters, TTabletCountersWithTxTypes* appTxCounters); bool TerminateTransaction(TAutoPtr<TSeat>, const TActorContext &ctx, const TActorId &ownerId); bool CommitROTransaction(TAutoPtr<TSeat> seat, const TActorContext &ownerCtx); TCommitRWTransactionResult CommitRWTransaction(TAutoPtr<TSeat> seat, NTable::TChange &change, bool force); diff --git a/ydb/core/tablet_flat/flat_iterator.h b/ydb/core/tablet_flat/flat_iterator.h index 60195c17b4..130de7e6e9 100644 --- a/ydb/core/tablet_flat/flat_iterator.h +++ b/ydb/core/tablet_flat/flat_iterator.h @@ -404,15 +404,15 @@ private: Inactive = Active; } - // ITERATORS STORAGE + // ITERATORS STORAGE // Range [ IteratorsHeap.begin(); Active ) form a heap // Range [ Active; IteratorsHeap.end() ) are currently active iterators (i.e. that have key equal to current key) - // Also note that active iterators should be traversed in reverse order + // Also note that active iterators should be traversed in reverse order TComparator Comparator; using TIterators = TSmallVec<TElement>; using TForwardIter = typename TIterators::iterator; using TReverseIter = typename TIterators::reverse_iterator; - + TIterators Iterators; TForwardIter Active; TForwardIter Inactive; @@ -420,7 +420,7 @@ private: TRowVersion DeltaVersion; bool Delta = false; bool Uncommitted = false; - + EReady Start() noexcept; EReady Turn() noexcept; EReady Snap() noexcept; @@ -428,7 +428,7 @@ private: EReady DoSkipUncommitted() noexcept; EReady Apply() noexcept; void AddReadyIterator(TArrayRef<const TCell> key, TIteratorId itId); - void AddNotReadyIterator(TIteratorId itId); + void AddNotReadyIterator(TIteratorId itId); bool SeekInternal(TArrayRef<const TCell> key, ESeek seek) noexcept; }; @@ -481,16 +481,16 @@ inline void TTableItBase<TIteratorOps>::AddReadyIterator(TArrayRef<const TCell> ++Active; std::push_heap(Iterators.begin(), Active, Comparator); Inactive = Active; -} - +} + template<class TIteratorOps> inline void TTableItBase<TIteratorOps>::AddNotReadyIterator(TIteratorId itId) { size_t actPos = Active - Iterators.begin(); Iterators.emplace_back(TElement({{ }, itId})); Active = Iterators.begin() + actPos; Inactive = Active; -} - +} + template<class TIteratorOps> inline void TTableItBase<TIteratorOps>::Push(TAutoPtr<TMemIt> it) { @@ -566,7 +566,7 @@ inline EReady TTableItBase<TIteratorOps>::Start() noexcept { return EReady::Gone; } - + auto key = Iterators.front().Key; PopHeap(Iterators.begin(), Active--, Comparator); while (Active != Iterators.begin()) { @@ -581,7 +581,7 @@ inline EReady TTableItBase<TIteratorOps>::Start() noexcept PopHeap(Iterators.begin(), Active--, Comparator); } - + Stage = EStage::Snap; Inactive = Iterators.end(); return EReady::Data; @@ -651,7 +651,7 @@ inline EReady TTableItBase<TIteratorOps>::Turn() noexcept return EReady::Page; } - return Start(); + return Start(); } template<class TIteratorOps> @@ -868,7 +868,7 @@ inline EReady TTableItBase<TIteratorOps>::Apply() noexcept bool committed = false; for (auto i = TReverseIter(Inactive), e = TReverseIter(Active); i != e; ++i) { - TIteratorId ai = i->IteratorId; + TIteratorId ai = i->IteratorId; switch (ai.Type) { case EType::Mem: { auto& it = *MemIters[ai.Index]; @@ -929,7 +929,7 @@ inline EReady TTableItBase<TIteratorOps>::Apply() noexcept template<class TIteratorOps> inline TDbTupleRef TTableItBase<TIteratorOps>::GetKey() const noexcept { - TIteratorId ai = Iterators.back().IteratorId; + TIteratorId ai = Iterators.back().IteratorId; switch (ai.Type) { case EType::Mem: return MemIters[ai.Index]->GetKey(); diff --git a/ydb/core/tablet_flat/flat_scan_actor.h b/ydb/core/tablet_flat/flat_scan_actor.h index 5cbf2797a0..34402b03ab 100644 --- a/ydb/core/tablet_flat/flat_scan_actor.h +++ b/ydb/core/tablet_flat/flat_scan_actor.h @@ -411,7 +411,7 @@ namespace NOps { : LastSeen(seen) , LastSkipped(skipped) { - GetTimeFast(&StartTime); + GetTimeFast(&StartTime); EndTime = StartTime; } @@ -425,7 +425,7 @@ namespace NOps { } void UpdateCycles() { - GetTimeFast(&EndTime); + GetTimeFast(&EndTime); } NHPTimer::STime ElapsedCycles() const { diff --git a/ydb/core/tablet_flat/flat_table.h b/ydb/core/tablet_flat/flat_table.h index a1fdeb9709..34839709af 100644 --- a/ydb/core/tablet_flat/flat_table.h +++ b/ydb/core/tablet_flat/flat_table.h @@ -9,7 +9,7 @@ #include "flat_part_laid.h" #include "flat_part_slice.h" #include "flat_table_committed.h" -#include "flat_table_part.h" +#include "flat_table_part.h" #include "flat_table_stats.h" #include "flat_table_subset.h" #include "flat_table_misc.h" @@ -217,7 +217,7 @@ public: return size; } - + ui64 GetMemWaste() const noexcept { return Stat_.FrozenWaste + (Mutable ? Mutable->GetWastedMem() : 0); diff --git a/ydb/core/tablet_flat/flat_table_part.cpp b/ydb/core/tablet_flat/flat_table_part.cpp index 235229cc35..ffd1dc5e93 100644 --- a/ydb/core/tablet_flat/flat_table_part.cpp +++ b/ydb/core/tablet_flat/flat_table_part.cpp @@ -1,23 +1,23 @@ #include "flat_page_label.h" #include "flat_part_iface.h" -#include "flat_table_part.h" +#include "flat_table_part.h" #include "util_basics.h" #include <ydb/core/util/pb.h> #include <ydb/core/tablet_flat/protos/flat_table_part.pb.h> #include <library/cpp/containers/stack_vector/stack_vec.h> #include <util/generic/map.h> - -namespace NKikimr { + +namespace NKikimr { namespace NTable { - + TPartScheme::TPartScheme(TArrayRef<const TColInfo> cols) { ui32 maxGroup = 0; for (auto& col : cols) { maxGroup = Max(maxGroup, col.Group); } - + ui32 pos = 0; Groups.resize(size_t(maxGroup) + 1); for (auto& col : cols) { @@ -27,8 +27,8 @@ TPartScheme::TPartScheme(TArrayRef<const TColInfo> cols) FillKeySlots(); FillHistoricSlots(); -} - +} + TIntrusiveConstPtr<TPartScheme> TPartScheme::Parse(TArrayRef<const char> raw, bool labeled) { if (labeled) { @@ -72,8 +72,8 @@ TIntrusiveConstPtr<TPartScheme> TPartScheme::Parse(TArrayRef<const char> raw, bo } return new TPartScheme(cols); -} - +} + void TPartScheme::FillKeySlots() { for (auto& group : Groups) { @@ -197,12 +197,12 @@ TSharedData TPartScheme::Serialize() const if (col.IsKey()) { pb->SetKey(col.Key); } - } - - TStringStream ss; + } + + TStringStream ss; proto.SerializeToArcadiaStream(&ss); return NPage::THello::Wrap(ss.Str(), EPage::Schem2, Groups.size() > 1 ? 1 : 0); -} - -}} +} + +}} diff --git a/ydb/core/tablet_flat/flat_table_part.h b/ydb/core/tablet_flat/flat_table_part.h index aa555c515b..5fd42ec7e2 100644 --- a/ydb/core/tablet_flat/flat_table_part.h +++ b/ydb/core/tablet_flat/flat_table_part.h @@ -101,9 +101,9 @@ namespace NTable { "Part has %" PRISZT " indexes, but %" PRISZT " historic indexes", Groups, HistoricIndexes.size()); } - + virtual ~TPart() = default; - + void Describe(IOutputStream &out) const noexcept { out @@ -124,7 +124,7 @@ namespace NTable { virtual ui64 DataSize() const = 0; virtual ui64 BackingSize() const = 0; virtual ui64 GetPageSize(NPage::TPageId id, NPage::TGroupId groupId = { }) const = 0; - + const NPage::TIndex& GetGroupIndex(NPage::TGroupId groupId) const noexcept { if (!groupId.Historic) { if (groupId.Index == 0) { diff --git a/ydb/core/tablet_flat/flat_table_part_ut.cpp b/ydb/core/tablet_flat/flat_table_part_ut.cpp index 185265a95e..04c823ca17 100644 --- a/ydb/core/tablet_flat/flat_table_part_ut.cpp +++ b/ydb/core/tablet_flat/flat_table_part_ut.cpp @@ -6,18 +6,18 @@ #include "flat_stat_part.h" #include "flat_stat_table.h" #include "flat_page_other.h" - + #include <library/cpp/testing/unittest/registar.h> - + #include <util/stream/null.h> #include <util/random/mersenne.h> -namespace NKikimr { +namespace NKikimr { namespace NTable { namespace NTest { - + Y_UNIT_TEST_SUITE(TLegacy) { - + /* This is legacy place for UT, do not put here more tests */ static TIntrusiveConstPtr<NPage::TFrames> CookFrames() @@ -312,10 +312,10 @@ Y_UNIT_TEST_SUITE(TLegacy) { } } -} - +} + } // namespace NTest } // namspace NTable -} // namespace NKikimr - - +} // namespace NKikimr + + diff --git a/ydb/core/tablet_flat/protos/flat_table_part.proto b/ydb/core/tablet_flat/protos/flat_table_part.proto index 61fa39e957..f2e00a0e91 100644 --- a/ydb/core/tablet_flat/protos/flat_table_part.proto +++ b/ydb/core/tablet_flat/protos/flat_table_part.proto @@ -1,26 +1,26 @@ import "ydb/core/protos/base.proto"; package NKikimr.NTable.NProto; -option java_package = "ru.yandex.kikimr.proto"; - +option java_package = "ru.yandex.kikimr.proto"; + message TEvol { required uint32 Tail = 1; required uint32 Head = 2; } message TPartColumn { - optional uint32 Tag = 1; - optional uint32 Type = 2; + optional uint32 Tag = 1; + optional uint32 Type = 2; optional uint32 Key = 3; optional uint32 Group = 4; -} - +} + message TPartScheme { repeated TPartColumn Columns = 1; - repeated uint32 KeyTags = 2; + repeated uint32 KeyTags = 2; optional uint32 Legacy0_ = 3; -} - +} + message TLayout { optional uint32 Index = 1; optional uint32 Globs = 2; // EPage::Globs, external blobs catalog @@ -52,7 +52,7 @@ message TRoot { // NTable::TPart page collection metablob optional TLayout Layout = 8;// Non-data pages layout information optional NKikimrProto.TRowVersion MinRowVersion = 9; optional NKikimrProto.TRowVersion MaxRowVersion = 10; -} +} message TSliceBounds { optional bytes FirstKey = 1; diff --git a/ydb/core/tablet_flat/protos/ya.make b/ydb/core/tablet_flat/protos/ya.make index fe35ffd0a8..91e7e3a2d8 100644 --- a/ydb/core/tablet_flat/protos/ya.make +++ b/ydb/core/tablet_flat/protos/ya.make @@ -7,7 +7,7 @@ OWNER( ) SRCS( - flat_table_part.proto + flat_table_part.proto flat_table_shard.proto ) diff --git a/ydb/core/tablet_flat/tablet_flat_executed.cpp b/ydb/core/tablet_flat/tablet_flat_executed.cpp index 4b3c15490c..1781cd149b 100644 --- a/ydb/core/tablet_flat/tablet_flat_executed.cpp +++ b/ydb/core/tablet_flat/tablet_flat_executed.cpp @@ -161,7 +161,7 @@ void TTabletExecutedFlat::Detach(const TActorContext &ctx) { bool TTabletExecutedFlat::OnRenderAppHtmlPage(NMon::TEvRemoteHttpInfo::TPtr ev, const TActorContext &ctx) { if (ev) { TStringStream str; - HTML(str) {str << "nothing to see here...";} + HTML(str) {str << "nothing to see here...";} ctx.Send(ev->Sender, new NMon::TEvRemoteHttpInfoRes(str.Str())); } return false; @@ -188,48 +188,48 @@ void TTabletExecutedFlat::RenderHtmlPage(NMon::TEvRemoteHttpInfo::TPtr &ev, cons } else { const TDuration uptime = TAppData::TimeProvider->Now() - StartTime0; TStringStream str; - HTML(str) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {str << "NodeID: " << ctx.SelfID.NodeId(); } - } - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {str << "Uptime: " << uptime.ToString(); } - } - DIV_CLASS("row") { + HTML(str) { + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {str << "NodeID: " << ctx.SelfID.NodeId(); } + } + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {str << "Uptime: " << uptime.ToString(); } + } + DIV_CLASS("row") { DIV_CLASS("col-md-12") {str << "Tablet type: " << TTabletTypes::TypeToStr((TTabletTypes::EType)TabletType()); } - } - DIV_CLASS("row") { + } + DIV_CLASS("row") { DIV_CLASS("col-md-12") {str << "Tablet id: " << TabletID() << (Executor()->GetStats().IsFollower ? " Follower" : " Leader"); } - } - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {str << "Tablet generation: " << Executor()->Generation();} - } + } + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {str << "Tablet generation: " << Executor()->Generation();} + } DIV_CLASS("row") { DIV_CLASS("col-md-12") { str << "Tenant id: " << Info()->TenantPathId; } } if (OnRenderAppHtmlPage(nullptr, ctx)) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {str << "<a href=\"tablets/app?" << queryString << "\">App</a>";} - } + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {str << "<a href=\"tablets/app?" << queryString << "\">App</a>";} + } } - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {str << "<a href=\"tablets/counters?" << queryString << "\">Counters</a>"; } - } - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {str << "<a href=\"tablets/executorInternals?" << queryString << "\">Executor DB internals</a>";} - } - DIV_CLASS("row") { + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {str << "<a href=\"tablets/counters?" << queryString << "\">Counters</a>"; } + } + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {str << "<a href=\"tablets/executorInternals?" << queryString << "\">Executor DB internals</a>";} + } + DIV_CLASS("row") { DIV_CLASS("col-md-12") {str << "<a href=\"tablets?FollowerID=" << TabletID() << "\">Connect to follower</a>";} - } - DIV_CLASS("row") { + } + DIV_CLASS("row") { DIV_CLASS("col-md-12") {str << "<a href=\"tablets?SsId=" << TabletID() << "\">State Storage</a>";} - } - DIV_CLASS("row") { - DIV_CLASS("col-md-12") {str << "<a href=\"tablets?KillTabletID=" << TabletID() << "\">Kill</a>";} - } - } + } + DIV_CLASS("row") { + DIV_CLASS("col-md-12") {str << "<a href=\"tablets?KillTabletID=" << TabletID() << "\">Kill</a>";} + } + } ctx.Send(ev->Sender, new NMon::TEvRemoteHttpInfoRes(str.Str())); return; diff --git a/ydb/core/tablet_flat/tablet_flat_executor.h b/ydb/core/tablet_flat/tablet_flat_executor.h index 075ebce354..beb7e8b844 100644 --- a/ydb/core/tablet_flat/tablet_flat_executor.h +++ b/ydb/core/tablet_flat/tablet_flat_executor.h @@ -523,7 +523,7 @@ namespace NFlatExecutorSetup { virtual void RenderHtmlPage(NMon::TEvRemoteHttpInfo::TPtr&) const = 0; virtual void RenderHtmlCounters(NMon::TEvRemoteHttpInfo::TPtr&) const = 0; virtual void RenderHtmlDb(NMon::TEvRemoteHttpInfo::TPtr &ev, const TActorContext &ctx) const = 0; - virtual void RegisterExternalTabletCounters(TAutoPtr<TTabletCountersBase> appCounters) = 0; + virtual void RegisterExternalTabletCounters(TAutoPtr<TTabletCountersBase> appCounters) = 0; virtual void GetTabletCounters(TEvTablet::TEvGetCounters::TPtr&) = 0; virtual void UpdateConfig(TEvTablet::TEvUpdateConfig::TPtr&) = 0; diff --git a/ydb/core/tablet_flat/test/tool/perf/app.h b/ydb/core/tablet_flat/test/tool/perf/app.h index 96f1e81d5a..4e7aa42fe5 100644 --- a/ydb/core/tablet_flat/test/tool/perf/app.h +++ b/ydb/core/tablet_flat/test/tool/perf/app.h @@ -1,11 +1,11 @@ #pragma once -#include "colons.h" +#include "colons.h" #include "do_zero.h" #include "do_mem.h" #include "do_part.h" #include "do_iter.h" -#include "logger.h" +#include "logger.h" #include "sponge.h" #include "runner.h" diff --git a/ydb/core/tablet_flat/test/tool/perf/colons.cpp b/ydb/core/tablet_flat/test/tool/perf/colons.cpp index ba9f318ba0..07b77e46bd 100644 --- a/ydb/core/tablet_flat/test/tool/perf/colons.cpp +++ b/ydb/core/tablet_flat/test/tool/perf/colons.cpp @@ -1,90 +1,90 @@ -#include "colons.h" - -#include <util/generic/algorithm.h> - -using namespace NKikiSched; - -TColons::TColons(const TString &line) - : At(0) - , Line(line) -{ - -} - - -TColons::~TColons() -{ - -} - - -TString TColons::Next() noexcept -{ - TString token; - - if (!*this) { - At = TString::npos; - - } else { - const size_t end = Line.find(':', At); - - token = Line.substr(At, end == TString::npos ? end : end - At); - - if ((At = end) != TString::npos) At++; - } - - return token; -} - - -TString TColons::Token(const TString &def) noexcept -{ - TString token = Next(); - - return token ? token : def; -} - - -size_t TColons::Large(size_t def) -{ - const TString item = Next(); - - return !item ? def : LargeParse(item); -} - - -size_t TColons::LargeParse(const TString &item) -{ - TString::const_iterator it = FindIf(item.begin(), item.end(), IsNumber); - - if (it == item.begin()) { - throw yexception() << "Invalid value literal " << item; - } - - size_t off = (it == item.end()) ? TString::npos : it - item.begin(); - - const TString pref = item.substr(0, off); - const TString suff = item.substr(off); - - size_t value = FromString<size_t>(pref); - - if (suff.empty()) { - - } else if (suff == "k" || suff == "K") { - value <<= 10; - - } else if (suff == "m" || suff == "M") { - value <<= 20; - - } else if (suff == "g" || suff == "G") { - value <<= 30; - - } else if (suff == "t" || suff == "T") { - value <<= 40; - - } else { - throw yexception() << "Unknown value suffix " << suff; - } - - return value; -} +#include "colons.h" + +#include <util/generic/algorithm.h> + +using namespace NKikiSched; + +TColons::TColons(const TString &line) + : At(0) + , Line(line) +{ + +} + + +TColons::~TColons() +{ + +} + + +TString TColons::Next() noexcept +{ + TString token; + + if (!*this) { + At = TString::npos; + + } else { + const size_t end = Line.find(':', At); + + token = Line.substr(At, end == TString::npos ? end : end - At); + + if ((At = end) != TString::npos) At++; + } + + return token; +} + + +TString TColons::Token(const TString &def) noexcept +{ + TString token = Next(); + + return token ? token : def; +} + + +size_t TColons::Large(size_t def) +{ + const TString item = Next(); + + return !item ? def : LargeParse(item); +} + + +size_t TColons::LargeParse(const TString &item) +{ + TString::const_iterator it = FindIf(item.begin(), item.end(), IsNumber); + + if (it == item.begin()) { + throw yexception() << "Invalid value literal " << item; + } + + size_t off = (it == item.end()) ? TString::npos : it - item.begin(); + + const TString pref = item.substr(0, off); + const TString suff = item.substr(off); + + size_t value = FromString<size_t>(pref); + + if (suff.empty()) { + + } else if (suff == "k" || suff == "K") { + value <<= 10; + + } else if (suff == "m" || suff == "M") { + value <<= 20; + + } else if (suff == "g" || suff == "G") { + value <<= 30; + + } else if (suff == "t" || suff == "T") { + value <<= 40; + + } else { + throw yexception() << "Unknown value suffix " << suff; + } + + return value; +} diff --git a/ydb/core/tablet_flat/test/tool/perf/colons.h b/ydb/core/tablet_flat/test/tool/perf/colons.h index 287187f682..3c07eba80d 100644 --- a/ydb/core/tablet_flat/test/tool/perf/colons.h +++ b/ydb/core/tablet_flat/test/tool/perf/colons.h @@ -1,79 +1,79 @@ -#pragma once - -#include <library/cpp/charset/ci_string.h> -#include <util/generic/string.h> -#include <util/string/cast.h> -#include <util/datetime/base.h> - -namespace NKikiSched { - class TColons { - public: - TColons(const TString &line); - ~TColons(); - - operator bool() const noexcept - { - return At != TString::npos && At < Line.size(); - } - - TString Next() noexcept; - TString Token(const TString &def) noexcept; - - template<typename TVal> - TVal Pop(const TVal &def) - { - const TString item = Next(); - - return !item ? def : FromString<TVal>(item); - } - - template<typename TVal> - void Put(TVal &value) - { - value = Pop<TVal>(value); - } - - template<typename TVal> - TVal Value(const TVal &def, bool hex = false) - { - const TString item = Next(); - - if (!item) { - return def; - - } else if (hex) { - return IntFromString<ui64,16>(item); - - } else { - return FromString<TVal>(item); - } - } - - size_t Large(size_t def); - - template<typename TInteger> - static TInteger LargeInt(const TCiString &literal) - { - size_t value = LargeParse(literal); - - if (value > size_t(Max<TInteger>())) { - - throw yexception() << "Value is out of integer range"; - } - - return value; - } - - static size_t LargeParse(const TString&); - - protected: - static bool IsNumber(char val) noexcept - { - return std::isdigit(val) == 0; - } - - private: - size_t At; - const TString Line; - }; -} +#pragma once + +#include <library/cpp/charset/ci_string.h> +#include <util/generic/string.h> +#include <util/string/cast.h> +#include <util/datetime/base.h> + +namespace NKikiSched { + class TColons { + public: + TColons(const TString &line); + ~TColons(); + + operator bool() const noexcept + { + return At != TString::npos && At < Line.size(); + } + + TString Next() noexcept; + TString Token(const TString &def) noexcept; + + template<typename TVal> + TVal Pop(const TVal &def) + { + const TString item = Next(); + + return !item ? def : FromString<TVal>(item); + } + + template<typename TVal> + void Put(TVal &value) + { + value = Pop<TVal>(value); + } + + template<typename TVal> + TVal Value(const TVal &def, bool hex = false) + { + const TString item = Next(); + + if (!item) { + return def; + + } else if (hex) { + return IntFromString<ui64,16>(item); + + } else { + return FromString<TVal>(item); + } + } + + size_t Large(size_t def); + + template<typename TInteger> + static TInteger LargeInt(const TCiString &literal) + { + size_t value = LargeParse(literal); + + if (value > size_t(Max<TInteger>())) { + + throw yexception() << "Value is out of integer range"; + } + + return value; + } + + static size_t LargeParse(const TString&); + + protected: + static bool IsNumber(char val) noexcept + { + return std::isdigit(val) == 0; + } + + private: + size_t At; + const TString Line; + }; +} diff --git a/ydb/core/tablet_flat/test/tool/perf/desc.h b/ydb/core/tablet_flat/test/tool/perf/desc.h index 2f90fe0113..fce72869dd 100644 --- a/ydb/core/tablet_flat/test/tool/perf/desc.h +++ b/ydb/core/tablet_flat/test/tool/perf/desc.h @@ -1,80 +1,80 @@ -#pragma once - -#include "help.h" - -#include <util/stream/str.h> - -#include <tuple> -#include <utility> - -namespace NKikiSched { - - namespace NFmt { - using TOut = IOutputStream&; - - template<typename Type> - struct TPut { - - template<typename ...TArg> - static void Do(TOut &out, const Type *ob, TArg&& ... args) noexcept - { - ob->Describe(out, std::forward<TArg>(args)...); - } - }; - - template<typename Type, typename ...TArg> - struct TDesc { - TDesc(const Type *ob, TArg&& ...args) - : Ob(ob), Args(std::forward<TArg>(args)...) { } - - inline TOut& Do(TOut &out) const noexcept - { - using Tups = std::tuple_size<std::tuple<TArg...>>; - - return Do(out, typename NHelp::TGenIx<Tups::value>::Type()); - } - - private: - template<size_t ... Index> - inline TOut& Do(TOut &out, NHelp::TIndexes<Index...>) const noexcept - { - if (Ob == nullptr) return out << "{nil}"; - - NFmt::TPut<Type>::Do(out, Ob, std::get<Index>(Args)...); - - return out; - } - - const Type *Ob = nullptr; - std::tuple<TArg...> Args; - }; - - template<typename Type, typename ...TArg> - inline TDesc<Type, TArg...> If(const Type *ob, TArg&& ...args) noexcept - { - return { ob, std::forward<TArg>(args)... }; - } - - template<typename Type, typename ...TArg> - inline TDesc<Type, TArg...> Do(const Type &ob, TArg&& ...args) noexcept - { - return { &ob, std::forward<TArg>(args)... }; - } - - template<typename Type, typename ...TArg> - inline TString Ln(const Type &ob, TArg&& ...args) noexcept - { - TStringStream ss; - - TDesc<Type, TArg...>(&ob, std::forward<TArg>(args)...).Do(ss); - - return ss.Str(); - } - - template<typename Type, typename ...TArg> - inline TOut& operator<<(TOut &out, const TDesc<Type, TArg...> &wrap) - { - return wrap.Do(out); - } - } -} +#pragma once + +#include "help.h" + +#include <util/stream/str.h> + +#include <tuple> +#include <utility> + +namespace NKikiSched { + + namespace NFmt { + using TOut = IOutputStream&; + + template<typename Type> + struct TPut { + + template<typename ...TArg> + static void Do(TOut &out, const Type *ob, TArg&& ... args) noexcept + { + ob->Describe(out, std::forward<TArg>(args)...); + } + }; + + template<typename Type, typename ...TArg> + struct TDesc { + TDesc(const Type *ob, TArg&& ...args) + : Ob(ob), Args(std::forward<TArg>(args)...) { } + + inline TOut& Do(TOut &out) const noexcept + { + using Tups = std::tuple_size<std::tuple<TArg...>>; + + return Do(out, typename NHelp::TGenIx<Tups::value>::Type()); + } + + private: + template<size_t ... Index> + inline TOut& Do(TOut &out, NHelp::TIndexes<Index...>) const noexcept + { + if (Ob == nullptr) return out << "{nil}"; + + NFmt::TPut<Type>::Do(out, Ob, std::get<Index>(Args)...); + + return out; + } + + const Type *Ob = nullptr; + std::tuple<TArg...> Args; + }; + + template<typename Type, typename ...TArg> + inline TDesc<Type, TArg...> If(const Type *ob, TArg&& ...args) noexcept + { + return { ob, std::forward<TArg>(args)... }; + } + + template<typename Type, typename ...TArg> + inline TDesc<Type, TArg...> Do(const Type &ob, TArg&& ...args) noexcept + { + return { &ob, std::forward<TArg>(args)... }; + } + + template<typename Type, typename ...TArg> + inline TString Ln(const Type &ob, TArg&& ...args) noexcept + { + TStringStream ss; + + TDesc<Type, TArg...>(&ob, std::forward<TArg>(args)...).Do(ss); + + return ss.Str(); + } + + template<typename Type, typename ...TArg> + inline TOut& operator<<(TOut &out, const TDesc<Type, TArg...> &wrap) + { + return wrap.Do(out); + } + } +} diff --git a/ydb/core/tablet_flat/test/tool/perf/format.h b/ydb/core/tablet_flat/test/tool/perf/format.h index 0a65fa404f..09d3cd6e76 100644 --- a/ydb/core/tablet_flat/test/tool/perf/format.h +++ b/ydb/core/tablet_flat/test/tool/perf/format.h @@ -1,261 +1,261 @@ -#pragma once - -#include "desc.h" - -#include <util/string/printf.h> -#include <util/system/types.h> -#include <util/datetime/base.h> - -namespace NKikiSched { - namespace NFmt { - using TOut = IOutputStream&; - - struct TSerial { - using TVal = ui64; - - TSerial(TVal val, size_t dig = 8) - : Val(val), Dig(Min(dig, TSerial::Lim())) { } - - static constexpr size_t Lim() noexcept - { - return sizeof(TVal) * 2; - } - - TOut& Do(TOut &out) const noexcept - { - const char _pad_zero[] = "00000000000000000000"; - const char _pad_ffff[] = "ff..ffffffffffffffff"; - - static_assert(TSerial::Lim() + 4 <= sizeof(_pad_ffff), ""); - - if (Val != Max<TVal>()) { - char ln_[24]; - - auto got = snprintf(ln_, sizeof(ln_), "%" PRIx64, Val); - - if (got < ssize_t(Dig)) out.Write(_pad_zero, Dig - got); - - out.Write(ln_, got); - - } else if (Dig >= TSerial::Lim()) { - - out.Write(_pad_ffff + 4, TSerial::Lim()); - - } else { - - out.Write(_pad_ffff, Max(size_t(6), Dig)); - } - - return out; - } - - TVal Val = 0; - size_t Dig = 0; - }; - - struct TLarge { - TLarge(ui64 val, bool pad = false): Val(val), Pad(pad) { } - - TOut& Do(TOut &out) const noexcept - { - const ui64 grid[] = { - 0x00000000000003e8, /* K 10 ** 3 */ - 0x00000000000f4240, /* M 10 ** 6 */ - 0x000000003b9aca00, /* G 10 ** 9 */ - 0x000000e8d4a51000, /* T 10 ** 12 */ - 0x00038d7ea4c68000, /* P 10 ** 15 */ - 0x0de0b6b3a7640000, /* E 10 ** 18 */ - }; - - if (Val < 10000) return Small(out); - if (Val < grid[1]) return Fixed(out, 'K', grid[0]); - if (Val < grid[2]) return Fixed(out, 'M', grid[1]); - if (Val < grid[3]) return Fixed(out, 'G', grid[2]); - if (Val < grid[4]) return Fixed(out, 'T', grid[3]); - if (Val < grid[5]) return Fixed(out, 'P', grid[4]); - - return Fixed(out, 'E', grid[5]); - } - - protected: - inline TOut& Small(TOut &out) const noexcept - { - char ln_[8]; - - auto got = snprintf(ln_, sizeof(ln_), " %zu", Val); - - if (got > 7 || got == 0) { - out << "?bug"; - - } else if (Pad) { - out.Write(ln_ + (got - 4), 4); - - } else { - out.Write(ln_ + 3, got - 3); - } - - return out; - } - - TOut& Fixed(TOut &out, char suff, ui64 base) const noexcept - { - char ln_[8]; - - snprintf(ln_, sizeof(ln_), "%.2f", double(Val) / base); - - return ln_[3] = suff, out.Write(ln_, 4), out; - } - - ui64 Val = 0; - bool Pad = false; - }; - - - struct TAverage { - TAverage(ui64 over, ui64 val, bool pad = true) - : Pad(pad), Ovr(over), Val(val) { } - - TOut& Do(TOut &out) const noexcept - { - if (Val > 0 && Val < Ovr * 100) { - char ln[8]; - - snprintf(ln, sizeof(ln), "%.3f", double(Val) / Ovr); - - return ln[4] = '\0', out << ln; - - } else if (Ovr > 0) { - return NFmt::TLarge(Val ? Val / Ovr : 0, Pad).Do(out); - - } else { - return out << "+inf"; - } - } - - bool Pad = true; - ui64 Ovr = 0; - ui64 Val = 0; - }; - - - struct TStamp { - TStamp(TInstant on): On(on) { } - - TOut& Do(TOut &out) const noexcept - { - char ln_[24]; - - if (On == TInstant::Max()) out << "~inf"; - - ui64 sec = On.Seconds(), ms = On.MilliSeconds() - sec * 1000; - - size_t sym = snprintf(ln_, sizeof(ln_), "%zu.%03zus", sec, ms); - - return out.Write(ln_, Min(sym, sizeof(ln_))), out; - } - - protected: - TInstant On; - }; - - - struct TDelay { - TDelay(TDuration val): Val(val) { } - - TOut& Do(TOut &out) const noexcept - { - const ui64 grid[] = { - 60ull, /* minute */ - 3600ull, /* hour */ - 86400ull, /* day */ - 604800ull, /* week */ - 8553600ull, /* 99 days */ - 31557600ull, /* Julian 365.25 days year */ - 3155760000ull, /* Julian 100 years century */ - }; - - if (Val == TDuration::Max()) return out << "undef~"; - - const auto secs = Val.Seconds(); - - if (secs < grid[0]) return Small(out, secs); - if (secs < grid[1]) return Large(out, secs, 'm', grid[0]); - if (secs < grid[2]) return Large(out, secs, 'h', grid[1]); - if (secs < grid[4]) return Large(out, secs, 'd', grid[2]); - if (secs < grid[5]) return Large(out, secs, 'w', grid[3]); - if (secs < grid[6]) return Large(out, secs, 'y', grid[5]); - - return Large(out, secs, 'c', grid[6]); - } - - protected: - inline TOut& Small(TOut &out, ui64 secs) const noexcept - { - char ln_[8]; - - auto ms = Val.MilliSeconds() - secs * 1000; - - snprintf(ln_, sizeof(ln_), "%zu.%.03zu", secs, ms); - - return ln_[5] = 's', out.Write(ln_, 6), out; - } - - TOut& Large(TOut &out, double sec, char suff, ui64 base) const - { - char ln_[16]; - - snprintf(ln_, sizeof(ln_), "%.03f", sec / base); - - return ln_[5] = suff, out.Write(ln_, 6), out; - } - - TDuration Val; - }; - - - struct TDelta { - TDelta(TInstant on, TInstant to): On(on), To(to) { } - - TOut& Do(TOut &out) const noexcept - { - const auto pfx = (On <= To ? '+' : '-'); - - return out << pfx, TDelay(Max(On, To) - Min(On, To)).Do(out); - } - - protected: - TInstant On; - TInstant To; - }; - - inline TOut& operator<<(TOut &out, const NFmt::TSerial &print) - { - return print.Do(out); - } - - inline TOut& operator<<(TOut &out, const NFmt::TLarge &print) - { - return print.Do(out); - } - - inline TOut& operator<<(TOut &out, const NFmt::TAverage &print) - { - return print.Do(out); - } - - inline TOut& operator<<(TOut &out, const NFmt::TStamp &print) - { - return print.Do(out); - } - - inline TOut& operator<<(TOut &out, const NFmt::TDelay &print) - { - return print.Do(out); - } - - inline TOut& operator<<(TOut &out, const NFmt::TDelta &print) - { - return print.Do(out); - } - } -} +#pragma once + +#include "desc.h" + +#include <util/string/printf.h> +#include <util/system/types.h> +#include <util/datetime/base.h> + +namespace NKikiSched { + namespace NFmt { + using TOut = IOutputStream&; + + struct TSerial { + using TVal = ui64; + + TSerial(TVal val, size_t dig = 8) + : Val(val), Dig(Min(dig, TSerial::Lim())) { } + + static constexpr size_t Lim() noexcept + { + return sizeof(TVal) * 2; + } + + TOut& Do(TOut &out) const noexcept + { + const char _pad_zero[] = "00000000000000000000"; + const char _pad_ffff[] = "ff..ffffffffffffffff"; + + static_assert(TSerial::Lim() + 4 <= sizeof(_pad_ffff), ""); + + if (Val != Max<TVal>()) { + char ln_[24]; + + auto got = snprintf(ln_, sizeof(ln_), "%" PRIx64, Val); + + if (got < ssize_t(Dig)) out.Write(_pad_zero, Dig - got); + + out.Write(ln_, got); + + } else if (Dig >= TSerial::Lim()) { + + out.Write(_pad_ffff + 4, TSerial::Lim()); + + } else { + + out.Write(_pad_ffff, Max(size_t(6), Dig)); + } + + return out; + } + + TVal Val = 0; + size_t Dig = 0; + }; + + struct TLarge { + TLarge(ui64 val, bool pad = false): Val(val), Pad(pad) { } + + TOut& Do(TOut &out) const noexcept + { + const ui64 grid[] = { + 0x00000000000003e8, /* K 10 ** 3 */ + 0x00000000000f4240, /* M 10 ** 6 */ + 0x000000003b9aca00, /* G 10 ** 9 */ + 0x000000e8d4a51000, /* T 10 ** 12 */ + 0x00038d7ea4c68000, /* P 10 ** 15 */ + 0x0de0b6b3a7640000, /* E 10 ** 18 */ + }; + + if (Val < 10000) return Small(out); + if (Val < grid[1]) return Fixed(out, 'K', grid[0]); + if (Val < grid[2]) return Fixed(out, 'M', grid[1]); + if (Val < grid[3]) return Fixed(out, 'G', grid[2]); + if (Val < grid[4]) return Fixed(out, 'T', grid[3]); + if (Val < grid[5]) return Fixed(out, 'P', grid[4]); + + return Fixed(out, 'E', grid[5]); + } + + protected: + inline TOut& Small(TOut &out) const noexcept + { + char ln_[8]; + + auto got = snprintf(ln_, sizeof(ln_), " %zu", Val); + + if (got > 7 || got == 0) { + out << "?bug"; + + } else if (Pad) { + out.Write(ln_ + (got - 4), 4); + + } else { + out.Write(ln_ + 3, got - 3); + } + + return out; + } + + TOut& Fixed(TOut &out, char suff, ui64 base) const noexcept + { + char ln_[8]; + + snprintf(ln_, sizeof(ln_), "%.2f", double(Val) / base); + + return ln_[3] = suff, out.Write(ln_, 4), out; + } + + ui64 Val = 0; + bool Pad = false; + }; + + + struct TAverage { + TAverage(ui64 over, ui64 val, bool pad = true) + : Pad(pad), Ovr(over), Val(val) { } + + TOut& Do(TOut &out) const noexcept + { + if (Val > 0 && Val < Ovr * 100) { + char ln[8]; + + snprintf(ln, sizeof(ln), "%.3f", double(Val) / Ovr); + + return ln[4] = '\0', out << ln; + + } else if (Ovr > 0) { + return NFmt::TLarge(Val ? Val / Ovr : 0, Pad).Do(out); + + } else { + return out << "+inf"; + } + } + + bool Pad = true; + ui64 Ovr = 0; + ui64 Val = 0; + }; + + + struct TStamp { + TStamp(TInstant on): On(on) { } + + TOut& Do(TOut &out) const noexcept + { + char ln_[24]; + + if (On == TInstant::Max()) out << "~inf"; + + ui64 sec = On.Seconds(), ms = On.MilliSeconds() - sec * 1000; + + size_t sym = snprintf(ln_, sizeof(ln_), "%zu.%03zus", sec, ms); + + return out.Write(ln_, Min(sym, sizeof(ln_))), out; + } + + protected: + TInstant On; + }; + + + struct TDelay { + TDelay(TDuration val): Val(val) { } + + TOut& Do(TOut &out) const noexcept + { + const ui64 grid[] = { + 60ull, /* minute */ + 3600ull, /* hour */ + 86400ull, /* day */ + 604800ull, /* week */ + 8553600ull, /* 99 days */ + 31557600ull, /* Julian 365.25 days year */ + 3155760000ull, /* Julian 100 years century */ + }; + + if (Val == TDuration::Max()) return out << "undef~"; + + const auto secs = Val.Seconds(); + + if (secs < grid[0]) return Small(out, secs); + if (secs < grid[1]) return Large(out, secs, 'm', grid[0]); + if (secs < grid[2]) return Large(out, secs, 'h', grid[1]); + if (secs < grid[4]) return Large(out, secs, 'd', grid[2]); + if (secs < grid[5]) return Large(out, secs, 'w', grid[3]); + if (secs < grid[6]) return Large(out, secs, 'y', grid[5]); + + return Large(out, secs, 'c', grid[6]); + } + + protected: + inline TOut& Small(TOut &out, ui64 secs) const noexcept + { + char ln_[8]; + + auto ms = Val.MilliSeconds() - secs * 1000; + + snprintf(ln_, sizeof(ln_), "%zu.%.03zu", secs, ms); + + return ln_[5] = 's', out.Write(ln_, 6), out; + } + + TOut& Large(TOut &out, double sec, char suff, ui64 base) const + { + char ln_[16]; + + snprintf(ln_, sizeof(ln_), "%.03f", sec / base); + + return ln_[5] = suff, out.Write(ln_, 6), out; + } + + TDuration Val; + }; + + + struct TDelta { + TDelta(TInstant on, TInstant to): On(on), To(to) { } + + TOut& Do(TOut &out) const noexcept + { + const auto pfx = (On <= To ? '+' : '-'); + + return out << pfx, TDelay(Max(On, To) - Min(On, To)).Do(out); + } + + protected: + TInstant On; + TInstant To; + }; + + inline TOut& operator<<(TOut &out, const NFmt::TSerial &print) + { + return print.Do(out); + } + + inline TOut& operator<<(TOut &out, const NFmt::TLarge &print) + { + return print.Do(out); + } + + inline TOut& operator<<(TOut &out, const NFmt::TAverage &print) + { + return print.Do(out); + } + + inline TOut& operator<<(TOut &out, const NFmt::TStamp &print) + { + return print.Do(out); + } + + inline TOut& operator<<(TOut &out, const NFmt::TDelay &print) + { + return print.Do(out); + } + + inline TOut& operator<<(TOut &out, const NFmt::TDelta &print) + { + return print.Do(out); + } + } +} diff --git a/ydb/core/tablet_flat/test/tool/perf/help.h b/ydb/core/tablet_flat/test/tool/perf/help.h index bcdb173a4a..e9ba94fb45 100644 --- a/ydb/core/tablet_flat/test/tool/perf/help.h +++ b/ydb/core/tablet_flat/test/tool/perf/help.h @@ -1,30 +1,30 @@ -#pragma once - -#include <tuple> -#include <cstddef> - -namespace NKikiSched { - - namespace NHelp { - - template<size_t ...> struct TIndexes { }; - +#pragma once + +#include <tuple> +#include <cstddef> + +namespace NKikiSched { + + namespace NHelp { + + template<size_t ...> struct TIndexes { }; + template<size_t N, size_t ...Obtained> struct TGenIx : TGenIx<N - 1, N - 1, Obtained...> { }; - + template<size_t ...Obtained> struct TGenIx<0, Obtained...> - { + { using Type = TIndexes<Obtained...>; - }; - - template<typename TAr1, typename TAr2> - static inline void IsArrSized(const TAr1&, const TAr2&) noexcept - { - constexpr auto nums = std::tuple_size<TAr1>::value; - - static_assert(nums == std::tuple_size<TAr1>::value, ""); - } - } - -} + }; + + template<typename TAr1, typename TAr2> + static inline void IsArrSized(const TAr1&, const TAr2&) noexcept + { + constexpr auto nums = std::tuple_size<TAr1>::value; + + static_assert(nums == std::tuple_size<TAr1>::value, ""); + } + } + +} diff --git a/ydb/core/tablet_flat/test/tool/perf/iface_logger.h b/ydb/core/tablet_flat/test/tool/perf/iface_logger.h index ea4d90a2b1..a267632616 100644 --- a/ydb/core/tablet_flat/test/tool/perf/iface_logger.h +++ b/ydb/core/tablet_flat/test/tool/perf/iface_logger.h @@ -1,70 +1,70 @@ -#pragma once - -#include <util/stream/str.h> -#include <util/string/printf.h> - -namespace NKikiSched { - - enum class ELnLev { - None = 0, - - CRIT = 1, - ERROR = 2, - WARN = 3, - - INFO = 4, - INF1 = 5, - INF2 = 6, - INF3 = 7, - - DEBUG = 8, - DBG01 = 9, - }; - - class ILogged { - public: - virtual void LogLn(ELnLev, const TString&) const noexcept = 0; - }; - - class TLogLn : public TStringStream { - public: - TLogLn(const ILogged *logged, ELnLev level) - : Logged(logged) - , Level(level) - { - - } - - ~TLogLn() - { - if (!Logged) { - /* Just a dummy line */ - - } else if (this->empty()) { - /* Nothing was logged */ - - } else { - Logged->LogLn(Level, Str()); - } - } - - explicit operator bool() const noexcept - { - return Logged != nullptr; - } - - private: - const ILogged * Logged = nullptr; - const ELnLev Level = ELnLev::None; - }; - - class ILogger { - public: - virtual ~ILogger() - { - - } - - virtual TLogLn Log(ELnLev) const noexcept = 0; - }; -} +#pragma once + +#include <util/stream/str.h> +#include <util/string/printf.h> + +namespace NKikiSched { + + enum class ELnLev { + None = 0, + + CRIT = 1, + ERROR = 2, + WARN = 3, + + INFO = 4, + INF1 = 5, + INF2 = 6, + INF3 = 7, + + DEBUG = 8, + DBG01 = 9, + }; + + class ILogged { + public: + virtual void LogLn(ELnLev, const TString&) const noexcept = 0; + }; + + class TLogLn : public TStringStream { + public: + TLogLn(const ILogged *logged, ELnLev level) + : Logged(logged) + , Level(level) + { + + } + + ~TLogLn() + { + if (!Logged) { + /* Just a dummy line */ + + } else if (this->empty()) { + /* Nothing was logged */ + + } else { + Logged->LogLn(Level, Str()); + } + } + + explicit operator bool() const noexcept + { + return Logged != nullptr; + } + + private: + const ILogged * Logged = nullptr; + const ELnLev Level = ELnLev::None; + }; + + class ILogger { + public: + virtual ~ILogger() + { + + } + + virtual TLogLn Log(ELnLev) const noexcept = 0; + }; +} diff --git a/ydb/core/tablet_flat/test/tool/perf/logger.h b/ydb/core/tablet_flat/test/tool/perf/logger.h index 979b5fead4..1cef7b360a 100644 --- a/ydb/core/tablet_flat/test/tool/perf/logger.h +++ b/ydb/core/tablet_flat/test/tool/perf/logger.h @@ -1,7 +1,7 @@ #pragma once -#include "iface_logger.h" -#include "format.h" +#include "iface_logger.h" +#include "format.h" #include <util/datetime/base.h> diff --git a/ydb/core/tablet_flat/test/tool/perf/meter.h b/ydb/core/tablet_flat/test/tool/perf/meter.h index cb6a76fd5a..7017ba5f6b 100644 --- a/ydb/core/tablet_flat/test/tool/perf/meter.h +++ b/ydb/core/tablet_flat/test/tool/perf/meter.h @@ -1,6 +1,6 @@ #pragma once -#include "format.h" +#include "format.h" namespace NKikimr { namespace NTable { diff --git a/ydb/core/tablet_flat/test/tool/perf/ya.make b/ydb/core/tablet_flat/test/tool/perf/ya.make index dc0e8ca728..f881bba2ed 100644 --- a/ydb/core/tablet_flat/test/tool/perf/ya.make +++ b/ydb/core/tablet_flat/test/tool/perf/ya.make @@ -3,13 +3,13 @@ PROGRAM(table-perf) OWNER(g:kikimr) SRCS( - colons.cpp + colons.cpp main.cpp ) PEERDIR( ydb/core/tablet_flat/test/libs/table - library/cpp/charset + library/cpp/charset library/cpp/getopt ydb/core/tablet_flat ) diff --git a/ydb/core/tablet_flat/ut/flat_test_db_helpers.h b/ydb/core/tablet_flat/ut/flat_test_db_helpers.h index ffc9a36daa..44d055d819 100644 --- a/ydb/core/tablet_flat/ut/flat_test_db_helpers.h +++ b/ydb/core/tablet_flat/ut/flat_test_db_helpers.h @@ -40,9 +40,9 @@ public: } void SetOp(ECellOp op) { - Op = op; - } - + Op = op; + } + TCell operator*() const { return TCell((const char*)Val.Data(), Val.Size()); @@ -51,10 +51,10 @@ public: const TRawTypeValue& Get() const { return Val; } - + ECellOp GetOp() const { - return Op; - } + return Op; + } }; // TODO: properly support all types @@ -77,11 +77,11 @@ inline TFakeTableCell FromVal(NScheme::TTypeId t, i64 val) { } inline TFakeTableCell MakeNull(ECellOp op) { - TFakeTableCell c; - c.SetOp(op); - return c; -} - + TFakeTableCell c; + c.SetOp(op); + return c; +} + inline TFakeTableCell FromVal(NScheme::TTypeId, std::nullptr_t) { return MakeNull(ECellOp::Set); } @@ -152,16 +152,16 @@ public: } TDbRowUpdate& Erase(TString tagName) { - const TScheme::TTableInfo* tableInfo = Scheme.GetTableInfo(GetRoot()); + const TScheme::TTableInfo* tableInfo = Scheme.GetTableInfo(GetRoot()); Y_VERIFY(tableInfo, "Unknown table id %u", GetRoot()); - const ui32* tagId = tableInfo->ColumnNames.FindPtr(tagName); + const ui32* tagId = tableInfo->ColumnNames.FindPtr(tagName); Y_VERIFY(tagId, "Unknown column \"%s\" in table %u", tagName.data(), GetRoot()); const auto * colInfo = Scheme.GetColumnInfo(GetRoot(), *tagId); Y_VERIFY(colInfo, "Column info not found for table id %u, column id %u", GetRoot(), *tagId); TagOps[*tagId] = MakeNull(ECellOp::Null); - return *this; - } - + return *this; + } + const TMap<ui32, TFakeTableCell>& GetTagOps() const { return TagOps; } @@ -185,12 +185,12 @@ void AppendKeyColumn(ui32 root, const TScheme& scheme, TVector<TFakeTableCell>& AppendKeyColumn(root, scheme, tuple, tt...); } -template <typename... Tt> +template <typename... Tt> void AppendKeyColumn(ui32 root, const TScheme& scheme, TVector<TFakeTableCell>& tuple, nullptr_t, Tt... tt) { tuple.push_back(MakeNull(ECellOp::Set)); - AppendKeyColumn(root, scheme, tuple, tt...); -} - + AppendKeyColumn(root, scheme, tuple, tt...); +} + // Helps to simplify test code that deals with ITestDb class TDbWrapper { ITestDb& Db; diff --git a/ydb/core/tablet_flat/ut/ya.make b/ydb/core/tablet_flat/ut/ya.make index fd66d04202..e16c0d8f92 100644 --- a/ydb/core/tablet_flat/ut/ya.make +++ b/ydb/core/tablet_flat/ut/ya.make @@ -25,7 +25,7 @@ SRCS( flat_range_cache_ut.cpp flat_row_versions_ut.cpp flat_sausagecache_ut.cpp - flat_table_part_ut.cpp + flat_table_part_ut.cpp flat_test_db.h flat_test_db.cpp flat_test_db_helpers.h diff --git a/ydb/core/testlib/actor_helpers.cpp b/ydb/core/testlib/actor_helpers.cpp index 7c039615ab..ccf0bb5f1c 100644 --- a/ydb/core/testlib/actor_helpers.cpp +++ b/ydb/core/testlib/actor_helpers.cpp @@ -7,7 +7,7 @@ TActorSystemStub::TActorSystemStub() { System.Reset(new NActors::TActorSystem(setup)); Mailbox.Reset(new NActors::TMailboxHeader(NActors::TMailboxType::Simple)); ExecutorThread.Reset(new NActors::TExecutorThread(0, System.Get(), nullptr, nullptr, "thread")); - Ctx.Reset(new NActors::TActorContext(*Mailbox, *ExecutorThread, GetCycleCountFast(), SelfID)); + Ctx.Reset(new NActors::TActorContext(*Mailbox, *ExecutorThread, GetCycleCountFast(), SelfID)); PrevCtx = NActors::TlsActivationContext; NActors::TlsActivationContext = Ctx.Get(); } diff --git a/ydb/core/testlib/actors/test_runtime.cpp b/ydb/core/testlib/actors/test_runtime.cpp index 63f0436bff..34000a4989 100644 --- a/ydb/core/testlib/actors/test_runtime.cpp +++ b/ydb/core/testlib/actors/test_runtime.cpp @@ -111,7 +111,7 @@ namespace NActors { node->SchedulerPool.Reset(CreateExecutorPoolStub(this, nodeIndex, node, 0)); node->MailboxTable.Reset(new TMailboxTable()); node->ActorSystem = MakeActorSystem(nodeIndex, node); - node->ExecutorThread.Reset(new TExecutorThread(0, 0, node->ActorSystem.Get(), node->SchedulerPool.Get(), node->MailboxTable.Get(), "TestExecutor")); + node->ExecutorThread.Reset(new TExecutorThread(0, 0, node->ActorSystem.Get(), node->SchedulerPool.Get(), node->MailboxTable.Get(), "TestExecutor")); } else { node->AppData0.reset(new NKikimr::TAppData(0, 1, 2, 3, { }, app0->TypeRegistry, app0->FunctionRegistry, app0->FormatFactory, nullptr)); node->ActorSystem = MakeActorSystem(nodeIndex, node); diff --git a/ydb/core/testlib/minikql_compile.h b/ydb/core/testlib/minikql_compile.h index 4d76ca8d73..4d527012ec 100644 --- a/ydb/core/testlib/minikql_compile.h +++ b/ydb/core/testlib/minikql_compile.h @@ -1,19 +1,19 @@ -#pragma once - +#pragma once + #include <ydb/core/scheme/scheme_tabledefs.h> #include <ydb/core/client/minikql_compile/db_key_resolver.h> #include <ydb/core/client/minikql_compile/yql_expr_minikql.h> #include <library/cpp/threading/future/future.h> #include <util/thread/pool.h> #include <library/cpp/testing/unittest/registar.h> - + class TMockDbSchemeResolver : public NYql::IDbSchemeResolver { -public: - TMockDbSchemeResolver() - { - MtpQueue.Start(2); - } - +public: + TMockDbSchemeResolver() + { + MtpQueue.Start(2); + } + template <typename Func> NThreading::TFuture<NThreading::TFutureType<::TFunctionResult<Func>>> Async(Func&& func, IThreadPool& queue) { auto promise = NThreading::NewPromise<NThreading::TFutureType<::TFunctionResult<Func>>>(); @@ -25,68 +25,68 @@ public: } virtual NThreading::TFuture<TTableResults> ResolveTables(const TVector<TTable>& tables) override { - TTableResults results; - results.reserve(tables.size()); - for (auto& table : tables) { - TTableResult result(TTableResult::Ok); - auto data = Tables.FindPtr(table.TableName); - if (!data) { - result.Status = TTableResult::Error; - result.Reason = TStringBuilder() << "Table " << table.TableName << " not found"; - } - else { - result.Table = table; - result.TableId.Reset(new NKikimr::TTableId(*data->TableId)); - result.KeyColumnCount = data->KeyColumnCount; - - for (auto& column : table.ColumnNames) { + TTableResults results; + results.reserve(tables.size()); + for (auto& table : tables) { + TTableResult result(TTableResult::Ok); + auto data = Tables.FindPtr(table.TableName); + if (!data) { + result.Status = TTableResult::Error; + result.Reason = TStringBuilder() << "Table " << table.TableName << " not found"; + } + else { + result.Table = table; + result.TableId.Reset(new NKikimr::TTableId(*data->TableId)); + result.KeyColumnCount = data->KeyColumnCount; + + for (auto& column : table.ColumnNames) { auto columnInfo = data->Columns.FindPtr(column); Y_VERIFY(column); - + auto insertResult = result.Columns.insert(std::make_pair(column, *columnInfo)); Y_VERIFY(insertResult.second); - } - } - - results.push_back(result); - } - + } + } + + results.push_back(result); + } + return Async([results]() { - return results; - }, MtpQueue); - } - + return results; + }, MtpQueue); + } + virtual void ResolveTables(const TVector<TTable>& tables, NActors::TActorId responseTo) override { Y_UNUSED(tables); Y_UNUSED(responseTo); - ythrow yexception() << "Not implemented"; - } - - void AddTable(const IDbSchemeResolver::TTableResult& table) { + ythrow yexception() << "Not implemented"; + } + + void AddTable(const IDbSchemeResolver::TTableResult& table) { Y_ENSURE(!!table.TableId, "TableId must be defined"); - if (!Tables.insert({ table.Table.TableName, table }).second) { - ythrow yexception() << "Table " << table.Table.TableName << " is already registered"; - } - } - -private: + if (!Tables.insert({ table.Table.TableName, table }).second) { + ythrow yexception() << "Table " << table.Table.TableName << " is already registered"; + } + } + +private: TThreadPool MtpQueue; THashMap<TString, IDbSchemeResolver::TTableResult> Tables; -}; - +}; + namespace NYql { inline TExprContainer::TPtr ParseText(const TString& programText) { - TAstParseResult astRes = ParseAst(programText); + TAstParseResult astRes = ParseAst(programText); astRes.Issues.PrintTo(Cerr); - UNIT_ASSERT(astRes.IsOk()); - - TExprContainer::TPtr expr(new TExprContainer()); + UNIT_ASSERT(astRes.IsOk()); + + TExprContainer::TPtr expr(new TExprContainer()); bool isOk = CompileExpr(*astRes.Root, expr->Root, expr->Context, nullptr); expr->Context.IssueManager.GetIssues().PrintTo(Cerr); - UNIT_ASSERT(isOk); - return expr; -} - + UNIT_ASSERT(isOk); + return expr; +} + } diff --git a/ydb/core/testlib/ya.make b/ydb/core/testlib/ya.make index 137fa829f3..fb0d89c9ce 100644 --- a/ydb/core/testlib/ya.make +++ b/ydb/core/testlib/ya.make @@ -13,7 +13,7 @@ SRCS( fake_coordinator.cpp fake_coordinator.h fake_scheme_shard.h - minikql_compile.h + minikql_compile.h mock_pq_metacache.h tablet_flat_dummy.cpp tablet_helpers.cpp diff --git a/ydb/core/tx/balance_coverage/balance_coverage_builder.cpp b/ydb/core/tx/balance_coverage/balance_coverage_builder.cpp index abec7fc8af..fb29446aab 100644 --- a/ydb/core/tx/balance_coverage/balance_coverage_builder.cpp +++ b/ydb/core/tx/balance_coverage/balance_coverage_builder.cpp @@ -1,4 +1,4 @@ -#include "balance_coverage_builder.h" +#include "balance_coverage_builder.h" namespace NKikimr { diff --git a/ydb/core/tx/coordinator/coordinator_impl.cpp b/ydb/core/tx/coordinator/coordinator_impl.cpp index b4eeb184e2..b282058574 100644 --- a/ydb/core/tx/coordinator/coordinator_impl.cpp +++ b/ydb/core/tx/coordinator/coordinator_impl.cpp @@ -66,13 +66,13 @@ TTxCoordinator::TTxCoordinator(TTabletStorageInfo *info, const TActorId &tablet) Config.RapidSlotFlushSize = 1000; // todo: something meaningful MonCounters.CurrentTxInFly = 0; - TabletCountersPtr.Reset(new TProtobufTabletCounters< - ESimpleCounters_descriptor, - ECumulativeCounters_descriptor, - EPercentileCounters_descriptor, - ETxTypes_descriptor - >()); - TabletCounters = TabletCountersPtr.Get(); + TabletCountersPtr.Reset(new TProtobufTabletCounters< + ESimpleCounters_descriptor, + ECumulativeCounters_descriptor, + EPercentileCounters_descriptor, + ETxTypes_descriptor + >()); + TabletCounters = TabletCountersPtr.Get(); } void TTxCoordinator::PlanTx(TAutoPtr<TTransactionProposal> &proposal, const TActorContext &ctx) { @@ -307,7 +307,7 @@ void TTxCoordinator::Handle(TEvents::TEvPoisonPill::TPtr&, const TActorContext& void TTxCoordinator::OnActivateExecutor(const TActorContext &ctx) { TryInitMonCounters(ctx); - Executor()->RegisterExternalTabletCounters(TabletCountersPtr); + Executor()->RegisterExternalTabletCounters(TabletCountersPtr); Execute(CreateTxSchema(), ctx); } diff --git a/ydb/core/tx/coordinator/coordinator_impl.h b/ydb/core/tx/coordinator/coordinator_impl.h index 39018aff1e..3a9bdb4133 100644 --- a/ydb/core/tx/coordinator/coordinator_impl.h +++ b/ydb/core/tx/coordinator/coordinator_impl.h @@ -407,8 +407,8 @@ private: TVolatileState VolatileState; TConfig Config; TCoordinatorMonCounters MonCounters; - TTabletCountersBase* TabletCounters; - TAutoPtr<TTabletCountersBase> TabletCountersPtr; + TTabletCountersBase* TabletCounters; + TAutoPtr<TTabletCountersBase> TabletCountersPtr; typedef THashMap<TTabletId, TMediator> TMediatorsIndex; TMediatorsIndex Mediators; diff --git a/ydb/core/tx/datashard/datashard.cpp b/ydb/core/tx/datashard/datashard.cpp index d86568b4a1..34e8243917 100644 --- a/ydb/core/tx/datashard/datashard.cpp +++ b/ydb/core/tx/datashard/datashard.cpp @@ -7,17 +7,17 @@ #include <ydb/core/tablet/tablet_counters_protobuf.h> #include <library/cpp/monlib/service/pages/templates.h> - + #include <contrib/libs/apache/arrow/cpp/src/arrow/api.h> -namespace NKikimr { - +namespace NKikimr { + IActor* CreateDataShard(const TActorId &tablet, TTabletStorageInfo *info) { return new NDataShard::TDataShard(tablet, info); -} - +} + namespace NDataShard { - + using namespace NSchemeShard; using namespace NTabletFlatExecutor; @@ -1330,15 +1330,15 @@ void TDataShard::Handle(TEvents::TEvGone::TPtr &ev) { } void TDataShard::Handle(TEvents::TEvPoisonPill::TPtr &ev, const TActorContext &ctx) { - LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Handle TEvents::TEvPoisonPill"); + LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Handle TEvents::TEvPoisonPill"); Y_UNUSED(ev); BecomeBroken(ctx); -} - +} + void TDataShard::Handle(TEvDataShard::TEvGetShardState::TPtr &ev, const TActorContext &ctx) { - Execute(new TTxGetShardState(this, ev), ctx); -} - + Execute(new TTxGetShardState(this, ev), ctx); +} + void TDataShard::Handle(TEvDataShard::TEvSchemaChangedResult::TPtr& ev, const TActorContext& ctx) { LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "Handle TEvSchemaChangedResult " << ev->Get()->Record.GetTxId() @@ -1513,35 +1513,35 @@ void TDataShard::Handle(TEvDataShard::TEvProposeTransaction::TPtr &ev, const TAc return; } - switch (ev->Get()->GetTxKind()) { - case NKikimrTxDataShard::TX_KIND_DATA: + switch (ev->Get()->GetTxKind()) { + case NKikimrTxDataShard::TX_KIND_DATA: case NKikimrTxDataShard::TX_KIND_SCAN: case NKikimrTxDataShard::TX_KIND_SNAPSHOT: case NKikimrTxDataShard::TX_KIND_DISTRIBUTED_ERASE: case NKikimrTxDataShard::TX_KIND_COMMIT_WRITES: ProposeTransaction(std::move(ev), ctx); - return; - case NKikimrTxDataShard::TX_KIND_SCHEME: + return; + case NKikimrTxDataShard::TX_KIND_SCHEME: ProposeTransaction(std::move(ev), ctx); - return; + return; default: break; - } - + } + THolder<TEvDataShard::TEvProposeTransactionResult> result = THolder(new TEvDataShard::TEvProposeTransactionResult(ev->Get()->GetTxKind(), TabletID(), ev->Get()->GetTxId(), NKikimrTxDataShard::TEvProposeTransactionResult::ERROR)); - result->AddError(NKikimrTxDataShard::TError::BAD_TX_KIND, "Unknown kind of transaction"); - ctx.Send(ev->Get()->GetSource(), result.Release()); + result->AddError(NKikimrTxDataShard::TError::BAD_TX_KIND, "Unknown kind of transaction"); + ctx.Send(ev->Get()->GetSource(), result.Release()); IncCounter(COUNTER_PREPARE_ERROR); IncCounter(COUNTER_PREPARE_COMPLETE); - - // TODO[serxa]: wake up! dont sleep! maybe... - //Executor()->WakeUp(ctx); -} - + + // TODO[serxa]: wake up! dont sleep! maybe... + //Executor()->WakeUp(ctx); +} + void TDataShard::Handle(TEvDataShard::TEvProposeTransactionAttach::TPtr &ev, const TActorContext &ctx) { const auto &record = ev->Get()->Record; const ui64 txId = record.GetTxId(); @@ -1631,21 +1631,21 @@ void TDataShard::Handle(TEvTxProcessing::TEvPlanStep::TPtr &ev, const TActorCont return; } - Execute(new TTxPlanStep(this, ev), ctx); -} - + Execute(new TTxPlanStep(this, ev), ctx); +} + void TDataShard::Handle(TEvTxProcessing::TEvReadSet::TPtr &ev, const TActorContext &ctx) { - ui64 sender = ev->Get()->Record.GetTabletSource(); - ui64 dest = ev->Get()->Record.GetTabletDest(); - ui64 producer = ev->Get()->Record.GetTabletProducer(); + ui64 sender = ev->Get()->Record.GetTabletSource(); + ui64 dest = ev->Get()->Record.GetTabletDest(); + ui64 producer = ev->Get()->Record.GetTabletProducer(); ui64 txId = ev->Get()->Record.GetTxId(); LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Receive RS at %" PRIu64 " source %" PRIu64 " dest %" PRIu64 " producer %" PRIu64 " txId %" PRIu64, TabletID(), sender, dest, producer, txId); IncCounter(COUNTER_READSET_RECEIVED_COUNT); IncCounter(COUNTER_READSET_RECEIVED_SIZE, ev->Get()->Record.GetReadSet().size()); - Execute(new TTxReadSet(this, ev), ctx); -} - + Execute(new TTxReadSet(this, ev), ctx); +} + void TDataShard::Handle(TEvTxProcessing::TEvReadSetAck::TPtr &ev, const TActorContext &ctx) { OutReadSets.SaveAck(ctx, ev->Release()); @@ -1657,14 +1657,14 @@ void TDataShard::Handle(TEvTxProcessing::TEvReadSetAck::TPtr &ev, const TActorCo } CheckStateChange(ctx); -} - +} + void TDataShard::Handle(TEvPrivate::TEvProgressTransaction::TPtr &ev, const TActorContext &ctx) { Y_UNUSED(ev); IncCounter(COUNTER_TX_PROGRESS_EV); ExecuteProgressTx(ctx); -} - +} + void TDataShard::Handle(TEvPrivate::TEvDelayedProposeTransaction::TPtr &ev, const TActorContext &ctx) { Y_UNUSED(ev); IncCounter(COUNTER_PROPOSE_QUEUE_EV); @@ -1697,10 +1697,10 @@ void TDataShard::Handle(TEvPrivate::TEvDelayedProposeTransaction::TPtr &ev, cons } void TDataShard::Handle(TEvPrivate::TEvProgressResendReadSet::TPtr &ev, const TActorContext &ctx) { - ResendReadSetQueue.Reset(ctx); - Execute(new TTxProgressResendRS(this, ev->Get()->Seqno), ctx); -} - + ResendReadSetQueue.Reset(ctx); + Execute(new TTxProgressResendRS(this, ev->Get()->Seqno), ctx); +} + void TDataShard::Handle(TEvPrivate::TEvRegisterScanActor::TPtr &ev, const TActorContext &ctx) { ui64 txId = ev->Get()->TxId; auto op = Pipeline.FindOp(txId); @@ -1752,7 +1752,7 @@ void TDataShard::Handle(TEvTabletPipe::TEvClientConnected::TPtr &ev, const TActo } return; } - + if (ev->Get()->Status != NKikimrProto::OK) { if (ev->Get()->ClientId == StateReportPipe) { StateReportPipe = TActorId(); @@ -1803,18 +1803,18 @@ void TDataShard::Handle(TEvTabletPipe::TEvClientConnected::TPtr &ev, const TActo } } - if (!PipeClientCache->OnConnect(ev)) { + if (!PipeClientCache->OnConnect(ev)) { if (ev->Get()->Dead) { AckRSToDeletedTablet(ev->Get()->TabletId, ctx); } else { LOG_NOTICE(ctx, NKikimrServices::TX_DATASHARD, "Failed to connect to tablet %" PRIu64 " from tablet %" PRIu64, ev->Get()->TabletId, TabletID()); RestartPipeRS(ev->Get()->TabletId, ctx); } - } else { - LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Connected to tablet %" PRIu64 " from tablet %" PRIu64, ev->Get()->TabletId, TabletID()); - } -} - + } else { + LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Connected to tablet %" PRIu64 " from tablet %" PRIu64, ev->Get()->TabletId, TabletID()); + } +} + void TDataShard::Handle(TEvTabletPipe::TEvClientDestroyed::TPtr &ev, const TActorContext &ctx) { if (ev->Get()->ClientId == SchemeShardPipe) { if (!TransQueue.HasNotAckedSchemaTx()) { @@ -1853,20 +1853,20 @@ void TDataShard::Handle(TEvTabletPipe::TEvClientDestroyed::TPtr &ev, const TActo ChangeSenderActivator.DoSend(ev->Get()->TabletId, ctx); } - LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Client pipe to tablet %" PRIu64 " from %" PRIu64 " is reset", ev->Get()->TabletId, TabletID()); - PipeClientCache->OnDisconnect(ev); - RestartPipeRS(ev->Get()->TabletId, ctx); -} - + LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Client pipe to tablet %" PRIu64 " from %" PRIu64 " is reset", ev->Get()->TabletId, TabletID()); + PipeClientCache->OnDisconnect(ev); + RestartPipeRS(ev->Get()->TabletId, ctx); +} + void TDataShard::RestartPipeRS(ui64 tabletId, const TActorContext& ctx) { - for (auto seqno : ResendReadSetPipeTracker.FindTx(tabletId)) { - LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Pipe reset to tablet %" PRIu64 " caused resend of readset %" PRIu64 - " at tablet %" PRIu64, tabletId, seqno, TabletID()); - - ResendReadSetQueue.Progress(seqno, ctx); - } -} - + for (auto seqno : ResendReadSetPipeTracker.FindTx(tabletId)) { + LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Pipe reset to tablet %" PRIu64 " caused resend of readset %" PRIu64 + " at tablet %" PRIu64, tabletId, seqno, TabletID()); + + ResendReadSetQueue.Progress(seqno, ctx); + } +} + void TDataShard::AckRSToDeletedTablet(ui64 tabletId, const TActorContext& ctx) { for (auto seqno : ResendReadSetPipeTracker.FindTx(tabletId)) { LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Pipe reset to dead tablet %" PRIu64 " caused ack of readset %" PRIu64 @@ -1888,23 +1888,23 @@ void TDataShard::Handle(TEvTabletPipe::TEvServerConnected::TPtr &ev, const TActo Y_UNUSED(ev); Y_UNUSED(ctx); LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Server connected at tablet %s %" PRIu64 , Executor()->GetStats().IsFollower ? "follower" : "leader", ev->Get()->TabletId); -} - +} + void TDataShard::Handle(TEvTabletPipe::TEvServerDisconnected::TPtr &ev, const TActorContext &ctx) { Y_UNUSED(ev); Y_UNUSED(ctx); -} - +} + void TDataShard::Handle(TEvMediatorTimecast::TEvRegisterTabletResult::TPtr& ev, const TActorContext& ctx) { LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "Got TEvMediatorTimecast::TEvRegisterTabletResult at " << TabletID() << " time " << ev->Get()->Entry->Get(TabletID())); Y_VERIFY(ev->Get()->TabletId == TabletID()); - MediatorTimeCastEntry = ev->Get()->Entry; + MediatorTimeCastEntry = ev->Get()->Entry; Y_VERIFY(MediatorTimeCastEntry); Pipeline.ActivateWaitingTxOps(ctx); -} - +} + void TDataShard::Handle(TEvMediatorTimecast::TEvNotifyPlanStep::TPtr& ev, const TActorContext& ctx) { const auto* msg = ev->Get(); Y_VERIFY(msg->TabletId == TabletID()); @@ -2012,8 +2012,8 @@ void TDataShard::UpdateLagCounters(const TActorContext &ctx) { void TDataShard::FillSplitTrajectory(ui64 origin, NKikimrTx::TBalanceTrackList& tracks) { Y_UNUSED(origin); Y_UNUSED(tracks); -} - +} + THolder<TEvTxProcessing::TEvReadSet> TDataShard::PrepareReadSet(ui64 step, ui64 txId, ui64 source, ui64 target, const TString& body, ui64 seqno) @@ -2032,13 +2032,13 @@ void TDataShard::SendReadSet(const TActorContext& ctx, ui64 step, "Send RS at " << TabletID() << " from " << source << " to " << target << " txId " << txId); auto ev = PrepareReadSet(step, txId, source, target, body, seqno); - + IncCounter(COUNTER_READSET_SENT_COUNT); IncCounter(COUNTER_READSET_SENT_SIZE, body.size()); PipeClientCache->Send(ctx, target, ev.Release()); -} - +} + void TDataShard::SendReadSets(const TActorContext& ctx, TVector<THolder<TEvTxProcessing::TEvReadSet>> &&readsets) { diff --git a/ydb/core/tx/datashard/datashard.h b/ydb/core/tx/datashard/datashard.h index 5a93c03502..62c1ad0527 100644 --- a/ydb/core/tx/datashard/datashard.h +++ b/ydb/core/tx/datashard/datashard.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "datashard_s3_upload.h" @@ -13,27 +13,27 @@ #include <ydb/core/tablet_flat/flat_row_versions.h> #include <library/cpp/time_provider/time_provider.h> - + namespace arrow { class RecordBatch; } -namespace NKikimr { - +namespace NKikimr { + namespace NDataShard { using TShardState = NKikimrTxDataShard::EDatashardState; - - struct TTxFlags { + + struct TTxFlags { enum Flags : ui64 { //////////////////////////// // Public operation flags // //////////////////////////// - Default = 0, - Dirty = 0x01, - DenyOnlineIfSnapshotNotReady = 0x02, - ForceOnline = 0x04, + Default = 0, + Dirty = 0x01, + DenyOnlineIfSnapshotNotReady = 0x02, + ForceOnline = 0x04, Immediate = 0x08, PublicFlagsMask = 0x000000000000FFFF, @@ -123,8 +123,8 @@ namespace NDataShard { PreservedPrivateFlagsMask = ReadOnly | ProposeBlocker | NeedDiagnostics | GlobalReader | GlobalWriter | KqpDataTransaction | KqpScanTransaction | BlockingImmediateOps | BlockingImmediateWrites, - }; - }; + }; + }; // Old datashard uses Uint32 column type for flags in local database. static_assert(TTxFlags::PreservedPrivateFlagsMask <= Max<ui64>()); @@ -167,22 +167,22 @@ namespace NDataShard { } }; -} - +} + // legacy namespace NTxDataShard { using NDataShard::TShardState; using NDataShard::TTxFlags; } -struct TEvDataShard { - enum EEv { - EvProposeTransaction = EventSpaceBegin(TKikimrEvents::ES_TX_DATASHARD), - EvCancelTransactionProposal, +struct TEvDataShard { + enum EEv { + EvProposeTransaction = EventSpaceBegin(TKikimrEvents::ES_TX_DATASHARD), + EvCancelTransactionProposal, EvApplyReplicationChanges, EvGetReplicationSourceOffsets, - - EvProposeTransactionResult = EvProposeTransaction + 1 * 512, + + EvProposeTransactionResult = EvProposeTransaction + 1 * 512, EvProposeTransactionRestart, EvProposeTransactionAttach, EvProposeTransactionAttachResult, @@ -190,25 +190,25 @@ struct TEvDataShard { EvReplicationSourceOffsets, EvReplicationSourceOffsetsAck, EvReplicationSourceOffsetsCancel, - - EvInitDataShard = EvProposeTransaction + 4 * 512, - EvGetShardState, - EvReadOperationHistogram, - EvUpdateConfig, + + EvInitDataShard = EvProposeTransaction + 4 * 512, + EvGetShardState, + EvReadOperationHistogram, + EvUpdateConfig, EvSchemaChanged, EvStateChanged, EvCancelBackup, EvMigrateSchemeShardRequest, EvMigrateSchemeShardResponse, EvCancelRestore, - - EvInitDataShardResult = EvProposeTransaction + 5 * 512, - EvGetShardStateResult, - EvReadOperationHistogramResult, - EvUpdateConfigResult, + + EvInitDataShardResult = EvProposeTransaction + 5 * 512, + EvGetShardStateResult, + EvReadOperationHistogramResult, + EvUpdateConfigResult, EvSchemaChangedResult, EvStateChangedResult, - + EvReturnBorrowedPart = 6 * 512, EvReturnBorrowedPartAck, @@ -298,47 +298,47 @@ struct TEvDataShard { EvReadAck, EvReadCancel, - EvEnd - }; - - static_assert(EvEnd < EventSpaceEnd(TKikimrEvents::ES_TX_DATASHARD), "expect EvEnd < EventSpaceEnd(TKikimrEvents::ES_TX_DATASHARD)"); - struct TEvGetShardState : public TEventPB<TEvGetShardState, NKikimrTxDataShard::TEvGetShardState, - TEvDataShard::EvGetShardState> { - TEvGetShardState() - { - } - + EvEnd + }; + + static_assert(EvEnd < EventSpaceEnd(TKikimrEvents::ES_TX_DATASHARD), "expect EvEnd < EventSpaceEnd(TKikimrEvents::ES_TX_DATASHARD)"); + struct TEvGetShardState : public TEventPB<TEvGetShardState, NKikimrTxDataShard::TEvGetShardState, + TEvDataShard::EvGetShardState> { + TEvGetShardState() + { + } + TEvGetShardState(const TActorId& source) - { + { ActorIdToProto(source, Record.MutableSource()); - } - + } + TActorId GetSource() const { return ActorIdFromProto(Record.GetSource()); - } - }; - - struct TEvGetShardStateResult : public TEventPB<TEvGetShardStateResult, NKikimrTxDataShard::TEvGetShardStateResult, - TEvDataShard::EvGetShardStateResult> { - TEvGetShardStateResult() - { - } - - TEvGetShardStateResult(ui64 origin, ui32 state) - { - Record.SetOrigin(origin); - Record.SetState(state); - } - - ui64 GetOrigin() const { - return Record.GetOrigin(); - } - - ui32 GetState() const { - return Record.GetState(); - } - }; - + } + }; + + struct TEvGetShardStateResult : public TEventPB<TEvGetShardStateResult, NKikimrTxDataShard::TEvGetShardStateResult, + TEvDataShard::EvGetShardStateResult> { + TEvGetShardStateResult() + { + } + + TEvGetShardStateResult(ui64 origin, ui32 state) + { + Record.SetOrigin(origin); + Record.SetState(state); + } + + ui64 GetOrigin() const { + return Record.GetOrigin(); + } + + ui32 GetState() const { + return Record.GetState(); + } + }; + struct TEvSchemaChanged : public TEventPB<TEvSchemaChanged, NKikimrTxDataShard::TEvSchemaChanged, TEvDataShard::EvSchemaChanged> { TEvSchemaChanged() @@ -399,23 +399,23 @@ struct TEvDataShard { } }; - struct TEvProposeTransaction : public TEventPB<TEvProposeTransaction, NKikimrTxDataShard::TEvProposeTransaction, - TEvDataShard::EvProposeTransaction> { - TEvProposeTransaction() - { - } - + struct TEvProposeTransaction : public TEventPB<TEvProposeTransaction, NKikimrTxDataShard::TEvProposeTransaction, + TEvDataShard::EvProposeTransaction> { + TEvProposeTransaction() + { + } + TEvProposeTransaction(NKikimrTxDataShard::ETransactionKind txKind, const TActorId& source, ui64 txId, const TStringBuf& txBody, ui32 flags = NDataShard::TTxFlags::Default) - { - Record.SetTxKind(txKind); + { + Record.SetTxKind(txKind); ActorIdToProto(source, Record.MutableSource()); - Record.SetTxId(txId); + Record.SetTxId(txId); Record.SetExecLevel(0); Record.SetTxBody(txBody.data(), txBody.size()); - Record.SetFlags(flags); - } - + Record.SetFlags(flags); + } + TEvProposeTransaction(NKikimrTxDataShard::ETransactionKind txKind, const TActorId& source, ui64 txId, const TStringBuf& txBody, ui64 snapshotStep, ui64 snapshotTxId, ui32 flags = NDataShard::TTxFlags::Default) : TEvProposeTransaction(txKind, source, txId, txBody, flags) @@ -449,51 +449,51 @@ struct TEvDataShard { } } - NKikimrTxDataShard::ETransactionKind GetTxKind() const { - return Record.GetTxKind(); - } - + NKikimrTxDataShard::ETransactionKind GetTxKind() const { + return Record.GetTxKind(); + } + TActorId GetSource() const { return ActorIdFromProto(Record.GetSource()); - } - - ui64 GetTxId() const { - return Record.GetTxId(); - } - + } + + ui64 GetTxId() const { + return Record.GetTxId(); + } + ui32 GetFlags() const { return Record.GetFlags(); - } - - TStringBuf GetTxBody() const { - return Record.GetTxBody(); - } - }; - - struct TEvCancelTransactionProposal : public TEventPB<TEvCancelTransactionProposal, NKikimrTxDataShard::TEvCancelTransactionProposal, TEvDataShard::EvCancelTransactionProposal> { - TEvCancelTransactionProposal() - {} - - TEvCancelTransactionProposal(ui64 txId) - { - Record.SetTxId(txId); - } - }; - - struct TEvProposeTransactionResult : public TEventPB<TEvProposeTransactionResult, NKikimrTxDataShard::TEvProposeTransactionResult, - TEvDataShard::EvProposeTransactionResult> { - + } + + TStringBuf GetTxBody() const { + return Record.GetTxBody(); + } + }; + + struct TEvCancelTransactionProposal : public TEventPB<TEvCancelTransactionProposal, NKikimrTxDataShard::TEvCancelTransactionProposal, TEvDataShard::EvCancelTransactionProposal> { + TEvCancelTransactionProposal() + {} + + TEvCancelTransactionProposal(ui64 txId) + { + Record.SetTxId(txId); + } + }; + + struct TEvProposeTransactionResult : public TEventPB<TEvProposeTransactionResult, NKikimrTxDataShard::TEvProposeTransactionResult, + TEvDataShard::EvProposeTransactionResult> { + TEvProposeTransactionResult() = default; - TEvProposeTransactionResult(NKikimrTxDataShard::ETransactionKind txKind, ui64 origin, ui64 txId, - NKikimrTxDataShard::TEvProposeTransactionResult::EStatus status) - { - Record.SetTxKind(txKind); - Record.SetOrigin(origin); - Record.SetTxId(txId); - Record.SetStatus(status); - } - + TEvProposeTransactionResult(NKikimrTxDataShard::ETransactionKind txKind, ui64 origin, ui64 txId, + NKikimrTxDataShard::TEvProposeTransactionResult::EStatus status) + { + Record.SetTxKind(txKind); + Record.SetOrigin(origin); + Record.SetTxId(txId); + Record.SetStatus(status); + } + bool IsPrepared() const { return GetStatus() == NKikimrTxDataShard::TEvProposeTransactionResult::PREPARED; } bool IsComplete() const { return GetStatus() == NKikimrTxDataShard::TEvProposeTransactionResult::COMPLETE; } bool IsTryLater() const { return GetStatus() == NKikimrTxDataShard::TEvProposeTransactionResult::TRY_LATER; } @@ -530,10 +530,10 @@ struct TEvDataShard { Record.SetPrepareArriveTime(RequestStartTime.MicroSeconds()); } - void SetTxResult(const TStringBuf& txResult) { + void SetTxResult(const TStringBuf& txResult) { Record.SetTxResult(txResult.data(), txResult.size()); - } - + } + void SetExecutionError(const NKikimrTxDataShard::TError::EKind& error, const TStringBuf& message) { switch (error) { case NKikimrTxDataShard::TError::REPLY_SIZE_EXECEEDED: @@ -563,11 +563,11 @@ struct TEvDataShard { AddError(error, message); } - void SetStepOrderId(const std::pair<ui64, ui64>& stepOrderId) { - Record.SetStep(stepOrderId.first); - Record.SetOrderId(stepOrderId.second); - } - + void SetStepOrderId(const std::pair<ui64, ui64>& stepOrderId) { + Record.SetStep(stepOrderId.first); + Record.SetOrderId(stepOrderId.second); + } + void AddTxLock(ui64 lockId, ui64 shard, ui32 generation, ui64 counter, ui64 ssId, ui64 pathId) { auto entry = Record.AddTxLocks(); entry->SetLockId(lockId); @@ -578,34 +578,34 @@ struct TEvDataShard { entry->SetPathId(pathId); } - NKikimrTxDataShard::ETransactionKind GetTxKind() const { - return Record.GetTxKind(); - } - - ui64 GetOrigin() const { - return Record.GetOrigin(); - } - - ui64 GetTxId() const { - return Record.GetTxId(); - } - - NKikimrTxDataShard::TEvProposeTransactionResult::EStatus GetStatus() const { - return Record.GetStatus(); - } - - bool HasTxResult() const { - return Record.HasTxResult(); - } - - TStringBuf GetTxResult() const { - return Record.GetTxResult(); - } - - std::pair<ui64, ui64> GetStepOrderId() const { - return std::make_pair(Record.GetStep(), Record.GetOrderId()); - } - + NKikimrTxDataShard::ETransactionKind GetTxKind() const { + return Record.GetTxKind(); + } + + ui64 GetOrigin() const { + return Record.GetOrigin(); + } + + ui64 GetTxId() const { + return Record.GetTxId(); + } + + NKikimrTxDataShard::TEvProposeTransactionResult::EStatus GetStatus() const { + return Record.GetStatus(); + } + + bool HasTxResult() const { + return Record.HasTxResult(); + } + + TStringBuf GetTxResult() const { + return Record.GetTxResult(); + } + + std::pair<ui64, ui64> GetStepOrderId() const { + return std::make_pair(Record.GetStep(), Record.GetOrderId()); + } + TString GetError() const { if (Record.ErrorSize() > 0) { TString result; @@ -622,22 +622,22 @@ struct TEvDataShard { } } - void AddError(NKikimrTxDataShard::TError::EKind kind, const TStringBuf& reason, const TStringBuf& keyBuffer = TStringBuf()) { - auto error = Record.MutableError()->Add(); - error->SetKind(kind); - if (reason) { + void AddError(NKikimrTxDataShard::TError::EKind kind, const TStringBuf& reason, const TStringBuf& keyBuffer = TStringBuf()) { + auto error = Record.MutableError()->Add(); + error->SetKind(kind); + if (reason) { error->SetReason(reason.data(), reason.size()); - } - - if (keyBuffer) { + } + + if (keyBuffer) { error->SetKey(keyBuffer.data(), keyBuffer.size()); - } - } + } + } private: bool ForceOnline = false; bool ForceDirty = false; - }; + }; struct TEvProposeTransactionRestart : public TEventPB<TEvProposeTransactionRestart, NKikimrTxDataShard::TEvProposeTransactionRestart, TEvDataShard::EvProposeTransactionRestart> { TEvProposeTransactionRestart() = default; @@ -1539,12 +1539,12 @@ struct TEvDataShard { } }; -}; - +}; + IActor* CreateDataShard(const TActorId &tablet, TTabletStorageInfo *info); - -} - + +} + inline TString DatashardStateName(ui32 state) { NKikimrTxDataShard::EDatashardState s = (NKikimrTxDataShard::EDatashardState)state; return NKikimrTxDataShard::EDatashardState_Name(s); diff --git a/ydb/core/tx/datashard/datashard__engine_host.cpp b/ydb/core/tx/datashard/datashard__engine_host.cpp index 876c337093..768075f3fc 100644 --- a/ydb/core/tx/datashard/datashard__engine_host.cpp +++ b/ydb/core/tx/datashard/datashard__engine_host.cpp @@ -12,17 +12,17 @@ #include <ydb/library/yql/minikql/mkql_function_registry.h> #include <ydb/library/yql/minikql/mkql_string_util.h> #include <ydb/library/yql/minikql/mkql_node_cast.h> - + #include <library/cpp/actors/core/log.h> #include <util/generic/cast.h> -namespace NKikimr { +namespace NKikimr { namespace NDataShard { - -using namespace NMiniKQL; -using namespace NTabletFlatExecutor; - + +using namespace NMiniKQL; +using namespace NTabletFlatExecutor; + namespace { NUdf::TUnboxedValue CreateRow(const TVector<TCell>& inRow, @@ -279,19 +279,19 @@ TIntrusivePtr<TThrRefBase> InitDataShardSysTables(TDataShard* self) { /// class TDataShardEngineHost : public TEngineHost { -public: +public: TDataShardEngineHost(TDataShard* self, NTable::TDatabase& db, TEngineHostCounters& counters, ui64& lockTxId, TInstant now) : TEngineHost(db, counters, TEngineHostSettings(self->TabletID(), (self->State == TShardState::Readonly || self->State == TShardState::Frozen), self->ByKeyFilterDisabled(), self->GetKeyAccessSampler())) - , Self(self) + , Self(self) , DB(db) , LockTxId(lockTxId) , Now(now) {} - + void SetWriteVersion(TRowVersion writeVersion) { WriteVersion = writeVersion; } @@ -361,7 +361,7 @@ public: NUdf::TUnboxedValue SelectRow(const TTableId& tableId, const TArrayRef<const TCell>& row, TStructLiteral* columnIds, TOptionalType* returnType, const TReadTarget& readTarget, const THolderFactory& holderFactory) override - { + { if (TSysTables::IsSystemTable(tableId)) { return DataShardSysTable(tableId).SelectRow(row, columnIds, returnType, readTarget, holderFactory); } @@ -370,13 +370,13 @@ public: Self->SetTableAccessTime(tableId, Now); return TEngineHost::SelectRow(tableId, row, columnIds, returnType, readTarget, holderFactory); - } - + } + NUdf::TUnboxedValue SelectRange(const TTableId& tableId, const TTableRange& range, TStructLiteral* columnIds, TListLiteral* skipNullKeys, TStructType* returnType, const TReadTarget& readTarget, ui64 itemsLimit, ui64 bytesLimit, bool reverse, std::pair<const TListLiteral*, const TListLiteral*> forbidNullArgs, const THolderFactory& holderFactory) override - { + { Y_VERIFY(!TSysTables::IsSystemTable(tableId), "SelectRange no system table is not supported"); Self->SysLocksTable().SetLock(tableId, range, LockTxId); @@ -384,8 +384,8 @@ public: Self->SetTableAccessTime(tableId, Now); return TEngineHost::SelectRange(tableId, range, columnIds, skipNullKeys, returnType, readTarget, itemsLimit, bytesLimit, reverse, forbidNullArgs, holderFactory); - } - + } + void UpdateRow(const TTableId& tableId, const TArrayRef<const TCell>& row, const TArrayRef<const TUpdateCommand>& commands) override { if (TSysTables::IsSystemTable(tableId)) { DataShardSysTable(tableId).UpdateRow(row, commands); @@ -436,8 +436,8 @@ public: } else { TEngineHost::UpdateRow(tableId, row, commands); } - } - + } + void EraseRow(const TTableId& tableId, const TArrayRef<const TCell>& row) override { if (TSysTables::IsSystemTable(tableId)) { DataShardSysTable(tableId).EraseRow(row); @@ -447,10 +447,10 @@ public: Self->SysLocksTable().BreakLock(tableId, row); Self->SetTableUpdateTime(tableId, Now); - TEngineHost::EraseRow(tableId, row); - } - - // Returns whether row belong this shard. + TEngineHost::EraseRow(tableId, row); + } + + // Returns whether row belong this shard. bool IsMyKey(const TTableId& tableId, const TArrayRef<const TCell>& row) const override { if (TSysTables::IsSystemTable(tableId)) return DataShardSysTable(tableId).IsMyKey(row); @@ -464,17 +464,17 @@ public: // Check row against range const TUserTable& info = *iter->second; return (ComparePointAndRange(row, info.GetTableRange(), info.KeyColumnTypes, info.KeyColumnTypes) == 0); - } - - bool IsPathErased(const TTableId& tableId) const override { + } + + bool IsPathErased(const TTableId& tableId) const override { if (TSysTables::IsSystemTable(tableId)) return false; return TDataShardEngineHost::LocalTableId(tableId) == 0; - } - - ui64 LocalTableId(const TTableId &tableId) const override { + } + + ui64 LocalTableId(const TTableId &tableId) const override { return Self->GetLocalTableId(tableId); - } + } ui64 GetTableSchemaVersion(const TTableId& tableId) const override { if (TSysTables::IsSystemTable(tableId)) @@ -491,7 +491,7 @@ public: } } -private: +private: const TDataShardSysTable& DataShardSysTable(const TTableId& tableId) const { return static_cast<const TDataShardSysTables *>(Self->GetDataShardSysTables())->Get(tableId); } @@ -504,8 +504,8 @@ private: TRowVersion WriteVersion = TRowVersion::Max(); TRowVersion ReadVersion = TRowVersion::Min(); mutable THashMap<TTableId, THolder<IChangeCollector>> ChangeCollectors; -}; - +}; + // TEngineBay::TEngineBay(TDataShard * self, TTransactionContext& txc, const TActorContext& ctx, diff --git a/ydb/core/tx/datashard/datashard__get_state_tx.cpp b/ydb/core/tx/datashard/datashard__get_state_tx.cpp index 552d27fd64..13878482d9 100644 --- a/ydb/core/tx/datashard/datashard__get_state_tx.cpp +++ b/ydb/core/tx/datashard/datashard__get_state_tx.cpp @@ -1,27 +1,27 @@ #include "datashard_txs.h" - -namespace NKikimr { + +namespace NKikimr { namespace NDataShard { - -using namespace NTabletFlatExecutor; - + +using namespace NTabletFlatExecutor; + TDataShard::TTxGetShardState::TTxGetShardState(TDataShard* ds, TEvDataShard::TEvGetShardState::TPtr ev) - : TBase(ds) - , Ev(ev) -{} - + : TBase(ds) + , Ev(ev) +{} + bool TDataShard::TTxGetShardState::Execute(TTransactionContext& txc, const TActorContext& ctx) { Y_UNUSED(txc); Y_UNUSED(ctx); - + Result = MakeHolder<TEvDataShard::TEvGetShardStateResult>(Self->TabletID(), Self->State); if (Self->Pipeline.HasDrop()) Result->Record.SetDropTxId(Self->Pipeline.CurrentSchemaTxId()); - return true; -} - + return true; +} + void TDataShard::TTxGetShardState::Complete(const TActorContext& ctx) { ctx.Send(Ev->Get()->GetSource(), Result.Release()); -} - -}} +} + +}} diff --git a/ydb/core/tx/datashard/datashard__init.cpp b/ydb/core/tx/datashard/datashard__init.cpp index dc12c49959..ce50054dd4 100644 --- a/ydb/core/tx/datashard/datashard__init.cpp +++ b/ydb/core/tx/datashard/datashard__init.cpp @@ -3,21 +3,21 @@ #include <ydb/core/base/tx_processing.h> #include <ydb/core/tablet/tablet_exception.h> #include <ydb/core/util/pb.h> + - -namespace NKikimr { +namespace NKikimr { namespace NDataShard { - -using namespace NTabletFlatExecutor; - + +using namespace NTabletFlatExecutor; + TDataShard::TTxInit::TTxInit(TDataShard* ds) - : TBase(ds) -{} - + : TBase(ds) +{} + bool TDataShard::TTxInit::Execute(TTransactionContext& txc, const TActorContext& ctx) { LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "TDataShard::TTxInit::Execute"); - - try { + + try { Self->State = TShardState::Unknown; Self->LastLocalTid = Schema::MinLocalTid; Self->LastSeqno = 1; @@ -41,19 +41,19 @@ bool TDataShard::TTxInit::Execute(TTransactionContext& txc, const TActorContext& } return done; - } catch (const TNotReadyTabletException &) { - return false; - } catch (const TSchemeErrorTabletException &ex) { + } catch (const TNotReadyTabletException &) { + return false; + } catch (const TSchemeErrorTabletException &ex) { Y_UNUSED(ex); Y_FAIL(); - } catch (...) { + } catch (...) { Y_FAIL("there must be no leaked exceptions"); - } -} - + } +} + void TDataShard::TTxInit::Complete(const TActorContext &ctx) { LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "TDataShard::TTxInit::Complete"); - + // Start MakeSnapshot() if we started in SplitSrcMakeSnapshot state if (Self->State == TShardState::SplitSrcMakeSnapshot) { Self->Execute(Self->CreateTxStartSplit(), ctx); @@ -69,7 +69,7 @@ void TDataShard::TTxInit::Complete(const TActorContext &ctx) { Self->Execute(Self->CreateTxInitSchemaDefaults(), ctx); } - Self->SwitchToWork(ctx); + Self->SwitchToWork(ctx); Self->SendRegistrationRequestTimeCast(ctx); // InReadSets table might have a lot of garbage due to old bug. @@ -120,18 +120,18 @@ void TDataShard::TTxInit::Complete(const TActorContext &ctx) { // Switch mvcc state if needed Self->CheckMvccStateChangeCanStart(ctx); -} - +} + #define LOAD_SYS_UI64(db, row, value) if (!TDataShard::SysGetUi64(db, row, value)) return false; #define LOAD_SYS_BYTES(db, row, value) if (!TDataShard::SysGetBytes(db, row, value)) return false; #define LOAD_SYS_BOOL(db, row, value) if (!TDataShard::SysGetBool(db, row, value)) return false; - + bool TDataShard::TTxInit::ReadEverything(TTransactionContext &txc) { - // Note that we should not store any data directly into Self until NoMoreReads() is called - // But it is ok for initialization, as long as ALL FOLLOWING ACTIONS ARE IDEMPOTENT - - NIceDb::TNiceDb db(txc.DB); - + // Note that we should not store any data directly into Self until NoMoreReads() is called + // But it is ok for initialization, as long as ALL FOLLOWING ACTIONS ARE IDEMPOTENT + + NIceDb::TNiceDb db(txc.DB); + { bool ready = true; @@ -171,7 +171,7 @@ bool TDataShard::TTxInit::ReadEverything(TTransactionContext &txc) { #undef PRECHARGE_SYS_TABLE } - // Reads from Sys table + // Reads from Sys table LOAD_SYS_UI64(db, Schema::Sys_State, Self->State); LOAD_SYS_UI64(db, Schema::Sys_LastLocalTid, Self->LastLocalTid); LOAD_SYS_UI64(db, Schema::Sys_LastSeqno, Self->LastSeqno); @@ -207,26 +207,26 @@ bool TDataShard::TTxInit::ReadEverything(TTransactionContext &txc) { if (!Self->Pipeline.Load(db)) return false; - - { // Reads user tables metadata + + { // Reads user tables metadata Self->TableInfos.clear(); // For idempotency auto rowset = db.Table<Schema::UserTables>().GreaterOrEqual(0).Select(); // TODO[serxa]: this should be Range() but it is not working right now - if (!rowset.IsReady()) - return false; - while (!rowset.EndOfSet()) { - ui64 tableId = rowset.GetValue<Schema::UserTables::Tid>(); - ui32 localTid = rowset.GetValue<Schema::UserTables::LocalTid>(); + if (!rowset.IsReady()) + return false; + while (!rowset.EndOfSet()) { + ui64 tableId = rowset.GetValue<Schema::UserTables::Tid>(); + ui32 localTid = rowset.GetValue<Schema::UserTables::LocalTid>(); ui32 shadowTid = rowset.GetValueOrDefault<Schema::UserTables::ShadowTid>(); TString schema = rowset.GetValue<Schema::UserTables::Schema>(); NKikimrSchemeOp::TTableDescription descr; bool parseOk = ParseFromStringNoSizeLimit(descr, schema); Y_VERIFY(parseOk); Self->AddUserTable(TPathId(Self->GetPathOwnerId(), tableId), new TUserTable(localTid, descr, shadowTid)); - if (!rowset.Next()) - return false; - } - } - + if (!rowset.Next()) + return false; + } + } + if (Self->State != TShardState::Offline && txc.DB.GetScheme().GetTableInfo(Schema::UserTablesStats::TableId)) { // Reads user tables persistent stats auto rowset = db.Table<Schema::UserTablesStats>().GreaterOrEqual(0).Select(); @@ -250,7 +250,7 @@ bool TDataShard::TTxInit::ReadEverything(TTransactionContext &txc) { auto rowset = db.Table<Schema::SplitSrcSnapshots>().GreaterOrEqual(0).Select(); if (!rowset.IsReady()) return false; - + while (!rowset.EndOfSet()) { ui64 dstTablet = rowset.GetValue<Schema::SplitSrcSnapshots::DstTabletId>(); TString snapBody = rowset.GetValue<Schema::SplitSrcSnapshots::SnapshotMeta>(); @@ -365,8 +365,8 @@ bool TDataShard::TTxInit::ReadEverything(TTransactionContext &txc) { // Load unsent ReadSets if (!Self->OutReadSets.LoadReadSets(db)) - return false; - + return false; + // TODO: properly check shard state if (Self->State != TShardState::Offline && txc.DB.GetScheme().GetTableInfo(Schema::TxMain::TableId)) { if (!Self->TransQueue.Load(db)) @@ -382,7 +382,7 @@ bool TDataShard::TTxInit::ReadEverything(TTransactionContext &txc) { Self->Pipeline.AddCandidateUnit(EExecutionUnitKind::PlanQueue); // TODO: add propose blockers to blockers list } - + if (Self->State != TShardState::Offline && txc.DB.GetScheme().GetTableInfo(Schema::Snapshots::TableId)) { if (!Self->SnapshotManager.Reload(db)) return false; @@ -479,9 +479,9 @@ bool TDataShard::TTxInit::ReadEverything(TTransactionContext &txc) { } } - return true; -} - + return true; +} + /// Creates and updates schema at tablet boot time class TDataShard::TTxInitSchema : public TTransactionBase<TDataShard> { public: @@ -721,4 +721,4 @@ bool TDataShard::SyncSchemeOnFollower(TTransactionContext &txc, const TActorCont return true; } -}} +}} diff --git a/ydb/core/tx/datashard/datashard__plan_step.cpp b/ydb/core/tx/datashard/datashard__plan_step.cpp index 6399598865..53702efa2b 100644 --- a/ydb/core/tx/datashard/datashard__plan_step.cpp +++ b/ydb/core/tx/datashard/datashard__plan_step.cpp @@ -1,30 +1,30 @@ #include "datashard_txs.h" - + #include <util/string/vector.h> -namespace NKikimr { +namespace NKikimr { namespace NDataShard { - -using namespace NTabletFlatExecutor; - + +using namespace NTabletFlatExecutor; + TDataShard::TTxPlanStep::TTxPlanStep(TDataShard *self, TEvTxProcessing::TEvPlanStep::TPtr ev) - : TBase(self) - , Ev(ev) - , IsAccepted(false) - , RequestStartTime(TAppData::TimeProvider->Now()) -{ + : TBase(self) + , Ev(ev) + , IsAccepted(false) + , RequestStartTime(TAppData::TimeProvider->Now()) +{ Y_VERIFY(Ev); -} - +} + bool TDataShard::TTxPlanStep::Execute(TTransactionContext &txc, const TActorContext &ctx) { Y_VERIFY(Ev); - + // TEvPlanStep are strictly ordered by mediator so this Tx must not be retried not to break this ordering! txc.DB.NoMoreReadsForTx(); - + TxByAck.clear(); IsAccepted = false; - + const ui64 step = Ev->Get()->Record.GetStep(); Self->LastKnownMediator = Ev->Get()->Record.GetMediatorID(); @@ -39,7 +39,7 @@ bool TDataShard::TTxPlanStep::Execute(TTransactionContext &txc, const TActorCont TActorId txOwner = ActorIdFromProto(tx.GetAckTo()); TxByAck[txOwner].push_back(tx.GetTxId()); } - + if (Self->State != TShardState::Offline && Self->State != TShardState::PreOffline) { // The DS is completing Drop, so we just ignore PlanStep assuming that it might only contain // transactions that have already been executed. @@ -56,40 +56,40 @@ bool TDataShard::TTxPlanStep::Execute(TTransactionContext &txc, const TActorCont Self->IncCounter(COUNTER_PLAN_STEP_IGNORED); return true; } - + for (ui64 txId : txIds) { LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "Planned transaction txId " << txId << " at step " << step << " at tablet " << Self->TabletID() << " " << Ev->Get()->Record); } - + Self->PlanQueue.Progress(ctx); Self->IncCounter(COUNTER_PLAN_STEP_ACCEPTED); return true; -} - +} + void TDataShard::TTxPlanStep::Complete(const TActorContext &ctx) { Y_VERIFY(Ev); ui64 step = Ev->Get()->Record.GetStep(); - - for (auto& kv : TxByAck) { + + for (auto& kv : TxByAck) { THolder<TEvTxProcessing::TEvPlanStepAck> ack = MakeHolder<TEvTxProcessing::TEvPlanStepAck>(Self->TabletID(), step, kv.second.begin(), kv.second.end()); LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "Sending '" << ack->ToString()); ctx.Send(kv.first, ack.Release()); // Ack to Tx coordinator - } - + } + THolder<TEvTxProcessing::TEvPlanStepAccepted> accepted = MakeHolder<TEvTxProcessing::TEvPlanStepAccepted>(Self->TabletID(), step); LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "Sending '" << accepted->ToString()); ctx.Send(Ev->Sender, accepted.Release()); // Reply to the mediator - if (IsAccepted) { + if (IsAccepted) { TDuration duration = TAppData::TimeProvider->Now() - RequestStartTime; Self->IncCounter(COUNTER_ACCEPTED_PLAN_STEP_COMPLETE_LATENCY, duration); - } -} - -}} + } +} + +}} diff --git a/ydb/core/tx/datashard/datashard__progress_resend_rs.cpp b/ydb/core/tx/datashard/datashard__progress_resend_rs.cpp index 6a96ceee8f..49397c85fb 100644 --- a/ydb/core/tx/datashard/datashard__progress_resend_rs.cpp +++ b/ydb/core/tx/datashard/datashard__progress_resend_rs.cpp @@ -1,24 +1,24 @@ #include "datashard_txs.h" - -namespace NKikimr { - + +namespace NKikimr { + namespace NDataShard { - + TDataShard::TTxProgressResendRS::TTxProgressResendRS(TDataShard *self, ui64 seqno) - : TBase(self) - , Seqno(seqno) - { - } - + : TBase(self) + , Seqno(seqno) + { + } + bool TDataShard::TTxProgressResendRS::Execute(TTransactionContext &txc, const TActorContext &ctx) { - LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Start TTxProgressResendRS at tablet %" PRIu64, Self->TabletID()); + LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Start TTxProgressResendRS at tablet %" PRIu64, Self->TabletID()); return Self->OutReadSets.ResendRS(txc, ctx, Seqno); - } - + } + void TDataShard::TTxProgressResendRS::Complete(const TActorContext &ctx) { Y_UNUSED(ctx); - /* no-op */ - } -} - -} + /* no-op */ + } +} + +} diff --git a/ydb/core/tx/datashard/datashard__progress_tx.cpp b/ydb/core/tx/datashard/datashard__progress_tx.cpp index 3f1fab6b46..fd5afe107d 100644 --- a/ydb/core/tx/datashard/datashard__progress_tx.cpp +++ b/ydb/core/tx/datashard/datashard__progress_tx.cpp @@ -1,28 +1,28 @@ #include "datashard_txs.h" #include "datashard_failpoints.h" - -namespace NKikimr { + +namespace NKikimr { namespace NDataShard { - + TDataShard::TTxProgressTransaction::TTxProgressTransaction(TDataShard *self, TOperation::TPtr op) - : TBase(self) + : TBase(self) , ActiveOp(std::move(op)) {} - + bool TDataShard::TTxProgressTransaction::Execute(TTransactionContext &txc, const TActorContext &ctx) { LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "TTxProgressTransaction::Execute at " << Self->TabletID()); - try { + try { if (!Self->IsStateActive()) { Self->IncCounter(COUNTER_TX_PROGRESS_SHARD_INACTIVE); LOG_INFO_S(ctx, NKikimrServices::TX_DATASHARD, "Progress tx at non-ready tablet " << Self->TabletID() << " state " << Self->State); Y_VERIFY(!ActiveOp, "Unexpected ActiveOp at inactive shard %" PRIu64, Self->TabletID()); Self->PlanQueue.Reset(ctx); - return true; - } - + return true; + } + NIceDb::TNiceDb db(txc.DB); if (!ActiveOp) { @@ -38,7 +38,7 @@ bool TDataShard::TTxProgressTransaction::Execute(TTransactionContext &txc, const if (needFutureCleanup) { Self->PlanCleanup(ctx); } - + // Allow another concurrent progress tx Self->PlanQueue.Reset(ctx); Self->Pipeline.ActivateWaitingTxOps(ctx); @@ -56,8 +56,8 @@ bool TDataShard::TTxProgressTransaction::Execute(TTransactionContext &txc, const << ActiveOp->GetKind() << " " << *ActiveOp << " (unit " << ActiveOp->GetCurrentUnit() << ") at " << Self->TabletID()); ActiveOp->IncrementInProgress(); - } - + } + Y_VERIFY(ActiveOp && ActiveOp->IsInProgress()); auto status = Self->Pipeline.RunExecutionPlan(ActiveOp, CompleteList, txc, ctx); @@ -101,11 +101,11 @@ bool TDataShard::TTxProgressTransaction::Execute(TTransactionContext &txc, const // Commit all side effects return true; - } catch (...) { + } catch (...) { Y_FAIL("there must be no leaked exceptions"); - } -} - + } +} + void TDataShard::TTxProgressTransaction::Complete(const TActorContext &ctx) { LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "TTxProgressTransaction::Complete at " << Self->TabletID()); @@ -133,6 +133,6 @@ void TDataShard::TTxProgressTransaction::Complete(const TActorContext &ctx) { Self->CheckSplitCanStart(ctx); Self->CheckMvccStateChangeCanStart(ctx); -} - -}} +} + +}} diff --git a/ydb/core/tx/datashard/datashard__propose_tx_base.cpp b/ydb/core/tx/datashard/datashard__propose_tx_base.cpp index 7dfb1a294e..1e222f7f3f 100644 --- a/ydb/core/tx/datashard/datashard__propose_tx_base.cpp +++ b/ydb/core/tx/datashard/datashard__propose_tx_base.cpp @@ -1,12 +1,12 @@ #include "datashard_txs.h" #include "datashard_failpoints.h" #include "operation.h" - + #include <ydb/core/util/pb.h> -namespace NKikimr { +namespace NKikimr { namespace NDataShard { - + TDataShard::TTxProposeTransactionBase::TTxProposeTransactionBase(TDataShard *self, TEvDataShard::TEvProposeTransaction::TPtr &&ev, TInstant receivedAt, ui64 tieBreakerIndex, @@ -33,7 +33,7 @@ bool TDataShard::TTxProposeTransactionBase::Execute(NTabletFlatExecutor::TTransa Acked = true; } - try { + try { TOutputOpData::TResultPtr result = nullptr; // If tablet is in follower mode then we should sync scheme // before we build and check operation. @@ -137,23 +137,23 @@ bool TDataShard::TTxProposeTransactionBase::Execute(NTabletFlatExecutor::TTransa } // Commit all side effects - return true; - } catch (const TNotReadyTabletException &) { + return true; + } catch (const TNotReadyTabletException &) { LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "TX [" << 0 << " : " << TxId << "] can't prepare (tablet's not ready) at tablet " << Self->TabletID()); - return false; - } catch (const TSchemeErrorTabletException &ex) { + return false; + } catch (const TSchemeErrorTabletException &ex) { Y_UNUSED(ex); Y_FAIL(); } catch (const TMemoryLimitExceededException &ex) { Y_FAIL("there must be no leaked exceptions: TMemoryLimitExceededException"); } catch (const std::exception &e) { Y_FAIL("there must be no leaked exceptions: %s", e.what()); - } catch (...) { + } catch (...) { Y_FAIL("there must be no leaked exceptions"); - } -} - + } +} + void TDataShard::TTxProposeTransactionBase::Complete(const TActorContext &ctx) { LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "TTxProposeTransactionBase::Complete at " << Self->TabletID()); @@ -181,6 +181,6 @@ void TDataShard::TTxProposeTransactionBase::Complete(const TActorContext &ctx) { Self->CheckSplitCanStart(ctx); Self->CheckMvccStateChangeCanStart(ctx); -} - -}} +} + +}} diff --git a/ydb/core/tx/datashard/datashard__readset.cpp b/ydb/core/tx/datashard/datashard__readset.cpp index c935025b80..423225c32c 100644 --- a/ydb/core/tx/datashard/datashard__readset.cpp +++ b/ydb/core/tx/datashard/datashard__readset.cpp @@ -1,14 +1,14 @@ #include "datashard_txs.h" - -namespace NKikimr { - + +namespace NKikimr { + namespace NDataShard { - + TDataShard::TTxReadSet::TTxReadSet(TDataShard *self, TEvTxProcessing::TEvReadSet::TPtr ev) - : TBase(self) - , Ev(ev) + : TBase(self) + , Ev(ev) {} - + bool TDataShard::TTxReadSet::Execute(TTransactionContext &txc, const TActorContext &ctx) { LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "TTxReadSet::Execute at " << Self->TabletID() << " got read set: " @@ -34,30 +34,30 @@ namespace NDataShard { if (!saved) { // delayed. Do not ack Y_VERIFY(!Ack); Ev.Reset(); - } - - return true; - } - + } + + return true; + } + THolder<IEventHandle> TDataShard::TTxReadSet::MakeAck(const TActorContext& ctx) { return THolder(new IEventHandle(Ev->Sender, ctx.SelfID, new TEvTxProcessing::TEvReadSetAck(*Ev->Get(), Self->TabletID()))); - } - + } + void TDataShard::TTxReadSet::Complete(const TActorContext &ctx) { LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, "TTxReadSet::Complete at " << Self->TabletID()); - // If it was read set for non-active tx we should send ACK back after successful save in DB - // Note that, active tx will send "delayed" ACK after tx complete + // If it was read set for non-active tx we should send ACK back after successful save in DB + // Note that, active tx will send "delayed" ACK after tx complete if (Ack) { LOG_DEBUG(ctx, NKikimrServices::TX_DATASHARD, "Send RS Ack at %" PRIu64 " %s", Self->TabletID(), Ev->Get()->ToString().data()); ctx.ExecutorThread.Send(Ack); Self->IncCounter(COUNTER_ACK_SENT); - } - } -} - -} + } + } +} + +} diff --git a/ydb/core/tx/datashard/datashard_impl.h b/ydb/core/tx/datashard/datashard_impl.h index 11313474f8..4429a8fc51 100644 --- a/ydb/core/tx/datashard/datashard_impl.h +++ b/ydb/core/tx/datashard/datashard_impl.h @@ -1,5 +1,5 @@ -#pragma once - +#pragma once + #include "datashard.h" #include "datashard_locks.h" #include "datashard_trans_queue.h" @@ -16,9 +16,9 @@ #include "datashard_repl_offsets_server.h" #include "change_exchange.h" #include "change_record.h" -#include "progress_queue.h" +#include "progress_queue.h" #include "read_iterator.h" - + #include <ydb/core/tx/time_cast/time_cast.h> #include <ydb/core/tx/tx_processing.h> #include <ydb/core/tx/schemeshard/schemeshard.h> @@ -40,16 +40,16 @@ #include <ydb/core/protos/tx_datashard.pb.h> #include <ydb/core/protos/subdomains.pb.h> #include <ydb/core/protos/counters_datashard.pb.h> - + #include <ydb/public/api/protos/ydb_status_codes.pb.h> #include <library/cpp/actors/interconnect/interconnect.h> #include <util/string/join.h> -namespace NKikimr { +namespace NKikimr { namespace NDataShard { - + extern TStringBuf SnapshotTransferReadSetMagic; using NTabletFlatExecutor::ITransaction; @@ -139,19 +139,19 @@ class TDataShard , public NTabletFlatExecutor::TTabletExecutedFlat { class TTxStopGuard; - class TTxGetShardState; - class TTxInit; + class TTxGetShardState; + class TTxInit; class TTxInitSchema; class TTxInitSchemaDefaults; - class TTxPlanStep; - class TTxProgressResendRS; - class TTxProgressTransaction; + class TTxPlanStep; + class TTxProgressResendRS; + class TTxProgressTransaction; class TTxCleanupTransaction; - class TTxProposeDataTransaction; + class TTxProposeDataTransaction; class TTxProposeSchemeTransaction; class TTxCancelTransactionProposal; - class TTxProposeTransactionBase; - class TTxReadSet; + class TTxProposeTransactionBase; + class TTxReadSet; class TTxSchemaChanged; class TTxInitiateBorrowedPartsReturn; class TTxReturnBorrowedPart; @@ -199,7 +199,7 @@ class TDataShard class TTxCompactBorrowed; class TTxCompactTable; class TTxPersistFullCompactionTs; - + template <typename T> friend class TTxDirectBase; class TTxUploadRows; class TTxEraseRows; @@ -222,7 +222,7 @@ class TDataShard NMon::TEvRemoteHttpInfo::TPtr ev); friend class TDataShardMiniKQLFactory; - friend class TDataTransactionProcessor; + friend class TDataTransactionProcessor; friend class TSchemeTransactionProcessor; friend class TScanTransactionProcessor; friend class TDataShardEngineHost; @@ -230,7 +230,7 @@ class TDataShard friend class TExecuteKqpScanTxUnit; friend class TTableScan; friend class TKqpScan; - + friend class TTransQueue; friend class TOutReadSets; friend class TPipeline; @@ -274,15 +274,15 @@ class TDataShard class TTxApplyReplicationChanges; - struct TEvPrivate { - enum EEv { + struct TEvPrivate { + enum EEv { EvProgressTransaction = EventSpaceBegin(TKikimrEvents::ES_PRIVATE), // WARNING: tests use ES_PRIVATE + 0 EvCleanupTransaction, EvDelayedProposeTransaction, // WARNING: tests use ES_PRIVATE + 2 - EvProgressResendReadSet, - EvFlushOperationCounters, - EvDelayedFlushOperationCounters, - EvProgressOperationHistogramScan, + EvProgressResendReadSet, + EvFlushOperationCounters, + EvDelayedFlushOperationCounters, + EvProgressOperationHistogramScan, EvPeriodicWakeup, EvAsyncTableStats, EvRemoveOldInReadSets, // WARNING: tests use ES_PRIVATE + 9 @@ -297,27 +297,27 @@ class TDataShard EvRequestChangeRecords, EvRemoveChangeRecords, EvReplicationSourceOffsets, - EvEnd - }; - - static_assert(EvEnd < EventSpaceEnd(TKikimrEvents::ES_PRIVATE), "expect EvEnd < EventSpaceEnd(TKikimrEvents::ES_PRIVATE)"); - - struct TEvProgressTransaction : public TEventLocal<TEvProgressTransaction, EvProgressTransaction> {}; + EvEnd + }; + + static_assert(EvEnd < EventSpaceEnd(TKikimrEvents::ES_PRIVATE), "expect EvEnd < EventSpaceEnd(TKikimrEvents::ES_PRIVATE)"); + + struct TEvProgressTransaction : public TEventLocal<TEvProgressTransaction, EvProgressTransaction> {}; struct TEvCleanupTransaction : public TEventLocal<TEvCleanupTransaction, EvCleanupTransaction> {}; struct TEvDelayedProposeTransaction : public TEventLocal<TEvDelayedProposeTransaction, EvDelayedProposeTransaction> {}; - - struct TEvProgressResendReadSet : public TEventLocal<TEvProgressResendReadSet, EvProgressResendReadSet> { - TEvProgressResendReadSet(ui64 seqno) - : Seqno(seqno) - {} - - const ui64 Seqno; - }; - - struct TEvFlushOperationCounters : public TEventLocal<TEvFlushOperationCounters, EvFlushOperationCounters> {}; - struct TEvDelayedFlushOperationCounters : public TEventLocal<TEvDelayedFlushOperationCounters, EvDelayedFlushOperationCounters> {}; - - struct TEvProgressOperationHistogramScan : public TEventLocal<TEvProgressOperationHistogramScan, EvProgressOperationHistogramScan> {}; + + struct TEvProgressResendReadSet : public TEventLocal<TEvProgressResendReadSet, EvProgressResendReadSet> { + TEvProgressResendReadSet(ui64 seqno) + : Seqno(seqno) + {} + + const ui64 Seqno; + }; + + struct TEvFlushOperationCounters : public TEventLocal<TEvFlushOperationCounters, EvFlushOperationCounters> {}; + struct TEvDelayedFlushOperationCounters : public TEventLocal<TEvDelayedFlushOperationCounters, EvDelayedFlushOperationCounters> {}; + + struct TEvProgressOperationHistogramScan : public TEventLocal<TEvProgressOperationHistogramScan, EvProgressOperationHistogramScan> {}; struct TEvPeriodicWakeup : public TEventLocal<TEvPeriodicWakeup, EvPeriodicWakeup> {}; @@ -436,32 +436,32 @@ class TDataShard // Note that keys are NOT sorted in any way THashMap<TString, TVector<TSplitKey>> SourceOffsets; }; - }; - + }; + struct Schema : NIceDb::Schema { - struct Sys : Table<1> { + struct Sys : Table<1> { struct Id : Column<1, NScheme::NTypeIds::Uint64> {}; struct Bytes : Column<2, NScheme::NTypeIds::String> {}; struct Uint64 : Column<3, NScheme::NTypeIds::Uint64> {}; - + using TKey = TableKey<Id>; using TColumns = TableColumns<Id, Bytes, Uint64>; - }; - + }; + // Note that table UserTablesStats must be always updated with this one - struct UserTables : Table<2> { + struct UserTables : Table<2> { struct Tid : Column<1, NScheme::NTypeIds::Uint64> {}; struct LocalTid : Column<2, NScheme::NTypeIds::Uint32> {}; struct Path : Column<3, NScheme::NTypeIds::String> {}; struct Name : Column<4, NScheme::NTypeIds::String> {}; struct Schema : Column<5, NScheme::NTypeIds::String> { using Type = TString; }; struct ShadowTid : Column<6, NScheme::NTypeIds::Uint32> { static constexpr ui32 Default = 0; }; - + using TKey = TableKey<Tid>; using TColumns = TableColumns<Tid, LocalTid, Path, Name, Schema, ShadowTid>; - }; - - struct TxMain : Table<3> { + }; + + struct TxMain : Table<3> { struct TxId : Column<1, NScheme::NTypeIds::Uint64> {}; struct Kind : Column<2, NScheme::NTypeIds::Uint32> { using Type = EOperationKind; }; struct Flags : Column<3, NScheme::NTypeIds::Uint32> {}; @@ -472,35 +472,35 @@ class TDataShard struct Flags64 : Column<8, NScheme::NTypeIds::Uint64> {}; struct Source : Column<9, NScheme::NTypeIds::ActorId> {}; struct Cookie : Column<10, NScheme::NTypeIds::Uint64> {}; - + using TKey = TableKey<TxId>; using TColumns = TableColumns<TxId, Kind, Flags, State, InRSRemain, MaxStep, ReceivedAt, Flags64, Source, Cookie>; - }; - - struct TxDetails : Table<4> { + }; + + struct TxDetails : Table<4> { struct TxId : Column<1, NScheme::NTypeIds::Uint64> {}; struct Origin : Column<2, NScheme::NTypeIds::Uint64> {}; struct InReadSetState : Column<3, NScheme::NTypeIds::Uint64> {}; // Not used struct Body : Column<4, NScheme::NTypeIds::String> { using Type = TString; }; struct Source : Column<5, NScheme::NTypeIds::ActorId> {}; - + using TKey = TableKey<TxId, Origin>; using TColumns = TableColumns<TxId, Origin, InReadSetState, Body, Source>; - }; - - struct InReadSets : Table<5> { + }; + + struct InReadSets : Table<5> { struct TxId : Column<1, NScheme::NTypeIds::Uint64> {}; struct Origin : Column<2, NScheme::NTypeIds::Uint64> {}; struct From : Column<3, NScheme::NTypeIds::Uint64> {}; struct To : Column<4, NScheme::NTypeIds::Uint64> {}; struct Body : Column<5, NScheme::NTypeIds::String> { using Type = TString; }; struct BalanceTrackList : Column<6, NScheme::NTypeIds::String> { using Type = TString; }; - + using TKey = TableKey<TxId, Origin, From, To>; using TColumns = TableColumns<TxId, Origin, From, To, Body, BalanceTrackList>; - }; - - struct OutReadSets : Table<6> { + }; + + struct OutReadSets : Table<6> { struct Seqno : Column<1, NScheme::NTypeIds::Uint64> {}; struct Step : Column<2, NScheme::NTypeIds::Uint64> {}; struct TxId : Column<3, NScheme::NTypeIds::Uint64> {}; @@ -509,27 +509,27 @@ class TDataShard struct To : Column<6, NScheme::NTypeIds::Uint64> {}; struct Body : Column<7, NScheme::NTypeIds::String> { using Type = TString; }; struct SplitTraj : Column<8, NScheme::NTypeIds::String> { using Type = TString; }; - + using TKey = TableKey<Seqno>; using TColumns = TableColumns<Seqno, Step, TxId, Origin, From, To, Body, SplitTraj>; - }; - - struct PlanQueue : Table<7> { + }; + + struct PlanQueue : Table<7> { struct Step : Column<1, NScheme::NTypeIds::Uint64> {}; struct TxId : Column<2, NScheme::NTypeIds::Uint64> {}; - + using TKey = TableKey<Step, TxId>; using TColumns = TableColumns<Step, TxId>; - }; - - struct DeadlineQueue : Table<8> { + }; + + struct DeadlineQueue : Table<8> { struct MaxStep : Column<1, NScheme::NTypeIds::Uint64> {}; struct TxId : Column<2, NScheme::NTypeIds::Uint64> {}; - + using TKey = TableKey<MaxStep, TxId>; using TColumns = TableColumns<MaxStep, TxId>; - }; - + }; + struct SchemaOperations : Table<9> { struct TxId : Column<1, NScheme::NTypeIds::Uint64> {}; struct Operation : Column<2, NScheme::NTypeIds::Uint32> {}; @@ -539,7 +539,7 @@ class TDataShard struct MaxStep : Column<6, NScheme::NTypeIds::Uint64> {}; struct PlanStep : Column<7, NScheme::NTypeIds::Uint64> {}; struct ReadOnly : Column<8, NScheme::NTypeIds::Bool> {}; - + struct Success : Column<9, NScheme::NTypeIds::Bool> {}; struct Error : Column<10, NScheme::NTypeIds::String> { using Type = TString; }; struct DataSize : Column<11, NScheme::NTypeIds::Uint64> {}; // Bytes @@ -816,11 +816,11 @@ class TDataShard static_assert(ESysTableKeys::Sys_SubDomainOutOfSpace == 35, "Sys_SubDomainOutOfSpace changed its value"); static constexpr ui64 MinLocalTid = TSysTables::SysTableMAX + 1; // 1000 - + static constexpr const char* UserTablePrefix = "__user__"; static constexpr const char* ShadowTablePrefix = "__shadow__"; - }; - + }; + inline static bool SysGetUi64(NIceDb::TNiceDb& db, ui64 row, ui64& value) { auto rowset = db.Table<Schema::Sys>().Key(row).Select<Schema::Sys::Uint64>(); if (!rowset.IsReady()) @@ -880,30 +880,30 @@ class TDataShard } void Handle(TEvents::TEvGone::TPtr &ev); - void Handle(TEvents::TEvPoisonPill::TPtr &ev, const TActorContext &ctx); - void Handle(TEvDataShard::TEvGetShardState::TPtr &ev, const TActorContext &ctx); + void Handle(TEvents::TEvPoisonPill::TPtr &ev, const TActorContext &ctx); + void Handle(TEvDataShard::TEvGetShardState::TPtr &ev, const TActorContext &ctx); void Handle(TEvDataShard::TEvSchemaChangedResult::TPtr &ev, const TActorContext &ctx); void Handle(TEvDataShard::TEvStateChangedResult::TPtr &ev, const TActorContext &ctx); - void Handle(TEvDataShard::TEvProposeTransaction::TPtr &ev, const TActorContext &ctx); + void Handle(TEvDataShard::TEvProposeTransaction::TPtr &ev, const TActorContext &ctx); void Handle(TEvDataShard::TEvProposeTransactionAttach::TPtr &ev, const TActorContext &ctx); void HandleAsFollower(TEvDataShard::TEvProposeTransaction::TPtr &ev, const TActorContext &ctx); void ProposeTransaction(TEvDataShard::TEvProposeTransaction::TPtr &&ev, const TActorContext &ctx); - void Handle(TEvTxProcessing::TEvPlanStep::TPtr &ev, const TActorContext &ctx); - void Handle(TEvTxProcessing::TEvReadSet::TPtr &ev, const TActorContext &ctx); - void Handle(TEvTxProcessing::TEvReadSetAck::TPtr &ev, const TActorContext &ctx); - void Handle(TEvPrivate::TEvProgressTransaction::TPtr &ev, const TActorContext &ctx); + void Handle(TEvTxProcessing::TEvPlanStep::TPtr &ev, const TActorContext &ctx); + void Handle(TEvTxProcessing::TEvReadSet::TPtr &ev, const TActorContext &ctx); + void Handle(TEvTxProcessing::TEvReadSetAck::TPtr &ev, const TActorContext &ctx); + void Handle(TEvPrivate::TEvProgressTransaction::TPtr &ev, const TActorContext &ctx); void Handle(TEvPrivate::TEvCleanupTransaction::TPtr &ev, const TActorContext &ctx); void Handle(TEvPrivate::TEvDelayedProposeTransaction::TPtr &ev, const TActorContext &ctx); - void Handle(TEvPrivate::TEvProgressResendReadSet::TPtr &ev, const TActorContext &ctx); + void Handle(TEvPrivate::TEvProgressResendReadSet::TPtr &ev, const TActorContext &ctx); void Handle(TEvPrivate::TEvRemoveOldInReadSets::TPtr &ev, const TActorContext &ctx); void Handle(TEvPrivate::TEvRegisterScanActor::TPtr &ev, const TActorContext &ctx); void Handle(TEvPrivate::TEvScanStats::TPtr &ev, const TActorContext &ctx); void Handle(TEvPrivate::TEvPersistScanState::TPtr &ev, const TActorContext &ctx); - void Handle(TEvTabletPipe::TEvClientConnected::TPtr &ev, const TActorContext &ctx); - void Handle(TEvTabletPipe::TEvClientDestroyed::TPtr &ev, const TActorContext &ctx); - void Handle(TEvTabletPipe::TEvServerConnected::TPtr &ev, const TActorContext &ctx); - void Handle(TEvTabletPipe::TEvServerDisconnected::TPtr &ev, const TActorContext &ctx); - void Handle(TEvMediatorTimecast::TEvRegisterTabletResult::TPtr& ev, const TActorContext& ctx); + void Handle(TEvTabletPipe::TEvClientConnected::TPtr &ev, const TActorContext &ctx); + void Handle(TEvTabletPipe::TEvClientDestroyed::TPtr &ev, const TActorContext &ctx); + void Handle(TEvTabletPipe::TEvServerConnected::TPtr &ev, const TActorContext &ctx); + void Handle(TEvTabletPipe::TEvServerDisconnected::TPtr &ev, const TActorContext &ctx); + void Handle(TEvMediatorTimecast::TEvRegisterTabletResult::TPtr& ev, const TActorContext& ctx); void Handle(TEvMediatorTimecast::TEvNotifyPlanStep::TPtr& ev, const TActorContext& ctx); void Handle(TEvDataShard::TEvCancelTransactionProposal::TPtr &ev, const TActorContext &ctx); void Handle(TEvDataShard::TEvReturnBorrowedPart::TPtr& ev, const TActorContext& ctx); @@ -947,7 +947,7 @@ class TDataShard void Handle(TEvDataShard::TEvUnsafeUploadRowsRequest::TPtr& ev, const TActorContext& ctx); void Handle(TEvDataShard::TEvBuildIndexCreateRequest::TPtr& ev, const TActorContext& ctx); void Handle(TEvPrivate::TEvAsyncJobComplete::TPtr& ev, const TActorContext& ctx); - + void Handle(TEvDataShard::TEvCancelBackup::TPtr &ev, const TActorContext &ctx); void Handle(TEvDataShard::TEvCancelRestore::TPtr &ev, const TActorContext &ctx); @@ -1010,27 +1010,27 @@ class TDataShard void UpdateLagCounters(const TActorContext &ctx); static NTabletPipe::TClientConfig GetPipeClientConfig(); - void OnDetach(const TActorContext &ctx) override; + void OnDetach(const TActorContext &ctx) override; void OnTabletStop(TEvTablet::TEvTabletStop::TPtr &ev, const TActorContext &ctx) override; void OnStopGuardStarting(const TActorContext &ctx); void OnStopGuardComplete(const TActorContext &ctx); - void OnTabletDead(TEvTablet::TEvTabletDead::TPtr &ev, const TActorContext &ctx) override; - void OnActivateExecutor(const TActorContext &ctx) override; + void OnTabletDead(TEvTablet::TEvTabletDead::TPtr &ev, const TActorContext &ctx) override; + void OnActivateExecutor(const TActorContext &ctx) override; void Cleanup(const TActorContext &ctx); - void SwitchToWork(const TActorContext &ctx); - void SyncConfig(); - - TMaybe<TInstant> GetTxPlanStartTimeAndCleanup(ui64 step); - - void RestartPipeRS(ui64 tabletId, const TActorContext& ctx); + void SwitchToWork(const TActorContext &ctx); + void SyncConfig(); + + TMaybe<TInstant> GetTxPlanStartTimeAndCleanup(ui64 step); + + void RestartPipeRS(ui64 tabletId, const TActorContext& ctx); void AckRSToDeletedTablet(ui64 tabletId, const TActorContext& ctx); - - void DefaultSignalTabletActive(const TActorContext &ctx) override { + + void DefaultSignalTabletActive(const TActorContext &ctx) override { // This overriden in order to pospone SignalTabletActive until TxInit completes Y_UNUSED(ctx); - } - + } + void PersistSys(NIceDb::TNiceDb& db, ui64 key, const TString& value) const; void PersistSys(NIceDb::TNiceDb& db, ui64 key, ui64 value) const; void PersistSys(NIceDb::TNiceDb& db, ui64 key, ui32 value) const; @@ -1057,13 +1057,13 @@ class TDataShard TReadWriteVersions GetLocalReadWriteVersions() const; -public: +public: static constexpr NKikimrServices::TActivity::EType ActorActivityType() { return NKikimrServices::TActivity::TX_DATASHARD_ACTOR; } TDataShard(const TActorId &tablet, TTabletStorageInfo *info); - + void PrepareAndSaveOutReadSets(ui64 step, ui64 txId, @@ -1083,8 +1083,8 @@ public: const TActorId &target, ui64 step, ui64 txId); - void FillSplitTrajectory(ui64 origin, NKikimrTx::TBalanceTrackList& tracks); - + void FillSplitTrajectory(ui64 origin, NKikimrTx::TBalanceTrackList& tracks); + void SetCounter(NDataShard::ESimpleCounters counter, ui64 num) const { TabletCounters->Simple()[counter].Set(num); } @@ -1443,7 +1443,7 @@ public: bool CheckChangesQueueOverflow() const; -private: +private: /// class TLoanReturnTracker { struct TLoanReturnInfo { @@ -1937,16 +1937,16 @@ private: }; THashSet<ui64> SysTablesPartOnwers; - // Sys table contents + // Sys table contents ui32 State; - ui32 LastLocalTid; - ui64 LastSeqno; + ui32 LastLocalTid; + ui64 LastSeqno; ui64 NextChangeRecordOrder; ui64 LastChangeRecordGroup; ui64 TxReadSizeLimit; ui64 StatisticsDisabled; bool Stopping = false; - + NMiniKQL::IKeyAccessSampler::TPtr DisabledKeySampler; NMiniKQL::IKeyAccessSampler::TPtr EnabledKeySampler; NMiniKQL::IKeyAccessSampler::TPtr CurrentKeySampler; // Points to enbaled or disabled @@ -1969,9 +1969,9 @@ private: TS3UploadsManager S3Uploads; TS3DownloadsManager S3Downloads; - TIntrusivePtr<TMediatorTimecastEntry> MediatorTimeCastEntry; + TIntrusivePtr<TMediatorTimecastEntry> MediatorTimeCastEntry; TSet<ui64> MediatorTimeCastWaitingSteps; - + TControlWrapper DisableByKeyFilter; TControlWrapper MaxTxInFly; TControlWrapper MaxTxLagMilliseconds; @@ -2095,41 +2095,41 @@ private: TReadIteratorsMap ReadIterators; -protected: - // Redundant init state required by flat executor implementation - void StateInit(TAutoPtr<NActors::IEventHandle> &ev, const NActors::TActorContext &ctx) { +protected: + // Redundant init state required by flat executor implementation + void StateInit(TAutoPtr<NActors::IEventHandle> &ev, const NActors::TActorContext &ctx) { TRACE_EVENT(NKikimrServices::TX_DATASHARD); switch (ev->GetTypeRewrite()) { HFuncTraced(TEvents::TEvPoisonPill, Handle); default: StateInitImpl(ev, ctx); } - } - + } + void Enqueue(STFUNC_SIG) override { LOG_WARN_S(ctx, NKikimrServices::TX_DATASHARD, "TDataShard::StateInit unhandled event type: " << ev->GetTypeRewrite() << " event: " << (ev->HasEvent() ? ev->GetBase()->ToString().data() : "serialized?")); } - // In this state we are not handling external pipes to datashard tablet (it's just another init phase) - void StateInactive(TAutoPtr<NActors::IEventHandle> &ev, const NActors::TActorContext &ctx) { + // In this state we are not handling external pipes to datashard tablet (it's just another init phase) + void StateInactive(TAutoPtr<NActors::IEventHandle> &ev, const NActors::TActorContext &ctx) { TRACE_EVENT(NKikimrServices::TX_DATASHARD); - switch (ev->GetTypeRewrite()) { + switch (ev->GetTypeRewrite()) { HFuncTraced(TEvMediatorTimecast::TEvRegisterTabletResult, Handle); HFuncTraced(TEvents::TEvPoisonPill, Handle); - default: + default: if (!HandleDefaultEvents(ev, ctx)) { LOG_WARN_S(ctx, NKikimrServices::TX_DATASHARD, "TDataShard::StateInactive unhandled event type: " << ev->GetTypeRewrite() << " event: " << (ev->HasEvent() ? ev->GetBase()->ToString().data() : "serialized?")); } - break; - } - } - - // This is the main state - void StateWork(TAutoPtr<NActors::IEventHandle> &ev, const NActors::TActorContext &ctx) { + break; + } + } + + // This is the main state + void StateWork(TAutoPtr<NActors::IEventHandle> &ev, const NActors::TActorContext &ctx) { TRACE_EVENT(NKikimrServices::TX_DATASHARD); - switch (ev->GetTypeRewrite()) { + switch (ev->GetTypeRewrite()) { hFunc(TEvents::TEvGone, Handle); HFuncTraced(TEvents::TEvPoisonPill, Handle); HFuncTraced(TEvDataShard::TEvGetShardState, Handle); @@ -2227,16 +2227,16 @@ protected: fFunc(TEvDataShard::EvGetReplicationSourceOffsets, HandleByReplicationSourceOffsetsServer); fFunc(TEvDataShard::EvReplicationSourceOffsetsAck, HandleByReplicationSourceOffsetsServer); fFunc(TEvDataShard::EvReplicationSourceOffsetsCancel, HandleByReplicationSourceOffsetsServer); - default: + default: if (!HandleDefaultEvents(ev, ctx)) { LOG_WARN_S(ctx, NKikimrServices::TX_DATASHARD, "TDataShard::StateWork unhandled event type: "<< ev->GetTypeRewrite() << " event: " << (ev->HasEvent() ? ev->GetBase()->ToString().data() : "serialized?")); } - break; - } - } - + break; + } + } + // This is the main state void StateWorkAsFollower(TAutoPtr<NActors::IEventHandle> &ev, const NActors::TActorContext &ctx) { TRACE_EVENT(NKikimrServices::TX_DATASHARD); @@ -2257,20 +2257,20 @@ protected: } } - // State after tablet takes poison pill - void StateBroken(TAutoPtr<NActors::IEventHandle> &ev, const NActors::TActorContext &ctx) { + // State after tablet takes poison pill + void StateBroken(TAutoPtr<NActors::IEventHandle> &ev, const NActors::TActorContext &ctx) { TRACE_EVENT(NKikimrServices::TX_DATASHARD); - switch (ev->GetTypeRewrite()) { + switch (ev->GetTypeRewrite()) { hFunc(TEvents::TEvGone, Handle); HFuncTraced(TEvTablet::TEvTabletDead, HandleTabletDead); - default: + default: LOG_WARN_S(ctx, NKikimrServices::TX_DATASHARD, "TDataShard::BrokenState at tablet " << TabletID() << " unhandled event type: " << ev->GetTypeRewrite() << " event: " << (ev->HasEvent() ? ev->GetBase()->ToString().data() : "serialized?")); ctx.Send(ev->ForwardOnNondelivery(TEvents::TEvUndelivered::ReasonActorUnknown)); - break; - } - } + break; + } + } void Die(const TActorContext &ctx) override { NTabletPipe::CloseAndForgetClient(SelfId(), SchemeShardPipe); @@ -2421,8 +2421,8 @@ protected: bool AllowCancelROwithReadsets() const; void ResolveTablePath(const TActorContext &ctx); -}; - +}; + NKikimrTxDataShard::TError::EKind ConvertErrCode(NMiniKQL::IEngineFlat::EResult code); Ydb::StatusIds::StatusCode ConvertToYdbStatusCode(NKikimrTxDataShard::TError::EKind); @@ -2439,4 +2439,4 @@ void SetStatusError(T &rec, issue->set_message(msg); } -}} +}} diff --git a/ydb/core/tx/datashard/datashard_txs.h b/ydb/core/tx/datashard/datashard_txs.h index 4a9ab00878..eefa6eb064 100644 --- a/ydb/core/tx/datashard/datashard_txs.h +++ b/ydb/core/tx/datashard/datashard_txs.h @@ -1,12 +1,12 @@ -#pragma once - +#pragma once + #include "datashard_common_upload.h" #include "datashard_impl.h" #include "execution_unit_kind.h" - -namespace NKikimr { + +namespace NKikimr { namespace NDataShard { - + using NTabletFlatExecutor::TTransactionContext; class TDataShard::TTxStopGuard : public NTabletFlatExecutor::TTransactionBase<TDataShard> { @@ -27,75 +27,75 @@ public: }; class TDataShard::TTxGetShardState : public NTabletFlatExecutor::TTransactionBase<TDataShard> { -public: +public: TTxGetShardState(TDataShard* ds, TEvDataShard::TEvGetShardState::TPtr ev); - bool Execute(TTransactionContext& txc, const TActorContext& ctx) override; - void Complete(const TActorContext &ctx) override; + bool Execute(TTransactionContext& txc, const TActorContext& ctx) override; + void Complete(const TActorContext &ctx) override; TTxType GetTxType() const override { return TXTYPE_GET_STARD_STATE; } -private: - TEvDataShard::TEvGetShardState::TPtr Ev; +private: + TEvDataShard::TEvGetShardState::TPtr Ev; THolder<TEvDataShard::TEvGetShardStateResult> Result; -}; - +}; + class TDataShard::TTxInit : public NTabletFlatExecutor::TTransactionBase<TDataShard> { -public: +public: TTxInit(TDataShard* ds); - bool Execute(TTransactionContext& txc, const TActorContext& ctx) override; - void Complete(const TActorContext &ctx) override; + bool Execute(TTransactionContext& txc, const TActorContext& ctx) override; + void Complete(const TActorContext &ctx) override; TTxType GetTxType() const override { return TXTYPE_INIT; } -private: - bool CreateScheme(TTransactionContext &txc); - bool ReadEverything(TTransactionContext &txc); +private: + bool CreateScheme(TTransactionContext &txc); + bool ReadEverything(TTransactionContext &txc); private: TVector<TEvChangeExchange::TEvEnqueueRecords::TRecordInfo> ChangeRecords; -}; - +}; + class TDataShard::TTxPlanStep : public NTabletFlatExecutor::TTransactionBase<TDataShard> { -public: +public: TTxPlanStep(TDataShard *self, TEvTxProcessing::TEvPlanStep::TPtr ev); - bool Execute(TTransactionContext &txc, const TActorContext &ctx) override; - void Complete(const TActorContext &ctx) override; + bool Execute(TTransactionContext &txc, const TActorContext &ctx) override; + void Complete(const TActorContext &ctx) override; TTxType GetTxType() const override { return TXTYPE_PLAN_STEP; } - -private: - TEvTxProcessing::TEvPlanStep::TPtr Ev; - bool IsAccepted; - TInstant RequestStartTime; + +private: + TEvTxProcessing::TEvPlanStep::TPtr Ev; + bool IsAccepted; + TInstant RequestStartTime; TMap<TActorId, TVector<ui64>> TxByAck; -}; - +}; + class TDataShard::TTxProgressTransaction : public NTabletFlatExecutor::TTransactionBase<TDataShard> { -public: +public: explicit TTxProgressTransaction(TDataShard *self, TOperation::TPtr op = nullptr); - bool Execute(TTransactionContext &txc, const TActorContext &ctx) override; - void Complete(const TActorContext &ctx) override; + bool Execute(TTransactionContext &txc, const TActorContext &ctx) override; + void Complete(const TActorContext &ctx) override; TTxType GetTxType() const override { return TXTYPE_PROGRESS_START; } - -private: + +private: TOperation::TPtr ActiveOp; TVector<EExecutionUnitKind> CompleteList; TInstant CommitStart; bool Rescheduled = false; -}; - +}; + class TDataShard::TTxProposeTransactionBase : public NTabletFlatExecutor::TTransactionBase<TDataShard> { public: TTxProposeTransactionBase(TDataShard *self, TEvDataShard::TEvProposeTransaction::TPtr &&ev, TInstant receivedAt, ui64 tieBreakerIndex, bool delayed); - + bool Execute(NTabletFlatExecutor::TTransactionContext &txc, const TActorContext &ctx) override; - void Complete(const TActorContext &ctx) override; + void Complete(const TActorContext &ctx) override; TTxType GetTxType() const override { return TXTYPE_PROPOSE; } - -private: + +private: bool SyncSchemeOnFollower(TOutputOpData::TResultPtr &result, TTransactionContext &txc, const TActorContext &ctx); - -protected: + +protected: TOperation::TPtr Op; TEvDataShard::TEvProposeTransaction::TPtr Ev; const TInstant ReceivedAt; @@ -106,32 +106,32 @@ protected: TInstant CommitStart; bool Acked; bool Rescheduled = false; -}; - +}; + class TDataShard::TTxReadSet : public NTabletFlatExecutor::TTransactionBase<TDataShard> { -public: +public: TTxReadSet(TDataShard *self, TEvTxProcessing::TEvReadSet::TPtr ev); - bool Execute(TTransactionContext &txc, const TActorContext &ctx) override; - void Complete(const TActorContext &ctx) override; + bool Execute(TTransactionContext &txc, const TActorContext &ctx) override; + void Complete(const TActorContext &ctx) override; TTxType GetTxType() const override { return TXTYPE_READSET; } - -private: + +private: TEvTxProcessing::TEvReadSet::TPtr Ev; THolder<IEventHandle> Ack; THolder<IEventHandle> MakeAck(const TActorContext &ctx); -}; - +}; + class TDataShard::TTxProgressResendRS : public NTabletFlatExecutor::TTransactionBase<TDataShard> { -public: +public: TTxProgressResendRS(TDataShard *self, ui64 seqno); - bool Execute(TTransactionContext &txc, const TActorContext &ctx) override; - void Complete(const TActorContext &ctx) override; + bool Execute(TTransactionContext &txc, const TActorContext &ctx) override; + void Complete(const TActorContext &ctx) override; TTxType GetTxType() const override { return TXTYPE_PROGRESS_RESEND_RS; } -private: - const ui64 Seqno; -}; - +private: + const ui64 Seqno; +}; + class TDataShard::TTxCancelTransactionProposal : public NTabletFlatExecutor::TTransactionBase<TDataShard> { public: TTxCancelTransactionProposal(TDataShard *self, ui64 txId); @@ -294,4 +294,4 @@ private: bool ActivateWaitingOps = false; }; -}} +}} diff --git a/ydb/core/tx/datashard/datashard_user_table.cpp b/ydb/core/tx/datashard/datashard_user_table.cpp index 70bc940073..3061290bbe 100644 --- a/ydb/core/tx/datashard/datashard_user_table.cpp +++ b/ydb/core/tx/datashard/datashard_user_table.cpp @@ -1,16 +1,16 @@ #include "datashard_user_table.h" - + #include <ydb/core/base/path.h> #include <ydb/core/tablet_flat/flat_cxx_database.h> #include <ydb/core/tablet_flat/tablet_flat_executed.h> #include <ydb/core/tablet_flat/tablet_flat_executor.h> -namespace NKikimr { +namespace NKikimr { using NTabletFlatExecutor::TTransactionContext; namespace NDataShard { - + TUserTable::TUserTable(ui32 localTid, const NKikimrSchemeOp::TTableDescription& descr, ui32 shadowTid) : LocalTid(localTid) , ShadowTid(shadowTid) @@ -596,4 +596,4 @@ void TUserTable::ApplyDefaults(TTransactionContext& txc) const } } -}} +}} diff --git a/ydb/core/tx/datashard/datashard_user_table.h b/ydb/core/tx/datashard/datashard_user_table.h index 0dab30cb84..19dd4bf865 100644 --- a/ydb/core/tx/datashard/datashard_user_table.h +++ b/ydb/core/tx/datashard/datashard_user_table.h @@ -1,22 +1,22 @@ -#pragma once - +#pragma once + #include "datashard.h" - + #include <ydb/core/base/storage_pools.h> #include <ydb/core/scheme/scheme_tabledefs.h> #include <ydb/core/tablet_flat/flat_stat_table.h> - + #include <util/generic/ptr.h> #include <util/generic/hash.h> -namespace NKikimr { +namespace NKikimr { namespace NTabletFlatExecutor { class TTransactionContext; } namespace NDataShard { - + // struct TUserTable : public TThrRefBase { using TPtr = TIntrusivePtr<TUserTable>; @@ -357,7 +357,7 @@ struct TUserTable : public TThrRefBase { TMap<TPathId, TTableIndex> Indexes; TMap<TPathId, TCdcStream> CdcStreams; ui32 AsyncIndexCount = 0; - + // Tablet thread access only, updated in-place mutable TStats Stats; mutable bool StatsUpdateInProgress = false; @@ -368,7 +368,7 @@ struct TUserTable : public TThrRefBase { ui32 SpecialColUpdateNo = Max<ui32>(); TUserTable() { } - + TUserTable(ui32 localTid, const NKikimrSchemeOp::TTableDescription& descr, ui32 shadowTid); // for create TUserTable(const TUserTable& table, const NKikimrSchemeOp::TTableDescription& descr); // for alter @@ -419,6 +419,6 @@ private: void CheckSpecialColumns(); void AlterSchema(); void ParseProto(const NKikimrSchemeOp::TTableDescription& descr); -}; - -}} +}; + +}} diff --git a/ydb/core/tx/datashard/datashard_ut_common.cpp b/ydb/core/tx/datashard/datashard_ut_common.cpp index d754f7ad0e..fe581002b1 100644 --- a/ydb/core/tx/datashard/datashard_ut_common.cpp +++ b/ydb/core/tx/datashard/datashard_ut_common.cpp @@ -16,24 +16,24 @@ #include <library/cpp/testing/unittest/registar.h> #include <google/protobuf/text_format.h> - + #include <util/system/valgrind.h> -namespace NKikimr { - -using namespace NMiniKQL; +namespace NKikimr { + +using namespace NMiniKQL; using namespace NSchemeShard; using namespace Tests; - + const bool ENABLE_DATASHARD_LOG = true; const bool DUMP_RESULT = false; - + void TTester::Setup(TTestActorRuntime& runtime, const TOptions& opts) { - if (ENABLE_DATASHARD_LOG) { + if (ENABLE_DATASHARD_LOG) { runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NActors::NLog::PRI_TRACE); - } - runtime.SetLogPriority(NKikimrServices::MINIKQL_ENGINE, NActors::NLog::PRI_DEBUG); - + } + runtime.SetLogPriority(NKikimrServices::MINIKQL_ENGINE, NActors::NLog::PRI_DEBUG); + ui32 domainId = 0; ui32 planResolution = 500; @@ -56,46 +56,46 @@ void TTester::Setup(TTestActorRuntime& runtime, const TOptions& opts) { app.AddDomain(domain.Release()); SetupTabletServices(runtime, &app); -} - +} + TTester::TTester(ESchema schema, const TOptions& opts) : Schema(schema) , LastTxId(0) , LastStep(opts.FirstStep) -{ +{ Setup(Runtime, opts); - Sender = Runtime.AllocateEdgeActor(); + Sender = Runtime.AllocateEdgeActor(); // Schemeshard is only used to receive notifications CreateTestBootstrapper(Runtime, CreateTestTabletInfo(FAKE_SCHEMESHARD_TABLET_ID, TTabletTypes::FLAT_SCHEMESHARD), &CreateFlatTxSchemeShard); CreateTestBootstrapper(Runtime, CreateTestTabletInfo(FAKE_TX_ALLOCATOR_TABLET_ID, TTabletTypes::TX_ALLOCATOR), &CreateTxAllocator); CreateSchema(schema, opts); -} - +} + TTester::TTester(ESchema schema, const TString& dispatchName, std::function<void (TTestActorRuntime&)> setup, bool& activeZone, const TOptions& opts) : Schema(schema) , LastTxId(0) , LastStep(1) -{ +{ Setup(Runtime, opts); - setup(Runtime); - Sender = Runtime.AllocateEdgeActor(); - AllowIncompleteResult = (dispatchName != INITIAL_TEST_DISPATCH_NAME); - ActiveZone = &activeZone; - DispatchName = dispatchName; + setup(Runtime); + Sender = Runtime.AllocateEdgeActor(); + AllowIncompleteResult = (dispatchName != INITIAL_TEST_DISPATCH_NAME); + ActiveZone = &activeZone; + DispatchName = dispatchName; // Schemeshard is only used to receive notifications CreateTestBootstrapper(Runtime, CreateTestTabletInfo(FAKE_SCHEMESHARD_TABLET_ID, TTabletTypes::FLAT_SCHEMESHARD), &CreateFlatTxSchemeShard); CreateTestBootstrapper(Runtime, CreateTestTabletInfo(FAKE_TX_ALLOCATOR_TABLET_ID, TTabletTypes::TX_ALLOCATOR), &CreateTxAllocator); CreateSchema(schema, opts); -} - +} + void TTester::EmptyShardKeyResolver(TKeyDesc& key) { Y_UNUSED(key); Y_FAIL(); -} - +} + void TTester::SingleShardKeyResolver(TKeyDesc& key) { key.Status = TKeyDesc::EStatus::Ok; key.Partitions.push_back(TKeyDesc::TPartitionInfo((ui64)TTestTxConfig::TxTablet0)); @@ -151,17 +151,17 @@ void TTester::CreateDataShard(TFakeMiniKQLProxy& proxy, ui64 tabletId, const TSt TActorId actorId = CreateTestBootstrapper(Runtime, CreateTestTabletInfo(tabletId, TTabletTypes::FLAT_DATASHARD), &::NKikimr::CreateDataShard); Y_UNUSED(actorId); - - TDispatchOptions options; - options.FinalEvents.push_back(TDispatchOptions::TFinalEventCondition(TEvTablet::EvBoot)); - Runtime.DispatchEvents(options); - + + TDispatchOptions options; + options.FinalEvents.push_back(TDispatchOptions::TFinalEventCondition(TEvTablet::EvBoot)); + Runtime.DispatchEvents(options); + UNIT_ASSERT_EQUAL(proxy.ExecSchemeCreateTable(schemeText, {tabletId}), IEngineFlat::EStatus::Complete); - + RebootTablet(Runtime, tabletId, Sender); - - //Runtime.EnableScheduleForActor(actorId, true); - + + //Runtime.EnableScheduleForActor(actorId, true); + if (withRegister) { RegisterTableInResolver(schemeText); } @@ -190,36 +190,36 @@ void TTester::RegisterTableInResolver(const TString& schemeText) for (size_t ki = 0; ki < tdesc.KeyColumnIdsSize(); ki++) { if (tdesc.GetKeyColumnIds(ki) == c.GetId()) { keyIdx = ki; - } - } + } + } table.Columns.insert(std::make_pair(c.GetName(), TColumn{c.GetId(), keyIdx, c.GetTypeId(), 0})); - } + } DbSchemeResolver.AddTable(table); -} - +} + void TTester::CreateSchema(ESchema schema, const TOptions& opts) { TString keyValueSchemeText = - "Name: \"table1\"\n" + "Name: \"table1\"\n" "Id_Deprecated: 13\n" "Path: \"/Root/table1\"\n" "Columns { Id: 34 Name: \"key\" TypeId: " + ToString<int>(NScheme::NTypeIds::Uint32) + " }\n" "Columns { Id: 56 Name: \"value\" TypeId: " + ToString<int>(NScheme::NTypeIds::Utf8) + " }\n" "Columns { Id: 57 Name: \"uint\" TypeId: " + ToString<int>(NScheme::NTypeIds::Uint32) + " }\n" - "KeyColumnIds: [ 34 ]\n" - ; - + "KeyColumnIds: [ 34 ]\n" + ; + TString doubleKeyValueSchemeText = - "Name: \"table2\"\n" + "Name: \"table2\"\n" "PathId { OwnerId: " + ToString(FAKE_SCHEMESHARD_TABLET_ID) + " LocalId: 14 }\n" "Path: \"/Root/table2\"\n" "Columns { Id: 34 Name: \"key1\" TypeId: " + ToString<int>(NScheme::NTypeIds::Uint32) + " }\n" "Columns { Id: 35 Name: \"key2\" TypeId: " + ToString<int>(NScheme::NTypeIds::Utf8) + " }\n" "Columns { Id: 56 Name: \"value\" TypeId: " + ToString<int>(NScheme::NTypeIds::Utf8) + " }\n" - "KeyColumnIds: [ 34, 35 ]\n" - ; - + "KeyColumnIds: [ 34, 35 ]\n" + ; + TString doubleKeyValueExternalSchemeText = "Name: \"table2\"\n" "PathId { OwnerId: " + ToString(FAKE_SCHEMESHARD_TABLET_ID) + " LocalId: 14 }\n" @@ -271,10 +271,10 @@ void TTester::CreateSchema(ESchema schema, const TOptions& opts) { CreateDataShard(proxy, TTestTxConfig::TxTablet2, keyValueSchemeText); break; } -} - +} + // - + TRuntimeNode TEngineHolder::ProgramText2Bin(TTester& tester, const TString& programText) { auto expr = NYql::ParseText(programText); @@ -344,7 +344,7 @@ ui32 TFakeProxyTx::SetProgram(TTester& tester, const TString& programText) { UNIT_ASSERT_VALUES_EQUAL(ShardsCount_, resolvedShards.size()); return ShardsCount_; } - + ui32 TFakeProxyTx::GetShardProgram(ui32 idx, TString& outTxBody) { IEngineFlat::TShardData shardData; auto result = Engine->GetAffectedShard(idx, shardData); @@ -525,12 +525,12 @@ IEngineFlat::EStatus TFakeMiniKQLProxy::Execute(const TString& programText, ui64 stepId = ++LastStep_; Plan(stepId, txs, waitForResult); status = tx.GetStatus(false); - } + } if (waitForResult) out = tx.GetResult(); - return status; -} - + return status; +} + IEngineFlat::EStatus TFakeMiniKQLProxy::ExecSchemeCreateTable(const TString& tableDesc, const TVector<ui64>& shards) { ui64 txId = ++LastTxId_; ui64 stepId = ++LastStep_; @@ -546,19 +546,19 @@ IEngineFlat::EStatus TFakeMiniKQLProxy::ExecSchemeCreateTable(const TString& tab UNIT_ASSERT(tx.MaxStep == Max<ui64>()); LastStep_ = Plan(stepId, txs); return IEngineFlat::EStatus::Complete; -} - +} + #if 0 -void TFakeMiniKQLProxy::Cancel(ui64 txId) { +void TFakeMiniKQLProxy::Cancel(ui64 txId) { for (auto shard : proxyTx.Shards) { - auto cancel = new TEvDataShard::TEvCancelTransactionProposal(txId); - Tester.Runtime.SendToPipe(shard, Tester.Sender, cancel); - } - - Tester.Runtime.DispatchEvents(); -} + auto cancel = new TEvDataShard::TEvCancelTransactionProposal(txId); + Tester.Runtime.SendToPipe(shard, Tester.Sender, cancel); + } + + Tester.Runtime.DispatchEvents(); +} #endif - + void TFakeMiniKQLProxy::ProposeSchemeCreateTable(TFakeProxyTx& tx, const TVector<ui64>& shards) { const TString& schemaText = tx.TxBody(); NKikimrSchemeOp::TTableDescription tableDesc; @@ -582,70 +582,70 @@ void TFakeMiniKQLProxy::ProposeScheme(TFakeProxyTx& tx, const TVector<ui64>& sha NKikimrTxDataShard::ETransactionKind kind = NKikimrTxDataShard::TX_KIND_SCHEME; ui64 txId = tx.TxId(); - bool hasErrors = false; + bool hasErrors = false; for (ui32 i = 0; i < shards.size(); ++i) { - ui64 shardId = shards[i]; + ui64 shardId = shards[i]; auto txBody = txBodyForShard(shards[i]).SerializeAsString(); ui32 txFlags = NDataShard::TTxFlags::Default; - - for (;;) { + + for (;;) { auto proposal = new TEvDataShard::TEvProposeTransaction(kind, FAKE_SCHEMESHARD_TABLET_ID, Tester.Sender, txId, txBody, NKikimrSubDomains::TProcessingParams(), txFlags); - Tester.Runtime.SendToPipe(shardId, Tester.Sender, proposal); - TAutoPtr<IEventHandle> handle; - auto event = Tester.Runtime.GrabEdgeEventIf<TEvDataShard::TEvProposeTransactionResult>(handle, - [=](const TEvDataShard::TEvProposeTransactionResult& event) { - return event.GetTxId() == txId && event.GetOrigin() == shardId; - }); - - UNIT_ASSERT(event); + Tester.Runtime.SendToPipe(shardId, Tester.Sender, proposal); + TAutoPtr<IEventHandle> handle; + auto event = Tester.Runtime.GrabEdgeEventIf<TEvDataShard::TEvProposeTransactionResult>(handle, + [=](const TEvDataShard::TEvProposeTransactionResult& event) { + return event.GetTxId() == txId && event.GetOrigin() == shardId; + }); + + UNIT_ASSERT(event); UNIT_ASSERT_EQUAL(event->GetTxKind(), kind); if (event->IsTryLater()) - continue; - + continue; + if (event->IsError()) { - hasErrors = true; - for (auto err : event->Record.GetError()) { - Cerr << "DataShard error: " << shardId << ", kind: " << - NKikimrTxDataShard::TError::EKind_Name(err.GetKind()) << ", reason: " << err.GetReason() << Endl; - } - - break; - } - + hasErrors = true; + for (auto err : event->Record.GetError()) { + Cerr << "DataShard error: " << shardId << ", kind: " << + NKikimrTxDataShard::TError::EKind_Name(err.GetKind()) << ", reason: " << err.GetReason() << Endl; + } + + break; + } + if (event->IsComplete()) - break; - + break; + UNIT_ASSERT(event->IsPrepared()); tx.Shards.push_back(shardId); tx.MinStep = Max(tx.MinStep, event->Record.GetMinStep()); tx.MaxStep = Min(tx.MaxStep, event->Record.GetMaxStep()); - break; - } - } - + break; + } + } + UNIT_ASSERT(!hasErrors); UNIT_ASSERT(!tx.Shards.empty()); -} - +} + void TFakeMiniKQLProxy::Propose(TFakeProxyTx& tx, bool holdImmediate) { ui64 txId = tx.TxId(); - + ui32 shardsCount = tx.SetProgram(Tester); if (holdImmediate && tx.Immediate()) return; - + TSet<ui64> shards; - for (ui32 i = 0; i < shardsCount; ++i) { + for (ui32 i = 0; i < shardsCount; ++i) { TString txBody; ui32 shard = tx.GetShardProgram(i, txBody); shards.insert(shard); - + auto proposal = new TEvDataShard::TEvProposeTransaction( tx.TxKind(), Tester.Sender, txId, txBody, tx.TxFlags()); Tester.Runtime.SendToPipe(shard, Tester.Sender, proposal); } - + ResolveShards(shards); while (shards) { @@ -657,14 +657,14 @@ void TFakeMiniKQLProxy::Propose(TFakeProxyTx& tx, bool holdImmediate) { UNIT_ASSERT(!event->IsTryLater()); // need resend otherwise UNIT_ASSERT_EQUAL(event->GetTxKind(), tx.TxKind()); - + ui64 shard = event->GetOrigin(); tx.AddProposeShardResult(shard, event); shards.erase(shard); - } -} - + } +} + void TFakeMiniKQLProxy::ResolveShards(const TSet<ui64>& shards) { for (ui64 shard : shards) { auto event = new TEvDataShard::TEvGetShardState(Tester.Sender); @@ -692,7 +692,7 @@ ui64 TFakeMiniKQLProxy::Plan(ui64 stepId, const TMap<ui64, TFakeProxyTx::TPtr>& using TEvStreamQuotaRequest = TEvTxProcessing::TEvStreamQuotaRequest; using TEvStreamQuotaResponse = TEvTxProcessing::TEvStreamQuotaResponse; using TEvStreamDataAck = TEvTxProcessing::TEvStreamDataAck; - + TSet<ui64> immediateTxs; THashMap<ui64, TVector<ui64>> plans; THashMap<ui64, TVector<ui64>> imm2onlineTxs; @@ -718,7 +718,7 @@ ui64 TFakeMiniKQLProxy::Plan(ui64 stepId, const TMap<ui64, TFakeProxyTx::TPtr>& } } } - + // send plan step for (const auto& pair : plans) { ui64 shard = pair.first; @@ -730,10 +730,10 @@ ui64 TFakeMiniKQLProxy::Plan(ui64 stepId, const TMap<ui64, TFakeProxyTx::TPtr>& plannedTx->SetTxId(txId); ActorIdToProto(Tester.Sender, plannedTx->MutableAckTo()); } - } + } Tester.Runtime.SendToPipe(shard, Tester.Sender, planStep); - } - + } + // prepare immediate TDeque<std::pair<ui64, THolder<TEvDataShard::TEvProposeTransaction>>> immEvents; for (ui64 txId : immediateTxs) { @@ -814,10 +814,10 @@ ui64 TFakeMiniKQLProxy::Plan(ui64 stepId, const TMap<ui64, TFakeProxyTx::TPtr>& #if 0 Cerr << "acks: " << acks.size() << " plans: " << plans.size() << " results: " << results.size() << Endl; #endif - TAutoPtr<IEventHandle> handle; + TAutoPtr<IEventHandle> handle; auto eventTuple = Tester.Runtime.GrabEdgeEvents<TEvPlanStepAck, TEvPlanStepAccepted, TEvProposeTransactionResult, TEvStreamClearanceRequest>(handle); - + switch (handle->Type) { case TEvPlanStepAck::EventType: { auto event = std::get<TEvPlanStepAck*>(eventTuple); @@ -839,7 +839,7 @@ ui64 TFakeMiniKQLProxy::Plan(ui64 stepId, const TMap<ui64, TFakeProxyTx::TPtr>& auto event = std::get<TEvProposeTransactionResult*>(eventTuple); ui64 txId = event->GetTxId(); ui64 shard = event->GetOrigin(); - + if (event->IsPrepared()) { Cerr << "immediate -> online tx " << txId << Endl; results.erase(std::make_pair(shard, txId)); @@ -852,7 +852,7 @@ ui64 TFakeMiniKQLProxy::Plan(ui64 stepId, const TMap<ui64, TFakeProxyTx::TPtr>& results.erase(std::make_pair(shard, txId)); break; } - + auto it = txs.find(txId); if (it == txs.end()) continue; @@ -896,9 +896,9 @@ ui64 TFakeMiniKQLProxy::Plan(ui64 stepId, const TMap<ui64, TFakeProxyTx::TPtr>& if (builder->IsComplete()) { results.erase(std::make_pair(shard, txId)); } - } + } break; - } + } case TEvStreamClearanceRequest::EventType: { auto event = std::get<TEvStreamClearanceRequest*>(eventTuple); ui64 txId = event->Record.GetTxId(); @@ -906,8 +906,8 @@ ui64 TFakeMiniKQLProxy::Plan(ui64 stepId, const TMap<ui64, TFakeProxyTx::TPtr>& streams.erase(std::make_pair(shard, txId)); Tester.Runtime.SendToPipe(shard, Tester.Sender, new TEvStreamClearancePending(txId)); } - } - } + } + } // exec imm2online @@ -983,8 +983,8 @@ ui64 TFakeMiniKQLProxy::Plan(ui64 stepId, const TMap<ui64, TFakeProxyTx::TPtr>& } return stepId; -} - +} + // TKeyExtractor::TKeyExtractor(TTester& tester, TString programText) { @@ -1004,30 +1004,30 @@ TKeyExtractor::TKeyExtractor(TTester& tester, TString programText) { // TDatashardInitialEventsFilter::TDatashardInitialEventsFilter(const TVector<ui64>& tabletIds) - : TabletIds(tabletIds) -{ -} - -TTestActorRuntime::TEventFilter TDatashardInitialEventsFilter::Prepare() { - RemainTablets = TabletIds; + : TabletIds(tabletIds) +{ +} + +TTestActorRuntime::TEventFilter TDatashardInitialEventsFilter::Prepare() { + RemainTablets = TabletIds; return [&](TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) { - return (*this)(runtime, event); - }; -} - + return (*this)(runtime, event); + }; +} + bool TDatashardInitialEventsFilter::operator()(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) { Y_UNUSED(runtime); - if (event->GetTypeRewrite() == TEvTxProcessing::EvPlanStepAck) { - ui64 tabletId = reinterpret_cast<TEvTxProcessing::TEvPlanStepAck::TPtr&>(event)->Get()->Record.GetTabletId(); - auto it = Find(RemainTablets.begin(), RemainTablets.end(), tabletId); - if (it != RemainTablets.end()) - RemainTablets.erase(it); - return true; - } - - return !RemainTablets.empty(); -} - + if (event->GetTypeRewrite() == TEvTxProcessing::EvPlanStepAck) { + ui64 tabletId = reinterpret_cast<TEvTxProcessing::TEvPlanStepAck::TPtr&>(event)->Get()->Record.GetTabletId(); + auto it = Find(RemainTablets.begin(), RemainTablets.end(), tabletId); + if (it != RemainTablets.end()) + RemainTablets.erase(it); + return true; + } + + return !RemainTablets.empty(); +} + THolder<NKqp::TEvKqp::TEvQueryRequest> MakeSQLRequest(const TString &sql, bool dml) { @@ -1040,7 +1040,7 @@ THolder<NKqp::TEvKqp::TEvQueryRequest> MakeSQLRequest(const TString &sql, : NKikimrKqp::QUERY_TYPE_SQL_DDL); request->Record.MutableRequest()->SetQuery(sql); return request; -} +} void InitRoot(Tests::TServer::TPtr server, TActorId sender) diff --git a/ydb/core/tx/datashard/datashard_ut_common.h b/ydb/core/tx/datashard/datashard_ut_common.h index 4b5d7fe4ea..f7245a8ebe 100644 --- a/ydb/core/tx/datashard/datashard_ut_common.h +++ b/ydb/core/tx/datashard/datashard_ut_common.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "datashard.h" #include "datashard_impl.h" @@ -9,17 +9,17 @@ #include <ydb/core/testlib/minikql_compile.h> #include <ydb/core/testlib/tablet_helpers.h> #include <ydb/core/testlib/test_client.h> - + #include <library/cpp/testing/unittest/registar.h> -namespace NKikimr { - +namespace NKikimr { + class TBalanceCoverageBuilder; class TEngineHolder; class TFakeMiniKQLProxy; class TFakeProxyTx; - + constexpr ui64 FAKE_SCHEMESHARD_TABLET_ID = 4200; constexpr ui64 FAKE_TX_ALLOCATOR_TABLET_ID = 4201; @@ -30,7 +30,7 @@ public: friend class TFakeMiniKQLProxy; friend class TFakeProxyTx; friend class TFakeScanTx; - + using TKeyResolver = std::function<void(TKeyDesc&)>; enum ESchema { @@ -107,20 +107,20 @@ private: ui64 LastStep; TMockDbSchemeResolver DbSchemeResolver; TString DispatchName = "NONE"; - bool AllowIncompleteResult = false; - bool* ActiveZone = nullptr; - TDuration Timeout = TDuration::Minutes(10); - + bool AllowIncompleteResult = false; + bool* ActiveZone = nullptr; + TDuration Timeout = TDuration::Minutes(10); + TKeyResolver GetKeyResolver() const; void CreateSchema(ESchema schema, const TOptions& opts); void CreateDataShard(TFakeMiniKQLProxy& proxy, ui64 tabletId, const TString& schemeText, bool withRegister = false); void RegisterTableInResolver(const TString& schemeText); - + static void EmptyShardKeyResolver(TKeyDesc& key); static void SingleShardKeyResolver(TKeyDesc& key); // uses TTestTxConfig::TxTablet0 static void ThreeShardPointKeyResolver(TKeyDesc& key); // uses TTestTxConfig::TxTablet0,1,2 -}; - +}; + /// struct TExpectedReadSet { struct TWaitFor { @@ -250,8 +250,8 @@ private: }; /// -class TFakeMiniKQLProxy { -public: +class TFakeMiniKQLProxy { +public: using IEngineFlat = NMiniKQL::IEngineFlat; //using TEvProgressTransaction = NDataShard::TDataShard::TEvPrivate::TEvProgressTransaction; @@ -261,7 +261,7 @@ public: , LastStep_(tester.LastStep) , RebootOnDelay(false) {} - + // Propose + Plan (if needed) in own step IEngineFlat::EStatus ExecSchemeCreateTable(const TString& schemaText, const TVector<ui64>& shards); IEngineFlat::EStatus Execute(const TString& programText, NKikimrMiniKQL::TResult& out, @@ -286,7 +286,7 @@ public: void EnqueueScan(const TString& programText, std::function<bool(TFakeProxyTx&)> check = DoNothing, ui32 flags = NDataShard::TTxFlags::ForceOnline); void ExecQueue(); - + static bool DoNothing(TFakeProxyTx&) { return true; } @@ -302,8 +302,8 @@ public: DelayedData.emplace_back(shardTx); } -private: - TTester& Tester; +private: + TTester& Tester; ui64& LastTxId_; ui64& LastStep_; TVector<TFakeProxyTx::TPtr> TxQueue; @@ -319,15 +319,15 @@ private: const std::function<NKikimrTxDataShard::TFlatSchemeTransaction(ui64)>& txBodyForShard); ui64 Plan(ui64 stepId, const TMap<ui64, TFakeProxyTx::TPtr>& txs, bool waitForResult = true); void ResolveShards(const TSet<ui64>& shards); -}; - +}; + /// class TDatashardInitialEventsFilter { -public: +public: TDatashardInitialEventsFilter(const TVector<ui64>& tabletIds); - TTestActorRuntime::TEventFilter Prepare(); + TTestActorRuntime::TEventFilter Prepare(); bool operator()(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event); - + TDatashardInitialEventsFilter(const TDatashardInitialEventsFilter&) = delete; TDatashardInitialEventsFilter(TDatashardInitialEventsFilter&&) = default; @@ -341,11 +341,11 @@ public: const TVector<ui64> Tablets() const { return TabletIds; } -private: +private: const TVector<ui64> TabletIds; TVector<ui64> RemainTablets; -}; - +}; + /// class TKeyExtractor : public TEngineHolder { public: @@ -625,4 +625,4 @@ struct IsTxResultComplete { void WaitTabletBecomesOffline(Tests::TServer::TPtr server, ui64 tabletId); -} +} diff --git a/ydb/core/tx/datashard/datashard_ut_init.cpp b/ydb/core/tx/datashard/datashard_ut_init.cpp index 818e30ab0c..fbf89acdef 100644 --- a/ydb/core/tx/datashard/datashard_ut_init.cpp +++ b/ydb/core/tx/datashard/datashard_ut_init.cpp @@ -6,11 +6,11 @@ #include <ydb/core/tx/schemeshard/schemeshard.h> #include <ydb/core/util/pb.h> #include <ydb/public/lib/deprecated/kicli/kicli.h> - + #include <util/string/printf.h> -namespace NKikimr { - +namespace NKikimr { + using namespace NSchemeShard; using namespace Tests; using NClient::TValue; @@ -97,22 +97,22 @@ Y_UNIT_TEST_SUITE(TTxDataShardTestInit) { Y_UNIT_TEST(TestGetShardStateAfterInitialization) { TTestBasicRuntime runtime; TTester::Setup(runtime); - + TActorId sender = runtime.AllocateEdgeActor(); CreateTestBootstrapper(runtime, CreateTestTabletInfo(TTestTxConfig::TxTablet0, TTabletTypes::FLAT_DATASHARD), &CreateDataShard); - - TDispatchOptions options; - options.FinalEvents.push_back(TDispatchOptions::TFinalEventCondition(TEvTablet::EvBoot)); - runtime.DispatchEvents(options); - + + TDispatchOptions options; + options.FinalEvents.push_back(TDispatchOptions::TFinalEventCondition(TEvTablet::EvBoot)); + runtime.DispatchEvents(options); + Y_UNUSED(sender); ForwardToTablet(runtime, TTestTxConfig::TxTablet0, sender, new TEvDataShard::TEvGetShardState(sender)); - TAutoPtr<IEventHandle> handle; - auto event = runtime.GrabEdgeEvent<TEvDataShard::TEvGetShardStateResult>(handle); - UNIT_ASSERT(event); + TAutoPtr<IEventHandle> handle; + auto event = runtime.GrabEdgeEvent<TEvDataShard::TEvGetShardStateResult>(handle); + UNIT_ASSERT(event); UNIT_ASSERT_EQUAL(event->GetOrigin(), TTestTxConfig::TxTablet0); UNIT_ASSERT_EQUAL(event->GetState(), NDataShard::TShardState::WaitScheme); - } + } void TestTablePath(bool oldCreate, bool restart) { @@ -198,6 +198,6 @@ Y_UNIT_TEST_SUITE(TTxDataShardTestInit) { Y_UNIT_TEST(TestResolvePathAfterRestart) { TestTablePath(true, true); } -} - -} +} + +} diff --git a/ydb/core/tx/datashard/datashard_ut_minikql.cpp b/ydb/core/tx/datashard/datashard_ut_minikql.cpp index 7974e47486..88a3be9df8 100644 --- a/ydb/core/tx/datashard/datashard_ut_minikql.cpp +++ b/ydb/core/tx/datashard/datashard_ut_minikql.cpp @@ -2,32 +2,32 @@ #include <ydb/public/lib/deprecated/kicli/kicli.h> - -namespace NKikimr { - + +namespace NKikimr { + using NClient::TValue; using IEngineFlat = NMiniKQL::IEngineFlat; - + Y_UNIT_TEST_SUITE(TTxDataShardMiniKQL) { - + Y_UNIT_TEST(ReadConstant) { TTester t(TTester::ESchema_KV); TFakeMiniKQLProxy proxy(t); - + auto programText = R"___(( (return (AsList (SetResult 'res1 (Int32 '2016)))) ))___"; - + UNIT_ASSERT_EQUAL(proxy.Execute(programText), IEngineFlat::EStatus::Complete); } - + // - + Y_UNIT_TEST(Write) { TTester t(TTester::ESchema_KV); TFakeMiniKQLProxy proxy(t); - + auto programText = R"___(( (let row '('('key (Uint32 '42)))) (let myUpd '( @@ -37,16 +37,16 @@ Y_UNIT_TEST(Write) { )) (return pgmReturn) ))___"; - + UNIT_ASSERT_EQUAL(proxy.Execute(programText), IEngineFlat::EStatus::Complete); } - + // - + Y_UNIT_TEST(ReadAfterWrite) { TTester t(TTester::ESchema_KV); TFakeMiniKQLProxy proxy(t); - + { auto programText = R"___(( (let row '('('key (Uint32 '42)))) @@ -57,10 +57,10 @@ Y_UNIT_TEST(ReadAfterWrite) { )) (return pgmReturn) ))___"; - + UNIT_ASSERT_EQUAL(proxy.Execute(programText), IEngineFlat::EStatus::Complete); } - + { auto programText = R"___(( (let row '('('key (Uint32 '42)))) @@ -70,7 +70,7 @@ Y_UNIT_TEST(ReadAfterWrite) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -78,9 +78,9 @@ Y_UNIT_TEST(ReadAfterWrite) { TValue row = value["myRes"]; TString data = row["value"]; UNIT_ASSERT_EQUAL(data, "Robert"); - } + } } - + Y_UNIT_TEST(ReadSpecialColumns) { TTester t(TTester::ESchema_SpecialKV); TFakeMiniKQLProxy proxy(t); @@ -157,7 +157,7 @@ Y_UNIT_TEST(ReadSpecialColumns) { } // - + Y_UNIT_TEST(ReadNonExisting) { TTester t(TTester::ESchema_KV); TFakeMiniKQLProxy proxy(t); @@ -184,7 +184,7 @@ Y_UNIT_TEST(ReadNonExisting) { Y_UNIT_TEST(WriteEraseRead) { TTester t(TTester::ESchema_KV); TFakeMiniKQLProxy proxy(t); - + { auto programText = R"___(( (let row '('('key (Uint32 '42)))) @@ -195,10 +195,10 @@ Y_UNIT_TEST(WriteEraseRead) { )) (return pgmReturn) ))___"; - + UNIT_ASSERT_EQUAL(proxy.Execute(programText), IEngineFlat::EStatus::Complete); } - + { auto programText = R"___(( (let row '('('key (Uint32 '42)))) @@ -207,10 +207,10 @@ Y_UNIT_TEST(WriteEraseRead) { )) (return pgmReturn) ))___"; - + UNIT_ASSERT_EQUAL(proxy.Execute(programText), IEngineFlat::EStatus::Complete); } - + { auto programText = R"___(( (let row '('('key (Uint32 '42)))) @@ -220,22 +220,22 @@ Y_UNIT_TEST(WriteEraseRead) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); TValue value = TValue::Create(res.GetValue(), res.GetType()); TValue row = value["myRes"]; UNIT_ASSERT(!row.HaveValue()); - } + } } - + // - + Y_UNIT_TEST(SelectRange) { TTester t(TTester::ESchema_KV); TFakeMiniKQLProxy proxy(t); - + { auto programText = R"___(( (let row1 '('('key (Uint32 '345)))) @@ -254,10 +254,10 @@ Y_UNIT_TEST(SelectRange) { )) (return pgmReturn) ))___"; - + UNIT_ASSERT_EQUAL(proxy.Execute(programText), IEngineFlat::EStatus::Complete); } - + { // Erase one row auto programText = R"___(( (let row '('('key (Uint32 '346)))) @@ -280,7 +280,7 @@ Y_UNIT_TEST(SelectRange) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -296,7 +296,7 @@ Y_UNIT_TEST(SelectRange) { UNIT_ASSERT_EQUAL(TString(row1["value"]), "Robert"); UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); } - + { auto programText = R"___(( (let range '('ExcFrom '('key (Uint32 '345) (Void)))) @@ -307,7 +307,7 @@ Y_UNIT_TEST(SelectRange) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -320,7 +320,7 @@ Y_UNIT_TEST(SelectRange) { UNIT_ASSERT_EQUAL(ui32(row2["key"]), 347); UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); } - + { auto programText = R"___(( (let range '('IncFrom '('key (Uint32 '345) (Void)))) @@ -331,7 +331,7 @@ Y_UNIT_TEST(SelectRange) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -347,7 +347,7 @@ Y_UNIT_TEST(SelectRange) { UNIT_ASSERT_EQUAL(TString(row1["value"]), "Robert"); UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); } - + { auto programText = R"___(( (let range '('IncFrom 'IncTo '('key (Uint32 '345) (Uint32 '347)))) @@ -358,7 +358,7 @@ Y_UNIT_TEST(SelectRange) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -374,7 +374,7 @@ Y_UNIT_TEST(SelectRange) { UNIT_ASSERT_EQUAL(TString(row1["value"]), "Robert"); UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); } - + { auto programText = R"___(( (let range '('ExcFrom 'IncTo '('key (Uint32 '345) (Uint32 '347)))) @@ -385,7 +385,7 @@ Y_UNIT_TEST(SelectRange) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -398,7 +398,7 @@ Y_UNIT_TEST(SelectRange) { UNIT_ASSERT_EQUAL(ui32(row2["key"]), 347); UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); } - + { auto programText = R"___(( (let range '('IncFrom 'ExcTo '('key (Uint32 '345) (Uint32 '347)))) @@ -409,7 +409,7 @@ Y_UNIT_TEST(SelectRange) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -422,7 +422,7 @@ Y_UNIT_TEST(SelectRange) { UNIT_ASSERT_EQUAL(ui32(row1["key"]), 345); UNIT_ASSERT_EQUAL(TString(row1["value"]), "Robert"); } - + { auto programText = R"___(( (let range '('ExcFrom 'ExcTo '('key (Uint32 '345) (Uint32 '347)))) @@ -433,7 +433,7 @@ Y_UNIT_TEST(SelectRange) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -442,15 +442,15 @@ Y_UNIT_TEST(SelectRange) { UNIT_ASSERT_EQUAL(bool(rs0["Truncated"]), false); TValue rsl = rs0["List"]; UNIT_ASSERT_EQUAL(rsl.Size(), 0); - } + } } - + // - + Y_UNIT_TEST(SelectRangeWithNotFullKey) { TTester t(TTester::ESchema_DoubleKV); TFakeMiniKQLProxy proxy(t); - + { auto programText = R"___(( (let row1 '('('key1 (Uint32 '345)) '('key2 (Utf8 'id123)))) @@ -473,10 +473,10 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { )) (return pgmReturn) ))___"; - + UNIT_ASSERT_EQUAL(proxy.Execute(programText), IEngineFlat::EStatus::Complete); } - + { // range end < range begin auto programText = R"___(( (let $4 (Uint32 '"346")) @@ -515,7 +515,7 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -533,7 +533,7 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { UNIT_ASSERT_EQUAL(TString(row1["value"]), "Tables"); UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); } - + { auto programText = R"___(( (let r1 '('key1 (Uint32 '345) (Uint32 '347))) @@ -546,7 +546,7 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -564,7 +564,7 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { UNIT_ASSERT_EQUAL(TString(row1["value"]), "Tables"); UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); } - + { auto programText = R"___(( (let r1 '('key1 (Uint32 '345) (Uint32 '347))) @@ -577,7 +577,7 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -595,7 +595,7 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { UNIT_ASSERT_EQUAL(TString(row1["value"]), "Tables"); UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); } - + { auto programText = R"___(( (let r1 '('key1 (Uint32 '345) (Uint32 '347))) @@ -608,7 +608,7 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -656,15 +656,15 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { UNIT_ASSERT_EQUAL(TString(row2["key2"]), "idXYZ"); UNIT_ASSERT_EQUAL(TString(row1["value"]), "Tables"); UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); - } + } } - + // - + Y_UNIT_TEST(WriteAndReadMultipleShards) { TTester t(TTester::ESchema_MultiShardKV); TFakeMiniKQLProxy proxy(t); - + { auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) @@ -683,10 +683,10 @@ Y_UNIT_TEST(WriteAndReadMultipleShards) { )) (return pgmReturn) ))___"; - + UNIT_ASSERT_EQUAL(proxy.Execute(programText), IEngineFlat::EStatus::Complete); } - + { auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) @@ -702,7 +702,7 @@ Y_UNIT_TEST(WriteAndReadMultipleShards) { )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -714,11 +714,11 @@ Y_UNIT_TEST(WriteAndReadMultipleShards) { UNIT_ASSERT_EQUAL(TString(row1["value"]), "ImInShard1"); UNIT_ASSERT_EQUAL(TString(row2["value"]), "ImInShard2"); UNIT_ASSERT_EQUAL(TString(row3["value"]), "ImInShard3"); - } + } } - + // - + void GetTableStats(TTestActorRuntime &runtime, ui64 tabletId, ui64 tableId, NKikimrTableStats::TTableStats& stats) { TAutoPtr<TEvDataShard::TEvGetTableStats> ev(new TEvDataShard::TEvGetTableStats(tableId)); @@ -849,7 +849,7 @@ Y_UNIT_TEST(TableStatsHistograms) { } // - + void InitCrossShard(TFakeMiniKQLProxy& proxy) { auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) @@ -875,11 +875,11 @@ void InitCrossShard(TFakeMiniKQLProxy& proxy) { void CrossShard_1_Cycle_Impl(const TString& dispatchName, std::function<void (TTestActorRuntime&)> setup, bool& activeZone) { TTester t(TTester::ESchema_MultiShardKV, dispatchName, setup, activeZone); TFakeMiniKQLProxy proxy(t); - + InitCrossShard(proxy); { - TTester::TActiveZone az(t); + TTester::TActiveZone az(t); auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) (let row2 '('('key (Uint32 '1100)))) @@ -898,10 +898,10 @@ void CrossShard_1_Cycle_Impl(const TString& dispatchName, std::function<void (TT )) (return pgmReturn) ))___"; - + proxy.Execute(programText, false); } - + { auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) @@ -917,7 +917,7 @@ void CrossShard_1_Cycle_Impl(const TString& dispatchName, std::function<void (TT )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -929,9 +929,9 @@ void CrossShard_1_Cycle_Impl(const TString& dispatchName, std::function<void (TT UNIT_ASSERT_EQUAL(TString(row1["value"]), "ImInShard3"); UNIT_ASSERT_EQUAL(TString(row2["value"]), "ImInShard1"); UNIT_ASSERT_EQUAL(TString(row3["value"]), "ImInShard2"); - } + } } - + Y_UNIT_TEST(CrossShard_1_Cycle) { TVector<ui64> tabletIds; tabletIds.push_back((ui64)TTestTxConfig::TxTablet0); @@ -942,17 +942,17 @@ Y_UNIT_TEST(CrossShard_1_Cycle) { return initialEventsFilter.Prepare(); }, &CrossShard_1_Cycle_Impl); } - + // - + void CrossShard_2_SwapAndCopy_Impl(const TString& dispatchName, std::function<void (TTestActorRuntime&)> setup, bool& activeZone) { TTester t(TTester::ESchema_MultiShardKV, dispatchName, setup, activeZone); TFakeMiniKQLProxy proxy(t); - + InitCrossShard(proxy); - + { - TTester::TActiveZone az(t); + TTester::TActiveZone az(t); auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) (let row2 '('('key (Uint32 '1100)))) @@ -972,10 +972,10 @@ void CrossShard_2_SwapAndCopy_Impl(const TString& dispatchName, std::function<vo )) (return pgmReturn) ))___"; - + proxy.Execute(programText, false); } - + { auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) @@ -993,7 +993,7 @@ void CrossShard_2_SwapAndCopy_Impl(const TString& dispatchName, std::function<vo )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); TValue value = TValue::Create(res.GetValue(), res.GetType()); @@ -1006,9 +1006,9 @@ void CrossShard_2_SwapAndCopy_Impl(const TString& dispatchName, std::function<vo UNIT_ASSERT_EQUAL(TString(row2["value"]), "ImInShard1"); UNIT_ASSERT_EQUAL(TString(row3["value"]), "ImInShard3"); UNIT_ASSERT_EQUAL(TString(row3new["value"]), "ImInShard3"); - } + } } - + Y_UNIT_TEST(CrossShard_2_SwapAndCopy) { TVector<ui64> tabletIds; tabletIds.push_back((ui64)TTestTxConfig::TxTablet0); @@ -1019,17 +1019,17 @@ Y_UNIT_TEST(CrossShard_2_SwapAndCopy) { return initialEventsFilter.Prepare(); }, &CrossShard_2_SwapAndCopy_Impl); } - + // - + void CrossShard_3_AllToOne_Impl(const TString& dispatchName, std::function<void (TTestActorRuntime&)> setup, bool& activeZone) { TTester t(TTester::ESchema_MultiShardKV, dispatchName, setup, activeZone); TFakeMiniKQLProxy proxy(t); - + InitCrossShard(proxy); - + { - TTester::TActiveZone az(t); + TTester::TActiveZone az(t); auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) (let row2 '('('key (Uint32 '1100)))) @@ -1051,10 +1051,10 @@ void CrossShard_3_AllToOne_Impl(const TString& dispatchName, std::function<void )) (return pgmReturn) ))___"; - + proxy.Execute(programText, false); } - + { auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) @@ -1072,7 +1072,7 @@ void CrossShard_3_AllToOne_Impl(const TString& dispatchName, std::function<void )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -1084,9 +1084,9 @@ void CrossShard_3_AllToOne_Impl(const TString& dispatchName, std::function<void UNIT_ASSERT_EQUAL(TString(row31["value"]), "ImInShard1"); UNIT_ASSERT_EQUAL(TString(row32["value"]), "ImInShard2"); UNIT_ASSERT_EQUAL(TString(row33["value"]), "ImInShard3"); - } + } } - + Y_UNIT_TEST(CrossShard_3_AllToOne) { TVector<ui64> tabletIds; tabletIds.push_back((ui64)TTestTxConfig::TxTablet0); @@ -1097,17 +1097,17 @@ Y_UNIT_TEST(CrossShard_3_AllToOne) { return initialEventsFilter.Prepare(); }, &CrossShard_3_AllToOne_Impl); } - + // - + void CrossShard_4_OneToAll_Impl(const TString& dispatchName, std::function<void (TTestActorRuntime&)> setup, bool& activeZone) { TTester t(TTester::ESchema_MultiShardKV, dispatchName, setup, activeZone); TFakeMiniKQLProxy proxy(t); - + InitCrossShard(proxy); { - TTester::TActiveZone az(t); + TTester::TActiveZone az(t); auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) (let row2 '('('key (Uint32 '1100)))) @@ -1129,10 +1129,10 @@ void CrossShard_4_OneToAll_Impl(const TString& dispatchName, std::function<void )) (return pgmReturn) ))___"; - + proxy.Execute(programText, false); } - + { auto programText = R"___(( (let row13 '('('key (Uint32 '203)))) @@ -1148,7 +1148,7 @@ void CrossShard_4_OneToAll_Impl(const TString& dispatchName, std::function<void )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -1160,9 +1160,9 @@ void CrossShard_4_OneToAll_Impl(const TString& dispatchName, std::function<void UNIT_ASSERT_EQUAL(TString(row13["value"]), "ImInShard3"); UNIT_ASSERT_EQUAL(TString(row23["value"]), "ImInShard3"); UNIT_ASSERT_EQUAL(TString(row33["value"]), "ImInShard3"); - } + } } - + Y_UNIT_TEST(CrossShard_4_OneToAll) { TVector<ui64> tabletIds; tabletIds.push_back((ui64)TTestTxConfig::TxTablet0); @@ -1173,17 +1173,17 @@ Y_UNIT_TEST(CrossShard_4_OneToAll) { return initialEventsFilter.Prepare(); }, &CrossShard_4_OneToAll_Impl); } - + // - + void CrossShard_5_AllToAll_Impl(const TString& dispatchName, std::function<void (TTestActorRuntime&)> setup, bool& activeZone) { TTester t(TTester::ESchema_MultiShardKV, dispatchName, setup, activeZone); TFakeMiniKQLProxy proxy(t); - + InitCrossShard(proxy); - + { - TTester::TActiveZone az(t); + TTester::TActiveZone az(t); auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) (let row2 '('('key (Uint32 '1100)))) @@ -1217,10 +1217,10 @@ void CrossShard_5_AllToAll_Impl(const TString& dispatchName, std::function<void )) (return pgmReturn) ))___"; - + proxy.Execute(programText, false); } - + { auto programText = R"___(( (let row11 '('('key (Uint32 '201)))) @@ -1248,7 +1248,7 @@ void CrossShard_5_AllToAll_Impl(const TString& dispatchName, std::function<void )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -1272,9 +1272,9 @@ void CrossShard_5_AllToAll_Impl(const TString& dispatchName, std::function<void UNIT_ASSERT_EQUAL(TString(row31["value"]), "ImInShard1"); UNIT_ASSERT_EQUAL(TString(row32["value"]), "ImInShard2"); UNIT_ASSERT_EQUAL(TString(row33["value"]), "ImInShard3"); - } + } } - + Y_UNIT_TEST(CrossShard_5_AllToAll) { TVector<ui64> tabletIds; tabletIds.push_back((ui64)TTestTxConfig::TxTablet0); @@ -1285,17 +1285,17 @@ Y_UNIT_TEST(CrossShard_5_AllToAll) { return initialEventsFilter.Prepare(); }, &CrossShard_5_AllToAll_Impl); } - + // - + void CrossShard_6_Local_Impl(const TString& dispatchName, std::function<void (TTestActorRuntime&)> setup, bool& activeZone) { TTester t(TTester::ESchema_MultiShardKV, dispatchName, setup, activeZone); TFakeMiniKQLProxy proxy(t); - + InitCrossShard(proxy); - + { - TTester::TActiveZone az(t); + TTester::TActiveZone az(t); auto programText = R"___(( (let row1 '('('key (Uint32 '100)))) (let row2 '('('key (Uint32 '1100)))) @@ -1317,10 +1317,10 @@ void CrossShard_6_Local_Impl(const TString& dispatchName, std::function<void (TT )) (return pgmReturn) ))___"; - + proxy.Execute(programText, false); } - + { auto programText = R"___(( (let row11 '('('key (Uint32 '201)))) @@ -1336,7 +1336,7 @@ void CrossShard_6_Local_Impl(const TString& dispatchName, std::function<void (TT )) (return pgmReturn) ))___"; - + NKikimrMiniKQL::TResult res; UNIT_ASSERT_EQUAL(proxy.Execute(programText, res), IEngineFlat::EStatus::Complete); @@ -1348,9 +1348,9 @@ void CrossShard_6_Local_Impl(const TString& dispatchName, std::function<void (TT UNIT_ASSERT_EQUAL(TString(row11["value"]), "ImInShard1"); UNIT_ASSERT_EQUAL(TString(row22["value"]), "ImInShard2"); UNIT_ASSERT_EQUAL(TString(row33["value"]), "ImInShard3"); - } + } } - + Y_UNIT_TEST(CrossShard_6_Local) { TVector<ui64> tabletIds; tabletIds.push_back((ui64)TTestTxConfig::TxTablet0); @@ -1361,7 +1361,7 @@ Y_UNIT_TEST(CrossShard_6_Local) { return initialEventsFilter.Prepare(); }, &CrossShard_6_Local_Impl); } - + Y_UNIT_TEST(WriteAndReadMany) { TTester t(TTester::ESchema_DoubleKV); TFakeMiniKQLProxy proxy(t); @@ -1710,5 +1710,5 @@ Y_UNIT_TEST(MemoryUsageMultiShard) { } } // Y_UNIT_TEST_SUITE(TTxDataShardMiniKQL) - -} // namespace NKikimr + +} // namespace NKikimr diff --git a/ydb/core/tx/schemeshard/schemeshard__serverless_storage_billing.cpp b/ydb/core/tx/schemeshard/schemeshard__serverless_storage_billing.cpp index fdb4593a73..39d84e883f 100644 --- a/ydb/core/tx/schemeshard/schemeshard__serverless_storage_billing.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__serverless_storage_billing.cpp @@ -98,7 +98,7 @@ struct TSchemeShard::TTxServerlessStorageBilling : public TTransactionBase<TSche auto last = Self->ServerlessStorageLastBillTime; if (now < last) { - LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "TTxServerlessStorageBilling: unable do anything from the past" + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "TTxServerlessStorageBilling: unable do anything from the past" << ", schemeshardId: " << Self->SelfTabletId() << ", domainId: " << Self->ParentDomainId << ", now: " << now diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.cpp b/ydb/core/tx/schemeshard/schemeshard_impl.cpp index 0715543a22..15e08a9628 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_impl.cpp @@ -3644,13 +3644,13 @@ TSchemeShard::TSchemeShard(const TActorId &tablet, TTabletStorageInfo *info) , EnableAsyncIndexes(0, 0, 1) , EnableSchemeTransactionsAtSchemeShard(0, 0, 1) { - TabletCountersPtr.Reset(new TProtobufTabletCounters< + TabletCountersPtr.Reset(new TProtobufTabletCounters< ESimpleCounters_descriptor, ECumulativeCounters_descriptor, EPercentileCounters_descriptor, ETxTypes_descriptor >()); - TabletCounters = TabletCountersPtr.Get(); + TabletCounters = TabletCountersPtr.Get(); SelfPinger = new TSelfPinger(SelfTabletId(), TabletCounters); } @@ -3777,7 +3777,7 @@ void TSchemeShard::OnActivateExecutor(const TActorContext &ctx) { SplitSettings.Register(appData->Icb); - Executor()->RegisterExternalTabletCounters(TabletCountersPtr); + Executor()->RegisterExternalTabletCounters(TabletCountersPtr); Execute(CreateTxInitSchema(), ctx); SubscribeConsoleConfigs(ctx); diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.h b/ydb/core/tx/schemeshard/schemeshard_impl.h index e1a1d08b9a..a291b43230 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.h +++ b/ydb/core/tx/schemeshard/schemeshard_impl.h @@ -203,9 +203,9 @@ public: TShardDeleter ShardDeleter; - // Counter-strike stuff + // Counter-strike stuff TTabletCountersBase* TabletCounters = nullptr; - TAutoPtr<TTabletCountersBase> TabletCountersPtr; + TAutoPtr<TTabletCountersBase> TabletCountersPtr; TAutoPtr<TSelfPinger> SelfPinger; diff --git a/ydb/core/tx/tx_processing.h b/ydb/core/tx/tx_processing.h index 72276c1af3..879f1a7ab0 100644 --- a/ydb/core/tx/tx_processing.h +++ b/ydb/core/tx/tx_processing.h @@ -117,7 +117,7 @@ struct TEvTxProcessing { Record.SetTabletDest(tabletDest); Record.SetTabletProducer(tabletProducer); Record.SetReadSet(readSet); - Record.SetSeqno(seqno); + Record.SetSeqno(seqno); } TString ToString() const { @@ -128,18 +128,18 @@ struct TEvTxProcessing { str << " TabletDest# " << Record.GetTabletDest(); str << " SetTabletProducer# " << Record.GetTabletProducer(); str << " ReadSet.Size()# " << Record.GetReadSet().size(); - str << " Seqno# " << Record.GetSeqno(); + str << " Seqno# " << Record.GetSeqno(); // BalanceTrackList str << "}"; return str.Str(); } }; - struct TEvReadSetAck : public TThrRefBase, public TEventPB<TEvReadSetAck, NKikimrTx::TEvReadSetAck, EvReadSetAck> { + struct TEvReadSetAck : public TThrRefBase, public TEventPB<TEvReadSetAck, NKikimrTx::TEvReadSetAck, EvReadSetAck> { TEvReadSetAck() {} - TEvReadSetAck(ui64 step, ui64 orderId, ui64 tabletSource, ui64 tabletDest, ui64 tabletConsumer, ui32 flags, ui64 seqno = 0) + TEvReadSetAck(ui64 step, ui64 orderId, ui64 tabletSource, ui64 tabletDest, ui64 tabletConsumer, ui32 flags, ui64 seqno = 0) { Record.SetStep(step); Record.SetTxId(orderId); @@ -147,7 +147,7 @@ struct TEvTxProcessing { Record.SetTabletDest(tabletDest); Record.SetTabletConsumer(tabletConsumer); Record.SetFlags(flags); - Record.SetSeqno(seqno); + Record.SetSeqno(seqno); } TEvReadSetAck(const TEvReadSet& evReadSet, ui64 tabletConsumer) @@ -169,7 +169,7 @@ struct TEvTxProcessing { str << " TabletDest# " << Record.GetTabletDest(); str << " SetTabletConsumer# " << Record.GetTabletConsumer(); str << " Flags# " << Record.GetFlags(); - str << " Seqno# " << Record.GetSeqno(); + str << " Seqno# " << Record.GetSeqno(); str << "}"; return str.Str(); } diff --git a/ydb/core/tx/tx_proxy/proxy_impl.cpp b/ydb/core/tx/tx_proxy/proxy_impl.cpp index 20dc8cce17..df82100d70 100644 --- a/ydb/core/tx/tx_proxy/proxy_impl.cpp +++ b/ydb/core/tx/tx_proxy/proxy_impl.cpp @@ -45,7 +45,7 @@ struct TDelayedQueue { class TTxProxy : public TActorBootstrapped<TTxProxy> { TTxProxyServices Services; - + THolder<NTabletPipe::IClientCache> PipeClientCache; TTxAllocatorClient TxAllocatorClient; diff --git a/ydb/core/util/failure_injection.cpp b/ydb/core/util/failure_injection.cpp index 9eeaaa968b..00c4dd6fa1 100644 --- a/ydb/core/util/failure_injection.cpp +++ b/ydb/core/util/failure_injection.cpp @@ -54,34 +54,34 @@ namespace NKikimr { } void DumpQueue(IOutputStream& str) { - HTML(str) { - TABLE() { - TABLEHEAD() { - TABLER() { - TABLEH() { + HTML(str) { + TABLE() { + TABLEHEAD() { + TABLER() { + TABLEH() { str << "Probe name"; - } - TABLEH() { + } + TABLEH() { str << "Remaining hit count"; - } - } - } - TABLEBODY() { + } + } + } + TABLEBODY() { with_lock (Mutex) { for (const TFailureQueueItem& item : FailureQ) { - TABLER() { - TABLED() { + TABLER() { + TABLED() { str << item.Name; - } - TABLED() { + } + TABLED() { str << item.HitCount; - } - } + } + } } } - } - } - } + } + } + } } private: @@ -106,14 +106,14 @@ namespace NKikimr { {} private: - bool DoExecute(TOrbit&, const TParams& params) override { + bool DoExecute(TOrbit&, const TParams& params) override { Manager->Inject(Name, params); return true; } }; class TFailureInjectionActor : public TActorBootstrapped<TFailureInjectionActor> { - TManager TraceManager; + TManager TraceManager; TVector<TString> Probes; TFailureInjectionManager Manager; bool Enabled = false; @@ -162,7 +162,7 @@ namespace NKikimr { auto& custom = *action.MutableCustomAction(); custom.SetName(actionName); - auto factory = [=](TProbe *probe, const TCustomAction& /*action*/, TSession* /*trace*/) { + auto factory = [=](TProbe *probe, const TCustomAction& /*action*/, TSession* /*trace*/) { return new TTraceActionExecutor(probe, &Manager, name); }; TraceManager.RegisterCustomAction(actionName, factory); @@ -197,11 +197,11 @@ namespace NKikimr { ui32 hitCount = hc ? FromString<ui32>(hc) : 1; Manager.EnqueueFailureItem(probe, {}, hitCount); } catch (const yexception& ex) { - HTML(str) { - DIV() { + HTML(str) { + DIV() { str << "<h1><font color=red>" << ex.what() << "</font></h1>"; - } - } + } + } } } } @@ -209,52 +209,52 @@ namespace NKikimr { Enable(); } - HTML(str) { - DIV() { + HTML(str) { + DIV() { Manager.DumpQueue(str); - } + } - FORM_CLASS("form-horizontal") { - DIV_CLASS("control-group") { - LABEL_CLASS_FOR("control-label", "probe") { + FORM_CLASS("form-horizontal") { + DIV_CLASS("control-group") { + LABEL_CLASS_FOR("control-label", "probe") { str << "Probe"; - } - DIV_CLASS("controls") { + } + DIV_CLASS("controls") { str << "<select id=\"probe\" name=\"probe\">"; for (const TString& probe : Probes) { str << "<option value=\"" << probe << "\">" << probe << "</option>"; } str << "</select>"; - } + } - LABEL_CLASS_FOR("control-label", "hitcount") { + LABEL_CLASS_FOR("control-label", "hitcount") { str << "Hit count"; - } - DIV_CLASS("controls") { + } + DIV_CLASS("controls") { str << "<input type=\"number\" id=\"hitcount\" name=\"hitcount\">"; - } + } - LABEL_CLASS_FOR("control-label", "queue") { + LABEL_CLASS_FOR("control-label", "queue") { str << "Queue definition string"; - } - DIV_CLASS("controls") { + } + DIV_CLASS("controls") { str << "<input id=\"queue\" name=\"queue\">"; - } - } - DIV_CLASS("control-group") { - DIV_CLASS("controls") { + } + } + DIV_CLASS("control-group") { + DIV_CLASS("controls") { str << "<button type=\"submit\" name=\"submit\" class=\"btn btn-default\">Add to queue</button>"; - } - } - } - } + } + } + } + } ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str(), ev->Get()->SubRequestId)); } void ProcessQueue(IOutputStream& str, const TString& queue) { TVector<std::tuple<TString, TMaybe<TParams>, ui32>> items; - HTML(str) { + HTML(str) { size_t pos = 0; for (;;) { TString probe; @@ -262,9 +262,9 @@ namespace NKikimr { probe.append(queue[pos]); } if (std::find(Probes.begin(), Probes.end(), probe) == Probes.end()) { - DIV() { + DIV() { str << "<h1><font color=red>Probe " << probe << " does not exist</font></h1>"; - } + } return; } ui32 hitCount = 1; @@ -274,9 +274,9 @@ namespace NKikimr { } } if (pos < queue.size() && queue[pos] != ';') { - DIV() { + DIV() { str << "<h1><font color=red>Missing semicolon</font></h1>"; - } + } return; } items.emplace_back(std::move(probe), Nothing(), hitCount); @@ -286,7 +286,7 @@ namespace NKikimr { break; } } - } + } for (const auto& item : items) { Manager.EnqueueFailureItem(std::get<0>(item), std::get<1>(item), std::get<2>(item)); diff --git a/ydb/core/util/fragmented_buffer.cpp b/ydb/core/util/fragmented_buffer.cpp index 6da04399b6..6a4525bca1 100644 --- a/ydb/core/util/fragmented_buffer.cpp +++ b/ydb/core/util/fragmented_buffer.cpp @@ -7,7 +7,7 @@ namespace NKikimr { TFragmentedBuffer::TFragmentedBuffer() { } -void TFragmentedBuffer::Insert(i32 begin, const char* source, i32 bytesToCopy) { +void TFragmentedBuffer::Insert(i32 begin, const char* source, i32 bytesToCopy) { Y_VERIFY(bytesToCopy); BufferForOffset[begin].AssignNoAlias(source, bytesToCopy); } @@ -28,7 +28,7 @@ void TFragmentedBuffer::SetMonolith(TString &data) { BufferForOffset.emplace(0, data); } -void TFragmentedBuffer::Write(i32 begin, const char* buffer, i32 size) { +void TFragmentedBuffer::Write(i32 begin, const char* buffer, i32 size) { Y_VERIFY(size); if (BufferForOffset.empty()) { Insert(begin, buffer, size); @@ -38,7 +38,7 @@ void TFragmentedBuffer::Write(i32 begin, const char* buffer, i32 size) { if (it != BufferForOffset.begin()) { it--; } - if (it != BufferForOffset.end() && it->first < begin && it->first + i32(it->second.size()) <= begin) { + if (it != BufferForOffset.end() && it->first < begin && it->first + i32(it->second.size()) <= begin) { // b....e // X....Y // skip @@ -46,24 +46,24 @@ void TFragmentedBuffer::Write(i32 begin, const char* buffer, i32 size) { } const char* source = buffer; - i32 bytesToCopy = size; - i32 offset = begin; + i32 bytesToCopy = size; + i32 offset = begin; while (bytesToCopy) { if (it == BufferForOffset.end()) { Insert(offset, source, bytesToCopy); break; } else if (it->first > offset) { - i32 bytesToNext = it->first - offset; - i32 bytesToInsert = Min(bytesToCopy, bytesToNext); + i32 bytesToNext = it->first - offset; + i32 bytesToInsert = Min(bytesToCopy, bytesToNext); Insert(offset, source, bytesToInsert); source += bytesToInsert; offset += bytesToInsert; bytesToCopy -= bytesToInsert; } else if (it->first <= offset) { Y_VERIFY(it->second.size()); - Y_VERIFY(it->first + i32(it->second.size()) > offset); - i32 bytesToNext = it->first + it->second.size() - offset; - i32 bytesToInsert = Min(bytesToCopy, bytesToNext); + Y_VERIFY(it->first + i32(it->second.size()) > offset); + i32 bytesToNext = it->first + it->second.size() - offset; + i32 bytesToInsert = Min(bytesToCopy, bytesToNext); char *destination = const_cast<char*>(it->second.data()) + offset - it->first; memcpy(destination, source, bytesToInsert); source += bytesToInsert; @@ -75,28 +75,28 @@ void TFragmentedBuffer::Write(i32 begin, const char* buffer, i32 size) { } -void TFragmentedBuffer::Read(i32 begin, char* buffer, i32 size) const { +void TFragmentedBuffer::Read(i32 begin, char* buffer, i32 size) const { Y_VERIFY(size); Y_VERIFY(!BufferForOffset.empty()); auto it = BufferForOffset.upper_bound(begin); if (it != BufferForOffset.begin()) { it--; } - if (it != BufferForOffset.end() && it->first < begin && it->first + i32(it->second.size()) <= begin) { + if (it != BufferForOffset.end() && it->first < begin && it->first + i32(it->second.size()) <= begin) { Y_VERIFY(false); // b....e // X....Y } char* destination = buffer; - i32 bytesToCopy = size; - i32 offset = begin; + i32 bytesToCopy = size; + i32 offset = begin; while (bytesToCopy) { - Y_VERIFY(it != BufferForOffset.end(), "offset# %" PRIi32 " Print# %s", (i32)offset, Print().c_str()); - Y_VERIFY(it->first <= offset, "offset# %" PRIi32 " Print# %s", (i32)offset, Print().c_str()); - Y_VERIFY(it->first + i32(it->second.size()) > offset); - i32 bytesToNext = it->first + it->second.size() - offset; - i32 bytesToInsert = Min(bytesToCopy, bytesToNext); + Y_VERIFY(it != BufferForOffset.end(), "offset# %" PRIi32 " Print# %s", (i32)offset, Print().c_str()); + Y_VERIFY(it->first <= offset, "offset# %" PRIi32 " Print# %s", (i32)offset, Print().c_str()); + Y_VERIFY(it->first + i32(it->second.size()) > offset); + i32 bytesToNext = it->first + it->second.size() - offset; + i32 bytesToInsert = Min(bytesToCopy, bytesToNext); const char *source = it->second.data() + offset - it->first; memcpy(destination, source, bytesToInsert); destination += bytesToInsert; @@ -119,23 +119,23 @@ TString TFragmentedBuffer::Print() const { return str.Str(); } -std::pair<const char*, i32> TFragmentedBuffer::Get(i32 begin) const { +std::pair<const char*, i32> TFragmentedBuffer::Get(i32 begin) const { auto it = BufferForOffset.upper_bound(begin); Y_VERIFY(it != BufferForOffset.begin()); --it; - const i32 offset = begin - it->first; + const i32 offset = begin - it->first; Y_VERIFY(offset >= 0 && (size_t)offset < it->second.size()); return std::make_pair(it->second.data() + offset, it->second.size() - offset); } -void TFragmentedBuffer::CopyFrom(const TFragmentedBuffer& from, const TIntervalSet<i32>& range) { +void TFragmentedBuffer::CopyFrom(const TFragmentedBuffer& from, const TIntervalSet<i32>& range) { Y_VERIFY(range); - for (auto it = range.begin(); it != range.end(); ++it) { - auto [begin, end] = *it; - i32 offset = begin; + for (auto it = range.begin(); it != range.end(); ++it) { + auto [begin, end] = *it; + i32 offset = begin; while (offset < end) { const auto& [data, maxLen] = from.Get(offset); - i32 len = Min(maxLen, end - offset); + i32 len = Min(maxLen, end - offset); Write(offset, data, len); offset += len; } diff --git a/ydb/core/util/fragmented_buffer.h b/ydb/core/util/fragmented_buffer.h index 0e7ce9f842..94dea29185 100644 --- a/ydb/core/util/fragmented_buffer.h +++ b/ydb/core/util/fragmented_buffer.h @@ -7,8 +7,8 @@ namespace NKikimr { class TFragmentedBuffer { - TMap<i32, TString> BufferForOffset; - void Insert(i32 begin, const char* source, i32 bytesToCopy); + TMap<i32, TString> BufferForOffset; + void Insert(i32 begin, const char* source, i32 bytesToCopy); public: TFragmentedBuffer(); @@ -17,12 +17,12 @@ public: TString GetMonolith(); void SetMonolith(TString &data); - void Write(i32 begin, const char* buffer, i32 size); - void Read(i32 begin, char* buffer, i32 size) const; + void Write(i32 begin, const char* buffer, i32 size); + void Read(i32 begin, char* buffer, i32 size) const; TString Print() const; - std::pair<const char*, i32> Get(i32 begin) const; - void CopyFrom(const TFragmentedBuffer& from, const TIntervalSet<i32>& range); + std::pair<const char*, i32> Get(i32 begin) const; + void CopyFrom(const TFragmentedBuffer& from, const TIntervalSet<i32>& range); explicit operator bool() const { return !BufferForOffset.empty(); diff --git a/ydb/core/util/interval_set.h b/ydb/core/util/interval_set.h index 68f6ea6658..6243a59a83 100644 --- a/ydb/core/util/interval_set.h +++ b/ydb/core/util/interval_set.h @@ -1,970 +1,970 @@ #pragma once #include "defs.h" -#include <variant> -#include <utility> +#include <variant> +#include <utility> #include <util/generic/map.h> -#include <util/stream/str.h> -#include <util/system/yassert.h> +#include <util/stream/str.h> +#include <util/system/yassert.h> #include <ydb/core/util/yverify_stream.h> -#include <library/cpp/containers/stack_vector/stack_vec.h> +#include <library/cpp/containers/stack_vector/stack_vec.h> namespace NKikimr { // // A set of non-intersecting non-adjoint non-empty intervals in form [begin, end) (end > begin) // -template <class T> struct TIntervalMap; // implemented as TMap -template <class T> struct TIntervalVec; // implemented as sorted TStackVec -template <class T, size_t ThresholdSize = 8> struct TIntervalSet; // implement as either of the above - -template <class T> -struct TIntervalMap { - TMap<T, T> EndForBegin; - - using iterator = typename decltype(EndForBegin)::iterator; - using const_iterator = typename decltype(EndForBegin)::const_iterator; - - TIntervalMap() = default; - TIntervalMap(const TIntervalMap<T>&) = default; - TIntervalMap(TIntervalMap<T>&&) = default; - - TIntervalMap(T begin, T end) { - Y_VERIFY_DEBUG_S(begin < end, "begin# " << begin << " end# " << end); - EndForBegin[begin] = end; - } - - TIntervalMap& operator=(const TIntervalMap<T>&) = default; - TIntervalMap& operator=(TIntervalMap<T>&&) = default; - - void Add(const TIntervalMap<T>& b) { - *this |= b; - } - - void Add(T begin, T end) { - *this |= TIntervalMap<T>(begin, end); - } - - void Clear() { - EndForBegin.clear(); - } - - void Assign(T begin, T end) { - Y_VERIFY_DEBUG_S(begin < end, "begin# " << begin << " end# " << end); - EndForBegin.clear(); - EndForBegin[begin] = end; - } - - bool IsEmpty() const { - return EndForBegin.empty(); - } - - auto UpperBound(const T& key) const { - return EndForBegin.upper_bound(key); - } - - bool IsSubsetOf(const TIntervalSet<T>& b) const { +template <class T> struct TIntervalMap; // implemented as TMap +template <class T> struct TIntervalVec; // implemented as sorted TStackVec +template <class T, size_t ThresholdSize = 8> struct TIntervalSet; // implement as either of the above + +template <class T> +struct TIntervalMap { + TMap<T, T> EndForBegin; + + using iterator = typename decltype(EndForBegin)::iterator; + using const_iterator = typename decltype(EndForBegin)::const_iterator; + + TIntervalMap() = default; + TIntervalMap(const TIntervalMap<T>&) = default; + TIntervalMap(TIntervalMap<T>&&) = default; + + TIntervalMap(T begin, T end) { + Y_VERIFY_DEBUG_S(begin < end, "begin# " << begin << " end# " << end); + EndForBegin[begin] = end; + } + + TIntervalMap& operator=(const TIntervalMap<T>&) = default; + TIntervalMap& operator=(TIntervalMap<T>&&) = default; + + void Add(const TIntervalMap<T>& b) { + *this |= b; + } + + void Add(T begin, T end) { + *this |= TIntervalMap<T>(begin, end); + } + + void Clear() { + EndForBegin.clear(); + } + + void Assign(T begin, T end) { + Y_VERIFY_DEBUG_S(begin < end, "begin# " << begin << " end# " << end); + EndForBegin.clear(); + EndForBegin[begin] = end; + } + + bool IsEmpty() const { + return EndForBegin.empty(); + } + + auto UpperBound(const T& key) const { + return EndForBegin.upper_bound(key); + } + + bool IsSubsetOf(const TIntervalSet<T>& b) const { return std::visit([this](auto& var) -> bool { return this->IsSubsetOf(var); }, b.Var); - } - - template <class B> - bool IsSubsetOf(const B& b) const { - auto aIt = EndForBegin.begin(); - if (aIt == EndForBegin.end()) { - return true; - } - auto bIt = b.UpperBound(aIt->first); - if (bIt != b.EndForBegin.begin()) { - --bIt; - } - if (bIt == b.EndForBegin.end()) { - return false; - } - while (true) { - // a---a - // b---b 1 - // b---b 2 - // b---b 3 - // b---b 4 - // b---b 5 - // b-b 6 - if (bIt->second <= aIt->first) { - // 1 - ++bIt; - if (bIt == b.EndForBegin.end()) { - return false; - } - } else if (bIt->first <= aIt->first) { - // 2,3 - if (bIt->second < aIt->second) { - // 2 - return false; - } - // 3 - ++aIt; - if (aIt == EndForBegin.end()) { - return true; - } - } else { - // 4, 5, 6 - return false; - } - } - } - - void Subtract(const TIntervalMap<T>& b) { - *this -= b; - } - - void Subtract(T begin, T end) { - *this -= TIntervalMap<T>(begin, end); - } - - TString ToString() const { - TStringStream str; - str << "{"; - for (auto it = EndForBegin.begin(); it != EndForBegin.end(); ++it) { - if (it != EndForBegin.begin()) { - str << " U "; - } - str << "[" << it->first << ", " << it->second << ")"; - } - str << "}"; - return str.Str(); - } - - void Verify() const { - T lastEnd = Min<T>(); - for (auto it = EndForBegin.begin(); it != EndForBegin.end(); ++it) { - Y_VERIFY_S(it->first < it->second, "begin# " << it->first << " end# " << it->second); - if (it != EndForBegin.begin()) { - Y_VERIFY_S(it->first > lastEnd, "[" << it->first << ", " << it->second << ") vs " << lastEnd); - } - lastEnd = it->second; - } - } - + } + + template <class B> + bool IsSubsetOf(const B& b) const { + auto aIt = EndForBegin.begin(); + if (aIt == EndForBegin.end()) { + return true; + } + auto bIt = b.UpperBound(aIt->first); + if (bIt != b.EndForBegin.begin()) { + --bIt; + } + if (bIt == b.EndForBegin.end()) { + return false; + } + while (true) { + // a---a + // b---b 1 + // b---b 2 + // b---b 3 + // b---b 4 + // b---b 5 + // b-b 6 + if (bIt->second <= aIt->first) { + // 1 + ++bIt; + if (bIt == b.EndForBegin.end()) { + return false; + } + } else if (bIt->first <= aIt->first) { + // 2,3 + if (bIt->second < aIt->second) { + // 2 + return false; + } + // 3 + ++aIt; + if (aIt == EndForBegin.end()) { + return true; + } + } else { + // 4, 5, 6 + return false; + } + } + } + + void Subtract(const TIntervalMap<T>& b) { + *this -= b; + } + + void Subtract(T begin, T end) { + *this -= TIntervalMap<T>(begin, end); + } + + TString ToString() const { + TStringStream str; + str << "{"; + for (auto it = EndForBegin.begin(); it != EndForBegin.end(); ++it) { + if (it != EndForBegin.begin()) { + str << " U "; + } + str << "[" << it->first << ", " << it->second << ")"; + } + str << "}"; + return str.Str(); + } + + void Verify() const { + T lastEnd = Min<T>(); + for (auto it = EndForBegin.begin(); it != EndForBegin.end(); ++it) { + Y_VERIFY_S(it->first < it->second, "begin# " << it->first << " end# " << it->second); + if (it != EndForBegin.begin()) { + Y_VERIFY_S(it->first > lastEnd, "[" << it->first << ", " << it->second << ") vs " << lastEnd); + } + lastEnd = it->second; + } + } + size_t Size() const { return EndForBegin.size(); } - template <class Y> - friend bool operator ==(const TIntervalMap<T>& x, const Y& y) { - if (x.EndForBegin.size() != y.EndForBegin.size()) { - return false; - } - auto xi = x.EndForBegin.begin(), xe = x.EndForBegin.end(); - auto yi = y.EndForBegin.begin(); - for (; xi != xe; ++xi, ++yi) { - if (xi->first != yi->first || xi->second != yi->second) { - return false; - } - } - return true; + template <class Y> + friend bool operator ==(const TIntervalMap<T>& x, const Y& y) { + if (x.EndForBegin.size() != y.EndForBegin.size()) { + return false; + } + auto xi = x.EndForBegin.begin(), xe = x.EndForBegin.end(); + auto yi = y.EndForBegin.begin(); + for (; xi != xe; ++xi, ++yi) { + if (xi->first != yi->first || xi->second != yi->second) { + return false; + } + } + return true; } explicit operator bool() const { return !IsEmpty(); } - template <class Y> - TIntervalMap<T> operator |(const Y& y) const { - TIntervalMap<T> res; - auto xIt = EndForBegin.begin(); - auto yIt = y.EndForBegin.begin(); - while (xIt != EndForBegin.end() || yIt != y.EndForBegin.end()) { - if (yIt == y.EndForBegin.end() || (xIt != EndForBegin.end() && xIt->second < yIt->first)) { - res.EndForBegin.insert(res.EndForBegin.end(), *xIt++); - } else if (xIt == EndForBegin.end() || yIt->second < xIt->first) { - res.EndForBegin.insert(res.EndForBegin.end(), *yIt++); - } else { // intervals do intersect - T begin = Min(xIt->first, yIt->first), end = Max(xIt->second, yIt->second); - ++xIt, ++yIt; - for (;;) { // consume any other intervals intersecting with [begin, end) - if (xIt != EndForBegin.end() && xIt->first <= end) { - end = Max(end, xIt->second); - ++xIt; - } else if (yIt != y.EndForBegin.end() && yIt->first <= end) { - end = Max(end, yIt->second); - ++yIt; - } else { - break; - } - } - res.EndForBegin.emplace_hint(res.EndForBegin.end(), begin, end); - } - } - return res; - } - - template <class Y> - TIntervalMap<T>& operator |=(const Y& y) { - auto yIt = y.EndForBegin.begin(); - auto ye = y.EndForBegin.end(); - if (yIt == ye) { - return *this; - } - auto xIt = EndForBegin.upper_bound(yIt->first); - if (xIt != EndForBegin.begin()) { - --xIt; - } - while (xIt != EndForBegin.end() && yIt != ye) { - if (xIt->second < yIt->first) { - ++xIt; - } else if (yIt->second < xIt->first) { - EndForBegin.insert(xIt, *yIt++); - } else { // intervals do intersect - T begin = Min(xIt->first, yIt->first), end = Max(xIt->second, yIt->second); - auto baseIt = xIt++; - ++yIt; - for (;;) { // consume any other intervals intersecting with [begin, end) - if (xIt != EndForBegin.end() && xIt->first <= end) { - end = Max(end, xIt->second); - ++xIt; - } else if (yIt != ye && yIt->first <= end) { - end = Max(end, yIt->second); - ++yIt; - } else { - break; - } - } - if (baseIt->first != begin) { - EndForBegin.emplace_hint(EndForBegin.erase(baseIt, xIt), begin, end); - } else { - baseIt->second = end; - EndForBegin.erase(++baseIt, xIt); - } - } - } - EndForBegin.insert(yIt, ye); - return *this; - } - - template <class Y> - TIntervalMap<T> operator &(const Y& y) const { - TIntervalMap<T> res; - auto xIt = EndForBegin.begin(); - auto yIt = y.EndForBegin.begin(); - while (xIt != EndForBegin.end() && yIt != y.EndForBegin.end()) { - const auto [xf, xs] = *xIt; - const auto [yf, ys] = *yIt; - if (xs <= yf) { - ++xIt; - } else if (ys <= xf) { - ++yIt; - } else { // intervals do intersect - const T begin = Max(xf, yf), end = Min(xs, ys); - if (xs <= ys) { - ++xIt; - } - if (ys <= xs) { - ++yIt; - } - res.EndForBegin.emplace_hint(res.EndForBegin.end(), begin, end); - } - } - return res; - } - - template <class Y> - TIntervalMap<T>& operator &=(const Y& y) { - auto xIt = EndForBegin.begin(); - auto yIt = y.EndForBegin.begin(); - std::optional<typename TMap<T, T>::value_type> carry; - auto dropFront = [&] { - if (carry) { - carry.reset(); - } else { - xIt = EndForBegin.erase(xIt); - } - return xIt; - }; - while ((carry || xIt != EndForBegin.end()) && yIt != y.EndForBegin.end()) { - const auto [xf, xs] = carry ? *carry : *xIt; - const auto [yf, ys] = *yIt; - if (xs <= yf) { - dropFront(); - } else if (ys <= xf) { - ++yIt; - } else { // intervals do intersect - const T begin = Max(xf, yf), end = Min(xs, ys); - if (!carry && xs <= ys && xf == begin) { // just replace interval's end - xIt->second = end; - } else { // or replace the whole entry - xIt = EndForBegin.emplace_hint(dropFront(), begin, end); - } - ++xIt; - if (ys <= xs) { - ++yIt; - } - if (end != xs) { // there is remaining part of the interval -- keep it - carry.emplace(end, xs); - } - } - } - EndForBegin.erase(xIt, EndForBegin.end()); - return *this; - } - - template <class Y> - TIntervalMap<T> operator -(const Y& y) const { - return TIntervalMap<T>(*this) -= y; - } - - template <class Y> - TIntervalMap<T>& operator -=(const Y& y) { - if constexpr (std::is_same_v<TIntervalMap<T>, Y>) { - if (this == &y) { - EndForBegin.clear(); - return *this; - } - } - - TIntervalMap<T> res; - auto xIt = EndForBegin.begin(); - if (y.EndForBegin.size() == 1) { - xIt = EndForBegin.upper_bound(y.EndForBegin.begin()->first); - if (xIt != EndForBegin.begin()) { - --xIt; - } - } - auto yIt = y.EndForBegin.begin(); - while (xIt != EndForBegin.end() && yIt != y.EndForBegin.end()) { - const auto [xf, xs] = *xIt; - const auto [yf, ys] = *yIt; - if (xs <= yf) { - ++xIt; - } else if (ys <= xf) { - ++yIt; - } else { - xIt = EndForBegin.erase(xIt); - if (xf < yf) { - xIt = EndForBegin.emplace_hint(xIt, xf, yf); - } - if (ys < xs) { - xIt = EndForBegin.emplace_hint(xf < yf ? std::next(xIt) : xIt, ys, xs); - } - } - } - return *this; - } + template <class Y> + TIntervalMap<T> operator |(const Y& y) const { + TIntervalMap<T> res; + auto xIt = EndForBegin.begin(); + auto yIt = y.EndForBegin.begin(); + while (xIt != EndForBegin.end() || yIt != y.EndForBegin.end()) { + if (yIt == y.EndForBegin.end() || (xIt != EndForBegin.end() && xIt->second < yIt->first)) { + res.EndForBegin.insert(res.EndForBegin.end(), *xIt++); + } else if (xIt == EndForBegin.end() || yIt->second < xIt->first) { + res.EndForBegin.insert(res.EndForBegin.end(), *yIt++); + } else { // intervals do intersect + T begin = Min(xIt->first, yIt->first), end = Max(xIt->second, yIt->second); + ++xIt, ++yIt; + for (;;) { // consume any other intervals intersecting with [begin, end) + if (xIt != EndForBegin.end() && xIt->first <= end) { + end = Max(end, xIt->second); + ++xIt; + } else if (yIt != y.EndForBegin.end() && yIt->first <= end) { + end = Max(end, yIt->second); + ++yIt; + } else { + break; + } + } + res.EndForBegin.emplace_hint(res.EndForBegin.end(), begin, end); + } + } + return res; + } + + template <class Y> + TIntervalMap<T>& operator |=(const Y& y) { + auto yIt = y.EndForBegin.begin(); + auto ye = y.EndForBegin.end(); + if (yIt == ye) { + return *this; + } + auto xIt = EndForBegin.upper_bound(yIt->first); + if (xIt != EndForBegin.begin()) { + --xIt; + } + while (xIt != EndForBegin.end() && yIt != ye) { + if (xIt->second < yIt->first) { + ++xIt; + } else if (yIt->second < xIt->first) { + EndForBegin.insert(xIt, *yIt++); + } else { // intervals do intersect + T begin = Min(xIt->first, yIt->first), end = Max(xIt->second, yIt->second); + auto baseIt = xIt++; + ++yIt; + for (;;) { // consume any other intervals intersecting with [begin, end) + if (xIt != EndForBegin.end() && xIt->first <= end) { + end = Max(end, xIt->second); + ++xIt; + } else if (yIt != ye && yIt->first <= end) { + end = Max(end, yIt->second); + ++yIt; + } else { + break; + } + } + if (baseIt->first != begin) { + EndForBegin.emplace_hint(EndForBegin.erase(baseIt, xIt), begin, end); + } else { + baseIt->second = end; + EndForBegin.erase(++baseIt, xIt); + } + } + } + EndForBegin.insert(yIt, ye); + return *this; + } + + template <class Y> + TIntervalMap<T> operator &(const Y& y) const { + TIntervalMap<T> res; + auto xIt = EndForBegin.begin(); + auto yIt = y.EndForBegin.begin(); + while (xIt != EndForBegin.end() && yIt != y.EndForBegin.end()) { + const auto [xf, xs] = *xIt; + const auto [yf, ys] = *yIt; + if (xs <= yf) { + ++xIt; + } else if (ys <= xf) { + ++yIt; + } else { // intervals do intersect + const T begin = Max(xf, yf), end = Min(xs, ys); + if (xs <= ys) { + ++xIt; + } + if (ys <= xs) { + ++yIt; + } + res.EndForBegin.emplace_hint(res.EndForBegin.end(), begin, end); + } + } + return res; + } + + template <class Y> + TIntervalMap<T>& operator &=(const Y& y) { + auto xIt = EndForBegin.begin(); + auto yIt = y.EndForBegin.begin(); + std::optional<typename TMap<T, T>::value_type> carry; + auto dropFront = [&] { + if (carry) { + carry.reset(); + } else { + xIt = EndForBegin.erase(xIt); + } + return xIt; + }; + while ((carry || xIt != EndForBegin.end()) && yIt != y.EndForBegin.end()) { + const auto [xf, xs] = carry ? *carry : *xIt; + const auto [yf, ys] = *yIt; + if (xs <= yf) { + dropFront(); + } else if (ys <= xf) { + ++yIt; + } else { // intervals do intersect + const T begin = Max(xf, yf), end = Min(xs, ys); + if (!carry && xs <= ys && xf == begin) { // just replace interval's end + xIt->second = end; + } else { // or replace the whole entry + xIt = EndForBegin.emplace_hint(dropFront(), begin, end); + } + ++xIt; + if (ys <= xs) { + ++yIt; + } + if (end != xs) { // there is remaining part of the interval -- keep it + carry.emplace(end, xs); + } + } + } + EndForBegin.erase(xIt, EndForBegin.end()); + return *this; + } + + template <class Y> + TIntervalMap<T> operator -(const Y& y) const { + return TIntervalMap<T>(*this) -= y; + } + + template <class Y> + TIntervalMap<T>& operator -=(const Y& y) { + if constexpr (std::is_same_v<TIntervalMap<T>, Y>) { + if (this == &y) { + EndForBegin.clear(); + return *this; + } + } + + TIntervalMap<T> res; + auto xIt = EndForBegin.begin(); + if (y.EndForBegin.size() == 1) { + xIt = EndForBegin.upper_bound(y.EndForBegin.begin()->first); + if (xIt != EndForBegin.begin()) { + --xIt; + } + } + auto yIt = y.EndForBegin.begin(); + while (xIt != EndForBegin.end() && yIt != y.EndForBegin.end()) { + const auto [xf, xs] = *xIt; + const auto [yf, ys] = *yIt; + if (xs <= yf) { + ++xIt; + } else if (ys <= xf) { + ++yIt; + } else { + xIt = EndForBegin.erase(xIt); + if (xf < yf) { + xIt = EndForBegin.emplace_hint(xIt, xf, yf); + } + if (ys < xs) { + xIt = EndForBegin.emplace_hint(xf < yf ? std::next(xIt) : xIt, ys, xs); + } + } + } + return *this; + } }; -template <class T> -struct TIntervalVec { - static constexpr size_t StackSize = 1; - - TStackVec<std::pair<T, T>, StackSize> EndForBegin; // <begin, end> - - using iterator = typename decltype(EndForBegin)::iterator; - using const_iterator = typename decltype(EndForBegin)::const_iterator; - - TIntervalVec() = default; - TIntervalVec(const TIntervalVec<T>&) = default; - TIntervalVec(TIntervalVec<T>&&) = default; - - TIntervalVec(T begin, T end) { - Y_VERIFY_DEBUG_S(begin < end, "begin# " << begin << " end# " << end); - EndForBegin.emplace_back(begin, end); - } - - TIntervalVec& operator=(const TIntervalVec<T>&) = default; - TIntervalVec& operator=(TIntervalVec<T>&&) = default; - - void Add(const TIntervalVec<T>& b) { - *this |= b; - } - - void Add(T begin, T end) { - *this |= TIntervalVec<T>(begin, end); - } - - void Clear() { - EndForBegin.clear(); - } - - void Assign(T begin, T end) { - Y_VERIFY_DEBUG_S(begin < end, "begin# " << begin << " end# " << end); - EndForBegin.assign(1, {begin, end}); - } - - bool IsEmpty() const { - return EndForBegin.empty(); - } - - auto UpperBound(const T& key) const { - // Do not use binary search to optimize for small vectors - for (auto i = EndForBegin.begin(), e = EndForBegin.end(); i != e; ++i) { - if (key < i->first) { - return i; - } - } - return EndForBegin.end(); - } - - bool IsSubsetOf(const TIntervalSet<T>& b) const { +template <class T> +struct TIntervalVec { + static constexpr size_t StackSize = 1; + + TStackVec<std::pair<T, T>, StackSize> EndForBegin; // <begin, end> + + using iterator = typename decltype(EndForBegin)::iterator; + using const_iterator = typename decltype(EndForBegin)::const_iterator; + + TIntervalVec() = default; + TIntervalVec(const TIntervalVec<T>&) = default; + TIntervalVec(TIntervalVec<T>&&) = default; + + TIntervalVec(T begin, T end) { + Y_VERIFY_DEBUG_S(begin < end, "begin# " << begin << " end# " << end); + EndForBegin.emplace_back(begin, end); + } + + TIntervalVec& operator=(const TIntervalVec<T>&) = default; + TIntervalVec& operator=(TIntervalVec<T>&&) = default; + + void Add(const TIntervalVec<T>& b) { + *this |= b; + } + + void Add(T begin, T end) { + *this |= TIntervalVec<T>(begin, end); + } + + void Clear() { + EndForBegin.clear(); + } + + void Assign(T begin, T end) { + Y_VERIFY_DEBUG_S(begin < end, "begin# " << begin << " end# " << end); + EndForBegin.assign(1, {begin, end}); + } + + bool IsEmpty() const { + return EndForBegin.empty(); + } + + auto UpperBound(const T& key) const { + // Do not use binary search to optimize for small vectors + for (auto i = EndForBegin.begin(), e = EndForBegin.end(); i != e; ++i) { + if (key < i->first) { + return i; + } + } + return EndForBegin.end(); + } + + bool IsSubsetOf(const TIntervalSet<T>& b) const { return std::visit([this](auto& var) -> bool { return this->IsSubsetOf(var); }, b.Var); - } - - template <class B> - bool IsSubsetOf(const B& b) const { - auto aIt = EndForBegin.begin(); - if (aIt == EndForBegin.end()) { - return true; - } - // Do not use binary search, optimized for small interval vecs, anyway worst-case is O(n) + O(m) - auto bIt = b.EndForBegin.begin(); - if (bIt == b.EndForBegin.end()) { - return false; - } - while (true) { - // a---a - // b---b 1 - // b---b 2 - // b---b 3 - // b---b 4 - // b---b 5 - // b-b 6 - if (bIt->second <= aIt->first) { - // 1 - ++bIt; - if (bIt == b.EndForBegin.end()) { - return false; - } - } else if (bIt->first <= aIt->first) { - // 2,3 - if (bIt->second < aIt->second) { - // 2 - return false; - } - // 3 - ++aIt; - if (aIt == EndForBegin.end()) { - return true; - } - } else { - // 4, 5, 6 - return false; - } - } - } - - void Subtract(const TIntervalVec<T>& b) { - *this -= b; - } - - void Subtract(T begin, T end) { - *this -= TIntervalVec<T>(begin, end); - } - - TString ToString() const { - TStringStream str; - str << "{"; - for (auto it = EndForBegin.begin(); it != EndForBegin.end(); ++it) { - if (it != EndForBegin.begin()) { - str << " U "; - } - str << "[" << it->first << ", " << it->second << ")"; - } - str << "}"; - return str.Str(); - } - - void Verify() const { - T lastEnd = Min<T>(); - for (auto it = EndForBegin.begin(); it != EndForBegin.end(); ++it) { - Y_VERIFY_S(it->first < it->second, "begin# " << it->first << " end# " << it->second); - if (it != EndForBegin.begin()) { - Y_VERIFY_S(it->first > lastEnd, "[" << it->first << ", " << it->second << ") vs " << lastEnd); - } - lastEnd = it->second; - } - } - - size_t Size() const { - return EndForBegin.size(); - } - - template <class Y> - friend bool operator ==(const TIntervalVec<T>& x, const Y& y) { - if (x.EndForBegin.size() != y.EndForBegin.size()) { - return false; - } - auto xi = x.EndForBegin.begin(), xe = x.EndForBegin.end(); - auto yi = y.EndForBegin.begin(); - for (; xi != xe; ++xi, ++yi) { - if (xi->first != yi->first || xi->second != yi->second) { - return false; - } - } - return true; - } - - explicit operator bool() const { - return !IsEmpty(); - } - - template <class Y> - TIntervalVec<T> operator |(const Y& y) const { - TIntervalVec<T> res; - auto xIt = EndForBegin.begin(); - auto yIt = y.EndForBegin.begin(); - while (xIt != EndForBegin.end() || yIt != y.EndForBegin.end()) { - if (yIt == y.EndForBegin.end() || (xIt != EndForBegin.end() && xIt->second < yIt->first)) { - res.EndForBegin.emplace_back(*xIt++); - } else if (xIt == EndForBegin.end() || yIt->second < xIt->first) { - res.EndForBegin.emplace_back(*yIt++); - } else { // intervals do intersect - T begin = Min(xIt->first, yIt->first), end = Max(xIt->second, yIt->second); - ++xIt, ++yIt; - for (;;) { // consume any other intervals intersecting with [begin, end) - if (xIt != EndForBegin.end() && xIt->first <= end) { - end = Max(end, xIt->second); - ++xIt; - } else if (yIt != y.EndForBegin.end() && yIt->first <= end) { - end = Max(end, yIt->second); - ++yIt; - } else { - break; - } - } - res.EndForBegin.emplace_back(begin, end); - } - } - return res; - } - - template <class Y> - TIntervalVec<T>& operator |=(const Y& y) { - size_t xi = 0; - size_t xo = 0; - auto yi = y.EndForBegin.begin(); - auto ye = y.EndForBegin.end(); - while (yi != ye && xi != EndForBegin.size()) { - if (EndForBegin[xi].second < yi->first) { - if (xi != xo) { - EndForBegin[xo] = EndForBegin[xi]; - } - ++xi; - ++xo; - } else if (yi->second < EndForBegin[xi].first) { - if (xo == xi) { - EndForBegin.insert(EndForBegin.begin() + xo, *yi++); - ++xi; - ++xo; - } else { - EndForBegin[xo++] = *yi++; - } - } else { // intervals do intersect - T begin = Min(EndForBegin[xi].first, yi->first); - T end = Max(EndForBegin[xi].second, yi->second); - ++xi; - ++yi; - for (;;) { // consume any other intervals intersecting with [begin, end) - if (xi != EndForBegin.size() && EndForBegin[xi].first <= end) { - end = Max(end, EndForBegin[xi].second); - ++xi; - } else if (yi != ye && yi->first <= end) { - end = Max(end, yi->second); - ++yi; - } else { - break; - } - } - EndForBegin[xo++] = {begin, end}; - } - } - EndForBegin.erase(EndForBegin.begin() + xo, EndForBegin.begin() + xi); - EndForBegin.insert(EndForBegin.end(), yi, ye); - return *this; - } - - template <class Y> - TIntervalVec<T> operator &(const Y& y) const { - TIntervalVec<T> res; - auto xIt = EndForBegin.begin(); - auto yIt = y.EndForBegin.begin(); - while (xIt != EndForBegin.end() && yIt != y.EndForBegin.end()) { - const auto [xf, xs] = *xIt; - const auto [yf, ys] = *yIt; - if (xs <= yf) { - ++xIt; - } else if (ys <= xf) { - ++yIt; - } else { // intervals do intersect - const T begin = Max(xf, yf), end = Min(xs, ys); - if (xs <= ys) { - ++xIt; - } - if (ys <= xs) { - ++yIt; - } - res.EndForBegin.emplace_back(begin, end); - } - } - return res; - } - - template <class Y> - TIntervalVec<T>& operator &=(const Y& y) { - size_t xi = 0; - auto yIt = y.EndForBegin.begin(); - std::optional<std::pair<T, T>> carry; - while ((carry || xi != EndForBegin.size()) && yIt != y.EndForBegin.end()) { - const auto [xf, xs] = carry ? *carry : EndForBegin[xi]; - const auto [yf, ys] = *yIt; - if (xs <= yf) { - if (carry) { - carry.reset(); - } else { - EndForBegin.erase(EndForBegin.begin() + xi); - } - } else if (ys <= xf) { - ++yIt; - } else { // intervals do intersect - const T begin = Max(xf, yf), end = Min(xs, ys); - if (!carry) { - EndForBegin[xi] = {begin, end}; - } else { - carry.reset(); - EndForBegin.emplace(EndForBegin.begin() + xi, begin, end); - } - ++xi; - if (ys <= xs) { - ++yIt; - } - if (end != xs) { // there is remaining part of the interval -- keep it - carry.emplace(end, xs); - } - } - } - EndForBegin.resize(xi); - return *this; - } - - template <class Y> - TIntervalVec<T> operator -(const Y& y) const { - return TIntervalVec<T>(*this) -= y; - } - - template <class Y> - TIntervalVec<T>& operator -=(const Y& y) { - if constexpr (std::is_same_v<TIntervalVec<T>, Y>) { - if (this == &y) { - EndForBegin.clear(); - return *this; - } - } - - TIntervalVec<T> res; - size_t xi = 0; - auto yIt = y.EndForBegin.begin(); - while (xi != EndForBegin.size() && yIt != y.EndForBegin.end()) { - const auto [xf, xs] = EndForBegin[xi]; - const auto [yf, ys] = *yIt; - if (xs <= yf) { - ++xi; - } else if (ys <= xf) { - ++yIt; - } else { - if (xf < yf) { - EndForBegin[xi++].second = yf; - if (ys < xs) { - EndForBegin.emplace(EndForBegin.begin() + xi, ys, xs); - } - } else if (ys < xs) { - EndForBegin[xi].first = ys; - } else { - EndForBegin.erase(EndForBegin.begin() + xi); - } - } - } - return *this; - } -}; - -// helper type for the visitor -template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; -// explicit deduction guide (not needed as of C++20) -template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; - -template <class T, size_t ThresholdSize> -struct TIntervalSet { - // Vec is used for small size, up to ThresholdSize intervals - // If vector become larger, then data is moved into Map - using TVec = TIntervalVec<T>; - using TMap = TIntervalMap<T>; - using TVar = std::variant<TVec, TMap>; - TVar Var; - - class TConstIterator { - using TVecIter = typename TIntervalVec<T>::const_iterator; - using TMapIter = typename TIntervalMap<T>::const_iterator; - using TValue = std::pair<T, T>; - - std::variant<TVecIter, TMapIter> Iter; - - public: - TConstIterator() {} - - explicit TConstIterator(TVecIter vecIter) - : Iter(vecIter) - {} - - explicit TConstIterator(TMapIter mapIter) - : Iter(mapIter) - {} - - TConstIterator(const TConstIterator&) = default; - TConstIterator& operator=(const TConstIterator& other) = default; - - TValue operator*() const { - return std::visit([](auto& iter) -> TValue { return *iter; }, Iter); - } - - TConstIterator& operator++() { - std::visit([](auto& iter) { iter++; }, Iter); - return *this; - } - - friend bool operator==(const TConstIterator& x, const TConstIterator& y) { - return x.Iter == y.Iter; - } - - friend bool operator!=(const TConstIterator& x, const TConstIterator& y) { - return !(x == y); - } - }; - - using const_iterator = TConstIterator; - - TIntervalSet() = default; - TIntervalSet(const TIntervalSet&) = default; - TIntervalSet(TIntervalSet&&) = default; - - TIntervalSet(T begin, T end) - : Var(std::in_place_type<TVec>, begin, end) - {} - - TIntervalSet(const TIntervalVec<T>& vec) : Var(vec) {} - TIntervalSet(TIntervalVec<T>&& vec) : Var(std::move(vec)) {} - TIntervalSet(const TIntervalMap<T>& map) : Var(map) {} - TIntervalSet(TIntervalMap<T>&& map) : Var(std::move(map)) {} - - TIntervalSet& operator=(const TIntervalSet&) = default; - TIntervalSet& operator=(TIntervalSet&&) = default; - - TIntervalSet& operator=(const TIntervalVec<T>& vec) { - Var = vec; - return *this; - } - - TIntervalSet& operator=(TIntervalVec<T>&& vec) { - Var = std::move(vec); - return *this; - } - - TIntervalSet& operator=(const TIntervalMap<T>& map) { - Var = map; - return *this; - } - - TIntervalSet& operator=(TIntervalMap<T>&& map) { - Var = std::move(map); - return *this; - } - - TConstIterator begin() const { - return std::visit([](auto& var) -> TConstIterator { return TConstIterator(var.EndForBegin.begin()); }, Var); - } - - TConstIterator end() const { - return std::visit([](auto& var) -> TConstIterator { return TConstIterator(var.EndForBegin.end()); }, Var); - } - - bool IsVec() const { - return Var.index() == 0; - } - - template <class Y> - void Add(const Y& y) { - *this |= y; - } - - void Add(T begin, T end) { - *this |= TIntervalVec<T>(begin, end); - } - - void Clear() { - std::visit([this](auto&& var) { - if constexpr (std::is_same_v<std::decay_t<decltype(var)>, TVec>) { - var.Clear(); // just clear vector (do not reset storage) - } else { - Var = TVec(); // use empty vector instead of map - } - }, Var); - } - - void Assign(T begin, T end) { - std::visit(overloaded { - [=](TVec& vec) { - vec.Assign(begin, end); // just clear vector (do not reset storage) - }, - [=](TMap&) { - Var = TVec(begin, end); // use vector instead of map - } - }, Var); - } - - bool IsEmpty() const { - return std::visit([](auto& var) -> bool { return var.IsEmpty(); }, Var); - } - - template <class Y> - bool IsSubsetOf(const Y& y) const { - return std::visit([&y](auto& var) -> bool { return var.IsSubsetOf(y); }, Var); - } - - bool IsSubsetOf(const TIntervalSet& y) const { + } + + template <class B> + bool IsSubsetOf(const B& b) const { + auto aIt = EndForBegin.begin(); + if (aIt == EndForBegin.end()) { + return true; + } + // Do not use binary search, optimized for small interval vecs, anyway worst-case is O(n) + O(m) + auto bIt = b.EndForBegin.begin(); + if (bIt == b.EndForBegin.end()) { + return false; + } + while (true) { + // a---a + // b---b 1 + // b---b 2 + // b---b 3 + // b---b 4 + // b---b 5 + // b-b 6 + if (bIt->second <= aIt->first) { + // 1 + ++bIt; + if (bIt == b.EndForBegin.end()) { + return false; + } + } else if (bIt->first <= aIt->first) { + // 2,3 + if (bIt->second < aIt->second) { + // 2 + return false; + } + // 3 + ++aIt; + if (aIt == EndForBegin.end()) { + return true; + } + } else { + // 4, 5, 6 + return false; + } + } + } + + void Subtract(const TIntervalVec<T>& b) { + *this -= b; + } + + void Subtract(T begin, T end) { + *this -= TIntervalVec<T>(begin, end); + } + + TString ToString() const { + TStringStream str; + str << "{"; + for (auto it = EndForBegin.begin(); it != EndForBegin.end(); ++it) { + if (it != EndForBegin.begin()) { + str << " U "; + } + str << "[" << it->first << ", " << it->second << ")"; + } + str << "}"; + return str.Str(); + } + + void Verify() const { + T lastEnd = Min<T>(); + for (auto it = EndForBegin.begin(); it != EndForBegin.end(); ++it) { + Y_VERIFY_S(it->first < it->second, "begin# " << it->first << " end# " << it->second); + if (it != EndForBegin.begin()) { + Y_VERIFY_S(it->first > lastEnd, "[" << it->first << ", " << it->second << ") vs " << lastEnd); + } + lastEnd = it->second; + } + } + + size_t Size() const { + return EndForBegin.size(); + } + + template <class Y> + friend bool operator ==(const TIntervalVec<T>& x, const Y& y) { + if (x.EndForBegin.size() != y.EndForBegin.size()) { + return false; + } + auto xi = x.EndForBegin.begin(), xe = x.EndForBegin.end(); + auto yi = y.EndForBegin.begin(); + for (; xi != xe; ++xi, ++yi) { + if (xi->first != yi->first || xi->second != yi->second) { + return false; + } + } + return true; + } + + explicit operator bool() const { + return !IsEmpty(); + } + + template <class Y> + TIntervalVec<T> operator |(const Y& y) const { + TIntervalVec<T> res; + auto xIt = EndForBegin.begin(); + auto yIt = y.EndForBegin.begin(); + while (xIt != EndForBegin.end() || yIt != y.EndForBegin.end()) { + if (yIt == y.EndForBegin.end() || (xIt != EndForBegin.end() && xIt->second < yIt->first)) { + res.EndForBegin.emplace_back(*xIt++); + } else if (xIt == EndForBegin.end() || yIt->second < xIt->first) { + res.EndForBegin.emplace_back(*yIt++); + } else { // intervals do intersect + T begin = Min(xIt->first, yIt->first), end = Max(xIt->second, yIt->second); + ++xIt, ++yIt; + for (;;) { // consume any other intervals intersecting with [begin, end) + if (xIt != EndForBegin.end() && xIt->first <= end) { + end = Max(end, xIt->second); + ++xIt; + } else if (yIt != y.EndForBegin.end() && yIt->first <= end) { + end = Max(end, yIt->second); + ++yIt; + } else { + break; + } + } + res.EndForBegin.emplace_back(begin, end); + } + } + return res; + } + + template <class Y> + TIntervalVec<T>& operator |=(const Y& y) { + size_t xi = 0; + size_t xo = 0; + auto yi = y.EndForBegin.begin(); + auto ye = y.EndForBegin.end(); + while (yi != ye && xi != EndForBegin.size()) { + if (EndForBegin[xi].second < yi->first) { + if (xi != xo) { + EndForBegin[xo] = EndForBegin[xi]; + } + ++xi; + ++xo; + } else if (yi->second < EndForBegin[xi].first) { + if (xo == xi) { + EndForBegin.insert(EndForBegin.begin() + xo, *yi++); + ++xi; + ++xo; + } else { + EndForBegin[xo++] = *yi++; + } + } else { // intervals do intersect + T begin = Min(EndForBegin[xi].first, yi->first); + T end = Max(EndForBegin[xi].second, yi->second); + ++xi; + ++yi; + for (;;) { // consume any other intervals intersecting with [begin, end) + if (xi != EndForBegin.size() && EndForBegin[xi].first <= end) { + end = Max(end, EndForBegin[xi].second); + ++xi; + } else if (yi != ye && yi->first <= end) { + end = Max(end, yi->second); + ++yi; + } else { + break; + } + } + EndForBegin[xo++] = {begin, end}; + } + } + EndForBegin.erase(EndForBegin.begin() + xo, EndForBegin.begin() + xi); + EndForBegin.insert(EndForBegin.end(), yi, ye); + return *this; + } + + template <class Y> + TIntervalVec<T> operator &(const Y& y) const { + TIntervalVec<T> res; + auto xIt = EndForBegin.begin(); + auto yIt = y.EndForBegin.begin(); + while (xIt != EndForBegin.end() && yIt != y.EndForBegin.end()) { + const auto [xf, xs] = *xIt; + const auto [yf, ys] = *yIt; + if (xs <= yf) { + ++xIt; + } else if (ys <= xf) { + ++yIt; + } else { // intervals do intersect + const T begin = Max(xf, yf), end = Min(xs, ys); + if (xs <= ys) { + ++xIt; + } + if (ys <= xs) { + ++yIt; + } + res.EndForBegin.emplace_back(begin, end); + } + } + return res; + } + + template <class Y> + TIntervalVec<T>& operator &=(const Y& y) { + size_t xi = 0; + auto yIt = y.EndForBegin.begin(); + std::optional<std::pair<T, T>> carry; + while ((carry || xi != EndForBegin.size()) && yIt != y.EndForBegin.end()) { + const auto [xf, xs] = carry ? *carry : EndForBegin[xi]; + const auto [yf, ys] = *yIt; + if (xs <= yf) { + if (carry) { + carry.reset(); + } else { + EndForBegin.erase(EndForBegin.begin() + xi); + } + } else if (ys <= xf) { + ++yIt; + } else { // intervals do intersect + const T begin = Max(xf, yf), end = Min(xs, ys); + if (!carry) { + EndForBegin[xi] = {begin, end}; + } else { + carry.reset(); + EndForBegin.emplace(EndForBegin.begin() + xi, begin, end); + } + ++xi; + if (ys <= xs) { + ++yIt; + } + if (end != xs) { // there is remaining part of the interval -- keep it + carry.emplace(end, xs); + } + } + } + EndForBegin.resize(xi); + return *this; + } + + template <class Y> + TIntervalVec<T> operator -(const Y& y) const { + return TIntervalVec<T>(*this) -= y; + } + + template <class Y> + TIntervalVec<T>& operator -=(const Y& y) { + if constexpr (std::is_same_v<TIntervalVec<T>, Y>) { + if (this == &y) { + EndForBegin.clear(); + return *this; + } + } + + TIntervalVec<T> res; + size_t xi = 0; + auto yIt = y.EndForBegin.begin(); + while (xi != EndForBegin.size() && yIt != y.EndForBegin.end()) { + const auto [xf, xs] = EndForBegin[xi]; + const auto [yf, ys] = *yIt; + if (xs <= yf) { + ++xi; + } else if (ys <= xf) { + ++yIt; + } else { + if (xf < yf) { + EndForBegin[xi++].second = yf; + if (ys < xs) { + EndForBegin.emplace(EndForBegin.begin() + xi, ys, xs); + } + } else if (ys < xs) { + EndForBegin[xi].first = ys; + } else { + EndForBegin.erase(EndForBegin.begin() + xi); + } + } + } + return *this; + } +}; + +// helper type for the visitor +template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; +// explicit deduction guide (not needed as of C++20) +template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; + +template <class T, size_t ThresholdSize> +struct TIntervalSet { + // Vec is used for small size, up to ThresholdSize intervals + // If vector become larger, then data is moved into Map + using TVec = TIntervalVec<T>; + using TMap = TIntervalMap<T>; + using TVar = std::variant<TVec, TMap>; + TVar Var; + + class TConstIterator { + using TVecIter = typename TIntervalVec<T>::const_iterator; + using TMapIter = typename TIntervalMap<T>::const_iterator; + using TValue = std::pair<T, T>; + + std::variant<TVecIter, TMapIter> Iter; + + public: + TConstIterator() {} + + explicit TConstIterator(TVecIter vecIter) + : Iter(vecIter) + {} + + explicit TConstIterator(TMapIter mapIter) + : Iter(mapIter) + {} + + TConstIterator(const TConstIterator&) = default; + TConstIterator& operator=(const TConstIterator& other) = default; + + TValue operator*() const { + return std::visit([](auto& iter) -> TValue { return *iter; }, Iter); + } + + TConstIterator& operator++() { + std::visit([](auto& iter) { iter++; }, Iter); + return *this; + } + + friend bool operator==(const TConstIterator& x, const TConstIterator& y) { + return x.Iter == y.Iter; + } + + friend bool operator!=(const TConstIterator& x, const TConstIterator& y) { + return !(x == y); + } + }; + + using const_iterator = TConstIterator; + + TIntervalSet() = default; + TIntervalSet(const TIntervalSet&) = default; + TIntervalSet(TIntervalSet&&) = default; + + TIntervalSet(T begin, T end) + : Var(std::in_place_type<TVec>, begin, end) + {} + + TIntervalSet(const TIntervalVec<T>& vec) : Var(vec) {} + TIntervalSet(TIntervalVec<T>&& vec) : Var(std::move(vec)) {} + TIntervalSet(const TIntervalMap<T>& map) : Var(map) {} + TIntervalSet(TIntervalMap<T>&& map) : Var(std::move(map)) {} + + TIntervalSet& operator=(const TIntervalSet&) = default; + TIntervalSet& operator=(TIntervalSet&&) = default; + + TIntervalSet& operator=(const TIntervalVec<T>& vec) { + Var = vec; + return *this; + } + + TIntervalSet& operator=(TIntervalVec<T>&& vec) { + Var = std::move(vec); + return *this; + } + + TIntervalSet& operator=(const TIntervalMap<T>& map) { + Var = map; + return *this; + } + + TIntervalSet& operator=(TIntervalMap<T>&& map) { + Var = std::move(map); + return *this; + } + + TConstIterator begin() const { + return std::visit([](auto& var) -> TConstIterator { return TConstIterator(var.EndForBegin.begin()); }, Var); + } + + TConstIterator end() const { + return std::visit([](auto& var) -> TConstIterator { return TConstIterator(var.EndForBegin.end()); }, Var); + } + + bool IsVec() const { + return Var.index() == 0; + } + + template <class Y> + void Add(const Y& y) { + *this |= y; + } + + void Add(T begin, T end) { + *this |= TIntervalVec<T>(begin, end); + } + + void Clear() { + std::visit([this](auto&& var) { + if constexpr (std::is_same_v<std::decay_t<decltype(var)>, TVec>) { + var.Clear(); // just clear vector (do not reset storage) + } else { + Var = TVec(); // use empty vector instead of map + } + }, Var); + } + + void Assign(T begin, T end) { + std::visit(overloaded { + [=](TVec& vec) { + vec.Assign(begin, end); // just clear vector (do not reset storage) + }, + [=](TMap&) { + Var = TVec(begin, end); // use vector instead of map + } + }, Var); + } + + bool IsEmpty() const { + return std::visit([](auto& var) -> bool { return var.IsEmpty(); }, Var); + } + + template <class Y> + bool IsSubsetOf(const Y& y) const { + return std::visit([&y](auto& var) -> bool { return var.IsSubsetOf(y); }, Var); + } + + bool IsSubsetOf(const TIntervalSet& y) const { return std::visit([this](auto& var) -> bool { return this->IsSubsetOf(var); }, y.Var); - } - - template <class Y> - void Subtract(const Y& y) { - *this -= y; - } - - void Subtract(T begin, T end) { - *this -= TIntervalVec<T>(begin, end); - } - - TString ToString() const { - return std::visit([](auto& var) -> TString { return var.ToString(); }, Var); - } - - void Verify() const { - std::visit([](auto& var) { var.Verify(); }, Var); - } - - size_t Size() const { - return std::visit([](auto& var) -> size_t { return var.Size(); }, Var); - } - - template <class Y> - friend bool operator ==(const TIntervalSet& x, const Y& y) { - return std::visit([&y](auto& var) -> bool { return var == y; }, x.Var); - } - - template <class X> - friend bool operator ==(const X& x, const TIntervalSet& y) { - return std::visit([&x](auto& var) -> bool { return x == var; }, y.Var); - } - - friend bool operator ==(const TIntervalSet& x, const TIntervalSet& y) { - return std::visit([&x](auto& var) -> bool { return x == var; }, y.Var); - } - - explicit operator bool() const { - return !IsEmpty(); - } - - template <class Y> - TIntervalSet operator |(const Y& y) const { - return std::visit([&y](auto& var) { return TIntervalSet(var | y); } , Var); - } - - TIntervalSet operator |(const TIntervalSet& y) const { - return std::visit([this](auto&& var) { return TIntervalSet(*this | var); }, y.Var); - } - - template <class Y> - TIntervalSet& operator |=(const Y& y) { - std::visit(overloaded { - [this, &y](TVec& vec) { - vec |= y; - if (vec.Size() > ThresholdSize) { - Mapify(vec); - } - }, - [&y](TMap& map) { - map |= y; - } - }, Var); - return *this; - } - - TIntervalSet& operator |=(const TIntervalSet& y) { - return std::visit([this](auto& var) -> TIntervalSet& { return *this |= var; }, y.Var); - } - - template <class Y> - TIntervalSet operator &(const Y& y) const { - return std::visit([&y](auto& var) { return TIntervalSet(var & y); }, Var); - } - - TIntervalSet operator &(const TIntervalSet& y) const { - return std::visit([this](auto& var) -> TIntervalSet { return *this & var; }, y.Var); - } - - template <class Y> - TIntervalSet& operator &=(const Y& y) { - std::visit(overloaded { - [this, &y](TVec& vec) { - vec &= y; - if (vec.Size() > ThresholdSize) { - Mapify(vec); - } - }, - [&y](TMap& map) { - map &= y; - } - }, Var); - return *this; - } - - TIntervalSet& operator &=(const TIntervalSet& y) { - return std::visit([this](auto& var) -> TIntervalSet& { return *this &= var; }, y.Var); - } - - template <class Y> - TIntervalSet operator -(const Y& y) const { - return std::visit([&y](auto& var) { return TIntervalSet(var - y); }, Var); - } - - TIntervalSet operator -(const TIntervalSet& y) const { - return std::visit([this](auto& var) -> TIntervalSet { return *this - var; }, y.Var); - } - - template <class Y> - TIntervalSet& operator -=(const Y& y) { - std::visit(overloaded { - [this, &y](TVec& vec) { - vec -= y; - if (vec.Size() > ThresholdSize) { - Mapify(vec); - } - }, - [&y](TMap& map) { - map -= y; - } - }, Var); - return *this; - } - - TIntervalSet& operator -=(const TIntervalSet& y) { - return std::visit([this](auto& var) -> TIntervalSet& { return *this -= var; }, y.Var); - } - -private: - void Mapify(TVec& vec) { - TMap map; - // move data from vec into map - for (auto [l, r] : vec.EndForBegin) { - map.EndForBegin.emplace_hint(map.EndForBegin.end(), l, r); - } - Var = std::move(map); - } - -}; - + } + + template <class Y> + void Subtract(const Y& y) { + *this -= y; + } + + void Subtract(T begin, T end) { + *this -= TIntervalVec<T>(begin, end); + } + + TString ToString() const { + return std::visit([](auto& var) -> TString { return var.ToString(); }, Var); + } + + void Verify() const { + std::visit([](auto& var) { var.Verify(); }, Var); + } + + size_t Size() const { + return std::visit([](auto& var) -> size_t { return var.Size(); }, Var); + } + + template <class Y> + friend bool operator ==(const TIntervalSet& x, const Y& y) { + return std::visit([&y](auto& var) -> bool { return var == y; }, x.Var); + } + + template <class X> + friend bool operator ==(const X& x, const TIntervalSet& y) { + return std::visit([&x](auto& var) -> bool { return x == var; }, y.Var); + } + + friend bool operator ==(const TIntervalSet& x, const TIntervalSet& y) { + return std::visit([&x](auto& var) -> bool { return x == var; }, y.Var); + } + + explicit operator bool() const { + return !IsEmpty(); + } + + template <class Y> + TIntervalSet operator |(const Y& y) const { + return std::visit([&y](auto& var) { return TIntervalSet(var | y); } , Var); + } + + TIntervalSet operator |(const TIntervalSet& y) const { + return std::visit([this](auto&& var) { return TIntervalSet(*this | var); }, y.Var); + } + + template <class Y> + TIntervalSet& operator |=(const Y& y) { + std::visit(overloaded { + [this, &y](TVec& vec) { + vec |= y; + if (vec.Size() > ThresholdSize) { + Mapify(vec); + } + }, + [&y](TMap& map) { + map |= y; + } + }, Var); + return *this; + } + + TIntervalSet& operator |=(const TIntervalSet& y) { + return std::visit([this](auto& var) -> TIntervalSet& { return *this |= var; }, y.Var); + } + + template <class Y> + TIntervalSet operator &(const Y& y) const { + return std::visit([&y](auto& var) { return TIntervalSet(var & y); }, Var); + } + + TIntervalSet operator &(const TIntervalSet& y) const { + return std::visit([this](auto& var) -> TIntervalSet { return *this & var; }, y.Var); + } + + template <class Y> + TIntervalSet& operator &=(const Y& y) { + std::visit(overloaded { + [this, &y](TVec& vec) { + vec &= y; + if (vec.Size() > ThresholdSize) { + Mapify(vec); + } + }, + [&y](TMap& map) { + map &= y; + } + }, Var); + return *this; + } + + TIntervalSet& operator &=(const TIntervalSet& y) { + return std::visit([this](auto& var) -> TIntervalSet& { return *this &= var; }, y.Var); + } + + template <class Y> + TIntervalSet operator -(const Y& y) const { + return std::visit([&y](auto& var) { return TIntervalSet(var - y); }, Var); + } + + TIntervalSet operator -(const TIntervalSet& y) const { + return std::visit([this](auto& var) -> TIntervalSet { return *this - var; }, y.Var); + } + + template <class Y> + TIntervalSet& operator -=(const Y& y) { + std::visit(overloaded { + [this, &y](TVec& vec) { + vec -= y; + if (vec.Size() > ThresholdSize) { + Mapify(vec); + } + }, + [&y](TMap& map) { + map -= y; + } + }, Var); + return *this; + } + + TIntervalSet& operator -=(const TIntervalSet& y) { + return std::visit([this](auto& var) -> TIntervalSet& { return *this -= var; }, y.Var); + } + +private: + void Mapify(TVec& vec) { + TMap map; + // move data from vec into map + for (auto [l, r] : vec.EndForBegin) { + map.EndForBegin.emplace_hint(map.EndForBegin.end(), l, r); + } + Var = std::move(map); + } + +}; + } // NKikimr diff --git a/ydb/core/util/interval_set_ut.cpp b/ydb/core/util/interval_set_ut.cpp index c1df7015fd..535ab61ee0 100644 --- a/ydb/core/util/interval_set_ut.cpp +++ b/ydb/core/util/interval_set_ut.cpp @@ -62,9 +62,9 @@ public: } } - template <class TIntervals> - TIntervals ToIntervalSet() const { - TIntervals set; + template <class TIntervals> + TIntervals ToIntervalSet() const { + TIntervals set; i64 prev = Max<i64>(); for (i64 i = 0; i <= 8; ++i) { if (Bits & (1 << i)) { @@ -133,9 +133,9 @@ public: }; -template <class TIntervals> -TIntervals MakeIntervalSet(ui64 n, ui32 len) { - TIntervals res; +template <class TIntervals> +TIntervals MakeIntervalSet(ui64 n, ui32 len) { + TIntervals res; for (ui32 i = 0; i < len; ) { if (n >> i & 1) { const ui32 begin = i; @@ -150,35 +150,35 @@ TIntervals MakeIntervalSet(ui64 n, ui32 len) { return res; } -#define MY_UNIT_TEST(N) \ - template <class TIntervals, const char* TestName> \ - struct TTestCase##N : public TCurrentTestCase { \ - TTestCase##N() { \ - Name_ = TestName; \ - ForceFork_ = false; \ - } \ - static THolder<NUnitTest::TBaseTestCase> Create() { \ - return ::MakeHolder<TTestCase##N>(); \ - } \ - void Execute_(NUnitTest::TTestContext&) override; \ - }; \ - struct TTestRegistration##N { \ - TTestRegistration##N() { \ - static const char NameMap[] = "IntervalMap" #N; \ - static const char NameVec[] = "IntervalVec" #N; \ - static const char NameSet[] = "IntervalSet" #N; \ - TCurrentTest::AddTest(TTestCase##N<TIntervalMap<i32>, NameMap>::Create); \ - TCurrentTest::AddTest(TTestCase##N<TIntervalVec<i32>, NameVec>::Create); \ - TCurrentTest::AddTest(TTestCase##N<TIntervalSet<i32, 2>, NameSet>::Create); \ - } \ - }; \ - static TTestRegistration##N testRegistration##N; \ - template <class TIntervals, const char* type_name> \ - void TTestCase##N<TIntervals, type_name>::Execute_(NUnitTest::TTestContext& ut_context Y_DECLARE_UNUSED) - +#define MY_UNIT_TEST(N) \ + template <class TIntervals, const char* TestName> \ + struct TTestCase##N : public TCurrentTestCase { \ + TTestCase##N() { \ + Name_ = TestName; \ + ForceFork_ = false; \ + } \ + static THolder<NUnitTest::TBaseTestCase> Create() { \ + return ::MakeHolder<TTestCase##N>(); \ + } \ + void Execute_(NUnitTest::TTestContext&) override; \ + }; \ + struct TTestRegistration##N { \ + TTestRegistration##N() { \ + static const char NameMap[] = "IntervalMap" #N; \ + static const char NameVec[] = "IntervalVec" #N; \ + static const char NameSet[] = "IntervalSet" #N; \ + TCurrentTest::AddTest(TTestCase##N<TIntervalMap<i32>, NameMap>::Create); \ + TCurrentTest::AddTest(TTestCase##N<TIntervalVec<i32>, NameVec>::Create); \ + TCurrentTest::AddTest(TTestCase##N<TIntervalSet<i32, 2>, NameSet>::Create); \ + } \ + }; \ + static TTestRegistration##N testRegistration##N; \ + template <class TIntervals, const char* type_name> \ + void TTestCase##N<TIntervals, type_name>::Execute_(NUnitTest::TTestContext& ut_context Y_DECLARE_UNUSED) + Y_UNIT_TEST_SUITE(TIntervalSetTest) { - MY_UNIT_TEST(TestEmpty) { - TIntervals a; + MY_UNIT_TEST(TestEmpty) { + TIntervals a; UNIT_ASSERT_EQUAL(a.IsEmpty(), true); a.Add(0, 1); UNIT_ASSERT_EQUAL(a.IsEmpty(), false); @@ -186,23 +186,23 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { UNIT_ASSERT_EQUAL(a.IsEmpty(), true); } - MY_UNIT_TEST(TestSpecificAdd) { - TIntervals a; + MY_UNIT_TEST(TestSpecificAdd) { + TIntervals a; a.Add(55, 56); a.Add(50, 80); - TIntervals b(50, 80); + TIntervals b(50, 80); UNIT_ASSERT_EQUAL_C(b.IsSubsetOf(a), true, "a# " << a.ToString() << " b# " << b.ToString()); UNIT_ASSERT_EQUAL_C(a.IsSubsetOf(b), true, "a# " << a.ToString() << " b# " << b.ToString()); b.Subtract(a); UNIT_ASSERT_EQUAL_C(b.IsEmpty(), true, "a# " << a.ToString() << " b# " << b.ToString()); } - MY_UNIT_TEST(TestAdd) { - TIntervals a(0, 10); + MY_UNIT_TEST(TestAdd) { + TIntervals a(0, 10); a.Add(20, 22); a.Add(44, 80); a.Add(90, 100); - TVector<TIntervals> sets; + TVector<TIntervals> sets; sets.emplace_back(0, 10); sets.emplace_back(20, 22); sets.emplace_back(44, 50); @@ -221,7 +221,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { while (counters.back() < sets.size()) { ui64 added = 0; //Cerr << "set" << Endl; - TIntervals b; + TIntervals b; for (ui32 i = 0; i < counters.size(); ++i) { added |= (1ull << counters[i]); b.Add(sets[counters[i]]); @@ -253,11 +253,11 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } } - MY_UNIT_TEST(TestAddSubtract) { - TIntervals a; + MY_UNIT_TEST(TestAddSubtract) { + TIntervals a; a.Add(4, 5); // [4, 5) { - TIntervals b(4, 5); + TIntervals b(4, 5); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -265,14 +265,14 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Add(1, 2); // [1, 2) U [4, 5) { - TIntervals b(1, 2); + TIntervals b(1, 2); UNIT_ASSERT_EQUAL_C(b.IsSubsetOf(a), true, "a# " << a.ToString() << " b# " << b.ToString()); UNIT_ASSERT_EQUAL_C(a.IsSubsetOf(b), false, "a# " << a.ToString() << " b# " << b.ToString()); b.Subtract(a); UNIT_ASSERT_EQUAL(b.IsEmpty(), true); } { - TIntervals b(4, 5); + TIntervals b(4, 5); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), false); b.Subtract(a); @@ -280,7 +280,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Add(2, 4); // [1, 5) { - TIntervals b(1, 5); + TIntervals b(1, 5); UNIT_ASSERT_EQUAL_C(b.IsSubsetOf(a), true, "a# " << a.ToString() << " b# " << b.ToString()); UNIT_ASSERT_EQUAL_C(a.IsSubsetOf(b), true, "a# " << a.ToString() << " b# " << b.ToString()); b.Subtract(a); @@ -288,7 +288,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Add(0, 1); // [0, 5) { - TIntervals b(0, 5); + TIntervals b(0, 5); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -296,7 +296,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Add(5, 6); // [0, 6) { - TIntervals b(0, 6); + TIntervals b(0, 6); UNIT_ASSERT_EQUAL_C(b.IsSubsetOf(a), true, "a# " << a.ToString() << " b# " << b.ToString()); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -304,7 +304,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Add(-1, 1); // [-1, 6) { - TIntervals b(-1, 6); + TIntervals b(-1, 6); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -312,7 +312,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Add(5, 7); // [-1, 7) { - TIntervals b(-1, 7); + TIntervals b(-1, 7); UNIT_ASSERT_EQUAL_C(b.IsSubsetOf(a), true, "a# " << a.ToString() << " b# " << b.ToString()); UNIT_ASSERT_EQUAL_C(a.IsSubsetOf(b), true, "a# " << a.ToString() << " b# " << b.ToString()); b.Subtract(a); @@ -320,7 +320,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Add(-1, 7); // [-1, 7) { - TIntervals b(-1, 7); + TIntervals b(-1, 7); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -328,7 +328,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Add(-1, 1); // [-1, 7) { - TIntervals b(-1, 7); + TIntervals b(-1, 7); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -336,7 +336,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Add(1, 7); // [-1, 7) { - TIntervals b(-1, 7); + TIntervals b(-1, 7); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -344,7 +344,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(-3, -2); // [-1, 7) { - TIntervals b(-1, 7); + TIntervals b(-1, 7); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -352,7 +352,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(-3, -1); // [-1, 7) { - TIntervals b(-1, 7); + TIntervals b(-1, 7); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -360,7 +360,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(-3, 0); // [0, 7) { - TIntervals b(0, 7); + TIntervals b(0, 7); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -368,7 +368,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(8, 9); // [0, 7) { - TIntervals b(0, 7); + TIntervals b(0, 7); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -376,7 +376,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(7, 9); // [0, 7) { - TIntervals b(0, 7); + TIntervals b(0, 7); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -384,7 +384,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(6, 9); // [0, 6) { - TIntervals b(0, 6); + TIntervals b(0, 6); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -392,7 +392,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(0, 1); // [1, 6) { - TIntervals b(1, 6); + TIntervals b(1, 6); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -400,7 +400,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(5, 6); // [1, 5) { - TIntervals b(1, 5); + TIntervals b(1, 5); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), true); b.Subtract(a); @@ -408,14 +408,14 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(2, 3); // [1, 2) U [3, 5) { - TIntervals b(1, 2); + TIntervals b(1, 2); UNIT_ASSERT_EQUAL(b.IsSubsetOf(a), true); UNIT_ASSERT_EQUAL(a.IsSubsetOf(b), false); b.Subtract(a); UNIT_ASSERT_EQUAL(b.IsEmpty(), true); } { - TIntervals b(3, 5); + TIntervals b(3, 5); UNIT_ASSERT_EQUAL_C(b.IsSubsetOf(a), true, "a# " << a.ToString() << " b# " << b.ToString()); UNIT_ASSERT_EQUAL_C(a.IsSubsetOf(b), false, "a# " << a.ToString() << " b# " << b.ToString()); b.Subtract(a); @@ -425,18 +425,18 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { UNIT_ASSERT_EQUAL(a.IsEmpty(), true); } - MY_UNIT_TEST(TestSubtract) { - TIntervals a(0, 100); // [0, 100) + MY_UNIT_TEST(TestSubtract) { + TIntervals a(0, 100); // [0, 100) a.Subtract(10, 20); // [0, 10) U [20, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 100); UNIT_ASSERT_EQUAL_C(b.IsSubsetOf(a), true, "a# " << a.ToString() << " b# " << b.ToString()); UNIT_ASSERT_EQUAL_C(a.IsSubsetOf(b), true, "a# " << a.ToString() << " b# " << b.ToString()); } a.Subtract(80, 90); // [0, 10) U [20, 80) U [90, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 80); b.Add(90, 100); UNIT_ASSERT_EQUAL_C(b.IsSubsetOf(a), true, "a# " << a.ToString() << " b# " << b.ToString()); @@ -444,7 +444,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(30, 40); // [0, 10) U [20, 30) U [40, 80) U [90, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 30); b.Add(40, 80); b.Add(90, 100); @@ -453,7 +453,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(29, 41); // [0, 10) U [20, 29) U [41, 80) U [90, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 29); b.Add(41, 80); b.Add(90, 100); @@ -462,7 +462,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(28, 41); // [0, 10) U [20, 28) U [41, 80) U [90, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 28); b.Add(41, 80); b.Add(90, 100); @@ -471,7 +471,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(27, 40); // [0, 10) U [20, 27) U [41, 80) U [90, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 27); b.Add(41, 80); b.Add(90, 100); @@ -480,7 +480,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(27, 42); // [0, 10) U [20, 27) U [42, 80) U [90, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 27); b.Add(42, 80); b.Add(90, 100); @@ -489,7 +489,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(28, 43); // [0, 10) U [20, 27) U [43, 80) U [90, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 27); b.Add(43, 80); b.Add(90, 100); @@ -498,7 +498,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(23, 24); // [0, 10) U [20, 23] U [24, 27) U [43, 80) U [90, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 23); b.Add(24, 27); b.Add(43, 80); @@ -508,7 +508,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(22, 44); // [0, 10) U [20, 22] U [44, 80) U [90, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 22); b.Add(44, 80); b.Add(90, 100); @@ -517,7 +517,7 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } a.Subtract(22, 44); // [0, 10) U [20, 22] U [44, 80) U [90, 100) { - TIntervals b(0, 10); + TIntervals b(0, 10); b.Add(20, 22); b.Add(44, 80); b.Add(90, 100); @@ -527,16 +527,16 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } - MY_UNIT_TEST(TestSubtractAgainstReference) { + MY_UNIT_TEST(TestSubtractAgainstReference) { for (ui64 aBits = 0; aBits < 128; ++aBits) { for (ui64 bBits = 0; bBits < 128; ++bBits) { TReferenceSet aRef(aBits); TReferenceSet bRef(bBits); - TIntervals a = aRef.ToIntervalSet<TIntervals>(); - TIntervals b = bRef.ToIntervalSet<TIntervals>(); + TIntervals a = aRef.ToIntervalSet<TIntervals>(); + TIntervals b = bRef.ToIntervalSet<TIntervals>(); aRef.Subtract(bRef); a.Subtract(b); - TIntervals aa = aRef.ToIntervalSet<TIntervals>(); + TIntervals aa = aRef.ToIntervalSet<TIntervals>(); if (!(a == aa)) { TReferenceSet ia(aBits); TReferenceSet ib(bBits); @@ -548,16 +548,16 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } } - MY_UNIT_TEST(TestAddAgainstReference) { + MY_UNIT_TEST(TestAddAgainstReference) { for (ui64 aBits = 0; aBits < 128; ++aBits) { for (ui64 bBits = 0; bBits < 128; ++bBits) { TReferenceSet aRef(aBits); TReferenceSet bRef(bBits); - TIntervals a = aRef.ToIntervalSet<TIntervals>(); - TIntervals b = bRef.ToIntervalSet<TIntervals>(); + TIntervals a = aRef.ToIntervalSet<TIntervals>(); + TIntervals b = bRef.ToIntervalSet<TIntervals>(); aRef.Add(bRef); a.Add(b); - TIntervals aa = aRef.ToIntervalSet<TIntervals>(); + TIntervals aa = aRef.ToIntervalSet<TIntervals>(); if (!(a == aa)) { TReferenceSet ia(aBits); TReferenceSet ib(bBits); @@ -569,13 +569,13 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } } - MY_UNIT_TEST(TestIsSubsetOfAgainstReference) { + MY_UNIT_TEST(TestIsSubsetOfAgainstReference) { for (ui64 aBits = 0; aBits < 128; ++aBits) { for (ui64 bBits = 0; bBits < 128; ++bBits) { TReferenceSet aRef(aBits); TReferenceSet bRef(bBits); - TIntervals a = aRef.ToIntervalSet<TIntervals>(); - TIntervals b = bRef.ToIntervalSet<TIntervals>(); + TIntervals a = aRef.ToIntervalSet<TIntervals>(); + TIntervals b = bRef.ToIntervalSet<TIntervals>(); bool isSubsetRef = aRef.IsSubsetOf(bRef); bool isSubset = a.IsSubsetOf(b); if (isSubset == isSubsetRef) { @@ -587,10 +587,10 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } } - MY_UNIT_TEST(TestToStringAgainstReference) { + MY_UNIT_TEST(TestToStringAgainstReference) { for (ui64 aBits = 0; aBits < 128; ++aBits) { TReferenceSet aRef(aBits); - TIntervals a = aRef.ToIntervalSet<TIntervals>(); + TIntervals a = aRef.ToIntervalSet<TIntervals>(); TString strRef = aRef.ToString(); TString str = a.ToString(); if (strRef == str) { @@ -600,142 +600,142 @@ Y_UNIT_TEST_SUITE(TIntervalSetTest) { } } - MY_UNIT_TEST(Union) { + MY_UNIT_TEST(Union) { ui32 len = 8; ui64 n = 1 << len; for (ui64 i = 0; i < n; ++i) { for (ui64 j = 0; j < n; ++j) { - const TIntervals a = MakeIntervalSet<TIntervals>(i, len); - const TIntervals b = MakeIntervalSet<TIntervals>(j, len); - const TIntervals res = a | b; - const TIntervals reference = MakeIntervalSet<TIntervals>(i | j, len); + const TIntervals a = MakeIntervalSet<TIntervals>(i, len); + const TIntervals b = MakeIntervalSet<TIntervals>(j, len); + const TIntervals res = a | b; + const TIntervals reference = MakeIntervalSet<TIntervals>(i | j, len); UNIT_ASSERT_EQUAL_C(res, reference, "a# " << a.ToString() << " b# " << b.ToString() << " res# " << res.ToString() << " reference# " << reference.ToString()); } } } - MY_UNIT_TEST(UnionInplace) { + MY_UNIT_TEST(UnionInplace) { ui32 len = 8; ui64 n = 1 << len; for (ui64 i = 0; i < n; ++i) { for (ui64 j = 0; j < n; ++j) { - const TIntervals a = MakeIntervalSet<TIntervals>(i, len); - const TIntervals b = MakeIntervalSet<TIntervals>(j, len); - TIntervals res = a; + const TIntervals a = MakeIntervalSet<TIntervals>(i, len); + const TIntervals b = MakeIntervalSet<TIntervals>(j, len); + TIntervals res = a; res |= b; - const TIntervals reference = MakeIntervalSet<TIntervals>(i | j, len); + const TIntervals reference = MakeIntervalSet<TIntervals>(i | j, len); UNIT_ASSERT_EQUAL_C(res, reference, "a# " << a.ToString() << " b# " << b.ToString() << " res# " << res.ToString() << " reference# " << reference.ToString()); } } } - MY_UNIT_TEST(UnionInplaceSelf) { + MY_UNIT_TEST(UnionInplaceSelf) { ui32 len = 8; ui64 n = 1 << len; for (ui64 i = 0; i < n; ++i) { - TIntervals res = MakeIntervalSet<TIntervals>(i, len); - TIntervals *other = &res; + TIntervals res = MakeIntervalSet<TIntervals>(i, len); + TIntervals *other = &res; res |= *other; - const TIntervals reference = MakeIntervalSet<TIntervals>(i, len); + const TIntervals reference = MakeIntervalSet<TIntervals>(i, len); UNIT_ASSERT_EQUAL(res, reference); } } - MY_UNIT_TEST(Intersection) { + MY_UNIT_TEST(Intersection) { ui32 len = 8; ui64 n = 1 << len; for (ui64 i = 0; i < n; ++i) { for (ui64 j = 0; j < n; ++j) { - const TIntervals a = MakeIntervalSet<TIntervals>(i, len); - const TIntervals b = MakeIntervalSet<TIntervals>(j, len); - const TIntervals res = a & b; - const TIntervals reference = MakeIntervalSet<TIntervals>(i & j, len); + const TIntervals a = MakeIntervalSet<TIntervals>(i, len); + const TIntervals b = MakeIntervalSet<TIntervals>(j, len); + const TIntervals res = a & b; + const TIntervals reference = MakeIntervalSet<TIntervals>(i & j, len); UNIT_ASSERT_EQUAL_C(res, reference, "a# " << a.ToString() << " b# " << b.ToString() << " res# " << res.ToString() << " reference# " << reference.ToString()); } } } - MY_UNIT_TEST(IntersectionInplace) { + MY_UNIT_TEST(IntersectionInplace) { ui32 len = 8; ui64 n = 1 << len; for (ui64 i = 0; i < n; ++i) { for (ui64 j = 0; j < n; ++j) { - const TIntervals a = MakeIntervalSet<TIntervals>(i, len); - const TIntervals b = MakeIntervalSet<TIntervals>(j, len); - TIntervals res = a; + const TIntervals a = MakeIntervalSet<TIntervals>(i, len); + const TIntervals b = MakeIntervalSet<TIntervals>(j, len); + TIntervals res = a; res &= b; - const TIntervals reference = MakeIntervalSet<TIntervals>(i & j, len); + const TIntervals reference = MakeIntervalSet<TIntervals>(i & j, len); UNIT_ASSERT_EQUAL_C(res, reference, "a# " << a.ToString() << " b# " << b.ToString() << " res# " << res.ToString() << " reference# " << reference.ToString()); } } } - MY_UNIT_TEST(IntersectionInplaceSelf) { + MY_UNIT_TEST(IntersectionInplaceSelf) { ui32 len = 8; ui64 n = 1 << len; for (ui64 i = 0; i < n; ++i) { - TIntervals res = MakeIntervalSet<TIntervals>(i, len); - TIntervals *other = &res; + TIntervals res = MakeIntervalSet<TIntervals>(i, len); + TIntervals *other = &res; res &= *other; - const TIntervals reference = MakeIntervalSet<TIntervals>(i, len); + const TIntervals reference = MakeIntervalSet<TIntervals>(i, len); UNIT_ASSERT_EQUAL(res, reference); } } - MY_UNIT_TEST(Difference) { + MY_UNIT_TEST(Difference) { ui32 len = 8; ui64 n = 1 << len; for (ui64 i = 0; i < n; ++i) { for (ui64 j = 0; j < n; ++j) { - const TIntervals a = MakeIntervalSet<TIntervals>(i, len); - const TIntervals b = MakeIntervalSet<TIntervals>(j, len); - const TIntervals res = a - b; - const TIntervals reference = MakeIntervalSet<TIntervals>(i & ~j, len); + const TIntervals a = MakeIntervalSet<TIntervals>(i, len); + const TIntervals b = MakeIntervalSet<TIntervals>(j, len); + const TIntervals res = a - b; + const TIntervals reference = MakeIntervalSet<TIntervals>(i & ~j, len); UNIT_ASSERT_EQUAL_C(res, reference, "a# " << a.ToString() << " b# " << b.ToString() << " res# " << res.ToString() << " reference# " << reference.ToString()); } } } - MY_UNIT_TEST(DifferenceInplaceSelf) { + MY_UNIT_TEST(DifferenceInplaceSelf) { ui32 len = 8; ui64 n = 1 << len; for (ui64 i = 0; i < n; ++i) { - TIntervals res = MakeIntervalSet<TIntervals>(i, len); - TIntervals *other = &res; + TIntervals res = MakeIntervalSet<TIntervals>(i, len); + TIntervals *other = &res; res -= *other; UNIT_ASSERT(!res); } } - Y_UNIT_TEST(IntervalSetTestIterator) { - using TIntervals = TIntervalSet<i32>; - for (ui64 aBits = 0; aBits < 128; ++aBits) { - TReferenceSet aRef(aBits); - TIntervals a = aRef.ToIntervalSet<TIntervals>(); - TString strRef = aRef.ToString(); - - TStringStream str; - str << "{"; - for (auto it = a.begin(); it != a.end(); ++it) { - if (it != a.begin()) { - str << " U "; - } - auto [begin, end] = *it; - str << "[" << begin << ", " << end << ")"; - } - str << "}"; - - if (strRef == str.Str()) { - UNIT_ASSERT_EQUAL_C(strRef == str.Str(), true, "str# " << str.Str() << " strRef# " << strRef - << " aBits# " << aBits); - } - } - } + Y_UNIT_TEST(IntervalSetTestIterator) { + using TIntervals = TIntervalSet<i32>; + for (ui64 aBits = 0; aBits < 128; ++aBits) { + TReferenceSet aRef(aBits); + TIntervals a = aRef.ToIntervalSet<TIntervals>(); + TString strRef = aRef.ToString(); + + TStringStream str; + str << "{"; + for (auto it = a.begin(); it != a.end(); ++it) { + if (it != a.begin()) { + str << " U "; + } + auto [begin, end] = *it; + str << "[" << begin << ", " << end << ")"; + } + str << "}"; + + if (strRef == str.Str()) { + UNIT_ASSERT_EQUAL_C(strRef == str.Str(), true, "str# " << str.Str() << " strRef# " << strRef + << " aBits# " << aBits); + } + } + } } } // NKikimr diff --git a/ydb/core/util/testactorsys.cpp b/ydb/core/util/testactorsys.cpp index 73d27bc9d9..8e709f65ea 100644 --- a/ydb/core/util/testactorsys.cpp +++ b/ydb/core/util/testactorsys.cpp @@ -19,23 +19,23 @@ public: , NodeId(nodeId) {} - ui32 GetReadyActivation(TWorkerContext& /*wctx*/, ui64 /*revolvingCounter*/) override { + ui32 GetReadyActivation(TWorkerContext& /*wctx*/, ui64 /*revolvingCounter*/) override { Y_FAIL(); } - void ReclaimMailbox(TMailboxType::EType /*mailboxType*/, ui32 /*hint*/, NActors::TWorkerId /*workerId*/, ui64 /*revolvingCounter*/) override { + void ReclaimMailbox(TMailboxType::EType /*mailboxType*/, ui32 /*hint*/, NActors::TWorkerId /*workerId*/, ui64 /*revolvingCounter*/) override { Y_FAIL(); } - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, NActors::TWorkerId /*workerId*/) override { + void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, NActors::TWorkerId /*workerId*/) override { Context->Schedule(deadline, ev, cookie, NodeId); } - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, NActors::TWorkerId /*workerId*/) override { + void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, NActors::TWorkerId /*workerId*/) override { Context->Schedule(TInstant::FromValue(deadline.GetValue()), ev, cookie, NodeId); } - void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, NActors::TWorkerId /*workerId*/) override { + void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, NActors::TWorkerId /*workerId*/) override { Context->Schedule(delta, ev, cookie, NodeId); } @@ -67,7 +67,7 @@ public: return Context->Register(actor, parentId, PoolId, hint, NodeId); } - void Prepare(TActorSystem* /*actorSystem*/, NSchedulerQueue::TReader** /*scheduleReaders*/, ui32* /*scheduleSz*/) override { + void Prepare(TActorSystem* /*actorSystem*/, NSchedulerQueue::TReader** /*scheduleReaders*/, ui32* /*scheduleSz*/) override { } void Start() override { diff --git a/ydb/core/util/testactorsys.h b/ydb/core/util/testactorsys.h index ce6ad7be10..fcf448e548 100644 --- a/ydb/core/util/testactorsys.h +++ b/ydb/core/util/testactorsys.h @@ -36,7 +36,7 @@ class TTestActorSystem { CurrentMonotonicPtr = currentMonotonic; } - void PrepareSchedules(NSchedulerQueue::TReader **readers, ui32 scheduleReadersCount) override { + void PrepareSchedules(NSchedulerQueue::TReader **readers, ui32 scheduleReadersCount) override { Readers = {readers, readers + scheduleReadersCount}; } diff --git a/ydb/core/util/time_series_vec.h b/ydb/core/util/time_series_vec.h index e0753e06ee..588035990d 100644 --- a/ydb/core/util/time_series_vec.h +++ b/ydb/core/util/time_series_vec.h @@ -1,217 +1,217 @@ -#pragma once - -#include <util/datetime/base.h> -#include <util/generic/vector.h> -#include <util/generic/hash.h> -#include <util/system/types.h> - -namespace NKikimr { - -template <class T, ui64 IntervalUs = 10'000> class TTimeSeriesMap; -template <class T, ui64 IntervalUs = 10'000> class TTimeSeriesVec; - -// Unbounded and sparse variant of TTimeSeriesVec. -template <class T, ui64 IntervalUs> -class TTimeSeriesMap { - THashMap<ui64, double> Values; // id -> value; unsorted -public: - void Clear() { - Values.clear(); - } - - TInstant Align(TInstant instant) const { - return TInstant::MicroSeconds(instant.MicroSeconds() / IntervalUs * IntervalUs); - } - - // Amount of stored intervals - size_t Size() const { - return Values.size(); - } - - static constexpr TDuration Interval() noexcept { - return TDuration::MicroSeconds(IntervalUs); - } - - void Add(TInstant instant, T value) { - Values[instant.MicroSeconds() / IntervalUs] += value; - } - - friend class TTimeSeriesVec<T>; -}; - -// Time series storage and aggregator with compile-time defined discretization -// Values added up and aligned according to grid with `IntervalUs` steps -// Fixed-size circular buffer is used as storage -// Only last consecutive `Size()` intervals are stored -template <class T, ui64 IntervalUs> -class TTimeSeriesVec { - TVector<T> Values; // circular buffer of intervals +#pragma once + +#include <util/datetime/base.h> +#include <util/generic/vector.h> +#include <util/generic/hash.h> +#include <util/system/types.h> + +namespace NKikimr { + +template <class T, ui64 IntervalUs = 10'000> class TTimeSeriesMap; +template <class T, ui64 IntervalUs = 10'000> class TTimeSeriesVec; + +// Unbounded and sparse variant of TTimeSeriesVec. +template <class T, ui64 IntervalUs> +class TTimeSeriesMap { + THashMap<ui64, double> Values; // id -> value; unsorted +public: + void Clear() { + Values.clear(); + } + + TInstant Align(TInstant instant) const { + return TInstant::MicroSeconds(instant.MicroSeconds() / IntervalUs * IntervalUs); + } + + // Amount of stored intervals + size_t Size() const { + return Values.size(); + } + + static constexpr TDuration Interval() noexcept { + return TDuration::MicroSeconds(IntervalUs); + } + + void Add(TInstant instant, T value) { + Values[instant.MicroSeconds() / IntervalUs] += value; + } + + friend class TTimeSeriesVec<T>; +}; + +// Time series storage and aggregator with compile-time defined discretization +// Values added up and aligned according to grid with `IntervalUs` steps +// Fixed-size circular buffer is used as storage +// Only last consecutive `Size()` intervals are stored +template <class T, ui64 IntervalUs> +class TTimeSeriesVec { + TVector<T> Values; // circular buffer of intervals ui64 Id = 0; // id (instant/interval) of the last value in buffer -public: - // Make empty time series - explicit TTimeSeriesVec(size_t size) { - Values.resize(size, T()); +public: + // Make empty time series + explicit TTimeSeriesVec(size_t size) { + Values.resize(size, T()); Id = size - 1; - } - - // Make a subseries holding values within given time range [begin; end) - TTimeSeriesVec(const TTimeSeriesVec& source, TInstant begin, TInstant end) { + } + + // Make a subseries holding values within given time range [begin; end) + TTimeSeriesVec(const TTimeSeriesVec& source, TInstant begin, TInstant end) { ui64 beginId = Max(source.BeginId(), begin.MicroSeconds() / IntervalUs); ui64 endId = Min(source.EndId(), end.MicroSeconds() / IntervalUs); - if (beginId < endId) { - Values.reserve(endId - beginId); - for (ui64 id = beginId; id != endId; id++) { - Values.emplace_back(source.Values[id % source.Size()]); - } - Id = endId - 1; - } else { - Values.resize(1, T()); - Id = 0; - } - } - - void Clear() { - for (T& value : Values) { - value = T(); - } - } - - TInstant Align(TInstant instant) const { - return TInstant::MicroSeconds(instant.MicroSeconds() / IntervalUs * IntervalUs); - } - - // Max amount of intervals - size_t Size() const { - return Values.size(); - } - - static constexpr TDuration Interval() noexcept { - return TDuration::MicroSeconds(IntervalUs); - } - - // Instant of start of the first available interval (the oldest one) - TInstant Begin() const { - return TInstant::MicroSeconds(BeginId() * IntervalUs); - } - - // Instant of interval after the last available one (the newest one) - TInstant End() const { - return TInstant::MicroSeconds(EndId() * IntervalUs); - } - - // Instant of the next interval - TInstant Next(TInstant instant) const { - return TInstant::MicroSeconds(instant.MicroSeconds() + IntervalUs); - } - - // Get value of interval containing instant - T Get(TInstant instant) const { + if (beginId < endId) { + Values.reserve(endId - beginId); + for (ui64 id = beginId; id != endId; id++) { + Values.emplace_back(source.Values[id % source.Size()]); + } + Id = endId - 1; + } else { + Values.resize(1, T()); + Id = 0; + } + } + + void Clear() { + for (T& value : Values) { + value = T(); + } + } + + TInstant Align(TInstant instant) const { + return TInstant::MicroSeconds(instant.MicroSeconds() / IntervalUs * IntervalUs); + } + + // Max amount of intervals + size_t Size() const { + return Values.size(); + } + + static constexpr TDuration Interval() noexcept { + return TDuration::MicroSeconds(IntervalUs); + } + + // Instant of start of the first available interval (the oldest one) + TInstant Begin() const { + return TInstant::MicroSeconds(BeginId() * IntervalUs); + } + + // Instant of interval after the last available one (the newest one) + TInstant End() const { + return TInstant::MicroSeconds(EndId() * IntervalUs); + } + + // Instant of the next interval + TInstant Next(TInstant instant) const { + return TInstant::MicroSeconds(instant.MicroSeconds() + IntervalUs); + } + + // Get value of interval containing instant + T Get(TInstant instant) const { ui64 id = instant.MicroSeconds() / IntervalUs; - return Values[id % Size()]; - } - - size_t Add(const TTimeSeriesVec& o, TInstant beginLimit = TInstant::Max()) { - ui64 idx = o.BeginId() % o.Size(); - size_t result = Add(o.Begin(), &o.Values[0] + idx, o.Size() - idx, beginLimit); - if (idx > 0) { - result += Add(o.Begin() + o.Interval() * (o.Size() - idx), &o.Values[0], idx, beginLimit); - } - return result; - } - - // Add values from array `values` of size `size` with custom `interval` (optimized for IntervalUs) - // History overwrite is allowed up to `beginLimit` (excluded) - // Returns number of added (or skipped) values - size_t Add(TDuration interval, TInstant start, const T* values, size_t size, TInstant beginLimit = TInstant::Max()) { - if (interval.MicroSeconds() == IntervalUs) { - return Add(start, values, size, beginLimit); - } else { - size_t result = 0; - while (size-- && Add(start, *values++, beginLimit)) { - result++; - start += interval; - } - return result; + return Values[id % Size()]; + } + + size_t Add(const TTimeSeriesVec& o, TInstant beginLimit = TInstant::Max()) { + ui64 idx = o.BeginId() % o.Size(); + size_t result = Add(o.Begin(), &o.Values[0] + idx, o.Size() - idx, beginLimit); + if (idx > 0) { + result += Add(o.Begin() + o.Interval() * (o.Size() - idx), &o.Values[0], idx, beginLimit); } - } - - // Add single value at given instant - // History overwrite is allowed up to `beginLimit` (excluded) - // Returns true iff addition was successful or skipped (too old) - bool Add(TInstant instant, T value, TInstant beginLimit = TInstant::Max()) { + return result; + } + + // Add values from array `values` of size `size` with custom `interval` (optimized for IntervalUs) + // History overwrite is allowed up to `beginLimit` (excluded) + // Returns number of added (or skipped) values + size_t Add(TDuration interval, TInstant start, const T* values, size_t size, TInstant beginLimit = TInstant::Max()) { + if (interval.MicroSeconds() == IntervalUs) { + return Add(start, values, size, beginLimit); + } else { + size_t result = 0; + while (size-- && Add(start, *values++, beginLimit)) { + result++; + start += interval; + } + return result; + } + } + + // Add single value at given instant + // History overwrite is allowed up to `beginLimit` (excluded) + // Returns true iff addition was successful or skipped (too old) + bool Add(TInstant instant, T value, TInstant beginLimit = TInstant::Max()) { ui64 id = instant.MicroSeconds() / IntervalUs; - return Add(id, value, beginLimit); - } - - size_t Add(const TTimeSeriesMap<T>& tsm, TInstant beginLimit = TInstant::Max()) { - size_t result = 0; - for (auto [id, value] : tsm.Values) { - if (Add(id, value, beginLimit)) { - result++; - } - } - return result; - } - -private: + return Add(id, value, beginLimit); + } + + size_t Add(const TTimeSeriesMap<T>& tsm, TInstant beginLimit = TInstant::Max()) { + size_t result = 0; + for (auto [id, value] : tsm.Values) { + if (Add(id, value, beginLimit)) { + result++; + } + } + return result; + } + +private: ui64 BeginId() const { - return Id + 1 - Size(); - } - + return Id + 1 - Size(); + } + ui64 EndId() const { - return Id + 1; - } - - // Optimized Add() for values with interval equal to IntervalUs - size_t Add(TInstant start, const T* values, size_t size, TInstant beginLimit = TInstant::Max()) { - ui64 id1 = start.MicroSeconds() / IntervalUs; - ui64 id2 = id1 + size; - if (beginLimit != TInstant::Max()) { // enforce limit - id2 = Min(id2, beginLimit.MicroSeconds() / IntervalUs + Size() - 1); - } - Propagate(id2 - 1); - ui64 skip = 0; - if (BeginId() > id1) { - skip = BeginId() - id1; - } - values += skip; - size -= skip; - size_t added = 0; - for (ui64 id = id1 + skip; id < id2; id++, added++) { - Values[id % Size()] += *values++; - } - return added; - } - - bool Add(ui64 id, T value, TInstant beginLimit = TInstant::Max()) { - if (beginLimit != TInstant::Max()) { - ui64 limitId = beginLimit.MicroSeconds() / IntervalUs + Size() - 1; - if (id > limitId) { - Propagate(limitId); // actually do propagation even on failure to be consistent - return false; // limit exceeded - } - } - Propagate(id); - if (id < BeginId()) { - return true; // skip value from past, successfully - } - Values[id % Size()] += value; - return true; // added successfully - } - + return Id + 1; + } + + // Optimized Add() for values with interval equal to IntervalUs + size_t Add(TInstant start, const T* values, size_t size, TInstant beginLimit = TInstant::Max()) { + ui64 id1 = start.MicroSeconds() / IntervalUs; + ui64 id2 = id1 + size; + if (beginLimit != TInstant::Max()) { // enforce limit + id2 = Min(id2, beginLimit.MicroSeconds() / IntervalUs + Size() - 1); + } + Propagate(id2 - 1); + ui64 skip = 0; + if (BeginId() > id1) { + skip = BeginId() - id1; + } + values += skip; + size -= skip; + size_t added = 0; + for (ui64 id = id1 + skip; id < id2; id++, added++) { + Values[id % Size()] += *values++; + } + return added; + } + + bool Add(ui64 id, T value, TInstant beginLimit = TInstant::Max()) { + if (beginLimit != TInstant::Max()) { + ui64 limitId = beginLimit.MicroSeconds() / IntervalUs + Size() - 1; + if (id > limitId) { + Propagate(limitId); // actually do propagation even on failure to be consistent + return false; // limit exceeded + } + } + Propagate(id); + if (id < BeginId()) { + return true; // skip value from past, successfully + } + Values[id % Size()] += value; + return true; // added successfully + } + void Propagate(ui64 id) { if (id <= Id) { - return; - } + return; + } if (id - Id >= Size()) { - Clear(); - Id = id; - } else { - while (Id < id) { - Values[++Id % Size()] = T(); - } - } - } -}; - -} + Clear(); + Id = id; + } else { + while (Id < id) { + Values[++Id % Size()] = T(); + } + } + } +}; + +} diff --git a/ydb/core/util/time_series_vec_ut.cpp b/ydb/core/util/time_series_vec_ut.cpp index ca5aa41d88..e117b5df49 100644 --- a/ydb/core/util/time_series_vec_ut.cpp +++ b/ydb/core/util/time_series_vec_ut.cpp @@ -1,28 +1,28 @@ -#include <library/cpp/testing/unittest/registar.h> -#include "time_series_vec.h" - -namespace NKikimr { - -Y_UNIT_TEST_SUITE(TTimeSeriesVecTest) { - Y_UNIT_TEST(Smoke) { - constexpr TDuration Interval = TDuration::MilliSeconds(1); - constexpr size_t Size = 3; - TTimeSeriesVec<int, Interval.MicroSeconds()> tsv(Size); - UNIT_ASSERT(tsv.Size() == Size); - TInstant now = TInstant::Now(); - tsv.Add(now, 10); - tsv.Add(now, 20); - UNIT_ASSERT(tsv.Get(now) == 30); - tsv.Add(now + Interval, 40); - UNIT_ASSERT(tsv.Get(now) == 30); - UNIT_ASSERT(tsv.Get(now + Interval) == 40); - - int total = 0; - for (TInstant i = tsv.Begin(), e = tsv.End(); i != e; i = tsv.Next(i)) { - total += tsv.Get(i); - } - UNIT_ASSERT(total == 70); - } +#include <library/cpp/testing/unittest/registar.h> +#include "time_series_vec.h" + +namespace NKikimr { + +Y_UNIT_TEST_SUITE(TTimeSeriesVecTest) { + Y_UNIT_TEST(Smoke) { + constexpr TDuration Interval = TDuration::MilliSeconds(1); + constexpr size_t Size = 3; + TTimeSeriesVec<int, Interval.MicroSeconds()> tsv(Size); + UNIT_ASSERT(tsv.Size() == Size); + TInstant now = TInstant::Now(); + tsv.Add(now, 10); + tsv.Add(now, 20); + UNIT_ASSERT(tsv.Get(now) == 30); + tsv.Add(now + Interval, 40); + UNIT_ASSERT(tsv.Get(now) == 30); + UNIT_ASSERT(tsv.Get(now + Interval) == 40); + + int total = 0; + for (TInstant i = tsv.Begin(), e = tsv.End(); i != e; i = tsv.Next(i)) { + total += tsv.Get(i); + } + UNIT_ASSERT(total == 70); + } Y_UNIT_TEST(IndexesArePositive) { constexpr TDuration Interval = TDuration::MilliSeconds(1); @@ -80,12 +80,12 @@ Y_UNIT_TEST_SUITE(TTimeSeriesVecTest) { } int data[3] = {5, 6, 7}; - tsv.Add(tsv.Interval(), tsv.End(), data, 3); + tsv.Add(tsv.Interval(), tsv.End(), data, 3); UNIT_ASSERT(tsv.Get(tsv.Begin()) == 3); UNIT_ASSERT(tsv.Get(tsv.End() - Interval) == 7); - tsv.Add(tsv.Interval(), tsv.Begin(), data, 3); + tsv.Add(tsv.Interval(), tsv.Begin(), data, 3); UNIT_ASSERT(tsv.Get(tsv.Begin()) == 8); // 3 + 5 UNIT_ASSERT(tsv.Get(tsv.Begin() + Interval) == 10); // 4 + 6 @@ -95,7 +95,7 @@ Y_UNIT_TEST_SUITE(TTimeSeriesVecTest) { int data2[7] = {8, 9, 10, 11, 12, 13, 14}; - tsv.Add(tsv.Interval(), tsv.End() - Interval, data2, 7); + tsv.Add(tsv.Interval(), tsv.End() - Interval, data2, 7); UNIT_ASSERT(tsv.Get(tsv.Begin()) == 10); UNIT_ASSERT(tsv.Get(tsv.End() - Interval) == 14); @@ -119,6 +119,6 @@ Y_UNIT_TEST_SUITE(TTimeSeriesVecTest) { UNIT_ASSERT(tsv.Get(tsv.Begin() + Interval * 3) == 3); // 3 UNIT_ASSERT(tsv.Get(tsv.Begin() + Interval * 4) == 11); // 4 + 7 } -} - -} // NKikimr +} + +} // NKikimr diff --git a/ydb/core/util/token_bucket.h b/ydb/core/util/token_bucket.h index 060f8c75a6..3d1be1b39e 100644 --- a/ydb/core/util/token_bucket.h +++ b/ydb/core/util/token_bucket.h @@ -1,74 +1,74 @@ -#pragma once - -#include <util/datetime/base.h> - +#pragma once + +#include <util/datetime/base.h> + #include <cmath> -namespace NKikimr { - -class TTokenBucket { - double Tokens = 0.0; // tokens currenty in bucket - double Rate = 0.0; // tokens filling rate [tokens/sec] - double Capacity = 0.0; // maximum amount of tokens allowed in bucket - TInstant LastFill = TInstant::Zero(); - -public: - // Create unlimited bucket - // NOTE: any bucket is created fully filled - TTokenBucket() { - SetUnlimited(); - } - - // Reset bucket into unlimited mode - void SetUnlimited() { - Tokens = std::numeric_limits<double>::infinity(); // tokens currenty in bucket - Rate = 0.0; // tokens fillig rate [tokens/sec] - Capacity = std::numeric_limits<double>::infinity(); // maximum amount of tokens allowed in bucket - } - +namespace NKikimr { + +class TTokenBucket { + double Tokens = 0.0; // tokens currenty in bucket + double Rate = 0.0; // tokens filling rate [tokens/sec] + double Capacity = 0.0; // maximum amount of tokens allowed in bucket + TInstant LastFill = TInstant::Zero(); + +public: + // Create unlimited bucket + // NOTE: any bucket is created fully filled + TTokenBucket() { + SetUnlimited(); + } + + // Reset bucket into unlimited mode + void SetUnlimited() { + Tokens = std::numeric_limits<double>::infinity(); // tokens currenty in bucket + Rate = 0.0; // tokens fillig rate [tokens/sec] + Capacity = std::numeric_limits<double>::infinity(); // maximum amount of tokens allowed in bucket + } + bool IsUnlimited() const { return Tokens == std::numeric_limits<double>::infinity() && Rate == 0.0 && Capacity == std::numeric_limits<double>::infinity(); } - // Reset rate - void SetRate(double rate) { - Rate = rate; - } - - // Reset capacity - void SetCapacity(double capacity) { - Capacity = capacity; - if (Tokens > Capacity) { - Tokens = Capacity; - } - } - - // Fill bucket with tokens, should be done just before Take() - void Fill(TInstant now) { - // NOTE: LastFill is allowed to be zero, the following code will work OK - TDuration elapsed = now - LastFill; - Tokens += elapsed.SecondsFloat() * Rate; - if (Tokens > Capacity) { - Tokens = Capacity; - } - LastFill = now; - } - - // Use accumulated tokens - void Take(double amount) { - Tokens -= amount; - } - - // Fill and take if available, returns taken amount - double FillAndTryTake(TInstant now, double amount) { - Fill(now); - amount = Min(amount, Tokens); - Take(amount); - return amount; - } - + // Reset rate + void SetRate(double rate) { + Rate = rate; + } + + // Reset capacity + void SetCapacity(double capacity) { + Capacity = capacity; + if (Tokens > Capacity) { + Tokens = Capacity; + } + } + + // Fill bucket with tokens, should be done just before Take() + void Fill(TInstant now) { + // NOTE: LastFill is allowed to be zero, the following code will work OK + TDuration elapsed = now - LastFill; + Tokens += elapsed.SecondsFloat() * Rate; + if (Tokens > Capacity) { + Tokens = Capacity; + } + LastFill = now; + } + + // Use accumulated tokens + void Take(double amount) { + Tokens -= amount; + } + + // Fill and take if available, returns taken amount + double FillAndTryTake(TInstant now, double amount) { + Fill(now); + amount = Min(amount, Tokens); + Take(amount); + return amount; + } + // don't forget to Fill or use FillAndNextAvailableDelay() instead TDuration NextAvailableDelay() const { if (IsUnlimited() || Available() >= 0) { @@ -83,22 +83,22 @@ public: return NextAvailableDelay(); } - // Amount of accumulated tokens - double Available() const { - return Tokens; - } - - double GetRate() const { - return Rate; - } - - double GetCapacity() const { - return Capacity; - } - - TInstant GetLastFill() const { - return LastFill; - } -}; - -} // namespace NKikimr + // Amount of accumulated tokens + double Available() const { + return Tokens; + } + + double GetRate() const { + return Rate; + } + + double GetCapacity() const { + return Capacity; + } + + TInstant GetLastFill() const { + return LastFill; + } +}; + +} // namespace NKikimr diff --git a/ydb/core/util/token_bucket_ut.cpp b/ydb/core/util/token_bucket_ut.cpp index ef35e78ccd..f974248e12 100644 --- a/ydb/core/util/token_bucket_ut.cpp +++ b/ydb/core/util/token_bucket_ut.cpp @@ -1,72 +1,72 @@ -#include <library/cpp/testing/unittest/registar.h> -#include "token_bucket.h" - -namespace NKikimr { - -Y_UNIT_TEST_SUITE(TTokenBucketTest) { - - static constexpr double Eps = 1e-9; - - Y_UNIT_TEST(Unlimited) { - TTokenBucket tb; - UNIT_ASSERT(tb.Available() == std::numeric_limits<double>::infinity()); - tb.Take(100500); - UNIT_ASSERT(tb.Available() == std::numeric_limits<double>::infinity()); - TInstant now = TInstant::Now(); - tb.Fill(now); - now += TDuration::Seconds(1); - UNIT_ASSERT(tb.Available() == std::numeric_limits<double>::infinity()); - UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 42), 42, Eps); - } - - Y_UNIT_TEST(Limited) { - TTokenBucket tb; - tb.SetRate(100); - tb.SetCapacity(1000); - UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 1000, Eps); - TInstant now = TInstant::Now(); - tb.Fill(now); - UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 1000, Eps); - tb.Take(500); - UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 500, Eps); - now += TDuration::Seconds(1); - UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 100500), 600, Eps); - now += TDuration::Days(1); - UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 100500), 1000, Eps); - now += TDuration::Seconds(1); - UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 100500), 100, Eps); - now += TDuration::Seconds(2); - UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 100), 100, Eps); - UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 50), 50, Eps); - now += TDuration::Seconds(1); - UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 200), 150, Eps); - tb.Take(100); - now += TDuration::Seconds(3); - tb.Fill(now); - UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 200, Eps); - - tb.SetRate(200); - now += TDuration::Seconds(1); - tb.Fill(now); - UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 400, Eps); - now += TDuration::Seconds(1); - tb.Fill(now); - UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 600, Eps); - now += TDuration::Days(365); - tb.Fill(now); - UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 1000, Eps); - - tb.SetCapacity(500); - UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 500, Eps); - tb.SetCapacity(2000); - UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 500, Eps); - now += TDuration::Days(365); - tb.Fill(now); - UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 2000, Eps); - - tb.SetUnlimited(); - UNIT_ASSERT(tb.Available() == std::numeric_limits<double>::infinity()); - } +#include <library/cpp/testing/unittest/registar.h> +#include "token_bucket.h" + +namespace NKikimr { + +Y_UNIT_TEST_SUITE(TTokenBucketTest) { + + static constexpr double Eps = 1e-9; + + Y_UNIT_TEST(Unlimited) { + TTokenBucket tb; + UNIT_ASSERT(tb.Available() == std::numeric_limits<double>::infinity()); + tb.Take(100500); + UNIT_ASSERT(tb.Available() == std::numeric_limits<double>::infinity()); + TInstant now = TInstant::Now(); + tb.Fill(now); + now += TDuration::Seconds(1); + UNIT_ASSERT(tb.Available() == std::numeric_limits<double>::infinity()); + UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 42), 42, Eps); + } + + Y_UNIT_TEST(Limited) { + TTokenBucket tb; + tb.SetRate(100); + tb.SetCapacity(1000); + UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 1000, Eps); + TInstant now = TInstant::Now(); + tb.Fill(now); + UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 1000, Eps); + tb.Take(500); + UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 500, Eps); + now += TDuration::Seconds(1); + UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 100500), 600, Eps); + now += TDuration::Days(1); + UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 100500), 1000, Eps); + now += TDuration::Seconds(1); + UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 100500), 100, Eps); + now += TDuration::Seconds(2); + UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 100), 100, Eps); + UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 50), 50, Eps); + now += TDuration::Seconds(1); + UNIT_ASSERT_DOUBLES_EQUAL(tb.FillAndTryTake(now, 200), 150, Eps); + tb.Take(100); + now += TDuration::Seconds(3); + tb.Fill(now); + UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 200, Eps); + + tb.SetRate(200); + now += TDuration::Seconds(1); + tb.Fill(now); + UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 400, Eps); + now += TDuration::Seconds(1); + tb.Fill(now); + UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 600, Eps); + now += TDuration::Days(365); + tb.Fill(now); + UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 1000, Eps); + + tb.SetCapacity(500); + UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 500, Eps); + tb.SetCapacity(2000); + UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 500, Eps); + now += TDuration::Days(365); + tb.Fill(now); + UNIT_ASSERT_DOUBLES_EQUAL(tb.Available(), 2000, Eps); + + tb.SetUnlimited(); + UNIT_ASSERT(tb.Available() == std::numeric_limits<double>::infinity()); + } Y_UNIT_TEST(DelayCalculation) { TTokenBucket tb; @@ -85,6 +85,6 @@ Y_UNIT_TEST_SUITE(TTokenBucketTest) { tb.Fill(now); UNIT_ASSERT_VALUES_EQUAL(tb.NextAvailableDelay(), TDuration::Zero()); } -} - -} // NKikimr +} + +} // NKikimr diff --git a/ydb/core/util/ut/ya.make b/ydb/core/util/ut/ya.make index 315713cad8..8826a4035f 100644 --- a/ydb/core/util/ut/ya.make +++ b/ydb/core/util/ut/ya.make @@ -44,8 +44,8 @@ SRCS( queue_inplace_ut.cpp queue_oneone_inplace_ut.cpp simple_cache_ut.cpp - time_series_vec_ut.cpp - token_bucket_ut.cpp + time_series_vec_ut.cpp + token_bucket_ut.cpp ulid_ut.cpp wildcard_ut.cpp ) diff --git a/ydb/core/util/ya.make b/ydb/core/util/ya.make index 4f325d8fcb..27d9fe30bd 100644 --- a/ydb/core/util/ya.make +++ b/ydb/core/util/ya.make @@ -50,8 +50,8 @@ SRCS( testactorsys.h text.cpp text.h - time_series_vec.h - token_bucket.h + time_series_vec.h + token_bucket.h throughput_meter.h tuples.h type_alias.h diff --git a/ydb/core/viewer/protos/viewer.proto b/ydb/core/viewer/protos/viewer.proto index 9f6c822a89..b47263ae8b 100644 --- a/ydb/core/viewer/protos/viewer.proto +++ b/ydb/core/viewer/protos/viewer.proto @@ -182,10 +182,10 @@ message TMetaRtmrOperationInfo { string Options = 1; // Force pause between operation executions on one key; seconds uint32 PostponeTimeout = 2; - // Pacing period for postponed keys (maximum error added to PostponeTimeout); seconds - uint32 PostponePacePeriod = 13; - // Force pause before first operation execution on one key; seconds - uint32 BatchTimeout = 11; + // Pacing period for postponed keys (maximum error added to PostponeTimeout); seconds + uint32 PostponePacePeriod = 13; + // Force pause before first operation execution on one key; seconds + uint32 BatchTimeout = 11; // Max age of data being read for operation execution; seconds uint32 MaxTimeBack = 3; // Operation instance recreation period; seconds @@ -202,8 +202,8 @@ message TMetaRtmrOperationInfo { string WorkingDirectory = 9; // Dynamic library name string LibraryName = 10; - // Tolerance to failures during operation execution - uint32 SuspendThreshold = 12; + // Tolerance to failures during operation execution + uint32 SuspendThreshold = 12; }; message TStats { diff --git a/ydb/library/aclib/aclib.cpp b/ydb/library/aclib/aclib.cpp index 946497ea30..1ad4e9648c 100644 --- a/ydb/library/aclib/aclib.cpp +++ b/ydb/library/aclib/aclib.cpp @@ -171,7 +171,7 @@ bool TSecurityObject::CheckAccess(ui32 access, const TUserToken& user) const { switch(static_cast<EAccessType>(ace.GetAccessType())) { case EAccessType::Deny: if (access && ace.GetAccessRight() != 0) - return false; // deny entries have precedence over allow entries + return false; // deny entries have precedence over allow entries break; case EAccessType::Allow: accessRightsLeft &= ~(accessRightsLeft & ace.GetAccessRight()); // some rights allowed @@ -263,26 +263,26 @@ TInstant TSecurityObject::GetExpireTime() const { return TInstant::MilliSeconds(static_cast<const NACLibProto::TSecurityObject&>(*this).GetExpireTime()); } -TString TSecurityObject::ToString() const Y_NO_SANITIZE("undefined") { - return static_cast<const TACL&>(GetACL()).ToString(); -} - -void TSecurityObject::FromString(const TString& string) Y_NO_SANITIZE("undefined") { - static_cast<TACL*>(MutableACL())->FromString(string); -} - +TString TSecurityObject::ToString() const Y_NO_SANITIZE("undefined") { + return static_cast<const TACL&>(GetACL()).ToString(); +} + +void TSecurityObject::FromString(const TString& string) Y_NO_SANITIZE("undefined") { + static_cast<TACL*>(MutableACL())->FromString(string); +} + void TSecurityObject::ApplyDiff(const NACLibProto::TDiffACL& diffACL) Y_NO_SANITIZE("undefined") { static_cast<TACL*>(MutableACL())->ApplyDiff(diffACL); } -bool TSecurityObject::operator ==(const NACLib::TSecurityObject& rhs) const { - return IsContainer == rhs.IsContainer && NProtoBuf::IsEqual(*this, rhs); -} - -bool TSecurityObject::operator !=(const NACLib::TSecurityObject& rhs) const { - return !(*this == rhs); -} - +bool TSecurityObject::operator ==(const NACLib::TSecurityObject& rhs) const { + return IsContainer == rhs.IsContainer && NProtoBuf::IsEqual(*this, rhs); +} + +bool TSecurityObject::operator !=(const NACLib::TSecurityObject& rhs) const { + return !(*this == rhs); +} + std::pair<ui32, ui32> TACL::AddAccess(NACLib::EAccessType type, ui32 access, const NACLib::TSID& sid, ui32 inheritance) Y_NO_SANITIZE("undefined") { for (int i = 0; i < static_cast<int>(ACESize()); ++i) { const NACLibProto::TACE& ace(GetACE(i)); @@ -646,7 +646,7 @@ void TACL::FromString(const TString& string) { FromString(ace, string.substr(start_pos, end_pos == TString::npos ? end_pos : end_pos - start_pos)); if (end_pos == TString::npos) break; - it = string.begin() + end_pos; + it = string.begin() + end_pos; } } diff --git a/ydb/library/aclib/aclib.h b/ydb/library/aclib/aclib.h index 655ca4b669..9d8ee84450 100644 --- a/ydb/library/aclib/aclib.h +++ b/ydb/library/aclib/aclib.h @@ -142,10 +142,10 @@ public: void ApplyDiff(const NACLibProto::TDiffACL& diffACL); void ClearAccess(); TInstant GetExpireTime() const; - TString ToString() const; // simple text format - void FromString(const TString& string); // simple text format - bool operator == (const TSecurityObject& rhs) const; - bool operator != (const TSecurityObject& rhs) const; + TString ToString() const; // simple text format + void FromString(const TString& string); // simple text format + bool operator == (const TSecurityObject& rhs) const; + bool operator != (const TSecurityObject& rhs) const; protected: bool IsContainer; diff --git a/ydb/library/schlab/mon/mon.cpp b/ydb/library/schlab/mon/mon.cpp index fc06b412ae..ad36e869d2 100644 --- a/ydb/library/schlab/mon/mon.cpp +++ b/ydb/library/schlab/mon/mon.cpp @@ -1,35 +1,35 @@ -#include "mon.h" - +#include "mon.h" + #include <ydb/library/schlab/schemu/schemu.h> #include <library/cpp/monlib/service/pages/mon_page.h> #include <library/cpp/monlib/service/pages/resource_mon_page.h> #include <library/cpp/monlib/service/pages/templates.h> #include <library/cpp/resource/resource.h> #include <library/cpp/html/pcdata/pcdata.h> -#include <util/stream/str.h> - -namespace NKikimr { - -using namespace NMonitoring; - -class TSchArmMonPage : public IMonPage { -private: - TString SchVizUrl; +#include <util/stream/str.h> + +namespace NKikimr { + +using namespace NMonitoring; + +class TSchArmMonPage : public IMonPage { +private: + TString SchVizUrl; TString JsonConfig; bool IsRunning = false; TMutex EmuMutex; THolder<NSchLab::TSchEmu> SchEmu; -public: - TSchArmMonPage(const TString& path, const TString& schVizUrl) - : IMonPage(path, "SchArm") - , SchVizUrl(schVizUrl) - {} - +public: + TSchArmMonPage(const TString& path, const TString& schVizUrl) + : IMonPage(path, "SchArm") + , SchVizUrl(schVizUrl) + {} + virtual void Output(IMonHttpRequest& request) { TGuard<TMutex> guard(EmuMutex); - - TStringStream out; - try { + + TStringStream out; + try { if (request.GetMethod() == HTTP_METHOD_GET) { if (request.GetParams().Get("mode") == "") { OutputIndex(request, out); @@ -44,31 +44,31 @@ public: } else { ythrow yexception() << "Bad request, expected mode=setconfig"; } - } else { + } else { ythrow yexception() << "Unexpected request method# " << (i32)request.GetMethod(); - } - } catch (...) { - out.Clear(); - out << HTTPOKTEXT; - out << "exception: " << CurrentExceptionMessage(); - } - + } + } catch (...) { + out.Clear(); + out << HTTPOKTEXT; + out << "exception: " << CurrentExceptionMessage(); + } + request.Output() << out.Str(); - } - -private: + } + +private: void OutputIndex(const IMonHttpRequest& request, IOutputStream& out) { TGuard<TMutex> guard(EmuMutex); - Y_UNUSED(request); - out << HTTPOKHTML; - HTML(out) { - out << NResource::Find("schlab/scharm.html") - << "<script type=\"text/javascript\">\n" + Y_UNUSED(request); + out << HTTPOKHTML; + HTML(out) { + out << NResource::Find("schlab/scharm.html") + << "<script type=\"text/javascript\">\n" << " $('#btnArm').click(function(){scharm.sendCfg(function(){window.open('" << SchVizUrl << "','_blank');});});\n" - << "</script>\n"; - } - } + << "</script>\n"; + } + } void InputConfig(const IMonHttpRequest& request, IOutputStream& out) { TGuard<TMutex> guard(EmuMutex); @@ -90,109 +90,109 @@ private: SchEmu->OutputLogJson(out); } } -}; - -class TSchVizMonPage : public IMonPage { -private: - TString DataUrl; -public: - TSchVizMonPage(const TString& path, const TString& dataUrl) - : IMonPage(path, "SchViz") - , DataUrl(dataUrl) - {} - +}; + +class TSchVizMonPage : public IMonPage { +private: + TString DataUrl; +public: + TSchVizMonPage(const TString& path, const TString& dataUrl) + : IMonPage(path, "SchViz") + , DataUrl(dataUrl) + {} + virtual void Output(IMonHttpRequest& request) { - TStringStream out; - try { - if (request.GetParams().Get("mode") == "") { - OutputIndex(request, out); - } else if (request.GetParams().Get("mode") == "js") { - OutputJavaScript(request, out); - } else { - ythrow yexception() << "Bad request"; - } - } catch (...) { - out.Clear(); - out << HTTPOKTEXT; - out << "exception: " << CurrentExceptionMessage(); - } - + TStringStream out; + try { + if (request.GetParams().Get("mode") == "") { + OutputIndex(request, out); + } else if (request.GetParams().Get("mode") == "js") { + OutputJavaScript(request, out); + } else { + ythrow yexception() << "Bad request"; + } + } catch (...) { + out.Clear(); + out << HTTPOKTEXT; + out << "exception: " << CurrentExceptionMessage(); + } + request.Output() << out.Str(); - } - -private: + } + +private: void OutputIndex(const IMonHttpRequest& request, IOutputStream& out) - { - Y_UNUSED(request); - out << HTTPOKHTML; - HTML(out) { - out << R"__EOF__(<!DOCTYPE html> -<html> -<head> - <title>SchViz</title> - <link type="text/css" href="css/schviz.css" rel="stylesheet" /> -</head> -<body></body> -</html> - -<script type="text/javascript" src="js/d3.v4.min.js"></script> -<script type="text/javascript" src="js/d3-tip-0.8.0-alpha.1.js"></script> -<script type="text/javascript" src="js/schviz.js"></script> -<script type="text/javascript" src="?mode=js"></script> -)__EOF__"; - } - } - + { + Y_UNUSED(request); + out << HTTPOKHTML; + HTML(out) { + out << R"__EOF__(<!DOCTYPE html> +<html> +<head> + <title>SchViz</title> + <link type="text/css" href="css/schviz.css" rel="stylesheet" /> +</head> +<body></body> +</html> + +<script type="text/javascript" src="js/d3.v4.min.js"></script> +<script type="text/javascript" src="js/d3-tip-0.8.0-alpha.1.js"></script> +<script type="text/javascript" src="js/schviz.js"></script> +<script type="text/javascript" src="?mode=js"></script> +)__EOF__"; + } + } + void OutputJavaScript(const IMonHttpRequest& request, IOutputStream& out) - { - Y_UNUSED(request); - out << HTTPOKJAVASCRIPT; - out << "d3.json(\"" << DataUrl << "\", function(data) {"; - out << R"__EOF__( - var schviz = d3.schviz(); - schviz.timeDomain([0, 1000]); - schviz(data); -}); -)__EOF__"; - } -}; - -#define SCHLAB_STATIC_FILE(file, type) \ - mon->Register(new TResourceMonPage(file, file, TResourceMonPage::type)); \ - /**/ - -void CreateSchLabCommonPages(TMonService2* mon) { - // used external components - SCHLAB_STATIC_FILE("schlab/js/d3.v4.min.js", JAVASCRIPT); -} - -void CreateSchArmPages(TMonService2* mon, const TString& path, const TString& schVizUrl) { - // used external components - SCHLAB_STATIC_FILE("schlab/css/bootstrap.min.css", CSS); - SCHLAB_STATIC_FILE("schlab/js/jquery.min.js", JAVASCRIPT); - SCHLAB_STATIC_FILE("schlab/js/bootstrap.min.js", JAVASCRIPT); - - // scharm static files - SCHLAB_STATIC_FILE("schlab/css/scharm.css", CSS); - SCHLAB_STATIC_FILE("schlab/js/scharm.js", JAVASCRIPT); + { + Y_UNUSED(request); + out << HTTPOKJAVASCRIPT; + out << "d3.json(\"" << DataUrl << "\", function(data) {"; + out << R"__EOF__( + var schviz = d3.schviz(); + schviz.timeDomain([0, 1000]); + schviz(data); +}); +)__EOF__"; + } +}; + +#define SCHLAB_STATIC_FILE(file, type) \ + mon->Register(new TResourceMonPage(file, file, TResourceMonPage::type)); \ + /**/ + +void CreateSchLabCommonPages(TMonService2* mon) { + // used external components + SCHLAB_STATIC_FILE("schlab/js/d3.v4.min.js", JAVASCRIPT); +} + +void CreateSchArmPages(TMonService2* mon, const TString& path, const TString& schVizUrl) { + // used external components + SCHLAB_STATIC_FILE("schlab/css/bootstrap.min.css", CSS); + SCHLAB_STATIC_FILE("schlab/js/jquery.min.js", JAVASCRIPT); + SCHLAB_STATIC_FILE("schlab/js/bootstrap.min.js", JAVASCRIPT); + + // scharm static files + SCHLAB_STATIC_FILE("schlab/css/scharm.css", CSS); + SCHLAB_STATIC_FILE("schlab/js/scharm.js", JAVASCRIPT); SCHLAB_STATIC_FILE("schlab/js/scharm-test0.js", JAVASCRIPT); - - // scharm page itself - mon->Register(new TSchArmMonPage(path, schVizUrl)); -} - -void CreateSchVizPages(TMonService2* mon, const TString& path, const TString& dataUrl) { - // used external components - SCHLAB_STATIC_FILE("schlab/js/d3-tip-0.8.0-alpha.1.js", JAVASCRIPT); - - // schviz static files - SCHLAB_STATIC_FILE("schlab/css/schviz.css", CSS); - SCHLAB_STATIC_FILE("schlab/js/schviz.js", JAVASCRIPT); - - // schviz page itself - mon->Register(new TSchVizMonPage(path, dataUrl)); -} - -#undef SCHLAB_STATIC_FILE - -} + + // scharm page itself + mon->Register(new TSchArmMonPage(path, schVizUrl)); +} + +void CreateSchVizPages(TMonService2* mon, const TString& path, const TString& dataUrl) { + // used external components + SCHLAB_STATIC_FILE("schlab/js/d3-tip-0.8.0-alpha.1.js", JAVASCRIPT); + + // schviz static files + SCHLAB_STATIC_FILE("schlab/css/schviz.css", CSS); + SCHLAB_STATIC_FILE("schlab/js/schviz.js", JAVASCRIPT); + + // schviz page itself + mon->Register(new TSchVizMonPage(path, dataUrl)); +} + +#undef SCHLAB_STATIC_FILE + +} diff --git a/ydb/library/schlab/mon/mon.h b/ydb/library/schlab/mon/mon.h index 82d17d334c..fe2b4185b8 100644 --- a/ydb/library/schlab/mon/mon.h +++ b/ydb/library/schlab/mon/mon.h @@ -1,11 +1,11 @@ -#pragma once - +#pragma once + #include <library/cpp/monlib/service/monservice.h> - -namespace NKikimr { - -void CreateSchLabCommonPages(NMonitoring::TMonService2* mon); -void CreateSchArmPages(NMonitoring::TMonService2* mon, const TString& path, const TString& schVizUrl); -void CreateSchVizPages(NMonitoring::TMonService2* mon, const TString& path, const TString& dataUrl); - -} // namespace NKikimr + +namespace NKikimr { + +void CreateSchLabCommonPages(NMonitoring::TMonService2* mon); +void CreateSchArmPages(NMonitoring::TMonService2* mon, const TString& path, const TString& schVizUrl); +void CreateSchVizPages(NMonitoring::TMonService2* mon, const TString& path, const TString& dataUrl); + +} // namespace NKikimr diff --git a/ydb/library/schlab/mon/static/css/bootstrap.min.css b/ydb/library/schlab/mon/static/css/bootstrap.min.css index f602cacbf8..361830c990 100644 --- a/ydb/library/schlab/mon/static/css/bootstrap.min.css +++ b/ydb/library/schlab/mon/static/css/bootstrap.min.css @@ -1,9 +1,9 @@ -/*! - * Bootstrap v3.0.2 by @fat and @mdo - * Copyright 2013 Twitter, Inc. - * Licensed under http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world by @mdo and @fat. - */ - -/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#c09853}.text-warning:hover{color:#a47e3c}.text-danger{color:#b94a48}.text-danger:hover{color:#953b39}.text-success{color:#468847}.text-success:hover{color:#356635}.text-info{color:#3a87ad}.text-info:hover{color:#2d6987}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.container{width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.container{width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.container{width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .open>a .caret,.nav .open>a:hover .caret,.nav .open>a:focus .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-pills>li.active>a .caret,.nav-pills>li.active>a:hover .caret,.nav-pills>li.active>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:auto}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image: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)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-heading>.dropdown .caret{border-color:#333 transparent}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-heading>.dropdown .caret{border-color:#fff transparent}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading>.dropdown .caret{border-color:#468847 transparent}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading>.dropdown .caret{border-color:#c09853 transparent}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading>.dropdown .caret{border-color:#b94a48 transparent}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading>.dropdown .caret{border-color:#3a87ad transparent}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} +/*! + * Bootstrap v3.0.2 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#c09853}.text-warning:hover{color:#a47e3c}.text-danger{color:#b94a48}.text-danger:hover{color:#953b39}.text-success{color:#468847}.text-success:hover{color:#356635}.text-info{color:#3a87ad}.text-info:hover{color:#2d6987}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.container{width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.container{width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.container{width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .open>a .caret,.nav .open>a:hover .caret,.nav .open>a:focus .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-pills>li.active>a .caret,.nav-pills>li.active>a:hover .caret,.nav-pills>li.active>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:auto}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image: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)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-heading>.dropdown .caret{border-color:#333 transparent}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-heading>.dropdown .caret{border-color:#fff transparent}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading>.dropdown .caret{border-color:#468847 transparent}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading>.dropdown .caret{border-color:#c09853 transparent}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading>.dropdown .caret{border-color:#b94a48 transparent}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading>.dropdown .caret{border-color:#3a87ad transparent}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} diff --git a/ydb/library/schlab/mon/static/css/scharm.css b/ydb/library/schlab/mon/static/css/scharm.css index defca84424..84432079f7 100644 --- a/ydb/library/schlab/mon/static/css/scharm.css +++ b/ydb/library/schlab/mon/static/css/scharm.css @@ -1,35 +1,35 @@ -html,body,#wrapper { - width: 100%; - height: 100%; - margin: 0px; -} - -body { - font: 14px Helvetica Neue; - text-rendering: optimizeLegibility; - margin-top: 1em; - overflow-y: scroll; -} - -.scharm-table { - border: 2px; - border-color: black; -} - -.chart { - font-family: Arial, sans-serif; - font-size: 12px; -} - -rect.zoom-panel { - /*cursor: ew-resize;*/ - fill: none; - pointer-events: all; -} - -.axis path,.axis line { - fill: none; - stroke: #000; - shape-rendering: crispEdges; -} - +html,body,#wrapper { + width: 100%; + height: 100%; + margin: 0px; +} + +body { + font: 14px Helvetica Neue; + text-rendering: optimizeLegibility; + margin-top: 1em; + overflow-y: scroll; +} + +.scharm-table { + border: 2px; + border-color: black; +} + +.chart { + font-family: Arial, sans-serif; + font-size: 12px; +} + +rect.zoom-panel { + /*cursor: ew-resize;*/ + fill: none; + pointer-events: all; +} + +.axis path,.axis line { + fill: none; + stroke: #000; + shape-rendering: crispEdges; +} + diff --git a/ydb/library/schlab/mon/static/css/schviz.css b/ydb/library/schlab/mon/static/css/schviz.css index eab7192656..926b232f7d 100644 --- a/ydb/library/schlab/mon/static/css/schviz.css +++ b/ydb/library/schlab/mon/static/css/schviz.css @@ -1,166 +1,166 @@ -html,body,#wrapper { - width: 100%; - height: 100%; - margin: 0px; -} - -body { - font: 14px Helvetica Neue; - text-rendering: optimizeLegibility; - margin-top: 1em; - overflow-y: scroll; -} - -.chart { - font-family: Arial, sans-serif; - font-size: 12px; -} - -rect.zoom-panel { - /*cursor: ew-resize;*/ - fill: none; - pointer-events: all; -} - -.axis path,.axis line { - fill: none; - stroke: #000; - shape-rendering: crispEdges; -} - -.axis.y { - font-size: 16px; - cursor: ns-resize; -} - -.axis.x { - font-size: 16px; -} - -#ruler { - text-anchor: middle; - alignment-baseline: before-edge; - font-size: 16px; - font-family: sans-serif; - pointer-events: none; -} - -.d3-tip { - line-height: 1; - font-weight: bold; - padding: 12px; - background: rgba(0, 0, 0, 0.8); - color: #fff; - border-radius: 2px; -} - -/* Creates a small triangle extender for the tooltip */ -.d3-tip:after { - box-sizing: border-box; - display: inline; - font-size: 10px; - width: 100%; - line-height: 1; - color: rgba(0, 0, 0, 0.8); - content: "\25BC"; - position: absolute; - text-align: center; -} - -/* Style northward tooltips differently */ -.d3-tip.n:after { - margin: -1px 0 0 0; - top: 100%; - left: 0; -} - -.d3-tip table { - border: 0px; -} - -td.tip-heading { - text-align: center; -} - -td.tip-key { - text-align: right; -} - -td.tip-value { - text-align: left; -} - -.cbs-idle { - fill: #eaeaea; -} - -.cbs-active { - fill: #c4ffc4; -} - -.cbs-running { - fill: #6aff6a; -} - -.cbs-depleted { - fill: #f9dccb; -} - -.cbs-dead { - fill: #ffffff; -} - -.req-real { - fill: #77a7ff; -} - -.req-real-hover { - fill: #90c0ff; -} - -.req-est { - fill: #5178bd; - pointer-events: none; -} - -.req-est-hover { - fill: #80b0ee; - pointer-events: none; -} - -.req-kind { - fill: #ce3a3a; - pointer-events: none; -} - -.arrow-arrival { - stroke-width:1; - stroke:#000; -} - -.arrow-arrival-hover { - stroke-width:3; - stroke:#333; -} - -.arrow-deadline { - stroke-width:1; - stroke:#000; -} - -/* for arrowhead marker */ -#arrow { - stroke-width:1; - stroke-dasharray:0; -} - -a { - color: steelblue; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - - +html,body,#wrapper { + width: 100%; + height: 100%; + margin: 0px; +} + +body { + font: 14px Helvetica Neue; + text-rendering: optimizeLegibility; + margin-top: 1em; + overflow-y: scroll; +} + +.chart { + font-family: Arial, sans-serif; + font-size: 12px; +} + +rect.zoom-panel { + /*cursor: ew-resize;*/ + fill: none; + pointer-events: all; +} + +.axis path,.axis line { + fill: none; + stroke: #000; + shape-rendering: crispEdges; +} + +.axis.y { + font-size: 16px; + cursor: ns-resize; +} + +.axis.x { + font-size: 16px; +} + +#ruler { + text-anchor: middle; + alignment-baseline: before-edge; + font-size: 16px; + font-family: sans-serif; + pointer-events: none; +} + +.d3-tip { + line-height: 1; + font-weight: bold; + padding: 12px; + background: rgba(0, 0, 0, 0.8); + color: #fff; + border-radius: 2px; +} + +/* Creates a small triangle extender for the tooltip */ +.d3-tip:after { + box-sizing: border-box; + display: inline; + font-size: 10px; + width: 100%; + line-height: 1; + color: rgba(0, 0, 0, 0.8); + content: "\25BC"; + position: absolute; + text-align: center; +} + +/* Style northward tooltips differently */ +.d3-tip.n:after { + margin: -1px 0 0 0; + top: 100%; + left: 0; +} + +.d3-tip table { + border: 0px; +} + +td.tip-heading { + text-align: center; +} + +td.tip-key { + text-align: right; +} + +td.tip-value { + text-align: left; +} + +.cbs-idle { + fill: #eaeaea; +} + +.cbs-active { + fill: #c4ffc4; +} + +.cbs-running { + fill: #6aff6a; +} + +.cbs-depleted { + fill: #f9dccb; +} + +.cbs-dead { + fill: #ffffff; +} + +.req-real { + fill: #77a7ff; +} + +.req-real-hover { + fill: #90c0ff; +} + +.req-est { + fill: #5178bd; + pointer-events: none; +} + +.req-est-hover { + fill: #80b0ee; + pointer-events: none; +} + +.req-kind { + fill: #ce3a3a; + pointer-events: none; +} + +.arrow-arrival { + stroke-width:1; + stroke:#000; +} + +.arrow-arrival-hover { + stroke-width:3; + stroke:#333; +} + +.arrow-deadline { + stroke-width:1; + stroke:#000; +} + +/* for arrowhead marker */ +#arrow { + stroke-width:1; + stroke-dasharray:0; +} + +a { + color: steelblue; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + + diff --git a/ydb/library/schlab/mon/static/js/bootstrap.min.js b/ydb/library/schlab/mon/static/js/bootstrap.min.js index 80e40418f2..175d50353d 100644 --- a/ydb/library/schlab/mon/static/js/bootstrap.min.js +++ b/ydb/library/schlab/mon/static/js/bootstrap.min.js @@ -1,9 +1,9 @@ -/*! - * Bootstrap v3.0.2 by @fat and @mdo - * Copyright 2013 Twitter, Inc. - * Licensed under http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world by @mdo and @fat. - */ - -if("undefined"==typeof jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]}}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(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 c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d)};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.is("input")?"val":"html",e=c.data();a+="Text",e.resetText||c.data("resetText",c[d]()),c[d](e[a]||this.options[a]),setTimeout(function(){"loadingText"==a?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons"]');if(a.length){var b=this.$element.find("input").prop("checked",!this.$element.hasClass("active")).trigger("change");"radio"===b.prop("type")&&a.find(".active").removeClass("active")}this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}this.sliding=!0,f&&this.pause();var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});if(!e.hasClass("active")){if(this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(j),j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.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)}).emulateTransitionEnd(600)}else{if(this.$element.trigger(j),j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?(this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350),void 0):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(jQuery),+function(a){"use strict";function b(){a(d).remove(),a(e).each(function(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b),f.trigger(d=a.Event("show.bs.dropdown")),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown"),e.focus()}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).focus(),d.click();var h=a("[role=menu] li:not(.divider):visible a",f);if(h.length){var i=h.index(h.filter(":focus"));38==b.keyCode&&i>0&&i--,40==b.keyCode&&i<h.length-1&&i++,~i||(i=0),h.eq(i).focus()}}}};var g=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var c=a(this),d=c.data("dropdown");d||c.data("dropdown",d=new f(this)),"string"==typeof b&&d[b].call(c)})},a.fn.dropdown.Constructor=f,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=g,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",e,f.prototype.toggle).on("keydown.bs.dropdown.data-api",e+", [role=menu]",f.prototype.keydown)}(jQuery),+function(a){"use strict";var b=function(b,c){this.options=c,this.$element=a(b),this.$backdrop=this.isShown=null,this.options.remote&&this.$element.load(this.options.remote)};b.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},b.prototype.toggle=function(a){return this[this.isShown?"hide":"show"](a)},b.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.$element.on("click.dismiss.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(document.body),c.$element.show(),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one(a.support.transition.end,function(){c.$element.focus().trigger(e)}).emulateTransitionEnd(300):c.$element.focus().trigger(e)}))},b.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one(a.support.transition.end,a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},b.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.focus()},this))},b.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},b.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden.bs.modal")})},b.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},b.prototype.backdrop=function(b){var c=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var d=a.support.transition&&c;if(this.$backdrop=a('<div class="modal-backdrop '+c+'" />').appendTo(document.body),this.$element.on("click.dismiss.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),d&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;d?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()):b&&b()};var c=a.fn.modal;a.fn.modal=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},b.DEFAULTS,e.data(),"object"==typeof c&&c);f||e.data("bs.modal",f=new b(this,g)),"string"==typeof c?f[c](d):g.show&&f.show(d)})},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f,this).one("hide",function(){c.is(":visible")&&c.focus()})}),a(document).on("show.bs.modal",".modal",function(){a(document.body).addClass("modal-open")}).on("hidden.bs.modal",".modal",function(){a(document.body).removeClass("modal-open")})}(jQuery),+function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focus",i="hover"==g?"mouseleave":"blur";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show),void 0):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide),void 0):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this.tip();this.setContent(),this.options.animation&&c.addClass("fade");var d="function"==typeof this.options.placement?this.options.placement.call(this,c[0],this.$element[0]):this.options.placement,e=/\s?auto?\s?/i,f=e.test(d);f&&(d=d.replace(e,"")||"top"),c.detach().css({top:0,left:0,display:"block"}).addClass(d),this.options.container?c.appendTo(this.options.container):c.insertAfter(this.$element);var g=this.getPosition(),h=c[0].offsetWidth,i=c[0].offsetHeight;if(f){var j=this.$element.parent(),k=d,l=document.documentElement.scrollTop||document.body.scrollTop,m="body"==this.options.container?window.innerWidth:j.outerWidth(),n="body"==this.options.container?window.innerHeight:j.outerHeight(),o="body"==this.options.container?0:j.offset().left;d="bottom"==d&&g.top+g.height+i-l>n?"top":"top"==d&&g.top-l-i<0?"bottom":"right"==d&&g.right+h>m?"left":"left"==d&&g.left-h<o?"right":d,c.removeClass(k).addClass(d)}var p=this.getCalculatedOffset(d,g,h,i);this.applyPlacement(p,d),this.$element.trigger("shown.bs."+this.type)}},b.prototype.applyPlacement=function(a,b){var c,d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),a.top=a.top+g,a.left=a.left+h,d.offset(a).addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;if("top"==b&&j!=f&&(c=!0,a.top=a.top+f-j),/bottom|top/.test(b)){var k=0;a.left<0&&(k=-2*a.left,a.left=0,d.offset(a),i=d[0].offsetWidth,j=d[0].offsetHeight),this.replaceArrow(k-e+i,i,"left")}else this.replaceArrow(j-f,j,"top");c&&d.offset(a)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach()}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.$element.trigger("hidden.bs."+this.type),this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(jQuery),+function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");b.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(c).is("body")?a(window):a(c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#\w/.test(e)&&a(e);return f&&f.length&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parents(".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top()),"function"==typeof h&&(h=f.bottom());var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;this.affixed!==i&&(this.unpin&&this.$element.css("top",""),this.affixed=i,this.unpin="bottom"==i?e.top-d:null,this.$element.removeClass(b.RESET).addClass("affix"+(i?"-"+i:"")),"bottom"==i&&this.$element.offset({top:document.body.offsetHeight-h-this.$element.height()}))}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(jQuery); +/*! + * Bootstrap v3.0.2 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +if("undefined"==typeof jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]}}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(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 c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d)};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.is("input")?"val":"html",e=c.data();a+="Text",e.resetText||c.data("resetText",c[d]()),c[d](e[a]||this.options[a]),setTimeout(function(){"loadingText"==a?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons"]');if(a.length){var b=this.$element.find("input").prop("checked",!this.$element.hasClass("active")).trigger("change");"radio"===b.prop("type")&&a.find(".active").removeClass("active")}this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}this.sliding=!0,f&&this.pause();var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});if(!e.hasClass("active")){if(this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(j),j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.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)}).emulateTransitionEnd(600)}else{if(this.$element.trigger(j),j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?(this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350),void 0):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(jQuery),+function(a){"use strict";function b(){a(d).remove(),a(e).each(function(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b),f.trigger(d=a.Event("show.bs.dropdown")),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown"),e.focus()}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).focus(),d.click();var h=a("[role=menu] li:not(.divider):visible a",f);if(h.length){var i=h.index(h.filter(":focus"));38==b.keyCode&&i>0&&i--,40==b.keyCode&&i<h.length-1&&i++,~i||(i=0),h.eq(i).focus()}}}};var g=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var c=a(this),d=c.data("dropdown");d||c.data("dropdown",d=new f(this)),"string"==typeof b&&d[b].call(c)})},a.fn.dropdown.Constructor=f,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=g,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",e,f.prototype.toggle).on("keydown.bs.dropdown.data-api",e+", [role=menu]",f.prototype.keydown)}(jQuery),+function(a){"use strict";var b=function(b,c){this.options=c,this.$element=a(b),this.$backdrop=this.isShown=null,this.options.remote&&this.$element.load(this.options.remote)};b.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},b.prototype.toggle=function(a){return this[this.isShown?"hide":"show"](a)},b.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.$element.on("click.dismiss.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(document.body),c.$element.show(),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one(a.support.transition.end,function(){c.$element.focus().trigger(e)}).emulateTransitionEnd(300):c.$element.focus().trigger(e)}))},b.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one(a.support.transition.end,a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},b.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.focus()},this))},b.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},b.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden.bs.modal")})},b.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},b.prototype.backdrop=function(b){var c=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var d=a.support.transition&&c;if(this.$backdrop=a('<div class="modal-backdrop '+c+'" />').appendTo(document.body),this.$element.on("click.dismiss.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),d&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;d?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()):b&&b()};var c=a.fn.modal;a.fn.modal=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},b.DEFAULTS,e.data(),"object"==typeof c&&c);f||e.data("bs.modal",f=new b(this,g)),"string"==typeof c?f[c](d):g.show&&f.show(d)})},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f,this).one("hide",function(){c.is(":visible")&&c.focus()})}),a(document).on("show.bs.modal",".modal",function(){a(document.body).addClass("modal-open")}).on("hidden.bs.modal",".modal",function(){a(document.body).removeClass("modal-open")})}(jQuery),+function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focus",i="hover"==g?"mouseleave":"blur";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show),void 0):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide),void 0):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this.tip();this.setContent(),this.options.animation&&c.addClass("fade");var d="function"==typeof this.options.placement?this.options.placement.call(this,c[0],this.$element[0]):this.options.placement,e=/\s?auto?\s?/i,f=e.test(d);f&&(d=d.replace(e,"")||"top"),c.detach().css({top:0,left:0,display:"block"}).addClass(d),this.options.container?c.appendTo(this.options.container):c.insertAfter(this.$element);var g=this.getPosition(),h=c[0].offsetWidth,i=c[0].offsetHeight;if(f){var j=this.$element.parent(),k=d,l=document.documentElement.scrollTop||document.body.scrollTop,m="body"==this.options.container?window.innerWidth:j.outerWidth(),n="body"==this.options.container?window.innerHeight:j.outerHeight(),o="body"==this.options.container?0:j.offset().left;d="bottom"==d&&g.top+g.height+i-l>n?"top":"top"==d&&g.top-l-i<0?"bottom":"right"==d&&g.right+h>m?"left":"left"==d&&g.left-h<o?"right":d,c.removeClass(k).addClass(d)}var p=this.getCalculatedOffset(d,g,h,i);this.applyPlacement(p,d),this.$element.trigger("shown.bs."+this.type)}},b.prototype.applyPlacement=function(a,b){var c,d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),a.top=a.top+g,a.left=a.left+h,d.offset(a).addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;if("top"==b&&j!=f&&(c=!0,a.top=a.top+f-j),/bottom|top/.test(b)){var k=0;a.left<0&&(k=-2*a.left,a.left=0,d.offset(a),i=d[0].offsetWidth,j=d[0].offsetHeight),this.replaceArrow(k-e+i,i,"left")}else this.replaceArrow(j-f,j,"top");c&&d.offset(a)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach()}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.$element.trigger("hidden.bs."+this.type),this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(jQuery),+function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");b.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(c).is("body")?a(window):a(c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#\w/.test(e)&&a(e);return f&&f.length&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parents(".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top()),"function"==typeof h&&(h=f.bottom());var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;this.affixed!==i&&(this.unpin&&this.$element.css("top",""),this.affixed=i,this.unpin="bottom"==i?e.top-d:null,this.$element.removeClass(b.RESET).addClass("affix"+(i?"-"+i:"")),"bottom"==i&&this.$element.offset({top:document.body.offsetHeight-h-this.$element.height()}))}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(jQuery); diff --git a/ydb/library/schlab/mon/static/js/d3-tip-0.8.0-alpha.1.js b/ydb/library/schlab/mon/static/js/d3-tip-0.8.0-alpha.1.js index ad3a6c0d19..2b2e61ad4c 100644 --- a/ydb/library/schlab/mon/static/js/d3-tip-0.8.0-alpha.1.js +++ b/ydb/library/schlab/mon/static/js/d3-tip-0.8.0-alpha.1.js @@ -1,352 +1,352 @@ -/** - * d3.tip - * Copyright (c) 2013 Justin Palmer - * - * Tooltips for d3.js SVG visualizations - */ -// eslint-disable-next-line no-extra-semi -;(function(root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module with d3 as a dependency. - define([ - 'd3-collection', - 'd3-selection' - ], factory) - } else if (typeof module === 'object' && module.exports) { - /* eslint-disable global-require */ - // CommonJS - var d3Collection = require('d3-collection'), - d3Selection = require('d3-selection') - module.exports = factory(d3Collection, d3Selection) - /* eslint-enable global-require */ - } else { - // Browser global. - var d3 = root.d3 - // eslint-disable-next-line no-param-reassign - root.d3.tip = factory(d3, d3) - } -}(this, function(d3Collection, d3Selection) { - // Public - contructs a new tooltip - // - // Returns a tip - return function() { - var direction = d3TipDirection, - offset = d3TipOffset, - html = d3TipHTML, - rootElement = document.body, - node = initNode(), - svg = null, - point = null, - target = null - - function tip(vis) { - svg = getSVGNode(vis) - if (!svg) return - point = svg.createSVGPoint() - rootElement.appendChild(node) - } - - // Public - show the tooltip on the screen - // - // Returns a tip - tip.show = function() { - var args = Array.prototype.slice.call(arguments) - if (args[args.length - 1] instanceof SVGElement) target = args.pop() - - var content = html.apply(this, args), - poffset = offset.apply(this, args), - dir = direction.apply(this, args), - nodel = getNodeEl(), - i = directions.length, - coords, - scrollTop = document.documentElement.scrollTop || - rootElement.scrollTop, - scrollLeft = document.documentElement.scrollLeft || - rootElement.scrollLeft - - nodel.html(content) - .style('opacity', 1).style('pointer-events', 'all') - - while (i--) nodel.classed(directions[i], false) - coords = directionCallbacks.get(dir).apply(this) - nodel.classed(dir, true) - .style('top', (coords.top + poffset[0]) + scrollTop + 'px') - .style('left', (coords.left + poffset[1]) + scrollLeft + 'px') - - return tip - } - - // Public - hide the tooltip - // - // Returns a tip - tip.hide = function() { - var nodel = getNodeEl() - nodel.style('opacity', 0).style('pointer-events', 'none') - return tip - } - - // Public: Proxy attr calls to the d3 tip container. - // Sets or gets attribute value. - // - // n - name of the attribute - // v - value of the attribute - // - // Returns tip or attribute value - // eslint-disable-next-line no-unused-vars - tip.attr = function(n, v) { - if (arguments.length < 2 && typeof n === 'string') { - return getNodeEl().attr(n) - } - - var args = Array.prototype.slice.call(arguments) - d3Selection.selection.prototype.attr.apply(getNodeEl(), args) - return tip - } - - // Public: Proxy style calls to the d3 tip container. - // Sets or gets a style value. - // - // n - name of the property - // v - value of the property - // - // Returns tip or style property value - // eslint-disable-next-line no-unused-vars - tip.style = function(n, v) { - if (arguments.length < 2 && typeof n === 'string') { - return getNodeEl().style(n) - } - - var args = Array.prototype.slice.call(arguments) - d3Selection.selection.prototype.style.apply(getNodeEl(), args) - return tip - } - - // Public: Set or get the direction of the tooltip - // - // v - One of n(north), s(south), e(east), or w(west), nw(northwest), - // sw(southwest), ne(northeast) or se(southeast) - // - // Returns tip or direction - tip.direction = function(v) { - if (!arguments.length) return direction - direction = v == null ? v : functor(v) - - return tip - } - - // Public: Sets or gets the offset of the tip - // - // v - Array of [x, y] offset - // - // Returns offset or - tip.offset = function(v) { - if (!arguments.length) return offset - offset = v == null ? v : functor(v) - - return tip - } - - // Public: sets or gets the html value of the tooltip - // - // v - String value of the tip - // - // Returns html value or tip - tip.html = function(v) { - if (!arguments.length) return html - html = v == null ? v : functor(v) - - return tip - } - - // Public: sets or gets the root element anchor of the tooltip - // - // v - root element of the tooltip - // - // Returns root node of tip - tip.rootElement = function(v) { - if (!arguments.length) return rootElement - rootElement = v == null ? v : functor(v) - - return tip - } - - // Public: destroys the tooltip and removes it from the DOM - // - // Returns a tip - tip.destroy = function() { - if (node) { - getNodeEl().remove() - node = null - } - return tip - } - - function d3TipDirection() { return 'n' } - function d3TipOffset() { return [0, 0] } - function d3TipHTML() { return ' ' } - - var directionCallbacks = d3Collection.map({ - n: directionNorth, - s: directionSouth, - e: directionEast, - w: directionWest, - nw: directionNorthWest, - ne: directionNorthEast, - sw: directionSouthWest, - se: directionSouthEast - }), - directions = directionCallbacks.keys() - - function directionNorth() { - var bbox = getScreenBBox() - return { - top: bbox.n.y - node.offsetHeight, - left: bbox.n.x - node.offsetWidth / 2 - } - } - - function directionSouth() { - var bbox = getScreenBBox() - return { - top: bbox.s.y, - left: bbox.s.x - node.offsetWidth / 2 - } - } - - function directionEast() { - var bbox = getScreenBBox() - return { - top: bbox.e.y - node.offsetHeight / 2, - left: bbox.e.x - } - } - - function directionWest() { - var bbox = getScreenBBox() - return { - top: bbox.w.y - node.offsetHeight / 2, - left: bbox.w.x - node.offsetWidth - } - } - - function directionNorthWest() { - var bbox = getScreenBBox() - return { - top: bbox.nw.y - node.offsetHeight, - left: bbox.nw.x - node.offsetWidth - } - } - - function directionNorthEast() { - var bbox = getScreenBBox() - return { - top: bbox.ne.y - node.offsetHeight, - left: bbox.ne.x - } - } - - function directionSouthWest() { - var bbox = getScreenBBox() - return { - top: bbox.sw.y, - left: bbox.sw.x - node.offsetWidth - } - } - - function directionSouthEast() { - var bbox = getScreenBBox() - return { - top: bbox.se.y, - left: bbox.se.x - } - } - - function initNode() { - var div = d3Selection.select(document.createElement('div')) - div - .style('position', 'absolute') - .style('top', 0) - .style('opacity', 0) - .style('pointer-events', 'none') - .style('box-sizing', 'border-box') - - return div.node() - } - - function getSVGNode(element) { - var svgNode = element.node() - if (!svgNode) return null - if (svgNode.tagName.toLowerCase() === 'svg') return svgNode - return svgNode.ownerSVGElement - } - - function getNodeEl() { - if (node == null) { - node = initNode() - // re-add node to DOM - rootElement.appendChild(node) - } - return d3Selection.select(node) - } - - // Private - gets the screen coordinates of a shape - // - // Given a shape on the screen, will return an SVGPoint for the directions - // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), - // nw(northwest), sw(southwest). - // - // +-+-+ - // | | - // + + - // | | - // +-+-+ - // - // Returns an Object {n, s, e, w, nw, sw, ne, se} - function getScreenBBox() { - var targetel = target || d3Selection.event.target - - while (targetel.getScreenCTM == null && targetel.parentNode == null) { - targetel = targetel.parentNode - } - - var bbox = {}, - matrix = targetel.getScreenCTM(), - tbbox = targetel.getBBox(), - width = tbbox.width, - height = tbbox.height, - x = tbbox.x, - y = tbbox.y - - point.x = x - point.y = y - bbox.nw = point.matrixTransform(matrix) - point.x += width - bbox.ne = point.matrixTransform(matrix) - point.y += height - bbox.se = point.matrixTransform(matrix) - point.x -= width - bbox.sw = point.matrixTransform(matrix) - point.y -= height / 2 - bbox.w = point.matrixTransform(matrix) - point.x += width - bbox.e = point.matrixTransform(matrix) - point.x -= width / 2 - point.y -= height / 2 - bbox.n = point.matrixTransform(matrix) - point.y += height - bbox.s = point.matrixTransform(matrix) - - return bbox - } - - // Private - replace D3JS 3.X d3.functor() function - function functor(v) { - return typeof v === 'function' ? v : function() { - return v - } - } - - return tip - } -// eslint-disable-next-line semi -})); +/** + * d3.tip + * Copyright (c) 2013 Justin Palmer + * + * Tooltips for d3.js SVG visualizations + */ +// eslint-disable-next-line no-extra-semi +;(function(root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module with d3 as a dependency. + define([ + 'd3-collection', + 'd3-selection' + ], factory) + } else if (typeof module === 'object' && module.exports) { + /* eslint-disable global-require */ + // CommonJS + var d3Collection = require('d3-collection'), + d3Selection = require('d3-selection') + module.exports = factory(d3Collection, d3Selection) + /* eslint-enable global-require */ + } else { + // Browser global. + var d3 = root.d3 + // eslint-disable-next-line no-param-reassign + root.d3.tip = factory(d3, d3) + } +}(this, function(d3Collection, d3Selection) { + // Public - contructs a new tooltip + // + // Returns a tip + return function() { + var direction = d3TipDirection, + offset = d3TipOffset, + html = d3TipHTML, + rootElement = document.body, + node = initNode(), + svg = null, + point = null, + target = null + + function tip(vis) { + svg = getSVGNode(vis) + if (!svg) return + point = svg.createSVGPoint() + rootElement.appendChild(node) + } + + // Public - show the tooltip on the screen + // + // Returns a tip + tip.show = function() { + var args = Array.prototype.slice.call(arguments) + if (args[args.length - 1] instanceof SVGElement) target = args.pop() + + var content = html.apply(this, args), + poffset = offset.apply(this, args), + dir = direction.apply(this, args), + nodel = getNodeEl(), + i = directions.length, + coords, + scrollTop = document.documentElement.scrollTop || + rootElement.scrollTop, + scrollLeft = document.documentElement.scrollLeft || + rootElement.scrollLeft + + nodel.html(content) + .style('opacity', 1).style('pointer-events', 'all') + + while (i--) nodel.classed(directions[i], false) + coords = directionCallbacks.get(dir).apply(this) + nodel.classed(dir, true) + .style('top', (coords.top + poffset[0]) + scrollTop + 'px') + .style('left', (coords.left + poffset[1]) + scrollLeft + 'px') + + return tip + } + + // Public - hide the tooltip + // + // Returns a tip + tip.hide = function() { + var nodel = getNodeEl() + nodel.style('opacity', 0).style('pointer-events', 'none') + return tip + } + + // Public: Proxy attr calls to the d3 tip container. + // Sets or gets attribute value. + // + // n - name of the attribute + // v - value of the attribute + // + // Returns tip or attribute value + // eslint-disable-next-line no-unused-vars + tip.attr = function(n, v) { + if (arguments.length < 2 && typeof n === 'string') { + return getNodeEl().attr(n) + } + + var args = Array.prototype.slice.call(arguments) + d3Selection.selection.prototype.attr.apply(getNodeEl(), args) + return tip + } + + // Public: Proxy style calls to the d3 tip container. + // Sets or gets a style value. + // + // n - name of the property + // v - value of the property + // + // Returns tip or style property value + // eslint-disable-next-line no-unused-vars + tip.style = function(n, v) { + if (arguments.length < 2 && typeof n === 'string') { + return getNodeEl().style(n) + } + + var args = Array.prototype.slice.call(arguments) + d3Selection.selection.prototype.style.apply(getNodeEl(), args) + return tip + } + + // Public: Set or get the direction of the tooltip + // + // v - One of n(north), s(south), e(east), or w(west), nw(northwest), + // sw(southwest), ne(northeast) or se(southeast) + // + // Returns tip or direction + tip.direction = function(v) { + if (!arguments.length) return direction + direction = v == null ? v : functor(v) + + return tip + } + + // Public: Sets or gets the offset of the tip + // + // v - Array of [x, y] offset + // + // Returns offset or + tip.offset = function(v) { + if (!arguments.length) return offset + offset = v == null ? v : functor(v) + + return tip + } + + // Public: sets or gets the html value of the tooltip + // + // v - String value of the tip + // + // Returns html value or tip + tip.html = function(v) { + if (!arguments.length) return html + html = v == null ? v : functor(v) + + return tip + } + + // Public: sets or gets the root element anchor of the tooltip + // + // v - root element of the tooltip + // + // Returns root node of tip + tip.rootElement = function(v) { + if (!arguments.length) return rootElement + rootElement = v == null ? v : functor(v) + + return tip + } + + // Public: destroys the tooltip and removes it from the DOM + // + // Returns a tip + tip.destroy = function() { + if (node) { + getNodeEl().remove() + node = null + } + return tip + } + + function d3TipDirection() { return 'n' } + function d3TipOffset() { return [0, 0] } + function d3TipHTML() { return ' ' } + + var directionCallbacks = d3Collection.map({ + n: directionNorth, + s: directionSouth, + e: directionEast, + w: directionWest, + nw: directionNorthWest, + ne: directionNorthEast, + sw: directionSouthWest, + se: directionSouthEast + }), + directions = directionCallbacks.keys() + + function directionNorth() { + var bbox = getScreenBBox() + return { + top: bbox.n.y - node.offsetHeight, + left: bbox.n.x - node.offsetWidth / 2 + } + } + + function directionSouth() { + var bbox = getScreenBBox() + return { + top: bbox.s.y, + left: bbox.s.x - node.offsetWidth / 2 + } + } + + function directionEast() { + var bbox = getScreenBBox() + return { + top: bbox.e.y - node.offsetHeight / 2, + left: bbox.e.x + } + } + + function directionWest() { + var bbox = getScreenBBox() + return { + top: bbox.w.y - node.offsetHeight / 2, + left: bbox.w.x - node.offsetWidth + } + } + + function directionNorthWest() { + var bbox = getScreenBBox() + return { + top: bbox.nw.y - node.offsetHeight, + left: bbox.nw.x - node.offsetWidth + } + } + + function directionNorthEast() { + var bbox = getScreenBBox() + return { + top: bbox.ne.y - node.offsetHeight, + left: bbox.ne.x + } + } + + function directionSouthWest() { + var bbox = getScreenBBox() + return { + top: bbox.sw.y, + left: bbox.sw.x - node.offsetWidth + } + } + + function directionSouthEast() { + var bbox = getScreenBBox() + return { + top: bbox.se.y, + left: bbox.se.x + } + } + + function initNode() { + var div = d3Selection.select(document.createElement('div')) + div + .style('position', 'absolute') + .style('top', 0) + .style('opacity', 0) + .style('pointer-events', 'none') + .style('box-sizing', 'border-box') + + return div.node() + } + + function getSVGNode(element) { + var svgNode = element.node() + if (!svgNode) return null + if (svgNode.tagName.toLowerCase() === 'svg') return svgNode + return svgNode.ownerSVGElement + } + + function getNodeEl() { + if (node == null) { + node = initNode() + // re-add node to DOM + rootElement.appendChild(node) + } + return d3Selection.select(node) + } + + // Private - gets the screen coordinates of a shape + // + // Given a shape on the screen, will return an SVGPoint for the directions + // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), + // nw(northwest), sw(southwest). + // + // +-+-+ + // | | + // + + + // | | + // +-+-+ + // + // Returns an Object {n, s, e, w, nw, sw, ne, se} + function getScreenBBox() { + var targetel = target || d3Selection.event.target + + while (targetel.getScreenCTM == null && targetel.parentNode == null) { + targetel = targetel.parentNode + } + + var bbox = {}, + matrix = targetel.getScreenCTM(), + tbbox = targetel.getBBox(), + width = tbbox.width, + height = tbbox.height, + x = tbbox.x, + y = tbbox.y + + point.x = x + point.y = y + bbox.nw = point.matrixTransform(matrix) + point.x += width + bbox.ne = point.matrixTransform(matrix) + point.y += height + bbox.se = point.matrixTransform(matrix) + point.x -= width + bbox.sw = point.matrixTransform(matrix) + point.y -= height / 2 + bbox.w = point.matrixTransform(matrix) + point.x += width + bbox.e = point.matrixTransform(matrix) + point.x -= width / 2 + point.y -= height / 2 + bbox.n = point.matrixTransform(matrix) + point.y += height + bbox.s = point.matrixTransform(matrix) + + return bbox + } + + // Private - replace D3JS 3.X d3.functor() function + function functor(v) { + return typeof v === 'function' ? v : function() { + return v + } + } + + return tip + } +// eslint-disable-next-line semi +})); diff --git a/ydb/library/schlab/mon/static/js/d3.v4.min.js b/ydb/library/schlab/mon/static/js/d3.v4.min.js index 6a2705865c..544c4eb8cd 100644 --- a/ydb/library/schlab/mon/static/js/d3.v4.min.js +++ b/ydb/library/schlab/mon/static/js/d3.v4.min.js @@ -1,2 +1,2 @@ -// https://d3js.org Version 4.10.0. Copyright 2017 Mike Bostock. -(function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})})(this,function(t){"use strict";function n(t){return function(n,e){return ss(t(n),e)}}function e(t,n){return[t,n]}function r(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=Ts?10:o>=ks?5:o>=Ns?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=Ts?10:o>=ks?5:o>=Ns?2:1)}function i(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=Ts?i*=10:o>=ks?i*=5:o>=Ns&&(i*=2),n<t?-i:i}function o(t){return t.length}function u(t){return"translate("+(t+.5)+",0)"}function a(t){return"translate(0,"+(t+.5)+")"}function c(t){return function(n){return+t(n)}}function s(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}function f(){return!this.__axis}function l(t,n){function e(e){var u=null==i?n.ticks?n.ticks.apply(n,r):n.domain():i,a=null==o?n.tickFormat?n.tickFormat.apply(n,r):Ls:o,y=Math.max(l,0)+p,g=n.range(),m=+g[0]+.5,x=+g[g.length-1]+.5,b=(n.bandwidth?s:c)(n.copy()),w=e.selection?e.selection():e,M=w.selectAll(".domain").data([null]),T=w.selectAll(".tick").data(u,n).order(),k=T.exit(),N=T.enter().append("g").attr("class","tick"),S=T.select("line"),E=T.select("text");M=M.merge(M.enter().insert("path",".tick").attr("class","domain").attr("stroke","#000")),T=T.merge(N),S=S.merge(N.append("line").attr("stroke","#000").attr(v+"2",d*l)),E=E.merge(N.append("text").attr("fill","#000").attr(v,d*y).attr("dy",t===qs?"0em":t===Ds?"0.71em":"0.32em")),e!==w&&(M=M.transition(e),T=T.transition(e),S=S.transition(e),E=E.transition(e),k=k.transition(e).attr("opacity",Fs).attr("transform",function(t){return isFinite(t=b(t))?_(t):this.getAttribute("transform")}),N.attr("opacity",Fs).attr("transform",function(t){var n=this.parentNode.__axis;return _(n&&isFinite(n=n(t))?n:b(t))})),k.remove(),M.attr("d",t===Os||t==Us?"M"+d*h+","+m+"H0.5V"+x+"H"+d*h:"M"+m+","+d*h+"V0.5H"+x+"V"+d*h),T.attr("opacity",1).attr("transform",function(t){return _(b(t))}),S.attr(v+"2",d*l),E.attr(v,d*y).text(a),w.filter(f).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===Us?"start":t===Os?"end":"middle"),w.each(function(){this.__axis=b})}var r=[],i=null,o=null,l=6,h=6,p=3,d=t===qs||t===Os?-1:1,v=t===Os||t===Us?"x":"y",_=t===qs||t===Ds?u:a;return e.scale=function(t){return arguments.length?(n=t,e):n},e.ticks=function(){return r=Rs.call(arguments),e},e.tickArguments=function(t){return arguments.length?(r=null==t?[]:Rs.call(t),e):r.slice()},e.tickValues=function(t){return arguments.length?(i=null==t?null:Rs.call(t),e):i&&i.slice()},e.tickFormat=function(t){return arguments.length?(o=t,e):o},e.tickSize=function(t){return arguments.length?(l=h=+t,e):l},e.tickSizeInner=function(t){return arguments.length?(l=+t,e):l},e.tickSizeOuter=function(t){return arguments.length?(h=+t,e):h},e.tickPadding=function(t){return arguments.length?(p=+t,e):p},e}function h(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r)throw new Error("illegal type: "+t);r[t]=[]}return new p(r)}function p(t){this._=t}function d(t,n){return t.trim().split(/^|\s+/).map(function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}function v(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function _(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=Is,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}function y(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===Ys&&n.documentElement.namespaceURI===Ys?n.createElement(t):n.createElementNS(e,t)}}function g(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function m(){return new x}function x(){this._="@"+(++Xs).toString(36)}function b(t,n,e){return t=w(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function w(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function M(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}function T(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function k(t,n,e){var r=Gs.hasOwnProperty(t.type)?b:w;return function(i,o,u){var a,c=this.__on,s=r(n,o,u);if(c)for(var f=0,l=c.length;f<l;++f)if((a=c[f]).type===t.type&&a.name===t.name)return this.removeEventListener(a.type,a.listener,a.capture),this.addEventListener(a.type,a.listener=s,a.capture=e),void(a.value=n);this.addEventListener(t.type,s,e),a={type:t.type,name:t.name,value:n,listener:s,capture:e},c?c.push(a):this.__on=[a]}}function N(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function S(){}function E(){return[]}function A(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function C(t,n,e,r,i,o){for(var u,a=0,c=n.length,s=o.length;a<s;++a)(u=n[a])?(u.__data__=o[a],r[a]=u):e[a]=new A(t,o[a]);for(;a<c;++a)(u=n[a])&&(i[a]=u)}function z(t,n,e,r,i,o,u){var a,c,s,f={},l=n.length,h=o.length,p=new Array(l);for(a=0;a<l;++a)(c=n[a])&&(p[a]=s=of+u.call(c,c.__data__,a,n),s in f?i[a]=c:f[s]=c);for(a=0;a<h;++a)(c=f[s=of+u.call(t,o[a],a,o)])?(r[a]=c,c.__data__=o[a],f[s]=null):e[a]=new A(t,o[a]);for(a=0;a<l;++a)(c=n[a])&&f[p[a]]===c&&(i[a]=c)}function P(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function R(t){return function(){this.removeAttribute(t)}}function L(t){return function(){this.removeAttributeNS(t.space,t.local)}}function q(t,n){return function(){this.setAttribute(t,n)}}function U(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function D(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function O(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function F(t){return function(){this.style.removeProperty(t)}}function I(t,n,e){return function(){this.style.setProperty(t,n,e)}}function Y(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function B(t,n){return t.style.getPropertyValue(n)||uf(t).getComputedStyle(t,null).getPropertyValue(n)}function j(t){return function(){delete this[t]}}function H(t,n){return function(){this[t]=n}}function X(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function $(t){return t.trim().split(/^|\s+/)}function V(t){return t.classList||new W(t)}function W(t){this._node=t,this._names=$(t.getAttribute("class")||"")}function Z(t,n){for(var e=V(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function G(t,n){for(var e=V(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function J(t){return function(){Z(this,t)}}function Q(t){return function(){G(this,t)}}function K(t,n){return function(){(n.apply(this,arguments)?Z:G)(this,t)}}function tt(){this.textContent=""}function nt(t){return function(){this.textContent=t}}function et(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}function rt(){this.innerHTML=""}function it(t){return function(){this.innerHTML=t}}function ot(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}function ut(){this.nextSibling&&this.parentNode.appendChild(this)}function at(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function ct(){return null}function st(){var t=this.parentNode;t&&t.removeChild(this)}function ft(t,n,e){var r=uf(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function lt(t,n){return function(){return ft(this,t,n)}}function ht(t,n){return function(){return ft(this,t,n.apply(this,arguments))}}function pt(t,n){this._groups=t,this._parents=n}function dt(){return new pt([[document.documentElement]],af)}function vt(){t.event.stopImmediatePropagation()}function _t(t,n){var e=t.document.documentElement,r=cf(t).on("dragstart.drag",null);n&&(r.on("click.drag",ff,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function yt(t,n,e,r,i,o,u,a,c,s){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=u,this.dx=a,this.dy=c,this._=s}function gt(){return!t.event.button}function mt(){return this.parentNode}function xt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function bt(){return"ontouchstart"in this}function wt(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Mt(){}function Tt(t){var n;return t=(t+"").trim().toLowerCase(),(n=yf.exec(t))?(n=parseInt(n[1],16),new At(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1)):(n=gf.exec(t))?kt(parseInt(n[1],16)):(n=mf.exec(t))?new At(n[1],n[2],n[3],1):(n=xf.exec(t))?new At(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=bf.exec(t))?Nt(n[1],n[2],n[3],n[4]):(n=wf.exec(t))?Nt(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Mf.exec(t))?Ct(n[1],n[2]/100,n[3]/100,1):(n=Tf.exec(t))?Ct(n[1],n[2]/100,n[3]/100,n[4]):kf.hasOwnProperty(t)?kt(kf[t]):"transparent"===t?new At(NaN,NaN,NaN,0):null}function kt(t){return new At(t>>16&255,t>>8&255,255&t,1)}function Nt(t,n,e,r){return r<=0&&(t=n=e=NaN),new At(t,n,e,r)}function St(t){return t instanceof Mt||(t=Tt(t)),t?(t=t.rgb(),new At(t.r,t.g,t.b,t.opacity)):new At}function Et(t,n,e,r){return 1===arguments.length?St(t):new At(t,n,e,null==r?1:r)}function At(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ct(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Rt(t,n,e,r)}function zt(t){if(t instanceof Rt)return new Rt(t.h,t.s,t.l,t.opacity);if(t instanceof Mt||(t=Tt(t)),!t)return new Rt;if(t instanceof Rt)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e<r):e===o?(r-n)/a+2:(n-e)/a+4,a/=c<.5?o+i:2-o-i,u*=60):a=c>0&&c<1?0:u,new Rt(u,a,c,t.opacity)}function Pt(t,n,e,r){return 1===arguments.length?zt(t):new Rt(t,n,e,null==r?1:r)}function Rt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Lt(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function qt(t){if(t instanceof Dt)return new Dt(t.l,t.a,t.b,t.opacity);if(t instanceof Ht){var n=t.h*Nf;return new Dt(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof At||(t=St(t));var e=Yt(t.r),r=Yt(t.g),i=Yt(t.b),o=Ot((.4124564*e+.3575761*r+.1804375*i)/Ef),u=Ot((.2126729*e+.7151522*r+.072175*i)/Af);return new Dt(116*u-16,500*(o-u),200*(u-Ot((.0193339*e+.119192*r+.9503041*i)/Cf)),t.opacity)}function Ut(t,n,e,r){return 1===arguments.length?qt(t):new Dt(t,n,e,null==r?1:r)}function Dt(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Ot(t){return t>Lf?Math.pow(t,1/3):t/Rf+zf}function Ft(t){return t>Pf?t*t*t:Rf*(t-zf)}function It(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Yt(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Bt(t){if(t instanceof Ht)return new Ht(t.h,t.c,t.l,t.opacity);t instanceof Dt||(t=qt(t));var n=Math.atan2(t.b,t.a)*Sf;return new Ht(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function jt(t,n,e,r){return 1===arguments.length?Bt(t):new Ht(t,n,e,null==r?1:r)}function Ht(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function Xt(t){if(t instanceof Vt)return new Vt(t.h,t.s,t.l,t.opacity);t instanceof At||(t=St(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Bf*r+If*n-Yf*e)/(Bf+If-Yf),o=r-i,u=(Ff*(e-i)-Df*o)/Of,a=Math.sqrt(u*u+o*o)/(Ff*i*(1-i)),c=a?Math.atan2(u,o)*Sf-120:NaN;return new Vt(c<0?c+360:c,a,i,t.opacity)}function $t(t,n,e,r){return 1===arguments.length?Xt(t):new Vt(t,n,e,null==r?1:r)}function Vt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Wt(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}function Zt(t,n){return function(e){return t+e*n}}function Gt(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}function Jt(t,n){var e=n-t;return e?Zt(t,e>180||e<-180?e-360*Math.round(e/360):e):Jf(isNaN(t)?n:t)}function Qt(t){return 1==(t=+t)?Kt:function(n,e){return e-n?Gt(n,e,t):Jf(isNaN(n)?e:n)}}function Kt(t,n){var e=n-t;return e?Zt(t,e):Jf(isNaN(t)?n:t)}function tn(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e<i;++e)r=Et(n[e]),o[e]=r.r||0,u[e]=r.g||0,a[e]=r.b||0;return o=t(o),u=t(u),a=t(a),r.opacity=1,function(t){return r.r=o(t),r.g=u(t),r.b=a(t),r+""}}}function nn(t){return function(){return t}}function en(t){return function(n){return t(n)+""}}function rn(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}function o(t,r,i,o,u,a){if(t!==i||r!==o){var c=u.push("translate(",null,n,null,e);a.push({i:c-4,x:rl(t,i)},{i:c-2,x:rl(r,o)})}else(i||o)&&u.push("translate("+i+n+o+e)}function u(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:rl(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}function a(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:rl(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}function c(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:rl(t,e)},{i:a-2,x:rl(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}return function(n,e){var r=[],i=[];return n=t(n),e=t(e),o(n.translateX,n.translateY,e.translateX,e.translateY,r,i),u(n.rotate,e.rotate,r,i),a(n.skewX,e.skewX,r,i),c(n.scaleX,n.scaleY,e.scaleX,e.scaleY,r,i),n=e=null,function(t){for(var n,e=-1,o=i.length;++e<o;)r[(n=i[e]).i]=n.x(t);return r.join("")}}}function on(t){return((t=Math.exp(t))+1/t)/2}function un(t){return((t=Math.exp(t))-1/t)/2}function an(t){return((t=Math.exp(2*t))-1)/(t+1)}function cn(t){return function(n,e){var r=t((n=Pt(n)).h,(e=Pt(e)).h),i=Kt(n.s,e.s),o=Kt(n.l,e.l),u=Kt(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function sn(t){return function(n,e){var r=t((n=jt(n)).h,(e=jt(e)).h),i=Kt(n.c,e.c),o=Kt(n.l,e.l),u=Kt(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function fn(t){return function n(e){function r(n,r){var i=t((n=$t(n)).h,(r=$t(r)).h),o=Kt(n.s,r.s),u=Kt(n.l,r.l),a=Kt(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=u(Math.pow(t,e)),n.opacity=a(t),n+""}}return e=+e,r.gamma=n,r}(1)}function ln(){return El||(zl(hn),El=Cl.now()+Al)}function hn(){El=0}function pn(){this._call=this._time=this._next=null}function dn(t,n,e){var r=new pn;return r.restart(t,n,e),r}function vn(){ln(),++Ml;for(var t,n=Vf;n;)(t=El-n._time)>=0&&n._call.call(null,t),n=n._next;--Ml}function _n(){El=(Sl=Cl.now())+Al,Ml=Tl=0;try{vn()}finally{Ml=0,gn(),El=0}}function yn(){var t=Cl.now(),n=t-Sl;n>Nl&&(Al-=n,Sl=t)}function gn(){for(var t,n,e=Vf,r=1/0;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Vf=n);Wf=t,mn(r)}function mn(t){if(!Ml){Tl&&(Tl=clearTimeout(Tl));var n=t-El;n>24?(t<1/0&&(Tl=setTimeout(_n,n)),kl&&(kl=clearInterval(kl))):(kl||(Sl=El,kl=setInterval(yn,Nl)),Ml=1,zl(_n))}}function xn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>ql)throw new Error("too late");return e}function bn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>Dl)throw new Error("too late");return e}function wn(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("too late");return e}function Mn(t,n,e){function r(c){var s,f,l,h;if(e.state!==Ul)return o();for(s in a)if((h=a[s]).name===e.name){if(h.state===Ol)return Pl(r);h.state===Fl?(h.state=Yl,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete a[s]):+s<n&&(h.state=Yl,h.timer.stop(),delete a[s])}if(Pl(function(){e.state===Ol&&(e.state=Fl,e.timer.restart(i,e.delay,e.time),i(c))}),e.state=Dl,e.on.call("start",t,t.__data__,e.index,e.group),e.state===Dl){for(e.state=Ol,u=new Array(l=e.tween.length),s=0,f=-1;s<l;++s)(h=e.tween[s].value.call(t,t.__data__,e.index,e.group))&&(u[++f]=h);u.length=f+1}}function i(n){for(var r=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(o),e.state=Il,1),i=-1,a=u.length;++i<a;)u[i].call(null,r);e.state===Il&&(e.on.call("end",t,t.__data__,e.index,e.group),o())}function o(){e.state=Yl,e.timer.stop(),delete a[n];for(var r in a)return;delete t.__transition}var u,a=t.__transition;a[n]=e,e.timer=dn(function(t){e.state=Ul,e.timer.restart(r,e.delay,e.time),e.delay<=t&&r(t-e.delay)},0,e.time)}function Tn(t,n){var e,r;return function(){var i=bn(this,t),o=i.tween;if(o!==e)for(var u=0,a=(r=e=o).length;u<a;++u)if(r[u].name===n){(r=r.slice()).splice(u,1);break}i.tween=r}}function kn(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=bn(this,t),u=o.tween;if(u!==r){i=(r=u).slice();for(var a={name:n,value:e},c=0,s=i.length;c<s;++c)if(i[c].name===n){i[c]=a;break}c===s&&i.push(a)}o.tween=i}}function Nn(t,n,e){var r=t._id;return t.each(function(){var t=bn(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return wn(t,r).value[n]}}function Sn(t){return function(){this.removeAttribute(t)}}function En(t){return function(){this.removeAttributeNS(t.space,t.local)}}function An(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}}function Cn(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}function zn(t,n,e){var r,i,o;return function(){var u,a=e(this);{if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}}}function Pn(t,n,e){var r,i,o;return function(){var u,a=e(this);{if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}}function Rn(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}function Ln(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e}function qn(t,n){return function(){xn(this,t).delay=+n.apply(this,arguments)}}function Un(t,n){return n=+n,function(){xn(this,t).delay=n}}function Dn(t,n){return function(){bn(this,t).duration=+n.apply(this,arguments)}}function On(t,n){return n=+n,function(){bn(this,t).duration=n}}function Fn(t,n){if("function"!=typeof n)throw new Error;return function(){bn(this,t).ease=n}}function In(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}function Yn(t,n,e){var r,i,o=In(n)?xn:bn;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}function Bn(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}function jn(t,n){var e,r,i;return function(){var o=B(this,t),u=(this.style.removeProperty(t),B(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}function Hn(t){return function(){this.style.removeProperty(t)}}function Xn(t,n,e){var r,i;return function(){var o=B(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}function $n(t,n,e){var r,i,o;return function(){var u=B(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=B(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}function Vn(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}function Wn(t){return function(){this.textContent=t}}function Zn(t){return function(){var n=t(this);this.textContent=null==n?"":n}}function Gn(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function Jn(t){return dt().transition(t)}function Qn(){return++$l}function Kn(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function te(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}function ne(t){return(1-Math.cos(Jl*t))/2}function ee(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function re(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}function ie(t){return(t=+t)<Kl?ch*t*t:t<nh?ch*(t-=th)*t+eh:t<ih?ch*(t-=rh)*t+oh:ch*(t-=uh)*t+ah}function oe(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return _h.time=ln(),_h;return e}function ue(){t.event.stopImmediatePropagation()}function ae(t){return{type:t}}function ce(){return!t.event.button}function se(){var t=this.ownerSVGElement||this;return[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function fe(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function le(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function he(n){function e(t){var e=t.property("__brush",a).selectAll(".overlay").data([ae("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",Eh.overlay).merge(e).each(function(){var t=fe(this).extent;cf(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([ae("selection")]).enter().append("rect").attr("class","selection").attr("cursor",Eh.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var i=t.selectAll(".handle").data(n.handles,function(t){return t.type});i.exit().remove(),i.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return Eh[t.type]}),t.each(r).attr("fill","none").attr("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush touchstart.brush",u)}function r(){var t=cf(this),n=fe(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-p/2:n[0][0]-p/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-p/2:n[0][1]-p/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+p:p}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+p:p})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function i(t,n){return t.__brush.emitter||new o(t,n)}function o(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function u(){function e(){var t=Ks(w);!L||x||b||(Math.abs(t[0]-U[0])>Math.abs(t[1]-U[1])?b=!0:x=!0),U=t,m=!0,xh(),o()}function o(){var t;switch(y=U[0]-q[0],g=U[1]-q[1],T){case wh:case bh:k&&(y=Math.max(C-a,Math.min(P-p,y)),s=a+y,d=p+y),N&&(g=Math.max(z-l,Math.min(R-v,g)),h=l+g,_=v+g);break;case Mh:k<0?(y=Math.max(C-a,Math.min(P-a,y)),s=a+y,d=p):k>0&&(y=Math.max(C-p,Math.min(P-p,y)),s=a,d=p+y),N<0?(g=Math.max(z-l,Math.min(R-l,g)),h=l+g,_=v):N>0&&(g=Math.max(z-v,Math.min(R-v,g)),h=l,_=v+g);break;case Th:k&&(s=Math.max(C,Math.min(P,a-y*k)),d=Math.max(C,Math.min(P,p+y*k))),N&&(h=Math.max(z,Math.min(R,l-g*N)),_=Math.max(z,Math.min(R,v+g*N)))}d<s&&(k*=-1,t=a,a=p,p=t,t=s,s=d,d=t,M in Ah&&F.attr("cursor",Eh[M=Ah[M]])),_<h&&(N*=-1,t=l,l=v,v=t,t=h,h=_,_=t,M in Ch&&F.attr("cursor",Eh[M=Ch[M]])),S.selection&&(A=S.selection),x&&(s=A[0][0],d=A[1][0]),b&&(h=A[0][1],_=A[1][1]),A[0][0]===s&&A[0][1]===h&&A[1][0]===d&&A[1][1]===_||(S.selection=[[s,h],[d,_]],r.call(w),D.brush())}function u(){if(ue(),t.event.touches){if(t.event.touches.length)return;c&&clearTimeout(c),c=setTimeout(function(){c=null},500),O.on("touchmove.brush touchend.brush touchcancel.brush",null)}else _t(t.event.view,m),I.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);O.attr("pointer-events","all"),F.attr("cursor",Eh.overlay),S.selection&&(A=S.selection),le(A)&&(S.selection=null,r.call(w)),D.end()}if(t.event.touches){if(t.event.changedTouches.length<t.event.touches.length)return xh()}else if(c)return;if(f.apply(this,arguments)){var a,s,l,h,p,d,v,_,y,g,m,x,b,w=this,M=t.event.target.__data__.type,T="selection"===(t.event.metaKey?M="overlay":M)?bh:t.event.altKey?Th:Mh,k=n===Nh?null:zh[M],N=n===kh?null:Ph[M],S=fe(w),E=S.extent,A=S.selection,C=E[0][0],z=E[0][1],P=E[1][0],R=E[1][1],L=k&&N&&t.event.shiftKey,q=Ks(w),U=q,D=i(w,arguments).beforestart();"overlay"===M?S.selection=A=[[a=n===Nh?C:q[0],l=n===kh?z:q[1]],[p=n===Nh?P:a,v=n===kh?R:l]]:(a=A[0][0],l=A[0][1],p=A[1][0],v=A[1][1]),s=a,h=l,d=p,_=v;var O=cf(w).attr("pointer-events","none"),F=O.selectAll(".overlay").attr("cursor",Eh[M]);if(t.event.touches)O.on("touchmove.brush",e,!0).on("touchend.brush touchcancel.brush",u,!0);else{var I=cf(t.event.view).on("keydown.brush",function(){switch(t.event.keyCode){case 16:L=k&&N;break;case 18:T===Mh&&(k&&(p=d-y*k,a=s+y*k),N&&(v=_-g*N,l=h+g*N),T=Th,o());break;case 32:T!==Mh&&T!==Th||(k<0?p=d-y:k>0&&(a=s-y),N<0?v=_-g:N>0&&(l=h-g),T=wh,F.attr("cursor",Eh.selection),o());break;default:return}xh()},!0).on("keyup.brush",function(){switch(t.event.keyCode){case 16:L&&(x=b=L=!1,o());break;case 18:T===Th&&(k<0?p=d:k>0&&(a=s),N<0?v=_:N>0&&(l=h),T=Mh,o());break;case 32:T===wh&&(t.event.altKey?(k&&(p=d-y*k,a=s+y*k),N&&(v=_-g*N,l=h+g*N),T=Th):(k<0?p=d:k>0&&(a=s),N<0?v=_:N>0&&(l=h),T=Mh),F.attr("cursor",Eh[M]),o());break;default:return}xh()},!0).on("mousemove.brush",e,!0).on("mouseup.brush",u,!0);lf(t.event.view)}ue(),jl(w),r.call(w),D.start()}}function a(){var t=this.__brush||{selection:null};return t.extent=s.apply(this,arguments),t.dim=n,t}var c,s=se,f=ce,l=h(e,"start","brush","end"),p=6;return e.move=function(t,e){t.selection?t.on("start.brush",function(){i(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){i(this,arguments).end()}).tween("brush",function(){function t(t){u.selection=1===t&&le(s)?null:f(t),r.call(o),a.brush()}var o=this,u=o.__brush,a=i(o,arguments),c=u.selection,s=n.input("function"==typeof e?e.apply(this,arguments):e,u.extent),f=cl(c,s);return c&&s?t:t(1)}):t.each(function(){var t=this,o=arguments,u=t.__brush,a=n.input("function"==typeof e?e.apply(t,o):e,u.extent),c=i(t,o).beforestart();jl(t),u.selection=null==a||le(a)?null:a,r.call(t),c.start().brush().end()})},o.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting&&(this.starting=!1,this.emit("start")),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){N(new mh(e,t,n.output(this.state.selection)),l.apply,l,[t,this.that,this.args])}},e.extent=function(t){return arguments.length?(s="function"==typeof t?t:gh([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),e):s},e.filter=function(t){return arguments.length?(f="function"==typeof t?t:gh(!!t),e):f},e.handleSize=function(t){return arguments.length?(p=+t,e):p},e.on=function(){var t=l.on.apply(l,arguments);return t===l?e:t},e}function pe(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}function de(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function ve(){return new de}function _e(t){return t.source}function ye(t){return t.target}function ge(t){return t.radius}function me(t){return t.startAngle}function xe(t){return t.endAngle}function be(){}function we(t,n){var e=new be;if(t instanceof be)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var u in t)e.set(u,t[u]);return e}function Me(){return{}}function Te(t,n,e){t[n]=e}function ke(){return we()}function Ne(t,n,e){t.set(n,e)}function Se(){}function Ee(t,n){var e=new Se;if(t instanceof Se)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}function Ae(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}")}function Ce(t,n){var e=Ae(t);return function(r,i){return n(e(r),i,t)}}function ze(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function Pe(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,u,a,c,s,f,l,h,p=t._root,d={data:r},v=t._x0,_=t._y0,y=t._x1,g=t._y1;if(!p)return t._root=d,t;for(;p.length;)if((s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u,i=p,!(p=p[l=f<<1|s]))return i[l]=d,t;if(a=+t._x.call(null,p.data),c=+t._y.call(null,p.data),n===a&&e===c)return d.next=p,i?i[l]=d:t._root=d,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u}while((l=f<<1|s)==(h=(c>=u)<<1|a>=o));return i[h]=p,i[l]=d,t}function Re(t){return t[0]}function Le(t){return t[1]}function qe(t,n,e){var r=new Ue(null==n?Re:n,null==e?Le:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ue(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function De(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}function Oe(t){return t.x+t.vx}function Fe(t){return t.y+t.vy}function Ie(t){return t.index}function Ye(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function Be(t){return t.x}function je(t){return t.y}function He(t){return new Xe(t)}function Xe(t){if(!(n=vp.exec(t)))throw new Error("invalid format: "+t);var n,e=n[1]||" ",r=n[2]||">",i=n[3]||"-",o=n[4]||"",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],s=n[8]&&+n[8].slice(1),f=n[9]||"";"n"===f?(c=!0,f="g"):dp[f]||(f=""),(u||"0"===e&&"="===r)&&(u=!0,e="0",r="="),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=s,this.type=f}function $e(n){return _p=mp(n),t.format=_p.format,t.formatPrefix=_p.formatPrefix,_p}function Ve(){this.reset()}function We(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}function Ze(t){return t>1?0:t<-1?rd:Math.acos(t)}function Ge(t){return t>1?id:t<-1?-id:Math.asin(t)}function Je(t){return(t=yd(t/2))*t}function Qe(){}function Ke(t,n){t&&wd.hasOwnProperty(t.type)&&wd[t.type](t,n)}function tr(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function nr(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)tr(t[e],n,1);n.polygonEnd()}function er(){Nd.point=ir}function rr(){or(Tp,kp)}function ir(t,n){Nd.point=or,Tp=t,kp=n,Np=t*=cd,Sp=hd(n=(n*=cd)/2+od),Ep=yd(n)}function or(t,n){n=(n*=cd)/2+od;var e=(t*=cd)-Np,r=e>=0?1:-1,i=r*e,o=hd(n),u=yd(n),a=Ep*u,c=Sp*o+a*hd(i),s=a*r*yd(i);Td.add(ld(s,c)),Np=t,Sp=o,Ep=u}function ur(t){return[ld(t[1],t[0]),Ge(t[2])]}function ar(t){var n=t[0],e=t[1],r=hd(e);return[r*hd(n),r*yd(n),yd(e)]}function cr(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function sr(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function fr(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function lr(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function hr(t){var n=md(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}function pr(t,n){Dp.push(Op=[Ap=t,zp=t]),n<Cp&&(Cp=n),n>Pp&&(Pp=n)}function dr(t,n){var e=ar([t*cd,n*cd]);if(Up){var r=sr(Up,e),i=sr([r[1],-r[0],0],r);hr(i),i=ur(i);var o,u=t-Rp,a=u>0?1:-1,c=i[0]*ad*a,s=sd(u)>180;s^(a*Rp<c&&c<a*t)?(o=i[1]*ad)>Pp&&(Pp=o):(c=(c+360)%360-180,s^(a*Rp<c&&c<a*t)?(o=-i[1]*ad)<Cp&&(Cp=o):(n<Cp&&(Cp=n),n>Pp&&(Pp=n))),s?t<Rp?xr(Ap,t)>xr(Ap,zp)&&(zp=t):xr(t,zp)>xr(Ap,zp)&&(Ap=t):zp>=Ap?(t<Ap&&(Ap=t),t>zp&&(zp=t)):t>Rp?xr(Ap,t)>xr(Ap,zp)&&(zp=t):xr(t,zp)>xr(Ap,zp)&&(Ap=t)}else Dp.push(Op=[Ap=t,zp=t]);n<Cp&&(Cp=n),n>Pp&&(Pp=n),Up=e,Rp=t}function vr(){Ed.point=dr}function _r(){Op[0]=Ap,Op[1]=zp,Ed.point=pr,Up=null}function yr(t,n){if(Up){var e=t-Rp;Sd.add(sd(e)>180?e+(e>0?360:-360):e)}else Lp=t,qp=n;Nd.point(t,n),dr(t,n)}function gr(){Nd.lineStart()}function mr(){yr(Lp,qp),Nd.lineEnd(),sd(Sd)>ed&&(Ap=-(zp=180)),Op[0]=Ap,Op[1]=zp,Up=null}function xr(t,n){return(n-=t)<0?n+360:n}function br(t,n){return t[0]-n[0]}function wr(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}function Mr(t,n){t*=cd;var e=hd(n*=cd);Tr(e*hd(t),e*yd(t),yd(n))}function Tr(t,n,e){Yp+=(t-Yp)/++Fp,Bp+=(n-Bp)/Fp,jp+=(e-jp)/Fp}function kr(){Ad.point=Nr}function Nr(t,n){t*=cd;var e=hd(n*=cd);Qp=e*hd(t),Kp=e*yd(t),td=yd(n),Ad.point=Sr,Tr(Qp,Kp,td)}function Sr(t,n){t*=cd;var e=hd(n*=cd),r=e*hd(t),i=e*yd(t),o=yd(n),u=ld(md((u=Kp*o-td*i)*u+(u=td*r-Qp*o)*u+(u=Qp*i-Kp*r)*u),Qp*r+Kp*i+td*o);Ip+=u,Hp+=u*(Qp+(Qp=r)),Xp+=u*(Kp+(Kp=i)),$p+=u*(td+(td=o)),Tr(Qp,Kp,td)}function Er(){Ad.point=Mr}function Ar(){Ad.point=zr}function Cr(){Pr(Gp,Jp),Ad.point=Mr}function zr(t,n){Gp=t,Jp=n,t*=cd,n*=cd,Ad.point=Pr;var e=hd(n);Qp=e*hd(t),Kp=e*yd(t),td=yd(n),Tr(Qp,Kp,td)}function Pr(t,n){t*=cd;var e=hd(n*=cd),r=e*hd(t),i=e*yd(t),o=yd(n),u=Kp*o-td*i,a=td*r-Qp*o,c=Qp*i-Kp*r,s=md(u*u+a*a+c*c),f=Ge(s),l=s&&-f/s;Vp+=l*u,Wp+=l*a,Zp+=l*c,Ip+=f,Hp+=f*(Qp+(Qp=r)),Xp+=f*(Kp+(Kp=i)),$p+=f*(td+(td=o)),Tr(Qp,Kp,td)}function Rr(t,n){return[t>rd?t-ud:t<-rd?t+ud:t,n]}function Lr(t,n,e){return(t%=ud)?n||e?zd(Ur(t),Dr(n,e)):Ur(t):n||e?Dr(n,e):Rr}function qr(t){return function(n,e){return n+=t,[n>rd?n-ud:n<-rd?n+ud:n,e]}}function Ur(t){var n=qr(t);return n.invert=qr(-t),n}function Dr(t,n){function e(t,n){var e=hd(n),a=hd(t)*e,c=yd(t)*e,s=yd(n),f=s*r+a*i;return[ld(c*o-f*u,a*r-s*i),Ge(f*o+c*u)]}var r=hd(t),i=yd(t),o=hd(n),u=yd(n);return e.invert=function(t,n){var e=hd(n),a=hd(t)*e,c=yd(t)*e,s=yd(n),f=s*o-c*u;return[ld(c*o+s*u,a*r+f*i),Ge(f*r-a*i)]},e}function Or(t,n,e,r,i,o){if(e){var u=hd(n),a=yd(n),c=r*e;null==i?(i=n+r*ud,o=n-c/2):(i=Fr(u,i),o=Fr(u,o),(r>0?i<o:i>o)&&(i+=r*ud));for(var s,f=i;r>0?f>o:f<o;f-=c)s=ur([u,-a*hd(f),-a*yd(f)]),t.point(s[0],s[1])}}function Fr(t,n){(n=ar(n))[0]-=t,hr(n);var e=Ze(-n[1]);return((-n[2]<0?-e:e)+ud-ed)%ud}function Ir(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Yr(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function Br(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,a,s){var f=0,l=0;if(null==i||(f=u(i,a))!==(l=u(o,a))||c(i,o)<0^a>0)do{s.point(0===f||3===f?t:e,f>1?r:n)}while((f=(f+a+4)%4)!==l);else s.point(o[0],o[1])}function u(r,i){return sd(r[0]-t)<ed?i>0?0:3:sd(r[0]-e)<ed?i>0?2:1:sd(r[1]-n)<ed?i>0?1:0:i>0?3:2}function a(t,n){return c(t.x,n.x)}function c(t,n){var e=u(t,1),r=u(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){function c(t,n){i(t,n)&&w.point(t,n)}function s(){for(var n=0,e=0,i=h.length;e<i;++e)for(var o,u,a=h[e],c=1,s=a.length,f=a[0],l=f[0],p=f[1];c<s;++c)o=l,u=p,l=(f=a[c])[0],p=f[1],u<=r?p>r&&(l-o)*(r-u)>(p-u)*(t-o)&&++n:p<=r&&(l-o)*(r-u)<(p-u)*(t-o)&&--n;return n}function f(o,u){var a=i(o,u);if(h&&p.push([o,u]),x)d=o,v=u,_=a,x=!1,a&&(w.lineStart(),w.point(o,u));else if(a&&m)w.point(o,u);else{var c=[y=Math.max(Zd,Math.min(Wd,y)),g=Math.max(Zd,Math.min(Wd,g))],s=[o=Math.max(Zd,Math.min(Wd,o)),u=Math.max(Zd,Math.min(Wd,u))];Xd(c,s,t,n,e,r)?(m||(w.lineStart(),w.point(c[0],c[1])),w.point(s[0],s[1]),a||w.lineEnd(),b=!1):a&&(w.lineStart(),w.point(o,u),b=!1)}y=o,g=u,m=a}var l,h,p,d,v,_,y,g,m,x,b,w=u,M=Hd(),T={point:c,lineStart:function(){T.point=f,h&&h.push(p=[]),x=!0,m=!1,y=g=NaN},lineEnd:function(){l&&(f(d,v),_&&m&&M.rejoin(),l.push(M.result())),T.point=c,m&&w.lineEnd()},polygonStart:function(){w=M,l=[],h=[],b=!0},polygonEnd:function(){var t=s(),n=b&&t,e=(l=Cs(l)).length;(n||e)&&(u.polygonStart(),n&&(u.lineStart(),o(null,null,1,u),u.lineEnd()),e&&Vd(l,a,t,o,u),u.polygonEnd()),w=u,l=h=p=null}};return T}}function jr(){Kd.point=Kd.lineEnd=Qe}function Hr(t,n){Pd=t*=cd,Rd=yd(n*=cd),Ld=hd(n),Kd.point=Xr}function Xr(t,n){t*=cd;var e=yd(n*=cd),r=hd(n),i=sd(t-Pd),o=hd(i),u=r*yd(i),a=Ld*e-Rd*r*o,c=Rd*e+Ld*r*o;Qd.add(ld(md(u*u+a*a),c)),Pd=t,Rd=e,Ld=r}function $r(t,n){return!(!t||!ov.hasOwnProperty(t.type))&&ov[t.type](t,n)}function Vr(t,n){return 0===rv(t,n)}function Wr(t,n){var e=rv(t[0],t[1]);return rv(t[0],n)+rv(n,t[1])<=e+ed}function Zr(t,n){return!!Jd(t.map(Gr),Jr(n))}function Gr(t){return(t=t.map(Jr)).pop(),t}function Jr(t){return[t[0]*cd,t[1]*cd]}function Qr(t,n,e){var r=Ms(t,n-ed,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function Kr(t,n,e){var r=Ms(t,n-ed,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function ti(){function t(){return{type:"MultiLineString",coordinates:n()}}function n(){return Ms(pd(o/_)*_,i,_).map(h).concat(Ms(pd(s/y)*y,c,y).map(p)).concat(Ms(pd(r/d)*d,e,d).filter(function(t){return sd(t%_)>ed}).map(f)).concat(Ms(pd(a/v)*v,u,v).filter(function(t){return sd(t%y)>ed}).map(l))}var e,r,i,o,u,a,c,s,f,l,h,p,d=10,v=d,_=90,y=360,g=2.5;return t.lines=function(){return n().map(function(t){return{type:"LineString",coordinates:t}})},t.outline=function(){return{type:"Polygon",coordinates:[h(o).concat(p(c).slice(1),h(i).reverse().slice(1),p(s).reverse().slice(1))]}},t.extent=function(n){return arguments.length?t.extentMajor(n).extentMinor(n):t.extentMinor()},t.extentMajor=function(n){return arguments.length?(o=+n[0][0],i=+n[1][0],s=+n[0][1],c=+n[1][1],o>i&&(n=o,o=i,i=n),s>c&&(n=s,s=c,c=n),t.precision(g)):[[o,s],[i,c]]},t.extentMinor=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],a=+n[0][1],u=+n[1][1],r>e&&(n=r,r=e,e=n),a>u&&(n=a,a=u,u=n),t.precision(g)):[[r,a],[e,u]]},t.step=function(n){return arguments.length?t.stepMajor(n).stepMinor(n):t.stepMinor()},t.stepMajor=function(n){return arguments.length?(_=+n[0],y=+n[1],t):[_,y]},t.stepMinor=function(n){return arguments.length?(d=+n[0],v=+n[1],t):[d,v]},t.precision=function(n){return arguments.length?(g=+n,f=Qr(a,u,90),l=Kr(r,e,g),h=Qr(s,c,90),p=Kr(o,i,g),t):g},t.extentMajor([[-180,-90+ed],[180,90-ed]]).extentMinor([[-180,-80-ed],[180,80+ed]])}function ni(){sv.point=ei}function ei(t,n){sv.point=ri,qd=Dd=t,Ud=Od=n}function ri(t,n){cv.add(Od*t-Dd*n),Dd=t,Od=n}function ii(){ri(qd,Ud)}function oi(t,n){vv+=t,_v+=n,++yv}function ui(){Tv.point=ai}function ai(t,n){Tv.point=ci,oi(Yd=t,Bd=n)}function ci(t,n){var e=t-Yd,r=n-Bd,i=md(e*e+r*r);gv+=i*(Yd+t)/2,mv+=i*(Bd+n)/2,xv+=i,oi(Yd=t,Bd=n)}function si(){Tv.point=oi}function fi(){Tv.point=hi}function li(){pi(Fd,Id)}function hi(t,n){Tv.point=pi,oi(Fd=Yd=t,Id=Bd=n)}function pi(t,n){var e=t-Yd,r=n-Bd,i=md(e*e+r*r);gv+=i*(Yd+t)/2,mv+=i*(Bd+n)/2,xv+=i,bv+=(i=Bd*t-Yd*n)*(Yd+t),wv+=i*(Bd+n),Mv+=3*i,oi(Yd=t,Bd=n)}function di(t){this._context=t}function vi(t,n){zv.point=_i,Nv=Ev=t,Sv=Av=n}function _i(t,n){Ev-=t,Av-=n,Cv.add(md(Ev*Ev+Av*Av)),Ev=t,Av=n}function yi(){this._string=[]}function gi(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function mi(t){return t.length>1}function xi(t,n){return((t=t.x)[0]<0?t[1]-id-ed:id-t[1])-((n=n.x)[0]<0?n[1]-id-ed:id-n[1])}function bi(t,n,e,r){var i,o,u=yd(t-e);return sd(u)>ed?fd((yd(n)*(o=hd(r))*yd(e)-yd(r)*(i=hd(n))*yd(t))/(i*o*u)):(n+r)/2}function wi(t){return function(n){var e=new Mi;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Mi(){}function Ti(t,n,e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=t.clipExtent&&t.clipExtent();t.scale(150).translate([0,0]),null!=o&&t.clipExtent(null),Md(e,t.stream(dv));var u=dv.result(),a=Math.min(r/(u[1][0]-u[0][0]),i/(u[1][1]-u[0][1])),c=+n[0][0]+(r-a*(u[1][0]+u[0][0]))/2,s=+n[0][1]+(i-a*(u[1][1]+u[0][1]))/2;return null!=o&&t.clipExtent(o),t.scale(150*a).translate([c,s])}function ki(t,n,e){return Ti(t,[[0,0],n],e)}function Ni(t){return wi({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}function Si(t,n){function e(r,i,o,u,a,c,s,f,l,h,p,d,v,_){var y=s-r,g=f-i,m=y*y+g*g;if(m>4*n&&v--){var x=u+h,b=a+p,w=c+d,M=md(x*x+b*b+w*w),T=Ge(w/=M),k=sd(sd(w)-1)<ed||sd(o-l)<ed?(o+l)/2:ld(b,x),N=t(k,T),S=N[0],E=N[1],A=S-r,C=E-i,z=g*A-y*C;(z*z/m>n||sd((y*A+g*C)/m-.5)>.3||u*h+a*p+c*d<Uv)&&(e(r,i,o,u,a,c,S,E,k,x/=M,b/=M,w,v,_),_.point(S,E),e(S,E,k,x,b,w,s,f,l,h,p,d,v,_))}}return function(n){function r(e,r){e=t(e,r),n.point(e[0],e[1])}function i(){y=NaN,w.point=o,n.lineStart()}function o(r,i){var o=ar([r,i]),u=t(r,i);e(y,g,_,m,x,b,y=u[0],g=u[1],_=r,m=o[0],x=o[1],b=o[2],qv,n),n.point(y,g)}function u(){w.point=r,n.lineEnd()}function a(){i(),w.point=c,w.lineEnd=s}function c(t,n){o(f=t,n),l=y,h=g,p=m,d=x,v=b,w.point=o}function s(){e(y,g,_,m,x,b,l,h,f,p,d,v,qv,n),w.lineEnd=u,u()}var f,l,h,p,d,v,_,y,g,m,x,b,w={point:r,lineStart:i,lineEnd:u,polygonStart:function(){n.polygonStart(),w.lineStart=a},polygonEnd:function(){n.polygonEnd(),w.lineStart=i}};return w}}function Ei(t){return Ai(function(){return t})()}function Ai(t){function n(t){return t=f(t[0]*cd,t[1]*cd),[t[0]*_+a,c-t[1]*_]}function e(t){return(t=f.invert((t[0]-a)/_,(c-t[1])/_))&&[t[0]*ad,t[1]*ad]}function r(t,n){return t=u(t,n),[t[0]*_+a,c-t[1]*_]}function i(){f=zd(s=Lr(b,w,M),u);var t=u(m,x);return a=y-t[0]*_,c=g+t[1]*_,o()}function o(){return d=v=null,n}var u,a,c,s,f,l,h,p,d,v,_=150,y=480,g=250,m=0,x=0,b=0,w=0,M=0,T=null,k=Rv,N=null,S=uv,E=.5,A=Dv(r,E);return n.stream=function(t){return d&&v===t?d:d=Ov(k(s,A(S(v=t))))},n.clipAngle=function(t){return arguments.length?(k=+t?Lv(T=t*cd,6*cd):(T=null,Rv),o()):T*ad},n.clipExtent=function(t){return arguments.length?(S=null==t?(N=l=h=p=null,uv):Br(N=+t[0][0],l=+t[0][1],h=+t[1][0],p=+t[1][1]),o()):null==N?null:[[N,l],[h,p]]},n.scale=function(t){return arguments.length?(_=+t,i()):_},n.translate=function(t){return arguments.length?(y=+t[0],g=+t[1],i()):[y,g]},n.center=function(t){return arguments.length?(m=t[0]%360*cd,x=t[1]%360*cd,i()):[m*ad,x*ad]},n.rotate=function(t){return arguments.length?(b=t[0]%360*cd,w=t[1]%360*cd,M=t.length>2?t[2]%360*cd:0,i()):[b*ad,w*ad,M*ad]},n.precision=function(t){return arguments.length?(A=Dv(r,E=t*t),o()):md(E)},n.fitExtent=function(t,e){return Ti(n,t,e)},n.fitSize=function(t,e){return ki(n,t,e)},function(){return u=t.apply(this,arguments),n.invert=u.invert&&e,i()}}function Ci(t){var n=0,e=rd/3,r=Ai(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*cd,e=t[1]*cd):[n*ad,e*ad]},i}function zi(t){function n(t,n){return[t*e,yd(n)/e]}var e=hd(t);return n.invert=function(t,n){return[t/e,Ge(n*e)]},n}function Pi(t,n){function e(t,n){var e=md(o-2*i*yd(n))/i;return[e*yd(t*=i),u-e*hd(t)]}var r=yd(t),i=(r+yd(n))/2;if(sd(i)<ed)return zi(t);var o=1+r*(2*i-r),u=md(o)/i;return e.invert=function(t,n){var e=u-n;return[ld(t,sd(e))/i*gd(e),Ge((o-(t*t+e*e)*i*i)/(2*i))]},e}function Ri(t){var n=t.length;return{point:function(e,r){for(var i=-1;++i<n;)t[i].point(e,r)},sphere:function(){for(var e=-1;++e<n;)t[e].sphere()},lineStart:function(){for(var e=-1;++e<n;)t[e].lineStart()},lineEnd:function(){for(var e=-1;++e<n;)t[e].lineEnd()},polygonStart:function(){for(var e=-1;++e<n;)t[e].polygonStart()},polygonEnd:function(){for(var e=-1;++e<n;)t[e].polygonEnd()}}}function Li(t){return function(n,e){var r=hd(n),i=hd(e),o=t(r*i);return[o*i*yd(n),o*yd(e)]}}function qi(t){return function(n,e){var r=md(n*n+e*e),i=t(r),o=yd(i),u=hd(i);return[ld(n*o,r*u),Ge(r&&e*o/r)]}}function Ui(t,n){return[t,vd(xd((id+n)/2))]}function Di(t){function n(){var n=rd*a(),u=o(jd(o.rotate()).invert([0,0]));return s(null==f?[[u[0]-n,u[1]-n],[u[0]+n,u[1]+n]]:t===Ui?[[Math.max(u[0]-n,f),e],[Math.min(u[0]+n,r),i]]:[[f,Math.max(u[1]-n,e)],[r,Math.min(u[1]+n,i)]])}var e,r,i,o=Ei(t),u=o.center,a=o.scale,c=o.translate,s=o.clipExtent,f=null;return o.scale=function(t){return arguments.length?(a(t),n()):a()},o.translate=function(t){return arguments.length?(c(t),n()):c()},o.center=function(t){return arguments.length?(u(t),n()):u()},o.clipExtent=function(t){return arguments.length?(null==t?f=e=r=i=null:(f=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),n()):null==f?null:[[f,e],[r,i]]},n()}function Oi(t){return xd((id+t)/2)}function Fi(t,n){function e(t,n){o>0?n<-id+ed&&(n=-id+ed):n>id-ed&&(n=id-ed);var e=o/_d(Oi(n),i);return[e*yd(i*t),o-e*hd(i*t)]}var r=hd(t),i=t===n?yd(t):vd(r/hd(n))/vd(Oi(n)/Oi(t)),o=r*_d(Oi(t),i)/i;return i?(e.invert=function(t,n){var e=o-n,r=gd(i)*md(t*t+e*e);return[ld(t,sd(e))/i*gd(e),2*fd(_d(o/r,1/i))-id]},e):Ui}function Ii(t,n){return[t,n]}function Yi(t,n){function e(t,n){var e=o-n,r=i*t;return[e*yd(r),o-e*hd(r)]}var r=hd(t),i=t===n?yd(t):(r-hd(n))/(n-t),o=r/i+t;return sd(i)<ed?Ii:(e.invert=function(t,n){var e=o-n;return[ld(t,sd(e))/i*gd(e),o-gd(i)*md(t*t+e*e)]},e)}function Bi(t,n){var e=hd(n),r=hd(t)*e;return[e*yd(t)/r,yd(n)/r]}function ji(t,n,e,r){return 1===t&&1===n&&0===e&&0===r?uv:wi({point:function(i,o){this.stream.point(i*t+e,o*n+r)}})}function Hi(t,n){return[hd(n)*yd(t),yd(n)]}function Xi(t,n){var e=hd(n),r=1+hd(t)*e;return[e*yd(t)/r,yd(n)/r]}function $i(t,n){return[vd(xd((id+n)/2)),-t]}function Vi(t,n){return t.parent===n.parent?1:2}function Wi(t){return t.reduce(Zi,0)/t.length}function Zi(t,n){return t+n.x}function Gi(t){return 1+t.reduce(Ji,0)}function Ji(t,n){return Math.max(t,n.y)}function Qi(t){for(var n;n=t.children;)t=n[0];return t}function Ki(t){for(var n;n=t.children;)t=n[n.length-1];return t}function to(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function no(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}function eo(t,n){var e,r,i,o,u,a=new uo(t),c=+t.value&&(a.value=t.value),s=[a];for(null==n&&(n=ro);e=s.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(u=i.length))for(e.children=new Array(u),o=u-1;o>=0;--o)s.push(r=e.children[o]=new uo(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(oo)}function ro(t){return t.children}function io(t){t.data=t.data.data}function oo(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function uo(t){this.data=t,this.depth=this.height=0,this.parent=null}function ao(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}function co(t,n){var e,r;if(lo(n,t))return[n];for(e=0;e<t.length;++e)if(so(n,t[e])&&lo(vo(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(so(vo(t[e],t[r]),n)&&so(vo(t[e],n),t[r])&&so(vo(t[r],n),t[e])&&lo(_o(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function so(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function fo(t,n){var e=t.r-n.r+1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function lo(t,n){for(var e=0;e<n.length;++e)if(!fo(t,n[e]))return!1;return!0}function ho(t){switch(t.length){case 1:return po(t[0]);case 2:return vo(t[0],t[1]);case 3:return _o(t[0],t[1],t[2])}}function po(t){return{x:t.x,y:t.y,r:t.r}}function vo(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,u=n.y,a=n.r,c=o-e,s=u-r,f=a-i,l=Math.sqrt(c*c+s*s);return{x:(e+o+c/l*f)/2,y:(r+u+s/l*f)/2,r:(l+i+a)/2}}function _o(t,n,e){var r=t.x,i=t.y,o=t.r,u=n.x,a=n.y,c=n.r,s=e.x,f=e.y,l=e.r,h=r-u,p=r-s,d=i-a,v=i-f,_=c-o,y=l-o,g=r*r+i*i-o*o,m=g-u*u-a*a+c*c,x=g-s*s-f*f+l*l,b=p*d-h*v,w=(d*x-v*m)/(2*b)-r,M=(v*_-d*y)/b,T=(p*m-h*x)/(2*b)-i,k=(h*y-p*_)/b,N=M*M+k*k-1,S=2*(o+w*M+T*k),E=w*w+T*T-o*o,A=-(N?(S+Math.sqrt(S*S-4*N*E))/(2*N):E/S);return{x:r+w+M*A,y:i+T+k*A,r:A}}function yo(t,n,e){var r=t.x,i=t.y,o=n.r+e.r,u=t.r+e.r,a=n.x-r,c=n.y-i,s=a*a+c*c;if(s){var f=.5+((u*=u)-(o*=o))/(2*s),l=Math.sqrt(Math.max(0,2*o*(u+s)-(u-=s)*u-o*o))/(2*s);e.x=r+f*a+l*c,e.y=i+f*c-l*a}else e.x=r+u,e.y=i}function go(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return i*i-1e-6>e*e+r*r}function mo(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function xo(t){this._=t,this.next=null,this.previous=null}function bo(t){if(!(i=t.length))return 0;var n,e,r,i,o,u,a,c,s,f,l;if(n=t[0],n.x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;yo(e,n,r=t[2]),n=new xo(n),e=new xo(e),r=new xo(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(a=3;a<i;++a){yo(n._,e._,r=t[a]),r=new xo(r),c=e.next,s=n.previous,f=e._.r,l=n._.r;do{if(f<=l){if(go(c._,r._)){e=c,n.next=e,e.previous=n,--a;continue t}f+=c._.r,c=c.next}else{if(go(s._,r._)){(n=s).next=e,e.previous=n,--a;continue t}l+=s._.r,s=s.previous}}while(c!==s.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=mo(n);(r=r.next)!==e;)(u=mo(r))<o&&(n=r,o=u);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Hv(n),a=0;a<i;++a)n=t[a],n.x-=r.x,n.y-=r.y;return r.r}function wo(t){return null==t?null:Mo(t)}function Mo(t){if("function"!=typeof t)throw new Error;return t}function To(){return 0}function ko(t){return Math.sqrt(t.value)}function No(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function So(t,n){return function(e){if(r=e.children){var r,i,o,u=r.length,a=t(e)*n||0;if(a)for(i=0;i<u;++i)r[i].r+=a;if(o=bo(r),a)for(i=0;i<u;++i)r[i].r-=a;e.r=o+a}}}function Eo(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Ao(t){return t.id}function Co(t){return t.parentId}function zo(t,n){return t.parent===n.parent?1:2}function Po(t){var n=t.children;return n?n[0]:t.t}function Ro(t){var n=t.children;return n?n[n.length-1]:t.t}function Lo(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function qo(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}function Uo(t,n,e){return t.a.parent===n.parent?t.a:e}function Do(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Oo(t){for(var n,e,r,i,o,u=new Do(t,0),a=[u];n=a.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)a.push(e=n.children[i]=new Do(r[i],i)),e.parent=n;return(u.parent=new Do(null,0)).children=[u],u}function Fo(t,n,e,r,i,o){for(var u,a,c,s,f,l,h,p,d,v,_,y=[],g=n.children,m=0,x=0,b=g.length,w=n.value;m<b;){c=i-e,s=o-r;do{f=g[x++].value}while(!f&&x<b);for(l=h=f,_=f*f*(v=Math.max(s/c,c/s)/(w*t)),d=Math.max(h/_,_/l);x<b;++x){if(f+=a=g[x].value,a<l&&(l=a),a>h&&(h=a),_=f*f*v,(p=Math.max(h/_,_/l))>d){f-=a;break}d=p}y.push(u={value:f,dice:c<s,children:g.slice(m,x)}),u.dice?Vv(u,e,r,i,w?r+=s*f/w:o):Jv(u,e,r,w?e+=c*f/w:i,o),w-=f,m=x}return y}function Io(t,n){return t[0]-n[0]||t[1]-n[1]}function Yo(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&n_(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function Bo(t){this._size=t,this._call=this._error=null,this._tasks=[],this._data=[],this._waiting=this._active=this._ended=this._start=0}function jo(t){if(!t._start)try{Ho(t)}catch(n){if(t._tasks[t._ended+t._active-1])$o(t,n);else if(!t._data)throw n}}function Ho(t){for(;t._start=t._waiting&&t._active<t._size;){var n=t._ended+t._active,e=t._tasks[n],r=e.length-1,i=e[r];e[r]=Xo(t,n),--t._waiting,++t._active,e=i.apply(null,e),t._tasks[n]&&(t._tasks[n]=e||r_)}}function Xo(t,n){return function(e,r){t._tasks[n]&&(--t._active,++t._ended,t._tasks[n]=null,null==t._error&&(null!=e?$o(t,e):(t._data[n]=r,t._waiting?jo(t):Vo(t))))}}function $o(t,n){var e,r=t._tasks.length;for(t._error=n,t._data=void 0,t._waiting=NaN;--r>=0;)if((e=t._tasks[r])&&(t._tasks[r]=null,e.abort))try{e.abort()}catch(n){}t._active=NaN,Vo(t)}function Vo(t){if(!t._active&&t._call){var n=t._data;t._data=void 0,t._call(t._error,n)}}function Wo(t){if(null==t)t=1/0;else if(!((t=+t)>=1))throw new Error("invalid concurrency");return new Bo(t)}function Zo(t){return function(n,e){t(null==n?e:null)}}function Go(t){var n=t.responseType;return n&&"text"!==n?t.response:t.responseText}function Jo(t,n){return function(e){return t(e.responseText,n)}}function Qo(t){function n(n){var o=n+"",u=e.get(o);if(!u){if(i!==M_)return i;e.set(o,u=r.push(n))}return t[(u-1)%t.length]}var e=we(),r=[],i=M_;return t=null==t?[]:w_.call(t),n.domain=function(t){if(!arguments.length)return r.slice();r=[],e=we();for(var i,o,u=-1,a=t.length;++u<a;)e.has(o=(i=t[u])+"")||e.set(o,r.push(i));return n},n.range=function(e){return arguments.length?(t=w_.call(e),n):t.slice()},n.unknown=function(t){return arguments.length?(i=t,n):i},n.copy=function(){return Qo().domain(r).range(t).unknown(i)},n}function Ko(){function t(){var t=i().length,r=u[1]<u[0],l=u[r-0],h=u[1-r];n=(h-l)/Math.max(1,t-c+2*s),a&&(n=Math.floor(n)),l+=(h-l-n*(t-c))*f,e=n*(1-c),a&&(l=Math.round(l),e=Math.round(e));var p=Ms(t).map(function(t){return l+n*t});return o(r?p.reverse():p)}var n,e,r=Qo().unknown(void 0),i=r.domain,o=r.range,u=[0,1],a=!1,c=0,s=0,f=.5;return delete r.unknown,r.domain=function(n){return arguments.length?(i(n),t()):i()},r.range=function(n){return arguments.length?(u=[+n[0],+n[1]],t()):u.slice()},r.rangeRound=function(n){return u=[+n[0],+n[1]],a=!0,t()},r.bandwidth=function(){return e},r.step=function(){return n},r.round=function(n){return arguments.length?(a=!!n,t()):a},r.padding=function(n){return arguments.length?(c=s=Math.max(0,Math.min(1,n)),t()):c},r.paddingInner=function(n){return arguments.length?(c=Math.max(0,Math.min(1,n)),t()):c},r.paddingOuter=function(n){return arguments.length?(s=Math.max(0,Math.min(1,n)),t()):s},r.align=function(n){return arguments.length?(f=Math.max(0,Math.min(1,n)),t()):f},r.copy=function(){return Ko().domain(i()).range(u).round(a).paddingInner(c).paddingOuter(s).align(f)},t()}function tu(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return tu(n())},t}function nu(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:T_(n)}function eu(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}function ru(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}function iu(t,n,e,r){var i=t[0],o=t[1],u=n[0],a=n[1];return o<i?(i=e(o,i),u=r(a,u)):(i=e(i,o),u=r(u,a)),function(t){return u(i(t))}}function ou(t,n,e,r){var i=Math.min(t.length,n.length)-1,o=new Array(i),u=new Array(i),a=-1;for(t[i]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<i;)o[a]=e(t[a],t[a+1]),u[a]=r(n[a],n[a+1]);return function(n){var e=hs(t,n,1,i)-1;return u[e](o[e](n))}}function uu(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp())}function au(t,n){function e(){return i=Math.min(a.length,c.length)>2?ou:iu,o=u=null,r}function r(n){return(o||(o=i(a,c,f?eu(t):t,s)))(+n)}var i,o,u,a=N_,c=N_,s=cl,f=!1;return r.invert=function(t){return(u||(u=i(c,a,nu,f?ru(n):n)))(+t)},r.domain=function(t){return arguments.length?(a=b_.call(t,k_),e()):a.slice()},r.range=function(t){return arguments.length?(c=w_.call(t),e()):c.slice()},r.rangeRound=function(t){return c=w_.call(t),s=sl,e()},r.clamp=function(t){return arguments.length?(f=!!t,e()):f},r.interpolate=function(t){return arguments.length?(s=t,e()):s},e()}function cu(t){var n=t.domain;return t.ticks=function(t){var e=n();return Ss(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){return S_(n(),t,e)},t.nice=function(e){null==e&&(e=10);var i,o=n(),u=0,a=o.length-1,c=o[u],s=o[a];return s<c&&(i=c,c=s,s=i,i=u,u=a,a=i),(i=r(c,s,e))>0?i=r(c=Math.floor(c/i)*i,s=Math.ceil(s/i)*i,e):i<0&&(i=r(c=Math.ceil(c*i)/i,s=Math.floor(s*i)/i,e)),i>0?(o[u]=Math.floor(c/i)*i,o[a]=Math.ceil(s/i)*i,n(o)):i<0&&(o[u]=Math.ceil(c*i)/i,o[a]=Math.floor(s*i)/i,n(o)),t},t}function su(){var t=au(nu,rl);return t.copy=function(){return uu(t,su())},cu(t)}function fu(){function t(t){return+t}var n=[0,1];return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=b_.call(e,k_),t):n.slice()},t.copy=function(){return fu().domain(n)},cu(t)}function lu(t,n){return(n=Math.log(n/t))?function(e){return Math.log(e/t)/n}:T_(n)}function hu(t,n){return t<0?function(e){return-Math.pow(-n,e)*Math.pow(-t,1-e)}:function(e){return Math.pow(n,e)*Math.pow(t,1-e)}}function pu(t){return isFinite(t)?+("1e"+t):t<0?0:t}function du(t){return 10===t?pu:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}function vu(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}function _u(t){return function(n){return-t(-n)}}function yu(){function n(){return o=vu(i),u=du(i),r()[0]<0&&(o=_u(o),u=_u(u)),e}var e=au(lu,hu).domain([1,10]),r=e.domain,i=10,o=vu(10),u=du(10);return e.base=function(t){return arguments.length?(i=+t,n()):i},e.domain=function(t){return arguments.length?(r(t),n()):r()},e.ticks=function(t){var n,e=r(),a=e[0],c=e[e.length-1];(n=c<a)&&(h=a,a=c,c=h);var s,f,l,h=o(a),p=o(c),d=null==t?10:+t,v=[];if(!(i%1)&&p-h<d){if(h=Math.round(h)-1,p=Math.round(p)+1,a>0){for(;h<p;++h)for(f=1,s=u(h);f<i;++f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else for(;h<p;++h)for(f=i-1,s=u(h);f>=1;--f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else v=Ss(h,p,Math.min(p-h,d)).map(u);return n?v.reverse():v},e.tickFormat=function(n,r){if(null==r&&(r=10===i?".0e":","),"function"!=typeof r&&(r=t.format(r)),n===1/0)return r;null==n&&(n=10);var a=Math.max(1,i*n/e.ticks().length);return function(t){var n=t/u(Math.round(o(t)));return n*i<i-.5&&(n*=i),n<=a?r(t):""}},e.nice=function(){return r(E_(r(),{floor:function(t){return u(Math.floor(o(t)))},ceil:function(t){return u(Math.ceil(o(t)))}}))},e.copy=function(){return uu(e,yu().base(i))},e}function gu(t,n){return t<0?-Math.pow(-t,n):Math.pow(t,n)}function mu(){var t=1,n=au(function(n,e){return(e=gu(e,t)-(n=gu(n,t)))?function(r){return(gu(r,t)-n)/e}:T_(e)},function(n,e){return e=gu(e,t)-(n=gu(n,t)),function(r){return gu(n+e*r,1/t)}}),e=n.domain;return n.exponent=function(n){return arguments.length?(t=+n,e(e())):t},n.copy=function(){return uu(n,mu().exponent(t))},cu(n)}function xu(){function t(){var t=0,o=Math.max(1,r.length);for(i=new Array(o-1);++t<o;)i[t-1]=As(e,t/o);return n}function n(t){if(!isNaN(t=+t))return r[hs(i,t)]}var e=[],r=[],i=[];return n.invertExtent=function(t){var n=r.indexOf(t);return n<0?[NaN,NaN]:[n>0?i[n-1]:e[0],n<i.length?i[n]:e[e.length-1]]},n.domain=function(n){if(!arguments.length)return e.slice();e=[];for(var r,i=0,o=n.length;i<o;++i)null==(r=n[i])||isNaN(r=+r)||e.push(r);return e.sort(ss),t()},n.range=function(n){return arguments.length?(r=w_.call(n),t()):r.slice()},n.quantiles=function(){return i.slice()},n.copy=function(){return xu().domain(e).range(r)},n}function bu(){function t(t){if(t<=t)return u[hs(o,t,0,i)]}function n(){var n=-1;for(o=new Array(i);++n<i;)o[n]=((n+1)*r-(n-i)*e)/(i+1);return t}var e=0,r=1,i=1,o=[.5],u=[0,1];return t.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n()):[e,r]},t.range=function(t){return arguments.length?(i=(u=w_.call(t)).length-1,n()):u.slice()},t.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},t.copy=function(){return bu().domain([e,r]).range(u)},cu(t)}function wu(){function t(t){if(t<=t)return e[hs(n,t,0,r)]}var n=[.5],e=[0,1],r=1;return t.domain=function(i){return arguments.length?(n=w_.call(i),r=Math.min(n.length,e.length-1),t):n.slice()},t.range=function(i){return arguments.length?(e=w_.call(i),r=Math.min(n.length,e.length-1),t):e.slice()},t.invertExtent=function(t){var r=e.indexOf(t);return[n[r-1],n[r]]},t.copy=function(){return wu().domain(n).range(e)},t}function Mu(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(new Date(+e))}while(n(e,o),t(e),e<r);return u},i.filter=function(e){return Mu(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return A_.setTime(+n),C_.setTime(+r),t(A_),t(C_),Math.floor(e(A_,C_))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}function Tu(t){return Mu(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*R_)/L_})}function ku(t){return Mu(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/L_})}function Nu(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Su(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Eu(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function Au(t){function n(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,s=t.length;for(e instanceof Date||(e=new Date(+e));++a<s;)37===t.charCodeAt(a)&&(u.push(t.slice(c,a)),null!=(i=Py[r=t.charAt(++a)])?r=t.charAt(++a):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),u.push(r),c=a+1);return u.push(t.slice(c,a)),u.join("")}}function e(t,n){return function(e){var i=Eu(1900);if(r(i,t,e+="",0)!=e.length)return null;if("p"in i&&(i.H=i.H%12+12*i.p),"W"in i||"U"in i){"w"in i||(i.w="W"in i?1:0);var o="Z"in i?Su(Eu(i.y)).getUTCDay():n(Eu(i.y)).getDay();i.m=0,i.d="W"in i?(i.w+6)%7+7*i.W-(o+5)%7:i.w+7*i.U-(o+6)%7}return"Z"in i?(i.H+=i.Z/100|0,i.M+=i.Z%100,Su(i)):n(i)}}function r(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u<a;){if(r>=c)return-1;if(37===(i=n.charCodeAt(u++))){if(i=n.charAt(u++),!(o=T[i in Py?n.charAt(u++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}var i=t.dateTime,o=t.date,u=t.time,a=t.periods,c=t.days,s=t.shortDays,f=t.months,l=t.shortMonths,h=Pu(a),p=Ru(a),d=Pu(c),v=Ru(c),_=Pu(s),y=Ru(s),g=Pu(f),m=Ru(f),x=Pu(l),b=Ru(l),w={a:function(t){return s[t.getDay()]},A:function(t){return c[t.getDay()]},b:function(t){return l[t.getMonth()]},B:function(t){return f[t.getMonth()]},c:null,d:Wu,e:Wu,H:Zu,I:Gu,j:Ju,L:Qu,m:Ku,M:ta,p:function(t){return a[+(t.getHours()>=12)]},S:na,U:ea,w:ra,W:ia,x:null,X:null,y:oa,Y:ua,Z:aa,"%":wa},M={a:function(t){return s[t.getUTCDay()]},A:function(t){return c[t.getUTCDay()]},b:function(t){return l[t.getUTCMonth()]},B:function(t){return f[t.getUTCMonth()]},c:null,d:ca,e:ca,H:sa,I:fa,j:la,L:ha,m:pa,M:da,p:function(t){return a[+(t.getUTCHours()>=12)]},S:va,U:_a,w:ya,W:ga,x:null,X:null,y:ma,Y:xa,Z:ba,"%":wa},T={a:function(t,n,e){var r=_.exec(n.slice(e));return r?(t.w=y[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=v[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=x.exec(n.slice(e));return r?(t.m=b[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=m[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,n,e){return r(t,i,n,e)},d:Yu,e:Yu,H:ju,I:ju,j:Bu,L:$u,m:Iu,M:Hu,p:function(t,n,e){var r=h.exec(n.slice(e));return r?(t.p=p[r[0].toLowerCase()],e+r[0].length):-1},S:Xu,U:qu,w:Lu,W:Uu,x:function(t,n,e){return r(t,o,n,e)},X:function(t,n,e){return r(t,u,n,e)},y:Ou,Y:Du,Z:Fu,"%":Vu};return w.x=n(o,w),w.X=n(u,w),w.c=n(i,w),M.x=n(o,M),M.X=n(u,M),M.c=n(i,M),{format:function(t){var e=n(t+="",w);return e.toString=function(){return t},e},parse:function(t){var n=e(t+="",Nu);return n.toString=function(){return t},n},utcFormat:function(t){var e=n(t+="",M);return e.toString=function(){return t},e},utcParse:function(t){var n=e(t,Su);return n.toString=function(){return t},n}}}function Cu(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function zu(t){return t.replace(qy,"\\$&")}function Pu(t){return new RegExp("^(?:"+t.map(zu).join("|")+")","i")}function Ru(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function Lu(t,n,e){var r=Ry.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function qu(t,n,e){var r=Ry.exec(n.slice(e));return r?(t.U=+r[0],e+r[0].length):-1}function Uu(t,n,e){var r=Ry.exec(n.slice(e));return r?(t.W=+r[0],e+r[0].length):-1}function Du(t,n,e){var r=Ry.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function Ou(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function Fu(t,n,e){var r=/^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Iu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function Yu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function Bu(t,n,e){var r=Ry.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function ju(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Hu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Xu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function $u(t,n,e){var r=Ry.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Vu(t,n,e){var r=Ly.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Wu(t,n){return Cu(t.getDate(),n,2)}function Zu(t,n){return Cu(t.getHours(),n,2)}function Gu(t,n){return Cu(t.getHours()%12||12,n,2)}function Ju(t,n){return Cu(1+Y_.count(oy(t),t),n,3)}function Qu(t,n){return Cu(t.getMilliseconds(),n,3)}function Ku(t,n){return Cu(t.getMonth()+1,n,2)}function ta(t,n){return Cu(t.getMinutes(),n,2)}function na(t,n){return Cu(t.getSeconds(),n,2)}function ea(t,n){return Cu(j_.count(oy(t),t),n,2)}function ra(t){return t.getDay()}function ia(t,n){return Cu(H_.count(oy(t),t),n,2)}function oa(t,n){return Cu(t.getFullYear()%100,n,2)}function ua(t,n){return Cu(t.getFullYear()%1e4,n,4)}function aa(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Cu(n/60|0,"0",2)+Cu(n%60,"0",2)}function ca(t,n){return Cu(t.getUTCDate(),n,2)}function sa(t,n){return Cu(t.getUTCHours(),n,2)}function fa(t,n){return Cu(t.getUTCHours()%12||12,n,2)}function la(t,n){return Cu(1+ly.count(Ay(t),t),n,3)}function ha(t,n){return Cu(t.getUTCMilliseconds(),n,3)}function pa(t,n){return Cu(t.getUTCMonth()+1,n,2)}function da(t,n){return Cu(t.getUTCMinutes(),n,2)}function va(t,n){return Cu(t.getUTCSeconds(),n,2)}function _a(t,n){return Cu(py.count(Ay(t),t),n,2)}function ya(t){return t.getUTCDay()}function ga(t,n){return Cu(dy.count(Ay(t),t),n,2)}function ma(t,n){return Cu(t.getUTCFullYear()%100,n,2)}function xa(t,n){return Cu(t.getUTCFullYear()%1e4,n,4)}function ba(){return"+0000"}function wa(){return"%"}function Ma(n){return Cy=Au(n),t.timeFormat=Cy.format,t.timeParse=Cy.parse,t.utcFormat=Cy.utcFormat,t.utcParse=Cy.utcParse,Cy}function Ta(t){return new Date(t)}function ka(t){return t instanceof Date?+t:+new Date(+t)}function Na(t,n,e,r,o,u,a,c,s){function f(i){return(a(i)<i?v:u(i)<i?_:o(i)<i?y:r(i)<i?g:n(i)<i?e(i)<i?m:x:t(i)<i?b:w)(i)}function l(n,e,r,o){if(null==n&&(n=10),"number"==typeof n){var u=Math.abs(r-e)/n,a=fs(function(t){return t[2]}).right(M,u);a===M.length?(o=i(e/Hy,r/Hy,n),n=t):a?(o=(a=M[u/M[a-1][2]<M[a][2]/u?a-1:a])[1],n=a[0]):(o=i(e,r,n),n=c)}return null==o?n:n.every(o)}var h=au(nu,rl),p=h.invert,d=h.domain,v=s(".%L"),_=s(":%S"),y=s("%I:%M"),g=s("%I %p"),m=s("%a %d"),x=s("%b %d"),b=s("%B"),w=s("%Y"),M=[[a,1,Oy],[a,5,5*Oy],[a,15,15*Oy],[a,30,30*Oy],[u,1,Fy],[u,5,5*Fy],[u,15,15*Fy],[u,30,30*Fy],[o,1,Iy],[o,3,3*Iy],[o,6,6*Iy],[o,12,12*Iy],[r,1,Yy],[r,2,2*Yy],[e,1,By],[n,1,jy],[n,3,3*jy],[t,1,Hy]];return h.invert=function(t){return new Date(p(t))},h.domain=function(t){return arguments.length?d(b_.call(t,ka)):d().map(Ta)},h.ticks=function(t,n){var e,r=d(),i=r[0],o=r[r.length-1],u=o<i;return u&&(e=i,i=o,o=e),e=l(t,i,o,n),e=e?e.range(i,o+1):[],u?e.reverse():e},h.tickFormat=function(t,n){return null==n?f:s(n)},h.nice=function(t,n){var e=d();return(t=l(t,e[0],e[e.length-1],n))?d(E_(e,t)):h},h.copy=function(){return uu(h,Na(t,n,e,r,o,u,a,c,s))},h}function Sa(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}function Ea(t){function n(n){var o=(n-e)/(r-e);return t(i?Math.max(0,Math.min(1,o)):o)}var e=0,r=1,i=!1;return n.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n):[e,r]},n.clamp=function(t){return arguments.length?(i=!!t,n):i},n.interpolator=function(e){return arguments.length?(t=e,n):t},n.copy=function(){return Ea(t).domain([e,r]).clamp(i)},cu(n)}function Aa(t){return t>1?0:t<-1?pg:Math.acos(t)}function Ca(t){return t>=1?dg:t<=-1?-dg:Math.asin(t)}function za(t){return t.innerRadius}function Pa(t){return t.outerRadius}function Ra(t){return t.startAngle}function La(t){return t.endAngle}function qa(t){return t&&t.padAngle}function Ua(t,n,e,r,i,o,u,a){var c=e-t,s=r-n,f=u-i,l=a-o,h=(f*(n-o)-l*(t-i))/(l*c-f*s);return[t+h*c,n+h*s]}function Da(t,n,e,r,i,o,u){var a=t-e,c=n-r,s=(u?o:-o)/lg(a*a+c*c),f=s*c,l=-s*a,h=t+f,p=n+l,d=e+f,v=r+l,_=(h+d)/2,y=(p+v)/2,g=d-h,m=v-p,x=g*g+m*m,b=i-o,w=h*v-d*p,M=(m<0?-1:1)*lg(cg(0,b*b*x-w*w)),T=(w*m-g*M)/x,k=(-w*g-m*M)/x,N=(w*m+g*M)/x,S=(-w*g+m*M)/x,E=T-_,A=k-y,C=N-_,z=S-y;return E*E+A*A>C*C+z*z&&(T=N,k=S),{cx:T,cy:k,x01:-f,y01:-l,x11:T*(i/b-1),y11:k*(i/b-1)}}function Oa(t){this._context=t}function Fa(t){return t[0]}function Ia(t){return t[1]}function Ya(t){this._curve=t}function Ba(t){function n(n){return new Ya(t(n))}return n._curve=t,n}function ja(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Ba(t)):n()._curve},t}function Ha(t){return t.source}function Xa(t){return t.target}function $a(t){function n(){var n,a=kg.call(arguments),c=e.apply(this,a),s=r.apply(this,a);if(u||(u=n=ve()),t(u,+i.apply(this,(a[0]=c,a)),+o.apply(this,a),+i.apply(this,(a[0]=s,a)),+o.apply(this,a)),n)return u=null,n+""||null}var e=Ha,r=Xa,i=Fa,o=Ia,u=null;return n.source=function(t){return arguments.length?(e=t,n):e},n.target=function(t){return arguments.length?(r=t,n):r},n.x=function(t){return arguments.length?(i="function"==typeof t?t:ig(+t),n):i},n.y=function(t){return arguments.length?(o="function"==typeof t?t:ig(+t),n):o},n.context=function(t){return arguments.length?(u=null==t?null:t,n):u},n}function Va(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function Wa(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function Za(t,n,e,r,i){var o=Tg(n,e),u=Tg(n,e=(e+i)/2),a=Tg(r,e),c=Tg(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(u[0],u[1],a[0],a[1],c[0],c[1])}function Ga(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Ja(t){this._context=t}function Qa(t){this._context=t}function Ka(t){this._context=t}function tc(t,n){this._basis=new Ja(t),this._beta=n}function nc(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function ec(t,n){this._context=t,this._k=(1-n)/6}function rc(t,n){this._context=t,this._k=(1-n)/6}function ic(t,n){this._context=t,this._k=(1-n)/6}function oc(t,n,e){var r=t._x1,i=t._y1,o=t._x2,u=t._y2;if(t._l01_a>hg){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>hg){var s=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*s+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*s+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function uc(t,n){this._context=t,this._alpha=n}function ac(t,n){this._context=t,this._alpha=n}function cc(t,n){this._context=t,this._alpha=n}function sc(t){this._context=t}function fc(t){return t<0?-1:1}function lc(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(fc(o)+fc(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function hc(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function pc(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function dc(t){this._context=t}function vc(t){this._context=new _c(t)}function _c(t){this._context=t}function yc(t){this._context=t}function gc(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(i[0]=0,o[0]=2,u[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,u[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,u[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,u[n]-=e*u[n-1];for(i[r-1]=u[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(u[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function mc(t,n){this._context=t,this._t=n}function xc(t,n){return t[n]}function bc(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function wc(t){return t[0]}function Mc(t){return t[1]}function Tc(){this._=null}function kc(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function Nc(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Sc(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function Ec(t){for(;t.L;)t=t.L;return t}function Ac(t,n,e,r){var i=[null,null],o=um.push(i)-1;return i.left=t,i.right=n,e&&zc(i,t,n,e),r&&zc(i,n,t,r),im[t.index].halfedges.push(o),im[n.index].halfedges.push(o),i}function Cc(t,n,e){var r=[n,e];return r.left=t,r}function zc(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function Pc(t,n,e,r,i){var o,u=t[0],a=t[1],c=u[0],s=u[1],f=0,l=1,h=a[0]-c,p=a[1]-s;if(o=n-c,h||!(o>0)){if(o/=h,h<0){if(o<f)return;o<l&&(l=o)}else if(h>0){if(o>l)return;o>f&&(f=o)}if(o=r-c,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>f&&(f=o)}else if(h>0){if(o<f)return;o<l&&(l=o)}if(o=e-s,p||!(o>0)){if(o/=p,p<0){if(o<f)return;o<l&&(l=o)}else if(p>0){if(o>l)return;o>f&&(f=o)}if(o=i-s,p||!(o<0)){if(o/=p,p<0){if(o>l)return;o>f&&(f=o)}else if(p>0){if(o<f)return;o<l&&(l=o)}return!(f>0||l<1)||(f>0&&(t[0]=[c+f*h,s+f*p]),l<1&&(t[1]=[c+l*h,s+l*p]),!0)}}}}}function Rc(t,n,e,r,i){var o=t[1];if(o)return!0;var u,a,c=t[0],s=t.left,f=t.right,l=s[0],h=s[1],p=f[0],d=f[1],v=(l+p)/2,_=(h+d)/2;if(d===h){if(v<n||v>=r)return;if(l>p){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=(l-p)/(d-h),a=_-u*v,u<-1||u>1)if(l>p){if(c){if(c[1]>=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]<e)return}else c=[(i-a)/u,i];o=[(e-a)/u,e]}else if(h<d){if(c){if(c[0]>=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]<n)return}else c=[r,u*r+a];o=[n,u*n+a]}return t[0]=c,t[1]=o,!0}function Lc(t,n,e,r){for(var i,o=um.length;o--;)Rc(i=um[o],t,n,e,r)&&Pc(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>sm||Math.abs(i[0][1]-i[1][1])>sm)||delete um[o]}function qc(t){return im[t.index]={site:t,halfedges:[]}}function Uc(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function Dc(t,n){return n[+(n.left!==t.site)]}function Oc(t,n){return n[+(n.left===t.site)]}function Fc(){for(var t,n,e,r,i=0,o=im.length;i<o;++i)if((t=im[i])&&(r=(n=t.halfedges).length)){var u=new Array(r),a=new Array(r);for(e=0;e<r;++e)u[e]=e,a[e]=Uc(t,um[n[e]]);for(u.sort(function(t,n){return a[n]-a[t]}),e=0;e<r;++e)a[e]=n[u[e]];for(e=0;e<r;++e)n[e]=a[e]}}function Ic(t,n,e,r){var i,o,u,a,c,s,f,l,h,p,d,v,_=im.length,y=!0;for(i=0;i<_;++i)if(o=im[i]){for(u=o.site,a=(c=o.halfedges).length;a--;)um[c[a]]||c.splice(a,1);for(a=0,s=c.length;a<s;)d=(p=Oc(o,um[c[a]]))[0],v=p[1],l=(f=Dc(o,um[c[++a%s]]))[0],h=f[1],(Math.abs(d-l)>sm||Math.abs(v-h)>sm)&&(c.splice(a,0,um.push(Cc(u,p,Math.abs(d-t)<sm&&r-v>sm?[t,Math.abs(l-t)<sm?h:r]:Math.abs(v-r)<sm&&e-d>sm?[Math.abs(h-r)<sm?l:e,r]:Math.abs(d-e)<sm&&v-n>sm?[e,Math.abs(l-e)<sm?h:n]:Math.abs(v-n)<sm&&d-t>sm?[Math.abs(h-n)<sm?l:t,n]:null))-1),++s);s&&(y=!1)}if(y){var g,m,x,b=1/0;for(i=0,y=null;i<_;++i)(o=im[i])&&(x=(g=(u=o.site)[0]-t)*g+(m=u[1]-n)*m)<b&&(b=x,y=o);if(y){var w=[t,n],M=[t,r],T=[e,r],k=[e,n];y.halfedges.push(um.push(Cc(u=y.site,w,M))-1,um.push(Cc(u,M,T))-1,um.push(Cc(u,T,k))-1,um.push(Cc(u,k,w))-1)}}for(i=0;i<_;++i)(o=im[i])&&(o.halfedges.length||delete im[i])}function Yc(){kc(this),this.x=this.y=this.arc=this.site=this.cy=null}function Bc(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var u=i[0],a=i[1],c=r[0]-u,s=r[1]-a,f=o[0]-u,l=o[1]-a,h=2*(c*l-s*f);if(!(h>=-fm)){var p=c*c+s*s,d=f*f+l*l,v=(l*p-s*d)/h,_=(c*d-f*p)/h,y=am.pop()||new Yc;y.arc=t,y.site=i,y.x=v+u,y.y=(y.cy=_+a)+Math.sqrt(v*v+_*_),t.circle=y;for(var g=null,m=om._;m;)if(y.y<m.y||y.y===m.y&&y.x<=m.x){if(!m.L){g=m.P;break}m=m.L}else{if(!m.R){g=m;break}m=m.R}om.insert(g,y),g||(em=y)}}}}function jc(t){var n=t.circle;n&&(n.P||(em=n.N),om.remove(n),am.push(n),kc(n),t.circle=null)}function Hc(){kc(this),this.edge=this.site=this.circle=null}function Xc(t){var n=cm.pop()||new Hc;return n.site=t,n}function $c(t){jc(t),rm.remove(t),cm.push(t),kc(t)}function Vc(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,u=t.N,a=[t];$c(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<sm&&Math.abs(r-c.circle.cy)<sm;)o=c.P,a.unshift(c),$c(c),c=o;a.unshift(c),jc(c);for(var s=u;s.circle&&Math.abs(e-s.circle.x)<sm&&Math.abs(r-s.circle.cy)<sm;)u=s.N,a.push(s),$c(s),s=u;a.push(s),jc(s);var f,l=a.length;for(f=1;f<l;++f)s=a[f],c=a[f-1],zc(s.edge,c.site,s.site,i);c=a[0],(s=a[l-1]).edge=Ac(c.site,s.site,null,i),Bc(c),Bc(s)}function Wc(t){for(var n,e,r,i,o=t[0],u=t[1],a=rm._;a;)if((r=Zc(a,u)-o)>sm)a=a.L;else{if(!((i=o-Gc(a,u))>sm)){r>-sm?(n=a.P,e=a):i>-sm?(n=a,e=a.N):n=e=a;break}if(!a.R){n=a;break}a=a.R}qc(t);var c=Xc(t);if(rm.insert(n,c),n||e){if(n===e)return jc(n),e=Xc(n.site),rm.insert(c,e),c.edge=e.edge=Ac(n.site,c.site),Bc(n),void Bc(e);if(e){jc(n),jc(e);var s=n.site,f=s[0],l=s[1],h=t[0]-f,p=t[1]-l,d=e.site,v=d[0]-f,_=d[1]-l,y=2*(h*_-p*v),g=h*h+p*p,m=v*v+_*_,x=[(_*g-p*m)/y+f,(h*m-v*g)/y+l];zc(e.edge,s,d,x),c.edge=Ac(s,t,null,x),e.edge=Ac(t,d,null,x),Bc(n),Bc(e)}else c.edge=Ac(n.site,c.site)}}function Zc(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var u=t.P;if(!u)return-1/0;var a=(e=u.site)[0],c=e[1],s=c-n;if(!s)return a;var f=a-r,l=1/o-1/s,h=f/s;return l?(-h+Math.sqrt(h*h-2*l*(f*f/(-2*s)-c+s/2+i-o/2)))/l+r:(r+a)/2}function Gc(t,n){var e=t.N;if(e)return Zc(e,n);var r=t.site;return r[1]===n?r[0]:1/0}function Jc(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function Qc(t,n){return n[1]-t[1]||n[0]-t[0]}function Kc(t,n){var e,r,i,o=t.sort(Qc).pop();for(um=[],im=new Array(t.length),rm=new Tc,om=new Tc;;)if(i=em,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(Wc(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;Vc(i.arc)}if(Fc(),n){var u=+n[0][0],a=+n[0][1],c=+n[1][0],s=+n[1][1];Lc(u,a,c,s),Ic(u,a,c,s)}this.edges=um,this.cells=im,rm=om=um=im=null}function ts(t,n,e){this.target=t,this.type=n,this.transform=e}function ns(t,n,e){this.k=t,this.x=n,this.y=e}function es(t){return t.__zoom||hm}function rs(){t.event.stopImmediatePropagation()}function is(){return!t.event.button}function os(){var t,n,e=this;return e instanceof SVGElement?(t=(e=e.ownerSVGElement||e).width.baseVal.value,n=e.height.baseVal.value):(t=e.clientWidth,n=e.clientHeight),[[0,0],[t,n]]}function us(){return this.__zoom||hm}function as(){return-t.event.deltaY*(t.event.deltaMode?120:1)/500}function cs(){return"ontouchstart"in this}var ss=function(t,n){return t<n?-1:t>n?1:t>=n?0:NaN},fs=function(t){return 1===t.length&&(t=n(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}},ls=fs(ss),hs=ls.right,ps=ls.left,ds=function(t){return null===t?NaN:+t},vs=function(t,n){var e,r,i=t.length,o=0,u=-1,a=0,c=0;if(null==n)for(;++u<i;)isNaN(e=ds(t[u]))||(c+=(r=e-a)*(e-(a+=r/++o)));else for(;++u<i;)isNaN(e=ds(n(t[u],u,t)))||(c+=(r=e-a)*(e-(a+=r/++o)));if(o>1)return c/(o-1)},_s=function(t,n){var e=vs(t,n);return e?Math.sqrt(e):e},ys=function(t,n){var e,r,i,o=t.length,u=-1;if(null==n){for(;++u<o;)if(null!=(e=t[u])&&e>=e)for(r=i=e;++u<o;)null!=(e=t[u])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++u<o;)if(null!=(e=n(t[u],u,t))&&e>=e)for(r=i=e;++u<o;)null!=(e=n(t[u],u,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]},gs=Array.prototype,ms=gs.slice,xs=gs.map,bs=function(t){return function(){return t}},ws=function(t){return t},Ms=function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o},Ts=Math.sqrt(50),ks=Math.sqrt(10),Ns=Math.sqrt(2),Ss=function(t,n,e){var i,o,u,a=n<t,c=-1;if(a&&(i=t,t=n,n=i),0===(u=r(t,n,e))||!isFinite(u))return[];if(u>0)for(t=Math.ceil(t/u),n=Math.floor(n/u),o=new Array(i=Math.ceil(n-t+1));++c<i;)o[c]=(t+c)*u;else for(t=Math.floor(t*u),n=Math.ceil(n*u),o=new Array(i=Math.ceil(t-n+1));++c<i;)o[c]=(t-c)/u;return a&&o.reverse(),o},Es=function(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1},As=function(t,n,e){if(null==e&&(e=ds),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t);return u+(+e(t[o+1],o+1,t)-u)*(i-o)}},Cs=function(t){for(var n,e,r,i=t.length,o=-1,u=0;++o<i;)u+=t[o].length;for(e=new Array(u);--i>=0;)for(n=(r=t[i]).length;--n>=0;)e[--u]=r[n];return e},zs=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r},Ps=function(t){if(!(i=t.length))return[];for(var n=-1,e=zs(t,o),r=new Array(e);++n<e;)for(var i,u=-1,a=r[n]=new Array(i);++u<i;)a[u]=t[u][n];return r},Rs=Array.prototype.slice,Ls=function(t){return t},qs=1,Us=2,Ds=3,Os=4,Fs=1e-6,Is={value:function(){}};p.prototype=h.prototype={constructor:p,on:function(t,n){var e,r=this._,i=d(t+"",r),o=-1,u=i.length;{if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<u;)if(e=(t=i[o]).type)r[e]=_(r[e],t.name,n);else if(null==n)for(e in r)r[e]=_(r[e],t.name,null);return this}for(;++o<u;)if((e=(t=i[o]).type)&&(e=v(r[e],t.name)))return e}},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new p(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var Ys="http://www.w3.org/1999/xhtml",Bs={svg:"http://www.w3.org/2000/svg",xhtml:Ys,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},js=function(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Bs.hasOwnProperty(n)?{space:Bs[n],local:t}:t},Hs=function(t){var n=js(t);return(n.local?g:y)(n)},Xs=0;x.prototype=m.prototype={constructor:x,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};var $s=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var Vs=document.documentElement;if(!Vs.matches){var Ws=Vs.webkitMatchesSelector||Vs.msMatchesSelector||Vs.mozMatchesSelector||Vs.oMatchesSelector;$s=function(t){return function(){return Ws.call(this,t)}}}}var Zs=$s,Gs={};t.event=null,"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(Gs={mouseenter:"mouseover",mouseleave:"mouseout"}));var Js=function(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e},Qs=function(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,r=r.matrixTransform(t.getScreenCTM().inverse()),[r.x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]},Ks=function(t){var n=Js();return n.changedTouches&&(n=n.changedTouches[0]),Qs(t,n)},tf=function(t){return null==t?S:function(){return this.querySelector(t)}},nf=function(t){return null==t?E:function(){return this.querySelectorAll(t)}},ef=function(t){return new Array(t.length)};A.prototype={constructor:A,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var rf=function(t){return function(){return t}},of="$",uf=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};W.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var af=[null];pt.prototype=dt.prototype={constructor:pt,select:function(t){"function"!=typeof t&&(t=tf(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u,a=n[i],c=a.length,s=r[i]=new Array(c),f=0;f<c;++f)(o=a[f])&&(u=t.call(o,o.__data__,f,a))&&("__data__"in o&&(u.__data__=o.__data__),s[f]=u);return new pt(r,this._parents)},selectAll:function(t){"function"!=typeof t&&(t=nf(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var u,a=n[o],c=a.length,s=0;s<c;++s)(u=a[s])&&(r.push(t.call(u,u.__data__,s,a)),i.push(u));return new pt(r,i)},filter:function(t){"function"!=typeof t&&(t=Zs(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new pt(r,this._parents)},data:function(t,n){if(!t)return p=new Array(this.size()),s=-1,this.each(function(t){p[++s]=t}),p;var e=n?z:C,r=this._parents,i=this._groups;"function"!=typeof t&&(t=rf(t));for(var o=i.length,u=new Array(o),a=new Array(o),c=new Array(o),s=0;s<o;++s){var f=r[s],l=i[s],h=l.length,p=t.call(f,f&&f.__data__,s,r),d=p.length,v=a[s]=new Array(d),_=u[s]=new Array(d);e(f,l,v,_,c[s]=new Array(h),p,n);for(var y,g,m=0,x=0;m<d;++m)if(y=v[m]){for(m>=x&&(x=m+1);!(g=_[x])&&++x<d;);y._next=g||null}}return u=new pt(u,r),u._enter=a,u._exit=c,u},enter:function(){return new pt(this._enter||this._groups.map(ef),this._parents)},exit:function(){return new pt(this._exit||this._groups.map(ef),this._parents)},merge:function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new pt(u,this._parents)},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,u=i[o];--o>=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){t||(t=P);for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i){for(var o,u=n[i],a=u.length,c=r[i]=new Array(a),s=0;s<a;++s)(o=u[s])&&(c[s]=o);c.sort(function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e})}return new pt(r,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var u=r[i];if(u)return u}return null},size:function(){var t=0;return this.each(function(){++t}),t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],u=0,a=o.length;u<a;++u)(i=o[u])&&t.call(i,i.__data__,u,o);return this},attr:function(t,n){var e=js(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?L:R:"function"==typeof n?e.local?O:D:e.local?U:q)(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?F:"function"==typeof n?Y:I)(t,n,null==e?"":e)):B(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?j:"function"==typeof n?X:H)(t,n)):this.node()[t]},classed:function(t,n){var e=$(t+"");if(arguments.length<2){for(var r=V(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?K:n?J:Q)(e,n))},text:function(t){return arguments.length?this.each(null==t?tt:("function"==typeof t?et:nt)(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?rt:("function"==typeof t?ot:it)(t)):this.node().innerHTML},raise:function(){return this.each(ut)},lower:function(){return this.each(at)},append:function(t){var n="function"==typeof t?t:Hs(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},insert:function(t,n){var e="function"==typeof t?t:Hs(t),r=null==n?ct:"function"==typeof n?n:tf(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},remove:function(){return this.each(st)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=M(t+""),u=o.length;{if(!(arguments.length<2)){for(a=n?k:T,null==e&&(e=!1),r=0;r<u;++r)this.each(a(o[r],n,e));return this}var a=this.node().__on;if(a)for(var c,s=0,f=a.length;s<f;++s)for(r=0,c=a[s];r<u;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value}},dispatch:function(t,n){return this.each(("function"==typeof n?ht:lt)(t,n))}};var cf=function(t){return"string"==typeof t?new pt([[document.querySelector(t)]],[document.documentElement]):new pt([[t]],af)},sf=function(t,n,e){arguments.length<3&&(e=n,n=Js().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Qs(t,r);return null},ff=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},lf=function(t){var n=t.document.documentElement,e=cf(t).on("dragstart.drag",ff,!0);"onselectstart"in n?e.on("selectstart.drag",ff,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")},hf=function(t){return function(){return t}};yt.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var pf=function(t,n,e){t.prototype=n.prototype=e,e.constructor=t},df="\\s*([+-]?\\d+)\\s*",vf="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",_f="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",yf=/^#([0-9a-f]{3})$/,gf=/^#([0-9a-f]{6})$/,mf=new RegExp("^rgb\\("+[df,df,df]+"\\)$"),xf=new RegExp("^rgb\\("+[_f,_f,_f]+"\\)$"),bf=new RegExp("^rgba\\("+[df,df,df,vf]+"\\)$"),wf=new RegExp("^rgba\\("+[_f,_f,_f,vf]+"\\)$"),Mf=new RegExp("^hsl\\("+[vf,_f,_f]+"\\)$"),Tf=new RegExp("^hsla\\("+[vf,_f,_f,vf]+"\\)$"),kf={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};pf(Mt,Tt,{displayable:function(){return this.rgb().displayable()},toString:function(){return this.rgb()+""}}),pf(At,Et,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new At(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new At(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),pf(Rt,Pt,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new At(Lt(t>=240?t-240:t+120,i,r),Lt(t,i,r),Lt(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Nf=Math.PI/180,Sf=180/Math.PI,Ef=.95047,Af=1,Cf=1.08883,zf=4/29,Pf=6/29,Rf=3*Pf*Pf,Lf=Pf*Pf*Pf;pf(Dt,Ut,wt(Mt,{brighter:function(t){return new Dt(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Dt(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=Af*Ft(t),n=Ef*Ft(n),e=Cf*Ft(e),new At(It(3.2404542*n-1.5371385*t-.4985314*e),It(-.969266*n+1.8760108*t+.041556*e),It(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),pf(Ht,jt,wt(Mt,{brighter:function(t){return new Ht(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Ht(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return qt(this).rgb()}}));var qf=-.14861,Uf=1.78277,Df=-.29227,Of=-.90649,Ff=1.97294,If=Ff*Of,Yf=Ff*Uf,Bf=Uf*Df-Of*qf;pf(Vt,$t,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Vt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Vt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Nf,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new At(255*(n+e*(qf*r+Uf*i)),255*(n+e*(Df*r+Of*i)),255*(n+e*(Ff*r)),this.opacity)}}));var jf,Hf,Xf,$f,Vf,Wf,Zf=function(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=r<n-1?t[r+2]:2*o-i;return Wt((e-r/n)*n,u,i,o,a)}},Gf=function(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],u=t[(r+1)%n],a=t[(r+2)%n];return Wt((e-r/n)*n,i,o,u,a)}},Jf=function(t){return function(){return t}},Qf=function t(n){function e(t,n){var e=r((t=Et(t)).r,(n=Et(n)).r),i=r(t.g,n.g),o=r(t.b,n.b),u=Kt(t.opacity,n.opacity);return function(n){return t.r=e(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}var r=Qt(n);return e.gamma=t,e}(1),Kf=tn(Zf),tl=tn(Gf),nl=function(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(r),u=new Array(r);for(e=0;e<i;++e)o[e]=cl(t[e],n[e]);for(;e<r;++e)u[e]=n[e];return function(t){for(e=0;e<i;++e)u[e]=o[e](t);return u}},el=function(t,n){var e=new Date;return t=+t,n-=t,function(r){return e.setTime(t+n*r),e}},rl=function(t,n){return t=+t,n-=t,function(e){return t+n*e}},il=function(t,n){var e,r={},i={};null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={});for(e in n)e in t?r[e]=cl(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}},ol=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ul=new RegExp(ol.source,"g"),al=function(t,n){var e,r,i,o=ol.lastIndex=ul.lastIndex=0,u=-1,a=[],c=[];for(t+="",n+="";(e=ol.exec(t))&&(r=ul.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:rl(e,r)})),o=ul.lastIndex;return o<n.length&&(i=n.slice(o),a[u]?a[u]+=i:a[++u]=i),a.length<2?c[0]?en(c[0].x):nn(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)a[(e=c[r]).i]=e.x(t);return a.join("")})},cl=function(t,n){var e,r=typeof n;return null==n||"boolean"===r?Jf(n):("number"===r?rl:"string"===r?(e=Tt(n))?(n=e,Qf):al:n instanceof Tt?Qf:n instanceof Date?el:Array.isArray(n)?nl:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?il:rl)(t,n)},sl=function(t,n){return t=+t,n-=t,function(e){return Math.round(t+n*e)}},fl=180/Math.PI,ll={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1},hl=function(t,n,e,r,i,o){var u,a,c;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,c/=a),t*r<n*e&&(t=-t,n=-n,c=-c,u=-u),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*fl,skewX:Math.atan(c)*fl,scaleX:u,scaleY:a}},pl=rn(function(t){return"none"===t?ll:(jf||(jf=document.createElement("DIV"),Hf=document.documentElement,Xf=document.defaultView),jf.style.transform=t,t=Xf.getComputedStyle(Hf.appendChild(jf),null).getPropertyValue("transform"),Hf.removeChild(jf),t=t.slice(7,-1).split(","),hl(+t[0],+t[1],+t[2],+t[3],+t[4],+t[5]))},"px, ","px)","deg)"),dl=rn(function(t){return null==t?ll:($f||($f=document.createElementNS("http://www.w3.org/2000/svg","g")),$f.setAttribute("transform",t),(t=$f.transform.baseVal.consolidate())?(t=t.matrix,hl(t.a,t.b,t.c,t.d,t.e,t.f)):ll)},", ",")",")"),vl=Math.SQRT2,_l=function(t,n){var e,r,i=t[0],o=t[1],u=t[2],a=n[0],c=n[1],s=n[2],f=a-i,l=c-o,h=f*f+l*l;if(h<1e-12)r=Math.log(s/u)/vl,e=function(t){return[i+t*f,o+t*l,u*Math.exp(vl*t*r)]};else{var p=Math.sqrt(h),d=(s*s-u*u+4*h)/(2*u*2*p),v=(s*s-u*u-4*h)/(2*s*2*p),_=Math.log(Math.sqrt(d*d+1)-d),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-_)/vl,e=function(t){var n=t*r,e=on(_),a=u/(2*p)*(e*an(vl*n+_)-un(_));return[i+a*f,o+a*l,u*e/on(vl*n+_)]}}return e.duration=1e3*r,e},yl=cn(Jt),gl=cn(Kt),ml=sn(Jt),xl=sn(Kt),bl=fn(Jt),wl=fn(Kt),Ml=0,Tl=0,kl=0,Nl=1e3,Sl=0,El=0,Al=0,Cl="object"==typeof performance&&performance.now?performance:Date,zl="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};pn.prototype=dn.prototype={constructor:pn,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?ln():+e)+(null==n?0:+n),this._next||Wf===this||(Wf?Wf._next=this:Vf=this,Wf=this),this._call=t,this._time=e,mn()},stop:function(){this._call&&(this._call=null,this._time=1/0,mn())}};var Pl=function(t,n,e){var r=new pn;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},Rl=h("start","end","interrupt"),Ll=[],ql=0,Ul=1,Dl=2,Ol=3,Fl=4,Il=5,Yl=6,Bl=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};Mn(t,e,{name:n,index:r,group:i,on:Rl,tween:Ll,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:ql})},jl=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){n=null==n?null:n+"";for(i in o)(e=o[i]).name===n?(r=e.state>Dl&&e.state<Il,e.state=Yl,e.timer.stop(),r&&e.on.call("interrupt",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}},Hl=function(t,n){var e;return("number"==typeof n?rl:n instanceof Tt?Qf:(e=Tt(n))?(n=e,Qf):al)(t,n)},Xl=dt.prototype.constructor,$l=0,Vl=dt.prototype;Gn.prototype=Jn.prototype={constructor:Gn,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=tf(t));for(var r=this._groups,i=r.length,o=new Array(i),u=0;u<i;++u)for(var a,c,s=r[u],f=s.length,l=o[u]=new Array(f),h=0;h<f;++h)(a=s[h])&&(c=t.call(a,a.__data__,h,s))&&("__data__"in a&&(c.__data__=a.__data__),l[h]=c,Bl(l[h],n,e,h,l,wn(a,e)));return new Gn(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=nf(t));for(var r=this._groups,i=r.length,o=[],u=[],a=0;a<i;++a)for(var c,s=r[a],f=s.length,l=0;l<f;++l)if(c=s[l]){for(var h,p=t.call(c,c.__data__,l,s),d=wn(c,e),v=0,_=p.length;v<_;++v)(h=p[v])&&Bl(h,n,e,v,p,d);o.push(p),u.push(c)}return new Gn(o,u,n,e)},filter:function(t){"function"!=typeof t&&(t=Zs(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new Gn(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new Gn(u,this._parents,this._name,this._id)},selection:function(){return new Xl(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Qn(),r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)if(u=a[s]){var f=wn(u,n);Bl(u,t,e,s,a,{time:f.time+f.delay+f.duration,delay:0,duration:f.duration,ease:f.ease})}return new Gn(r,this._parents,t,e)},call:Vl.call,nodes:Vl.nodes,node:Vl.node,size:Vl.size,empty:Vl.empty,each:Vl.each,on:function(t,n){var e=this._id;return arguments.length<2?wn(this.node(),e).on.on(t):this.each(Yn(e,t,n))},attr:function(t,n){var e=js(t),r="transform"===e?dl:Hl;return this.attrTween(t,"function"==typeof n?(e.local?Pn:zn)(e,r,Nn(this,"attr."+t,n)):null==n?(e.local?En:Sn)(e):(e.local?Cn:An)(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=js(t);return this.tween(e,(r.local?Rn:Ln)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?pl:Hl;return null==n?this.styleTween(t,jn(t,r)).on("end.style."+t,Hn(t)):this.styleTween(t,"function"==typeof n?$n(t,r,Nn(this,"style."+t,n)):Xn(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,Vn(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?Zn(Nn(this,"text",t)):Wn(null==t?"":t+""))},remove:function(){return this.on("end.remove",Bn(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=wn(this.node(),e).tween,o=0,u=i.length;o<u;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?Tn:kn)(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?qn:Un)(n,t)):wn(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?Dn:On)(n,t)):wn(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(Fn(n,t)):wn(this.node(),n).ease}};var Wl=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),Zl=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Gl=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Jl=Math.PI,Ql=Jl/2,Kl=4/11,th=6/11,nh=8/11,eh=.75,rh=9/11,ih=10/11,oh=.9375,uh=21/22,ah=63/64,ch=1/Kl/Kl,sh=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),fh=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),lh=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),hh=2*Math.PI,ph=function t(n,e){function r(t){return n*Math.pow(2,10*--t)*Math.sin((i-t)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),dh=function t(n,e){function r(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+i)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),vh=function t(n,e){function r(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((i-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((i+t)/e))/2}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),_h={time:null,delay:0,duration:250,ease:te};dt.prototype.interrupt=function(t){return this.each(function(){jl(this,t)})},dt.prototype.transition=function(t){var n,e;t instanceof Gn?(n=t._id,t=t._name):(n=Qn(),(e=_h).time=ln(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)(u=a[s])&&Bl(u,t,n,s,a,e||oe(u,n));return new Gn(r,this._parents,t,n)};var yh=[null],gh=function(t){return function(){return t}},mh=function(t,n,e){this.target=t,this.type=n,this.selection=e},xh=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},bh={name:"drag"},wh={name:"space"},Mh={name:"handle"},Th={name:"center"},kh={name:"x",handles:["e","w"].map(ae),input:function(t,n){return t&&[[t[0],n[0][1]],[t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Nh={name:"y",handles:["n","s"].map(ae),input:function(t,n){return t&&[[n[0][0],t[0]],[n[1][0],t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Sh={name:"xy",handles:["n","e","s","w","nw","ne","se","sw"].map(ae),input:function(t){return t},output:function(t){return t}},Eh={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ah={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ch={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},zh={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Ph={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1},Rh=Math.cos,Lh=Math.sin,qh=Math.PI,Uh=qh/2,Dh=2*qh,Oh=Math.max,Fh=Array.prototype.slice,Ih=function(t){return function(){return t}},Yh=Math.PI,Bh=2*Yh,jh=Bh-1e-6;de.prototype=ve.prototype={constructor:de,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,u=this._y1,a=e-t,c=r-n,s=o-t,f=u-n,l=s*s+f*f;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(f*a-c*s)>1e-6&&i){var h=e-o,p=r-u,d=a*a+c*c,v=h*h+p*p,_=Math.sqrt(d),y=Math.sqrt(l),g=i*Math.tan((Yh-Math.acos((d+l-v)/(2*_*y)))/2),m=g/y,x=g/_;Math.abs(m-1)>1e-6&&(this._+="L"+(t+m*s)+","+(n+m*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>s*p)+","+(this._x1=t+x*a)+","+(this._y1=n+x*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,s=n+a,f=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+s:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-s)>1e-6)&&(this._+="L"+c+","+s),e&&(l<0&&(l=l%Bh+Bh),l>jh?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=s):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Yh)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};be.prototype=we.prototype={constructor:be,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var Hh=we.prototype;Se.prototype=Ee.prototype={constructor:Se,has:Hh.has,add:function(t){return t+="",this["$"+t]=t,this},remove:Hh.remove,clear:Hh.clear,values:Hh.keys,size:Hh.size,empty:Hh.empty,each:Hh.each};var Xh=function(t){function n(t,n){function e(){if(f>=s)return a;if(i)return i=!1,u;var n,e=f;if(34===t.charCodeAt(e)){for(var r=e;r++<s;)if(34===t.charCodeAt(r)){if(34!==t.charCodeAt(r+1))break;++r}return f=r+2,13===(n=t.charCodeAt(r+1))?(i=!0,10===t.charCodeAt(r+2)&&++f):10===n&&(i=!0),t.slice(e+1,r).replace(/""/g,'"')}for(;f<s;){var c=1;if(10===(n=t.charCodeAt(f++)))i=!0;else if(13===n)i=!0,10===t.charCodeAt(f)&&(++f,++c);else if(n!==o)continue;return t.slice(e,f-c)}return t.slice(e)}for(var r,i,u={},a={},c=[],s=t.length,f=0,l=0;(r=e())!==a;){for(var h=[];r!==u&&r!==a;)h.push(r),r=e();n&&null==(h=n(h,l++))||c.push(h)}return c}function e(n){return n.map(r).join(t)}function r(t){return null==t?"":i.test(t+="")?'"'+t.replace(/\"/g,'""')+'"':t}var i=new RegExp('["'+t+"\n\r]"),o=t.charCodeAt(0);return{parse:function(t,e){var r,i,o=n(t,function(t,n){if(r)return r(t,n-1);i=t,r=e?Ce(t,e):Ae(t)});return o.columns=i,o},parseRows:n,format:function(n,e){return null==e&&(e=ze(n)),[e.map(r).join(t)].concat(n.map(function(n){return e.map(function(t){return r(n[t])}).join(t)})).join("\n")},formatRows:function(t){return t.map(e).join("\n")}}},$h=Xh(","),Vh=$h.parse,Wh=$h.parseRows,Zh=$h.format,Gh=$h.formatRows,Jh=Xh("\t"),Qh=Jh.parse,Kh=Jh.parseRows,tp=Jh.format,np=Jh.formatRows,ep=function(t){return function(){return t}},rp=function(){return 1e-6*(Math.random()-.5)},ip=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i},op=qe.prototype=Ue.prototype;op.copy=function(){var t,n,e=new Ue(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=De(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=De(n));return e},op.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return Pe(this.cover(n,e),n,e,t)},op.addAll=function(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,s=1/0,f=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(u[e]=r,a[e]=i,r<c&&(c=r),r>f&&(f=r),i<s&&(s=i),i>l&&(l=i));for(f<c&&(c=this._x0,f=this._x1),l<s&&(s=this._y0,l=this._y1),this.cover(c,s).cover(f,l),e=0;e<o;++e)Pe(this,u[e],a[e],t[e]);return this},op.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{if(!(e>t||t>i||r>n||n>o))return this;var u,a,c=i-e,s=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,o=r+c,t>i||n>o);break;case 1:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,o=r+c,e>t||n>o);break;case 2:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,r=o-c,t>i||r>n);break;case 3:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,r=o-c,e>t||r>n)}this._root&&this._root.length&&(this._root=s)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},op.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},op.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},op.find=function(t,n,e){var r,i,o,u,a,c,s,f=this._x0,l=this._y0,h=this._x1,p=this._y1,d=[],v=this._root;for(v&&d.push(new ip(v,f,l,h,p)),null==e?e=1/0:(f=t-e,l=n-e,h=t+e,p=n+e,e*=e);c=d.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>p||(u=c.x1)<f||(a=c.y1)<l))if(v.length){var _=(i+u)/2,y=(o+a)/2;d.push(new ip(v[3],_,y,u,a),new ip(v[2],i,y,_,a),new ip(v[1],_,o,u,y),new ip(v[0],i,o,_,y)),(s=(n>=y)<<1|t>=_)&&(c=d[d.length-1],d[d.length-1]=d[d.length-1-s],d[d.length-1-s]=c)}else{var g=t-+this._x.call(null,v.data),m=n-+this._y.call(null,v.data),x=g*g+m*m;if(x<e){var b=Math.sqrt(e=x);f=t-b,l=n-b,h=t+b,p=n+b,r=v.data}}return r},op.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(u=+this._y.call(null,t)))return this;var n,e,r,i,o,u,a,c,s,f,l,h,p=this._root,d=this._x0,v=this._y0,_=this._x1,y=this._y1;if(!p)return this;if(p.length)for(;;){if((s=o>=(a=(d+_)/2))?d=a:_=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=p,!(p=p[l=f<<1|s]))return this;if(!p.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;p.data!==t;)if(r=p,!(p=p.next))return this;return(i=p.next)&&delete p.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(p=n[0]||n[1]||n[2]||n[3])&&p===(n[3]||n[2]||n[1]||n[0])&&!p.length&&(e?e[h]=p:this._root=p),this):(this._root=i,this)},op.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},op.root=function(){return this._root},op.size=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},op.visit=function(t){var n,e,r,i,o,u,a=[],c=this._root;for(c&&a.push(new ip(c,this._x0,this._y0,this._x1,this._y1));n=a.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,u=n.y1)&&c.length){var s=(r+o)/2,f=(i+u)/2;(e=c[3])&&a.push(new ip(e,s,f,o,u)),(e=c[2])&&a.push(new ip(e,r,f,s,u)),(e=c[1])&&a.push(new ip(e,s,i,o,f)),(e=c[0])&&a.push(new ip(e,r,i,s,f))}return this},op.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new ip(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,u=n.x0,a=n.y0,c=n.x1,s=n.y1,f=(u+c)/2,l=(a+s)/2;(o=i[0])&&e.push(new ip(o,u,a,f,l)),(o=i[1])&&e.push(new ip(o,f,a,c,l)),(o=i[2])&&e.push(new ip(o,u,l,f,s)),(o=i[3])&&e.push(new ip(o,f,l,c,s))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},op.x=function(t){return arguments.length?(this._x=t,this):this._x},op.y=function(t){return arguments.length?(this._y=t,this):this._y};var up,ap=10,cp=Math.PI*(3-Math.sqrt(5)),sp=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},fp=function(t){return(t=sp(Math.abs(t)))?t[1]:NaN},lp=function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}},hp=function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}},pp=function(t,n){var e=sp(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},dp={"":function(t,n){t:for(var e,r=(t=t.toPrecision(n)).length,i=1,o=-1;i<r;++i)switch(t[i]){case".":o=e=i;break;case"0":0===o&&(o=i),e=i;break;case"e":break t;default:o>0&&(o=0)}return o>0?t.slice(0,o)+t.slice(e+1):t},"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return pp(100*t,n)},r:pp,s:function(t,n){var e=sp(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(up=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+sp(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},vp=/^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;He.prototype=Xe.prototype,Xe.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var _p,yp=function(t){return t},gp=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],mp=function(t){function n(t){function n(t){var n,r,u,f=_,x=y;if("c"===v)x=g(t)+x,t="";else{var b=(t=+t)<0;if(t=g(Math.abs(t),d),b&&0==+t&&(b=!1),f=(b?"("===s?s:"-":"-"===s||"("===s?"":s)+f,x=x+("s"===v?gp[8+up/3]:"")+(b&&"("===s?")":""),m)for(n=-1,r=t.length;++n<r;)if(48>(u=t.charCodeAt(n))||u>57){x=(46===u?i+t.slice(n+1):t.slice(n))+x,t=t.slice(0,n);break}}p&&!l&&(t=e(t,1/0));var w=f.length+t.length+x.length,M=w<h?new Array(h-w+1).join(a):"";switch(p&&l&&(t=e(M+t,M.length?h-x.length:1/0),M=""),c){case"<":t=f+t+x+M;break;case"=":t=f+M+t+x;break;case"^":t=M.slice(0,w=M.length>>1)+f+t+x+M.slice(w);break;default:t=M+f+t+x}return o(t)}var a=(t=He(t)).fill,c=t.align,s=t.sign,f=t.symbol,l=t.zero,h=t.width,p=t.comma,d=t.precision,v=t.type,_="$"===f?r[0]:"#"===f&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",y="$"===f?r[1]:/[%p]/.test(v)?u:"",g=dp[v],m=!v||/[defgprs%]/.test(v);return d=null==d?v?6:12:/[gprs]/.test(v)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),n.toString=function(){return t+""},n}var e=t.grouping&&t.thousands?lp(t.grouping,t.thousands):yp,r=t.currency,i=t.decimal,o=t.numerals?hp(t.numerals):yp,u=t.percent||"%";return{format:n,formatPrefix:function(t,e){var r=n((t=He(t),t.type="f",t)),i=3*Math.max(-8,Math.min(8,Math.floor(fp(e)/3))),o=Math.pow(10,-i),u=gp[8+i/3];return function(t){return r(o*t)+u}}}};$e({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var xp=function(t){return Math.max(0,-fp(Math.abs(t)))},bp=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(fp(n)/3)))-fp(Math.abs(t)))},wp=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,fp(n)-fp(t))+1},Mp=function(){return new Ve};Ve.prototype={constructor:Ve,reset:function(){this.s=this.t=0},add:function(t){We(nd,t,this.t),We(this,nd.s,this.s),this.s?this.t+=nd.t:this.s=nd.t},valueOf:function(){return this.s}};var Tp,kp,Np,Sp,Ep,Ap,Cp,zp,Pp,Rp,Lp,qp,Up,Dp,Op,Fp,Ip,Yp,Bp,jp,Hp,Xp,$p,Vp,Wp,Zp,Gp,Jp,Qp,Kp,td,nd=new Ve,ed=1e-6,rd=Math.PI,id=rd/2,od=rd/4,ud=2*rd,ad=180/rd,cd=rd/180,sd=Math.abs,fd=Math.atan,ld=Math.atan2,hd=Math.cos,pd=Math.ceil,dd=Math.exp,vd=Math.log,_d=Math.pow,yd=Math.sin,gd=Math.sign||function(t){return t>0?1:t<0?-1:0},md=Math.sqrt,xd=Math.tan,bd={Feature:function(t,n){Ke(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)Ke(e[r].geometry,n)}},wd={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){tr(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)tr(e[r],n,0)},Polygon:function(t,n){nr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)nr(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)Ke(e[r],n)}},Md=function(t,n){t&&bd.hasOwnProperty(t.type)?bd[t.type](t,n):Ke(t,n)},Td=Mp(),kd=Mp(),Nd={point:Qe,lineStart:Qe,lineEnd:Qe,polygonStart:function(){Td.reset(),Nd.lineStart=er,Nd.lineEnd=rr},polygonEnd:function(){var t=+Td;kd.add(t<0?ud+t:t),this.lineStart=this.lineEnd=this.point=Qe},sphere:function(){kd.add(ud)}},Sd=Mp(),Ed={point:pr,lineStart:vr,lineEnd:_r,polygonStart:function(){Ed.point=yr,Ed.lineStart=gr,Ed.lineEnd=mr,Sd.reset(),Nd.polygonStart()},polygonEnd:function(){Nd.polygonEnd(),Ed.point=pr,Ed.lineStart=vr,Ed.lineEnd=_r,Td<0?(Ap=-(zp=180),Cp=-(Pp=90)):Sd>ed?Pp=90:Sd<-ed&&(Cp=-90),Op[0]=Ap,Op[1]=zp}},Ad={sphere:Qe,point:Mr,lineStart:kr,lineEnd:Er,polygonStart:function(){Ad.lineStart=Ar,Ad.lineEnd=Cr},polygonEnd:function(){Ad.lineStart=kr,Ad.lineEnd=Er}},Cd=function(t){return function(){return t}},zd=function(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e};Rr.invert=Rr;var Pd,Rd,Ld,qd,Ud,Dd,Od,Fd,Id,Yd,Bd,jd=function(t){function n(n){return n=t(n[0]*cd,n[1]*cd),n[0]*=ad,n[1]*=ad,n}return t=Lr(t[0]*cd,t[1]*cd,t.length>2?t[2]*cd:0),n.invert=function(n){return n=t.invert(n[0]*cd,n[1]*cd),n[0]*=ad,n[1]*=ad,n},n},Hd=function(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:Qe,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}},Xd=function(t,n,e,r,i,o){var u,a=t[0],c=t[1],s=0,f=1,l=n[0]-a,h=n[1]-c;if(u=e-a,l||!(u>0)){if(u/=l,l<0){if(u<s)return;u<f&&(f=u)}else if(l>0){if(u>f)return;u>s&&(s=u)}if(u=i-a,l||!(u<0)){if(u/=l,l<0){if(u>f)return;u>s&&(s=u)}else if(l>0){if(u<s)return;u<f&&(f=u)}if(u=r-c,h||!(u>0)){if(u/=h,h<0){if(u<s)return;u<f&&(f=u)}else if(h>0){if(u>f)return;u>s&&(s=u)}if(u=o-c,h||!(u<0)){if(u/=h,h<0){if(u>f)return;u>s&&(s=u)}else if(h>0){if(u<s)return;u<f&&(f=u)}return s>0&&(t[0]=a+s*l,t[1]=c+s*h),f<1&&(n[0]=a+f*l,n[1]=c+f*h),!0}}}}},$d=function(t,n){return sd(t[0]-n[0])<ed&&sd(t[1]-n[1])<ed},Vd=function(t,n,e,r,i){var o,u,a=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],u=t[n];if($d(r,u)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);i.lineEnd()}else a.push(e=new Ir(r,t,null,!0)),c.push(e.o=new Ir(r,null,e,!1)),a.push(e=new Ir(u,t,null,!1)),c.push(e.o=new Ir(u,null,e,!0))}}),a.length){for(c.sort(n),Yr(a),Yr(c),o=0,u=c.length;o<u;++o)c[o].e=e=!e;for(var s,f,l=a[0];;){for(var h=l,p=!0;h.v;)if((h=h.n)===l)return;s=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(p)for(o=0,u=s.length;o<u;++o)i.point((f=s[o])[0],f[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(p)for(s=h.p.z,o=s.length-1;o>=0;--o)i.point((f=s[o])[0],f[1]);else r(h.x,h.p.x,-1,i);h=h.p}s=(h=h.o).z,p=!p}while(!h.v);i.lineEnd()}}},Wd=1e9,Zd=-Wd,Gd=Mp(),Jd=function(t,n){var e=n[0],r=n[1],i=[yd(e),-hd(e),0],o=0,u=0;Gd.reset();for(var a=0,c=t.length;a<c;++a)if(f=(s=t[a]).length)for(var s,f,l=s[f-1],h=l[0],p=l[1]/2+od,d=yd(p),v=hd(p),_=0;_<f;++_,h=g,d=x,v=b,l=y){var y=s[_],g=y[0],m=y[1]/2+od,x=yd(m),b=hd(m),w=g-h,M=w>=0?1:-1,T=M*w,k=T>rd,N=d*x;if(Gd.add(ld(N*M*yd(T),v*b+N*hd(T))),o+=k?w+M*ud:w,k^h>=e^g>=e){var S=sr(ar(l),ar(y));hr(S);var E=sr(i,S);hr(E);var A=(k^w>=0?-1:1)*Ge(E[2]);(r>A||r===A&&(S[0]||S[1]))&&(u+=k^w>=0?1:-1)}}return(o<-ed||o<ed&&Gd<-ed)^1&u},Qd=Mp(),Kd={sphere:Qe,point:Qe,lineStart:function(){Kd.point=Hr,Kd.lineEnd=jr},lineEnd:Qe,polygonStart:Qe,polygonEnd:Qe},tv=function(t){return Qd.reset(),Md(t,Kd),+Qd},nv=[null,null],ev={type:"LineString",coordinates:nv},rv=function(t,n){return nv[0]=t,nv[1]=n,tv(ev)},iv={Feature:function(t,n){return $r(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if($r(e[r].geometry,n))return!0;return!1}},ov={Sphere:function(){return!0},Point:function(t,n){return Vr(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Vr(e[r],n))return!0;return!1},LineString:function(t,n){return Wr(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Wr(e[r],n))return!0;return!1},Polygon:function(t,n){return Zr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Zr(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if($r(e[r],n))return!0;return!1}},uv=function(t){return t},av=Mp(),cv=Mp(),sv={point:Qe,lineStart:Qe,lineEnd:Qe,polygonStart:function(){sv.lineStart=ni,sv.lineEnd=ii},polygonEnd:function(){sv.lineStart=sv.lineEnd=sv.point=Qe,av.add(sd(cv)),cv.reset()},result:function(){var t=av/2;return av.reset(),t}},fv=1/0,lv=fv,hv=-fv,pv=hv,dv={point:function(t,n){t<fv&&(fv=t),t>hv&&(hv=t),n<lv&&(lv=n),n>pv&&(pv=n)},lineStart:Qe,lineEnd:Qe,polygonStart:Qe,polygonEnd:Qe,result:function(){var t=[[fv,lv],[hv,pv]];return hv=pv=-(lv=fv=1/0),t}},vv=0,_v=0,yv=0,gv=0,mv=0,xv=0,bv=0,wv=0,Mv=0,Tv={point:oi,lineStart:ui,lineEnd:si,polygonStart:function(){Tv.lineStart=fi,Tv.lineEnd=li},polygonEnd:function(){Tv.point=oi,Tv.lineStart=ui,Tv.lineEnd=si},result:function(){var t=Mv?[bv/Mv,wv/Mv]:xv?[gv/xv,mv/xv]:yv?[vv/yv,_v/yv]:[NaN,NaN];return vv=_v=yv=gv=mv=xv=bv=wv=Mv=0,t}};di.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,ud)}},result:Qe};var kv,Nv,Sv,Ev,Av,Cv=Mp(),zv={point:Qe,lineStart:function(){zv.point=vi},lineEnd:function(){kv&&_i(Nv,Sv),zv.point=Qe},polygonStart:function(){kv=!0},polygonEnd:function(){kv=null},result:function(){var t=+Cv;return Cv.reset(),t}};yi.prototype={_radius:4.5,_circle:gi(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=gi(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}};var Pv=function(t,n,e,r){return function(i,o){function u(n,e){var r=i(n,e);t(n=r[0],e=r[1])&&o.point(n,e)}function a(t,n){var e=i(t,n);_.point(e[0],e[1])}function c(){b.point=a,_.lineStart()}function s(){b.point=u,_.lineEnd()}function f(t,n){v.push([t,n]);var e=i(t,n);m.point(e[0],e[1])}function l(){m.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),m.lineEnd();var t,n,e,r,i=m.clean(),u=g.result(),a=u.length;if(v.pop(),p.push(v),v=null,a)if(1&i){if(e=u[0],(n=e.length-1)>0){for(x||(o.polygonStart(),x=!0),o.lineStart(),t=0;t<n;++t)o.point((r=e[t])[0],r[1]);o.lineEnd()}}else a>1&&2&i&&u.push(u.pop().concat(u.shift())),d.push(u.filter(mi))}var p,d,v,_=n(o),y=i.invert(r[0],r[1]),g=Hd(),m=n(g),x=!1,b={point:u,lineStart:c,lineEnd:s,polygonStart:function(){b.point=f,b.lineStart=l,b.lineEnd=h,d=[],p=[]},polygonEnd:function(){b.point=u,b.lineStart=c,b.lineEnd=s,d=Cs(d);var t=Jd(p,y);d.length?(x||(o.polygonStart(),x=!0),Vd(d,xi,t,e,o)):t&&(x||(o.polygonStart(),x=!0),o.lineStart(),e(null,null,1,o),o.lineEnd()),x&&(o.polygonEnd(),x=!1),d=p=null},sphere:function(){o.polygonStart(),o.lineStart(),e(null,null,1,o),o.lineEnd(),o.polygonEnd()}};return b}},Rv=Pv(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,u){var a=o>0?rd:-rd,c=sd(o-e);sd(c-rd)<ed?(t.point(e,r=(r+u)/2>0?id:-id),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),t.point(o,r),n=0):i!==a&&c>=rd&&(sd(e-i)<ed&&(e-=i*ed),sd(o-a)<ed&&(o-=a*ed),r=bi(e,r,o,u),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),n=0),t.point(e=o,r=u),i=a},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*id,r.point(-rd,i),r.point(0,i),r.point(rd,i),r.point(rd,0),r.point(rd,-i),r.point(0,-i),r.point(-rd,-i),r.point(-rd,0),r.point(-rd,i);else if(sd(t[0]-n[0])>ed){var o=t[0]<n[0]?rd:-rd;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])},[-rd,-id]),Lv=function(t,n){function e(t,n){return hd(t)*hd(n)>o}function r(t,n,e){var r=[1,0,0],i=sr(ar(t),ar(n)),u=cr(i,i),a=i[0],c=u-a*a;if(!c)return!e&&t;var s=o*u/c,f=-o*a/c,l=sr(r,i),h=lr(r,s);fr(h,lr(i,f));var p=l,d=cr(h,p),v=cr(p,p),_=d*d-v*(cr(h,h)-1);if(!(_<0)){var y=md(_),g=lr(p,(-d-y)/v);if(fr(g,h),g=ur(g),!e)return g;var m,x=t[0],b=n[0],w=t[1],M=n[1];b<x&&(m=x,x=b,b=m);var T=b-x,k=sd(T-rd)<ed,N=k||T<ed;if(!k&&M<w&&(m=w,w=M,M=m),N?k?w+M>0^g[1]<(sd(g[0]-x)<ed?w:M):w<=g[1]&&g[1]<=M:T>rd^(x<=g[0]&&g[0]<=b)){var S=lr(p,(-d+y)/v);return fr(S,h),[g,ur(S)]}}}function i(n,e){var r=u?t:rd-t,i=0;return n<-r?i|=1:n>r&&(i|=2),e<-r?i|=4:e>r&&(i|=8),i}var o=hd(t),u=o>0,a=sd(o)>ed;return Pv(e,function(t){var n,o,c,s,f;return{lineStart:function(){s=c=!1,f=1},point:function(l,h){var p,d=[l,h],v=e(l,h),_=u?v?0:i(l,h):v?i(l+(l<0?rd:-rd),h):0;if(!n&&(s=c=v)&&t.lineStart(),v!==c&&(!(p=r(n,d))||$d(n,p)||$d(d,p))&&(d[0]+=ed,d[1]+=ed,v=e(d[0],d[1])),v!==c)f=0,v?(t.lineStart(),p=r(d,n),t.point(p[0],p[1])):(p=r(n,d),t.point(p[0],p[1]),t.lineEnd()),n=p;else if(a&&n&&u^v){var y;_&o||!(y=r(d,n,!0))||(f=0,u?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&$d(n,d)||t.point(d[0],d[1]),n=d,c=v,o=_},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return f|(s&&c)<<1}}},function(e,r,i,o){Or(o,t,n,i,e,r)},u?[0,-t]:[-rd,t-rd])};Mi.prototype={constructor:Mi,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var qv=16,Uv=hd(30*cd),Dv=function(t,n){return+n?Si(t,n):Ni(t)},Ov=wi({point:function(t,n){this.stream.point(t*cd,n*cd)}}),Fv=function(){return Ci(Pi).scale(155.424).center([0,33.6442])},Iv=function(){return Fv().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])},Yv=Li(function(t){return md(2/(1+t))});Yv.invert=qi(function(t){return 2*Ge(t/2)});var Bv=Li(function(t){return(t=Ze(t))&&t/yd(t)});Bv.invert=qi(function(t){return t});Ui.invert=function(t,n){return[t,2*fd(dd(n))-id]};Ii.invert=Ii;Bi.invert=qi(fd);Hi.invert=qi(Ge);Xi.invert=qi(function(t){return 2*fd(t)});$i.invert=function(t,n){return[-n,2*fd(dd(t))-id]};uo.prototype=eo.prototype={constructor:uo,count:function(){return this.eachAfter(to)},each:function(t){var n,e,r,i,o=this,u=[o];do{for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)u.push(e[r])}while(u.length);return this},eachAfter:function(t){for(var n,e,r,i=this,o=[i],u=[];i=o.pop();)if(u.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=u.pop();)t(i);return this},eachBefore:function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=no(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return eo(this).eachBefore(io)}};var jv=Array.prototype.slice,Hv=function(t){for(var n,e,r=0,i=(t=ao(jv.call(t))).length,o=[];r<i;)n=t[r],e&&fo(e,n)?++r:(e=ho(o=co(o,n)),r=0);return e},Xv=function(t){return function(){return t}},$v=function(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)},Vv=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(r-n)/t.value;++a<c;)(o=u[a]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*s},Wv="$",Zv={depth:-1},Gv={};Do.prototype=Object.create(uo.prototype);var Jv=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(i-e)/t.value;++a<c;)(o=u[a]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*s},Qv=(1+Math.sqrt(5))/2,Kv=function t(n){function e(t,e,r,i,o){Fo(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Qv),t_=function t(n){function e(t,e,r,i,o){if((u=t._squarify)&&u.ratio===n)for(var u,a,c,s,f,l=-1,h=u.length,p=t.value;++l<h;){for(c=(a=u[l]).children,s=a.value=0,f=c.length;s<f;++s)a.value+=c[s].value;a.dice?Vv(a,e,r,i,r+=(o-r)*a.value/p):Jv(a,e,r,e+=(i-e)*a.value/p,o),p-=a.value}else t._squarify=u=Fo(n,t,e,r,i,o),u.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Qv),n_=function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])},e_=[].slice,r_={};Bo.prototype=Wo.prototype={constructor:Bo,defer:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("defer after await");if(null!=this._error)return this;var n=e_.call(arguments,1);return n.push(t),++this._waiting,this._tasks.push(n),jo(this),this},abort:function(){return null==this._error&&$o(this,new Error("abort")),this},await:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=function(n,e){t.apply(null,[n].concat(e))},Vo(this),this},awaitAll:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=t,Vo(this),this}};var i_=function(){return Math.random()},o_=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(i_),u_=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(i_),a_=function t(n){function e(){var t=u_.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(i_),c_=function t(n){function e(t){return function(){for(var e=0,r=0;r<t;++r)e+=n();return e}}return e.source=t,e}(i_),s_=function t(n){function e(t){var e=c_.source(n)(t);return function(){return e()/t}}return e.source=t,e}(i_),f_=function t(n){function e(t){return function(){return-Math.log(1-n())/t}}return e.source=t,e}(i_),l_=function(t,n){function e(t){var n,e=s.status;if(!e&&Go(s)||e>=200&&e<300||304===e){if(o)try{n=o.call(r,s)}catch(t){return void a.call("error",r,t)}else n=s;a.call("load",r,n)}else a.call("error",r,t)}var r,i,o,u,a=h("beforesend","progress","load","error"),c=we(),s=new XMLHttpRequest,f=null,l=null,p=0;if("undefined"==typeof XDomainRequest||"withCredentials"in s||!/^(http(s)?:)?\/\//.test(t)||(s=new XDomainRequest),"onload"in s?s.onload=s.onerror=s.ontimeout=e:s.onreadystatechange=function(t){s.readyState>3&&e(t)},s.onprogress=function(t){a.call("progress",r,t)},r={header:function(t,n){return t=(t+"").toLowerCase(),arguments.length<2?c.get(t):(null==n?c.remove(t):c.set(t,n+""),r)},mimeType:function(t){return arguments.length?(i=null==t?null:t+"",r):i},responseType:function(t){return arguments.length?(u=t,r):u},timeout:function(t){return arguments.length?(p=+t,r):p},user:function(t){return arguments.length<1?f:(f=null==t?null:t+"",r)},password:function(t){return arguments.length<1?l:(l=null==t?null:t+"",r)},response:function(t){return o=t,r},get:function(t,n){return r.send("GET",t,n)},post:function(t,n){return r.send("POST",t,n)},send:function(n,e,o){return s.open(n,t,!0,f,l),null==i||c.has("accept")||c.set("accept",i+",*/*"),s.setRequestHeader&&c.each(function(t,n){s.setRequestHeader(n,t)}),null!=i&&s.overrideMimeType&&s.overrideMimeType(i),null!=u&&(s.responseType=u),p>0&&(s.timeout=p),null==o&&"function"==typeof e&&(o=e,e=null),null!=o&&1===o.length&&(o=Zo(o)),null!=o&&r.on("error",o).on("load",function(t){o(null,t)}),a.call("beforesend",r,s),s.send(null==e?null:e),r},abort:function(){return s.abort(),r},on:function(){var t=a.on.apply(a,arguments);return t===a?r:t}},null!=n){if("function"!=typeof n)throw new Error("invalid callback: "+n);return r.get(n)}return r},h_=function(t,n){return function(e,r){var i=l_(e).mimeType(t).response(n);if(null!=r){if("function"!=typeof r)throw new Error("invalid callback: "+r);return i.get(r)}return i}},p_=h_("text/html",function(t){return document.createRange().createContextualFragment(t.responseText)}),d_=h_("application/json",function(t){return JSON.parse(t.responseText)}),v_=h_("text/plain",function(t){return t.responseText}),__=h_("application/xml",function(t){var n=t.responseXML;if(!n)throw new Error("parse error");return n}),y_=function(t,n){return function(e,r,i){arguments.length<3&&(i=r,r=null);var o=l_(e).mimeType(t);return o.row=function(t){return arguments.length?o.response(Jo(n,r=t)):r},o.row(r),i?o.get(i):o}},g_=y_("text/csv",Vh),m_=y_("text/tab-separated-values",Qh),x_=Array.prototype,b_=x_.map,w_=x_.slice,M_={name:"implicit"},T_=function(t){return function(){return t}},k_=function(t){return+t},N_=[0,1],S_=function(n,e,r){var o,u=n[0],a=n[n.length-1],c=i(u,a,null==e?10:e);switch((r=He(null==r?",f":r)).type){case"s":var s=Math.max(Math.abs(u),Math.abs(a));return null!=r.precision||isNaN(o=bp(c,s))||(r.precision=o),t.formatPrefix(r,s);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(o=wp(c,Math.max(Math.abs(u),Math.abs(a))))||(r.precision=o-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(o=xp(c))||(r.precision=o-2*("%"===r.type))}return t.format(r)},E_=function(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],u=t[i];return u<o&&(e=r,r=i,i=e,e=o,o=u,u=e),t[r]=n.floor(o),t[i]=n.ceil(u),t},A_=new Date,C_=new Date,z_=Mu(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});z_.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Mu(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):z_:null};var P_=z_.range,R_=6e4,L_=6048e5,q_=Mu(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),U_=q_.range,D_=Mu(function(t){t.setTime(Math.floor(t/R_)*R_)},function(t,n){t.setTime(+t+n*R_)},function(t,n){return(n-t)/R_},function(t){return t.getMinutes()}),O_=D_.range,F_=Mu(function(t){var n=t.getTimezoneOffset()*R_%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),I_=F_.range,Y_=Mu(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*R_)/864e5},function(t){return t.getDate()-1}),B_=Y_.range,j_=Tu(0),H_=Tu(1),X_=Tu(2),$_=Tu(3),V_=Tu(4),W_=Tu(5),Z_=Tu(6),G_=j_.range,J_=H_.range,Q_=X_.range,K_=$_.range,ty=V_.range,ny=W_.range,ey=Z_.range,ry=Mu(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),iy=ry.range,oy=Mu(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});oy.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Mu(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var uy=oy.range,ay=Mu(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*R_)},function(t,n){return(n-t)/R_},function(t){return t.getUTCMinutes()}),cy=ay.range,sy=Mu(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),fy=sy.range,ly=Mu(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),hy=ly.range,py=ku(0),dy=ku(1),vy=ku(2),_y=ku(3),yy=ku(4),gy=ku(5),my=ku(6),xy=py.range,by=dy.range,wy=vy.range,My=_y.range,Ty=yy.range,ky=gy.range,Ny=my.range,Sy=Mu(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),Ey=Sy.range,Ay=Mu(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});Ay.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Mu(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Cy,zy=Ay.range,Py={"-":"",_:" ",0:"0"},Ry=/^\s*\d+/,Ly=/^%/,qy=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;Ma({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Uy=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ"),Dy=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),Oy=1e3,Fy=60*Oy,Iy=60*Fy,Yy=24*Iy,By=7*Yy,jy=30*Yy,Hy=365*Yy,Xy=function(t){return t.match(/.{6}/g).map(function(t){return"#"+t})},$y=Xy("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),Vy=Xy("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6"),Wy=Xy("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9"),Zy=Xy("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5"),Gy=wl($t(300,.5,0),$t(-240,.5,1)),Jy=wl($t(-100,.75,.35),$t(80,1.5,.8)),Qy=wl($t(260,.75,.35),$t(80,1.5,.8)),Ky=$t(),tg=Sa(Xy("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),ng=Sa(Xy("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),eg=Sa(Xy("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),rg=Sa(Xy("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921")),ig=function(t){return function(){return t}},og=Math.abs,ug=Math.atan2,ag=Math.cos,cg=Math.max,sg=Math.min,fg=Math.sin,lg=Math.sqrt,hg=1e-12,pg=Math.PI,dg=pg/2,vg=2*pg;Oa.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var _g=function(t){return new Oa(t)},yg=function(){function t(t){var a,c,s,f=t.length,l=!1;for(null==i&&(u=o(s=ve())),a=0;a<=f;++a)!(a<f&&r(c=t[a],a,t))===l&&((l=!l)?u.lineStart():u.lineEnd()),l&&u.point(+n(c,a,t),+e(c,a,t));if(s)return u=null,s+""||null}var n=Fa,e=Ia,r=ig(!0),i=null,o=_g,u=null;return t.x=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.defined=function(n){return arguments.length?(r="function"==typeof n?n:ig(!!n),t):r},t.curve=function(n){return arguments.length?(o=n,null!=i&&(u=o(i)),t):o},t.context=function(n){return arguments.length?(null==n?i=u=null:u=o(i=n),t):i},t},gg=function(){function t(t){var n,f,l,h,p,d=t.length,v=!1,_=new Array(d),y=new Array(d);for(null==a&&(s=c(p=ve())),n=0;n<=d;++n){if(!(n<d&&u(h=t[n],n,t))===v)if(v=!v)f=n,s.areaStart(),s.lineStart();else{for(s.lineEnd(),s.lineStart(),l=n-1;l>=f;--l)s.point(_[l],y[l]);s.lineEnd(),s.areaEnd()}v&&(_[n]=+e(h,n,t),y[n]=+i(h,n,t),s.point(r?+r(h,n,t):_[n],o?+o(h,n,t):y[n]))}if(p)return s=null,p+""||null}function n(){return yg().defined(u).curve(c).context(a)}var e=Fa,r=null,i=ig(0),o=Ia,u=ig(!0),a=null,c=_g,s=null;return t.x=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),r=null,t):e},t.x0=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.x1=function(n){return arguments.length?(r=null==n?null:"function"==typeof n?n:ig(+n),t):r},t.y=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),o=null,t):i},t.y0=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.y1=function(n){return arguments.length?(o=null==n?null:"function"==typeof n?n:ig(+n),t):o},t.lineX0=t.lineY0=function(){return n().x(e).y(i)},t.lineY1=function(){return n().x(e).y(o)},t.lineX1=function(){return n().x(r).y(i)},t.defined=function(n){return arguments.length?(u="function"==typeof n?n:ig(!!n),t):u},t.curve=function(n){return arguments.length?(c=n,null!=a&&(s=c(a)),t):c},t.context=function(n){return arguments.length?(null==n?a=s=null:s=c(a=n),t):a},t},mg=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},xg=function(t){return t},bg=Ba(_g);Ya.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var wg=function(){return ja(yg().curve(bg))},Mg=function(){var t=gg().curve(bg),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return ja(e())},delete t.lineX0,t.lineEndAngle=function(){return ja(r())},delete t.lineX1,t.lineInnerRadius=function(){return ja(i())},delete t.lineY0,t.lineOuterRadius=function(){return ja(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Ba(t)):n()._curve},t},Tg=function(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]},kg=Array.prototype.slice,Ng={draw:function(t,n){var e=Math.sqrt(n/pg);t.moveTo(e,0),t.arc(0,0,e,0,vg)}},Sg={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},Eg=Math.sqrt(1/3),Ag=2*Eg,Cg={draw:function(t,n){var e=Math.sqrt(n/Ag),r=e*Eg;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},zg=Math.sin(pg/10)/Math.sin(7*pg/10),Pg=Math.sin(vg/10)*zg,Rg=-Math.cos(vg/10)*zg,Lg={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=Pg*e,i=Rg*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var u=vg*o/5,a=Math.cos(u),c=Math.sin(u);t.lineTo(c*e,-a*e),t.lineTo(a*r-c*i,c*r+a*i)}t.closePath()}},qg={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},Ug=Math.sqrt(3),Dg={draw:function(t,n){var e=-Math.sqrt(n/(3*Ug));t.moveTo(0,2*e),t.lineTo(-Ug*e,-e),t.lineTo(Ug*e,-e),t.closePath()}},Og=-.5,Fg=Math.sqrt(3)/2,Ig=1/Math.sqrt(12),Yg=3*(Ig/2+1),Bg={draw:function(t,n){var e=Math.sqrt(n/Yg),r=e/2,i=e*Ig,o=r,u=e*Ig+e,a=-o,c=u;t.moveTo(r,i),t.lineTo(o,u),t.lineTo(a,c),t.lineTo(Og*r-Fg*i,Fg*r+Og*i),t.lineTo(Og*o-Fg*u,Fg*o+Og*u),t.lineTo(Og*a-Fg*c,Fg*a+Og*c),t.lineTo(Og*r+Fg*i,Og*i-Fg*r),t.lineTo(Og*o+Fg*u,Og*u-Fg*o),t.lineTo(Og*a+Fg*c,Og*c-Fg*a),t.closePath()}},jg=[Ng,Sg,Cg,qg,Lg,Dg,Bg],Hg=function(){};Ja.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Ga(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};Qa.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};Ka.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};tc.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],u=t[e]-i,a=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*u),this._beta*n[c]+(1-this._beta)*(o+r*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Xg=function t(n){function e(t){return 1===n?new Ja(t):new tc(t,n)}return e.beta=function(n){return t(+n)},e}(.85);ec.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:nc(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var $g=function t(n){function e(t){return new ec(t,n)}return e.tension=function(n){return t(+n)},e}(0);rc.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Vg=function t(n){function e(t){return new rc(t,n)}return e.tension=function(n){return t(+n)},e}(0);ic.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Wg=function t(n){function e(t){return new ic(t,n)}return e.tension=function(n){return t(+n)},e}(0);uc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Zg=function t(n){function e(t){return n?new uc(t,n):new ec(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);ac.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Gg=function t(n){function e(t){return n?new ac(t,n):new rc(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);cc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Jg=function t(n){function e(t){return n?new cc(t,n):new ic(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);sc.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}};dc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:pc(this,this._t0,hc(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(t=+t,n=+n,t!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,pc(this,hc(this,e=lc(this,t,n)),e);break;default:pc(this,this._t0,e=lc(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(vc.prototype=Object.create(dc.prototype)).point=function(t,n){dc.prototype.point.call(this,n,t)},_c.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},yc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=gc(t),i=gc(n),o=0,u=1;u<e;++o,++u)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[u],n[u]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}};mc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var Qg=function(t,n){if((i=t.length)>1)for(var e,r,i,o=1,u=t[n[0]],a=u.length;o<i;++o)for(r=u,u=t[n[o]],e=0;e<a;++e)u[e][1]+=u[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]},Kg=function(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e},tm=function(t){var n=t.map(bc);return Kg(t).sort(function(t,e){return n[t]-n[e]})},nm=function(t){return function(){return t}};Tc.prototype={constructor:Tc,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=Ec(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(Nc(this,e),e=(t=e).U),e.C=!1,r.C=!0,Sc(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(Sc(this,e),e=(t=e).U),e.C=!1,r.C=!0,Nc(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,u=t.R;if(e=o?u?Ec(u):o:u,i?i.L===t?i.L=e:i.R=e:this._=e,o&&u?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==u?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=u,u.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,Nc(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,Sc(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,Nc(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,Sc(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,Nc(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,Sc(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var em,rm,im,om,um,am=[],cm=[],sm=1e-6,fm=1e-12;Kc.prototype={constructor:Kc,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return Dc(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,u,a=e.site,c=-1,s=n[i[o-1]],f=s.left===a?s.right:s.left;++c<o;)u=f,f=(s=n[i[c]]).left===a?s.right:s.left,u&&f&&r<u.index&&r<f.index&&Jc(a,u,f)<0&&t.push([a.data,u.data,f.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,u=o._found||0,a=o.cells.length;!(i=o.cells[u]);)if(++u>=a)return null;var c=t-i.site[0],s=n-i.site[1],f=c*c+s*s;do{i=o.cells[r=u],u=null,i.halfedges.forEach(function(e){var r=o.edges[e],a=r.left;if(a!==i.site&&a||(a=r.right)){var c=t-a[0],s=n-a[1],l=c*c+s*s;l<f&&(f=l,u=a.index)}})}while(null!==u);return o._found=r,null==e||f<=e*e?i.site:null}};var lm=function(t){return function(){return t}};ns.prototype={constructor:ns,scale:function(t){return 1===t?this:new ns(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ns(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var hm=new ns(1,0,0);es.prototype=ns.prototype;var pm=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()};t.version="4.10.0",t.bisect=hs,t.bisectRight=hs,t.bisectLeft=ps,t.ascending=ss,t.bisector=fs,t.cross=function(t,n,r){var i,o,u,a,c=t.length,s=n.length,f=new Array(c*s);for(null==r&&(r=e),i=u=0;i<c;++i)for(a=t[i],o=0;o<s;++o,++u)f[u]=r(a,n[o]);return f},t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=_s,t.extent=ys,t.histogram=function(){function t(t){var o,u,a=t.length,c=new Array(a);for(o=0;o<a;++o)c[o]=n(t[o],o,t);var s=e(c),f=s[0],l=s[1],h=r(c,f,l);Array.isArray(h)||(h=i(f,l,h),h=Ms(Math.ceil(f/h)*h,Math.floor(l/h)*h,h));for(var p=h.length;h[0]<=f;)h.shift(),--p;for(;h[p-1]>l;)h.pop(),--p;var d,v=new Array(p+1);for(o=0;o<=p;++o)(d=v[o]=[]).x0=o>0?h[o-1]:f,d.x1=o<p?h[o]:l;for(o=0;o<a;++o)f<=(u=c[o])&&u<=l&&v[hs(h,u,0,p)].push(t[o]);return v}var n=ws,e=ys,r=Es;return t.value=function(e){return arguments.length?(n="function"==typeof e?e:bs(e),t):n},t.domain=function(n){return arguments.length?(e="function"==typeof n?n:bs([n[0],n[1]]),t):e},t.thresholds=function(n){return arguments.length?(r="function"==typeof n?n:bs(Array.isArray(n)?ms.call(n):n),t):r},t},t.thresholdFreedmanDiaconis=function(t,n,e){return t=xs.call(t,ds).sort(ss),Math.ceil((e-n)/(2*(As(t,.75)-As(t,.25))*Math.pow(t.length,-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*_s(t)*Math.pow(t.length,-1/3)))},t.thresholdSturges=Es,t.max=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r},t.mean=function(t,n){var e,r=t.length,i=r,o=-1,u=0;if(null==n)for(;++o<r;)isNaN(e=ds(t[o]))?--i:u+=e;else for(;++o<r;)isNaN(e=ds(n(t[o],o,t)))?--i:u+=e;if(i)return u/i},t.median=function(t,n){var e,r=t.length,i=-1,o=[];if(null==n)for(;++i<r;)isNaN(e=ds(t[i]))||o.push(e);else for(;++i<r;)isNaN(e=ds(n(t[i],i,t)))||o.push(e);return As(o.sort(ss),.5)},t.merge=Cs,t.min=zs,t.pairs=function(t,n){null==n&&(n=e);for(var r=0,i=t.length-1,o=t[0],u=new Array(i<0?0:i);r<i;)u[r]=n(o,o=t[++r]);return u},t.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},t.quantile=As,t.range=Ms,t.scan=function(t,n){if(e=t.length){var e,r,i=0,o=0,u=t[o];for(null==n&&(n=ss);++i<e;)(n(r=t[i],u)<0||0!==n(u,u))&&(u=r,o=i);return 0===n(u,u)?o:void 0}},t.shuffle=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},t.sum=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},t.ticks=Ss,t.tickIncrement=r,t.tickStep=i,t.transpose=Ps,t.variance=vs,t.zip=function(){return Ps(arguments)},t.axisTop=function(t){return l(qs,t)},t.axisRight=function(t){return l(Us,t)},t.axisBottom=function(t){return l(Ds,t)},t.axisLeft=function(t){return l(Os,t)},t.brush=function(){return he(Sh)},t.brushX=function(){return he(kh)},t.brushY=function(){return he(Nh)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.chord=function(){function t(t){var o,u,a,c,s,f,l=t.length,h=[],p=Ms(l),d=[],v=[],_=v.groups=new Array(l),y=new Array(l*l);for(o=0,s=-1;++s<l;){for(u=0,f=-1;++f<l;)u+=t[s][f];h.push(u),d.push(Ms(l)),o+=u}for(e&&p.sort(function(t,n){return e(h[t],h[n])}),r&&d.forEach(function(n,e){n.sort(function(n,i){return r(t[e][n],t[e][i])})}),c=(o=Oh(0,Dh-n*l)/o)?n:Dh/l,u=0,s=-1;++s<l;){for(a=u,f=-1;++f<l;){var g=p[s],m=d[g][f],x=t[g][m],b=u,w=u+=x*o;y[m*l+g]={index:g,subindex:m,startAngle:b,endAngle:w,value:x}}_[g]={index:g,startAngle:a,endAngle:u,value:h[g]},u+=c}for(s=-1;++s<l;)for(f=s-1;++f<l;){var M=y[f*l+s],T=y[s*l+f];(M.value||T.value)&&v.push(M.value<T.value?{source:T,target:M}:{source:M,target:T})}return i?v.sort(i):v}var n=0,e=null,r=null,i=null;return t.padAngle=function(e){return arguments.length?(n=Oh(0,e),t):n},t.sortGroups=function(n){return arguments.length?(e=n,t):e},t.sortSubgroups=function(n){return arguments.length?(r=n,t):r},t.sortChords=function(n){return arguments.length?(null==n?i=null:(i=pe(n))._=n,t):i&&i._},t},t.ribbon=function(){function t(){var t,a=Fh.call(arguments),c=n.apply(this,a),s=e.apply(this,a),f=+r.apply(this,(a[0]=c,a)),l=i.apply(this,a)-Uh,h=o.apply(this,a)-Uh,p=f*Rh(l),d=f*Lh(l),v=+r.apply(this,(a[0]=s,a)),_=i.apply(this,a)-Uh,y=o.apply(this,a)-Uh;if(u||(u=t=ve()),u.moveTo(p,d),u.arc(0,0,f,l,h),l===_&&h===y||(u.quadraticCurveTo(0,0,v*Rh(_),v*Lh(_)),u.arc(0,0,v,_,y)),u.quadraticCurveTo(0,0,p,d),u.closePath(),t)return u=null,t+""||null}var n=_e,e=ye,r=ge,i=me,o=xe,u=null;return t.radius=function(n){return arguments.length?(r="function"==typeof n?n:Ih(+n),t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:Ih(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:Ih(+n),t):o},t.source=function(e){return arguments.length?(n=e,t):n},t.target=function(n){return arguments.length?(e=n,t):e},t.context=function(n){return arguments.length?(u=null==n?null:n,t):u},t},t.nest=function(){function t(n,i,u,a){if(i>=o.length)return null!=e&&n.sort(e),null!=r?r(n):n;for(var c,s,f,l=-1,h=n.length,p=o[i++],d=we(),v=u();++l<h;)(f=d.get(c=p(s=n[l])+""))?f.push(s):d.set(c,[s]);return d.each(function(n,e){a(v,e,t(n,i,u,a))}),v}function n(t,e){if(++e>o.length)return t;var i,a=u[e-1];return null!=r&&e>=o.length?i=t.entries():(i=[],t.each(function(t,r){i.push({key:r,values:n(t,e)})})),null!=a?i.sort(function(t,n){return a(t.key,n.key)}):i}var e,r,i,o=[],u=[];return i={object:function(n){return t(n,0,Me,Te)},map:function(n){return t(n,0,ke,Ne)},entries:function(e){return n(t(e,0,ke,Ne),0)},key:function(t){return o.push(t),i},sortKeys:function(t){return u[o.length-1]=t,i},sortValues:function(t){return e=t,i},rollup:function(t){return r=t,i}}},t.set=Ee,t.map=we,t.keys=function(t){var n=[];for(var e in t)n.push(e);return n},t.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},t.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},t.color=Tt,t.rgb=Et,t.hsl=Pt,t.lab=Ut,t.hcl=jt,t.cubehelix=$t,t.dispatch=h,t.drag=function(){function n(t){t.on("mousedown.drag",e).filter(bt).on("touchstart.drag",o).on("touchmove.drag",u).on("touchend.drag touchcancel.drag",a).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(){if(!p&&d.apply(this,arguments)){var n=c("mouse",v.apply(this,arguments),Ks,this,arguments);n&&(cf(t.event.view).on("mousemove.drag",r,!0).on("mouseup.drag",i,!0),lf(t.event.view),vt(),l=!1,s=t.event.clientX,f=t.event.clientY,n("start"))}}function r(){if(ff(),!l){var n=t.event.clientX-s,e=t.event.clientY-f;l=n*n+e*e>x}y.mouse("drag")}function i(){cf(t.event.view).on("mousemove.drag mouseup.drag",null),_t(t.event.view,l),ff(),y.mouse("end")}function o(){if(d.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=v.apply(this,arguments),o=r.length;for(n=0;n<o;++n)(e=c(r[n].identifier,i,sf,this,arguments))&&(vt(),e("start"))}}function u(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=y[r[n].identifier])&&(ff(),e("drag"))}function a(){var n,e,r=t.event.changedTouches,i=r.length;for(p&&clearTimeout(p),p=setTimeout(function(){p=null},500),n=0;n<i;++n)(e=y[r[n].identifier])&&(vt(),e("end"))}function c(e,r,i,o,u){var a,c,s,f=i(r,e),l=g.copy();if(N(new yt(n,"beforestart",a,e,m,f[0],f[1],0,0,l),function(){return null!=(t.event.subject=a=_.apply(o,u))&&(c=a.x-f[0]||0,s=a.y-f[1]||0,!0)}))return function t(h){var p,d=f;switch(h){case"start":y[e]=t,p=m++;break;case"end":delete y[e],--m;case"drag":f=i(r,e),p=m}N(new yt(n,h,a,e,p,f[0]+c,f[1]+s,f[0]-d[0],f[1]-d[1],l),l.apply,l,[h,o,u])}}var s,f,l,p,d=gt,v=mt,_=xt,y={},g=h("start","drag","end"),m=0,x=0;return n.filter=function(t){return arguments.length?(d="function"==typeof t?t:hf(!!t),n):d},n.container=function(t){return arguments.length?(v="function"==typeof t?t:hf(t),n):v},n.subject=function(t){return arguments.length?(_="function"==typeof t?t:hf(t),n):_},n.on=function(){var t=g.on.apply(g,arguments);return t===g?n:t},n.clickDistance=function(t){return arguments.length?(x=(t=+t)*t,n):Math.sqrt(x)},n},t.dragDisable=lf,t.dragEnable=_t,t.dsvFormat=Xh,t.csvParse=Vh,t.csvParseRows=Wh,t.csvFormat=Zh,t.csvFormatRows=Gh,t.tsvParse=Qh,t.tsvParseRows=Kh,t.tsvFormat=tp,t.tsvFormatRows=np,t.easeLinear=function(t){return+t},t.easeQuad=Kn,t.easeQuadIn=function(t){return t*t},t.easeQuadOut=function(t){return t*(2-t)},t.easeQuadInOut=Kn,t.easeCubic=te,t.easeCubicIn=function(t){return t*t*t},t.easeCubicOut=function(t){return--t*t*t+1},t.easeCubicInOut=te,t.easePoly=Gl,t.easePolyIn=Wl,t.easePolyOut=Zl,t.easePolyInOut=Gl,t.easeSin=ne,t.easeSinIn=function(t){return 1-Math.cos(t*Ql)},t.easeSinOut=function(t){return Math.sin(t*Ql)},t.easeSinInOut=ne,t.easeExp=ee,t.easeExpIn=function(t){return Math.pow(2,10*t-10)},t.easeExpOut=function(t){return 1-Math.pow(2,-10*t)},t.easeExpInOut=ee,t.easeCircle=re,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCircleInOut=re,t.easeBounce=ie,t.easeBounceIn=function(t){return 1-ie(1-t)},t.easeBounceOut=ie,t.easeBounceInOut=function(t){return((t*=2)<=1?1-ie(1-t):ie(t-1)+1)/2},t.easeBack=lh,t.easeBackIn=sh,t.easeBackOut=fh,t.easeBackInOut=lh,t.easeElastic=dh,t.easeElasticIn=ph,t.easeElasticOut=dh,t.easeElasticInOut=vh,t.forceCenter=function(t,n){function e(){var e,i,o=r.length,u=0,a=0;for(e=0;e<o;++e)u+=(i=r[e]).x,a+=i.y;for(u=u/o-t,a=a/o-n,e=0;e<o;++e)(i=r[e]).x-=u,i.y-=a}var r;return null==t&&(t=0),null==n&&(n=0),e.initialize=function(t){r=t},e.x=function(n){return arguments.length?(t=+n,e):t},e.y=function(t){return arguments.length?(n=+t,e):n},e},t.forceCollide=function(t){function n(){for(var t,n,r,c,s,f,l,h=i.length,p=0;p<a;++p)for(n=qe(i,Oe,Fe).visitAfter(e),t=0;t<h;++t)r=i[t],f=o[r.index],l=f*f,c=r.x+r.vx,s=r.y+r.vy,n.visit(function(t,n,e,i,o){var a=t.data,h=t.r,p=f+h;if(!a)return n>c+p||i<c-p||e>s+p||o<s-p;if(a.index>r.index){var d=c-a.x-a.vx,v=s-a.y-a.vy,_=d*d+v*v;_<p*p&&(0===d&&(d=rp(),_+=d*d),0===v&&(v=rp(),_+=v*v),_=(p-(_=Math.sqrt(_)))/_*u,r.vx+=(d*=_)*(p=(h*=h)/(l+h)),r.vy+=(v*=_)*p,a.vx-=d*(p=1-p),a.vy-=v*p)}})}function e(t){if(t.data)return t.r=o[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function r(){if(i){var n,e,r=i.length;for(o=new Array(r),n=0;n<r;++n)e=i[n],o[e.index]=+t(e,n,i)}}var i,o,u=1,a=1;return"function"!=typeof t&&(t=ep(null==t?1:+t)),n.initialize=function(t){i=t,r()},n.iterations=function(t){return arguments.length?(a=+t,n):a},n.strength=function(t){return arguments.length?(u=+t,n):u},n.radius=function(e){return arguments.length?(t="function"==typeof e?e:ep(+e),r(),n):t},n},t.forceLink=function(t){function n(n){for(var e=0,r=t.length;e<p;++e)for(var i,a,c,f,l,h,d,v=0;v<r;++v)a=(i=t[v]).source,f=(c=i.target).x+c.vx-a.x-a.vx||rp(),l=c.y+c.vy-a.y-a.vy||rp(),f*=h=((h=Math.sqrt(f*f+l*l))-u[v])/h*n*o[v],l*=h,c.vx-=f*(d=s[v]),c.vy-=l*d,a.vx+=f*(d=1-d),a.vy+=l*d}function e(){if(a){var n,e,l=a.length,h=t.length,p=we(a,f);for(n=0,c=new Array(l);n<h;++n)(e=t[n]).index=n,"object"!=typeof e.source&&(e.source=Ye(p,e.source)),"object"!=typeof e.target&&(e.target=Ye(p,e.target)),c[e.source.index]=(c[e.source.index]||0)+1,c[e.target.index]=(c[e.target.index]||0)+1;for(n=0,s=new Array(h);n<h;++n)e=t[n],s[n]=c[e.source.index]/(c[e.source.index]+c[e.target.index]);o=new Array(h),r(),u=new Array(h),i()}}function r(){if(a)for(var n=0,e=t.length;n<e;++n)o[n]=+l(t[n],n,t)}function i(){if(a)for(var n=0,e=t.length;n<e;++n)u[n]=+h(t[n],n,t)}var o,u,a,c,s,f=Ie,l=function(t){return 1/Math.min(c[t.source.index],c[t.target.index])},h=ep(30),p=1;return null==t&&(t=[]),n.initialize=function(t){a=t,e()},n.links=function(r){return arguments.length?(t=r,e(),n):t},n.id=function(t){return arguments.length?(f=t,n):f},n.iterations=function(t){return arguments.length?(p=+t,n):p},n.strength=function(t){return arguments.length?(l="function"==typeof t?t:ep(+t),r(),n):l},n.distance=function(t){return arguments.length?(h="function"==typeof t?t:ep(+t),i(),n):h},n},t.forceManyBody=function(){function t(t){var n,a=i.length,c=qe(i,Be,je).visitAfter(e);for(u=t,n=0;n<a;++n)o=i[n],c.visit(r)}function n(){if(i){var t,n,e=i.length;for(a=new Array(e),t=0;t<e;++t)n=i[t],a[n.index]=+c(n,t,i)}}function e(t){var n,e,r,i,o,u=0;if(t.length){for(r=i=o=0;o<4;++o)(n=t[o])&&(e=n.value)&&(u+=e,r+=e*n.x,i+=e*n.y);t.x=r/u,t.y=i/u}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=a[n.data.index]}while(n=n.next)}t.value=u}function r(t,n,e,r){if(!t.value)return!0;var i=t.x-o.x,c=t.y-o.y,h=r-n,p=i*i+c*c;if(h*h/l<p)return p<f&&(0===i&&(i=rp(),p+=i*i),0===c&&(c=rp(),p+=c*c),p<s&&(p=Math.sqrt(s*p)),o.vx+=i*t.value*u/p,o.vy+=c*t.value*u/p),!0;if(!(t.length||p>=f)){(t.data!==o||t.next)&&(0===i&&(i=rp(),p+=i*i),0===c&&(c=rp(),p+=c*c),p<s&&(p=Math.sqrt(s*p)));do{t.data!==o&&(h=a[t.data.index]*u/p,o.vx+=i*h,o.vy+=c*h)}while(t=t.next)}}var i,o,u,a,c=ep(-30),s=1,f=1/0,l=.81;return t.initialize=function(t){i=t,n()},t.strength=function(e){return arguments.length?(c="function"==typeof e?e:ep(+e),n(),t):c},t.distanceMin=function(n){return arguments.length?(s=n*n,t):Math.sqrt(s)},t.distanceMax=function(n){return arguments.length?(f=n*n,t):Math.sqrt(f)},t.theta=function(n){return arguments.length?(l=n*n,t):Math.sqrt(l)},t},t.forceSimulation=function(t){function n(){e(),d.call("tick",o),u<a&&(p.stop(),d.call("end",o))}function e(){var n,e,r=t.length;for(u+=(s-u)*c,l.each(function(t){t(u)}),n=0;n<r;++n)null==(e=t[n]).fx?e.x+=e.vx*=f:(e.x=e.fx,e.vx=0),null==e.fy?e.y+=e.vy*=f:(e.y=e.fy,e.vy=0)}function r(){for(var n,e=0,r=t.length;e<r;++e){if(n=t[e],n.index=e,isNaN(n.x)||isNaN(n.y)){var i=ap*Math.sqrt(e),o=e*cp;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function i(n){return n.initialize&&n.initialize(t),n}var o,u=1,a=.001,c=1-Math.pow(a,1/300),s=0,f=.6,l=we(),p=dn(n),d=h("tick","end");return null==t&&(t=[]),r(),o={tick:e,restart:function(){return p.restart(n),o},stop:function(){return p.stop(),o},nodes:function(n){return arguments.length?(t=n,r(),l.each(i),o):t},alpha:function(t){return arguments.length?(u=+t,o):u},alphaMin:function(t){return arguments.length?(a=+t,o):a},alphaDecay:function(t){return arguments.length?(c=+t,o):+c},alphaTarget:function(t){return arguments.length?(s=+t,o):s},velocityDecay:function(t){return arguments.length?(f=1-t,o):1-f},force:function(t,n){return arguments.length>1?(null==n?l.remove(t):l.set(t,i(n)),o):l.get(t)},find:function(n,e,r){var i,o,u,a,c,s=0,f=t.length;for(null==r?r=1/0:r*=r,s=0;s<f;++s)(u=(i=n-(a=t[s]).x)*i+(o=e-a.y)*o)<r&&(c=a,r=u);return c},on:function(t,n){return arguments.length>1?(d.on(t,n),o):d.on(t)}}},t.forceX=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)(n=r[e]).vx+=(o[e]-n.x)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=ep(.1);return"function"!=typeof t&&(t=ep(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),e(),n):u},n.x=function(r){return arguments.length?(t="function"==typeof r?r:ep(+r),e(),n):t},n},t.forceY=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)(n=r[e]).vy+=(o[e]-n.y)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=ep(.1);return"function"!=typeof t&&(t=ep(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),e(),n):u},n.y=function(r){return arguments.length?(t="function"==typeof r?r:ep(+r),e(),n):t},n},t.formatDefaultLocale=$e,t.formatLocale=mp,t.formatSpecifier=He,t.precisionFixed=xp,t.precisionPrefix=bp,t.precisionRound=wp,t.geoArea=function(t){return kd.reset(),Md(t,Nd),2*kd},t.geoBounds=function(t){var n,e,r,i,o,u,a;if(Pp=zp=-(Ap=Cp=1/0),Dp=[],Md(t,Ed),e=Dp.length){for(Dp.sort(br),n=1,o=[r=Dp[0]];n<e;++n)wr(r,(i=Dp[n])[0])||wr(r,i[1])?(xr(r[0],i[1])>xr(r[0],r[1])&&(r[1]=i[1]),xr(i[0],r[1])>xr(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(a=xr(r[1],i[0]))>u&&(u=a,Ap=i[0],zp=r[1])}return Dp=Op=null,Ap===1/0||Cp===1/0?[[NaN,NaN],[NaN,NaN]]:[[Ap,Cp],[zp,Pp]]},t.geoCentroid=function(t){Fp=Ip=Yp=Bp=jp=Hp=Xp=$p=Vp=Wp=Zp=0,Md(t,Ad);var n=Vp,e=Wp,r=Zp,i=n*n+e*e+r*r;return i<1e-12&&(n=Hp,e=Xp,r=$p,Ip<ed&&(n=Yp,e=Bp,r=jp),(i=n*n+e*e+r*r)<1e-12)?[NaN,NaN]:[ld(e,n)*ad,Ge(r/md(i))*ad]},t.geoCircle=function(){function t(){var t=r.apply(this,arguments),a=i.apply(this,arguments)*cd,c=o.apply(this,arguments)*cd;return n=[],e=Lr(-t[0]*cd,-t[1]*cd,0).invert,Or(u,a,c,1),t={type:"Polygon",coordinates:[n]},n=e=null,t}var n,e,r=Cd([0,0]),i=Cd(90),o=Cd(6),u={point:function(t,r){n.push(t=e(t,r)),t[0]*=ad,t[1]*=ad}};return t.center=function(n){return arguments.length?(r="function"==typeof n?n:Cd([+n[0],+n[1]]),t):r},t.radius=function(n){return arguments.length?(i="function"==typeof n?n:Cd(+n),t):i},t.precision=function(n){return arguments.length?(o="function"==typeof n?n:Cd(+n),t):o},t},t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,u=500;return e={stream:function(e){return t&&n===e?t:t=Br(r,i,o,u)(n=e)},extent:function(a){return arguments.length?(r=+a[0][0],i=+a[0][1],o=+a[1][0],u=+a[1][1],t=n=null,e):[[r,i],[o,u]]}}},t.geoContains=function(t,n){return(t&&iv.hasOwnProperty(t.type)?iv[t.type]:$r)(t,n)},t.geoDistance=rv,t.geoGraticule=ti,t.geoGraticule10=function(){return ti()()},t.geoInterpolate=function(t,n){var e=t[0]*cd,r=t[1]*cd,i=n[0]*cd,o=n[1]*cd,u=hd(r),a=yd(r),c=hd(o),s=yd(o),f=u*hd(e),l=u*yd(e),h=c*hd(i),p=c*yd(i),d=2*Ge(md(Je(o-r)+u*c*Je(i-e))),v=yd(d),_=d?function(t){var n=yd(t*=d)/v,e=yd(d-t)/v,r=e*f+n*h,i=e*l+n*p,o=e*a+n*s;return[ld(i,r)*ad,ld(o,md(r*r+i*i))*ad]}:function(){return[e*ad,r*ad]};return _.distance=d,_},t.geoLength=tv,t.geoPath=function(t,n){function e(t){return t&&("function"==typeof o&&i.pointRadius(+o.apply(this,arguments)),Md(t,r(i))),i.result()}var r,i,o=4.5;return e.area=function(t){return Md(t,r(sv)),sv.result()},e.measure=function(t){return Md(t,r(zv)),zv.result()},e.bounds=function(t){return Md(t,r(dv)),dv.result()},e.centroid=function(t){return Md(t,r(Tv)),Tv.result()},e.projection=function(n){return arguments.length?(r=null==n?(t=null,uv):(t=n).stream,e):t},e.context=function(t){return arguments.length?(i=null==t?(n=null,new yi):new di(n=t),"function"!=typeof o&&i.pointRadius(o),e):n},e.pointRadius=function(t){return arguments.length?(o="function"==typeof t?t:(i.pointRadius(+t),+t),e):o},e.projection(t).context(n)},t.geoAlbers=Iv,t.geoAlbersUsa=function(){function t(t){var n=t[0],e=t[1];return a=null,i.point(n,e),a||(o.point(n,e),a)||(u.point(n,e),a)}function n(){return e=r=null,t}var e,r,i,o,u,a,c=Iv(),s=Fv().rotate([154,0]).center([-2,58.5]).parallels([55,65]),f=Fv().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(t,n){a=[t,n]}};return t.invert=function(t){var n=c.scale(),e=c.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?f:c).invert(t)},t.stream=function(t){return e&&r===t?e:e=Ri([c.stream(r=t),s.stream(t),f.stream(t)])},t.precision=function(t){return arguments.length?(c.precision(t),s.precision(t),f.precision(t),n()):c.precision()},t.scale=function(n){return arguments.length?(c.scale(n),s.scale(.35*n),f.scale(n),t.translate(c.translate())):c.scale()},t.translate=function(t){if(!arguments.length)return c.translate();var e=c.scale(),r=+t[0],a=+t[1];return i=c.translate(t).clipExtent([[r-.455*e,a-.238*e],[r+.455*e,a+.238*e]]).stream(l),o=s.translate([r-.307*e,a+.201*e]).clipExtent([[r-.425*e+ed,a+.12*e+ed],[r-.214*e-ed,a+.234*e-ed]]).stream(l),u=f.translate([r-.205*e,a+.212*e]).clipExtent([[r-.214*e+ed,a+.166*e+ed],[r-.115*e-ed,a+.234*e-ed]]).stream(l),n()},t.fitExtent=function(n,e){return Ti(t,n,e)},t.fitSize=function(n,e){return ki(t,n,e)},t.scale(1070)},t.geoAzimuthalEqualArea=function(){return Ei(Yv).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Yv,t.geoAzimuthalEquidistant=function(){return Ei(Bv).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=Bv,t.geoConicConformal=function(){return Ci(Fi).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=Fi,t.geoConicEqualArea=Fv,t.geoConicEqualAreaRaw=Pi,t.geoConicEquidistant=function(){return Ci(Yi).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=Yi,t.geoEquirectangular=function(){return Ei(Ii).scale(152.63)},t.geoEquirectangularRaw=Ii,t.geoGnomonic=function(){return Ei(Bi).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=Bi,t.geoIdentity=function(){function t(){return i=o=null,u}var n,e,r,i,o,u,a=1,c=0,s=0,f=1,l=1,h=uv,p=null,d=uv;return u={stream:function(t){return i&&o===t?i:i=h(d(o=t))},clipExtent:function(i){return arguments.length?(d=null==i?(p=n=e=r=null,uv):Br(p=+i[0][0],n=+i[0][1],e=+i[1][0],r=+i[1][1]),t()):null==p?null:[[p,n],[e,r]]},scale:function(n){return arguments.length?(h=ji((a=+n)*f,a*l,c,s),t()):a},translate:function(n){return arguments.length?(h=ji(a*f,a*l,c=+n[0],s=+n[1]),t()):[c,s]},reflectX:function(n){return arguments.length?(h=ji(a*(f=n?-1:1),a*l,c,s),t()):f<0},reflectY:function(n){return arguments.length?(h=ji(a*f,a*(l=n?-1:1),c,s),t()):l<0},fitExtent:function(t,n){return Ti(u,t,n)},fitSize:function(t,n){return ki(u,t,n)}}},t.geoProjection=Ei,t.geoProjectionMutator=Ai,t.geoMercator=function(){return Di(Ui).scale(961/ud)},t.geoMercatorRaw=Ui,t.geoOrthographic=function(){return Ei(Hi).scale(249.5).clipAngle(90+ed)},t.geoOrthographicRaw=Hi,t.geoStereographic=function(){return Ei(Xi).scale(250).clipAngle(142)},t.geoStereographicRaw=Xi,t.geoTransverseMercator=function(){var t=Di($i),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):(t=n(),[t[1],-t[0]])},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):(t=e(),[t[0],t[1],t[2]-90])},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=$i,t.geoRotation=jd,t.geoStream=Md,t.geoTransform=function(t){return{stream:wi(t)}},t.cluster=function(){function t(t){var o,u=0;t.eachAfter(function(t){var e=t.children;e?(t.x=Wi(e),t.y=Gi(e)):(t.x=o?u+=n(t,o):0,t.y=0,o=t)});var a=Qi(t),c=Ki(t),s=a.x-n(a,c)/2,f=c.x+n(c,a)/2;return t.eachAfter(i?function(n){n.x=(n.x-t.x)*e,n.y=(t.y-n.y)*r}:function(n){n.x=(n.x-s)/(f-s)*e,n.y=(1-(t.y?n.y/t.y:1))*r})}var n=Vi,e=1,r=1,i=!1;return t.separation=function(e){return arguments.length?(n=e,t):n},t.size=function(n){return arguments.length?(i=!1,e=+n[0],r=+n[1],t):i?null:[e,r]},t.nodeSize=function(n){return arguments.length?(i=!0,e=+n[0],r=+n[1],t):i?[e,r]:null},t},t.hierarchy=eo,t.pack=function(){function t(t){return t.x=e/2,t.y=r/2,n?t.eachBefore(No(n)).eachAfter(So(i,.5)).eachBefore(Eo(1)):t.eachBefore(No(ko)).eachAfter(So(To,1)).eachAfter(So(i,t.r/Math.min(e,r))).eachBefore(Eo(Math.min(e,r)/(2*t.r))),t}var n=null,e=1,r=1,i=To;return t.radius=function(e){return arguments.length?(n=wo(e),t):n},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i="function"==typeof n?n:Xv(+n),t):i},t},t.packSiblings=function(t){return bo(t),t},t.packEnclose=Hv,t.partition=function(){function t(t){var u=t.height+1;return t.x0=t.y0=i,t.x1=e,t.y1=r/u,t.eachBefore(n(r,u)),o&&t.eachBefore($v),t}function n(t,n){return function(e){e.children&&Vv(e,e.x0,t*(e.depth+1)/n,e.x1,t*(e.depth+2)/n);var r=e.x0,o=e.y0,u=e.x1-i,a=e.y1-i;u<r&&(r=u=(r+u)/2),a<o&&(o=a=(o+a)/2),e.x0=r,e.y0=o,e.x1=u,e.y1=a}}var e=1,r=1,i=0,o=!1;return t.round=function(n){return arguments.length?(o=!!n,t):o},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i=+n,t):i},t},t.stratify=function(){function t(t){var r,i,o,u,a,c,s,f=t.length,l=new Array(f),h={};for(i=0;i<f;++i)r=t[i],a=l[i]=new uo(r),null!=(c=n(r,i,t))&&(c+="")&&(h[s=Wv+(a.id=c)]=s in h?Gv:a);for(i=0;i<f;++i)if(a=l[i],null!=(c=e(t[i],i,t))&&(c+="")){if(!(u=h[Wv+c]))throw new Error("missing: "+c);if(u===Gv)throw new Error("ambiguous: "+c);u.children?u.children.push(a):u.children=[a],a.parent=u}else{if(o)throw new Error("multiple roots");o=a}if(!o)throw new Error("no root");if(o.parent=Zv,o.eachBefore(function(t){t.depth=t.parent.depth+1,--f}).eachBefore(oo),o.parent=null,f>0)throw new Error("cycle");return o}var n=Ao,e=Co;return t.id=function(e){return arguments.length?(n=Mo(e),t):n},t.parentId=function(n){return arguments.length?(e=Mo(n),t):e},t},t.tree=function(){function t(t){var r=Oo(t);if(r.eachAfter(n),r.parent.m=-r.z,r.eachBefore(e),c)t.eachBefore(i);else{var s=t,f=t,l=t;t.eachBefore(function(t){t.x<s.x&&(s=t),t.x>f.x&&(f=t),t.depth>l.depth&&(l=t)});var h=s===f?1:o(s,f)/2,p=h-s.x,d=u/(f.x+h+p),v=a/(l.depth||1);t.eachBefore(function(t){t.x=(t.x+p)*d,t.y=t.depth*v})}return t}function n(t){var n=t.children,e=t.parent.children,i=t.i?e[t.i-1]:null;if(n){qo(t);var u=(n[0].z+n[n.length-1].z)/2;i?(t.z=i.z+o(t._,i._),t.m=t.z-u):t.z=u}else i&&(t.z=i.z+o(t._,i._));t.parent.A=r(t,i,t.parent.A||e[0])}function e(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function r(t,n,e){if(n){for(var r,i=t,u=t,a=n,c=i.parent.children[0],s=i.m,f=u.m,l=a.m,h=c.m;a=Ro(a),i=Po(i),a&&i;)c=Po(c),(u=Ro(u)).a=t,(r=a.z+l-i.z-s+o(a._,i._))>0&&(Lo(Uo(a,t,e),t,r),s+=r,f+=r),l+=a.m,s+=i.m,h+=c.m,f+=u.m;a&&!Ro(u)&&(u.t=a,u.m+=l-f),i&&!Po(c)&&(c.t=i,c.m+=s-h,e=t)}return e}function i(t){t.x*=u,t.y=t.depth*a}var o=zo,u=1,a=1,c=null;return t.separation=function(n){return arguments.length?(o=n,t):o},t.size=function(n){return arguments.length?(c=!1,u=+n[0],a=+n[1],t):c?null:[u,a]},t.nodeSize=function(n){return arguments.length?(c=!0,u=+n[0],a=+n[1],t):c?[u,a]:null},t},t.treemap=function(){function t(t){return t.x0=t.y0=0,t.x1=i,t.y1=o,t.eachBefore(n),u=[0],r&&t.eachBefore($v),t}function n(t){var n=u[t.depth],r=t.x0+n,i=t.y0+n,o=t.x1-n,h=t.y1-n;o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),t.x0=r,t.y0=i,t.x1=o,t.y1=h,t.children&&(n=u[t.depth+1]=a(t)/2,r+=l(t)-n,i+=c(t)-n,o-=s(t)-n,h-=f(t)-n,o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),e(t,r,i,o,h))}var e=Kv,r=!1,i=1,o=1,u=[0],a=To,c=To,s=To,f=To,l=To;return t.round=function(n){return arguments.length?(r=!!n,t):r},t.size=function(n){return arguments.length?(i=+n[0],o=+n[1],t):[i,o]},t.tile=function(n){return arguments.length?(e=Mo(n),t):e},t.padding=function(n){return arguments.length?t.paddingInner(n).paddingOuter(n):t.paddingInner()},t.paddingInner=function(n){return arguments.length?(a="function"==typeof n?n:Xv(+n),t):a},t.paddingOuter=function(n){return arguments.length?t.paddingTop(n).paddingRight(n).paddingBottom(n).paddingLeft(n):t.paddingTop()},t.paddingTop=function(n){return arguments.length?(c="function"==typeof n?n:Xv(+n),t):c},t.paddingRight=function(n){return arguments.length?(s="function"==typeof n?n:Xv(+n),t):s},t.paddingBottom=function(n){return arguments.length?(f="function"==typeof n?n:Xv(+n),t):f},t.paddingLeft=function(n){return arguments.length?(l="function"==typeof n?n:Xv(+n),t):l},t},t.treemapBinary=function(t,n,e,r,i){function o(t,n,e,r,i,u,a){if(t>=n-1){var s=c[t];return s.x0=r,s.y0=i,s.x1=u,void(s.y1=a)}for(var l=f[t],h=e/2+l,p=t+1,d=n-1;p<d;){var v=p+d>>>1;f[v]<h?p=v+1:d=v}h-f[p-1]<f[p]-h&&t+1<p&&--p;var _=f[p]-l,y=e-_;if(u-r>a-i){var g=(r*y+u*_)/e;o(t,p,_,r,i,g,a),o(p,n,y,g,i,u,a)}else{var m=(i*y+a*_)/e;o(t,p,_,r,i,u,m),o(p,n,y,r,m,u,a)}}var u,a,c=t.children,s=c.length,f=new Array(s+1);for(f[0]=a=u=0;u<s;++u)f[u+1]=a+=c[u].value;o(0,s,t.value,n,e,r,i)},t.treemapDice=Vv,t.treemapSlice=Jv,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Jv:Vv)(t,n,e,r,i)},t.treemapSquarify=Kv,t.treemapResquarify=t_,t.interpolate=cl,t.interpolateArray=nl,t.interpolateBasis=Zf,t.interpolateBasisClosed=Gf,t.interpolateDate=el,t.interpolateNumber=rl,t.interpolateObject=il,t.interpolateRound=sl,t.interpolateString=al,t.interpolateTransformCss=pl,t.interpolateTransformSvg=dl,t.interpolateZoom=_l,t.interpolateRgb=Qf,t.interpolateRgbBasis=Kf,t.interpolateRgbBasisClosed=tl,t.interpolateHsl=yl,t.interpolateHslLong=gl,t.interpolateLab=function(t,n){var e=Kt((t=Ut(t)).l,(n=Ut(n)).l),r=Kt(t.a,n.a),i=Kt(t.b,n.b),o=Kt(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateHcl=ml,t.interpolateHclLong=xl,t.interpolateCubehelix=bl,t.interpolateCubehelixLong=wl,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.path=ve,t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,u=0,a=t[i-1],c=0;++r<i;)n=a,a=t[r],c+=e=n[0]*a[1]-a[0]*n[1],o+=(n[0]+a[0])*e,u+=(n[1]+a[1])*e;return c*=3,[o/c,u/c]},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(Io),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=Yo(r),u=Yo(i),a=u[0]===o[0],c=u[u.length-1]===o[o.length-1],s=[];for(n=o.length-1;n>=0;--n)s.push(t[r[o[n]][2]]);for(n=+a;n<u.length-c;++n)s.push(t[r[u[n]][2]]);return s},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],u=n[0],a=n[1],c=o[0],s=o[1],f=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>a!=s>a&&u<(c-e)*(a-r)/(s-r)+e&&(f=!f),c=e,s=r;return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],u=o[0],a=o[1],c=0;++r<i;)n=u,e=a,n-=u=(o=t[r])[0],e-=a=o[1],c+=Math.sqrt(n*n+e*e);return c},t.quadtree=qe,t.queue=Wo,t.randomUniform=o_,t.randomNormal=u_,t.randomLogNormal=a_,t.randomBates=s_,t.randomIrwinHall=c_,t.randomExponential=f_,t.request=l_,t.html=p_,t.json=d_,t.text=v_,t.xml=__,t.csv=g_,t.tsv=m_,t.scaleBand=Ko,t.scalePoint=function(){return tu(Ko().paddingInner(1))},t.scaleIdentity=fu,t.scaleLinear=su,t.scaleLog=yu,t.scaleOrdinal=Qo,t.scaleImplicit=M_,t.scalePow=mu,t.scaleSqrt=function(){return mu().exponent(.5)},t.scaleQuantile=xu,t.scaleQuantize=bu,t.scaleThreshold=wu,t.scaleTime=function(){return Na(oy,ry,j_,Y_,F_,D_,q_,z_,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)])},t.scaleUtc=function(){return Na(Ay,Sy,py,ly,sy,ay,q_,z_,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)])},t.schemeCategory10=$y,t.schemeCategory20b=Vy,t.schemeCategory20c=Wy,t.schemeCategory20=Zy,t.interpolateCubehelixDefault=Gy,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return Ky.h=360*t-100,Ky.s=1.5-1.5*n,Ky.l=.8-.9*n,Ky+""},t.interpolateWarm=Jy,t.interpolateCool=Qy,t.interpolateViridis=tg,t.interpolateMagma=ng,t.interpolateInferno=eg,t.interpolatePlasma=rg,t.scaleSequential=Ea,t.creator=Hs,t.local=m,t.matcher=Zs,t.mouse=Ks,t.namespace=js,t.namespaces=Bs,t.select=cf,t.selectAll=function(t){return"string"==typeof t?new pt([document.querySelectorAll(t)],[document.documentElement]):new pt([null==t?[]:t],af)},t.selection=dt,t.selector=tf,t.selectorAll=nf,t.style=B,t.touch=sf,t.touches=function(t,n){null==n&&(n=Js().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Qs(t,n[e]);return i},t.window=uf,t.customEvent=N,t.arc=function(){function t(){var t,s,f=+n.apply(this,arguments),l=+e.apply(this,arguments),h=o.apply(this,arguments)-dg,p=u.apply(this,arguments)-dg,d=og(p-h),v=p>h;if(c||(c=t=ve()),l<f&&(s=l,l=f,f=s),l>hg)if(d>vg-hg)c.moveTo(l*ag(h),l*fg(h)),c.arc(0,0,l,h,p,!v),f>hg&&(c.moveTo(f*ag(p),f*fg(p)),c.arc(0,0,f,p,h,v));else{var _,y,g=h,m=p,x=h,b=p,w=d,M=d,T=a.apply(this,arguments)/2,k=T>hg&&(i?+i.apply(this,arguments):lg(f*f+l*l)),N=sg(og(l-f)/2,+r.apply(this,arguments)),S=N,E=N;if(k>hg){var A=Ca(k/f*fg(T)),C=Ca(k/l*fg(T));(w-=2*A)>hg?(A*=v?1:-1,x+=A,b-=A):(w=0,x=b=(h+p)/2),(M-=2*C)>hg?(C*=v?1:-1,g+=C,m-=C):(M=0,g=m=(h+p)/2)}var z=l*ag(g),P=l*fg(g),R=f*ag(b),L=f*fg(b);if(N>hg){var q=l*ag(m),U=l*fg(m),D=f*ag(x),O=f*fg(x);if(d<pg){var F=w>hg?Ua(z,P,D,O,q,U,R,L):[R,L],I=z-F[0],Y=P-F[1],B=q-F[0],j=U-F[1],H=1/fg(Aa((I*B+Y*j)/(lg(I*I+Y*Y)*lg(B*B+j*j)))/2),X=lg(F[0]*F[0]+F[1]*F[1]);S=sg(N,(f-X)/(H-1)),E=sg(N,(l-X)/(H+1))}}M>hg?E>hg?(_=Da(D,O,z,P,l,E,v),y=Da(q,U,R,L,l,E,v),c.moveTo(_.cx+_.x01,_.cy+_.y01),E<N?c.arc(_.cx,_.cy,E,ug(_.y01,_.x01),ug(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,E,ug(_.y01,_.x01),ug(_.y11,_.x11),!v),c.arc(0,0,l,ug(_.cy+_.y11,_.cx+_.x11),ug(y.cy+y.y11,y.cx+y.x11),!v),c.arc(y.cx,y.cy,E,ug(y.y11,y.x11),ug(y.y01,y.x01),!v))):(c.moveTo(z,P),c.arc(0,0,l,g,m,!v)):c.moveTo(z,P),f>hg&&w>hg?S>hg?(_=Da(R,L,q,U,f,-S,v),y=Da(z,P,D,O,f,-S,v),c.lineTo(_.cx+_.x01,_.cy+_.y01),S<N?c.arc(_.cx,_.cy,S,ug(_.y01,_.x01),ug(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,S,ug(_.y01,_.x01),ug(_.y11,_.x11),!v),c.arc(0,0,f,ug(_.cy+_.y11,_.cx+_.x11),ug(y.cy+y.y11,y.cx+y.x11),v),c.arc(y.cx,y.cy,S,ug(y.y11,y.x11),ug(y.y01,y.x01),!v))):c.arc(0,0,f,b,x,v):c.lineTo(R,L)}else c.moveTo(0,0);if(c.closePath(),t)return c=null,t+""||null}var n=za,e=Pa,r=ig(0),i=null,o=Ra,u=La,a=qa,c=null;return t.centroid=function(){var t=(+n.apply(this,arguments)+ +e.apply(this,arguments))/2,r=(+o.apply(this,arguments)+ +u.apply(this,arguments))/2-pg/2;return[ag(r)*t,fg(r)*t]},t.innerRadius=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.outerRadius=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.cornerRadius=function(n){return arguments.length?(r="function"==typeof n?n:ig(+n),t):r},t.padRadius=function(n){return arguments.length?(i=null==n?null:"function"==typeof n?n:ig(+n),t):i},t.startAngle=function(n){return arguments.length?(o="function"==typeof n?n:ig(+n),t):o},t.endAngle=function(n){return arguments.length?(u="function"==typeof n?n:ig(+n),t):u},t.padAngle=function(n){return arguments.length?(a="function"==typeof n?n:ig(+n),t):a},t.context=function(n){return arguments.length?(c=null==n?null:n,t):c},t},t.area=gg,t.line=yg,t.pie=function(){function t(t){var a,c,s,f,l,h=t.length,p=0,d=new Array(h),v=new Array(h),_=+i.apply(this,arguments),y=Math.min(vg,Math.max(-vg,o.apply(this,arguments)-_)),g=Math.min(Math.abs(y)/h,u.apply(this,arguments)),m=g*(y<0?-1:1);for(a=0;a<h;++a)(l=v[d[a]=a]=+n(t[a],a,t))>0&&(p+=l);for(null!=e?d.sort(function(t,n){return e(v[t],v[n])}):null!=r&&d.sort(function(n,e){return r(t[n],t[e])}),a=0,s=p?(y-h*m)/p:0;a<h;++a,_=f)c=d[a],f=_+((l=v[c])>0?l*s:0)+m,v[c]={data:t[c],index:a,value:l,startAngle:_,endAngle:f,padAngle:g};return v}var n=xg,e=mg,r=null,i=ig(0),o=ig(vg),u=ig(0);return t.value=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.sortValues=function(n){return arguments.length?(e=n,r=null,t):e},t.sort=function(n){return arguments.length?(r=n,e=null,t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:ig(+n),t):o},t.padAngle=function(n){return arguments.length?(u="function"==typeof n?n:ig(+n),t):u},t},t.areaRadial=Mg,t.radialArea=Mg,t.lineRadial=wg,t.radialLine=wg,t.pointRadial=Tg,t.linkHorizontal=function(){return $a(Va)},t.linkVertical=function(){return $a(Wa)},t.linkRadial=function(){var t=$a(Za);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.symbol=function(){function t(){var t;if(r||(r=t=ve()),n.apply(this,arguments).draw(r,+e.apply(this,arguments)),t)return r=null,t+""||null}var n=ig(Ng),e=ig(64),r=null;return t.type=function(e){return arguments.length?(n="function"==typeof e?e:ig(e),t):n},t.size=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.context=function(n){return arguments.length?(r=null==n?null:n,t):r},t},t.symbols=jg,t.symbolCircle=Ng,t.symbolCross=Sg,t.symbolDiamond=Cg,t.symbolSquare=qg,t.symbolStar=Lg,t.symbolTriangle=Dg,t.symbolWye=Bg,t.curveBasisClosed=function(t){return new Qa(t)},t.curveBasisOpen=function(t){return new Ka(t)},t.curveBasis=function(t){return new Ja(t)},t.curveBundle=Xg,t.curveCardinalClosed=Vg,t.curveCardinalOpen=Wg,t.curveCardinal=$g,t.curveCatmullRomClosed=Gg,t.curveCatmullRomOpen=Jg,t.curveCatmullRom=Zg,t.curveLinearClosed=function(t){return new sc(t)},t.curveLinear=_g,t.curveMonotoneX=function(t){return new dc(t)},t.curveMonotoneY=function(t){return new vc(t)},t.curveNatural=function(t){return new yc(t)},t.curveStep=function(t){return new mc(t,.5)},t.curveStepAfter=function(t){return new mc(t,1)},t.curveStepBefore=function(t){return new mc(t,0)},t.stack=function(){function t(t){var o,u,a=n.apply(this,arguments),c=t.length,s=a.length,f=new Array(s);for(o=0;o<s;++o){for(var l,h=a[o],p=f[o]=new Array(c),d=0;d<c;++d)p[d]=l=[0,+i(t[d],h,d,t)],l.data=t[d];p.key=h}for(o=0,u=e(f);o<s;++o)f[u[o]].index=o;return r(f,u),f}var n=ig([]),e=Kg,r=Qg,i=xc;return t.keys=function(e){return arguments.length?(n="function"==typeof e?e:ig(kg.call(e)),t):n},t.value=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.order=function(n){return arguments.length?(e=null==n?Kg:"function"==typeof n?n:ig(kg.call(n)),t):e},t.offset=function(n){return arguments.length?(r=null==n?Qg:n,t):r},t},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,u=t[0].length;o<u;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}Qg(t,n)}},t.stackOffsetDiverging=function(t,n){if((a=t.length)>1)for(var e,r,i,o,u,a,c=0,s=t[n[0]].length;c<s;++c)for(o=u=0,e=0;e<a;++e)(i=(r=t[n[e]][c])[1]-r[0])>=0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=u,r[0]=u+=i):r[0]=o},t.stackOffsetNone=Qg,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var u=0,a=0;u<e;++u)a+=t[u][r][1]||0;i[r][1]+=i[r][0]=-a/2}Qg(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,u=1;u<r;++u){for(var a=0,c=0,s=0;a<i;++a){for(var f=t[n[a]],l=f[u][1]||0,h=(l-(f[u-1][1]||0))/2,p=0;p<a;++p){var d=t[n[p]];h+=(d[u][1]||0)-(d[u-1][1]||0)}c+=l,s+=h*l}e[u-1][1]+=e[u-1][0]=o,c&&(o-=s/c)}e[u-1][1]+=e[u-1][0]=o,Qg(t,n)}},t.stackOrderAscending=tm,t.stackOrderDescending=function(t){return tm(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(bc),o=Kg(t).sort(function(t,n){return i[n]-i[t]}),u=0,a=0,c=[],s=[];for(n=0;n<r;++n)e=o[n],u<a?(u+=i[e],c.push(e)):(a+=i[e],s.push(e));return s.reverse().concat(c)},t.stackOrderNone=Kg,t.stackOrderReverse=function(t){return Kg(t).reverse()},t.timeInterval=Mu,t.timeMillisecond=z_,t.timeMilliseconds=P_,t.utcMillisecond=z_,t.utcMilliseconds=P_,t.timeSecond=q_,t.timeSeconds=U_,t.utcSecond=q_,t.utcSeconds=U_,t.timeMinute=D_,t.timeMinutes=O_,t.timeHour=F_,t.timeHours=I_,t.timeDay=Y_,t.timeDays=B_,t.timeWeek=j_,t.timeWeeks=G_,t.timeSunday=j_,t.timeSundays=G_,t.timeMonday=H_,t.timeMondays=J_,t.timeTuesday=X_,t.timeTuesdays=Q_,t.timeWednesday=$_,t.timeWednesdays=K_,t.timeThursday=V_,t.timeThursdays=ty,t.timeFriday=W_,t.timeFridays=ny,t.timeSaturday=Z_,t.timeSaturdays=ey,t.timeMonth=ry,t.timeMonths=iy,t.timeYear=oy,t.timeYears=uy,t.utcMinute=ay,t.utcMinutes=cy,t.utcHour=sy,t.utcHours=fy,t.utcDay=ly,t.utcDays=hy,t.utcWeek=py,t.utcWeeks=xy,t.utcSunday=py,t.utcSundays=xy,t.utcMonday=dy,t.utcMondays=by,t.utcTuesday=vy,t.utcTuesdays=wy,t.utcWednesday=_y,t.utcWednesdays=My,t.utcThursday=yy,t.utcThursdays=Ty,t.utcFriday=gy,t.utcFridays=ky,t.utcSaturday=my,t.utcSaturdays=Ny,t.utcMonth=Sy,t.utcMonths=Ey,t.utcYear=Ay,t.utcYears=zy,t.timeFormatDefaultLocale=Ma,t.timeFormatLocale=Au,t.isoFormat=Uy,t.isoParse=Dy,t.now=ln,t.timer=dn,t.timerFlush=vn,t.timeout=Pl,t.interval=function(t,n,e){var r=new pn,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?ln():+e,r.restart(function o(u){u+=i,r.restart(o,i+=n,e),t(u)},n,e),r)},t.transition=Jn,t.active=function(t,n){var e,r,i=t.__transition;if(i){n=null==n?null:n+"";for(r in i)if((e=i[r]).state>Ul&&e.name===n)return new Gn([[t]],yh,n,+r)}return null},t.interrupt=jl,t.voronoi=function(){function t(t){return new Kc(t.map(function(r,i){var o=[Math.round(n(r,i,t)/sm)*sm,Math.round(e(r,i,t)/sm)*sm];return o.index=i,o.data=r,o}),r)}var n=wc,e=Mc,r=null;return t.polygons=function(n){return t(n).polygons()},t.links=function(n){return t(n).links()},t.triangles=function(n){return t(n).triangles()},t.x=function(e){return arguments.length?(n="function"==typeof e?e:nm(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:nm(+n),t):e},t.extent=function(n){return arguments.length?(r=null==n?null:[[+n[0][0],+n[0][1]],[+n[1][0],+n[1][1]]],t):r&&[[r[0][0],r[0][1]],[r[1][0],r[1][1]]]},t.size=function(n){return arguments.length?(r=null==n?null:[[0,0],[+n[0],+n[1]]],t):r&&[r[1][0]-r[0][0],r[1][1]-r[0][1]]},t},t.zoom=function(){function n(t){t.property("__zoom",us).on("wheel.zoom",s).on("mousedown.zoom",f).on("dblclick.zoom",l).filter(cs).on("touchstart.zoom",p).on("touchmove.zoom",d).on("touchend.zoom touchcancel.zoom",v).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(t,n){return(n=Math.max(b,Math.min(w,n)))===t.k?t:new ns(n,t.x,t.y)}function r(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ns(t.k,r,i)}function i(t,n){var e=t.invertX(n[0][0])-M,r=t.invertX(n[1][0])-T,i=t.invertY(n[0][1])-k,o=t.invertY(n[1][1])-S;return t.translate(r>e?(e+r)/2:Math.min(0,e)||Math.max(0,r),o>i?(i+o)/2:Math.min(0,i)||Math.max(0,o))}function o(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function u(t,n,e){t.on("start.zoom",function(){a(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){a(this,arguments).end()}).tween("zoom",function(){var t=this,r=arguments,i=a(t,r),u=m.apply(t,r),c=e||o(u),s=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),f=t.__zoom,l="function"==typeof n?n.apply(t,r):n,h=A(f.invert(c).concat(s/f.k),l.invert(c).concat(s/l.k));return function(t){if(1===t)t=l;else{var n=h(t),e=s/n[2];t=new ns(e,c[0]-n[0]*e,c[1]-n[1]*e)}i.zoom(null,t)}})}function a(t,n){for(var e,r=0,i=C.length;r<i;++r)if((e=C[r]).that===t)return e;return new c(t,n)}function c(t,n){this.that=t,this.args=n,this.index=-1,this.active=0,this.extent=m.apply(t,n)}function s(){if(g.apply(this,arguments)){var t=a(this,arguments),n=this.__zoom,o=Math.max(b,Math.min(w,n.k*Math.pow(2,x.apply(this,arguments)))),u=Ks(this);if(t.wheel)t.mouse[0][0]===u[0]&&t.mouse[0][1]===u[1]||(t.mouse[1]=n.invert(t.mouse[0]=u)),clearTimeout(t.wheel);else{if(n.k===o)return;t.mouse=[u,n.invert(u)],jl(this),t.start()}pm(),t.wheel=setTimeout(function(){t.wheel=null,t.end()},R),t.zoom("mouse",i(r(e(n,o),t.mouse[0],t.mouse[1]),t.extent))}}function f(){if(!y&&g.apply(this,arguments)){var n=a(this,arguments),e=cf(t.event.view).on("mousemove.zoom",function(){if(pm(),!n.moved){var e=t.event.clientX-u,o=t.event.clientY-c;n.moved=e*e+o*o>L}n.zoom("mouse",i(r(n.that.__zoom,n.mouse[0]=Ks(n.that),n.mouse[1]),n.extent))},!0).on("mouseup.zoom",function(){e.on("mousemove.zoom mouseup.zoom",null),_t(t.event.view,n.moved),pm(),n.end()},!0),o=Ks(this),u=t.event.clientX,c=t.event.clientY;lf(t.event.view),rs(),n.mouse=[o,this.__zoom.invert(o)],jl(this),n.start()}}function l(){if(g.apply(this,arguments)){var o=this.__zoom,a=Ks(this),c=o.invert(a),s=i(r(e(o,o.k*(t.event.shiftKey?.5:2)),a,c),m.apply(this,arguments));pm(),E>0?cf(this).transition().duration(E).call(u,s,a):cf(this).call(n.transform,s)}}function p(){if(g.apply(this,arguments)){var n,e,r,i,o=a(this,arguments),u=t.event.changedTouches,c=u.length;for(rs(),e=0;e<c;++e)r=u[e],i=[i=sf(this,u,r.identifier),this.__zoom.invert(i),r.identifier],o.touch0?o.touch1||(o.touch1=i):(o.touch0=i,n=!0);if(_&&(_=clearTimeout(_),!o.touch1))return o.end(),void((i=cf(this).on("dblclick.zoom"))&&i.apply(this,arguments));n&&(_=setTimeout(function(){_=null},P),jl(this),o.start())}}function d(){var n,o,u,c,s=a(this,arguments),f=t.event.changedTouches,l=f.length;for(pm(),_&&(_=clearTimeout(_)),n=0;n<l;++n)o=f[n],u=sf(this,f,o.identifier),s.touch0&&s.touch0[2]===o.identifier?s.touch0[0]=u:s.touch1&&s.touch1[2]===o.identifier&&(s.touch1[0]=u);if(o=s.that.__zoom,s.touch1){var h=s.touch0[0],p=s.touch0[1],d=s.touch1[0],v=s.touch1[1],y=(y=d[0]-h[0])*y+(y=d[1]-h[1])*y,g=(g=v[0]-p[0])*g+(g=v[1]-p[1])*g;o=e(o,Math.sqrt(y/g)),u=[(h[0]+d[0])/2,(h[1]+d[1])/2],c=[(p[0]+v[0])/2,(p[1]+v[1])/2]}else{if(!s.touch0)return;u=s.touch0[0],c=s.touch0[1]}s.zoom("touch",i(r(o,u,c),s.extent))}function v(){var n,e,r=a(this,arguments),i=t.event.changedTouches,o=i.length;for(rs(),y&&clearTimeout(y),y=setTimeout(function(){y=null},P),n=0;n<o;++n)e=i[n],r.touch0&&r.touch0[2]===e.identifier?delete r.touch0:r.touch1&&r.touch1[2]===e.identifier&&delete r.touch1;r.touch1&&!r.touch0&&(r.touch0=r.touch1,delete r.touch1),r.touch0?r.touch0[1]=this.__zoom.invert(r.touch0[0]):r.end()}var _,y,g=is,m=os,x=as,b=0,w=1/0,M=-w,T=w,k=M,S=T,E=250,A=_l,C=[],z=h("start","zoom","end"),P=500,R=150,L=0;return n.transform=function(t,n){var e=t.selection?t.selection():t;e.property("__zoom",us),t!==e?u(t,n):e.interrupt().each(function(){a(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},n.scaleBy=function(t,e){n.scaleTo(t,function(){return this.__zoom.k*("function"==typeof e?e.apply(this,arguments):e)})},n.scaleTo=function(t,u){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,a=o(t),c=n.invert(a);return i(r(e(n,"function"==typeof u?u.apply(this,arguments):u),a,c),t)})},n.translateBy=function(t,e,r){n.transform(t,function(){return i(this.__zoom.translate("function"==typeof e?e.apply(this,arguments):e,"function"==typeof r?r.apply(this,arguments):r),m.apply(this,arguments))})},n.translateTo=function(t,e,r){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,u=o(t);return i(hm.translate(u[0],u[1]).scale(n.k).translate("function"==typeof e?-e.apply(this,arguments):-e,"function"==typeof r?-r.apply(this,arguments):-r),t)})},c.prototype={start:function(){return 1==++this.active&&(this.index=C.push(this)-1,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(C.splice(this.index,1),this.index=-1,this.emit("end")),this},emit:function(t){N(new ts(n,t,this.that.__zoom),z.apply,z,[t,this.that,this.args])}},n.wheelDelta=function(t){return arguments.length?(x="function"==typeof t?t:lm(+t),n):x},n.filter=function(t){return arguments.length?(g="function"==typeof t?t:lm(!!t),n):g},n.extent=function(t){return arguments.length?(m="function"==typeof t?t:lm([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),n):m},n.scaleExtent=function(t){return arguments.length?(b=+t[0],w=+t[1],n):[b,w]},n.translateExtent=function(t){return arguments.length?(M=+t[0][0],T=+t[1][0],k=+t[0][1],S=+t[1][1],n):[[M,k],[T,S]]},n.duration=function(t){return arguments.length?(E=+t,n):E},n.interpolate=function(t){return arguments.length?(A=t,n):A},n.on=function(){var t=z.on.apply(z,arguments);return t===z?n:t},n.clickDistance=function(t){return arguments.length?(L=(t=+t)*t,n):Math.sqrt(L)},n},t.zoomTransform=es,t.zoomIdentity=hm,Object.defineProperty(t,"__esModule",{value:!0})});
\ No newline at end of file +// https://d3js.org Version 4.10.0. Copyright 2017 Mike Bostock. +(function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})})(this,function(t){"use strict";function n(t){return function(n,e){return ss(t(n),e)}}function e(t,n){return[t,n]}function r(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=Ts?10:o>=ks?5:o>=Ns?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=Ts?10:o>=ks?5:o>=Ns?2:1)}function i(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=Ts?i*=10:o>=ks?i*=5:o>=Ns&&(i*=2),n<t?-i:i}function o(t){return t.length}function u(t){return"translate("+(t+.5)+",0)"}function a(t){return"translate(0,"+(t+.5)+")"}function c(t){return function(n){return+t(n)}}function s(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}function f(){return!this.__axis}function l(t,n){function e(e){var u=null==i?n.ticks?n.ticks.apply(n,r):n.domain():i,a=null==o?n.tickFormat?n.tickFormat.apply(n,r):Ls:o,y=Math.max(l,0)+p,g=n.range(),m=+g[0]+.5,x=+g[g.length-1]+.5,b=(n.bandwidth?s:c)(n.copy()),w=e.selection?e.selection():e,M=w.selectAll(".domain").data([null]),T=w.selectAll(".tick").data(u,n).order(),k=T.exit(),N=T.enter().append("g").attr("class","tick"),S=T.select("line"),E=T.select("text");M=M.merge(M.enter().insert("path",".tick").attr("class","domain").attr("stroke","#000")),T=T.merge(N),S=S.merge(N.append("line").attr("stroke","#000").attr(v+"2",d*l)),E=E.merge(N.append("text").attr("fill","#000").attr(v,d*y).attr("dy",t===qs?"0em":t===Ds?"0.71em":"0.32em")),e!==w&&(M=M.transition(e),T=T.transition(e),S=S.transition(e),E=E.transition(e),k=k.transition(e).attr("opacity",Fs).attr("transform",function(t){return isFinite(t=b(t))?_(t):this.getAttribute("transform")}),N.attr("opacity",Fs).attr("transform",function(t){var n=this.parentNode.__axis;return _(n&&isFinite(n=n(t))?n:b(t))})),k.remove(),M.attr("d",t===Os||t==Us?"M"+d*h+","+m+"H0.5V"+x+"H"+d*h:"M"+m+","+d*h+"V0.5H"+x+"V"+d*h),T.attr("opacity",1).attr("transform",function(t){return _(b(t))}),S.attr(v+"2",d*l),E.attr(v,d*y).text(a),w.filter(f).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===Us?"start":t===Os?"end":"middle"),w.each(function(){this.__axis=b})}var r=[],i=null,o=null,l=6,h=6,p=3,d=t===qs||t===Os?-1:1,v=t===Os||t===Us?"x":"y",_=t===qs||t===Ds?u:a;return e.scale=function(t){return arguments.length?(n=t,e):n},e.ticks=function(){return r=Rs.call(arguments),e},e.tickArguments=function(t){return arguments.length?(r=null==t?[]:Rs.call(t),e):r.slice()},e.tickValues=function(t){return arguments.length?(i=null==t?null:Rs.call(t),e):i&&i.slice()},e.tickFormat=function(t){return arguments.length?(o=t,e):o},e.tickSize=function(t){return arguments.length?(l=h=+t,e):l},e.tickSizeInner=function(t){return arguments.length?(l=+t,e):l},e.tickSizeOuter=function(t){return arguments.length?(h=+t,e):h},e.tickPadding=function(t){return arguments.length?(p=+t,e):p},e}function h(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r)throw new Error("illegal type: "+t);r[t]=[]}return new p(r)}function p(t){this._=t}function d(t,n){return t.trim().split(/^|\s+/).map(function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}function v(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function _(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=Is,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}function y(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===Ys&&n.documentElement.namespaceURI===Ys?n.createElement(t):n.createElementNS(e,t)}}function g(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function m(){return new x}function x(){this._="@"+(++Xs).toString(36)}function b(t,n,e){return t=w(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function w(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function M(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}function T(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function k(t,n,e){var r=Gs.hasOwnProperty(t.type)?b:w;return function(i,o,u){var a,c=this.__on,s=r(n,o,u);if(c)for(var f=0,l=c.length;f<l;++f)if((a=c[f]).type===t.type&&a.name===t.name)return this.removeEventListener(a.type,a.listener,a.capture),this.addEventListener(a.type,a.listener=s,a.capture=e),void(a.value=n);this.addEventListener(t.type,s,e),a={type:t.type,name:t.name,value:n,listener:s,capture:e},c?c.push(a):this.__on=[a]}}function N(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function S(){}function E(){return[]}function A(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function C(t,n,e,r,i,o){for(var u,a=0,c=n.length,s=o.length;a<s;++a)(u=n[a])?(u.__data__=o[a],r[a]=u):e[a]=new A(t,o[a]);for(;a<c;++a)(u=n[a])&&(i[a]=u)}function z(t,n,e,r,i,o,u){var a,c,s,f={},l=n.length,h=o.length,p=new Array(l);for(a=0;a<l;++a)(c=n[a])&&(p[a]=s=of+u.call(c,c.__data__,a,n),s in f?i[a]=c:f[s]=c);for(a=0;a<h;++a)(c=f[s=of+u.call(t,o[a],a,o)])?(r[a]=c,c.__data__=o[a],f[s]=null):e[a]=new A(t,o[a]);for(a=0;a<l;++a)(c=n[a])&&f[p[a]]===c&&(i[a]=c)}function P(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function R(t){return function(){this.removeAttribute(t)}}function L(t){return function(){this.removeAttributeNS(t.space,t.local)}}function q(t,n){return function(){this.setAttribute(t,n)}}function U(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function D(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function O(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function F(t){return function(){this.style.removeProperty(t)}}function I(t,n,e){return function(){this.style.setProperty(t,n,e)}}function Y(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function B(t,n){return t.style.getPropertyValue(n)||uf(t).getComputedStyle(t,null).getPropertyValue(n)}function j(t){return function(){delete this[t]}}function H(t,n){return function(){this[t]=n}}function X(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function $(t){return t.trim().split(/^|\s+/)}function V(t){return t.classList||new W(t)}function W(t){this._node=t,this._names=$(t.getAttribute("class")||"")}function Z(t,n){for(var e=V(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function G(t,n){for(var e=V(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function J(t){return function(){Z(this,t)}}function Q(t){return function(){G(this,t)}}function K(t,n){return function(){(n.apply(this,arguments)?Z:G)(this,t)}}function tt(){this.textContent=""}function nt(t){return function(){this.textContent=t}}function et(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}function rt(){this.innerHTML=""}function it(t){return function(){this.innerHTML=t}}function ot(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}function ut(){this.nextSibling&&this.parentNode.appendChild(this)}function at(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function ct(){return null}function st(){var t=this.parentNode;t&&t.removeChild(this)}function ft(t,n,e){var r=uf(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function lt(t,n){return function(){return ft(this,t,n)}}function ht(t,n){return function(){return ft(this,t,n.apply(this,arguments))}}function pt(t,n){this._groups=t,this._parents=n}function dt(){return new pt([[document.documentElement]],af)}function vt(){t.event.stopImmediatePropagation()}function _t(t,n){var e=t.document.documentElement,r=cf(t).on("dragstart.drag",null);n&&(r.on("click.drag",ff,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function yt(t,n,e,r,i,o,u,a,c,s){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=u,this.dx=a,this.dy=c,this._=s}function gt(){return!t.event.button}function mt(){return this.parentNode}function xt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function bt(){return"ontouchstart"in this}function wt(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Mt(){}function Tt(t){var n;return t=(t+"").trim().toLowerCase(),(n=yf.exec(t))?(n=parseInt(n[1],16),new At(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1)):(n=gf.exec(t))?kt(parseInt(n[1],16)):(n=mf.exec(t))?new At(n[1],n[2],n[3],1):(n=xf.exec(t))?new At(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=bf.exec(t))?Nt(n[1],n[2],n[3],n[4]):(n=wf.exec(t))?Nt(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Mf.exec(t))?Ct(n[1],n[2]/100,n[3]/100,1):(n=Tf.exec(t))?Ct(n[1],n[2]/100,n[3]/100,n[4]):kf.hasOwnProperty(t)?kt(kf[t]):"transparent"===t?new At(NaN,NaN,NaN,0):null}function kt(t){return new At(t>>16&255,t>>8&255,255&t,1)}function Nt(t,n,e,r){return r<=0&&(t=n=e=NaN),new At(t,n,e,r)}function St(t){return t instanceof Mt||(t=Tt(t)),t?(t=t.rgb(),new At(t.r,t.g,t.b,t.opacity)):new At}function Et(t,n,e,r){return 1===arguments.length?St(t):new At(t,n,e,null==r?1:r)}function At(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ct(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Rt(t,n,e,r)}function zt(t){if(t instanceof Rt)return new Rt(t.h,t.s,t.l,t.opacity);if(t instanceof Mt||(t=Tt(t)),!t)return new Rt;if(t instanceof Rt)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e<r):e===o?(r-n)/a+2:(n-e)/a+4,a/=c<.5?o+i:2-o-i,u*=60):a=c>0&&c<1?0:u,new Rt(u,a,c,t.opacity)}function Pt(t,n,e,r){return 1===arguments.length?zt(t):new Rt(t,n,e,null==r?1:r)}function Rt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Lt(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function qt(t){if(t instanceof Dt)return new Dt(t.l,t.a,t.b,t.opacity);if(t instanceof Ht){var n=t.h*Nf;return new Dt(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof At||(t=St(t));var e=Yt(t.r),r=Yt(t.g),i=Yt(t.b),o=Ot((.4124564*e+.3575761*r+.1804375*i)/Ef),u=Ot((.2126729*e+.7151522*r+.072175*i)/Af);return new Dt(116*u-16,500*(o-u),200*(u-Ot((.0193339*e+.119192*r+.9503041*i)/Cf)),t.opacity)}function Ut(t,n,e,r){return 1===arguments.length?qt(t):new Dt(t,n,e,null==r?1:r)}function Dt(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Ot(t){return t>Lf?Math.pow(t,1/3):t/Rf+zf}function Ft(t){return t>Pf?t*t*t:Rf*(t-zf)}function It(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Yt(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Bt(t){if(t instanceof Ht)return new Ht(t.h,t.c,t.l,t.opacity);t instanceof Dt||(t=qt(t));var n=Math.atan2(t.b,t.a)*Sf;return new Ht(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function jt(t,n,e,r){return 1===arguments.length?Bt(t):new Ht(t,n,e,null==r?1:r)}function Ht(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function Xt(t){if(t instanceof Vt)return new Vt(t.h,t.s,t.l,t.opacity);t instanceof At||(t=St(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Bf*r+If*n-Yf*e)/(Bf+If-Yf),o=r-i,u=(Ff*(e-i)-Df*o)/Of,a=Math.sqrt(u*u+o*o)/(Ff*i*(1-i)),c=a?Math.atan2(u,o)*Sf-120:NaN;return new Vt(c<0?c+360:c,a,i,t.opacity)}function $t(t,n,e,r){return 1===arguments.length?Xt(t):new Vt(t,n,e,null==r?1:r)}function Vt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Wt(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}function Zt(t,n){return function(e){return t+e*n}}function Gt(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}function Jt(t,n){var e=n-t;return e?Zt(t,e>180||e<-180?e-360*Math.round(e/360):e):Jf(isNaN(t)?n:t)}function Qt(t){return 1==(t=+t)?Kt:function(n,e){return e-n?Gt(n,e,t):Jf(isNaN(n)?e:n)}}function Kt(t,n){var e=n-t;return e?Zt(t,e):Jf(isNaN(t)?n:t)}function tn(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e<i;++e)r=Et(n[e]),o[e]=r.r||0,u[e]=r.g||0,a[e]=r.b||0;return o=t(o),u=t(u),a=t(a),r.opacity=1,function(t){return r.r=o(t),r.g=u(t),r.b=a(t),r+""}}}function nn(t){return function(){return t}}function en(t){return function(n){return t(n)+""}}function rn(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}function o(t,r,i,o,u,a){if(t!==i||r!==o){var c=u.push("translate(",null,n,null,e);a.push({i:c-4,x:rl(t,i)},{i:c-2,x:rl(r,o)})}else(i||o)&&u.push("translate("+i+n+o+e)}function u(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:rl(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}function a(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:rl(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}function c(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:rl(t,e)},{i:a-2,x:rl(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}return function(n,e){var r=[],i=[];return n=t(n),e=t(e),o(n.translateX,n.translateY,e.translateX,e.translateY,r,i),u(n.rotate,e.rotate,r,i),a(n.skewX,e.skewX,r,i),c(n.scaleX,n.scaleY,e.scaleX,e.scaleY,r,i),n=e=null,function(t){for(var n,e=-1,o=i.length;++e<o;)r[(n=i[e]).i]=n.x(t);return r.join("")}}}function on(t){return((t=Math.exp(t))+1/t)/2}function un(t){return((t=Math.exp(t))-1/t)/2}function an(t){return((t=Math.exp(2*t))-1)/(t+1)}function cn(t){return function(n,e){var r=t((n=Pt(n)).h,(e=Pt(e)).h),i=Kt(n.s,e.s),o=Kt(n.l,e.l),u=Kt(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function sn(t){return function(n,e){var r=t((n=jt(n)).h,(e=jt(e)).h),i=Kt(n.c,e.c),o=Kt(n.l,e.l),u=Kt(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function fn(t){return function n(e){function r(n,r){var i=t((n=$t(n)).h,(r=$t(r)).h),o=Kt(n.s,r.s),u=Kt(n.l,r.l),a=Kt(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=u(Math.pow(t,e)),n.opacity=a(t),n+""}}return e=+e,r.gamma=n,r}(1)}function ln(){return El||(zl(hn),El=Cl.now()+Al)}function hn(){El=0}function pn(){this._call=this._time=this._next=null}function dn(t,n,e){var r=new pn;return r.restart(t,n,e),r}function vn(){ln(),++Ml;for(var t,n=Vf;n;)(t=El-n._time)>=0&&n._call.call(null,t),n=n._next;--Ml}function _n(){El=(Sl=Cl.now())+Al,Ml=Tl=0;try{vn()}finally{Ml=0,gn(),El=0}}function yn(){var t=Cl.now(),n=t-Sl;n>Nl&&(Al-=n,Sl=t)}function gn(){for(var t,n,e=Vf,r=1/0;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Vf=n);Wf=t,mn(r)}function mn(t){if(!Ml){Tl&&(Tl=clearTimeout(Tl));var n=t-El;n>24?(t<1/0&&(Tl=setTimeout(_n,n)),kl&&(kl=clearInterval(kl))):(kl||(Sl=El,kl=setInterval(yn,Nl)),Ml=1,zl(_n))}}function xn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>ql)throw new Error("too late");return e}function bn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>Dl)throw new Error("too late");return e}function wn(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("too late");return e}function Mn(t,n,e){function r(c){var s,f,l,h;if(e.state!==Ul)return o();for(s in a)if((h=a[s]).name===e.name){if(h.state===Ol)return Pl(r);h.state===Fl?(h.state=Yl,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete a[s]):+s<n&&(h.state=Yl,h.timer.stop(),delete a[s])}if(Pl(function(){e.state===Ol&&(e.state=Fl,e.timer.restart(i,e.delay,e.time),i(c))}),e.state=Dl,e.on.call("start",t,t.__data__,e.index,e.group),e.state===Dl){for(e.state=Ol,u=new Array(l=e.tween.length),s=0,f=-1;s<l;++s)(h=e.tween[s].value.call(t,t.__data__,e.index,e.group))&&(u[++f]=h);u.length=f+1}}function i(n){for(var r=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(o),e.state=Il,1),i=-1,a=u.length;++i<a;)u[i].call(null,r);e.state===Il&&(e.on.call("end",t,t.__data__,e.index,e.group),o())}function o(){e.state=Yl,e.timer.stop(),delete a[n];for(var r in a)return;delete t.__transition}var u,a=t.__transition;a[n]=e,e.timer=dn(function(t){e.state=Ul,e.timer.restart(r,e.delay,e.time),e.delay<=t&&r(t-e.delay)},0,e.time)}function Tn(t,n){var e,r;return function(){var i=bn(this,t),o=i.tween;if(o!==e)for(var u=0,a=(r=e=o).length;u<a;++u)if(r[u].name===n){(r=r.slice()).splice(u,1);break}i.tween=r}}function kn(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=bn(this,t),u=o.tween;if(u!==r){i=(r=u).slice();for(var a={name:n,value:e},c=0,s=i.length;c<s;++c)if(i[c].name===n){i[c]=a;break}c===s&&i.push(a)}o.tween=i}}function Nn(t,n,e){var r=t._id;return t.each(function(){var t=bn(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return wn(t,r).value[n]}}function Sn(t){return function(){this.removeAttribute(t)}}function En(t){return function(){this.removeAttributeNS(t.space,t.local)}}function An(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}}function Cn(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}function zn(t,n,e){var r,i,o;return function(){var u,a=e(this);{if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}}}function Pn(t,n,e){var r,i,o;return function(){var u,a=e(this);{if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}}function Rn(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}function Ln(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e}function qn(t,n){return function(){xn(this,t).delay=+n.apply(this,arguments)}}function Un(t,n){return n=+n,function(){xn(this,t).delay=n}}function Dn(t,n){return function(){bn(this,t).duration=+n.apply(this,arguments)}}function On(t,n){return n=+n,function(){bn(this,t).duration=n}}function Fn(t,n){if("function"!=typeof n)throw new Error;return function(){bn(this,t).ease=n}}function In(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}function Yn(t,n,e){var r,i,o=In(n)?xn:bn;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}function Bn(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}function jn(t,n){var e,r,i;return function(){var o=B(this,t),u=(this.style.removeProperty(t),B(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}function Hn(t){return function(){this.style.removeProperty(t)}}function Xn(t,n,e){var r,i;return function(){var o=B(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}function $n(t,n,e){var r,i,o;return function(){var u=B(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=B(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}function Vn(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}function Wn(t){return function(){this.textContent=t}}function Zn(t){return function(){var n=t(this);this.textContent=null==n?"":n}}function Gn(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function Jn(t){return dt().transition(t)}function Qn(){return++$l}function Kn(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function te(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}function ne(t){return(1-Math.cos(Jl*t))/2}function ee(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function re(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}function ie(t){return(t=+t)<Kl?ch*t*t:t<nh?ch*(t-=th)*t+eh:t<ih?ch*(t-=rh)*t+oh:ch*(t-=uh)*t+ah}function oe(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return _h.time=ln(),_h;return e}function ue(){t.event.stopImmediatePropagation()}function ae(t){return{type:t}}function ce(){return!t.event.button}function se(){var t=this.ownerSVGElement||this;return[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function fe(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function le(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function he(n){function e(t){var e=t.property("__brush",a).selectAll(".overlay").data([ae("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",Eh.overlay).merge(e).each(function(){var t=fe(this).extent;cf(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([ae("selection")]).enter().append("rect").attr("class","selection").attr("cursor",Eh.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var i=t.selectAll(".handle").data(n.handles,function(t){return t.type});i.exit().remove(),i.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return Eh[t.type]}),t.each(r).attr("fill","none").attr("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush touchstart.brush",u)}function r(){var t=cf(this),n=fe(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-p/2:n[0][0]-p/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-p/2:n[0][1]-p/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+p:p}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+p:p})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function i(t,n){return t.__brush.emitter||new o(t,n)}function o(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function u(){function e(){var t=Ks(w);!L||x||b||(Math.abs(t[0]-U[0])>Math.abs(t[1]-U[1])?b=!0:x=!0),U=t,m=!0,xh(),o()}function o(){var t;switch(y=U[0]-q[0],g=U[1]-q[1],T){case wh:case bh:k&&(y=Math.max(C-a,Math.min(P-p,y)),s=a+y,d=p+y),N&&(g=Math.max(z-l,Math.min(R-v,g)),h=l+g,_=v+g);break;case Mh:k<0?(y=Math.max(C-a,Math.min(P-a,y)),s=a+y,d=p):k>0&&(y=Math.max(C-p,Math.min(P-p,y)),s=a,d=p+y),N<0?(g=Math.max(z-l,Math.min(R-l,g)),h=l+g,_=v):N>0&&(g=Math.max(z-v,Math.min(R-v,g)),h=l,_=v+g);break;case Th:k&&(s=Math.max(C,Math.min(P,a-y*k)),d=Math.max(C,Math.min(P,p+y*k))),N&&(h=Math.max(z,Math.min(R,l-g*N)),_=Math.max(z,Math.min(R,v+g*N)))}d<s&&(k*=-1,t=a,a=p,p=t,t=s,s=d,d=t,M in Ah&&F.attr("cursor",Eh[M=Ah[M]])),_<h&&(N*=-1,t=l,l=v,v=t,t=h,h=_,_=t,M in Ch&&F.attr("cursor",Eh[M=Ch[M]])),S.selection&&(A=S.selection),x&&(s=A[0][0],d=A[1][0]),b&&(h=A[0][1],_=A[1][1]),A[0][0]===s&&A[0][1]===h&&A[1][0]===d&&A[1][1]===_||(S.selection=[[s,h],[d,_]],r.call(w),D.brush())}function u(){if(ue(),t.event.touches){if(t.event.touches.length)return;c&&clearTimeout(c),c=setTimeout(function(){c=null},500),O.on("touchmove.brush touchend.brush touchcancel.brush",null)}else _t(t.event.view,m),I.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);O.attr("pointer-events","all"),F.attr("cursor",Eh.overlay),S.selection&&(A=S.selection),le(A)&&(S.selection=null,r.call(w)),D.end()}if(t.event.touches){if(t.event.changedTouches.length<t.event.touches.length)return xh()}else if(c)return;if(f.apply(this,arguments)){var a,s,l,h,p,d,v,_,y,g,m,x,b,w=this,M=t.event.target.__data__.type,T="selection"===(t.event.metaKey?M="overlay":M)?bh:t.event.altKey?Th:Mh,k=n===Nh?null:zh[M],N=n===kh?null:Ph[M],S=fe(w),E=S.extent,A=S.selection,C=E[0][0],z=E[0][1],P=E[1][0],R=E[1][1],L=k&&N&&t.event.shiftKey,q=Ks(w),U=q,D=i(w,arguments).beforestart();"overlay"===M?S.selection=A=[[a=n===Nh?C:q[0],l=n===kh?z:q[1]],[p=n===Nh?P:a,v=n===kh?R:l]]:(a=A[0][0],l=A[0][1],p=A[1][0],v=A[1][1]),s=a,h=l,d=p,_=v;var O=cf(w).attr("pointer-events","none"),F=O.selectAll(".overlay").attr("cursor",Eh[M]);if(t.event.touches)O.on("touchmove.brush",e,!0).on("touchend.brush touchcancel.brush",u,!0);else{var I=cf(t.event.view).on("keydown.brush",function(){switch(t.event.keyCode){case 16:L=k&&N;break;case 18:T===Mh&&(k&&(p=d-y*k,a=s+y*k),N&&(v=_-g*N,l=h+g*N),T=Th,o());break;case 32:T!==Mh&&T!==Th||(k<0?p=d-y:k>0&&(a=s-y),N<0?v=_-g:N>0&&(l=h-g),T=wh,F.attr("cursor",Eh.selection),o());break;default:return}xh()},!0).on("keyup.brush",function(){switch(t.event.keyCode){case 16:L&&(x=b=L=!1,o());break;case 18:T===Th&&(k<0?p=d:k>0&&(a=s),N<0?v=_:N>0&&(l=h),T=Mh,o());break;case 32:T===wh&&(t.event.altKey?(k&&(p=d-y*k,a=s+y*k),N&&(v=_-g*N,l=h+g*N),T=Th):(k<0?p=d:k>0&&(a=s),N<0?v=_:N>0&&(l=h),T=Mh),F.attr("cursor",Eh[M]),o());break;default:return}xh()},!0).on("mousemove.brush",e,!0).on("mouseup.brush",u,!0);lf(t.event.view)}ue(),jl(w),r.call(w),D.start()}}function a(){var t=this.__brush||{selection:null};return t.extent=s.apply(this,arguments),t.dim=n,t}var c,s=se,f=ce,l=h(e,"start","brush","end"),p=6;return e.move=function(t,e){t.selection?t.on("start.brush",function(){i(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){i(this,arguments).end()}).tween("brush",function(){function t(t){u.selection=1===t&&le(s)?null:f(t),r.call(o),a.brush()}var o=this,u=o.__brush,a=i(o,arguments),c=u.selection,s=n.input("function"==typeof e?e.apply(this,arguments):e,u.extent),f=cl(c,s);return c&&s?t:t(1)}):t.each(function(){var t=this,o=arguments,u=t.__brush,a=n.input("function"==typeof e?e.apply(t,o):e,u.extent),c=i(t,o).beforestart();jl(t),u.selection=null==a||le(a)?null:a,r.call(t),c.start().brush().end()})},o.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting&&(this.starting=!1,this.emit("start")),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){N(new mh(e,t,n.output(this.state.selection)),l.apply,l,[t,this.that,this.args])}},e.extent=function(t){return arguments.length?(s="function"==typeof t?t:gh([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),e):s},e.filter=function(t){return arguments.length?(f="function"==typeof t?t:gh(!!t),e):f},e.handleSize=function(t){return arguments.length?(p=+t,e):p},e.on=function(){var t=l.on.apply(l,arguments);return t===l?e:t},e}function pe(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}function de(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function ve(){return new de}function _e(t){return t.source}function ye(t){return t.target}function ge(t){return t.radius}function me(t){return t.startAngle}function xe(t){return t.endAngle}function be(){}function we(t,n){var e=new be;if(t instanceof be)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var u in t)e.set(u,t[u]);return e}function Me(){return{}}function Te(t,n,e){t[n]=e}function ke(){return we()}function Ne(t,n,e){t.set(n,e)}function Se(){}function Ee(t,n){var e=new Se;if(t instanceof Se)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}function Ae(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}")}function Ce(t,n){var e=Ae(t);return function(r,i){return n(e(r),i,t)}}function ze(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function Pe(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,u,a,c,s,f,l,h,p=t._root,d={data:r},v=t._x0,_=t._y0,y=t._x1,g=t._y1;if(!p)return t._root=d,t;for(;p.length;)if((s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u,i=p,!(p=p[l=f<<1|s]))return i[l]=d,t;if(a=+t._x.call(null,p.data),c=+t._y.call(null,p.data),n===a&&e===c)return d.next=p,i?i[l]=d:t._root=d,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u}while((l=f<<1|s)==(h=(c>=u)<<1|a>=o));return i[h]=p,i[l]=d,t}function Re(t){return t[0]}function Le(t){return t[1]}function qe(t,n,e){var r=new Ue(null==n?Re:n,null==e?Le:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ue(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function De(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}function Oe(t){return t.x+t.vx}function Fe(t){return t.y+t.vy}function Ie(t){return t.index}function Ye(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function Be(t){return t.x}function je(t){return t.y}function He(t){return new Xe(t)}function Xe(t){if(!(n=vp.exec(t)))throw new Error("invalid format: "+t);var n,e=n[1]||" ",r=n[2]||">",i=n[3]||"-",o=n[4]||"",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],s=n[8]&&+n[8].slice(1),f=n[9]||"";"n"===f?(c=!0,f="g"):dp[f]||(f=""),(u||"0"===e&&"="===r)&&(u=!0,e="0",r="="),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=s,this.type=f}function $e(n){return _p=mp(n),t.format=_p.format,t.formatPrefix=_p.formatPrefix,_p}function Ve(){this.reset()}function We(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}function Ze(t){return t>1?0:t<-1?rd:Math.acos(t)}function Ge(t){return t>1?id:t<-1?-id:Math.asin(t)}function Je(t){return(t=yd(t/2))*t}function Qe(){}function Ke(t,n){t&&wd.hasOwnProperty(t.type)&&wd[t.type](t,n)}function tr(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function nr(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)tr(t[e],n,1);n.polygonEnd()}function er(){Nd.point=ir}function rr(){or(Tp,kp)}function ir(t,n){Nd.point=or,Tp=t,kp=n,Np=t*=cd,Sp=hd(n=(n*=cd)/2+od),Ep=yd(n)}function or(t,n){n=(n*=cd)/2+od;var e=(t*=cd)-Np,r=e>=0?1:-1,i=r*e,o=hd(n),u=yd(n),a=Ep*u,c=Sp*o+a*hd(i),s=a*r*yd(i);Td.add(ld(s,c)),Np=t,Sp=o,Ep=u}function ur(t){return[ld(t[1],t[0]),Ge(t[2])]}function ar(t){var n=t[0],e=t[1],r=hd(e);return[r*hd(n),r*yd(n),yd(e)]}function cr(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function sr(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function fr(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function lr(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function hr(t){var n=md(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}function pr(t,n){Dp.push(Op=[Ap=t,zp=t]),n<Cp&&(Cp=n),n>Pp&&(Pp=n)}function dr(t,n){var e=ar([t*cd,n*cd]);if(Up){var r=sr(Up,e),i=sr([r[1],-r[0],0],r);hr(i),i=ur(i);var o,u=t-Rp,a=u>0?1:-1,c=i[0]*ad*a,s=sd(u)>180;s^(a*Rp<c&&c<a*t)?(o=i[1]*ad)>Pp&&(Pp=o):(c=(c+360)%360-180,s^(a*Rp<c&&c<a*t)?(o=-i[1]*ad)<Cp&&(Cp=o):(n<Cp&&(Cp=n),n>Pp&&(Pp=n))),s?t<Rp?xr(Ap,t)>xr(Ap,zp)&&(zp=t):xr(t,zp)>xr(Ap,zp)&&(Ap=t):zp>=Ap?(t<Ap&&(Ap=t),t>zp&&(zp=t)):t>Rp?xr(Ap,t)>xr(Ap,zp)&&(zp=t):xr(t,zp)>xr(Ap,zp)&&(Ap=t)}else Dp.push(Op=[Ap=t,zp=t]);n<Cp&&(Cp=n),n>Pp&&(Pp=n),Up=e,Rp=t}function vr(){Ed.point=dr}function _r(){Op[0]=Ap,Op[1]=zp,Ed.point=pr,Up=null}function yr(t,n){if(Up){var e=t-Rp;Sd.add(sd(e)>180?e+(e>0?360:-360):e)}else Lp=t,qp=n;Nd.point(t,n),dr(t,n)}function gr(){Nd.lineStart()}function mr(){yr(Lp,qp),Nd.lineEnd(),sd(Sd)>ed&&(Ap=-(zp=180)),Op[0]=Ap,Op[1]=zp,Up=null}function xr(t,n){return(n-=t)<0?n+360:n}function br(t,n){return t[0]-n[0]}function wr(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}function Mr(t,n){t*=cd;var e=hd(n*=cd);Tr(e*hd(t),e*yd(t),yd(n))}function Tr(t,n,e){Yp+=(t-Yp)/++Fp,Bp+=(n-Bp)/Fp,jp+=(e-jp)/Fp}function kr(){Ad.point=Nr}function Nr(t,n){t*=cd;var e=hd(n*=cd);Qp=e*hd(t),Kp=e*yd(t),td=yd(n),Ad.point=Sr,Tr(Qp,Kp,td)}function Sr(t,n){t*=cd;var e=hd(n*=cd),r=e*hd(t),i=e*yd(t),o=yd(n),u=ld(md((u=Kp*o-td*i)*u+(u=td*r-Qp*o)*u+(u=Qp*i-Kp*r)*u),Qp*r+Kp*i+td*o);Ip+=u,Hp+=u*(Qp+(Qp=r)),Xp+=u*(Kp+(Kp=i)),$p+=u*(td+(td=o)),Tr(Qp,Kp,td)}function Er(){Ad.point=Mr}function Ar(){Ad.point=zr}function Cr(){Pr(Gp,Jp),Ad.point=Mr}function zr(t,n){Gp=t,Jp=n,t*=cd,n*=cd,Ad.point=Pr;var e=hd(n);Qp=e*hd(t),Kp=e*yd(t),td=yd(n),Tr(Qp,Kp,td)}function Pr(t,n){t*=cd;var e=hd(n*=cd),r=e*hd(t),i=e*yd(t),o=yd(n),u=Kp*o-td*i,a=td*r-Qp*o,c=Qp*i-Kp*r,s=md(u*u+a*a+c*c),f=Ge(s),l=s&&-f/s;Vp+=l*u,Wp+=l*a,Zp+=l*c,Ip+=f,Hp+=f*(Qp+(Qp=r)),Xp+=f*(Kp+(Kp=i)),$p+=f*(td+(td=o)),Tr(Qp,Kp,td)}function Rr(t,n){return[t>rd?t-ud:t<-rd?t+ud:t,n]}function Lr(t,n,e){return(t%=ud)?n||e?zd(Ur(t),Dr(n,e)):Ur(t):n||e?Dr(n,e):Rr}function qr(t){return function(n,e){return n+=t,[n>rd?n-ud:n<-rd?n+ud:n,e]}}function Ur(t){var n=qr(t);return n.invert=qr(-t),n}function Dr(t,n){function e(t,n){var e=hd(n),a=hd(t)*e,c=yd(t)*e,s=yd(n),f=s*r+a*i;return[ld(c*o-f*u,a*r-s*i),Ge(f*o+c*u)]}var r=hd(t),i=yd(t),o=hd(n),u=yd(n);return e.invert=function(t,n){var e=hd(n),a=hd(t)*e,c=yd(t)*e,s=yd(n),f=s*o-c*u;return[ld(c*o+s*u,a*r+f*i),Ge(f*r-a*i)]},e}function Or(t,n,e,r,i,o){if(e){var u=hd(n),a=yd(n),c=r*e;null==i?(i=n+r*ud,o=n-c/2):(i=Fr(u,i),o=Fr(u,o),(r>0?i<o:i>o)&&(i+=r*ud));for(var s,f=i;r>0?f>o:f<o;f-=c)s=ur([u,-a*hd(f),-a*yd(f)]),t.point(s[0],s[1])}}function Fr(t,n){(n=ar(n))[0]-=t,hr(n);var e=Ze(-n[1]);return((-n[2]<0?-e:e)+ud-ed)%ud}function Ir(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Yr(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function Br(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,a,s){var f=0,l=0;if(null==i||(f=u(i,a))!==(l=u(o,a))||c(i,o)<0^a>0)do{s.point(0===f||3===f?t:e,f>1?r:n)}while((f=(f+a+4)%4)!==l);else s.point(o[0],o[1])}function u(r,i){return sd(r[0]-t)<ed?i>0?0:3:sd(r[0]-e)<ed?i>0?2:1:sd(r[1]-n)<ed?i>0?1:0:i>0?3:2}function a(t,n){return c(t.x,n.x)}function c(t,n){var e=u(t,1),r=u(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){function c(t,n){i(t,n)&&w.point(t,n)}function s(){for(var n=0,e=0,i=h.length;e<i;++e)for(var o,u,a=h[e],c=1,s=a.length,f=a[0],l=f[0],p=f[1];c<s;++c)o=l,u=p,l=(f=a[c])[0],p=f[1],u<=r?p>r&&(l-o)*(r-u)>(p-u)*(t-o)&&++n:p<=r&&(l-o)*(r-u)<(p-u)*(t-o)&&--n;return n}function f(o,u){var a=i(o,u);if(h&&p.push([o,u]),x)d=o,v=u,_=a,x=!1,a&&(w.lineStart(),w.point(o,u));else if(a&&m)w.point(o,u);else{var c=[y=Math.max(Zd,Math.min(Wd,y)),g=Math.max(Zd,Math.min(Wd,g))],s=[o=Math.max(Zd,Math.min(Wd,o)),u=Math.max(Zd,Math.min(Wd,u))];Xd(c,s,t,n,e,r)?(m||(w.lineStart(),w.point(c[0],c[1])),w.point(s[0],s[1]),a||w.lineEnd(),b=!1):a&&(w.lineStart(),w.point(o,u),b=!1)}y=o,g=u,m=a}var l,h,p,d,v,_,y,g,m,x,b,w=u,M=Hd(),T={point:c,lineStart:function(){T.point=f,h&&h.push(p=[]),x=!0,m=!1,y=g=NaN},lineEnd:function(){l&&(f(d,v),_&&m&&M.rejoin(),l.push(M.result())),T.point=c,m&&w.lineEnd()},polygonStart:function(){w=M,l=[],h=[],b=!0},polygonEnd:function(){var t=s(),n=b&&t,e=(l=Cs(l)).length;(n||e)&&(u.polygonStart(),n&&(u.lineStart(),o(null,null,1,u),u.lineEnd()),e&&Vd(l,a,t,o,u),u.polygonEnd()),w=u,l=h=p=null}};return T}}function jr(){Kd.point=Kd.lineEnd=Qe}function Hr(t,n){Pd=t*=cd,Rd=yd(n*=cd),Ld=hd(n),Kd.point=Xr}function Xr(t,n){t*=cd;var e=yd(n*=cd),r=hd(n),i=sd(t-Pd),o=hd(i),u=r*yd(i),a=Ld*e-Rd*r*o,c=Rd*e+Ld*r*o;Qd.add(ld(md(u*u+a*a),c)),Pd=t,Rd=e,Ld=r}function $r(t,n){return!(!t||!ov.hasOwnProperty(t.type))&&ov[t.type](t,n)}function Vr(t,n){return 0===rv(t,n)}function Wr(t,n){var e=rv(t[0],t[1]);return rv(t[0],n)+rv(n,t[1])<=e+ed}function Zr(t,n){return!!Jd(t.map(Gr),Jr(n))}function Gr(t){return(t=t.map(Jr)).pop(),t}function Jr(t){return[t[0]*cd,t[1]*cd]}function Qr(t,n,e){var r=Ms(t,n-ed,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function Kr(t,n,e){var r=Ms(t,n-ed,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function ti(){function t(){return{type:"MultiLineString",coordinates:n()}}function n(){return Ms(pd(o/_)*_,i,_).map(h).concat(Ms(pd(s/y)*y,c,y).map(p)).concat(Ms(pd(r/d)*d,e,d).filter(function(t){return sd(t%_)>ed}).map(f)).concat(Ms(pd(a/v)*v,u,v).filter(function(t){return sd(t%y)>ed}).map(l))}var e,r,i,o,u,a,c,s,f,l,h,p,d=10,v=d,_=90,y=360,g=2.5;return t.lines=function(){return n().map(function(t){return{type:"LineString",coordinates:t}})},t.outline=function(){return{type:"Polygon",coordinates:[h(o).concat(p(c).slice(1),h(i).reverse().slice(1),p(s).reverse().slice(1))]}},t.extent=function(n){return arguments.length?t.extentMajor(n).extentMinor(n):t.extentMinor()},t.extentMajor=function(n){return arguments.length?(o=+n[0][0],i=+n[1][0],s=+n[0][1],c=+n[1][1],o>i&&(n=o,o=i,i=n),s>c&&(n=s,s=c,c=n),t.precision(g)):[[o,s],[i,c]]},t.extentMinor=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],a=+n[0][1],u=+n[1][1],r>e&&(n=r,r=e,e=n),a>u&&(n=a,a=u,u=n),t.precision(g)):[[r,a],[e,u]]},t.step=function(n){return arguments.length?t.stepMajor(n).stepMinor(n):t.stepMinor()},t.stepMajor=function(n){return arguments.length?(_=+n[0],y=+n[1],t):[_,y]},t.stepMinor=function(n){return arguments.length?(d=+n[0],v=+n[1],t):[d,v]},t.precision=function(n){return arguments.length?(g=+n,f=Qr(a,u,90),l=Kr(r,e,g),h=Qr(s,c,90),p=Kr(o,i,g),t):g},t.extentMajor([[-180,-90+ed],[180,90-ed]]).extentMinor([[-180,-80-ed],[180,80+ed]])}function ni(){sv.point=ei}function ei(t,n){sv.point=ri,qd=Dd=t,Ud=Od=n}function ri(t,n){cv.add(Od*t-Dd*n),Dd=t,Od=n}function ii(){ri(qd,Ud)}function oi(t,n){vv+=t,_v+=n,++yv}function ui(){Tv.point=ai}function ai(t,n){Tv.point=ci,oi(Yd=t,Bd=n)}function ci(t,n){var e=t-Yd,r=n-Bd,i=md(e*e+r*r);gv+=i*(Yd+t)/2,mv+=i*(Bd+n)/2,xv+=i,oi(Yd=t,Bd=n)}function si(){Tv.point=oi}function fi(){Tv.point=hi}function li(){pi(Fd,Id)}function hi(t,n){Tv.point=pi,oi(Fd=Yd=t,Id=Bd=n)}function pi(t,n){var e=t-Yd,r=n-Bd,i=md(e*e+r*r);gv+=i*(Yd+t)/2,mv+=i*(Bd+n)/2,xv+=i,bv+=(i=Bd*t-Yd*n)*(Yd+t),wv+=i*(Bd+n),Mv+=3*i,oi(Yd=t,Bd=n)}function di(t){this._context=t}function vi(t,n){zv.point=_i,Nv=Ev=t,Sv=Av=n}function _i(t,n){Ev-=t,Av-=n,Cv.add(md(Ev*Ev+Av*Av)),Ev=t,Av=n}function yi(){this._string=[]}function gi(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function mi(t){return t.length>1}function xi(t,n){return((t=t.x)[0]<0?t[1]-id-ed:id-t[1])-((n=n.x)[0]<0?n[1]-id-ed:id-n[1])}function bi(t,n,e,r){var i,o,u=yd(t-e);return sd(u)>ed?fd((yd(n)*(o=hd(r))*yd(e)-yd(r)*(i=hd(n))*yd(t))/(i*o*u)):(n+r)/2}function wi(t){return function(n){var e=new Mi;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Mi(){}function Ti(t,n,e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=t.clipExtent&&t.clipExtent();t.scale(150).translate([0,0]),null!=o&&t.clipExtent(null),Md(e,t.stream(dv));var u=dv.result(),a=Math.min(r/(u[1][0]-u[0][0]),i/(u[1][1]-u[0][1])),c=+n[0][0]+(r-a*(u[1][0]+u[0][0]))/2,s=+n[0][1]+(i-a*(u[1][1]+u[0][1]))/2;return null!=o&&t.clipExtent(o),t.scale(150*a).translate([c,s])}function ki(t,n,e){return Ti(t,[[0,0],n],e)}function Ni(t){return wi({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}function Si(t,n){function e(r,i,o,u,a,c,s,f,l,h,p,d,v,_){var y=s-r,g=f-i,m=y*y+g*g;if(m>4*n&&v--){var x=u+h,b=a+p,w=c+d,M=md(x*x+b*b+w*w),T=Ge(w/=M),k=sd(sd(w)-1)<ed||sd(o-l)<ed?(o+l)/2:ld(b,x),N=t(k,T),S=N[0],E=N[1],A=S-r,C=E-i,z=g*A-y*C;(z*z/m>n||sd((y*A+g*C)/m-.5)>.3||u*h+a*p+c*d<Uv)&&(e(r,i,o,u,a,c,S,E,k,x/=M,b/=M,w,v,_),_.point(S,E),e(S,E,k,x,b,w,s,f,l,h,p,d,v,_))}}return function(n){function r(e,r){e=t(e,r),n.point(e[0],e[1])}function i(){y=NaN,w.point=o,n.lineStart()}function o(r,i){var o=ar([r,i]),u=t(r,i);e(y,g,_,m,x,b,y=u[0],g=u[1],_=r,m=o[0],x=o[1],b=o[2],qv,n),n.point(y,g)}function u(){w.point=r,n.lineEnd()}function a(){i(),w.point=c,w.lineEnd=s}function c(t,n){o(f=t,n),l=y,h=g,p=m,d=x,v=b,w.point=o}function s(){e(y,g,_,m,x,b,l,h,f,p,d,v,qv,n),w.lineEnd=u,u()}var f,l,h,p,d,v,_,y,g,m,x,b,w={point:r,lineStart:i,lineEnd:u,polygonStart:function(){n.polygonStart(),w.lineStart=a},polygonEnd:function(){n.polygonEnd(),w.lineStart=i}};return w}}function Ei(t){return Ai(function(){return t})()}function Ai(t){function n(t){return t=f(t[0]*cd,t[1]*cd),[t[0]*_+a,c-t[1]*_]}function e(t){return(t=f.invert((t[0]-a)/_,(c-t[1])/_))&&[t[0]*ad,t[1]*ad]}function r(t,n){return t=u(t,n),[t[0]*_+a,c-t[1]*_]}function i(){f=zd(s=Lr(b,w,M),u);var t=u(m,x);return a=y-t[0]*_,c=g+t[1]*_,o()}function o(){return d=v=null,n}var u,a,c,s,f,l,h,p,d,v,_=150,y=480,g=250,m=0,x=0,b=0,w=0,M=0,T=null,k=Rv,N=null,S=uv,E=.5,A=Dv(r,E);return n.stream=function(t){return d&&v===t?d:d=Ov(k(s,A(S(v=t))))},n.clipAngle=function(t){return arguments.length?(k=+t?Lv(T=t*cd,6*cd):(T=null,Rv),o()):T*ad},n.clipExtent=function(t){return arguments.length?(S=null==t?(N=l=h=p=null,uv):Br(N=+t[0][0],l=+t[0][1],h=+t[1][0],p=+t[1][1]),o()):null==N?null:[[N,l],[h,p]]},n.scale=function(t){return arguments.length?(_=+t,i()):_},n.translate=function(t){return arguments.length?(y=+t[0],g=+t[1],i()):[y,g]},n.center=function(t){return arguments.length?(m=t[0]%360*cd,x=t[1]%360*cd,i()):[m*ad,x*ad]},n.rotate=function(t){return arguments.length?(b=t[0]%360*cd,w=t[1]%360*cd,M=t.length>2?t[2]%360*cd:0,i()):[b*ad,w*ad,M*ad]},n.precision=function(t){return arguments.length?(A=Dv(r,E=t*t),o()):md(E)},n.fitExtent=function(t,e){return Ti(n,t,e)},n.fitSize=function(t,e){return ki(n,t,e)},function(){return u=t.apply(this,arguments),n.invert=u.invert&&e,i()}}function Ci(t){var n=0,e=rd/3,r=Ai(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*cd,e=t[1]*cd):[n*ad,e*ad]},i}function zi(t){function n(t,n){return[t*e,yd(n)/e]}var e=hd(t);return n.invert=function(t,n){return[t/e,Ge(n*e)]},n}function Pi(t,n){function e(t,n){var e=md(o-2*i*yd(n))/i;return[e*yd(t*=i),u-e*hd(t)]}var r=yd(t),i=(r+yd(n))/2;if(sd(i)<ed)return zi(t);var o=1+r*(2*i-r),u=md(o)/i;return e.invert=function(t,n){var e=u-n;return[ld(t,sd(e))/i*gd(e),Ge((o-(t*t+e*e)*i*i)/(2*i))]},e}function Ri(t){var n=t.length;return{point:function(e,r){for(var i=-1;++i<n;)t[i].point(e,r)},sphere:function(){for(var e=-1;++e<n;)t[e].sphere()},lineStart:function(){for(var e=-1;++e<n;)t[e].lineStart()},lineEnd:function(){for(var e=-1;++e<n;)t[e].lineEnd()},polygonStart:function(){for(var e=-1;++e<n;)t[e].polygonStart()},polygonEnd:function(){for(var e=-1;++e<n;)t[e].polygonEnd()}}}function Li(t){return function(n,e){var r=hd(n),i=hd(e),o=t(r*i);return[o*i*yd(n),o*yd(e)]}}function qi(t){return function(n,e){var r=md(n*n+e*e),i=t(r),o=yd(i),u=hd(i);return[ld(n*o,r*u),Ge(r&&e*o/r)]}}function Ui(t,n){return[t,vd(xd((id+n)/2))]}function Di(t){function n(){var n=rd*a(),u=o(jd(o.rotate()).invert([0,0]));return s(null==f?[[u[0]-n,u[1]-n],[u[0]+n,u[1]+n]]:t===Ui?[[Math.max(u[0]-n,f),e],[Math.min(u[0]+n,r),i]]:[[f,Math.max(u[1]-n,e)],[r,Math.min(u[1]+n,i)]])}var e,r,i,o=Ei(t),u=o.center,a=o.scale,c=o.translate,s=o.clipExtent,f=null;return o.scale=function(t){return arguments.length?(a(t),n()):a()},o.translate=function(t){return arguments.length?(c(t),n()):c()},o.center=function(t){return arguments.length?(u(t),n()):u()},o.clipExtent=function(t){return arguments.length?(null==t?f=e=r=i=null:(f=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),n()):null==f?null:[[f,e],[r,i]]},n()}function Oi(t){return xd((id+t)/2)}function Fi(t,n){function e(t,n){o>0?n<-id+ed&&(n=-id+ed):n>id-ed&&(n=id-ed);var e=o/_d(Oi(n),i);return[e*yd(i*t),o-e*hd(i*t)]}var r=hd(t),i=t===n?yd(t):vd(r/hd(n))/vd(Oi(n)/Oi(t)),o=r*_d(Oi(t),i)/i;return i?(e.invert=function(t,n){var e=o-n,r=gd(i)*md(t*t+e*e);return[ld(t,sd(e))/i*gd(e),2*fd(_d(o/r,1/i))-id]},e):Ui}function Ii(t,n){return[t,n]}function Yi(t,n){function e(t,n){var e=o-n,r=i*t;return[e*yd(r),o-e*hd(r)]}var r=hd(t),i=t===n?yd(t):(r-hd(n))/(n-t),o=r/i+t;return sd(i)<ed?Ii:(e.invert=function(t,n){var e=o-n;return[ld(t,sd(e))/i*gd(e),o-gd(i)*md(t*t+e*e)]},e)}function Bi(t,n){var e=hd(n),r=hd(t)*e;return[e*yd(t)/r,yd(n)/r]}function ji(t,n,e,r){return 1===t&&1===n&&0===e&&0===r?uv:wi({point:function(i,o){this.stream.point(i*t+e,o*n+r)}})}function Hi(t,n){return[hd(n)*yd(t),yd(n)]}function Xi(t,n){var e=hd(n),r=1+hd(t)*e;return[e*yd(t)/r,yd(n)/r]}function $i(t,n){return[vd(xd((id+n)/2)),-t]}function Vi(t,n){return t.parent===n.parent?1:2}function Wi(t){return t.reduce(Zi,0)/t.length}function Zi(t,n){return t+n.x}function Gi(t){return 1+t.reduce(Ji,0)}function Ji(t,n){return Math.max(t,n.y)}function Qi(t){for(var n;n=t.children;)t=n[0];return t}function Ki(t){for(var n;n=t.children;)t=n[n.length-1];return t}function to(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function no(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}function eo(t,n){var e,r,i,o,u,a=new uo(t),c=+t.value&&(a.value=t.value),s=[a];for(null==n&&(n=ro);e=s.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(u=i.length))for(e.children=new Array(u),o=u-1;o>=0;--o)s.push(r=e.children[o]=new uo(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(oo)}function ro(t){return t.children}function io(t){t.data=t.data.data}function oo(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function uo(t){this.data=t,this.depth=this.height=0,this.parent=null}function ao(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}function co(t,n){var e,r;if(lo(n,t))return[n];for(e=0;e<t.length;++e)if(so(n,t[e])&&lo(vo(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(so(vo(t[e],t[r]),n)&&so(vo(t[e],n),t[r])&&so(vo(t[r],n),t[e])&&lo(_o(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function so(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function fo(t,n){var e=t.r-n.r+1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function lo(t,n){for(var e=0;e<n.length;++e)if(!fo(t,n[e]))return!1;return!0}function ho(t){switch(t.length){case 1:return po(t[0]);case 2:return vo(t[0],t[1]);case 3:return _o(t[0],t[1],t[2])}}function po(t){return{x:t.x,y:t.y,r:t.r}}function vo(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,u=n.y,a=n.r,c=o-e,s=u-r,f=a-i,l=Math.sqrt(c*c+s*s);return{x:(e+o+c/l*f)/2,y:(r+u+s/l*f)/2,r:(l+i+a)/2}}function _o(t,n,e){var r=t.x,i=t.y,o=t.r,u=n.x,a=n.y,c=n.r,s=e.x,f=e.y,l=e.r,h=r-u,p=r-s,d=i-a,v=i-f,_=c-o,y=l-o,g=r*r+i*i-o*o,m=g-u*u-a*a+c*c,x=g-s*s-f*f+l*l,b=p*d-h*v,w=(d*x-v*m)/(2*b)-r,M=(v*_-d*y)/b,T=(p*m-h*x)/(2*b)-i,k=(h*y-p*_)/b,N=M*M+k*k-1,S=2*(o+w*M+T*k),E=w*w+T*T-o*o,A=-(N?(S+Math.sqrt(S*S-4*N*E))/(2*N):E/S);return{x:r+w+M*A,y:i+T+k*A,r:A}}function yo(t,n,e){var r=t.x,i=t.y,o=n.r+e.r,u=t.r+e.r,a=n.x-r,c=n.y-i,s=a*a+c*c;if(s){var f=.5+((u*=u)-(o*=o))/(2*s),l=Math.sqrt(Math.max(0,2*o*(u+s)-(u-=s)*u-o*o))/(2*s);e.x=r+f*a+l*c,e.y=i+f*c-l*a}else e.x=r+u,e.y=i}function go(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return i*i-1e-6>e*e+r*r}function mo(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function xo(t){this._=t,this.next=null,this.previous=null}function bo(t){if(!(i=t.length))return 0;var n,e,r,i,o,u,a,c,s,f,l;if(n=t[0],n.x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;yo(e,n,r=t[2]),n=new xo(n),e=new xo(e),r=new xo(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(a=3;a<i;++a){yo(n._,e._,r=t[a]),r=new xo(r),c=e.next,s=n.previous,f=e._.r,l=n._.r;do{if(f<=l){if(go(c._,r._)){e=c,n.next=e,e.previous=n,--a;continue t}f+=c._.r,c=c.next}else{if(go(s._,r._)){(n=s).next=e,e.previous=n,--a;continue t}l+=s._.r,s=s.previous}}while(c!==s.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=mo(n);(r=r.next)!==e;)(u=mo(r))<o&&(n=r,o=u);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Hv(n),a=0;a<i;++a)n=t[a],n.x-=r.x,n.y-=r.y;return r.r}function wo(t){return null==t?null:Mo(t)}function Mo(t){if("function"!=typeof t)throw new Error;return t}function To(){return 0}function ko(t){return Math.sqrt(t.value)}function No(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function So(t,n){return function(e){if(r=e.children){var r,i,o,u=r.length,a=t(e)*n||0;if(a)for(i=0;i<u;++i)r[i].r+=a;if(o=bo(r),a)for(i=0;i<u;++i)r[i].r-=a;e.r=o+a}}}function Eo(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Ao(t){return t.id}function Co(t){return t.parentId}function zo(t,n){return t.parent===n.parent?1:2}function Po(t){var n=t.children;return n?n[0]:t.t}function Ro(t){var n=t.children;return n?n[n.length-1]:t.t}function Lo(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function qo(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}function Uo(t,n,e){return t.a.parent===n.parent?t.a:e}function Do(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Oo(t){for(var n,e,r,i,o,u=new Do(t,0),a=[u];n=a.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)a.push(e=n.children[i]=new Do(r[i],i)),e.parent=n;return(u.parent=new Do(null,0)).children=[u],u}function Fo(t,n,e,r,i,o){for(var u,a,c,s,f,l,h,p,d,v,_,y=[],g=n.children,m=0,x=0,b=g.length,w=n.value;m<b;){c=i-e,s=o-r;do{f=g[x++].value}while(!f&&x<b);for(l=h=f,_=f*f*(v=Math.max(s/c,c/s)/(w*t)),d=Math.max(h/_,_/l);x<b;++x){if(f+=a=g[x].value,a<l&&(l=a),a>h&&(h=a),_=f*f*v,(p=Math.max(h/_,_/l))>d){f-=a;break}d=p}y.push(u={value:f,dice:c<s,children:g.slice(m,x)}),u.dice?Vv(u,e,r,i,w?r+=s*f/w:o):Jv(u,e,r,w?e+=c*f/w:i,o),w-=f,m=x}return y}function Io(t,n){return t[0]-n[0]||t[1]-n[1]}function Yo(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&n_(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function Bo(t){this._size=t,this._call=this._error=null,this._tasks=[],this._data=[],this._waiting=this._active=this._ended=this._start=0}function jo(t){if(!t._start)try{Ho(t)}catch(n){if(t._tasks[t._ended+t._active-1])$o(t,n);else if(!t._data)throw n}}function Ho(t){for(;t._start=t._waiting&&t._active<t._size;){var n=t._ended+t._active,e=t._tasks[n],r=e.length-1,i=e[r];e[r]=Xo(t,n),--t._waiting,++t._active,e=i.apply(null,e),t._tasks[n]&&(t._tasks[n]=e||r_)}}function Xo(t,n){return function(e,r){t._tasks[n]&&(--t._active,++t._ended,t._tasks[n]=null,null==t._error&&(null!=e?$o(t,e):(t._data[n]=r,t._waiting?jo(t):Vo(t))))}}function $o(t,n){var e,r=t._tasks.length;for(t._error=n,t._data=void 0,t._waiting=NaN;--r>=0;)if((e=t._tasks[r])&&(t._tasks[r]=null,e.abort))try{e.abort()}catch(n){}t._active=NaN,Vo(t)}function Vo(t){if(!t._active&&t._call){var n=t._data;t._data=void 0,t._call(t._error,n)}}function Wo(t){if(null==t)t=1/0;else if(!((t=+t)>=1))throw new Error("invalid concurrency");return new Bo(t)}function Zo(t){return function(n,e){t(null==n?e:null)}}function Go(t){var n=t.responseType;return n&&"text"!==n?t.response:t.responseText}function Jo(t,n){return function(e){return t(e.responseText,n)}}function Qo(t){function n(n){var o=n+"",u=e.get(o);if(!u){if(i!==M_)return i;e.set(o,u=r.push(n))}return t[(u-1)%t.length]}var e=we(),r=[],i=M_;return t=null==t?[]:w_.call(t),n.domain=function(t){if(!arguments.length)return r.slice();r=[],e=we();for(var i,o,u=-1,a=t.length;++u<a;)e.has(o=(i=t[u])+"")||e.set(o,r.push(i));return n},n.range=function(e){return arguments.length?(t=w_.call(e),n):t.slice()},n.unknown=function(t){return arguments.length?(i=t,n):i},n.copy=function(){return Qo().domain(r).range(t).unknown(i)},n}function Ko(){function t(){var t=i().length,r=u[1]<u[0],l=u[r-0],h=u[1-r];n=(h-l)/Math.max(1,t-c+2*s),a&&(n=Math.floor(n)),l+=(h-l-n*(t-c))*f,e=n*(1-c),a&&(l=Math.round(l),e=Math.round(e));var p=Ms(t).map(function(t){return l+n*t});return o(r?p.reverse():p)}var n,e,r=Qo().unknown(void 0),i=r.domain,o=r.range,u=[0,1],a=!1,c=0,s=0,f=.5;return delete r.unknown,r.domain=function(n){return arguments.length?(i(n),t()):i()},r.range=function(n){return arguments.length?(u=[+n[0],+n[1]],t()):u.slice()},r.rangeRound=function(n){return u=[+n[0],+n[1]],a=!0,t()},r.bandwidth=function(){return e},r.step=function(){return n},r.round=function(n){return arguments.length?(a=!!n,t()):a},r.padding=function(n){return arguments.length?(c=s=Math.max(0,Math.min(1,n)),t()):c},r.paddingInner=function(n){return arguments.length?(c=Math.max(0,Math.min(1,n)),t()):c},r.paddingOuter=function(n){return arguments.length?(s=Math.max(0,Math.min(1,n)),t()):s},r.align=function(n){return arguments.length?(f=Math.max(0,Math.min(1,n)),t()):f},r.copy=function(){return Ko().domain(i()).range(u).round(a).paddingInner(c).paddingOuter(s).align(f)},t()}function tu(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return tu(n())},t}function nu(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:T_(n)}function eu(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}function ru(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}function iu(t,n,e,r){var i=t[0],o=t[1],u=n[0],a=n[1];return o<i?(i=e(o,i),u=r(a,u)):(i=e(i,o),u=r(u,a)),function(t){return u(i(t))}}function ou(t,n,e,r){var i=Math.min(t.length,n.length)-1,o=new Array(i),u=new Array(i),a=-1;for(t[i]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<i;)o[a]=e(t[a],t[a+1]),u[a]=r(n[a],n[a+1]);return function(n){var e=hs(t,n,1,i)-1;return u[e](o[e](n))}}function uu(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp())}function au(t,n){function e(){return i=Math.min(a.length,c.length)>2?ou:iu,o=u=null,r}function r(n){return(o||(o=i(a,c,f?eu(t):t,s)))(+n)}var i,o,u,a=N_,c=N_,s=cl,f=!1;return r.invert=function(t){return(u||(u=i(c,a,nu,f?ru(n):n)))(+t)},r.domain=function(t){return arguments.length?(a=b_.call(t,k_),e()):a.slice()},r.range=function(t){return arguments.length?(c=w_.call(t),e()):c.slice()},r.rangeRound=function(t){return c=w_.call(t),s=sl,e()},r.clamp=function(t){return arguments.length?(f=!!t,e()):f},r.interpolate=function(t){return arguments.length?(s=t,e()):s},e()}function cu(t){var n=t.domain;return t.ticks=function(t){var e=n();return Ss(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){return S_(n(),t,e)},t.nice=function(e){null==e&&(e=10);var i,o=n(),u=0,a=o.length-1,c=o[u],s=o[a];return s<c&&(i=c,c=s,s=i,i=u,u=a,a=i),(i=r(c,s,e))>0?i=r(c=Math.floor(c/i)*i,s=Math.ceil(s/i)*i,e):i<0&&(i=r(c=Math.ceil(c*i)/i,s=Math.floor(s*i)/i,e)),i>0?(o[u]=Math.floor(c/i)*i,o[a]=Math.ceil(s/i)*i,n(o)):i<0&&(o[u]=Math.ceil(c*i)/i,o[a]=Math.floor(s*i)/i,n(o)),t},t}function su(){var t=au(nu,rl);return t.copy=function(){return uu(t,su())},cu(t)}function fu(){function t(t){return+t}var n=[0,1];return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=b_.call(e,k_),t):n.slice()},t.copy=function(){return fu().domain(n)},cu(t)}function lu(t,n){return(n=Math.log(n/t))?function(e){return Math.log(e/t)/n}:T_(n)}function hu(t,n){return t<0?function(e){return-Math.pow(-n,e)*Math.pow(-t,1-e)}:function(e){return Math.pow(n,e)*Math.pow(t,1-e)}}function pu(t){return isFinite(t)?+("1e"+t):t<0?0:t}function du(t){return 10===t?pu:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}function vu(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}function _u(t){return function(n){return-t(-n)}}function yu(){function n(){return o=vu(i),u=du(i),r()[0]<0&&(o=_u(o),u=_u(u)),e}var e=au(lu,hu).domain([1,10]),r=e.domain,i=10,o=vu(10),u=du(10);return e.base=function(t){return arguments.length?(i=+t,n()):i},e.domain=function(t){return arguments.length?(r(t),n()):r()},e.ticks=function(t){var n,e=r(),a=e[0],c=e[e.length-1];(n=c<a)&&(h=a,a=c,c=h);var s,f,l,h=o(a),p=o(c),d=null==t?10:+t,v=[];if(!(i%1)&&p-h<d){if(h=Math.round(h)-1,p=Math.round(p)+1,a>0){for(;h<p;++h)for(f=1,s=u(h);f<i;++f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else for(;h<p;++h)for(f=i-1,s=u(h);f>=1;--f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else v=Ss(h,p,Math.min(p-h,d)).map(u);return n?v.reverse():v},e.tickFormat=function(n,r){if(null==r&&(r=10===i?".0e":","),"function"!=typeof r&&(r=t.format(r)),n===1/0)return r;null==n&&(n=10);var a=Math.max(1,i*n/e.ticks().length);return function(t){var n=t/u(Math.round(o(t)));return n*i<i-.5&&(n*=i),n<=a?r(t):""}},e.nice=function(){return r(E_(r(),{floor:function(t){return u(Math.floor(o(t)))},ceil:function(t){return u(Math.ceil(o(t)))}}))},e.copy=function(){return uu(e,yu().base(i))},e}function gu(t,n){return t<0?-Math.pow(-t,n):Math.pow(t,n)}function mu(){var t=1,n=au(function(n,e){return(e=gu(e,t)-(n=gu(n,t)))?function(r){return(gu(r,t)-n)/e}:T_(e)},function(n,e){return e=gu(e,t)-(n=gu(n,t)),function(r){return gu(n+e*r,1/t)}}),e=n.domain;return n.exponent=function(n){return arguments.length?(t=+n,e(e())):t},n.copy=function(){return uu(n,mu().exponent(t))},cu(n)}function xu(){function t(){var t=0,o=Math.max(1,r.length);for(i=new Array(o-1);++t<o;)i[t-1]=As(e,t/o);return n}function n(t){if(!isNaN(t=+t))return r[hs(i,t)]}var e=[],r=[],i=[];return n.invertExtent=function(t){var n=r.indexOf(t);return n<0?[NaN,NaN]:[n>0?i[n-1]:e[0],n<i.length?i[n]:e[e.length-1]]},n.domain=function(n){if(!arguments.length)return e.slice();e=[];for(var r,i=0,o=n.length;i<o;++i)null==(r=n[i])||isNaN(r=+r)||e.push(r);return e.sort(ss),t()},n.range=function(n){return arguments.length?(r=w_.call(n),t()):r.slice()},n.quantiles=function(){return i.slice()},n.copy=function(){return xu().domain(e).range(r)},n}function bu(){function t(t){if(t<=t)return u[hs(o,t,0,i)]}function n(){var n=-1;for(o=new Array(i);++n<i;)o[n]=((n+1)*r-(n-i)*e)/(i+1);return t}var e=0,r=1,i=1,o=[.5],u=[0,1];return t.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n()):[e,r]},t.range=function(t){return arguments.length?(i=(u=w_.call(t)).length-1,n()):u.slice()},t.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},t.copy=function(){return bu().domain([e,r]).range(u)},cu(t)}function wu(){function t(t){if(t<=t)return e[hs(n,t,0,r)]}var n=[.5],e=[0,1],r=1;return t.domain=function(i){return arguments.length?(n=w_.call(i),r=Math.min(n.length,e.length-1),t):n.slice()},t.range=function(i){return arguments.length?(e=w_.call(i),r=Math.min(n.length,e.length-1),t):e.slice()},t.invertExtent=function(t){var r=e.indexOf(t);return[n[r-1],n[r]]},t.copy=function(){return wu().domain(n).range(e)},t}function Mu(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(new Date(+e))}while(n(e,o),t(e),e<r);return u},i.filter=function(e){return Mu(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return A_.setTime(+n),C_.setTime(+r),t(A_),t(C_),Math.floor(e(A_,C_))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}function Tu(t){return Mu(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*R_)/L_})}function ku(t){return Mu(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/L_})}function Nu(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Su(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Eu(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function Au(t){function n(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,s=t.length;for(e instanceof Date||(e=new Date(+e));++a<s;)37===t.charCodeAt(a)&&(u.push(t.slice(c,a)),null!=(i=Py[r=t.charAt(++a)])?r=t.charAt(++a):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),u.push(r),c=a+1);return u.push(t.slice(c,a)),u.join("")}}function e(t,n){return function(e){var i=Eu(1900);if(r(i,t,e+="",0)!=e.length)return null;if("p"in i&&(i.H=i.H%12+12*i.p),"W"in i||"U"in i){"w"in i||(i.w="W"in i?1:0);var o="Z"in i?Su(Eu(i.y)).getUTCDay():n(Eu(i.y)).getDay();i.m=0,i.d="W"in i?(i.w+6)%7+7*i.W-(o+5)%7:i.w+7*i.U-(o+6)%7}return"Z"in i?(i.H+=i.Z/100|0,i.M+=i.Z%100,Su(i)):n(i)}}function r(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u<a;){if(r>=c)return-1;if(37===(i=n.charCodeAt(u++))){if(i=n.charAt(u++),!(o=T[i in Py?n.charAt(u++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}var i=t.dateTime,o=t.date,u=t.time,a=t.periods,c=t.days,s=t.shortDays,f=t.months,l=t.shortMonths,h=Pu(a),p=Ru(a),d=Pu(c),v=Ru(c),_=Pu(s),y=Ru(s),g=Pu(f),m=Ru(f),x=Pu(l),b=Ru(l),w={a:function(t){return s[t.getDay()]},A:function(t){return c[t.getDay()]},b:function(t){return l[t.getMonth()]},B:function(t){return f[t.getMonth()]},c:null,d:Wu,e:Wu,H:Zu,I:Gu,j:Ju,L:Qu,m:Ku,M:ta,p:function(t){return a[+(t.getHours()>=12)]},S:na,U:ea,w:ra,W:ia,x:null,X:null,y:oa,Y:ua,Z:aa,"%":wa},M={a:function(t){return s[t.getUTCDay()]},A:function(t){return c[t.getUTCDay()]},b:function(t){return l[t.getUTCMonth()]},B:function(t){return f[t.getUTCMonth()]},c:null,d:ca,e:ca,H:sa,I:fa,j:la,L:ha,m:pa,M:da,p:function(t){return a[+(t.getUTCHours()>=12)]},S:va,U:_a,w:ya,W:ga,x:null,X:null,y:ma,Y:xa,Z:ba,"%":wa},T={a:function(t,n,e){var r=_.exec(n.slice(e));return r?(t.w=y[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=v[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=x.exec(n.slice(e));return r?(t.m=b[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=m[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,n,e){return r(t,i,n,e)},d:Yu,e:Yu,H:ju,I:ju,j:Bu,L:$u,m:Iu,M:Hu,p:function(t,n,e){var r=h.exec(n.slice(e));return r?(t.p=p[r[0].toLowerCase()],e+r[0].length):-1},S:Xu,U:qu,w:Lu,W:Uu,x:function(t,n,e){return r(t,o,n,e)},X:function(t,n,e){return r(t,u,n,e)},y:Ou,Y:Du,Z:Fu,"%":Vu};return w.x=n(o,w),w.X=n(u,w),w.c=n(i,w),M.x=n(o,M),M.X=n(u,M),M.c=n(i,M),{format:function(t){var e=n(t+="",w);return e.toString=function(){return t},e},parse:function(t){var n=e(t+="",Nu);return n.toString=function(){return t},n},utcFormat:function(t){var e=n(t+="",M);return e.toString=function(){return t},e},utcParse:function(t){var n=e(t,Su);return n.toString=function(){return t},n}}}function Cu(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function zu(t){return t.replace(qy,"\\$&")}function Pu(t){return new RegExp("^(?:"+t.map(zu).join("|")+")","i")}function Ru(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function Lu(t,n,e){var r=Ry.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function qu(t,n,e){var r=Ry.exec(n.slice(e));return r?(t.U=+r[0],e+r[0].length):-1}function Uu(t,n,e){var r=Ry.exec(n.slice(e));return r?(t.W=+r[0],e+r[0].length):-1}function Du(t,n,e){var r=Ry.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function Ou(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function Fu(t,n,e){var r=/^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Iu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function Yu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function Bu(t,n,e){var r=Ry.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function ju(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Hu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Xu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function $u(t,n,e){var r=Ry.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Vu(t,n,e){var r=Ly.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Wu(t,n){return Cu(t.getDate(),n,2)}function Zu(t,n){return Cu(t.getHours(),n,2)}function Gu(t,n){return Cu(t.getHours()%12||12,n,2)}function Ju(t,n){return Cu(1+Y_.count(oy(t),t),n,3)}function Qu(t,n){return Cu(t.getMilliseconds(),n,3)}function Ku(t,n){return Cu(t.getMonth()+1,n,2)}function ta(t,n){return Cu(t.getMinutes(),n,2)}function na(t,n){return Cu(t.getSeconds(),n,2)}function ea(t,n){return Cu(j_.count(oy(t),t),n,2)}function ra(t){return t.getDay()}function ia(t,n){return Cu(H_.count(oy(t),t),n,2)}function oa(t,n){return Cu(t.getFullYear()%100,n,2)}function ua(t,n){return Cu(t.getFullYear()%1e4,n,4)}function aa(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Cu(n/60|0,"0",2)+Cu(n%60,"0",2)}function ca(t,n){return Cu(t.getUTCDate(),n,2)}function sa(t,n){return Cu(t.getUTCHours(),n,2)}function fa(t,n){return Cu(t.getUTCHours()%12||12,n,2)}function la(t,n){return Cu(1+ly.count(Ay(t),t),n,3)}function ha(t,n){return Cu(t.getUTCMilliseconds(),n,3)}function pa(t,n){return Cu(t.getUTCMonth()+1,n,2)}function da(t,n){return Cu(t.getUTCMinutes(),n,2)}function va(t,n){return Cu(t.getUTCSeconds(),n,2)}function _a(t,n){return Cu(py.count(Ay(t),t),n,2)}function ya(t){return t.getUTCDay()}function ga(t,n){return Cu(dy.count(Ay(t),t),n,2)}function ma(t,n){return Cu(t.getUTCFullYear()%100,n,2)}function xa(t,n){return Cu(t.getUTCFullYear()%1e4,n,4)}function ba(){return"+0000"}function wa(){return"%"}function Ma(n){return Cy=Au(n),t.timeFormat=Cy.format,t.timeParse=Cy.parse,t.utcFormat=Cy.utcFormat,t.utcParse=Cy.utcParse,Cy}function Ta(t){return new Date(t)}function ka(t){return t instanceof Date?+t:+new Date(+t)}function Na(t,n,e,r,o,u,a,c,s){function f(i){return(a(i)<i?v:u(i)<i?_:o(i)<i?y:r(i)<i?g:n(i)<i?e(i)<i?m:x:t(i)<i?b:w)(i)}function l(n,e,r,o){if(null==n&&(n=10),"number"==typeof n){var u=Math.abs(r-e)/n,a=fs(function(t){return t[2]}).right(M,u);a===M.length?(o=i(e/Hy,r/Hy,n),n=t):a?(o=(a=M[u/M[a-1][2]<M[a][2]/u?a-1:a])[1],n=a[0]):(o=i(e,r,n),n=c)}return null==o?n:n.every(o)}var h=au(nu,rl),p=h.invert,d=h.domain,v=s(".%L"),_=s(":%S"),y=s("%I:%M"),g=s("%I %p"),m=s("%a %d"),x=s("%b %d"),b=s("%B"),w=s("%Y"),M=[[a,1,Oy],[a,5,5*Oy],[a,15,15*Oy],[a,30,30*Oy],[u,1,Fy],[u,5,5*Fy],[u,15,15*Fy],[u,30,30*Fy],[o,1,Iy],[o,3,3*Iy],[o,6,6*Iy],[o,12,12*Iy],[r,1,Yy],[r,2,2*Yy],[e,1,By],[n,1,jy],[n,3,3*jy],[t,1,Hy]];return h.invert=function(t){return new Date(p(t))},h.domain=function(t){return arguments.length?d(b_.call(t,ka)):d().map(Ta)},h.ticks=function(t,n){var e,r=d(),i=r[0],o=r[r.length-1],u=o<i;return u&&(e=i,i=o,o=e),e=l(t,i,o,n),e=e?e.range(i,o+1):[],u?e.reverse():e},h.tickFormat=function(t,n){return null==n?f:s(n)},h.nice=function(t,n){var e=d();return(t=l(t,e[0],e[e.length-1],n))?d(E_(e,t)):h},h.copy=function(){return uu(h,Na(t,n,e,r,o,u,a,c,s))},h}function Sa(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}function Ea(t){function n(n){var o=(n-e)/(r-e);return t(i?Math.max(0,Math.min(1,o)):o)}var e=0,r=1,i=!1;return n.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n):[e,r]},n.clamp=function(t){return arguments.length?(i=!!t,n):i},n.interpolator=function(e){return arguments.length?(t=e,n):t},n.copy=function(){return Ea(t).domain([e,r]).clamp(i)},cu(n)}function Aa(t){return t>1?0:t<-1?pg:Math.acos(t)}function Ca(t){return t>=1?dg:t<=-1?-dg:Math.asin(t)}function za(t){return t.innerRadius}function Pa(t){return t.outerRadius}function Ra(t){return t.startAngle}function La(t){return t.endAngle}function qa(t){return t&&t.padAngle}function Ua(t,n,e,r,i,o,u,a){var c=e-t,s=r-n,f=u-i,l=a-o,h=(f*(n-o)-l*(t-i))/(l*c-f*s);return[t+h*c,n+h*s]}function Da(t,n,e,r,i,o,u){var a=t-e,c=n-r,s=(u?o:-o)/lg(a*a+c*c),f=s*c,l=-s*a,h=t+f,p=n+l,d=e+f,v=r+l,_=(h+d)/2,y=(p+v)/2,g=d-h,m=v-p,x=g*g+m*m,b=i-o,w=h*v-d*p,M=(m<0?-1:1)*lg(cg(0,b*b*x-w*w)),T=(w*m-g*M)/x,k=(-w*g-m*M)/x,N=(w*m+g*M)/x,S=(-w*g+m*M)/x,E=T-_,A=k-y,C=N-_,z=S-y;return E*E+A*A>C*C+z*z&&(T=N,k=S),{cx:T,cy:k,x01:-f,y01:-l,x11:T*(i/b-1),y11:k*(i/b-1)}}function Oa(t){this._context=t}function Fa(t){return t[0]}function Ia(t){return t[1]}function Ya(t){this._curve=t}function Ba(t){function n(n){return new Ya(t(n))}return n._curve=t,n}function ja(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Ba(t)):n()._curve},t}function Ha(t){return t.source}function Xa(t){return t.target}function $a(t){function n(){var n,a=kg.call(arguments),c=e.apply(this,a),s=r.apply(this,a);if(u||(u=n=ve()),t(u,+i.apply(this,(a[0]=c,a)),+o.apply(this,a),+i.apply(this,(a[0]=s,a)),+o.apply(this,a)),n)return u=null,n+""||null}var e=Ha,r=Xa,i=Fa,o=Ia,u=null;return n.source=function(t){return arguments.length?(e=t,n):e},n.target=function(t){return arguments.length?(r=t,n):r},n.x=function(t){return arguments.length?(i="function"==typeof t?t:ig(+t),n):i},n.y=function(t){return arguments.length?(o="function"==typeof t?t:ig(+t),n):o},n.context=function(t){return arguments.length?(u=null==t?null:t,n):u},n}function Va(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function Wa(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function Za(t,n,e,r,i){var o=Tg(n,e),u=Tg(n,e=(e+i)/2),a=Tg(r,e),c=Tg(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(u[0],u[1],a[0],a[1],c[0],c[1])}function Ga(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Ja(t){this._context=t}function Qa(t){this._context=t}function Ka(t){this._context=t}function tc(t,n){this._basis=new Ja(t),this._beta=n}function nc(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function ec(t,n){this._context=t,this._k=(1-n)/6}function rc(t,n){this._context=t,this._k=(1-n)/6}function ic(t,n){this._context=t,this._k=(1-n)/6}function oc(t,n,e){var r=t._x1,i=t._y1,o=t._x2,u=t._y2;if(t._l01_a>hg){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>hg){var s=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*s+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*s+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function uc(t,n){this._context=t,this._alpha=n}function ac(t,n){this._context=t,this._alpha=n}function cc(t,n){this._context=t,this._alpha=n}function sc(t){this._context=t}function fc(t){return t<0?-1:1}function lc(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(fc(o)+fc(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function hc(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function pc(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function dc(t){this._context=t}function vc(t){this._context=new _c(t)}function _c(t){this._context=t}function yc(t){this._context=t}function gc(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(i[0]=0,o[0]=2,u[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,u[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,u[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,u[n]-=e*u[n-1];for(i[r-1]=u[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(u[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function mc(t,n){this._context=t,this._t=n}function xc(t,n){return t[n]}function bc(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function wc(t){return t[0]}function Mc(t){return t[1]}function Tc(){this._=null}function kc(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function Nc(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Sc(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function Ec(t){for(;t.L;)t=t.L;return t}function Ac(t,n,e,r){var i=[null,null],o=um.push(i)-1;return i.left=t,i.right=n,e&&zc(i,t,n,e),r&&zc(i,n,t,r),im[t.index].halfedges.push(o),im[n.index].halfedges.push(o),i}function Cc(t,n,e){var r=[n,e];return r.left=t,r}function zc(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function Pc(t,n,e,r,i){var o,u=t[0],a=t[1],c=u[0],s=u[1],f=0,l=1,h=a[0]-c,p=a[1]-s;if(o=n-c,h||!(o>0)){if(o/=h,h<0){if(o<f)return;o<l&&(l=o)}else if(h>0){if(o>l)return;o>f&&(f=o)}if(o=r-c,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>f&&(f=o)}else if(h>0){if(o<f)return;o<l&&(l=o)}if(o=e-s,p||!(o>0)){if(o/=p,p<0){if(o<f)return;o<l&&(l=o)}else if(p>0){if(o>l)return;o>f&&(f=o)}if(o=i-s,p||!(o<0)){if(o/=p,p<0){if(o>l)return;o>f&&(f=o)}else if(p>0){if(o<f)return;o<l&&(l=o)}return!(f>0||l<1)||(f>0&&(t[0]=[c+f*h,s+f*p]),l<1&&(t[1]=[c+l*h,s+l*p]),!0)}}}}}function Rc(t,n,e,r,i){var o=t[1];if(o)return!0;var u,a,c=t[0],s=t.left,f=t.right,l=s[0],h=s[1],p=f[0],d=f[1],v=(l+p)/2,_=(h+d)/2;if(d===h){if(v<n||v>=r)return;if(l>p){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=(l-p)/(d-h),a=_-u*v,u<-1||u>1)if(l>p){if(c){if(c[1]>=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]<e)return}else c=[(i-a)/u,i];o=[(e-a)/u,e]}else if(h<d){if(c){if(c[0]>=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]<n)return}else c=[r,u*r+a];o=[n,u*n+a]}return t[0]=c,t[1]=o,!0}function Lc(t,n,e,r){for(var i,o=um.length;o--;)Rc(i=um[o],t,n,e,r)&&Pc(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>sm||Math.abs(i[0][1]-i[1][1])>sm)||delete um[o]}function qc(t){return im[t.index]={site:t,halfedges:[]}}function Uc(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function Dc(t,n){return n[+(n.left!==t.site)]}function Oc(t,n){return n[+(n.left===t.site)]}function Fc(){for(var t,n,e,r,i=0,o=im.length;i<o;++i)if((t=im[i])&&(r=(n=t.halfedges).length)){var u=new Array(r),a=new Array(r);for(e=0;e<r;++e)u[e]=e,a[e]=Uc(t,um[n[e]]);for(u.sort(function(t,n){return a[n]-a[t]}),e=0;e<r;++e)a[e]=n[u[e]];for(e=0;e<r;++e)n[e]=a[e]}}function Ic(t,n,e,r){var i,o,u,a,c,s,f,l,h,p,d,v,_=im.length,y=!0;for(i=0;i<_;++i)if(o=im[i]){for(u=o.site,a=(c=o.halfedges).length;a--;)um[c[a]]||c.splice(a,1);for(a=0,s=c.length;a<s;)d=(p=Oc(o,um[c[a]]))[0],v=p[1],l=(f=Dc(o,um[c[++a%s]]))[0],h=f[1],(Math.abs(d-l)>sm||Math.abs(v-h)>sm)&&(c.splice(a,0,um.push(Cc(u,p,Math.abs(d-t)<sm&&r-v>sm?[t,Math.abs(l-t)<sm?h:r]:Math.abs(v-r)<sm&&e-d>sm?[Math.abs(h-r)<sm?l:e,r]:Math.abs(d-e)<sm&&v-n>sm?[e,Math.abs(l-e)<sm?h:n]:Math.abs(v-n)<sm&&d-t>sm?[Math.abs(h-n)<sm?l:t,n]:null))-1),++s);s&&(y=!1)}if(y){var g,m,x,b=1/0;for(i=0,y=null;i<_;++i)(o=im[i])&&(x=(g=(u=o.site)[0]-t)*g+(m=u[1]-n)*m)<b&&(b=x,y=o);if(y){var w=[t,n],M=[t,r],T=[e,r],k=[e,n];y.halfedges.push(um.push(Cc(u=y.site,w,M))-1,um.push(Cc(u,M,T))-1,um.push(Cc(u,T,k))-1,um.push(Cc(u,k,w))-1)}}for(i=0;i<_;++i)(o=im[i])&&(o.halfedges.length||delete im[i])}function Yc(){kc(this),this.x=this.y=this.arc=this.site=this.cy=null}function Bc(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var u=i[0],a=i[1],c=r[0]-u,s=r[1]-a,f=o[0]-u,l=o[1]-a,h=2*(c*l-s*f);if(!(h>=-fm)){var p=c*c+s*s,d=f*f+l*l,v=(l*p-s*d)/h,_=(c*d-f*p)/h,y=am.pop()||new Yc;y.arc=t,y.site=i,y.x=v+u,y.y=(y.cy=_+a)+Math.sqrt(v*v+_*_),t.circle=y;for(var g=null,m=om._;m;)if(y.y<m.y||y.y===m.y&&y.x<=m.x){if(!m.L){g=m.P;break}m=m.L}else{if(!m.R){g=m;break}m=m.R}om.insert(g,y),g||(em=y)}}}}function jc(t){var n=t.circle;n&&(n.P||(em=n.N),om.remove(n),am.push(n),kc(n),t.circle=null)}function Hc(){kc(this),this.edge=this.site=this.circle=null}function Xc(t){var n=cm.pop()||new Hc;return n.site=t,n}function $c(t){jc(t),rm.remove(t),cm.push(t),kc(t)}function Vc(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,u=t.N,a=[t];$c(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<sm&&Math.abs(r-c.circle.cy)<sm;)o=c.P,a.unshift(c),$c(c),c=o;a.unshift(c),jc(c);for(var s=u;s.circle&&Math.abs(e-s.circle.x)<sm&&Math.abs(r-s.circle.cy)<sm;)u=s.N,a.push(s),$c(s),s=u;a.push(s),jc(s);var f,l=a.length;for(f=1;f<l;++f)s=a[f],c=a[f-1],zc(s.edge,c.site,s.site,i);c=a[0],(s=a[l-1]).edge=Ac(c.site,s.site,null,i),Bc(c),Bc(s)}function Wc(t){for(var n,e,r,i,o=t[0],u=t[1],a=rm._;a;)if((r=Zc(a,u)-o)>sm)a=a.L;else{if(!((i=o-Gc(a,u))>sm)){r>-sm?(n=a.P,e=a):i>-sm?(n=a,e=a.N):n=e=a;break}if(!a.R){n=a;break}a=a.R}qc(t);var c=Xc(t);if(rm.insert(n,c),n||e){if(n===e)return jc(n),e=Xc(n.site),rm.insert(c,e),c.edge=e.edge=Ac(n.site,c.site),Bc(n),void Bc(e);if(e){jc(n),jc(e);var s=n.site,f=s[0],l=s[1],h=t[0]-f,p=t[1]-l,d=e.site,v=d[0]-f,_=d[1]-l,y=2*(h*_-p*v),g=h*h+p*p,m=v*v+_*_,x=[(_*g-p*m)/y+f,(h*m-v*g)/y+l];zc(e.edge,s,d,x),c.edge=Ac(s,t,null,x),e.edge=Ac(t,d,null,x),Bc(n),Bc(e)}else c.edge=Ac(n.site,c.site)}}function Zc(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var u=t.P;if(!u)return-1/0;var a=(e=u.site)[0],c=e[1],s=c-n;if(!s)return a;var f=a-r,l=1/o-1/s,h=f/s;return l?(-h+Math.sqrt(h*h-2*l*(f*f/(-2*s)-c+s/2+i-o/2)))/l+r:(r+a)/2}function Gc(t,n){var e=t.N;if(e)return Zc(e,n);var r=t.site;return r[1]===n?r[0]:1/0}function Jc(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function Qc(t,n){return n[1]-t[1]||n[0]-t[0]}function Kc(t,n){var e,r,i,o=t.sort(Qc).pop();for(um=[],im=new Array(t.length),rm=new Tc,om=new Tc;;)if(i=em,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(Wc(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;Vc(i.arc)}if(Fc(),n){var u=+n[0][0],a=+n[0][1],c=+n[1][0],s=+n[1][1];Lc(u,a,c,s),Ic(u,a,c,s)}this.edges=um,this.cells=im,rm=om=um=im=null}function ts(t,n,e){this.target=t,this.type=n,this.transform=e}function ns(t,n,e){this.k=t,this.x=n,this.y=e}function es(t){return t.__zoom||hm}function rs(){t.event.stopImmediatePropagation()}function is(){return!t.event.button}function os(){var t,n,e=this;return e instanceof SVGElement?(t=(e=e.ownerSVGElement||e).width.baseVal.value,n=e.height.baseVal.value):(t=e.clientWidth,n=e.clientHeight),[[0,0],[t,n]]}function us(){return this.__zoom||hm}function as(){return-t.event.deltaY*(t.event.deltaMode?120:1)/500}function cs(){return"ontouchstart"in this}var ss=function(t,n){return t<n?-1:t>n?1:t>=n?0:NaN},fs=function(t){return 1===t.length&&(t=n(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}},ls=fs(ss),hs=ls.right,ps=ls.left,ds=function(t){return null===t?NaN:+t},vs=function(t,n){var e,r,i=t.length,o=0,u=-1,a=0,c=0;if(null==n)for(;++u<i;)isNaN(e=ds(t[u]))||(c+=(r=e-a)*(e-(a+=r/++o)));else for(;++u<i;)isNaN(e=ds(n(t[u],u,t)))||(c+=(r=e-a)*(e-(a+=r/++o)));if(o>1)return c/(o-1)},_s=function(t,n){var e=vs(t,n);return e?Math.sqrt(e):e},ys=function(t,n){var e,r,i,o=t.length,u=-1;if(null==n){for(;++u<o;)if(null!=(e=t[u])&&e>=e)for(r=i=e;++u<o;)null!=(e=t[u])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++u<o;)if(null!=(e=n(t[u],u,t))&&e>=e)for(r=i=e;++u<o;)null!=(e=n(t[u],u,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]},gs=Array.prototype,ms=gs.slice,xs=gs.map,bs=function(t){return function(){return t}},ws=function(t){return t},Ms=function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o},Ts=Math.sqrt(50),ks=Math.sqrt(10),Ns=Math.sqrt(2),Ss=function(t,n,e){var i,o,u,a=n<t,c=-1;if(a&&(i=t,t=n,n=i),0===(u=r(t,n,e))||!isFinite(u))return[];if(u>0)for(t=Math.ceil(t/u),n=Math.floor(n/u),o=new Array(i=Math.ceil(n-t+1));++c<i;)o[c]=(t+c)*u;else for(t=Math.floor(t*u),n=Math.ceil(n*u),o=new Array(i=Math.ceil(t-n+1));++c<i;)o[c]=(t-c)/u;return a&&o.reverse(),o},Es=function(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1},As=function(t,n,e){if(null==e&&(e=ds),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t);return u+(+e(t[o+1],o+1,t)-u)*(i-o)}},Cs=function(t){for(var n,e,r,i=t.length,o=-1,u=0;++o<i;)u+=t[o].length;for(e=new Array(u);--i>=0;)for(n=(r=t[i]).length;--n>=0;)e[--u]=r[n];return e},zs=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r},Ps=function(t){if(!(i=t.length))return[];for(var n=-1,e=zs(t,o),r=new Array(e);++n<e;)for(var i,u=-1,a=r[n]=new Array(i);++u<i;)a[u]=t[u][n];return r},Rs=Array.prototype.slice,Ls=function(t){return t},qs=1,Us=2,Ds=3,Os=4,Fs=1e-6,Is={value:function(){}};p.prototype=h.prototype={constructor:p,on:function(t,n){var e,r=this._,i=d(t+"",r),o=-1,u=i.length;{if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<u;)if(e=(t=i[o]).type)r[e]=_(r[e],t.name,n);else if(null==n)for(e in r)r[e]=_(r[e],t.name,null);return this}for(;++o<u;)if((e=(t=i[o]).type)&&(e=v(r[e],t.name)))return e}},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new p(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var Ys="http://www.w3.org/1999/xhtml",Bs={svg:"http://www.w3.org/2000/svg",xhtml:Ys,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},js=function(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Bs.hasOwnProperty(n)?{space:Bs[n],local:t}:t},Hs=function(t){var n=js(t);return(n.local?g:y)(n)},Xs=0;x.prototype=m.prototype={constructor:x,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};var $s=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var Vs=document.documentElement;if(!Vs.matches){var Ws=Vs.webkitMatchesSelector||Vs.msMatchesSelector||Vs.mozMatchesSelector||Vs.oMatchesSelector;$s=function(t){return function(){return Ws.call(this,t)}}}}var Zs=$s,Gs={};t.event=null,"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(Gs={mouseenter:"mouseover",mouseleave:"mouseout"}));var Js=function(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e},Qs=function(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,r=r.matrixTransform(t.getScreenCTM().inverse()),[r.x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]},Ks=function(t){var n=Js();return n.changedTouches&&(n=n.changedTouches[0]),Qs(t,n)},tf=function(t){return null==t?S:function(){return this.querySelector(t)}},nf=function(t){return null==t?E:function(){return this.querySelectorAll(t)}},ef=function(t){return new Array(t.length)};A.prototype={constructor:A,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var rf=function(t){return function(){return t}},of="$",uf=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};W.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var af=[null];pt.prototype=dt.prototype={constructor:pt,select:function(t){"function"!=typeof t&&(t=tf(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u,a=n[i],c=a.length,s=r[i]=new Array(c),f=0;f<c;++f)(o=a[f])&&(u=t.call(o,o.__data__,f,a))&&("__data__"in o&&(u.__data__=o.__data__),s[f]=u);return new pt(r,this._parents)},selectAll:function(t){"function"!=typeof t&&(t=nf(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var u,a=n[o],c=a.length,s=0;s<c;++s)(u=a[s])&&(r.push(t.call(u,u.__data__,s,a)),i.push(u));return new pt(r,i)},filter:function(t){"function"!=typeof t&&(t=Zs(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new pt(r,this._parents)},data:function(t,n){if(!t)return p=new Array(this.size()),s=-1,this.each(function(t){p[++s]=t}),p;var e=n?z:C,r=this._parents,i=this._groups;"function"!=typeof t&&(t=rf(t));for(var o=i.length,u=new Array(o),a=new Array(o),c=new Array(o),s=0;s<o;++s){var f=r[s],l=i[s],h=l.length,p=t.call(f,f&&f.__data__,s,r),d=p.length,v=a[s]=new Array(d),_=u[s]=new Array(d);e(f,l,v,_,c[s]=new Array(h),p,n);for(var y,g,m=0,x=0;m<d;++m)if(y=v[m]){for(m>=x&&(x=m+1);!(g=_[x])&&++x<d;);y._next=g||null}}return u=new pt(u,r),u._enter=a,u._exit=c,u},enter:function(){return new pt(this._enter||this._groups.map(ef),this._parents)},exit:function(){return new pt(this._exit||this._groups.map(ef),this._parents)},merge:function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new pt(u,this._parents)},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,u=i[o];--o>=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){t||(t=P);for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i){for(var o,u=n[i],a=u.length,c=r[i]=new Array(a),s=0;s<a;++s)(o=u[s])&&(c[s]=o);c.sort(function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e})}return new pt(r,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var u=r[i];if(u)return u}return null},size:function(){var t=0;return this.each(function(){++t}),t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],u=0,a=o.length;u<a;++u)(i=o[u])&&t.call(i,i.__data__,u,o);return this},attr:function(t,n){var e=js(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?L:R:"function"==typeof n?e.local?O:D:e.local?U:q)(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?F:"function"==typeof n?Y:I)(t,n,null==e?"":e)):B(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?j:"function"==typeof n?X:H)(t,n)):this.node()[t]},classed:function(t,n){var e=$(t+"");if(arguments.length<2){for(var r=V(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?K:n?J:Q)(e,n))},text:function(t){return arguments.length?this.each(null==t?tt:("function"==typeof t?et:nt)(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?rt:("function"==typeof t?ot:it)(t)):this.node().innerHTML},raise:function(){return this.each(ut)},lower:function(){return this.each(at)},append:function(t){var n="function"==typeof t?t:Hs(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},insert:function(t,n){var e="function"==typeof t?t:Hs(t),r=null==n?ct:"function"==typeof n?n:tf(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},remove:function(){return this.each(st)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=M(t+""),u=o.length;{if(!(arguments.length<2)){for(a=n?k:T,null==e&&(e=!1),r=0;r<u;++r)this.each(a(o[r],n,e));return this}var a=this.node().__on;if(a)for(var c,s=0,f=a.length;s<f;++s)for(r=0,c=a[s];r<u;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value}},dispatch:function(t,n){return this.each(("function"==typeof n?ht:lt)(t,n))}};var cf=function(t){return"string"==typeof t?new pt([[document.querySelector(t)]],[document.documentElement]):new pt([[t]],af)},sf=function(t,n,e){arguments.length<3&&(e=n,n=Js().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Qs(t,r);return null},ff=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},lf=function(t){var n=t.document.documentElement,e=cf(t).on("dragstart.drag",ff,!0);"onselectstart"in n?e.on("selectstart.drag",ff,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")},hf=function(t){return function(){return t}};yt.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var pf=function(t,n,e){t.prototype=n.prototype=e,e.constructor=t},df="\\s*([+-]?\\d+)\\s*",vf="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",_f="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",yf=/^#([0-9a-f]{3})$/,gf=/^#([0-9a-f]{6})$/,mf=new RegExp("^rgb\\("+[df,df,df]+"\\)$"),xf=new RegExp("^rgb\\("+[_f,_f,_f]+"\\)$"),bf=new RegExp("^rgba\\("+[df,df,df,vf]+"\\)$"),wf=new RegExp("^rgba\\("+[_f,_f,_f,vf]+"\\)$"),Mf=new RegExp("^hsl\\("+[vf,_f,_f]+"\\)$"),Tf=new RegExp("^hsla\\("+[vf,_f,_f,vf]+"\\)$"),kf={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};pf(Mt,Tt,{displayable:function(){return this.rgb().displayable()},toString:function(){return this.rgb()+""}}),pf(At,Et,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new At(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new At(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),pf(Rt,Pt,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new At(Lt(t>=240?t-240:t+120,i,r),Lt(t,i,r),Lt(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Nf=Math.PI/180,Sf=180/Math.PI,Ef=.95047,Af=1,Cf=1.08883,zf=4/29,Pf=6/29,Rf=3*Pf*Pf,Lf=Pf*Pf*Pf;pf(Dt,Ut,wt(Mt,{brighter:function(t){return new Dt(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Dt(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=Af*Ft(t),n=Ef*Ft(n),e=Cf*Ft(e),new At(It(3.2404542*n-1.5371385*t-.4985314*e),It(-.969266*n+1.8760108*t+.041556*e),It(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),pf(Ht,jt,wt(Mt,{brighter:function(t){return new Ht(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Ht(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return qt(this).rgb()}}));var qf=-.14861,Uf=1.78277,Df=-.29227,Of=-.90649,Ff=1.97294,If=Ff*Of,Yf=Ff*Uf,Bf=Uf*Df-Of*qf;pf(Vt,$t,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Vt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Vt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Nf,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new At(255*(n+e*(qf*r+Uf*i)),255*(n+e*(Df*r+Of*i)),255*(n+e*(Ff*r)),this.opacity)}}));var jf,Hf,Xf,$f,Vf,Wf,Zf=function(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=r<n-1?t[r+2]:2*o-i;return Wt((e-r/n)*n,u,i,o,a)}},Gf=function(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],u=t[(r+1)%n],a=t[(r+2)%n];return Wt((e-r/n)*n,i,o,u,a)}},Jf=function(t){return function(){return t}},Qf=function t(n){function e(t,n){var e=r((t=Et(t)).r,(n=Et(n)).r),i=r(t.g,n.g),o=r(t.b,n.b),u=Kt(t.opacity,n.opacity);return function(n){return t.r=e(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}var r=Qt(n);return e.gamma=t,e}(1),Kf=tn(Zf),tl=tn(Gf),nl=function(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(r),u=new Array(r);for(e=0;e<i;++e)o[e]=cl(t[e],n[e]);for(;e<r;++e)u[e]=n[e];return function(t){for(e=0;e<i;++e)u[e]=o[e](t);return u}},el=function(t,n){var e=new Date;return t=+t,n-=t,function(r){return e.setTime(t+n*r),e}},rl=function(t,n){return t=+t,n-=t,function(e){return t+n*e}},il=function(t,n){var e,r={},i={};null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={});for(e in n)e in t?r[e]=cl(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}},ol=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ul=new RegExp(ol.source,"g"),al=function(t,n){var e,r,i,o=ol.lastIndex=ul.lastIndex=0,u=-1,a=[],c=[];for(t+="",n+="";(e=ol.exec(t))&&(r=ul.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:rl(e,r)})),o=ul.lastIndex;return o<n.length&&(i=n.slice(o),a[u]?a[u]+=i:a[++u]=i),a.length<2?c[0]?en(c[0].x):nn(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)a[(e=c[r]).i]=e.x(t);return a.join("")})},cl=function(t,n){var e,r=typeof n;return null==n||"boolean"===r?Jf(n):("number"===r?rl:"string"===r?(e=Tt(n))?(n=e,Qf):al:n instanceof Tt?Qf:n instanceof Date?el:Array.isArray(n)?nl:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?il:rl)(t,n)},sl=function(t,n){return t=+t,n-=t,function(e){return Math.round(t+n*e)}},fl=180/Math.PI,ll={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1},hl=function(t,n,e,r,i,o){var u,a,c;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,c/=a),t*r<n*e&&(t=-t,n=-n,c=-c,u=-u),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*fl,skewX:Math.atan(c)*fl,scaleX:u,scaleY:a}},pl=rn(function(t){return"none"===t?ll:(jf||(jf=document.createElement("DIV"),Hf=document.documentElement,Xf=document.defaultView),jf.style.transform=t,t=Xf.getComputedStyle(Hf.appendChild(jf),null).getPropertyValue("transform"),Hf.removeChild(jf),t=t.slice(7,-1).split(","),hl(+t[0],+t[1],+t[2],+t[3],+t[4],+t[5]))},"px, ","px)","deg)"),dl=rn(function(t){return null==t?ll:($f||($f=document.createElementNS("http://www.w3.org/2000/svg","g")),$f.setAttribute("transform",t),(t=$f.transform.baseVal.consolidate())?(t=t.matrix,hl(t.a,t.b,t.c,t.d,t.e,t.f)):ll)},", ",")",")"),vl=Math.SQRT2,_l=function(t,n){var e,r,i=t[0],o=t[1],u=t[2],a=n[0],c=n[1],s=n[2],f=a-i,l=c-o,h=f*f+l*l;if(h<1e-12)r=Math.log(s/u)/vl,e=function(t){return[i+t*f,o+t*l,u*Math.exp(vl*t*r)]};else{var p=Math.sqrt(h),d=(s*s-u*u+4*h)/(2*u*2*p),v=(s*s-u*u-4*h)/(2*s*2*p),_=Math.log(Math.sqrt(d*d+1)-d),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-_)/vl,e=function(t){var n=t*r,e=on(_),a=u/(2*p)*(e*an(vl*n+_)-un(_));return[i+a*f,o+a*l,u*e/on(vl*n+_)]}}return e.duration=1e3*r,e},yl=cn(Jt),gl=cn(Kt),ml=sn(Jt),xl=sn(Kt),bl=fn(Jt),wl=fn(Kt),Ml=0,Tl=0,kl=0,Nl=1e3,Sl=0,El=0,Al=0,Cl="object"==typeof performance&&performance.now?performance:Date,zl="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};pn.prototype=dn.prototype={constructor:pn,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?ln():+e)+(null==n?0:+n),this._next||Wf===this||(Wf?Wf._next=this:Vf=this,Wf=this),this._call=t,this._time=e,mn()},stop:function(){this._call&&(this._call=null,this._time=1/0,mn())}};var Pl=function(t,n,e){var r=new pn;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},Rl=h("start","end","interrupt"),Ll=[],ql=0,Ul=1,Dl=2,Ol=3,Fl=4,Il=5,Yl=6,Bl=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};Mn(t,e,{name:n,index:r,group:i,on:Rl,tween:Ll,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:ql})},jl=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){n=null==n?null:n+"";for(i in o)(e=o[i]).name===n?(r=e.state>Dl&&e.state<Il,e.state=Yl,e.timer.stop(),r&&e.on.call("interrupt",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}},Hl=function(t,n){var e;return("number"==typeof n?rl:n instanceof Tt?Qf:(e=Tt(n))?(n=e,Qf):al)(t,n)},Xl=dt.prototype.constructor,$l=0,Vl=dt.prototype;Gn.prototype=Jn.prototype={constructor:Gn,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=tf(t));for(var r=this._groups,i=r.length,o=new Array(i),u=0;u<i;++u)for(var a,c,s=r[u],f=s.length,l=o[u]=new Array(f),h=0;h<f;++h)(a=s[h])&&(c=t.call(a,a.__data__,h,s))&&("__data__"in a&&(c.__data__=a.__data__),l[h]=c,Bl(l[h],n,e,h,l,wn(a,e)));return new Gn(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=nf(t));for(var r=this._groups,i=r.length,o=[],u=[],a=0;a<i;++a)for(var c,s=r[a],f=s.length,l=0;l<f;++l)if(c=s[l]){for(var h,p=t.call(c,c.__data__,l,s),d=wn(c,e),v=0,_=p.length;v<_;++v)(h=p[v])&&Bl(h,n,e,v,p,d);o.push(p),u.push(c)}return new Gn(o,u,n,e)},filter:function(t){"function"!=typeof t&&(t=Zs(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new Gn(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new Gn(u,this._parents,this._name,this._id)},selection:function(){return new Xl(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Qn(),r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)if(u=a[s]){var f=wn(u,n);Bl(u,t,e,s,a,{time:f.time+f.delay+f.duration,delay:0,duration:f.duration,ease:f.ease})}return new Gn(r,this._parents,t,e)},call:Vl.call,nodes:Vl.nodes,node:Vl.node,size:Vl.size,empty:Vl.empty,each:Vl.each,on:function(t,n){var e=this._id;return arguments.length<2?wn(this.node(),e).on.on(t):this.each(Yn(e,t,n))},attr:function(t,n){var e=js(t),r="transform"===e?dl:Hl;return this.attrTween(t,"function"==typeof n?(e.local?Pn:zn)(e,r,Nn(this,"attr."+t,n)):null==n?(e.local?En:Sn)(e):(e.local?Cn:An)(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=js(t);return this.tween(e,(r.local?Rn:Ln)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?pl:Hl;return null==n?this.styleTween(t,jn(t,r)).on("end.style."+t,Hn(t)):this.styleTween(t,"function"==typeof n?$n(t,r,Nn(this,"style."+t,n)):Xn(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,Vn(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?Zn(Nn(this,"text",t)):Wn(null==t?"":t+""))},remove:function(){return this.on("end.remove",Bn(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=wn(this.node(),e).tween,o=0,u=i.length;o<u;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?Tn:kn)(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?qn:Un)(n,t)):wn(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?Dn:On)(n,t)):wn(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(Fn(n,t)):wn(this.node(),n).ease}};var Wl=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),Zl=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Gl=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Jl=Math.PI,Ql=Jl/2,Kl=4/11,th=6/11,nh=8/11,eh=.75,rh=9/11,ih=10/11,oh=.9375,uh=21/22,ah=63/64,ch=1/Kl/Kl,sh=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),fh=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),lh=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),hh=2*Math.PI,ph=function t(n,e){function r(t){return n*Math.pow(2,10*--t)*Math.sin((i-t)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),dh=function t(n,e){function r(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+i)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),vh=function t(n,e){function r(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((i-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((i+t)/e))/2}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),_h={time:null,delay:0,duration:250,ease:te};dt.prototype.interrupt=function(t){return this.each(function(){jl(this,t)})},dt.prototype.transition=function(t){var n,e;t instanceof Gn?(n=t._id,t=t._name):(n=Qn(),(e=_h).time=ln(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)(u=a[s])&&Bl(u,t,n,s,a,e||oe(u,n));return new Gn(r,this._parents,t,n)};var yh=[null],gh=function(t){return function(){return t}},mh=function(t,n,e){this.target=t,this.type=n,this.selection=e},xh=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},bh={name:"drag"},wh={name:"space"},Mh={name:"handle"},Th={name:"center"},kh={name:"x",handles:["e","w"].map(ae),input:function(t,n){return t&&[[t[0],n[0][1]],[t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Nh={name:"y",handles:["n","s"].map(ae),input:function(t,n){return t&&[[n[0][0],t[0]],[n[1][0],t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Sh={name:"xy",handles:["n","e","s","w","nw","ne","se","sw"].map(ae),input:function(t){return t},output:function(t){return t}},Eh={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ah={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ch={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},zh={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Ph={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1},Rh=Math.cos,Lh=Math.sin,qh=Math.PI,Uh=qh/2,Dh=2*qh,Oh=Math.max,Fh=Array.prototype.slice,Ih=function(t){return function(){return t}},Yh=Math.PI,Bh=2*Yh,jh=Bh-1e-6;de.prototype=ve.prototype={constructor:de,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,u=this._y1,a=e-t,c=r-n,s=o-t,f=u-n,l=s*s+f*f;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(f*a-c*s)>1e-6&&i){var h=e-o,p=r-u,d=a*a+c*c,v=h*h+p*p,_=Math.sqrt(d),y=Math.sqrt(l),g=i*Math.tan((Yh-Math.acos((d+l-v)/(2*_*y)))/2),m=g/y,x=g/_;Math.abs(m-1)>1e-6&&(this._+="L"+(t+m*s)+","+(n+m*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>s*p)+","+(this._x1=t+x*a)+","+(this._y1=n+x*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,s=n+a,f=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+s:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-s)>1e-6)&&(this._+="L"+c+","+s),e&&(l<0&&(l=l%Bh+Bh),l>jh?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=s):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Yh)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};be.prototype=we.prototype={constructor:be,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var Hh=we.prototype;Se.prototype=Ee.prototype={constructor:Se,has:Hh.has,add:function(t){return t+="",this["$"+t]=t,this},remove:Hh.remove,clear:Hh.clear,values:Hh.keys,size:Hh.size,empty:Hh.empty,each:Hh.each};var Xh=function(t){function n(t,n){function e(){if(f>=s)return a;if(i)return i=!1,u;var n,e=f;if(34===t.charCodeAt(e)){for(var r=e;r++<s;)if(34===t.charCodeAt(r)){if(34!==t.charCodeAt(r+1))break;++r}return f=r+2,13===(n=t.charCodeAt(r+1))?(i=!0,10===t.charCodeAt(r+2)&&++f):10===n&&(i=!0),t.slice(e+1,r).replace(/""/g,'"')}for(;f<s;){var c=1;if(10===(n=t.charCodeAt(f++)))i=!0;else if(13===n)i=!0,10===t.charCodeAt(f)&&(++f,++c);else if(n!==o)continue;return t.slice(e,f-c)}return t.slice(e)}for(var r,i,u={},a={},c=[],s=t.length,f=0,l=0;(r=e())!==a;){for(var h=[];r!==u&&r!==a;)h.push(r),r=e();n&&null==(h=n(h,l++))||c.push(h)}return c}function e(n){return n.map(r).join(t)}function r(t){return null==t?"":i.test(t+="")?'"'+t.replace(/\"/g,'""')+'"':t}var i=new RegExp('["'+t+"\n\r]"),o=t.charCodeAt(0);return{parse:function(t,e){var r,i,o=n(t,function(t,n){if(r)return r(t,n-1);i=t,r=e?Ce(t,e):Ae(t)});return o.columns=i,o},parseRows:n,format:function(n,e){return null==e&&(e=ze(n)),[e.map(r).join(t)].concat(n.map(function(n){return e.map(function(t){return r(n[t])}).join(t)})).join("\n")},formatRows:function(t){return t.map(e).join("\n")}}},$h=Xh(","),Vh=$h.parse,Wh=$h.parseRows,Zh=$h.format,Gh=$h.formatRows,Jh=Xh("\t"),Qh=Jh.parse,Kh=Jh.parseRows,tp=Jh.format,np=Jh.formatRows,ep=function(t){return function(){return t}},rp=function(){return 1e-6*(Math.random()-.5)},ip=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i},op=qe.prototype=Ue.prototype;op.copy=function(){var t,n,e=new Ue(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=De(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=De(n));return e},op.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return Pe(this.cover(n,e),n,e,t)},op.addAll=function(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,s=1/0,f=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(u[e]=r,a[e]=i,r<c&&(c=r),r>f&&(f=r),i<s&&(s=i),i>l&&(l=i));for(f<c&&(c=this._x0,f=this._x1),l<s&&(s=this._y0,l=this._y1),this.cover(c,s).cover(f,l),e=0;e<o;++e)Pe(this,u[e],a[e],t[e]);return this},op.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{if(!(e>t||t>i||r>n||n>o))return this;var u,a,c=i-e,s=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,o=r+c,t>i||n>o);break;case 1:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,o=r+c,e>t||n>o);break;case 2:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,r=o-c,t>i||r>n);break;case 3:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,r=o-c,e>t||r>n)}this._root&&this._root.length&&(this._root=s)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},op.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},op.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},op.find=function(t,n,e){var r,i,o,u,a,c,s,f=this._x0,l=this._y0,h=this._x1,p=this._y1,d=[],v=this._root;for(v&&d.push(new ip(v,f,l,h,p)),null==e?e=1/0:(f=t-e,l=n-e,h=t+e,p=n+e,e*=e);c=d.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>p||(u=c.x1)<f||(a=c.y1)<l))if(v.length){var _=(i+u)/2,y=(o+a)/2;d.push(new ip(v[3],_,y,u,a),new ip(v[2],i,y,_,a),new ip(v[1],_,o,u,y),new ip(v[0],i,o,_,y)),(s=(n>=y)<<1|t>=_)&&(c=d[d.length-1],d[d.length-1]=d[d.length-1-s],d[d.length-1-s]=c)}else{var g=t-+this._x.call(null,v.data),m=n-+this._y.call(null,v.data),x=g*g+m*m;if(x<e){var b=Math.sqrt(e=x);f=t-b,l=n-b,h=t+b,p=n+b,r=v.data}}return r},op.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(u=+this._y.call(null,t)))return this;var n,e,r,i,o,u,a,c,s,f,l,h,p=this._root,d=this._x0,v=this._y0,_=this._x1,y=this._y1;if(!p)return this;if(p.length)for(;;){if((s=o>=(a=(d+_)/2))?d=a:_=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=p,!(p=p[l=f<<1|s]))return this;if(!p.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;p.data!==t;)if(r=p,!(p=p.next))return this;return(i=p.next)&&delete p.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(p=n[0]||n[1]||n[2]||n[3])&&p===(n[3]||n[2]||n[1]||n[0])&&!p.length&&(e?e[h]=p:this._root=p),this):(this._root=i,this)},op.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},op.root=function(){return this._root},op.size=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},op.visit=function(t){var n,e,r,i,o,u,a=[],c=this._root;for(c&&a.push(new ip(c,this._x0,this._y0,this._x1,this._y1));n=a.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,u=n.y1)&&c.length){var s=(r+o)/2,f=(i+u)/2;(e=c[3])&&a.push(new ip(e,s,f,o,u)),(e=c[2])&&a.push(new ip(e,r,f,s,u)),(e=c[1])&&a.push(new ip(e,s,i,o,f)),(e=c[0])&&a.push(new ip(e,r,i,s,f))}return this},op.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new ip(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,u=n.x0,a=n.y0,c=n.x1,s=n.y1,f=(u+c)/2,l=(a+s)/2;(o=i[0])&&e.push(new ip(o,u,a,f,l)),(o=i[1])&&e.push(new ip(o,f,a,c,l)),(o=i[2])&&e.push(new ip(o,u,l,f,s)),(o=i[3])&&e.push(new ip(o,f,l,c,s))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},op.x=function(t){return arguments.length?(this._x=t,this):this._x},op.y=function(t){return arguments.length?(this._y=t,this):this._y};var up,ap=10,cp=Math.PI*(3-Math.sqrt(5)),sp=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},fp=function(t){return(t=sp(Math.abs(t)))?t[1]:NaN},lp=function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}},hp=function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}},pp=function(t,n){var e=sp(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},dp={"":function(t,n){t:for(var e,r=(t=t.toPrecision(n)).length,i=1,o=-1;i<r;++i)switch(t[i]){case".":o=e=i;break;case"0":0===o&&(o=i),e=i;break;case"e":break t;default:o>0&&(o=0)}return o>0?t.slice(0,o)+t.slice(e+1):t},"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return pp(100*t,n)},r:pp,s:function(t,n){var e=sp(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(up=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+sp(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},vp=/^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;He.prototype=Xe.prototype,Xe.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var _p,yp=function(t){return t},gp=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],mp=function(t){function n(t){function n(t){var n,r,u,f=_,x=y;if("c"===v)x=g(t)+x,t="";else{var b=(t=+t)<0;if(t=g(Math.abs(t),d),b&&0==+t&&(b=!1),f=(b?"("===s?s:"-":"-"===s||"("===s?"":s)+f,x=x+("s"===v?gp[8+up/3]:"")+(b&&"("===s?")":""),m)for(n=-1,r=t.length;++n<r;)if(48>(u=t.charCodeAt(n))||u>57){x=(46===u?i+t.slice(n+1):t.slice(n))+x,t=t.slice(0,n);break}}p&&!l&&(t=e(t,1/0));var w=f.length+t.length+x.length,M=w<h?new Array(h-w+1).join(a):"";switch(p&&l&&(t=e(M+t,M.length?h-x.length:1/0),M=""),c){case"<":t=f+t+x+M;break;case"=":t=f+M+t+x;break;case"^":t=M.slice(0,w=M.length>>1)+f+t+x+M.slice(w);break;default:t=M+f+t+x}return o(t)}var a=(t=He(t)).fill,c=t.align,s=t.sign,f=t.symbol,l=t.zero,h=t.width,p=t.comma,d=t.precision,v=t.type,_="$"===f?r[0]:"#"===f&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",y="$"===f?r[1]:/[%p]/.test(v)?u:"",g=dp[v],m=!v||/[defgprs%]/.test(v);return d=null==d?v?6:12:/[gprs]/.test(v)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),n.toString=function(){return t+""},n}var e=t.grouping&&t.thousands?lp(t.grouping,t.thousands):yp,r=t.currency,i=t.decimal,o=t.numerals?hp(t.numerals):yp,u=t.percent||"%";return{format:n,formatPrefix:function(t,e){var r=n((t=He(t),t.type="f",t)),i=3*Math.max(-8,Math.min(8,Math.floor(fp(e)/3))),o=Math.pow(10,-i),u=gp[8+i/3];return function(t){return r(o*t)+u}}}};$e({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var xp=function(t){return Math.max(0,-fp(Math.abs(t)))},bp=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(fp(n)/3)))-fp(Math.abs(t)))},wp=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,fp(n)-fp(t))+1},Mp=function(){return new Ve};Ve.prototype={constructor:Ve,reset:function(){this.s=this.t=0},add:function(t){We(nd,t,this.t),We(this,nd.s,this.s),this.s?this.t+=nd.t:this.s=nd.t},valueOf:function(){return this.s}};var Tp,kp,Np,Sp,Ep,Ap,Cp,zp,Pp,Rp,Lp,qp,Up,Dp,Op,Fp,Ip,Yp,Bp,jp,Hp,Xp,$p,Vp,Wp,Zp,Gp,Jp,Qp,Kp,td,nd=new Ve,ed=1e-6,rd=Math.PI,id=rd/2,od=rd/4,ud=2*rd,ad=180/rd,cd=rd/180,sd=Math.abs,fd=Math.atan,ld=Math.atan2,hd=Math.cos,pd=Math.ceil,dd=Math.exp,vd=Math.log,_d=Math.pow,yd=Math.sin,gd=Math.sign||function(t){return t>0?1:t<0?-1:0},md=Math.sqrt,xd=Math.tan,bd={Feature:function(t,n){Ke(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)Ke(e[r].geometry,n)}},wd={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){tr(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)tr(e[r],n,0)},Polygon:function(t,n){nr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)nr(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)Ke(e[r],n)}},Md=function(t,n){t&&bd.hasOwnProperty(t.type)?bd[t.type](t,n):Ke(t,n)},Td=Mp(),kd=Mp(),Nd={point:Qe,lineStart:Qe,lineEnd:Qe,polygonStart:function(){Td.reset(),Nd.lineStart=er,Nd.lineEnd=rr},polygonEnd:function(){var t=+Td;kd.add(t<0?ud+t:t),this.lineStart=this.lineEnd=this.point=Qe},sphere:function(){kd.add(ud)}},Sd=Mp(),Ed={point:pr,lineStart:vr,lineEnd:_r,polygonStart:function(){Ed.point=yr,Ed.lineStart=gr,Ed.lineEnd=mr,Sd.reset(),Nd.polygonStart()},polygonEnd:function(){Nd.polygonEnd(),Ed.point=pr,Ed.lineStart=vr,Ed.lineEnd=_r,Td<0?(Ap=-(zp=180),Cp=-(Pp=90)):Sd>ed?Pp=90:Sd<-ed&&(Cp=-90),Op[0]=Ap,Op[1]=zp}},Ad={sphere:Qe,point:Mr,lineStart:kr,lineEnd:Er,polygonStart:function(){Ad.lineStart=Ar,Ad.lineEnd=Cr},polygonEnd:function(){Ad.lineStart=kr,Ad.lineEnd=Er}},Cd=function(t){return function(){return t}},zd=function(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e};Rr.invert=Rr;var Pd,Rd,Ld,qd,Ud,Dd,Od,Fd,Id,Yd,Bd,jd=function(t){function n(n){return n=t(n[0]*cd,n[1]*cd),n[0]*=ad,n[1]*=ad,n}return t=Lr(t[0]*cd,t[1]*cd,t.length>2?t[2]*cd:0),n.invert=function(n){return n=t.invert(n[0]*cd,n[1]*cd),n[0]*=ad,n[1]*=ad,n},n},Hd=function(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:Qe,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}},Xd=function(t,n,e,r,i,o){var u,a=t[0],c=t[1],s=0,f=1,l=n[0]-a,h=n[1]-c;if(u=e-a,l||!(u>0)){if(u/=l,l<0){if(u<s)return;u<f&&(f=u)}else if(l>0){if(u>f)return;u>s&&(s=u)}if(u=i-a,l||!(u<0)){if(u/=l,l<0){if(u>f)return;u>s&&(s=u)}else if(l>0){if(u<s)return;u<f&&(f=u)}if(u=r-c,h||!(u>0)){if(u/=h,h<0){if(u<s)return;u<f&&(f=u)}else if(h>0){if(u>f)return;u>s&&(s=u)}if(u=o-c,h||!(u<0)){if(u/=h,h<0){if(u>f)return;u>s&&(s=u)}else if(h>0){if(u<s)return;u<f&&(f=u)}return s>0&&(t[0]=a+s*l,t[1]=c+s*h),f<1&&(n[0]=a+f*l,n[1]=c+f*h),!0}}}}},$d=function(t,n){return sd(t[0]-n[0])<ed&&sd(t[1]-n[1])<ed},Vd=function(t,n,e,r,i){var o,u,a=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],u=t[n];if($d(r,u)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);i.lineEnd()}else a.push(e=new Ir(r,t,null,!0)),c.push(e.o=new Ir(r,null,e,!1)),a.push(e=new Ir(u,t,null,!1)),c.push(e.o=new Ir(u,null,e,!0))}}),a.length){for(c.sort(n),Yr(a),Yr(c),o=0,u=c.length;o<u;++o)c[o].e=e=!e;for(var s,f,l=a[0];;){for(var h=l,p=!0;h.v;)if((h=h.n)===l)return;s=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(p)for(o=0,u=s.length;o<u;++o)i.point((f=s[o])[0],f[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(p)for(s=h.p.z,o=s.length-1;o>=0;--o)i.point((f=s[o])[0],f[1]);else r(h.x,h.p.x,-1,i);h=h.p}s=(h=h.o).z,p=!p}while(!h.v);i.lineEnd()}}},Wd=1e9,Zd=-Wd,Gd=Mp(),Jd=function(t,n){var e=n[0],r=n[1],i=[yd(e),-hd(e),0],o=0,u=0;Gd.reset();for(var a=0,c=t.length;a<c;++a)if(f=(s=t[a]).length)for(var s,f,l=s[f-1],h=l[0],p=l[1]/2+od,d=yd(p),v=hd(p),_=0;_<f;++_,h=g,d=x,v=b,l=y){var y=s[_],g=y[0],m=y[1]/2+od,x=yd(m),b=hd(m),w=g-h,M=w>=0?1:-1,T=M*w,k=T>rd,N=d*x;if(Gd.add(ld(N*M*yd(T),v*b+N*hd(T))),o+=k?w+M*ud:w,k^h>=e^g>=e){var S=sr(ar(l),ar(y));hr(S);var E=sr(i,S);hr(E);var A=(k^w>=0?-1:1)*Ge(E[2]);(r>A||r===A&&(S[0]||S[1]))&&(u+=k^w>=0?1:-1)}}return(o<-ed||o<ed&&Gd<-ed)^1&u},Qd=Mp(),Kd={sphere:Qe,point:Qe,lineStart:function(){Kd.point=Hr,Kd.lineEnd=jr},lineEnd:Qe,polygonStart:Qe,polygonEnd:Qe},tv=function(t){return Qd.reset(),Md(t,Kd),+Qd},nv=[null,null],ev={type:"LineString",coordinates:nv},rv=function(t,n){return nv[0]=t,nv[1]=n,tv(ev)},iv={Feature:function(t,n){return $r(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if($r(e[r].geometry,n))return!0;return!1}},ov={Sphere:function(){return!0},Point:function(t,n){return Vr(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Vr(e[r],n))return!0;return!1},LineString:function(t,n){return Wr(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Wr(e[r],n))return!0;return!1},Polygon:function(t,n){return Zr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Zr(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if($r(e[r],n))return!0;return!1}},uv=function(t){return t},av=Mp(),cv=Mp(),sv={point:Qe,lineStart:Qe,lineEnd:Qe,polygonStart:function(){sv.lineStart=ni,sv.lineEnd=ii},polygonEnd:function(){sv.lineStart=sv.lineEnd=sv.point=Qe,av.add(sd(cv)),cv.reset()},result:function(){var t=av/2;return av.reset(),t}},fv=1/0,lv=fv,hv=-fv,pv=hv,dv={point:function(t,n){t<fv&&(fv=t),t>hv&&(hv=t),n<lv&&(lv=n),n>pv&&(pv=n)},lineStart:Qe,lineEnd:Qe,polygonStart:Qe,polygonEnd:Qe,result:function(){var t=[[fv,lv],[hv,pv]];return hv=pv=-(lv=fv=1/0),t}},vv=0,_v=0,yv=0,gv=0,mv=0,xv=0,bv=0,wv=0,Mv=0,Tv={point:oi,lineStart:ui,lineEnd:si,polygonStart:function(){Tv.lineStart=fi,Tv.lineEnd=li},polygonEnd:function(){Tv.point=oi,Tv.lineStart=ui,Tv.lineEnd=si},result:function(){var t=Mv?[bv/Mv,wv/Mv]:xv?[gv/xv,mv/xv]:yv?[vv/yv,_v/yv]:[NaN,NaN];return vv=_v=yv=gv=mv=xv=bv=wv=Mv=0,t}};di.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,ud)}},result:Qe};var kv,Nv,Sv,Ev,Av,Cv=Mp(),zv={point:Qe,lineStart:function(){zv.point=vi},lineEnd:function(){kv&&_i(Nv,Sv),zv.point=Qe},polygonStart:function(){kv=!0},polygonEnd:function(){kv=null},result:function(){var t=+Cv;return Cv.reset(),t}};yi.prototype={_radius:4.5,_circle:gi(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=gi(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}};var Pv=function(t,n,e,r){return function(i,o){function u(n,e){var r=i(n,e);t(n=r[0],e=r[1])&&o.point(n,e)}function a(t,n){var e=i(t,n);_.point(e[0],e[1])}function c(){b.point=a,_.lineStart()}function s(){b.point=u,_.lineEnd()}function f(t,n){v.push([t,n]);var e=i(t,n);m.point(e[0],e[1])}function l(){m.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),m.lineEnd();var t,n,e,r,i=m.clean(),u=g.result(),a=u.length;if(v.pop(),p.push(v),v=null,a)if(1&i){if(e=u[0],(n=e.length-1)>0){for(x||(o.polygonStart(),x=!0),o.lineStart(),t=0;t<n;++t)o.point((r=e[t])[0],r[1]);o.lineEnd()}}else a>1&&2&i&&u.push(u.pop().concat(u.shift())),d.push(u.filter(mi))}var p,d,v,_=n(o),y=i.invert(r[0],r[1]),g=Hd(),m=n(g),x=!1,b={point:u,lineStart:c,lineEnd:s,polygonStart:function(){b.point=f,b.lineStart=l,b.lineEnd=h,d=[],p=[]},polygonEnd:function(){b.point=u,b.lineStart=c,b.lineEnd=s,d=Cs(d);var t=Jd(p,y);d.length?(x||(o.polygonStart(),x=!0),Vd(d,xi,t,e,o)):t&&(x||(o.polygonStart(),x=!0),o.lineStart(),e(null,null,1,o),o.lineEnd()),x&&(o.polygonEnd(),x=!1),d=p=null},sphere:function(){o.polygonStart(),o.lineStart(),e(null,null,1,o),o.lineEnd(),o.polygonEnd()}};return b}},Rv=Pv(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,u){var a=o>0?rd:-rd,c=sd(o-e);sd(c-rd)<ed?(t.point(e,r=(r+u)/2>0?id:-id),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),t.point(o,r),n=0):i!==a&&c>=rd&&(sd(e-i)<ed&&(e-=i*ed),sd(o-a)<ed&&(o-=a*ed),r=bi(e,r,o,u),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),n=0),t.point(e=o,r=u),i=a},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*id,r.point(-rd,i),r.point(0,i),r.point(rd,i),r.point(rd,0),r.point(rd,-i),r.point(0,-i),r.point(-rd,-i),r.point(-rd,0),r.point(-rd,i);else if(sd(t[0]-n[0])>ed){var o=t[0]<n[0]?rd:-rd;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])},[-rd,-id]),Lv=function(t,n){function e(t,n){return hd(t)*hd(n)>o}function r(t,n,e){var r=[1,0,0],i=sr(ar(t),ar(n)),u=cr(i,i),a=i[0],c=u-a*a;if(!c)return!e&&t;var s=o*u/c,f=-o*a/c,l=sr(r,i),h=lr(r,s);fr(h,lr(i,f));var p=l,d=cr(h,p),v=cr(p,p),_=d*d-v*(cr(h,h)-1);if(!(_<0)){var y=md(_),g=lr(p,(-d-y)/v);if(fr(g,h),g=ur(g),!e)return g;var m,x=t[0],b=n[0],w=t[1],M=n[1];b<x&&(m=x,x=b,b=m);var T=b-x,k=sd(T-rd)<ed,N=k||T<ed;if(!k&&M<w&&(m=w,w=M,M=m),N?k?w+M>0^g[1]<(sd(g[0]-x)<ed?w:M):w<=g[1]&&g[1]<=M:T>rd^(x<=g[0]&&g[0]<=b)){var S=lr(p,(-d+y)/v);return fr(S,h),[g,ur(S)]}}}function i(n,e){var r=u?t:rd-t,i=0;return n<-r?i|=1:n>r&&(i|=2),e<-r?i|=4:e>r&&(i|=8),i}var o=hd(t),u=o>0,a=sd(o)>ed;return Pv(e,function(t){var n,o,c,s,f;return{lineStart:function(){s=c=!1,f=1},point:function(l,h){var p,d=[l,h],v=e(l,h),_=u?v?0:i(l,h):v?i(l+(l<0?rd:-rd),h):0;if(!n&&(s=c=v)&&t.lineStart(),v!==c&&(!(p=r(n,d))||$d(n,p)||$d(d,p))&&(d[0]+=ed,d[1]+=ed,v=e(d[0],d[1])),v!==c)f=0,v?(t.lineStart(),p=r(d,n),t.point(p[0],p[1])):(p=r(n,d),t.point(p[0],p[1]),t.lineEnd()),n=p;else if(a&&n&&u^v){var y;_&o||!(y=r(d,n,!0))||(f=0,u?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&$d(n,d)||t.point(d[0],d[1]),n=d,c=v,o=_},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return f|(s&&c)<<1}}},function(e,r,i,o){Or(o,t,n,i,e,r)},u?[0,-t]:[-rd,t-rd])};Mi.prototype={constructor:Mi,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var qv=16,Uv=hd(30*cd),Dv=function(t,n){return+n?Si(t,n):Ni(t)},Ov=wi({point:function(t,n){this.stream.point(t*cd,n*cd)}}),Fv=function(){return Ci(Pi).scale(155.424).center([0,33.6442])},Iv=function(){return Fv().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])},Yv=Li(function(t){return md(2/(1+t))});Yv.invert=qi(function(t){return 2*Ge(t/2)});var Bv=Li(function(t){return(t=Ze(t))&&t/yd(t)});Bv.invert=qi(function(t){return t});Ui.invert=function(t,n){return[t,2*fd(dd(n))-id]};Ii.invert=Ii;Bi.invert=qi(fd);Hi.invert=qi(Ge);Xi.invert=qi(function(t){return 2*fd(t)});$i.invert=function(t,n){return[-n,2*fd(dd(t))-id]};uo.prototype=eo.prototype={constructor:uo,count:function(){return this.eachAfter(to)},each:function(t){var n,e,r,i,o=this,u=[o];do{for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)u.push(e[r])}while(u.length);return this},eachAfter:function(t){for(var n,e,r,i=this,o=[i],u=[];i=o.pop();)if(u.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=u.pop();)t(i);return this},eachBefore:function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=no(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return eo(this).eachBefore(io)}};var jv=Array.prototype.slice,Hv=function(t){for(var n,e,r=0,i=(t=ao(jv.call(t))).length,o=[];r<i;)n=t[r],e&&fo(e,n)?++r:(e=ho(o=co(o,n)),r=0);return e},Xv=function(t){return function(){return t}},$v=function(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)},Vv=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(r-n)/t.value;++a<c;)(o=u[a]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*s},Wv="$",Zv={depth:-1},Gv={};Do.prototype=Object.create(uo.prototype);var Jv=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(i-e)/t.value;++a<c;)(o=u[a]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*s},Qv=(1+Math.sqrt(5))/2,Kv=function t(n){function e(t,e,r,i,o){Fo(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Qv),t_=function t(n){function e(t,e,r,i,o){if((u=t._squarify)&&u.ratio===n)for(var u,a,c,s,f,l=-1,h=u.length,p=t.value;++l<h;){for(c=(a=u[l]).children,s=a.value=0,f=c.length;s<f;++s)a.value+=c[s].value;a.dice?Vv(a,e,r,i,r+=(o-r)*a.value/p):Jv(a,e,r,e+=(i-e)*a.value/p,o),p-=a.value}else t._squarify=u=Fo(n,t,e,r,i,o),u.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Qv),n_=function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])},e_=[].slice,r_={};Bo.prototype=Wo.prototype={constructor:Bo,defer:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("defer after await");if(null!=this._error)return this;var n=e_.call(arguments,1);return n.push(t),++this._waiting,this._tasks.push(n),jo(this),this},abort:function(){return null==this._error&&$o(this,new Error("abort")),this},await:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=function(n,e){t.apply(null,[n].concat(e))},Vo(this),this},awaitAll:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=t,Vo(this),this}};var i_=function(){return Math.random()},o_=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(i_),u_=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(i_),a_=function t(n){function e(){var t=u_.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(i_),c_=function t(n){function e(t){return function(){for(var e=0,r=0;r<t;++r)e+=n();return e}}return e.source=t,e}(i_),s_=function t(n){function e(t){var e=c_.source(n)(t);return function(){return e()/t}}return e.source=t,e}(i_),f_=function t(n){function e(t){return function(){return-Math.log(1-n())/t}}return e.source=t,e}(i_),l_=function(t,n){function e(t){var n,e=s.status;if(!e&&Go(s)||e>=200&&e<300||304===e){if(o)try{n=o.call(r,s)}catch(t){return void a.call("error",r,t)}else n=s;a.call("load",r,n)}else a.call("error",r,t)}var r,i,o,u,a=h("beforesend","progress","load","error"),c=we(),s=new XMLHttpRequest,f=null,l=null,p=0;if("undefined"==typeof XDomainRequest||"withCredentials"in s||!/^(http(s)?:)?\/\//.test(t)||(s=new XDomainRequest),"onload"in s?s.onload=s.onerror=s.ontimeout=e:s.onreadystatechange=function(t){s.readyState>3&&e(t)},s.onprogress=function(t){a.call("progress",r,t)},r={header:function(t,n){return t=(t+"").toLowerCase(),arguments.length<2?c.get(t):(null==n?c.remove(t):c.set(t,n+""),r)},mimeType:function(t){return arguments.length?(i=null==t?null:t+"",r):i},responseType:function(t){return arguments.length?(u=t,r):u},timeout:function(t){return arguments.length?(p=+t,r):p},user:function(t){return arguments.length<1?f:(f=null==t?null:t+"",r)},password:function(t){return arguments.length<1?l:(l=null==t?null:t+"",r)},response:function(t){return o=t,r},get:function(t,n){return r.send("GET",t,n)},post:function(t,n){return r.send("POST",t,n)},send:function(n,e,o){return s.open(n,t,!0,f,l),null==i||c.has("accept")||c.set("accept",i+",*/*"),s.setRequestHeader&&c.each(function(t,n){s.setRequestHeader(n,t)}),null!=i&&s.overrideMimeType&&s.overrideMimeType(i),null!=u&&(s.responseType=u),p>0&&(s.timeout=p),null==o&&"function"==typeof e&&(o=e,e=null),null!=o&&1===o.length&&(o=Zo(o)),null!=o&&r.on("error",o).on("load",function(t){o(null,t)}),a.call("beforesend",r,s),s.send(null==e?null:e),r},abort:function(){return s.abort(),r},on:function(){var t=a.on.apply(a,arguments);return t===a?r:t}},null!=n){if("function"!=typeof n)throw new Error("invalid callback: "+n);return r.get(n)}return r},h_=function(t,n){return function(e,r){var i=l_(e).mimeType(t).response(n);if(null!=r){if("function"!=typeof r)throw new Error("invalid callback: "+r);return i.get(r)}return i}},p_=h_("text/html",function(t){return document.createRange().createContextualFragment(t.responseText)}),d_=h_("application/json",function(t){return JSON.parse(t.responseText)}),v_=h_("text/plain",function(t){return t.responseText}),__=h_("application/xml",function(t){var n=t.responseXML;if(!n)throw new Error("parse error");return n}),y_=function(t,n){return function(e,r,i){arguments.length<3&&(i=r,r=null);var o=l_(e).mimeType(t);return o.row=function(t){return arguments.length?o.response(Jo(n,r=t)):r},o.row(r),i?o.get(i):o}},g_=y_("text/csv",Vh),m_=y_("text/tab-separated-values",Qh),x_=Array.prototype,b_=x_.map,w_=x_.slice,M_={name:"implicit"},T_=function(t){return function(){return t}},k_=function(t){return+t},N_=[0,1],S_=function(n,e,r){var o,u=n[0],a=n[n.length-1],c=i(u,a,null==e?10:e);switch((r=He(null==r?",f":r)).type){case"s":var s=Math.max(Math.abs(u),Math.abs(a));return null!=r.precision||isNaN(o=bp(c,s))||(r.precision=o),t.formatPrefix(r,s);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(o=wp(c,Math.max(Math.abs(u),Math.abs(a))))||(r.precision=o-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(o=xp(c))||(r.precision=o-2*("%"===r.type))}return t.format(r)},E_=function(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],u=t[i];return u<o&&(e=r,r=i,i=e,e=o,o=u,u=e),t[r]=n.floor(o),t[i]=n.ceil(u),t},A_=new Date,C_=new Date,z_=Mu(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});z_.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Mu(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):z_:null};var P_=z_.range,R_=6e4,L_=6048e5,q_=Mu(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),U_=q_.range,D_=Mu(function(t){t.setTime(Math.floor(t/R_)*R_)},function(t,n){t.setTime(+t+n*R_)},function(t,n){return(n-t)/R_},function(t){return t.getMinutes()}),O_=D_.range,F_=Mu(function(t){var n=t.getTimezoneOffset()*R_%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),I_=F_.range,Y_=Mu(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*R_)/864e5},function(t){return t.getDate()-1}),B_=Y_.range,j_=Tu(0),H_=Tu(1),X_=Tu(2),$_=Tu(3),V_=Tu(4),W_=Tu(5),Z_=Tu(6),G_=j_.range,J_=H_.range,Q_=X_.range,K_=$_.range,ty=V_.range,ny=W_.range,ey=Z_.range,ry=Mu(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),iy=ry.range,oy=Mu(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});oy.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Mu(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var uy=oy.range,ay=Mu(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*R_)},function(t,n){return(n-t)/R_},function(t){return t.getUTCMinutes()}),cy=ay.range,sy=Mu(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),fy=sy.range,ly=Mu(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),hy=ly.range,py=ku(0),dy=ku(1),vy=ku(2),_y=ku(3),yy=ku(4),gy=ku(5),my=ku(6),xy=py.range,by=dy.range,wy=vy.range,My=_y.range,Ty=yy.range,ky=gy.range,Ny=my.range,Sy=Mu(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),Ey=Sy.range,Ay=Mu(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});Ay.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Mu(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Cy,zy=Ay.range,Py={"-":"",_:" ",0:"0"},Ry=/^\s*\d+/,Ly=/^%/,qy=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;Ma({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Uy=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ"),Dy=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),Oy=1e3,Fy=60*Oy,Iy=60*Fy,Yy=24*Iy,By=7*Yy,jy=30*Yy,Hy=365*Yy,Xy=function(t){return t.match(/.{6}/g).map(function(t){return"#"+t})},$y=Xy("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),Vy=Xy("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6"),Wy=Xy("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9"),Zy=Xy("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5"),Gy=wl($t(300,.5,0),$t(-240,.5,1)),Jy=wl($t(-100,.75,.35),$t(80,1.5,.8)),Qy=wl($t(260,.75,.35),$t(80,1.5,.8)),Ky=$t(),tg=Sa(Xy("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),ng=Sa(Xy("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),eg=Sa(Xy("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),rg=Sa(Xy("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921")),ig=function(t){return function(){return t}},og=Math.abs,ug=Math.atan2,ag=Math.cos,cg=Math.max,sg=Math.min,fg=Math.sin,lg=Math.sqrt,hg=1e-12,pg=Math.PI,dg=pg/2,vg=2*pg;Oa.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var _g=function(t){return new Oa(t)},yg=function(){function t(t){var a,c,s,f=t.length,l=!1;for(null==i&&(u=o(s=ve())),a=0;a<=f;++a)!(a<f&&r(c=t[a],a,t))===l&&((l=!l)?u.lineStart():u.lineEnd()),l&&u.point(+n(c,a,t),+e(c,a,t));if(s)return u=null,s+""||null}var n=Fa,e=Ia,r=ig(!0),i=null,o=_g,u=null;return t.x=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.defined=function(n){return arguments.length?(r="function"==typeof n?n:ig(!!n),t):r},t.curve=function(n){return arguments.length?(o=n,null!=i&&(u=o(i)),t):o},t.context=function(n){return arguments.length?(null==n?i=u=null:u=o(i=n),t):i},t},gg=function(){function t(t){var n,f,l,h,p,d=t.length,v=!1,_=new Array(d),y=new Array(d);for(null==a&&(s=c(p=ve())),n=0;n<=d;++n){if(!(n<d&&u(h=t[n],n,t))===v)if(v=!v)f=n,s.areaStart(),s.lineStart();else{for(s.lineEnd(),s.lineStart(),l=n-1;l>=f;--l)s.point(_[l],y[l]);s.lineEnd(),s.areaEnd()}v&&(_[n]=+e(h,n,t),y[n]=+i(h,n,t),s.point(r?+r(h,n,t):_[n],o?+o(h,n,t):y[n]))}if(p)return s=null,p+""||null}function n(){return yg().defined(u).curve(c).context(a)}var e=Fa,r=null,i=ig(0),o=Ia,u=ig(!0),a=null,c=_g,s=null;return t.x=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),r=null,t):e},t.x0=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.x1=function(n){return arguments.length?(r=null==n?null:"function"==typeof n?n:ig(+n),t):r},t.y=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),o=null,t):i},t.y0=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.y1=function(n){return arguments.length?(o=null==n?null:"function"==typeof n?n:ig(+n),t):o},t.lineX0=t.lineY0=function(){return n().x(e).y(i)},t.lineY1=function(){return n().x(e).y(o)},t.lineX1=function(){return n().x(r).y(i)},t.defined=function(n){return arguments.length?(u="function"==typeof n?n:ig(!!n),t):u},t.curve=function(n){return arguments.length?(c=n,null!=a&&(s=c(a)),t):c},t.context=function(n){return arguments.length?(null==n?a=s=null:s=c(a=n),t):a},t},mg=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},xg=function(t){return t},bg=Ba(_g);Ya.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var wg=function(){return ja(yg().curve(bg))},Mg=function(){var t=gg().curve(bg),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return ja(e())},delete t.lineX0,t.lineEndAngle=function(){return ja(r())},delete t.lineX1,t.lineInnerRadius=function(){return ja(i())},delete t.lineY0,t.lineOuterRadius=function(){return ja(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Ba(t)):n()._curve},t},Tg=function(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]},kg=Array.prototype.slice,Ng={draw:function(t,n){var e=Math.sqrt(n/pg);t.moveTo(e,0),t.arc(0,0,e,0,vg)}},Sg={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},Eg=Math.sqrt(1/3),Ag=2*Eg,Cg={draw:function(t,n){var e=Math.sqrt(n/Ag),r=e*Eg;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},zg=Math.sin(pg/10)/Math.sin(7*pg/10),Pg=Math.sin(vg/10)*zg,Rg=-Math.cos(vg/10)*zg,Lg={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=Pg*e,i=Rg*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var u=vg*o/5,a=Math.cos(u),c=Math.sin(u);t.lineTo(c*e,-a*e),t.lineTo(a*r-c*i,c*r+a*i)}t.closePath()}},qg={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},Ug=Math.sqrt(3),Dg={draw:function(t,n){var e=-Math.sqrt(n/(3*Ug));t.moveTo(0,2*e),t.lineTo(-Ug*e,-e),t.lineTo(Ug*e,-e),t.closePath()}},Og=-.5,Fg=Math.sqrt(3)/2,Ig=1/Math.sqrt(12),Yg=3*(Ig/2+1),Bg={draw:function(t,n){var e=Math.sqrt(n/Yg),r=e/2,i=e*Ig,o=r,u=e*Ig+e,a=-o,c=u;t.moveTo(r,i),t.lineTo(o,u),t.lineTo(a,c),t.lineTo(Og*r-Fg*i,Fg*r+Og*i),t.lineTo(Og*o-Fg*u,Fg*o+Og*u),t.lineTo(Og*a-Fg*c,Fg*a+Og*c),t.lineTo(Og*r+Fg*i,Og*i-Fg*r),t.lineTo(Og*o+Fg*u,Og*u-Fg*o),t.lineTo(Og*a+Fg*c,Og*c-Fg*a),t.closePath()}},jg=[Ng,Sg,Cg,qg,Lg,Dg,Bg],Hg=function(){};Ja.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Ga(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};Qa.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};Ka.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};tc.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],u=t[e]-i,a=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*u),this._beta*n[c]+(1-this._beta)*(o+r*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Xg=function t(n){function e(t){return 1===n?new Ja(t):new tc(t,n)}return e.beta=function(n){return t(+n)},e}(.85);ec.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:nc(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var $g=function t(n){function e(t){return new ec(t,n)}return e.tension=function(n){return t(+n)},e}(0);rc.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Vg=function t(n){function e(t){return new rc(t,n)}return e.tension=function(n){return t(+n)},e}(0);ic.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Wg=function t(n){function e(t){return new ic(t,n)}return e.tension=function(n){return t(+n)},e}(0);uc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Zg=function t(n){function e(t){return n?new uc(t,n):new ec(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);ac.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Gg=function t(n){function e(t){return n?new ac(t,n):new rc(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);cc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Jg=function t(n){function e(t){return n?new cc(t,n):new ic(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);sc.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}};dc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:pc(this,this._t0,hc(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(t=+t,n=+n,t!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,pc(this,hc(this,e=lc(this,t,n)),e);break;default:pc(this,this._t0,e=lc(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(vc.prototype=Object.create(dc.prototype)).point=function(t,n){dc.prototype.point.call(this,n,t)},_c.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},yc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=gc(t),i=gc(n),o=0,u=1;u<e;++o,++u)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[u],n[u]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}};mc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var Qg=function(t,n){if((i=t.length)>1)for(var e,r,i,o=1,u=t[n[0]],a=u.length;o<i;++o)for(r=u,u=t[n[o]],e=0;e<a;++e)u[e][1]+=u[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]},Kg=function(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e},tm=function(t){var n=t.map(bc);return Kg(t).sort(function(t,e){return n[t]-n[e]})},nm=function(t){return function(){return t}};Tc.prototype={constructor:Tc,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=Ec(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(Nc(this,e),e=(t=e).U),e.C=!1,r.C=!0,Sc(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(Sc(this,e),e=(t=e).U),e.C=!1,r.C=!0,Nc(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,u=t.R;if(e=o?u?Ec(u):o:u,i?i.L===t?i.L=e:i.R=e:this._=e,o&&u?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==u?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=u,u.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,Nc(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,Sc(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,Nc(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,Sc(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,Nc(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,Sc(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var em,rm,im,om,um,am=[],cm=[],sm=1e-6,fm=1e-12;Kc.prototype={constructor:Kc,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return Dc(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,u,a=e.site,c=-1,s=n[i[o-1]],f=s.left===a?s.right:s.left;++c<o;)u=f,f=(s=n[i[c]]).left===a?s.right:s.left,u&&f&&r<u.index&&r<f.index&&Jc(a,u,f)<0&&t.push([a.data,u.data,f.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,u=o._found||0,a=o.cells.length;!(i=o.cells[u]);)if(++u>=a)return null;var c=t-i.site[0],s=n-i.site[1],f=c*c+s*s;do{i=o.cells[r=u],u=null,i.halfedges.forEach(function(e){var r=o.edges[e],a=r.left;if(a!==i.site&&a||(a=r.right)){var c=t-a[0],s=n-a[1],l=c*c+s*s;l<f&&(f=l,u=a.index)}})}while(null!==u);return o._found=r,null==e||f<=e*e?i.site:null}};var lm=function(t){return function(){return t}};ns.prototype={constructor:ns,scale:function(t){return 1===t?this:new ns(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ns(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var hm=new ns(1,0,0);es.prototype=ns.prototype;var pm=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()};t.version="4.10.0",t.bisect=hs,t.bisectRight=hs,t.bisectLeft=ps,t.ascending=ss,t.bisector=fs,t.cross=function(t,n,r){var i,o,u,a,c=t.length,s=n.length,f=new Array(c*s);for(null==r&&(r=e),i=u=0;i<c;++i)for(a=t[i],o=0;o<s;++o,++u)f[u]=r(a,n[o]);return f},t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=_s,t.extent=ys,t.histogram=function(){function t(t){var o,u,a=t.length,c=new Array(a);for(o=0;o<a;++o)c[o]=n(t[o],o,t);var s=e(c),f=s[0],l=s[1],h=r(c,f,l);Array.isArray(h)||(h=i(f,l,h),h=Ms(Math.ceil(f/h)*h,Math.floor(l/h)*h,h));for(var p=h.length;h[0]<=f;)h.shift(),--p;for(;h[p-1]>l;)h.pop(),--p;var d,v=new Array(p+1);for(o=0;o<=p;++o)(d=v[o]=[]).x0=o>0?h[o-1]:f,d.x1=o<p?h[o]:l;for(o=0;o<a;++o)f<=(u=c[o])&&u<=l&&v[hs(h,u,0,p)].push(t[o]);return v}var n=ws,e=ys,r=Es;return t.value=function(e){return arguments.length?(n="function"==typeof e?e:bs(e),t):n},t.domain=function(n){return arguments.length?(e="function"==typeof n?n:bs([n[0],n[1]]),t):e},t.thresholds=function(n){return arguments.length?(r="function"==typeof n?n:bs(Array.isArray(n)?ms.call(n):n),t):r},t},t.thresholdFreedmanDiaconis=function(t,n,e){return t=xs.call(t,ds).sort(ss),Math.ceil((e-n)/(2*(As(t,.75)-As(t,.25))*Math.pow(t.length,-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*_s(t)*Math.pow(t.length,-1/3)))},t.thresholdSturges=Es,t.max=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r},t.mean=function(t,n){var e,r=t.length,i=r,o=-1,u=0;if(null==n)for(;++o<r;)isNaN(e=ds(t[o]))?--i:u+=e;else for(;++o<r;)isNaN(e=ds(n(t[o],o,t)))?--i:u+=e;if(i)return u/i},t.median=function(t,n){var e,r=t.length,i=-1,o=[];if(null==n)for(;++i<r;)isNaN(e=ds(t[i]))||o.push(e);else for(;++i<r;)isNaN(e=ds(n(t[i],i,t)))||o.push(e);return As(o.sort(ss),.5)},t.merge=Cs,t.min=zs,t.pairs=function(t,n){null==n&&(n=e);for(var r=0,i=t.length-1,o=t[0],u=new Array(i<0?0:i);r<i;)u[r]=n(o,o=t[++r]);return u},t.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},t.quantile=As,t.range=Ms,t.scan=function(t,n){if(e=t.length){var e,r,i=0,o=0,u=t[o];for(null==n&&(n=ss);++i<e;)(n(r=t[i],u)<0||0!==n(u,u))&&(u=r,o=i);return 0===n(u,u)?o:void 0}},t.shuffle=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},t.sum=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},t.ticks=Ss,t.tickIncrement=r,t.tickStep=i,t.transpose=Ps,t.variance=vs,t.zip=function(){return Ps(arguments)},t.axisTop=function(t){return l(qs,t)},t.axisRight=function(t){return l(Us,t)},t.axisBottom=function(t){return l(Ds,t)},t.axisLeft=function(t){return l(Os,t)},t.brush=function(){return he(Sh)},t.brushX=function(){return he(kh)},t.brushY=function(){return he(Nh)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.chord=function(){function t(t){var o,u,a,c,s,f,l=t.length,h=[],p=Ms(l),d=[],v=[],_=v.groups=new Array(l),y=new Array(l*l);for(o=0,s=-1;++s<l;){for(u=0,f=-1;++f<l;)u+=t[s][f];h.push(u),d.push(Ms(l)),o+=u}for(e&&p.sort(function(t,n){return e(h[t],h[n])}),r&&d.forEach(function(n,e){n.sort(function(n,i){return r(t[e][n],t[e][i])})}),c=(o=Oh(0,Dh-n*l)/o)?n:Dh/l,u=0,s=-1;++s<l;){for(a=u,f=-1;++f<l;){var g=p[s],m=d[g][f],x=t[g][m],b=u,w=u+=x*o;y[m*l+g]={index:g,subindex:m,startAngle:b,endAngle:w,value:x}}_[g]={index:g,startAngle:a,endAngle:u,value:h[g]},u+=c}for(s=-1;++s<l;)for(f=s-1;++f<l;){var M=y[f*l+s],T=y[s*l+f];(M.value||T.value)&&v.push(M.value<T.value?{source:T,target:M}:{source:M,target:T})}return i?v.sort(i):v}var n=0,e=null,r=null,i=null;return t.padAngle=function(e){return arguments.length?(n=Oh(0,e),t):n},t.sortGroups=function(n){return arguments.length?(e=n,t):e},t.sortSubgroups=function(n){return arguments.length?(r=n,t):r},t.sortChords=function(n){return arguments.length?(null==n?i=null:(i=pe(n))._=n,t):i&&i._},t},t.ribbon=function(){function t(){var t,a=Fh.call(arguments),c=n.apply(this,a),s=e.apply(this,a),f=+r.apply(this,(a[0]=c,a)),l=i.apply(this,a)-Uh,h=o.apply(this,a)-Uh,p=f*Rh(l),d=f*Lh(l),v=+r.apply(this,(a[0]=s,a)),_=i.apply(this,a)-Uh,y=o.apply(this,a)-Uh;if(u||(u=t=ve()),u.moveTo(p,d),u.arc(0,0,f,l,h),l===_&&h===y||(u.quadraticCurveTo(0,0,v*Rh(_),v*Lh(_)),u.arc(0,0,v,_,y)),u.quadraticCurveTo(0,0,p,d),u.closePath(),t)return u=null,t+""||null}var n=_e,e=ye,r=ge,i=me,o=xe,u=null;return t.radius=function(n){return arguments.length?(r="function"==typeof n?n:Ih(+n),t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:Ih(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:Ih(+n),t):o},t.source=function(e){return arguments.length?(n=e,t):n},t.target=function(n){return arguments.length?(e=n,t):e},t.context=function(n){return arguments.length?(u=null==n?null:n,t):u},t},t.nest=function(){function t(n,i,u,a){if(i>=o.length)return null!=e&&n.sort(e),null!=r?r(n):n;for(var c,s,f,l=-1,h=n.length,p=o[i++],d=we(),v=u();++l<h;)(f=d.get(c=p(s=n[l])+""))?f.push(s):d.set(c,[s]);return d.each(function(n,e){a(v,e,t(n,i,u,a))}),v}function n(t,e){if(++e>o.length)return t;var i,a=u[e-1];return null!=r&&e>=o.length?i=t.entries():(i=[],t.each(function(t,r){i.push({key:r,values:n(t,e)})})),null!=a?i.sort(function(t,n){return a(t.key,n.key)}):i}var e,r,i,o=[],u=[];return i={object:function(n){return t(n,0,Me,Te)},map:function(n){return t(n,0,ke,Ne)},entries:function(e){return n(t(e,0,ke,Ne),0)},key:function(t){return o.push(t),i},sortKeys:function(t){return u[o.length-1]=t,i},sortValues:function(t){return e=t,i},rollup:function(t){return r=t,i}}},t.set=Ee,t.map=we,t.keys=function(t){var n=[];for(var e in t)n.push(e);return n},t.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},t.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},t.color=Tt,t.rgb=Et,t.hsl=Pt,t.lab=Ut,t.hcl=jt,t.cubehelix=$t,t.dispatch=h,t.drag=function(){function n(t){t.on("mousedown.drag",e).filter(bt).on("touchstart.drag",o).on("touchmove.drag",u).on("touchend.drag touchcancel.drag",a).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(){if(!p&&d.apply(this,arguments)){var n=c("mouse",v.apply(this,arguments),Ks,this,arguments);n&&(cf(t.event.view).on("mousemove.drag",r,!0).on("mouseup.drag",i,!0),lf(t.event.view),vt(),l=!1,s=t.event.clientX,f=t.event.clientY,n("start"))}}function r(){if(ff(),!l){var n=t.event.clientX-s,e=t.event.clientY-f;l=n*n+e*e>x}y.mouse("drag")}function i(){cf(t.event.view).on("mousemove.drag mouseup.drag",null),_t(t.event.view,l),ff(),y.mouse("end")}function o(){if(d.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=v.apply(this,arguments),o=r.length;for(n=0;n<o;++n)(e=c(r[n].identifier,i,sf,this,arguments))&&(vt(),e("start"))}}function u(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=y[r[n].identifier])&&(ff(),e("drag"))}function a(){var n,e,r=t.event.changedTouches,i=r.length;for(p&&clearTimeout(p),p=setTimeout(function(){p=null},500),n=0;n<i;++n)(e=y[r[n].identifier])&&(vt(),e("end"))}function c(e,r,i,o,u){var a,c,s,f=i(r,e),l=g.copy();if(N(new yt(n,"beforestart",a,e,m,f[0],f[1],0,0,l),function(){return null!=(t.event.subject=a=_.apply(o,u))&&(c=a.x-f[0]||0,s=a.y-f[1]||0,!0)}))return function t(h){var p,d=f;switch(h){case"start":y[e]=t,p=m++;break;case"end":delete y[e],--m;case"drag":f=i(r,e),p=m}N(new yt(n,h,a,e,p,f[0]+c,f[1]+s,f[0]-d[0],f[1]-d[1],l),l.apply,l,[h,o,u])}}var s,f,l,p,d=gt,v=mt,_=xt,y={},g=h("start","drag","end"),m=0,x=0;return n.filter=function(t){return arguments.length?(d="function"==typeof t?t:hf(!!t),n):d},n.container=function(t){return arguments.length?(v="function"==typeof t?t:hf(t),n):v},n.subject=function(t){return arguments.length?(_="function"==typeof t?t:hf(t),n):_},n.on=function(){var t=g.on.apply(g,arguments);return t===g?n:t},n.clickDistance=function(t){return arguments.length?(x=(t=+t)*t,n):Math.sqrt(x)},n},t.dragDisable=lf,t.dragEnable=_t,t.dsvFormat=Xh,t.csvParse=Vh,t.csvParseRows=Wh,t.csvFormat=Zh,t.csvFormatRows=Gh,t.tsvParse=Qh,t.tsvParseRows=Kh,t.tsvFormat=tp,t.tsvFormatRows=np,t.easeLinear=function(t){return+t},t.easeQuad=Kn,t.easeQuadIn=function(t){return t*t},t.easeQuadOut=function(t){return t*(2-t)},t.easeQuadInOut=Kn,t.easeCubic=te,t.easeCubicIn=function(t){return t*t*t},t.easeCubicOut=function(t){return--t*t*t+1},t.easeCubicInOut=te,t.easePoly=Gl,t.easePolyIn=Wl,t.easePolyOut=Zl,t.easePolyInOut=Gl,t.easeSin=ne,t.easeSinIn=function(t){return 1-Math.cos(t*Ql)},t.easeSinOut=function(t){return Math.sin(t*Ql)},t.easeSinInOut=ne,t.easeExp=ee,t.easeExpIn=function(t){return Math.pow(2,10*t-10)},t.easeExpOut=function(t){return 1-Math.pow(2,-10*t)},t.easeExpInOut=ee,t.easeCircle=re,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCircleInOut=re,t.easeBounce=ie,t.easeBounceIn=function(t){return 1-ie(1-t)},t.easeBounceOut=ie,t.easeBounceInOut=function(t){return((t*=2)<=1?1-ie(1-t):ie(t-1)+1)/2},t.easeBack=lh,t.easeBackIn=sh,t.easeBackOut=fh,t.easeBackInOut=lh,t.easeElastic=dh,t.easeElasticIn=ph,t.easeElasticOut=dh,t.easeElasticInOut=vh,t.forceCenter=function(t,n){function e(){var e,i,o=r.length,u=0,a=0;for(e=0;e<o;++e)u+=(i=r[e]).x,a+=i.y;for(u=u/o-t,a=a/o-n,e=0;e<o;++e)(i=r[e]).x-=u,i.y-=a}var r;return null==t&&(t=0),null==n&&(n=0),e.initialize=function(t){r=t},e.x=function(n){return arguments.length?(t=+n,e):t},e.y=function(t){return arguments.length?(n=+t,e):n},e},t.forceCollide=function(t){function n(){for(var t,n,r,c,s,f,l,h=i.length,p=0;p<a;++p)for(n=qe(i,Oe,Fe).visitAfter(e),t=0;t<h;++t)r=i[t],f=o[r.index],l=f*f,c=r.x+r.vx,s=r.y+r.vy,n.visit(function(t,n,e,i,o){var a=t.data,h=t.r,p=f+h;if(!a)return n>c+p||i<c-p||e>s+p||o<s-p;if(a.index>r.index){var d=c-a.x-a.vx,v=s-a.y-a.vy,_=d*d+v*v;_<p*p&&(0===d&&(d=rp(),_+=d*d),0===v&&(v=rp(),_+=v*v),_=(p-(_=Math.sqrt(_)))/_*u,r.vx+=(d*=_)*(p=(h*=h)/(l+h)),r.vy+=(v*=_)*p,a.vx-=d*(p=1-p),a.vy-=v*p)}})}function e(t){if(t.data)return t.r=o[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function r(){if(i){var n,e,r=i.length;for(o=new Array(r),n=0;n<r;++n)e=i[n],o[e.index]=+t(e,n,i)}}var i,o,u=1,a=1;return"function"!=typeof t&&(t=ep(null==t?1:+t)),n.initialize=function(t){i=t,r()},n.iterations=function(t){return arguments.length?(a=+t,n):a},n.strength=function(t){return arguments.length?(u=+t,n):u},n.radius=function(e){return arguments.length?(t="function"==typeof e?e:ep(+e),r(),n):t},n},t.forceLink=function(t){function n(n){for(var e=0,r=t.length;e<p;++e)for(var i,a,c,f,l,h,d,v=0;v<r;++v)a=(i=t[v]).source,f=(c=i.target).x+c.vx-a.x-a.vx||rp(),l=c.y+c.vy-a.y-a.vy||rp(),f*=h=((h=Math.sqrt(f*f+l*l))-u[v])/h*n*o[v],l*=h,c.vx-=f*(d=s[v]),c.vy-=l*d,a.vx+=f*(d=1-d),a.vy+=l*d}function e(){if(a){var n,e,l=a.length,h=t.length,p=we(a,f);for(n=0,c=new Array(l);n<h;++n)(e=t[n]).index=n,"object"!=typeof e.source&&(e.source=Ye(p,e.source)),"object"!=typeof e.target&&(e.target=Ye(p,e.target)),c[e.source.index]=(c[e.source.index]||0)+1,c[e.target.index]=(c[e.target.index]||0)+1;for(n=0,s=new Array(h);n<h;++n)e=t[n],s[n]=c[e.source.index]/(c[e.source.index]+c[e.target.index]);o=new Array(h),r(),u=new Array(h),i()}}function r(){if(a)for(var n=0,e=t.length;n<e;++n)o[n]=+l(t[n],n,t)}function i(){if(a)for(var n=0,e=t.length;n<e;++n)u[n]=+h(t[n],n,t)}var o,u,a,c,s,f=Ie,l=function(t){return 1/Math.min(c[t.source.index],c[t.target.index])},h=ep(30),p=1;return null==t&&(t=[]),n.initialize=function(t){a=t,e()},n.links=function(r){return arguments.length?(t=r,e(),n):t},n.id=function(t){return arguments.length?(f=t,n):f},n.iterations=function(t){return arguments.length?(p=+t,n):p},n.strength=function(t){return arguments.length?(l="function"==typeof t?t:ep(+t),r(),n):l},n.distance=function(t){return arguments.length?(h="function"==typeof t?t:ep(+t),i(),n):h},n},t.forceManyBody=function(){function t(t){var n,a=i.length,c=qe(i,Be,je).visitAfter(e);for(u=t,n=0;n<a;++n)o=i[n],c.visit(r)}function n(){if(i){var t,n,e=i.length;for(a=new Array(e),t=0;t<e;++t)n=i[t],a[n.index]=+c(n,t,i)}}function e(t){var n,e,r,i,o,u=0;if(t.length){for(r=i=o=0;o<4;++o)(n=t[o])&&(e=n.value)&&(u+=e,r+=e*n.x,i+=e*n.y);t.x=r/u,t.y=i/u}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=a[n.data.index]}while(n=n.next)}t.value=u}function r(t,n,e,r){if(!t.value)return!0;var i=t.x-o.x,c=t.y-o.y,h=r-n,p=i*i+c*c;if(h*h/l<p)return p<f&&(0===i&&(i=rp(),p+=i*i),0===c&&(c=rp(),p+=c*c),p<s&&(p=Math.sqrt(s*p)),o.vx+=i*t.value*u/p,o.vy+=c*t.value*u/p),!0;if(!(t.length||p>=f)){(t.data!==o||t.next)&&(0===i&&(i=rp(),p+=i*i),0===c&&(c=rp(),p+=c*c),p<s&&(p=Math.sqrt(s*p)));do{t.data!==o&&(h=a[t.data.index]*u/p,o.vx+=i*h,o.vy+=c*h)}while(t=t.next)}}var i,o,u,a,c=ep(-30),s=1,f=1/0,l=.81;return t.initialize=function(t){i=t,n()},t.strength=function(e){return arguments.length?(c="function"==typeof e?e:ep(+e),n(),t):c},t.distanceMin=function(n){return arguments.length?(s=n*n,t):Math.sqrt(s)},t.distanceMax=function(n){return arguments.length?(f=n*n,t):Math.sqrt(f)},t.theta=function(n){return arguments.length?(l=n*n,t):Math.sqrt(l)},t},t.forceSimulation=function(t){function n(){e(),d.call("tick",o),u<a&&(p.stop(),d.call("end",o))}function e(){var n,e,r=t.length;for(u+=(s-u)*c,l.each(function(t){t(u)}),n=0;n<r;++n)null==(e=t[n]).fx?e.x+=e.vx*=f:(e.x=e.fx,e.vx=0),null==e.fy?e.y+=e.vy*=f:(e.y=e.fy,e.vy=0)}function r(){for(var n,e=0,r=t.length;e<r;++e){if(n=t[e],n.index=e,isNaN(n.x)||isNaN(n.y)){var i=ap*Math.sqrt(e),o=e*cp;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function i(n){return n.initialize&&n.initialize(t),n}var o,u=1,a=.001,c=1-Math.pow(a,1/300),s=0,f=.6,l=we(),p=dn(n),d=h("tick","end");return null==t&&(t=[]),r(),o={tick:e,restart:function(){return p.restart(n),o},stop:function(){return p.stop(),o},nodes:function(n){return arguments.length?(t=n,r(),l.each(i),o):t},alpha:function(t){return arguments.length?(u=+t,o):u},alphaMin:function(t){return arguments.length?(a=+t,o):a},alphaDecay:function(t){return arguments.length?(c=+t,o):+c},alphaTarget:function(t){return arguments.length?(s=+t,o):s},velocityDecay:function(t){return arguments.length?(f=1-t,o):1-f},force:function(t,n){return arguments.length>1?(null==n?l.remove(t):l.set(t,i(n)),o):l.get(t)},find:function(n,e,r){var i,o,u,a,c,s=0,f=t.length;for(null==r?r=1/0:r*=r,s=0;s<f;++s)(u=(i=n-(a=t[s]).x)*i+(o=e-a.y)*o)<r&&(c=a,r=u);return c},on:function(t,n){return arguments.length>1?(d.on(t,n),o):d.on(t)}}},t.forceX=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)(n=r[e]).vx+=(o[e]-n.x)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=ep(.1);return"function"!=typeof t&&(t=ep(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),e(),n):u},n.x=function(r){return arguments.length?(t="function"==typeof r?r:ep(+r),e(),n):t},n},t.forceY=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)(n=r[e]).vy+=(o[e]-n.y)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=ep(.1);return"function"!=typeof t&&(t=ep(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),e(),n):u},n.y=function(r){return arguments.length?(t="function"==typeof r?r:ep(+r),e(),n):t},n},t.formatDefaultLocale=$e,t.formatLocale=mp,t.formatSpecifier=He,t.precisionFixed=xp,t.precisionPrefix=bp,t.precisionRound=wp,t.geoArea=function(t){return kd.reset(),Md(t,Nd),2*kd},t.geoBounds=function(t){var n,e,r,i,o,u,a;if(Pp=zp=-(Ap=Cp=1/0),Dp=[],Md(t,Ed),e=Dp.length){for(Dp.sort(br),n=1,o=[r=Dp[0]];n<e;++n)wr(r,(i=Dp[n])[0])||wr(r,i[1])?(xr(r[0],i[1])>xr(r[0],r[1])&&(r[1]=i[1]),xr(i[0],r[1])>xr(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(a=xr(r[1],i[0]))>u&&(u=a,Ap=i[0],zp=r[1])}return Dp=Op=null,Ap===1/0||Cp===1/0?[[NaN,NaN],[NaN,NaN]]:[[Ap,Cp],[zp,Pp]]},t.geoCentroid=function(t){Fp=Ip=Yp=Bp=jp=Hp=Xp=$p=Vp=Wp=Zp=0,Md(t,Ad);var n=Vp,e=Wp,r=Zp,i=n*n+e*e+r*r;return i<1e-12&&(n=Hp,e=Xp,r=$p,Ip<ed&&(n=Yp,e=Bp,r=jp),(i=n*n+e*e+r*r)<1e-12)?[NaN,NaN]:[ld(e,n)*ad,Ge(r/md(i))*ad]},t.geoCircle=function(){function t(){var t=r.apply(this,arguments),a=i.apply(this,arguments)*cd,c=o.apply(this,arguments)*cd;return n=[],e=Lr(-t[0]*cd,-t[1]*cd,0).invert,Or(u,a,c,1),t={type:"Polygon",coordinates:[n]},n=e=null,t}var n,e,r=Cd([0,0]),i=Cd(90),o=Cd(6),u={point:function(t,r){n.push(t=e(t,r)),t[0]*=ad,t[1]*=ad}};return t.center=function(n){return arguments.length?(r="function"==typeof n?n:Cd([+n[0],+n[1]]),t):r},t.radius=function(n){return arguments.length?(i="function"==typeof n?n:Cd(+n),t):i},t.precision=function(n){return arguments.length?(o="function"==typeof n?n:Cd(+n),t):o},t},t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,u=500;return e={stream:function(e){return t&&n===e?t:t=Br(r,i,o,u)(n=e)},extent:function(a){return arguments.length?(r=+a[0][0],i=+a[0][1],o=+a[1][0],u=+a[1][1],t=n=null,e):[[r,i],[o,u]]}}},t.geoContains=function(t,n){return(t&&iv.hasOwnProperty(t.type)?iv[t.type]:$r)(t,n)},t.geoDistance=rv,t.geoGraticule=ti,t.geoGraticule10=function(){return ti()()},t.geoInterpolate=function(t,n){var e=t[0]*cd,r=t[1]*cd,i=n[0]*cd,o=n[1]*cd,u=hd(r),a=yd(r),c=hd(o),s=yd(o),f=u*hd(e),l=u*yd(e),h=c*hd(i),p=c*yd(i),d=2*Ge(md(Je(o-r)+u*c*Je(i-e))),v=yd(d),_=d?function(t){var n=yd(t*=d)/v,e=yd(d-t)/v,r=e*f+n*h,i=e*l+n*p,o=e*a+n*s;return[ld(i,r)*ad,ld(o,md(r*r+i*i))*ad]}:function(){return[e*ad,r*ad]};return _.distance=d,_},t.geoLength=tv,t.geoPath=function(t,n){function e(t){return t&&("function"==typeof o&&i.pointRadius(+o.apply(this,arguments)),Md(t,r(i))),i.result()}var r,i,o=4.5;return e.area=function(t){return Md(t,r(sv)),sv.result()},e.measure=function(t){return Md(t,r(zv)),zv.result()},e.bounds=function(t){return Md(t,r(dv)),dv.result()},e.centroid=function(t){return Md(t,r(Tv)),Tv.result()},e.projection=function(n){return arguments.length?(r=null==n?(t=null,uv):(t=n).stream,e):t},e.context=function(t){return arguments.length?(i=null==t?(n=null,new yi):new di(n=t),"function"!=typeof o&&i.pointRadius(o),e):n},e.pointRadius=function(t){return arguments.length?(o="function"==typeof t?t:(i.pointRadius(+t),+t),e):o},e.projection(t).context(n)},t.geoAlbers=Iv,t.geoAlbersUsa=function(){function t(t){var n=t[0],e=t[1];return a=null,i.point(n,e),a||(o.point(n,e),a)||(u.point(n,e),a)}function n(){return e=r=null,t}var e,r,i,o,u,a,c=Iv(),s=Fv().rotate([154,0]).center([-2,58.5]).parallels([55,65]),f=Fv().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(t,n){a=[t,n]}};return t.invert=function(t){var n=c.scale(),e=c.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?f:c).invert(t)},t.stream=function(t){return e&&r===t?e:e=Ri([c.stream(r=t),s.stream(t),f.stream(t)])},t.precision=function(t){return arguments.length?(c.precision(t),s.precision(t),f.precision(t),n()):c.precision()},t.scale=function(n){return arguments.length?(c.scale(n),s.scale(.35*n),f.scale(n),t.translate(c.translate())):c.scale()},t.translate=function(t){if(!arguments.length)return c.translate();var e=c.scale(),r=+t[0],a=+t[1];return i=c.translate(t).clipExtent([[r-.455*e,a-.238*e],[r+.455*e,a+.238*e]]).stream(l),o=s.translate([r-.307*e,a+.201*e]).clipExtent([[r-.425*e+ed,a+.12*e+ed],[r-.214*e-ed,a+.234*e-ed]]).stream(l),u=f.translate([r-.205*e,a+.212*e]).clipExtent([[r-.214*e+ed,a+.166*e+ed],[r-.115*e-ed,a+.234*e-ed]]).stream(l),n()},t.fitExtent=function(n,e){return Ti(t,n,e)},t.fitSize=function(n,e){return ki(t,n,e)},t.scale(1070)},t.geoAzimuthalEqualArea=function(){return Ei(Yv).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Yv,t.geoAzimuthalEquidistant=function(){return Ei(Bv).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=Bv,t.geoConicConformal=function(){return Ci(Fi).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=Fi,t.geoConicEqualArea=Fv,t.geoConicEqualAreaRaw=Pi,t.geoConicEquidistant=function(){return Ci(Yi).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=Yi,t.geoEquirectangular=function(){return Ei(Ii).scale(152.63)},t.geoEquirectangularRaw=Ii,t.geoGnomonic=function(){return Ei(Bi).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=Bi,t.geoIdentity=function(){function t(){return i=o=null,u}var n,e,r,i,o,u,a=1,c=0,s=0,f=1,l=1,h=uv,p=null,d=uv;return u={stream:function(t){return i&&o===t?i:i=h(d(o=t))},clipExtent:function(i){return arguments.length?(d=null==i?(p=n=e=r=null,uv):Br(p=+i[0][0],n=+i[0][1],e=+i[1][0],r=+i[1][1]),t()):null==p?null:[[p,n],[e,r]]},scale:function(n){return arguments.length?(h=ji((a=+n)*f,a*l,c,s),t()):a},translate:function(n){return arguments.length?(h=ji(a*f,a*l,c=+n[0],s=+n[1]),t()):[c,s]},reflectX:function(n){return arguments.length?(h=ji(a*(f=n?-1:1),a*l,c,s),t()):f<0},reflectY:function(n){return arguments.length?(h=ji(a*f,a*(l=n?-1:1),c,s),t()):l<0},fitExtent:function(t,n){return Ti(u,t,n)},fitSize:function(t,n){return ki(u,t,n)}}},t.geoProjection=Ei,t.geoProjectionMutator=Ai,t.geoMercator=function(){return Di(Ui).scale(961/ud)},t.geoMercatorRaw=Ui,t.geoOrthographic=function(){return Ei(Hi).scale(249.5).clipAngle(90+ed)},t.geoOrthographicRaw=Hi,t.geoStereographic=function(){return Ei(Xi).scale(250).clipAngle(142)},t.geoStereographicRaw=Xi,t.geoTransverseMercator=function(){var t=Di($i),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):(t=n(),[t[1],-t[0]])},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):(t=e(),[t[0],t[1],t[2]-90])},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=$i,t.geoRotation=jd,t.geoStream=Md,t.geoTransform=function(t){return{stream:wi(t)}},t.cluster=function(){function t(t){var o,u=0;t.eachAfter(function(t){var e=t.children;e?(t.x=Wi(e),t.y=Gi(e)):(t.x=o?u+=n(t,o):0,t.y=0,o=t)});var a=Qi(t),c=Ki(t),s=a.x-n(a,c)/2,f=c.x+n(c,a)/2;return t.eachAfter(i?function(n){n.x=(n.x-t.x)*e,n.y=(t.y-n.y)*r}:function(n){n.x=(n.x-s)/(f-s)*e,n.y=(1-(t.y?n.y/t.y:1))*r})}var n=Vi,e=1,r=1,i=!1;return t.separation=function(e){return arguments.length?(n=e,t):n},t.size=function(n){return arguments.length?(i=!1,e=+n[0],r=+n[1],t):i?null:[e,r]},t.nodeSize=function(n){return arguments.length?(i=!0,e=+n[0],r=+n[1],t):i?[e,r]:null},t},t.hierarchy=eo,t.pack=function(){function t(t){return t.x=e/2,t.y=r/2,n?t.eachBefore(No(n)).eachAfter(So(i,.5)).eachBefore(Eo(1)):t.eachBefore(No(ko)).eachAfter(So(To,1)).eachAfter(So(i,t.r/Math.min(e,r))).eachBefore(Eo(Math.min(e,r)/(2*t.r))),t}var n=null,e=1,r=1,i=To;return t.radius=function(e){return arguments.length?(n=wo(e),t):n},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i="function"==typeof n?n:Xv(+n),t):i},t},t.packSiblings=function(t){return bo(t),t},t.packEnclose=Hv,t.partition=function(){function t(t){var u=t.height+1;return t.x0=t.y0=i,t.x1=e,t.y1=r/u,t.eachBefore(n(r,u)),o&&t.eachBefore($v),t}function n(t,n){return function(e){e.children&&Vv(e,e.x0,t*(e.depth+1)/n,e.x1,t*(e.depth+2)/n);var r=e.x0,o=e.y0,u=e.x1-i,a=e.y1-i;u<r&&(r=u=(r+u)/2),a<o&&(o=a=(o+a)/2),e.x0=r,e.y0=o,e.x1=u,e.y1=a}}var e=1,r=1,i=0,o=!1;return t.round=function(n){return arguments.length?(o=!!n,t):o},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i=+n,t):i},t},t.stratify=function(){function t(t){var r,i,o,u,a,c,s,f=t.length,l=new Array(f),h={};for(i=0;i<f;++i)r=t[i],a=l[i]=new uo(r),null!=(c=n(r,i,t))&&(c+="")&&(h[s=Wv+(a.id=c)]=s in h?Gv:a);for(i=0;i<f;++i)if(a=l[i],null!=(c=e(t[i],i,t))&&(c+="")){if(!(u=h[Wv+c]))throw new Error("missing: "+c);if(u===Gv)throw new Error("ambiguous: "+c);u.children?u.children.push(a):u.children=[a],a.parent=u}else{if(o)throw new Error("multiple roots");o=a}if(!o)throw new Error("no root");if(o.parent=Zv,o.eachBefore(function(t){t.depth=t.parent.depth+1,--f}).eachBefore(oo),o.parent=null,f>0)throw new Error("cycle");return o}var n=Ao,e=Co;return t.id=function(e){return arguments.length?(n=Mo(e),t):n},t.parentId=function(n){return arguments.length?(e=Mo(n),t):e},t},t.tree=function(){function t(t){var r=Oo(t);if(r.eachAfter(n),r.parent.m=-r.z,r.eachBefore(e),c)t.eachBefore(i);else{var s=t,f=t,l=t;t.eachBefore(function(t){t.x<s.x&&(s=t),t.x>f.x&&(f=t),t.depth>l.depth&&(l=t)});var h=s===f?1:o(s,f)/2,p=h-s.x,d=u/(f.x+h+p),v=a/(l.depth||1);t.eachBefore(function(t){t.x=(t.x+p)*d,t.y=t.depth*v})}return t}function n(t){var n=t.children,e=t.parent.children,i=t.i?e[t.i-1]:null;if(n){qo(t);var u=(n[0].z+n[n.length-1].z)/2;i?(t.z=i.z+o(t._,i._),t.m=t.z-u):t.z=u}else i&&(t.z=i.z+o(t._,i._));t.parent.A=r(t,i,t.parent.A||e[0])}function e(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function r(t,n,e){if(n){for(var r,i=t,u=t,a=n,c=i.parent.children[0],s=i.m,f=u.m,l=a.m,h=c.m;a=Ro(a),i=Po(i),a&&i;)c=Po(c),(u=Ro(u)).a=t,(r=a.z+l-i.z-s+o(a._,i._))>0&&(Lo(Uo(a,t,e),t,r),s+=r,f+=r),l+=a.m,s+=i.m,h+=c.m,f+=u.m;a&&!Ro(u)&&(u.t=a,u.m+=l-f),i&&!Po(c)&&(c.t=i,c.m+=s-h,e=t)}return e}function i(t){t.x*=u,t.y=t.depth*a}var o=zo,u=1,a=1,c=null;return t.separation=function(n){return arguments.length?(o=n,t):o},t.size=function(n){return arguments.length?(c=!1,u=+n[0],a=+n[1],t):c?null:[u,a]},t.nodeSize=function(n){return arguments.length?(c=!0,u=+n[0],a=+n[1],t):c?[u,a]:null},t},t.treemap=function(){function t(t){return t.x0=t.y0=0,t.x1=i,t.y1=o,t.eachBefore(n),u=[0],r&&t.eachBefore($v),t}function n(t){var n=u[t.depth],r=t.x0+n,i=t.y0+n,o=t.x1-n,h=t.y1-n;o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),t.x0=r,t.y0=i,t.x1=o,t.y1=h,t.children&&(n=u[t.depth+1]=a(t)/2,r+=l(t)-n,i+=c(t)-n,o-=s(t)-n,h-=f(t)-n,o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),e(t,r,i,o,h))}var e=Kv,r=!1,i=1,o=1,u=[0],a=To,c=To,s=To,f=To,l=To;return t.round=function(n){return arguments.length?(r=!!n,t):r},t.size=function(n){return arguments.length?(i=+n[0],o=+n[1],t):[i,o]},t.tile=function(n){return arguments.length?(e=Mo(n),t):e},t.padding=function(n){return arguments.length?t.paddingInner(n).paddingOuter(n):t.paddingInner()},t.paddingInner=function(n){return arguments.length?(a="function"==typeof n?n:Xv(+n),t):a},t.paddingOuter=function(n){return arguments.length?t.paddingTop(n).paddingRight(n).paddingBottom(n).paddingLeft(n):t.paddingTop()},t.paddingTop=function(n){return arguments.length?(c="function"==typeof n?n:Xv(+n),t):c},t.paddingRight=function(n){return arguments.length?(s="function"==typeof n?n:Xv(+n),t):s},t.paddingBottom=function(n){return arguments.length?(f="function"==typeof n?n:Xv(+n),t):f},t.paddingLeft=function(n){return arguments.length?(l="function"==typeof n?n:Xv(+n),t):l},t},t.treemapBinary=function(t,n,e,r,i){function o(t,n,e,r,i,u,a){if(t>=n-1){var s=c[t];return s.x0=r,s.y0=i,s.x1=u,void(s.y1=a)}for(var l=f[t],h=e/2+l,p=t+1,d=n-1;p<d;){var v=p+d>>>1;f[v]<h?p=v+1:d=v}h-f[p-1]<f[p]-h&&t+1<p&&--p;var _=f[p]-l,y=e-_;if(u-r>a-i){var g=(r*y+u*_)/e;o(t,p,_,r,i,g,a),o(p,n,y,g,i,u,a)}else{var m=(i*y+a*_)/e;o(t,p,_,r,i,u,m),o(p,n,y,r,m,u,a)}}var u,a,c=t.children,s=c.length,f=new Array(s+1);for(f[0]=a=u=0;u<s;++u)f[u+1]=a+=c[u].value;o(0,s,t.value,n,e,r,i)},t.treemapDice=Vv,t.treemapSlice=Jv,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Jv:Vv)(t,n,e,r,i)},t.treemapSquarify=Kv,t.treemapResquarify=t_,t.interpolate=cl,t.interpolateArray=nl,t.interpolateBasis=Zf,t.interpolateBasisClosed=Gf,t.interpolateDate=el,t.interpolateNumber=rl,t.interpolateObject=il,t.interpolateRound=sl,t.interpolateString=al,t.interpolateTransformCss=pl,t.interpolateTransformSvg=dl,t.interpolateZoom=_l,t.interpolateRgb=Qf,t.interpolateRgbBasis=Kf,t.interpolateRgbBasisClosed=tl,t.interpolateHsl=yl,t.interpolateHslLong=gl,t.interpolateLab=function(t,n){var e=Kt((t=Ut(t)).l,(n=Ut(n)).l),r=Kt(t.a,n.a),i=Kt(t.b,n.b),o=Kt(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateHcl=ml,t.interpolateHclLong=xl,t.interpolateCubehelix=bl,t.interpolateCubehelixLong=wl,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.path=ve,t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,u=0,a=t[i-1],c=0;++r<i;)n=a,a=t[r],c+=e=n[0]*a[1]-a[0]*n[1],o+=(n[0]+a[0])*e,u+=(n[1]+a[1])*e;return c*=3,[o/c,u/c]},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(Io),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=Yo(r),u=Yo(i),a=u[0]===o[0],c=u[u.length-1]===o[o.length-1],s=[];for(n=o.length-1;n>=0;--n)s.push(t[r[o[n]][2]]);for(n=+a;n<u.length-c;++n)s.push(t[r[u[n]][2]]);return s},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],u=n[0],a=n[1],c=o[0],s=o[1],f=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>a!=s>a&&u<(c-e)*(a-r)/(s-r)+e&&(f=!f),c=e,s=r;return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],u=o[0],a=o[1],c=0;++r<i;)n=u,e=a,n-=u=(o=t[r])[0],e-=a=o[1],c+=Math.sqrt(n*n+e*e);return c},t.quadtree=qe,t.queue=Wo,t.randomUniform=o_,t.randomNormal=u_,t.randomLogNormal=a_,t.randomBates=s_,t.randomIrwinHall=c_,t.randomExponential=f_,t.request=l_,t.html=p_,t.json=d_,t.text=v_,t.xml=__,t.csv=g_,t.tsv=m_,t.scaleBand=Ko,t.scalePoint=function(){return tu(Ko().paddingInner(1))},t.scaleIdentity=fu,t.scaleLinear=su,t.scaleLog=yu,t.scaleOrdinal=Qo,t.scaleImplicit=M_,t.scalePow=mu,t.scaleSqrt=function(){return mu().exponent(.5)},t.scaleQuantile=xu,t.scaleQuantize=bu,t.scaleThreshold=wu,t.scaleTime=function(){return Na(oy,ry,j_,Y_,F_,D_,q_,z_,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)])},t.scaleUtc=function(){return Na(Ay,Sy,py,ly,sy,ay,q_,z_,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)])},t.schemeCategory10=$y,t.schemeCategory20b=Vy,t.schemeCategory20c=Wy,t.schemeCategory20=Zy,t.interpolateCubehelixDefault=Gy,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return Ky.h=360*t-100,Ky.s=1.5-1.5*n,Ky.l=.8-.9*n,Ky+""},t.interpolateWarm=Jy,t.interpolateCool=Qy,t.interpolateViridis=tg,t.interpolateMagma=ng,t.interpolateInferno=eg,t.interpolatePlasma=rg,t.scaleSequential=Ea,t.creator=Hs,t.local=m,t.matcher=Zs,t.mouse=Ks,t.namespace=js,t.namespaces=Bs,t.select=cf,t.selectAll=function(t){return"string"==typeof t?new pt([document.querySelectorAll(t)],[document.documentElement]):new pt([null==t?[]:t],af)},t.selection=dt,t.selector=tf,t.selectorAll=nf,t.style=B,t.touch=sf,t.touches=function(t,n){null==n&&(n=Js().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Qs(t,n[e]);return i},t.window=uf,t.customEvent=N,t.arc=function(){function t(){var t,s,f=+n.apply(this,arguments),l=+e.apply(this,arguments),h=o.apply(this,arguments)-dg,p=u.apply(this,arguments)-dg,d=og(p-h),v=p>h;if(c||(c=t=ve()),l<f&&(s=l,l=f,f=s),l>hg)if(d>vg-hg)c.moveTo(l*ag(h),l*fg(h)),c.arc(0,0,l,h,p,!v),f>hg&&(c.moveTo(f*ag(p),f*fg(p)),c.arc(0,0,f,p,h,v));else{var _,y,g=h,m=p,x=h,b=p,w=d,M=d,T=a.apply(this,arguments)/2,k=T>hg&&(i?+i.apply(this,arguments):lg(f*f+l*l)),N=sg(og(l-f)/2,+r.apply(this,arguments)),S=N,E=N;if(k>hg){var A=Ca(k/f*fg(T)),C=Ca(k/l*fg(T));(w-=2*A)>hg?(A*=v?1:-1,x+=A,b-=A):(w=0,x=b=(h+p)/2),(M-=2*C)>hg?(C*=v?1:-1,g+=C,m-=C):(M=0,g=m=(h+p)/2)}var z=l*ag(g),P=l*fg(g),R=f*ag(b),L=f*fg(b);if(N>hg){var q=l*ag(m),U=l*fg(m),D=f*ag(x),O=f*fg(x);if(d<pg){var F=w>hg?Ua(z,P,D,O,q,U,R,L):[R,L],I=z-F[0],Y=P-F[1],B=q-F[0],j=U-F[1],H=1/fg(Aa((I*B+Y*j)/(lg(I*I+Y*Y)*lg(B*B+j*j)))/2),X=lg(F[0]*F[0]+F[1]*F[1]);S=sg(N,(f-X)/(H-1)),E=sg(N,(l-X)/(H+1))}}M>hg?E>hg?(_=Da(D,O,z,P,l,E,v),y=Da(q,U,R,L,l,E,v),c.moveTo(_.cx+_.x01,_.cy+_.y01),E<N?c.arc(_.cx,_.cy,E,ug(_.y01,_.x01),ug(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,E,ug(_.y01,_.x01),ug(_.y11,_.x11),!v),c.arc(0,0,l,ug(_.cy+_.y11,_.cx+_.x11),ug(y.cy+y.y11,y.cx+y.x11),!v),c.arc(y.cx,y.cy,E,ug(y.y11,y.x11),ug(y.y01,y.x01),!v))):(c.moveTo(z,P),c.arc(0,0,l,g,m,!v)):c.moveTo(z,P),f>hg&&w>hg?S>hg?(_=Da(R,L,q,U,f,-S,v),y=Da(z,P,D,O,f,-S,v),c.lineTo(_.cx+_.x01,_.cy+_.y01),S<N?c.arc(_.cx,_.cy,S,ug(_.y01,_.x01),ug(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,S,ug(_.y01,_.x01),ug(_.y11,_.x11),!v),c.arc(0,0,f,ug(_.cy+_.y11,_.cx+_.x11),ug(y.cy+y.y11,y.cx+y.x11),v),c.arc(y.cx,y.cy,S,ug(y.y11,y.x11),ug(y.y01,y.x01),!v))):c.arc(0,0,f,b,x,v):c.lineTo(R,L)}else c.moveTo(0,0);if(c.closePath(),t)return c=null,t+""||null}var n=za,e=Pa,r=ig(0),i=null,o=Ra,u=La,a=qa,c=null;return t.centroid=function(){var t=(+n.apply(this,arguments)+ +e.apply(this,arguments))/2,r=(+o.apply(this,arguments)+ +u.apply(this,arguments))/2-pg/2;return[ag(r)*t,fg(r)*t]},t.innerRadius=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.outerRadius=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.cornerRadius=function(n){return arguments.length?(r="function"==typeof n?n:ig(+n),t):r},t.padRadius=function(n){return arguments.length?(i=null==n?null:"function"==typeof n?n:ig(+n),t):i},t.startAngle=function(n){return arguments.length?(o="function"==typeof n?n:ig(+n),t):o},t.endAngle=function(n){return arguments.length?(u="function"==typeof n?n:ig(+n),t):u},t.padAngle=function(n){return arguments.length?(a="function"==typeof n?n:ig(+n),t):a},t.context=function(n){return arguments.length?(c=null==n?null:n,t):c},t},t.area=gg,t.line=yg,t.pie=function(){function t(t){var a,c,s,f,l,h=t.length,p=0,d=new Array(h),v=new Array(h),_=+i.apply(this,arguments),y=Math.min(vg,Math.max(-vg,o.apply(this,arguments)-_)),g=Math.min(Math.abs(y)/h,u.apply(this,arguments)),m=g*(y<0?-1:1);for(a=0;a<h;++a)(l=v[d[a]=a]=+n(t[a],a,t))>0&&(p+=l);for(null!=e?d.sort(function(t,n){return e(v[t],v[n])}):null!=r&&d.sort(function(n,e){return r(t[n],t[e])}),a=0,s=p?(y-h*m)/p:0;a<h;++a,_=f)c=d[a],f=_+((l=v[c])>0?l*s:0)+m,v[c]={data:t[c],index:a,value:l,startAngle:_,endAngle:f,padAngle:g};return v}var n=xg,e=mg,r=null,i=ig(0),o=ig(vg),u=ig(0);return t.value=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.sortValues=function(n){return arguments.length?(e=n,r=null,t):e},t.sort=function(n){return arguments.length?(r=n,e=null,t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:ig(+n),t):o},t.padAngle=function(n){return arguments.length?(u="function"==typeof n?n:ig(+n),t):u},t},t.areaRadial=Mg,t.radialArea=Mg,t.lineRadial=wg,t.radialLine=wg,t.pointRadial=Tg,t.linkHorizontal=function(){return $a(Va)},t.linkVertical=function(){return $a(Wa)},t.linkRadial=function(){var t=$a(Za);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.symbol=function(){function t(){var t;if(r||(r=t=ve()),n.apply(this,arguments).draw(r,+e.apply(this,arguments)),t)return r=null,t+""||null}var n=ig(Ng),e=ig(64),r=null;return t.type=function(e){return arguments.length?(n="function"==typeof e?e:ig(e),t):n},t.size=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.context=function(n){return arguments.length?(r=null==n?null:n,t):r},t},t.symbols=jg,t.symbolCircle=Ng,t.symbolCross=Sg,t.symbolDiamond=Cg,t.symbolSquare=qg,t.symbolStar=Lg,t.symbolTriangle=Dg,t.symbolWye=Bg,t.curveBasisClosed=function(t){return new Qa(t)},t.curveBasisOpen=function(t){return new Ka(t)},t.curveBasis=function(t){return new Ja(t)},t.curveBundle=Xg,t.curveCardinalClosed=Vg,t.curveCardinalOpen=Wg,t.curveCardinal=$g,t.curveCatmullRomClosed=Gg,t.curveCatmullRomOpen=Jg,t.curveCatmullRom=Zg,t.curveLinearClosed=function(t){return new sc(t)},t.curveLinear=_g,t.curveMonotoneX=function(t){return new dc(t)},t.curveMonotoneY=function(t){return new vc(t)},t.curveNatural=function(t){return new yc(t)},t.curveStep=function(t){return new mc(t,.5)},t.curveStepAfter=function(t){return new mc(t,1)},t.curveStepBefore=function(t){return new mc(t,0)},t.stack=function(){function t(t){var o,u,a=n.apply(this,arguments),c=t.length,s=a.length,f=new Array(s);for(o=0;o<s;++o){for(var l,h=a[o],p=f[o]=new Array(c),d=0;d<c;++d)p[d]=l=[0,+i(t[d],h,d,t)],l.data=t[d];p.key=h}for(o=0,u=e(f);o<s;++o)f[u[o]].index=o;return r(f,u),f}var n=ig([]),e=Kg,r=Qg,i=xc;return t.keys=function(e){return arguments.length?(n="function"==typeof e?e:ig(kg.call(e)),t):n},t.value=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.order=function(n){return arguments.length?(e=null==n?Kg:"function"==typeof n?n:ig(kg.call(n)),t):e},t.offset=function(n){return arguments.length?(r=null==n?Qg:n,t):r},t},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,u=t[0].length;o<u;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}Qg(t,n)}},t.stackOffsetDiverging=function(t,n){if((a=t.length)>1)for(var e,r,i,o,u,a,c=0,s=t[n[0]].length;c<s;++c)for(o=u=0,e=0;e<a;++e)(i=(r=t[n[e]][c])[1]-r[0])>=0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=u,r[0]=u+=i):r[0]=o},t.stackOffsetNone=Qg,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var u=0,a=0;u<e;++u)a+=t[u][r][1]||0;i[r][1]+=i[r][0]=-a/2}Qg(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,u=1;u<r;++u){for(var a=0,c=0,s=0;a<i;++a){for(var f=t[n[a]],l=f[u][1]||0,h=(l-(f[u-1][1]||0))/2,p=0;p<a;++p){var d=t[n[p]];h+=(d[u][1]||0)-(d[u-1][1]||0)}c+=l,s+=h*l}e[u-1][1]+=e[u-1][0]=o,c&&(o-=s/c)}e[u-1][1]+=e[u-1][0]=o,Qg(t,n)}},t.stackOrderAscending=tm,t.stackOrderDescending=function(t){return tm(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(bc),o=Kg(t).sort(function(t,n){return i[n]-i[t]}),u=0,a=0,c=[],s=[];for(n=0;n<r;++n)e=o[n],u<a?(u+=i[e],c.push(e)):(a+=i[e],s.push(e));return s.reverse().concat(c)},t.stackOrderNone=Kg,t.stackOrderReverse=function(t){return Kg(t).reverse()},t.timeInterval=Mu,t.timeMillisecond=z_,t.timeMilliseconds=P_,t.utcMillisecond=z_,t.utcMilliseconds=P_,t.timeSecond=q_,t.timeSeconds=U_,t.utcSecond=q_,t.utcSeconds=U_,t.timeMinute=D_,t.timeMinutes=O_,t.timeHour=F_,t.timeHours=I_,t.timeDay=Y_,t.timeDays=B_,t.timeWeek=j_,t.timeWeeks=G_,t.timeSunday=j_,t.timeSundays=G_,t.timeMonday=H_,t.timeMondays=J_,t.timeTuesday=X_,t.timeTuesdays=Q_,t.timeWednesday=$_,t.timeWednesdays=K_,t.timeThursday=V_,t.timeThursdays=ty,t.timeFriday=W_,t.timeFridays=ny,t.timeSaturday=Z_,t.timeSaturdays=ey,t.timeMonth=ry,t.timeMonths=iy,t.timeYear=oy,t.timeYears=uy,t.utcMinute=ay,t.utcMinutes=cy,t.utcHour=sy,t.utcHours=fy,t.utcDay=ly,t.utcDays=hy,t.utcWeek=py,t.utcWeeks=xy,t.utcSunday=py,t.utcSundays=xy,t.utcMonday=dy,t.utcMondays=by,t.utcTuesday=vy,t.utcTuesdays=wy,t.utcWednesday=_y,t.utcWednesdays=My,t.utcThursday=yy,t.utcThursdays=Ty,t.utcFriday=gy,t.utcFridays=ky,t.utcSaturday=my,t.utcSaturdays=Ny,t.utcMonth=Sy,t.utcMonths=Ey,t.utcYear=Ay,t.utcYears=zy,t.timeFormatDefaultLocale=Ma,t.timeFormatLocale=Au,t.isoFormat=Uy,t.isoParse=Dy,t.now=ln,t.timer=dn,t.timerFlush=vn,t.timeout=Pl,t.interval=function(t,n,e){var r=new pn,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?ln():+e,r.restart(function o(u){u+=i,r.restart(o,i+=n,e),t(u)},n,e),r)},t.transition=Jn,t.active=function(t,n){var e,r,i=t.__transition;if(i){n=null==n?null:n+"";for(r in i)if((e=i[r]).state>Ul&&e.name===n)return new Gn([[t]],yh,n,+r)}return null},t.interrupt=jl,t.voronoi=function(){function t(t){return new Kc(t.map(function(r,i){var o=[Math.round(n(r,i,t)/sm)*sm,Math.round(e(r,i,t)/sm)*sm];return o.index=i,o.data=r,o}),r)}var n=wc,e=Mc,r=null;return t.polygons=function(n){return t(n).polygons()},t.links=function(n){return t(n).links()},t.triangles=function(n){return t(n).triangles()},t.x=function(e){return arguments.length?(n="function"==typeof e?e:nm(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:nm(+n),t):e},t.extent=function(n){return arguments.length?(r=null==n?null:[[+n[0][0],+n[0][1]],[+n[1][0],+n[1][1]]],t):r&&[[r[0][0],r[0][1]],[r[1][0],r[1][1]]]},t.size=function(n){return arguments.length?(r=null==n?null:[[0,0],[+n[0],+n[1]]],t):r&&[r[1][0]-r[0][0],r[1][1]-r[0][1]]},t},t.zoom=function(){function n(t){t.property("__zoom",us).on("wheel.zoom",s).on("mousedown.zoom",f).on("dblclick.zoom",l).filter(cs).on("touchstart.zoom",p).on("touchmove.zoom",d).on("touchend.zoom touchcancel.zoom",v).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(t,n){return(n=Math.max(b,Math.min(w,n)))===t.k?t:new ns(n,t.x,t.y)}function r(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ns(t.k,r,i)}function i(t,n){var e=t.invertX(n[0][0])-M,r=t.invertX(n[1][0])-T,i=t.invertY(n[0][1])-k,o=t.invertY(n[1][1])-S;return t.translate(r>e?(e+r)/2:Math.min(0,e)||Math.max(0,r),o>i?(i+o)/2:Math.min(0,i)||Math.max(0,o))}function o(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function u(t,n,e){t.on("start.zoom",function(){a(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){a(this,arguments).end()}).tween("zoom",function(){var t=this,r=arguments,i=a(t,r),u=m.apply(t,r),c=e||o(u),s=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),f=t.__zoom,l="function"==typeof n?n.apply(t,r):n,h=A(f.invert(c).concat(s/f.k),l.invert(c).concat(s/l.k));return function(t){if(1===t)t=l;else{var n=h(t),e=s/n[2];t=new ns(e,c[0]-n[0]*e,c[1]-n[1]*e)}i.zoom(null,t)}})}function a(t,n){for(var e,r=0,i=C.length;r<i;++r)if((e=C[r]).that===t)return e;return new c(t,n)}function c(t,n){this.that=t,this.args=n,this.index=-1,this.active=0,this.extent=m.apply(t,n)}function s(){if(g.apply(this,arguments)){var t=a(this,arguments),n=this.__zoom,o=Math.max(b,Math.min(w,n.k*Math.pow(2,x.apply(this,arguments)))),u=Ks(this);if(t.wheel)t.mouse[0][0]===u[0]&&t.mouse[0][1]===u[1]||(t.mouse[1]=n.invert(t.mouse[0]=u)),clearTimeout(t.wheel);else{if(n.k===o)return;t.mouse=[u,n.invert(u)],jl(this),t.start()}pm(),t.wheel=setTimeout(function(){t.wheel=null,t.end()},R),t.zoom("mouse",i(r(e(n,o),t.mouse[0],t.mouse[1]),t.extent))}}function f(){if(!y&&g.apply(this,arguments)){var n=a(this,arguments),e=cf(t.event.view).on("mousemove.zoom",function(){if(pm(),!n.moved){var e=t.event.clientX-u,o=t.event.clientY-c;n.moved=e*e+o*o>L}n.zoom("mouse",i(r(n.that.__zoom,n.mouse[0]=Ks(n.that),n.mouse[1]),n.extent))},!0).on("mouseup.zoom",function(){e.on("mousemove.zoom mouseup.zoom",null),_t(t.event.view,n.moved),pm(),n.end()},!0),o=Ks(this),u=t.event.clientX,c=t.event.clientY;lf(t.event.view),rs(),n.mouse=[o,this.__zoom.invert(o)],jl(this),n.start()}}function l(){if(g.apply(this,arguments)){var o=this.__zoom,a=Ks(this),c=o.invert(a),s=i(r(e(o,o.k*(t.event.shiftKey?.5:2)),a,c),m.apply(this,arguments));pm(),E>0?cf(this).transition().duration(E).call(u,s,a):cf(this).call(n.transform,s)}}function p(){if(g.apply(this,arguments)){var n,e,r,i,o=a(this,arguments),u=t.event.changedTouches,c=u.length;for(rs(),e=0;e<c;++e)r=u[e],i=[i=sf(this,u,r.identifier),this.__zoom.invert(i),r.identifier],o.touch0?o.touch1||(o.touch1=i):(o.touch0=i,n=!0);if(_&&(_=clearTimeout(_),!o.touch1))return o.end(),void((i=cf(this).on("dblclick.zoom"))&&i.apply(this,arguments));n&&(_=setTimeout(function(){_=null},P),jl(this),o.start())}}function d(){var n,o,u,c,s=a(this,arguments),f=t.event.changedTouches,l=f.length;for(pm(),_&&(_=clearTimeout(_)),n=0;n<l;++n)o=f[n],u=sf(this,f,o.identifier),s.touch0&&s.touch0[2]===o.identifier?s.touch0[0]=u:s.touch1&&s.touch1[2]===o.identifier&&(s.touch1[0]=u);if(o=s.that.__zoom,s.touch1){var h=s.touch0[0],p=s.touch0[1],d=s.touch1[0],v=s.touch1[1],y=(y=d[0]-h[0])*y+(y=d[1]-h[1])*y,g=(g=v[0]-p[0])*g+(g=v[1]-p[1])*g;o=e(o,Math.sqrt(y/g)),u=[(h[0]+d[0])/2,(h[1]+d[1])/2],c=[(p[0]+v[0])/2,(p[1]+v[1])/2]}else{if(!s.touch0)return;u=s.touch0[0],c=s.touch0[1]}s.zoom("touch",i(r(o,u,c),s.extent))}function v(){var n,e,r=a(this,arguments),i=t.event.changedTouches,o=i.length;for(rs(),y&&clearTimeout(y),y=setTimeout(function(){y=null},P),n=0;n<o;++n)e=i[n],r.touch0&&r.touch0[2]===e.identifier?delete r.touch0:r.touch1&&r.touch1[2]===e.identifier&&delete r.touch1;r.touch1&&!r.touch0&&(r.touch0=r.touch1,delete r.touch1),r.touch0?r.touch0[1]=this.__zoom.invert(r.touch0[0]):r.end()}var _,y,g=is,m=os,x=as,b=0,w=1/0,M=-w,T=w,k=M,S=T,E=250,A=_l,C=[],z=h("start","zoom","end"),P=500,R=150,L=0;return n.transform=function(t,n){var e=t.selection?t.selection():t;e.property("__zoom",us),t!==e?u(t,n):e.interrupt().each(function(){a(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},n.scaleBy=function(t,e){n.scaleTo(t,function(){return this.__zoom.k*("function"==typeof e?e.apply(this,arguments):e)})},n.scaleTo=function(t,u){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,a=o(t),c=n.invert(a);return i(r(e(n,"function"==typeof u?u.apply(this,arguments):u),a,c),t)})},n.translateBy=function(t,e,r){n.transform(t,function(){return i(this.__zoom.translate("function"==typeof e?e.apply(this,arguments):e,"function"==typeof r?r.apply(this,arguments):r),m.apply(this,arguments))})},n.translateTo=function(t,e,r){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,u=o(t);return i(hm.translate(u[0],u[1]).scale(n.k).translate("function"==typeof e?-e.apply(this,arguments):-e,"function"==typeof r?-r.apply(this,arguments):-r),t)})},c.prototype={start:function(){return 1==++this.active&&(this.index=C.push(this)-1,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(C.splice(this.index,1),this.index=-1,this.emit("end")),this},emit:function(t){N(new ts(n,t,this.that.__zoom),z.apply,z,[t,this.that,this.args])}},n.wheelDelta=function(t){return arguments.length?(x="function"==typeof t?t:lm(+t),n):x},n.filter=function(t){return arguments.length?(g="function"==typeof t?t:lm(!!t),n):g},n.extent=function(t){return arguments.length?(m="function"==typeof t?t:lm([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),n):m},n.scaleExtent=function(t){return arguments.length?(b=+t[0],w=+t[1],n):[b,w]},n.translateExtent=function(t){return arguments.length?(M=+t[0][0],T=+t[1][0],k=+t[0][1],S=+t[1][1],n):[[M,k],[T,S]]},n.duration=function(t){return arguments.length?(E=+t,n):E},n.interpolate=function(t){return arguments.length?(A=t,n):A},n.on=function(){var t=z.on.apply(z,arguments);return t===z?n:t},n.clickDistance=function(t){return arguments.length?(L=(t=+t)*t,n):Math.sqrt(L)},n},t.zoomTransform=es,t.zoomIdentity=hm,Object.defineProperty(t,"__esModule",{value:!0})});
\ No newline at end of file diff --git a/ydb/library/schlab/mon/static/js/jquery.min.js b/ydb/library/schlab/mon/static/js/jquery.min.js index ee48790811..c82a235fee 100644 --- a/ydb/library/schlab/mon/static/js/jquery.min.js +++ b/ydb/library/schlab/mon/static/js/jquery.min.js @@ -1,5 +1,5 @@ -(function(window,undefined){var rootjQuery,readyList,document=window.document,location=window.location,navigator=window.navigator,_jQuery=window.jQuery,_$=window.$,core_push=Array.prototype.push,core_slice=Array.prototype.slice,core_indexOf=Array.prototype.indexOf,core_toString=Object.prototype.toString,core_hasOwn=Object.prototype.hasOwnProperty,core_trim=String.prototype.trim,jQuery=function(selector,context){return new jQuery.fn.init(selector,context,rootjQuery)},core_pnum=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,core_rnotwhite=/\S/,core_rspace=/\s+/,rtrim=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,rquickExpr=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,rsingleTag=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,rvalidchars=/^[\],:{}\s]*$/,rvalidbraces=/(?:^|:|,)(?:\s*\[)+/g,rvalidescape=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,rvalidtokens=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,rmsPrefix=/^-ms-/,rdashAlpha=/-([\da-z])/gi,fcamelCase=function(all,letter){return(letter+"").toUpperCase()},DOMContentLoaded=function(){if(document.addEventListener){document.removeEventListener("DOMContentLoaded",DOMContentLoaded,false);jQuery.ready()}else if(document.readyState==="complete"){document.detachEvent("onreadystatechange",DOMContentLoaded);jQuery.ready()}},class2type={};jQuery.fn=jQuery.prototype={constructor:jQuery,init:function(selector,context,rootjQuery){var match,elem,ret,doc;if(!selector){return this}if(selector.nodeType){this.context=this[0]=selector;this.length=1;return this}if(typeof selector==="string"){if(selector.charAt(0)==="<"&&selector.charAt(selector.length-1)===">"&&selector.length>=3){match=[null,selector,null]}else{match=rquickExpr.exec(selector)}if(match&&(match[1]||!context)){if(match[1]){context=context instanceof jQuery?context[0]:context;doc=context&&context.nodeType?context.ownerDocument||context:document;selector=jQuery.parseHTML(match[1],doc,true);if(rsingleTag.test(match[1])&&jQuery.isPlainObject(context)){this.attr.call(selector,context,true)}return jQuery.merge(this,selector)}else{elem=document.getElementById(match[2]);if(elem&&elem.parentNode){if(elem.id!==match[2]){return rootjQuery.find(selector)}this.length=1;this[0]=elem}this.context=document;this.selector=selector;return this}}else if(!context||context.jquery){return(context||rootjQuery).find(selector)}else{return this.constructor(context).find(selector)}}else if(jQuery.isFunction(selector)){return rootjQuery.ready(selector)}if(selector.selector!==undefined){this.selector=selector.selector;this.context=selector.context}return jQuery.makeArray(selector,this)},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return core_slice.call(this)},get:function(num){return num==null?this.toArray():num<0?this[this.length+num]:this[num]},pushStack:function(elems,name,selector){var ret=jQuery.merge(this.constructor(),elems);ret.prevObject=this;ret.context=this.context;if(name==="find"){ret.selector=this.selector+(this.selector?" ":"")+selector}else if(name){ret.selector=this.selector+"."+name+"("+selector+")"}return ret},each:function(callback,args){return jQuery.each(this,callback,args)},ready:function(fn){jQuery.ready.promise().done(fn);return this},eq:function(i){i=+i;return i===-1?this.slice(i):this.slice(i,i+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(core_slice.apply(this,arguments),"slice",core_slice.call(arguments).join(","))},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem)}))},end:function(){return this.prevObject||this.constructor(null)},push:core_push,sort:[].sort,splice:[].splice};jQuery.fn.init.prototype=jQuery.fn;jQuery.extend=jQuery.fn.extend=function(){var options,name,src,copy,copyIsArray,clone,target=arguments[0]||{},i=1,length=arguments.length,deep=false;if(typeof target==="boolean"){deep=target;target=arguments[1]||{};i=2}if(typeof target!=="object"&&!jQuery.isFunction(target)){target={}}if(length===i){target=this;--i}for(;i<length;i++){if((options=arguments[i])!=null){for(name in options){src=target[name];copy=options[name];if(target===copy){continue}if(deep&©&&(jQuery.isPlainObject(copy)||(copyIsArray=jQuery.isArray(copy)))){if(copyIsArray){copyIsArray=false;clone=src&&jQuery.isArray(src)?src:[]}else{clone=src&&jQuery.isPlainObject(src)?src:{}}target[name]=jQuery.extend(deep,clone,copy)}else if(copy!==undefined){target[name]=copy}}}}return target};jQuery.extend({noConflict:function(deep){if(window.$===jQuery){window.$=_$}if(deep&&window.jQuery===jQuery){window.jQuery=_jQuery}return jQuery},isReady:false,readyWait:1,holdReady:function(hold){if(hold){jQuery.readyWait++}else{jQuery.ready(true)}},ready:function(wait){if(wait===true?--jQuery.readyWait:jQuery.isReady){return}if(!document.body){return setTimeout(jQuery.ready,1)}jQuery.isReady=true;if(wait!==true&&--jQuery.readyWait>0){return}readyList.resolveWith(document,[jQuery]);if(jQuery.fn.trigger){jQuery(document).trigger("ready").off("ready")}},isFunction:function(obj){return jQuery.type(obj)==="function"},isArray:Array.isArray||function(obj){return jQuery.type(obj)==="array"},isWindow:function(obj){return obj!=null&&obj==obj.window},isNumeric:function(obj){return!isNaN(parseFloat(obj))&&isFinite(obj)},type:function(obj){return obj==null?String(obj):class2type[core_toString.call(obj)]||"object"},isPlainObject:function(obj){if(!obj||jQuery.type(obj)!=="object"||obj.nodeType||jQuery.isWindow(obj)){return false}try{if(obj.constructor&&!core_hasOwn.call(obj,"constructor")&&!core_hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){return false}}catch(e){return false}var key;for(key in obj){}return key===undefined||core_hasOwn.call(obj,key)},isEmptyObject:function(obj){var name;for(name in obj){return false}return true},error:function(msg){throw new Error(msg)},parseHTML:function(data,context,scripts){var parsed;if(!data||typeof data!=="string"){return null}if(typeof context==="boolean"){scripts=context;context=0}context=context||document;if(parsed=rsingleTag.exec(data)){return[context.createElement(parsed[1])]}parsed=jQuery.buildFragment([data],context,scripts?null:[]);return jQuery.merge([],(parsed.cacheable?jQuery.clone(parsed.fragment):parsed.fragment).childNodes)},parseJSON:function(data){if(!data||typeof data!=="string"){return null}data=jQuery.trim(data);if(window.JSON&&window.JSON.parse){return window.JSON.parse(data)}if(rvalidchars.test(data.replace(rvalidescape,"@").replace(rvalidtokens,"]").replace(rvalidbraces,""))){return new Function("return "+data)()}jQuery.error("Invalid JSON: "+data)},parseXML:function(data){var xml,tmp;if(!data||typeof data!=="string"){return null}try{if(window.DOMParser){tmp=new DOMParser;xml=tmp.parseFromString(data,"text/xml")}else{xml=new ActiveXObject("Microsoft.XMLDOM");xml.async="false";xml.loadXML(data)}}catch(e){xml=undefined}if(!xml||!xml.documentElement||xml.getElementsByTagName("parsererror").length){jQuery.error("Invalid XML: "+data)}return xml},noop:function(){},globalEval:function(data){if(data&&core_rnotwhite.test(data)){(window.execScript||function(data){window["eval"].call(window,data)})(data)}},camelCase:function(string){return string.replace(rmsPrefix,"ms-").replace(rdashAlpha,fcamelCase)},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toLowerCase()===name.toLowerCase()},each:function(obj,callback,args){var name,i=0,length=obj.length,isObj=length===undefined||jQuery.isFunction(obj);if(args){if(isObj){for(name in obj){if(callback.apply(obj[name],args)===false){break}}}else{for(;i<length;){if(callback.apply(obj[i++],args)===false){break}}}}else{if(isObj){for(name in obj){if(callback.call(obj[name],name,obj[name])===false){break}}}else{for(;i<length;){if(callback.call(obj[i],i,obj[i++])===false){break}}}}return obj},trim:core_trim&&!core_trim.call(" ")?function(text){return text==null?"":core_trim.call(text)}:function(text){return text==null?"":(text+"").replace(rtrim,"")},makeArray:function(arr,results){var type,ret=results||[];if(arr!=null){type=jQuery.type(arr);if(arr.length==null||type==="string"||type==="function"||type==="regexp"||jQuery.isWindow(arr)){core_push.call(ret,arr)}else{jQuery.merge(ret,arr)}}return ret},inArray:function(elem,arr,i){var len;if(arr){if(core_indexOf){return core_indexOf.call(arr,elem,i)}len=arr.length;i=i?i<0?Math.max(0,len+i):i:0;for(;i<len;i++){if(i in arr&&arr[i]===elem){return i}}}return-1},merge:function(first,second){var l=second.length,i=first.length,j=0;if(typeof l==="number"){for(;j<l;j++){first[i++]=second[j]}}else{while(second[j]!==undefined){first[i++]=second[j++]}}first.length=i;return first},grep:function(elems,callback,inv){var retVal,ret=[],i=0,length=elems.length;inv=!!inv;for(;i<length;i++){retVal=!!callback(elems[i],i);if(inv!==retVal){ret.push(elems[i])}}return ret},map:function(elems,callback,arg){var value,key,ret=[],i=0,length=elems.length,isArray=elems instanceof jQuery||length!==undefined&&typeof length==="number"&&(length>0&&elems[0]&&elems[length-1]||length===0||jQuery.isArray(elems));if(isArray){for(;i<length;i++){value=callback(elems[i],i,arg);if(value!=null){ret[ret.length]=value}}}else{for(key in elems){value=callback(elems[key],key,arg);if(value!=null){ret[ret.length]=value}}}return ret.concat.apply([],ret)},guid:1,proxy:function(fn,context){var tmp,args,proxy;if(typeof context==="string"){tmp=fn[context];context=fn;fn=tmp}if(!jQuery.isFunction(fn)){return undefined}args=core_slice.call(arguments,2);proxy=function(){return fn.apply(context,args.concat(core_slice.call(arguments)))};proxy.guid=fn.guid=fn.guid||jQuery.guid++;return proxy},access:function(elems,fn,key,value,chainable,emptyGet,pass){var exec,bulk=key==null,i=0,length=elems.length;if(key&&typeof key==="object"){for(i in key){jQuery.access(elems,fn,i,key[i],1,emptyGet,value)}chainable=1}else if(value!==undefined){exec=pass===undefined&&jQuery.isFunction(value);if(bulk){if(exec){exec=fn;fn=function(elem,key,value){return exec.call(jQuery(elem),value)}}else{fn.call(elems,value);fn=null}}if(fn){for(;i<length;i++){fn(elems[i],key,exec?value.call(elems[i],i,fn(elems[i],key)):value,pass)}}chainable=1}return chainable?elems:bulk?fn.call(elems):length?fn(elems[0],key):emptyGet},now:function(){return(new Date).getTime()}});jQuery.ready.promise=function(obj){if(!readyList){readyList=jQuery.Deferred();if(document.readyState==="complete"){setTimeout(jQuery.ready,1)}else if(document.addEventListener){document.addEventListener("DOMContentLoaded",DOMContentLoaded,false);window.addEventListener("load",jQuery.ready,false)}else{document.attachEvent("onreadystatechange",DOMContentLoaded);window.attachEvent("onload",jQuery.ready);var top=false;try{top=window.frameElement==null&&document.documentElement}catch(e){}if(top&&top.doScroll){(function doScrollCheck(){if(!jQuery.isReady){try{top.doScroll("left")}catch(e){return setTimeout(doScrollCheck,50)}jQuery.ready()}})()}}}return readyList.promise(obj)};jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(i,name){class2type["[object "+name+"]"]=name.toLowerCase()});rootjQuery=jQuery(document);var optionsCache={};function createOptions(options){var object=optionsCache[options]={};jQuery.each(options.split(core_rspace),function(_,flag){object[flag]=true});return object}jQuery.Callbacks=function(options){options=typeof options==="string"?optionsCache[options]||createOptions(options):jQuery.extend({},options);var memory,fired,firing,firingStart,firingLength,firingIndex,list=[],stack=!options.once&&[],fire=function(data){memory=options.memory&&data;fired=true;firingIndex=firingStart||0;firingStart=0;firingLength=list.length;firing=true;for(;list&&firingIndex<firingLength;firingIndex++){if(list[firingIndex].apply(data[0],data[1])===false&&options.stopOnFalse){memory=false;break}}firing=false;if(list){if(stack){if(stack.length){fire(stack.shift())}}else if(memory){list=[]}else{self.disable()}}},self={add:function(){if(list){var start=list.length;(function add(args){jQuery.each(args,function(_,arg){var type=jQuery.type(arg);if(type==="function"){if(!options.unique||!self.has(arg)){list.push(arg)}}else if(arg&&arg.length&&type!=="string"){add(arg)}})})(arguments);if(firing){firingLength=list.length}else if(memory){firingStart=start;fire(memory)}}return this},remove:function(){if(list){jQuery.each(arguments,function(_,arg){var index;while((index=jQuery.inArray(arg,list,index))>-1){list.splice(index,1);if(firing){if(index<=firingLength){firingLength--}if(index<=firingIndex){firingIndex--}}}})}return this},has:function(fn){return jQuery.inArray(fn,list)>-1},empty:function(){list=[];return this},disable:function(){list=stack=memory=undefined;return this},disabled:function(){return!list},lock:function(){stack=undefined;if(!memory){self.disable()}return this},locked:function(){return!stack},fireWith:function(context,args){args=args||[];args=[context,args.slice?args.slice():args];if(list&&(!fired||stack)){if(firing){stack.push(args)}else{fire(args)}}return this},fire:function(){self.fireWith(this,arguments);return this},fired:function(){return!!fired}};return self};jQuery.extend({Deferred:function(func){var tuples=[["resolve","done",jQuery.Callbacks("once memory"),"resolved"],["reject","fail",jQuery.Callbacks("once memory"),"rejected"],["notify","progress",jQuery.Callbacks("memory")]],state="pending",promise={state:function(){return state},always:function(){deferred.done(arguments).fail(arguments);return this},then:function(){var fns=arguments;return jQuery.Deferred(function(newDefer){jQuery.each(tuples,function(i,tuple){var action=tuple[0],fn=fns[i];deferred[tuple[1]](jQuery.isFunction(fn)?function(){var returned=fn.apply(this,arguments);if(returned&&jQuery.isFunction(returned.promise)){returned.promise().done(newDefer.resolve).fail(newDefer.reject).progress(newDefer.notify)}else{newDefer[action+"With"](this===deferred?newDefer:this,[returned])}}:newDefer[action])});fns=null}).promise()},promise:function(obj){return obj!=null?jQuery.extend(obj,promise):promise}},deferred={};promise.pipe=promise.then;jQuery.each(tuples,function(i,tuple){var list=tuple[2],stateString=tuple[3];promise[tuple[1]]=list.add;if(stateString){list.add(function(){state=stateString},tuples[i^1][2].disable,tuples[2][2].lock)}deferred[tuple[0]]=list.fire;deferred[tuple[0]+"With"]=list.fireWith});promise.promise(deferred);if(func){func.call(deferred,deferred)}return deferred},when:function(subordinate){var i=0,resolveValues=core_slice.call(arguments),length=resolveValues.length,remaining=length!==1||subordinate&&jQuery.isFunction(subordinate.promise)?length:0,deferred=remaining===1?subordinate:jQuery.Deferred(),updateFunc=function(i,contexts,values){return function(value){contexts[i]=this;values[i]=arguments.length>1?core_slice.call(arguments):value;if(values===progressValues){deferred.notifyWith(contexts,values)}else if(!--remaining){deferred.resolveWith(contexts,values)}}},progressValues,progressContexts,resolveContexts;if(length>1){progressValues=new Array(length);progressContexts=new Array(length);resolveContexts=new Array(length);for(;i<length;i++){if(resolveValues[i]&&jQuery.isFunction(resolveValues[i].promise)){resolveValues[i].promise().done(updateFunc(i,resolveContexts,resolveValues)).fail(deferred.reject).progress(updateFunc(i,progressContexts,progressValues))}else{--remaining}}}if(!remaining){deferred.resolveWith(resolveContexts,resolveValues)}return deferred.promise()}});jQuery.support=function(){var support,all,a,select,opt,input,fragment,eventName,i,isSupported,clickFn,div=document.createElement("div");div.setAttribute("className","t");div.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";all=div.getElementsByTagName("*");a=div.getElementsByTagName("a")[0];if(!all||!a||!all.length){return{}}select=document.createElement("select");opt=select.appendChild(document.createElement("option"));input=div.getElementsByTagName("input")[0];a.style.cssText="top:1px;float:left;opacity:.5";support={leadingWhitespace:div.firstChild.nodeType===3,tbody:!div.getElementsByTagName("tbody").length,htmlSerialize:!!div.getElementsByTagName("link").length,style:/top/.test(a.getAttribute("style")),hrefNormalized:a.getAttribute("href")==="/a",opacity:/^0.5/.test(a.style.opacity),cssFloat:!!a.style.cssFloat,checkOn:input.value==="on",optSelected:opt.selected,getSetAttribute:div.className!=="t",enctype:!!document.createElement("form").enctype,html5Clone:document.createElement("nav").cloneNode(true).outerHTML!=="<:nav></:nav>",boxModel:document.compatMode==="CSS1Compat",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true,boxSizingReliable:true,pixelPosition:false};input.checked=true;support.noCloneChecked=input.cloneNode(true).checked;select.disabled=true;support.optDisabled=!opt.disabled;try{delete div.test}catch(e){support.deleteExpando=false}if(!div.addEventListener&&div.attachEvent&&div.fireEvent){div.attachEvent("onclick",clickFn=function(){support.noCloneEvent=false});div.cloneNode(true).fireEvent("onclick");div.detachEvent("onclick",clickFn)}input=document.createElement("input");input.value="t";input.setAttribute("type","radio");support.radioValue=input.value==="t";input.setAttribute("checked","checked");input.setAttribute("name","t");div.appendChild(input);fragment=document.createDocumentFragment();fragment.appendChild(div.lastChild);support.checkClone=fragment.cloneNode(true).cloneNode(true).lastChild.checked;support.appendChecked=input.checked;fragment.removeChild(input);fragment.appendChild(div);if(div.attachEvent){for(i in{submit:true,change:true,focusin:true}){eventName="on"+i;isSupported=eventName in div;if(!isSupported){div.setAttribute(eventName,"return;");isSupported=typeof div[eventName]==="function"}support[i+"Bubbles"]=isSupported}}jQuery(function(){var container,div,tds,marginDiv,divReset="padding:0;margin:0;border:0;display:block;overflow:hidden;",body=document.getElementsByTagName("body")[0];if(!body){return}container=document.createElement("div");container.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";body.insertBefore(container,body.firstChild);div=document.createElement("div");container.appendChild(div);div.innerHTML="<table><tr><td></td><td>t</td></tr></table>";tds=div.getElementsByTagName("td");tds[0].style.cssText="padding:0;margin:0;border:0;display:none";isSupported=tds[0].offsetHeight===0;tds[0].style.display="";tds[1].style.display="none";support.reliableHiddenOffsets=isSupported&&tds[0].offsetHeight===0;div.innerHTML="";div.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";support.boxSizing=div.offsetWidth===4;support.doesNotIncludeMarginInBodyOffset=body.offsetTop!==1;if(window.getComputedStyle){support.pixelPosition=(window.getComputedStyle(div,null)||{}).top!=="1%";support.boxSizingReliable=(window.getComputedStyle(div,null)||{width:"4px"}).width==="4px";marginDiv=document.createElement("div");marginDiv.style.cssText=div.style.cssText=divReset;marginDiv.style.marginRight=marginDiv.style.width="0";div.style.width="1px";div.appendChild(marginDiv);support.reliableMarginRight=!parseFloat((window.getComputedStyle(marginDiv,null)||{}).marginRight)}if(typeof div.style.zoom!=="undefined"){div.innerHTML="";div.style.cssText=divReset+"width:1px;padding:1px;display:inline;zoom:1";support.inlineBlockNeedsLayout=div.offsetWidth===3;div.style.display="block";div.style.overflow="visible";div.innerHTML="<div></div>";div.firstChild.style.width="5px";support.shrinkWrapBlocks=div.offsetWidth!==3;container.style.zoom=1}body.removeChild(container);container=div=tds=marginDiv=null});fragment.removeChild(div);all=a=select=opt=input=fragment=div=null;return support}();var rbrace=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,rmultiDash=/([A-Z])/g;jQuery.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(jQuery.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(elem){elem=elem.nodeType?jQuery.cache[elem[jQuery.expando]]:elem[jQuery.expando];return!!elem&&!isEmptyDataObject(elem)},data:function(elem,name,data,pvt){if(!jQuery.acceptData(elem)){return}var thisCache,ret,internalKey=jQuery.expando,getByName=typeof name==="string",isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[internalKey]:elem[internalKey]&&internalKey;if((!id||!cache[id]||!pvt&&!cache[id].data)&&getByName&&data===undefined){return}if(!id){if(isNode){elem[internalKey]=id=jQuery.deletedIds.pop()||jQuery.guid++}else{id=internalKey}}if(!cache[id]){cache[id]={};if(!isNode){cache[id].toJSON=jQuery.noop}}if(typeof name==="object"||typeof name==="function"){if(pvt){cache[id]=jQuery.extend(cache[id],name)}else{cache[id].data=jQuery.extend(cache[id].data,name)}}thisCache=cache[id];if(!pvt){if(!thisCache.data){thisCache.data={}}thisCache=thisCache.data}if(data!==undefined){thisCache[jQuery.camelCase(name)]=data}if(getByName){ret=thisCache[name];if(ret==null){ret=thisCache[jQuery.camelCase(name)]}}else{ret=thisCache}return ret},removeData:function(elem,name,pvt){if(!jQuery.acceptData(elem)){return}var thisCache,i,l,isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[jQuery.expando]:jQuery.expando;if(!cache[id]){return}if(name){thisCache=pvt?cache[id]:cache[id].data;if(thisCache){if(!jQuery.isArray(name)){if(name in thisCache){name=[name]}else{name=jQuery.camelCase(name);if(name in thisCache){name=[name]}else{name=name.split(" ")}}}for(i=0,l=name.length;i<l;i++){delete thisCache[name[i]]}if(!(pvt?isEmptyDataObject:jQuery.isEmptyObject)(thisCache)){return}}}if(!pvt){delete cache[id].data;if(!isEmptyDataObject(cache[id])){return}}if(isNode){jQuery.cleanData([elem],true)}else if(jQuery.support.deleteExpando||cache!=cache.window){delete cache[id]}else{cache[id]=null}},_data:function(elem,name,data){return jQuery.data(elem,name,data,true)},acceptData:function(elem){var noData=elem.nodeName&&jQuery.noData[elem.nodeName.toLowerCase()];return!noData||noData!==true&&elem.getAttribute("classid")===noData}});jQuery.fn.extend({data:function(key,value){var parts,part,attr,name,l,elem=this[0],i=0,data=null;if(key===undefined){if(this.length){data=jQuery.data(elem);if(elem.nodeType===1&&!jQuery._data(elem,"parsedAttrs")){attr=elem.attributes;for(l=attr.length;i<l;i++){name=attr[i].name;if(!name.indexOf("data-")){name=jQuery.camelCase(name.substring(5));dataAttr(elem,name,data[name])}}jQuery._data(elem,"parsedAttrs",true)}}return data}if(typeof key==="object"){return this.each(function(){jQuery.data(this,key)})}parts=key.split(".",2);parts[1]=parts[1]?"."+parts[1]:"";part=parts[1]+"!";return jQuery.access(this,function(value){if(value===undefined){data=this.triggerHandler("getData"+part,[parts[0]]);if(data===undefined&&elem){data=jQuery.data(elem,key);data=dataAttr(elem,key,data)}return data===undefined&&parts[1]?this.data(parts[0]):data}parts[1]=value;this.each(function(){var self=jQuery(this);self.triggerHandler("setData"+part,parts);jQuery.data(this,key,value);self.triggerHandler("changeData"+part,parts)})},null,value,arguments.length>1,null,false)},removeData:function(key){return this.each(function(){jQuery.removeData(this,key)})}});function dataAttr(elem,key,data){if(data===undefined&&elem.nodeType===1){var name="data-"+key.replace(rmultiDash,"-$1").toLowerCase();data=elem.getAttribute(name);if(typeof data==="string"){try{data=data==="true"?true:data==="false"?false:data==="null"?null:+data+""===data?+data:rbrace.test(data)?jQuery.parseJSON(data):data}catch(e){}jQuery.data(elem,key,data)}else{data=undefined}}return data}function isEmptyDataObject(obj){var name;for(name in obj){if(name==="data"&&jQuery.isEmptyObject(obj[name])){continue}if(name!=="toJSON"){return false}}return true}jQuery.extend({queue:function(elem,type,data){var queue;if(elem){type=(type||"fx")+"queue";queue=jQuery._data(elem,type);if(data){if(!queue||jQuery.isArray(data)){queue=jQuery._data(elem,type,jQuery.makeArray(data))}else{queue.push(data)}}return queue||[]}},dequeue:function(elem,type){type=type||"fx";var queue=jQuery.queue(elem,type),startLength=queue.length,fn=queue.shift(),hooks=jQuery._queueHooks(elem,type),next=function(){jQuery.dequeue(elem,type)};if(fn==="inprogress"){fn=queue.shift();startLength--}if(fn){if(type==="fx"){queue.unshift("inprogress")}delete hooks.stop;fn.call(elem,next,hooks)}if(!startLength&&hooks){hooks.empty.fire()}},_queueHooks:function(elem,type){var key=type+"queueHooks";return jQuery._data(elem,key)||jQuery._data(elem,key,{empty:jQuery.Callbacks("once memory").add(function(){jQuery.removeData(elem,type+"queue",true);jQuery.removeData(elem,key,true)})})}});jQuery.fn.extend({queue:function(type,data){var setter=2;if(typeof type!=="string"){data=type;type="fx";setter--}if(arguments.length<setter){return jQuery.queue(this[0],type)}return data===undefined?this:this.each(function(){var queue=jQuery.queue(this,type,data);jQuery._queueHooks(this,type);if(type==="fx"&&queue[0]!=="inprogress"){jQuery.dequeue(this,type)}})},dequeue:function(type){return this.each(function(){jQuery.dequeue(this,type)})},delay:function(time,type){time=jQuery.fx?jQuery.fx.speeds[time]||time:time;type=type||"fx";return this.queue(type,function(next,hooks){var timeout=setTimeout(next,time);hooks.stop=function(){clearTimeout(timeout)}})},clearQueue:function(type){return this.queue(type||"fx",[])},promise:function(type,obj){var tmp,count=1,defer=jQuery.Deferred(),elements=this,i=this.length,resolve=function(){if(!--count){defer.resolveWith(elements,[elements])}};if(typeof type!=="string"){obj=type;type=undefined}type=type||"fx";while(i--){tmp=jQuery._data(elements[i],type+"queueHooks");if(tmp&&tmp.empty){count++;tmp.empty.add(resolve)}}resolve();return defer.promise(obj)}});var nodeHook,boolHook,fixSpecified,rclass=/[\t\r\n]/g,rreturn=/\r/g,rtype=/^(?:button|input)$/i,rfocusable=/^(?:button|input|object|select|textarea)$/i,rclickable=/^a(?:rea|)$/i,rboolean=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,getSetAttribute=jQuery.support.getSetAttribute;jQuery.fn.extend({attr:function(name,value){return jQuery.access(this,jQuery.attr,name,value,arguments.length>1)},removeAttr:function(name){return this.each(function(){jQuery.removeAttr(this,name)})},prop:function(name,value){return jQuery.access(this,jQuery.prop,name,value,arguments.length>1)},removeProp:function(name){name=jQuery.propFix[name]||name;return this.each(function(){try{this[name]=undefined;delete this[name]}catch(e){}})},addClass:function(value){var classNames,i,l,elem,setClass,c,cl;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).addClass(value.call(this,j,this.className))})}if(value&&typeof value==="string"){classNames=value.split(core_rspace);for(i=0,l=this.length;i<l;i++){elem=this[i];if(elem.nodeType===1){if(!elem.className&&classNames.length===1){elem.className=value}else{setClass=" "+elem.className+" ";for(c=0,cl=classNames.length;c<cl;c++){if(setClass.indexOf(" "+classNames[c]+" ")<0){setClass+=classNames[c]+" "}}elem.className=jQuery.trim(setClass)}}}}return this},removeClass:function(value){var removes,className,elem,c,cl,i,l;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).removeClass(value.call(this,j,this.className))})}if(value&&typeof value==="string"||value===undefined){removes=(value||"").split(core_rspace);for(i=0,l=this.length;i<l;i++){elem=this[i];if(elem.nodeType===1&&elem.className){className=(" "+elem.className+" ").replace(rclass," ");for(c=0,cl=removes.length;c<cl;c++){while(className.indexOf(" "+removes[c]+" ")>=0){className=className.replace(" "+removes[c]+" "," ")}}elem.className=value?jQuery.trim(className):""}}}return this},toggleClass:function(value,stateVal){var type=typeof value,isBool=typeof stateVal==="boolean";if(jQuery.isFunction(value)){return this.each(function(i){jQuery(this).toggleClass(value.call(this,i,this.className,stateVal),stateVal)})}return this.each(function(){if(type==="string"){var className,i=0,self=jQuery(this),state=stateVal,classNames=value.split(core_rspace);while(className=classNames[i++]){state=isBool?state:!self.hasClass(className);self[state?"addClass":"removeClass"](className)}}else if(type==="undefined"||type==="boolean"){if(this.className){jQuery._data(this,"__className__",this.className)}this.className=this.className||value===false?"":jQuery._data(this,"__className__")||""}})},hasClass:function(selector){var className=" "+selector+" ",i=0,l=this.length;for(;i<l;i++){if(this[i].nodeType===1&&(" "+this[i].className+" ").replace(rclass," ").indexOf(className)>=0){return true}}return false},val:function(value){var hooks,ret,isFunction,elem=this[0];if(!arguments.length){if(elem){hooks=jQuery.valHooks[elem.type]||jQuery.valHooks[elem.nodeName.toLowerCase()];if(hooks&&"get"in hooks&&(ret=hooks.get(elem,"value"))!==undefined){return ret}ret=elem.value;return typeof ret==="string"?ret.replace(rreturn,""):ret==null?"":ret}return}isFunction=jQuery.isFunction(value);return this.each(function(i){var val,self=jQuery(this);if(this.nodeType!==1){return}if(isFunction){val=value.call(this,i,self.val())}else{val=value}if(val==null){val=""}else if(typeof val==="number"){val+=""}else if(jQuery.isArray(val)){val=jQuery.map(val,function(value){return value==null?"":value+""})}hooks=jQuery.valHooks[this.type]||jQuery.valHooks[this.nodeName.toLowerCase()];if(!hooks||!("set"in hooks)||hooks.set(this,val,"value")===undefined){this.value=val}})}});jQuery.extend({valHooks:{option:{get:function(elem){var val=elem.attributes.value;return!val||val.specified?elem.value:elem.text}},select:{get:function(elem){var value,option,options=elem.options,index=elem.selectedIndex,one=elem.type==="select-one"||index<0,values=one?null:[],max=one?index+1:options.length,i=index<0?max:one?index:0;for(;i<max;i++){option=options[i];if((option.selected||i===index)&&(jQuery.support.optDisabled?!option.disabled:option.getAttribute("disabled")===null)&&(!option.parentNode.disabled||!jQuery.nodeName(option.parentNode,"optgroup"))){value=jQuery(option).val();if(one){return value}values.push(value)}}return values},set:function(elem,value){var values=jQuery.makeArray(value);jQuery(elem).find("option").each(function(){this.selected=jQuery.inArray(jQuery(this).val(),values)>=0});if(!values.length){elem.selectedIndex=-1}return values}}},attrFn:{},attr:function(elem,name,value,pass){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return}if(pass&&jQuery.isFunction(jQuery.fn[name])){return jQuery(elem)[name](value)}if(typeof elem.getAttribute==="undefined"){return jQuery.prop(elem,name,value)}notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=name.toLowerCase();hooks=jQuery.attrHooks[name]||(rboolean.test(name)?boolHook:nodeHook)}if(value!==undefined){if(value===null){jQuery.removeAttr(elem,name);return}else if(hooks&&"set"in hooks&¬xml&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{elem.setAttribute(name,value+"");return value}}else if(hooks&&"get"in hooks&¬xml&&(ret=hooks.get(elem,name))!==null){return ret}else{ret=elem.getAttribute(name);return ret===null?undefined:ret}},removeAttr:function(elem,value){var propName,attrNames,name,isBool,i=0;if(value&&elem.nodeType===1){attrNames=value.split(core_rspace);for(;i<attrNames.length;i++){name=attrNames[i];if(name){propName=jQuery.propFix[name]||name;isBool=rboolean.test(name);if(!isBool){jQuery.attr(elem,name,"")}elem.removeAttribute(getSetAttribute?name:propName);if(isBool&&propName in elem){elem[propName]=false}}}}},attrHooks:{type:{set:function(elem,value){if(rtype.test(elem.nodeName)&&elem.parentNode){jQuery.error("type property can't be changed") -}else if(!jQuery.support.radioValue&&value==="radio"&&jQuery.nodeName(elem,"input")){var val=elem.value;elem.setAttribute("type",value);if(val){elem.value=val}return value}}},value:{get:function(elem,name){if(nodeHook&&jQuery.nodeName(elem,"button")){return nodeHook.get(elem,name)}return name in elem?elem.value:null},set:function(elem,value,name){if(nodeHook&&jQuery.nodeName(elem,"button")){return nodeHook.set(elem,value,name)}elem.value=value}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(elem,name,value){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return}notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=jQuery.propFix[name]||name;hooks=jQuery.propHooks[name]}if(value!==undefined){if(hooks&&"set"in hooks&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{return elem[name]=value}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,name))!==null){return ret}else{return elem[name]}}},propHooks:{tabIndex:{get:function(elem){var attributeNode=elem.getAttributeNode("tabindex");return attributeNode&&attributeNode.specified?parseInt(attributeNode.value,10):rfocusable.test(elem.nodeName)||rclickable.test(elem.nodeName)&&elem.href?0:undefined}}}});boolHook={get:function(elem,name){var attrNode,property=jQuery.prop(elem,name);return property===true||typeof property!=="boolean"&&(attrNode=elem.getAttributeNode(name))&&attrNode.nodeValue!==false?name.toLowerCase():undefined},set:function(elem,value,name){var propName;if(value===false){jQuery.removeAttr(elem,name)}else{propName=jQuery.propFix[name]||name;if(propName in elem){elem[propName]=true}elem.setAttribute(name,name.toLowerCase())}return name}};if(!getSetAttribute){fixSpecified={name:true,id:true,coords:true};nodeHook=jQuery.valHooks.button={get:function(elem,name){var ret;ret=elem.getAttributeNode(name);return ret&&(fixSpecified[name]?ret.value!=="":ret.specified)?ret.value:undefined},set:function(elem,value,name){var ret=elem.getAttributeNode(name);if(!ret){ret=document.createAttribute(name);elem.setAttributeNode(ret)}return ret.value=value+""}};jQuery.each(["width","height"],function(i,name){jQuery.attrHooks[name]=jQuery.extend(jQuery.attrHooks[name],{set:function(elem,value){if(value===""){elem.setAttribute(name,"auto");return value}}})});jQuery.attrHooks.contenteditable={get:nodeHook.get,set:function(elem,value,name){if(value===""){value="false"}nodeHook.set(elem,value,name)}}}if(!jQuery.support.hrefNormalized){jQuery.each(["href","src","width","height"],function(i,name){jQuery.attrHooks[name]=jQuery.extend(jQuery.attrHooks[name],{get:function(elem){var ret=elem.getAttribute(name,2);return ret===null?undefined:ret}})})}if(!jQuery.support.style){jQuery.attrHooks.style={get:function(elem){return elem.style.cssText.toLowerCase()||undefined},set:function(elem,value){return elem.style.cssText=value+""}}}if(!jQuery.support.optSelected){jQuery.propHooks.selected=jQuery.extend(jQuery.propHooks.selected,{get:function(elem){var parent=elem.parentNode;if(parent){parent.selectedIndex;if(parent.parentNode){parent.parentNode.selectedIndex}}return null}})}if(!jQuery.support.enctype){jQuery.propFix.enctype="encoding"}if(!jQuery.support.checkOn){jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]={get:function(elem){return elem.getAttribute("value")===null?"on":elem.value}}})}jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]=jQuery.extend(jQuery.valHooks[this],{set:function(elem,value){if(jQuery.isArray(value)){return elem.checked=jQuery.inArray(jQuery(elem).val(),value)>=0}}})});var rformElems=/^(?:textarea|input|select)$/i,rtypenamespace=/^([^\.]*|)(?:\.(.+)|)$/,rhoverHack=/(?:^|\s)hover(\.\S+|)\b/,rkeyEvent=/^key/,rmouseEvent=/^(?:mouse|contextmenu)|click/,rfocusMorph=/^(?:focusinfocus|focusoutblur)$/,hoverHack=function(events){return jQuery.event.special.hover?events:events.replace(rhoverHack,"mouseenter$1 mouseleave$1")};jQuery.event={add:function(elem,types,handler,data,selector){var elemData,eventHandle,events,t,tns,type,namespaces,handleObj,handleObjIn,handlers,special;if(elem.nodeType===3||elem.nodeType===8||!types||!handler||!(elemData=jQuery._data(elem))){return}if(handler.handler){handleObjIn=handler;handler=handleObjIn.handler;selector=handleObjIn.selector}if(!handler.guid){handler.guid=jQuery.guid++}events=elemData.events;if(!events){elemData.events=events={}}eventHandle=elemData.handle;if(!eventHandle){elemData.handle=eventHandle=function(e){return typeof jQuery!=="undefined"&&(!e||jQuery.event.triggered!==e.type)?jQuery.event.dispatch.apply(eventHandle.elem,arguments):undefined};eventHandle.elem=elem}types=jQuery.trim(hoverHack(types)).split(" ");for(t=0;t<types.length;t++){tns=rtypenamespace.exec(types[t])||[];type=tns[1];namespaces=(tns[2]||"").split(".").sort();special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;special=jQuery.event.special[type]||{};handleObj=jQuery.extend({type:type,origType:tns[1],data:data,handler:handler,guid:handler.guid,selector:selector,needsContext:selector&&jQuery.expr.match.needsContext.test(selector),namespace:namespaces.join(".")},handleObjIn);handlers=events[type];if(!handlers){handlers=events[type]=[];handlers.delegateCount=0;if(!special.setup||special.setup.call(elem,data,namespaces,eventHandle)===false){if(elem.addEventListener){elem.addEventListener(type,eventHandle,false)}else if(elem.attachEvent){elem.attachEvent("on"+type,eventHandle)}}}if(special.add){special.add.call(elem,handleObj);if(!handleObj.handler.guid){handleObj.handler.guid=handler.guid}}if(selector){handlers.splice(handlers.delegateCount++,0,handleObj)}else{handlers.push(handleObj)}jQuery.event.global[type]=true}elem=null},global:{},remove:function(elem,types,handler,selector,mappedTypes){var t,tns,type,origType,namespaces,origCount,j,events,special,eventType,handleObj,elemData=jQuery.hasData(elem)&&jQuery._data(elem);if(!elemData||!(events=elemData.events)){return}types=jQuery.trim(hoverHack(types||"")).split(" ");for(t=0;t<types.length;t++){tns=rtypenamespace.exec(types[t])||[];type=origType=tns[1];namespaces=tns[2];if(!type){for(type in events){jQuery.event.remove(elem,type+types[t],handler,selector,true)}continue}special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;eventType=events[type]||[];origCount=eventType.length;namespaces=namespaces?new RegExp("(^|\\.)"+namespaces.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(j=0;j<eventType.length;j++){handleObj=eventType[j];if((mappedTypes||origType===handleObj.origType)&&(!handler||handler.guid===handleObj.guid)&&(!namespaces||namespaces.test(handleObj.namespace))&&(!selector||selector===handleObj.selector||selector==="**"&&handleObj.selector)){eventType.splice(j--,1);if(handleObj.selector){eventType.delegateCount--}if(special.remove){special.remove.call(elem,handleObj)}}}if(eventType.length===0&&origCount!==eventType.length){if(!special.teardown||special.teardown.call(elem,namespaces,elemData.handle)===false){jQuery.removeEvent(elem,type,elemData.handle)}delete events[type]}}if(jQuery.isEmptyObject(events)){delete elemData.handle;jQuery.removeData(elem,"events",true)}},customEvent:{getData:true,setData:true,changeData:true},trigger:function(event,data,elem,onlyHandlers){if(elem&&(elem.nodeType===3||elem.nodeType===8)){return}var cache,exclusive,i,cur,old,ontype,special,handle,eventPath,bubbleType,type=event.type||event,namespaces=[];if(rfocusMorph.test(type+jQuery.event.triggered)){return}if(type.indexOf("!")>=0){type=type.slice(0,-1);exclusive=true}if(type.indexOf(".")>=0){namespaces=type.split(".");type=namespaces.shift();namespaces.sort()}if((!elem||jQuery.event.customEvent[type])&&!jQuery.event.global[type]){return}event=typeof event==="object"?event[jQuery.expando]?event:new jQuery.Event(type,event):new jQuery.Event(type);event.type=type;event.isTrigger=true;event.exclusive=exclusive;event.namespace=namespaces.join(".");event.namespace_re=event.namespace?new RegExp("(^|\\.)"+namespaces.join("\\.(?:.*\\.|)")+"(\\.|$)"):null;ontype=type.indexOf(":")<0?"on"+type:"";if(!elem){cache=jQuery.cache;for(i in cache){if(cache[i].events&&cache[i].events[type]){jQuery.event.trigger(event,data,cache[i].handle.elem,true)}}return}event.result=undefined;if(!event.target){event.target=elem}data=data!=null?jQuery.makeArray(data):[];data.unshift(event);special=jQuery.event.special[type]||{};if(special.trigger&&special.trigger.apply(elem,data)===false){return}eventPath=[[elem,special.bindType||type]];if(!onlyHandlers&&!special.noBubble&&!jQuery.isWindow(elem)){bubbleType=special.delegateType||type;cur=rfocusMorph.test(bubbleType+type)?elem:elem.parentNode;for(old=elem;cur;cur=cur.parentNode){eventPath.push([cur,bubbleType]);old=cur}if(old===(elem.ownerDocument||document)){eventPath.push([old.defaultView||old.parentWindow||window,bubbleType])}}for(i=0;i<eventPath.length&&!event.isPropagationStopped();i++){cur=eventPath[i][0];event.type=eventPath[i][1];handle=(jQuery._data(cur,"events")||{})[event.type]&&jQuery._data(cur,"handle");if(handle){handle.apply(cur,data)}handle=ontype&&cur[ontype];if(handle&&jQuery.acceptData(cur)&&handle.apply&&handle.apply(cur,data)===false){event.preventDefault()}}event.type=type;if(!onlyHandlers&&!event.isDefaultPrevented()){if((!special._default||special._default.apply(elem.ownerDocument,data)===false)&&!(type==="click"&&jQuery.nodeName(elem,"a"))&&jQuery.acceptData(elem)){if(ontype&&elem[type]&&(type!=="focus"&&type!=="blur"||event.target.offsetWidth!==0)&&!jQuery.isWindow(elem)){old=elem[ontype];if(old){elem[ontype]=null}jQuery.event.triggered=type;elem[type]();jQuery.event.triggered=undefined;if(old){elem[ontype]=old}}}}return event.result},dispatch:function(event){event=jQuery.event.fix(event||window.event);var i,j,cur,ret,selMatch,matched,matches,handleObj,sel,related,handlers=(jQuery._data(this,"events")||{})[event.type]||[],delegateCount=handlers.delegateCount,args=core_slice.call(arguments),run_all=!event.exclusive&&!event.namespace,special=jQuery.event.special[event.type]||{},handlerQueue=[];args[0]=event;event.delegateTarget=this;if(special.preDispatch&&special.preDispatch.call(this,event)===false){return}if(delegateCount&&!(event.button&&event.type==="click")){for(cur=event.target;cur!=this;cur=cur.parentNode||this){if(cur.disabled!==true||event.type!=="click"){selMatch={};matches=[];for(i=0;i<delegateCount;i++){handleObj=handlers[i];sel=handleObj.selector;if(selMatch[sel]===undefined){selMatch[sel]=handleObj.needsContext?jQuery(sel,this).index(cur)>=0:jQuery.find(sel,this,null,[cur]).length}if(selMatch[sel]){matches.push(handleObj)}}if(matches.length){handlerQueue.push({elem:cur,matches:matches})}}}}if(handlers.length>delegateCount){handlerQueue.push({elem:this,matches:handlers.slice(delegateCount)})}for(i=0;i<handlerQueue.length&&!event.isPropagationStopped();i++){matched=handlerQueue[i];event.currentTarget=matched.elem;for(j=0;j<matched.matches.length&&!event.isImmediatePropagationStopped();j++){handleObj=matched.matches[j];if(run_all||!event.namespace&&!handleObj.namespace||event.namespace_re&&event.namespace_re.test(handleObj.namespace)){event.data=handleObj.data;event.handleObj=handleObj;ret=((jQuery.event.special[handleObj.origType]||{}).handle||handleObj.handler).apply(matched.elem,args);if(ret!==undefined){event.result=ret;if(ret===false){event.preventDefault();event.stopPropagation()}}}}}if(special.postDispatch){special.postDispatch.call(this,event)}return event.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(event,original){if(event.which==null){event.which=original.charCode!=null?original.charCode:original.keyCode}return event}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(event,original){var eventDoc,doc,body,button=original.button,fromElement=original.fromElement;if(event.pageX==null&&original.clientX!=null){eventDoc=event.target.ownerDocument||document;doc=eventDoc.documentElement;body=eventDoc.body;event.pageX=original.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc&&doc.clientLeft||body&&body.clientLeft||0);event.pageY=original.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc&&doc.clientTop||body&&body.clientTop||0)}if(!event.relatedTarget&&fromElement){event.relatedTarget=fromElement===event.target?original.toElement:fromElement}if(!event.which&&button!==undefined){event.which=button&1?1:button&2?3:button&4?2:0}return event}},fix:function(event){if(event[jQuery.expando]){return event}var i,prop,originalEvent=event,fixHook=jQuery.event.fixHooks[event.type]||{},copy=fixHook.props?this.props.concat(fixHook.props):this.props;event=jQuery.Event(originalEvent);for(i=copy.length;i;){prop=copy[--i];event[prop]=originalEvent[prop]}if(!event.target){event.target=originalEvent.srcElement||document}if(event.target.nodeType===3){event.target=event.target.parentNode}event.metaKey=!!event.metaKey;return fixHook.filter?fixHook.filter(event,originalEvent):event},special:{load:{noBubble:true},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(data,namespaces,eventHandle){if(jQuery.isWindow(this)){this.onbeforeunload=eventHandle}},teardown:function(namespaces,eventHandle){if(this.onbeforeunload===eventHandle){this.onbeforeunload=null}}}},simulate:function(type,elem,event,bubble){var e=jQuery.extend(new jQuery.Event,event,{type:type,isSimulated:true,originalEvent:{}});if(bubble){jQuery.event.trigger(e,null,elem)}else{jQuery.event.dispatch.call(elem,e)}if(e.isDefaultPrevented()){event.preventDefault()}}};jQuery.event.handle=jQuery.event.dispatch;jQuery.removeEvent=document.removeEventListener?function(elem,type,handle){if(elem.removeEventListener){elem.removeEventListener(type,handle,false)}}:function(elem,type,handle){var name="on"+type;if(elem.detachEvent){if(typeof elem[name]==="undefined"){elem[name]=null}elem.detachEvent(name,handle)}};jQuery.Event=function(src,props){if(!(this instanceof jQuery.Event)){return new jQuery.Event(src,props)}if(src&&src.type){this.originalEvent=src;this.type=src.type;this.isDefaultPrevented=src.defaultPrevented||src.returnValue===false||src.getPreventDefault&&src.getPreventDefault()?returnTrue:returnFalse}else{this.type=src}if(props){jQuery.extend(this,props)}this.timeStamp=src&&src.timeStamp||jQuery.now();this[jQuery.expando]=true};function returnFalse(){return false}function returnTrue(){return true}jQuery.Event.prototype={preventDefault:function(){this.isDefaultPrevented=returnTrue;var e=this.originalEvent;if(!e){return}if(e.preventDefault){e.preventDefault()}else{e.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=returnTrue;var e=this.originalEvent;if(!e){return}if(e.stopPropagation){e.stopPropagation()}e.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=returnTrue;this.stopPropagation()},isDefaultPrevented:returnFalse,isPropagationStopped:returnFalse,isImmediatePropagationStopped:returnFalse};jQuery.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(orig,fix){jQuery.event.special[orig]={delegateType:fix,bindType:fix,handle:function(event){var ret,target=this,related=event.relatedTarget,handleObj=event.handleObj,selector=handleObj.selector;if(!related||related!==target&&!jQuery.contains(target,related)){event.type=handleObj.origType;ret=handleObj.handler.apply(this,arguments);event.type=fix}return ret}}});if(!jQuery.support.submitBubbles){jQuery.event.special.submit={setup:function(){if(jQuery.nodeName(this,"form")){return false}jQuery.event.add(this,"click._submit keypress._submit",function(e){var elem=e.target,form=jQuery.nodeName(elem,"input")||jQuery.nodeName(elem,"button")?elem.form:undefined;if(form&&!jQuery._data(form,"_submit_attached")){jQuery.event.add(form,"submit._submit",function(event){event._submit_bubble=true});jQuery._data(form,"_submit_attached",true)}})},postDispatch:function(event){if(event._submit_bubble){delete event._submit_bubble;if(this.parentNode&&!event.isTrigger){jQuery.event.simulate("submit",this.parentNode,event,true)}}},teardown:function(){if(jQuery.nodeName(this,"form")){return false}jQuery.event.remove(this,"._submit")}}}if(!jQuery.support.changeBubbles){jQuery.event.special.change={setup:function(){if(rformElems.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio"){jQuery.event.add(this,"propertychange._change",function(event){if(event.originalEvent.propertyName==="checked"){this._just_changed=true}});jQuery.event.add(this,"click._change",function(event){if(this._just_changed&&!event.isTrigger){this._just_changed=false}jQuery.event.simulate("change",this,event,true)})}return false}jQuery.event.add(this,"beforeactivate._change",function(e){var elem=e.target;if(rformElems.test(elem.nodeName)&&!jQuery._data(elem,"_change_attached")){jQuery.event.add(elem,"change._change",function(event){if(this.parentNode&&!event.isSimulated&&!event.isTrigger){jQuery.event.simulate("change",this.parentNode,event,true)}});jQuery._data(elem,"_change_attached",true)}})},handle:function(event){var elem=event.target;if(this!==elem||event.isSimulated||event.isTrigger||elem.type!=="radio"&&elem.type!=="checkbox"){return event.handleObj.handler.apply(this,arguments)}},teardown:function(){jQuery.event.remove(this,"._change");return!rformElems.test(this.nodeName)}}}if(!jQuery.support.focusinBubbles){jQuery.each({focus:"focusin",blur:"focusout"},function(orig,fix){var attaches=0,handler=function(event){jQuery.event.simulate(fix,event.target,jQuery.event.fix(event),true)};jQuery.event.special[fix]={setup:function(){if(attaches++===0){document.addEventListener(orig,handler,true)}},teardown:function(){if(--attaches===0){document.removeEventListener(orig,handler,true)}}}})}jQuery.fn.extend({on:function(types,selector,data,fn,one){var origFn,type;if(typeof types==="object"){if(typeof selector!=="string"){data=data||selector;selector=undefined}for(type in types){this.on(type,selector,data,types[type],one)}return this}if(data==null&&fn==null){fn=selector;data=selector=undefined}else if(fn==null){if(typeof selector==="string"){fn=data;data=undefined}else{fn=data;data=selector;selector=undefined}}if(fn===false){fn=returnFalse}else if(!fn){return this}if(one===1){origFn=fn;fn=function(event){jQuery().off(event);return origFn.apply(this,arguments)};fn.guid=origFn.guid||(origFn.guid=jQuery.guid++)}return this.each(function(){jQuery.event.add(this,types,fn,data,selector)})},one:function(types,selector,data,fn){return this.on(types,selector,data,fn,1)},off:function(types,selector,fn){var handleObj,type;if(types&&types.preventDefault&&types.handleObj){handleObj=types.handleObj;jQuery(types.delegateTarget).off(handleObj.namespace?handleObj.origType+"."+handleObj.namespace:handleObj.origType,handleObj.selector,handleObj.handler);return this}if(typeof types==="object"){for(type in types){this.off(type,selector,types[type])}return this}if(selector===false||typeof selector==="function"){fn=selector;selector=undefined}if(fn===false){fn=returnFalse}return this.each(function(){jQuery.event.remove(this,types,fn,selector)})},bind:function(types,data,fn){return this.on(types,null,data,fn)},unbind:function(types,fn){return this.off(types,null,fn)},live:function(types,data,fn){jQuery(this.context).on(types,this.selector,data,fn);return this},die:function(types,fn){jQuery(this.context).off(types,this.selector||"**",fn);return this},delegate:function(selector,types,data,fn){return this.on(types,selector,data,fn)},undelegate:function(selector,types,fn){return arguments.length===1?this.off(selector,"**"):this.off(types,selector||"**",fn)},trigger:function(type,data){return this.each(function(){jQuery.event.trigger(type,data,this)})},triggerHandler:function(type,data){if(this[0]){return jQuery.event.trigger(type,data,this[0],true)}},toggle:function(fn){var args=arguments,guid=fn.guid||jQuery.guid++,i=0,toggler=function(event){var lastToggle=(jQuery._data(this,"lastToggle"+fn.guid)||0)%i;jQuery._data(this,"lastToggle"+fn.guid,lastToggle+1);event.preventDefault();return args[lastToggle].apply(this,arguments)||false};toggler.guid=guid;while(i<args.length){args[i++].guid=guid}return this.click(toggler)},hover:function(fnOver,fnOut){return this.mouseenter(fnOver).mouseleave(fnOut||fnOver)}});jQuery.each(("blur focus focusin focusout load resize scroll unload click dblclick "+"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave "+"change select submit keydown keypress keyup error contextmenu").split(" "),function(i,name){jQuery.fn[name]=function(data,fn){if(fn==null){fn=data;data=null}return arguments.length>0?this.on(name,null,data,fn):this.trigger(name)};if(rkeyEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.keyHooks}if(rmouseEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.mouseHooks}});(function(window,undefined){var cachedruns,assertGetIdNotName,Expr,getText,isXML,contains,compile,sortOrder,hasDuplicate,outermostContext,baseHasDuplicate=true,strundefined="undefined",expando=("sizcache"+Math.random()).replace(".",""),Token=String,document=window.document,docElem=document.documentElement,dirruns=0,done=0,pop=[].pop,push=[].push,slice=[].slice,indexOf=[].indexOf||function(elem){var i=0,len=this.length;for(;i<len;i++){if(this[i]===elem){return i}}return-1},markFunction=function(fn,value){fn[expando]=value==null||value;return fn},createCache=function(){var cache={},keys=[];return markFunction(function(key,value){if(keys.push(key)>Expr.cacheLength){delete cache[keys.shift()]}return cache[key+" "]=value},cache)},classCache=createCache(),tokenCache=createCache(),compilerCache=createCache(),whitespace="[\\x20\\t\\r\\n\\f]",characterEncoding="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",identifier=characterEncoding.replace("w","w#"),operators="([*^$|!~]?=)",attributes="\\["+whitespace+"*("+characterEncoding+")"+whitespace+"*(?:"+operators+whitespace+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+identifier+")|)|)"+whitespace+"*\\]",pseudos=":("+characterEncoding+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+attributes+")|[^:]|\\\\.)*|.*))\\)|)",pos=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+whitespace+"*((?:-\\d)?\\d*)"+whitespace+"*\\)|)(?=[^-]|$)",rtrim=new RegExp("^"+whitespace+"+|((?:^|[^\\\\])(?:\\\\.)*)"+whitespace+"+$","g"),rcomma=new RegExp("^"+whitespace+"*,"+whitespace+"*"),rcombinators=new RegExp("^"+whitespace+"*([\\x20\\t\\r\\n\\f>+~])"+whitespace+"*"),rpseudo=new RegExp(pseudos),rquickExpr=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,rnot=/^:not/,rsibling=/[\x20\t\r\n\f]*[+~]/,rendsWithNot=/:not\($/,rheader=/h\d/i,rinputs=/input|select|textarea|button/i,rbackslash=/\\(?!\\)/g,matchExpr={ID:new RegExp("^#("+characterEncoding+")"),CLASS:new RegExp("^\\.("+characterEncoding+")"),NAME:new RegExp("^\\[name=['\"]?("+characterEncoding+")['\"]?\\]"),TAG:new RegExp("^("+characterEncoding.replace("w","w*")+")"),ATTR:new RegExp("^"+attributes),PSEUDO:new RegExp("^"+pseudos),POS:new RegExp(pos,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+whitespace+"*(even|odd|(([+-]|)(\\d*)n|)"+whitespace+"*(?:([+-]|)"+whitespace+"*(\\d+)|))"+whitespace+"*\\)|)","i"),needsContext:new RegExp("^"+whitespace+"*[>+~]|"+pos,"i")},assert=function(fn){var div=document.createElement("div");try{return fn(div)}catch(e){return false}finally{div=null}},assertTagNameNoComments=assert(function(div){div.appendChild(document.createComment(""));return!div.getElementsByTagName("*").length}),assertHrefNotNormalized=assert(function(div){div.innerHTML="<a href='#'></a>";return div.firstChild&&typeof div.firstChild.getAttribute!==strundefined&&div.firstChild.getAttribute("href")==="#"}),assertAttributes=assert(function(div){div.innerHTML="<select></select>";var type=typeof div.lastChild.getAttribute("multiple");return type!=="boolean"&&type!=="string"}),assertUsableClassName=assert(function(div){div.innerHTML="<div class='hidden e'></div><div class='hidden'></div>";if(!div.getElementsByClassName||!div.getElementsByClassName("e").length){return false}div.lastChild.className="e";return div.getElementsByClassName("e").length===2}),assertUsableName=assert(function(div){div.id=expando+0;div.innerHTML="<a name='"+expando+"'></a><div name='"+expando+"'></div>";docElem.insertBefore(div,docElem.firstChild);var pass=document.getElementsByName&&document.getElementsByName(expando).length===2+document.getElementsByName(expando+0).length;assertGetIdNotName=!document.getElementById(expando);docElem.removeChild(div);return pass});try{slice.call(docElem.childNodes,0)[0].nodeType}catch(e){slice=function(i){var elem,results=[];for(;elem=this[i];i++){results.push(elem)}return results}}function Sizzle(selector,context,results,seed){results=results||[];context=context||document;var match,elem,xml,m,nodeType=context.nodeType;if(!selector||typeof selector!=="string"){return results}if(nodeType!==1&&nodeType!==9){return[]}xml=isXML(context);if(!xml&&!seed){if(match=rquickExpr.exec(selector)){if(m=match[1]){if(nodeType===9){elem=context.getElementById(m);if(elem&&elem.parentNode){if(elem.id===m){results.push(elem);return results}}else{return results}}else{if(context.ownerDocument&&(elem=context.ownerDocument.getElementById(m))&&contains(context,elem)&&elem.id===m){results.push(elem);return results}}}else if(match[2]){push.apply(results,slice.call(context.getElementsByTagName(selector),0));return results}else if((m=match[3])&&assertUsableClassName&&context.getElementsByClassName){push.apply(results,slice.call(context.getElementsByClassName(m),0));return results}}}return select(selector.replace(rtrim,"$1"),context,results,seed,xml)}Sizzle.matches=function(expr,elements){return Sizzle(expr,null,null,elements)};Sizzle.matchesSelector=function(elem,expr){return Sizzle(expr,null,null,[elem]).length>0};function createInputPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type===type}}function createButtonPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return(name==="input"||name==="button")&&elem.type===type}}function createPositionalPseudo(fn){return markFunction(function(argument){argument=+argument;return markFunction(function(seed,matches){var j,matchIndexes=fn([],seed.length,argument),i=matchIndexes.length;while(i--){if(seed[j=matchIndexes[i]]){seed[j]=!(matches[j]=seed[j])}}})})}getText=Sizzle.getText=function(elem){var node,ret="",i=0,nodeType=elem.nodeType;if(nodeType){if(nodeType===1||nodeType===9||nodeType===11){if(typeof elem.textContent==="string"){return elem.textContent}else{for(elem=elem.firstChild;elem;elem=elem.nextSibling){ret+=getText(elem)}}}else if(nodeType===3||nodeType===4){return elem.nodeValue}}else{for(;node=elem[i];i++){ret+=getText(node)}}return ret};isXML=Sizzle.isXML=function(elem){var documentElement=elem&&(elem.ownerDocument||elem).documentElement;return documentElement?documentElement.nodeName!=="HTML":false};contains=Sizzle.contains=docElem.contains?function(a,b){var adown=a.nodeType===9?a.documentElement:a,bup=b&&b.parentNode;return a===bup||!!(bup&&bup.nodeType===1&&adown.contains&&adown.contains(bup))}:docElem.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode){if(b===a){return true}}return false};Sizzle.attr=function(elem,name){var val,xml=isXML(elem);if(!xml){name=name.toLowerCase()}if(val=Expr.attrHandle[name]){return val(elem)}if(xml||assertAttributes){return elem.getAttribute(name)}val=elem.getAttributeNode(name);return val?typeof elem[name]==="boolean"?elem[name]?name:null:val.specified?val.value:null:null};Expr=Sizzle.selectors={cacheLength:50,createPseudo:markFunction,match:matchExpr,attrHandle:assertHrefNotNormalized?{}:{href:function(elem){return elem.getAttribute("href",2)},type:function(elem){return elem.getAttribute("type")}},find:{ID:assertGetIdNotName?function(id,context,xml){if(typeof context.getElementById!==strundefined&&!xml){var m=context.getElementById(id);return m&&m.parentNode?[m]:[]}}:function(id,context,xml){if(typeof context.getElementById!==strundefined&&!xml){var m=context.getElementById(id);return m?m.id===id||typeof m.getAttributeNode!==strundefined&&m.getAttributeNode("id").value===id?[m]:undefined:[]}},TAG:assertTagNameNoComments?function(tag,context){if(typeof context.getElementsByTagName!==strundefined){return context.getElementsByTagName(tag)}}:function(tag,context){var results=context.getElementsByTagName(tag);if(tag==="*"){var elem,tmp=[],i=0;for(;elem=results[i];i++){if(elem.nodeType===1){tmp.push(elem)}}return tmp}return results},NAME:assertUsableName&&function(tag,context){if(typeof context.getElementsByName!==strundefined){return context.getElementsByName(name)}},CLASS:assertUsableClassName&&function(className,context,xml){if(typeof context.getElementsByClassName!==strundefined&&!xml){return context.getElementsByClassName(className)}}},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(match){match[1]=match[1].replace(rbackslash,"");match[3]=(match[4]||match[5]||"").replace(rbackslash,"");if(match[2]==="~="){match[3]=" "+match[3]+" "}return match.slice(0,4)},CHILD:function(match){match[1]=match[1].toLowerCase();if(match[1]==="nth"){if(!match[2]){Sizzle.error(match[0])}match[3]=+(match[3]?match[4]+(match[5]||1):2*(match[2]==="even"||match[2]==="odd"));match[4]=+(match[6]+match[7]||match[2]==="odd")}else if(match[2]){Sizzle.error(match[0])}return match},PSEUDO:function(match){var unquoted,excess;if(matchExpr["CHILD"].test(match[0])){return null}if(match[3]){match[2]=match[3]}else if(unquoted=match[4]){if(rpseudo.test(unquoted)&&(excess=tokenize(unquoted,true))&&(excess=unquoted.indexOf(")",unquoted.length-excess)-unquoted.length)){unquoted=unquoted.slice(0,excess);match[0]=match[0].slice(0,excess)}match[2]=unquoted}return match.slice(0,3)}},filter:{ID:assertGetIdNotName?function(id){id=id.replace(rbackslash,"");return function(elem){return elem.getAttribute("id")===id}}:function(id){id=id.replace(rbackslash,"");return function(elem){var node=typeof elem.getAttributeNode!==strundefined&&elem.getAttributeNode("id");return node&&node.value===id}},TAG:function(nodeName){if(nodeName==="*"){return function(){return true}}nodeName=nodeName.replace(rbackslash,"").toLowerCase();return function(elem){return elem.nodeName&&elem.nodeName.toLowerCase()===nodeName}},CLASS:function(className){var pattern=classCache[expando][className+" "];return pattern||(pattern=new RegExp("(^|"+whitespace+")"+className+"("+whitespace+"|$)"))&&classCache(className,function(elem){return pattern.test(elem.className||typeof elem.getAttribute!==strundefined&&elem.getAttribute("class")||"")})},ATTR:function(name,operator,check){return function(elem,context){var result=Sizzle.attr(elem,name);if(result==null){return operator==="!="}if(!operator){return true}result+="";return operator==="="?result===check:operator==="!="?result!==check:operator==="^="?check&&result.indexOf(check)===0:operator==="*="?check&&result.indexOf(check)>-1:operator==="$="?check&&result.substr(result.length-check.length)===check:operator==="~="?(" "+result+" ").indexOf(check)>-1:operator==="|="?result===check||result.substr(0,check.length+1)===check+"-":false}},CHILD:function(type,argument,first,last){if(type==="nth"){return function(elem){var node,diff,parent=elem.parentNode;if(first===1&&last===0){return true}if(parent){diff=0;for(node=parent.firstChild;node;node=node.nextSibling){if(node.nodeType===1){diff++; -if(elem===node){break}}}}diff-=last;return diff===first||diff%first===0&&diff/first>=0}}return function(elem){var node=elem;switch(type){case"only":case"first":while(node=node.previousSibling){if(node.nodeType===1){return false}}if(type==="first"){return true}node=elem;case"last":while(node=node.nextSibling){if(node.nodeType===1){return false}}return true}}},PSEUDO:function(pseudo,argument){var args,fn=Expr.pseudos[pseudo]||Expr.setFilters[pseudo.toLowerCase()]||Sizzle.error("unsupported pseudo: "+pseudo);if(fn[expando]){return fn(argument)}if(fn.length>1){args=[pseudo,pseudo,"",argument];return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase())?markFunction(function(seed,matches){var idx,matched=fn(seed,argument),i=matched.length;while(i--){idx=indexOf.call(seed,matched[i]);seed[idx]=!(matches[idx]=matched[i])}}):function(elem){return fn(elem,0,args)}}return fn}},pseudos:{not:markFunction(function(selector){var input=[],results=[],matcher=compile(selector.replace(rtrim,"$1"));return matcher[expando]?markFunction(function(seed,matches,context,xml){var elem,unmatched=matcher(seed,null,xml,[]),i=seed.length;while(i--){if(elem=unmatched[i]){seed[i]=!(matches[i]=elem)}}}):function(elem,context,xml){input[0]=elem;matcher(input,null,xml,results);return!results.pop()}}),has:markFunction(function(selector){return function(elem){return Sizzle(selector,elem).length>0}}),contains:markFunction(function(text){return function(elem){return(elem.textContent||elem.innerText||getText(elem)).indexOf(text)>-1}}),enabled:function(elem){return elem.disabled===false},disabled:function(elem){return elem.disabled===true},checked:function(elem){var nodeName=elem.nodeName.toLowerCase();return nodeName==="input"&&!!elem.checked||nodeName==="option"&&!!elem.selected},selected:function(elem){if(elem.parentNode){elem.parentNode.selectedIndex}return elem.selected===true},parent:function(elem){return!Expr.pseudos["empty"](elem)},empty:function(elem){var nodeType;elem=elem.firstChild;while(elem){if(elem.nodeName>"@"||(nodeType=elem.nodeType)===3||nodeType===4){return false}elem=elem.nextSibling}return true},header:function(elem){return rheader.test(elem.nodeName)},text:function(elem){var type,attr;return elem.nodeName.toLowerCase()==="input"&&(type=elem.type)==="text"&&((attr=elem.getAttribute("type"))==null||attr.toLowerCase()===type)},radio:createInputPseudo("radio"),checkbox:createInputPseudo("checkbox"),file:createInputPseudo("file"),password:createInputPseudo("password"),image:createInputPseudo("image"),submit:createButtonPseudo("submit"),reset:createButtonPseudo("reset"),button:function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type==="button"||name==="button"},input:function(elem){return rinputs.test(elem.nodeName)},focus:function(elem){var doc=elem.ownerDocument;return elem===doc.activeElement&&(!doc.hasFocus||doc.hasFocus())&&!!(elem.type||elem.href||~elem.tabIndex)},active:function(elem){return elem===elem.ownerDocument.activeElement},first:createPositionalPseudo(function(){return[0]}),last:createPositionalPseudo(function(matchIndexes,length){return[length-1]}),eq:createPositionalPseudo(function(matchIndexes,length,argument){return[argument<0?argument+length:argument]}),even:createPositionalPseudo(function(matchIndexes,length){for(var i=0;i<length;i+=2){matchIndexes.push(i)}return matchIndexes}),odd:createPositionalPseudo(function(matchIndexes,length){for(var i=1;i<length;i+=2){matchIndexes.push(i)}return matchIndexes}),lt:createPositionalPseudo(function(matchIndexes,length,argument){for(var i=argument<0?argument+length:argument;--i>=0;){matchIndexes.push(i)}return matchIndexes}),gt:createPositionalPseudo(function(matchIndexes,length,argument){for(var i=argument<0?argument+length:argument;++i<length;){matchIndexes.push(i)}return matchIndexes})}};function siblingCheck(a,b,ret){if(a===b){return ret}var cur=a.nextSibling;while(cur){if(cur===b){return-1}cur=cur.nextSibling}return 1}sortOrder=docElem.compareDocumentPosition?function(a,b){if(a===b){hasDuplicate=true;return 0}return(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b){hasDuplicate=true;return 0}else if(a.sourceIndex&&b.sourceIndex){return a.sourceIndex-b.sourceIndex}var al,bl,ap=[],bp=[],aup=a.parentNode,bup=b.parentNode,cur=aup;if(aup===bup){return siblingCheck(a,b)}else if(!aup){return-1}else if(!bup){return 1}while(cur){ap.unshift(cur);cur=cur.parentNode}cur=bup;while(cur){bp.unshift(cur);cur=cur.parentNode}al=ap.length;bl=bp.length;for(var i=0;i<al&&i<bl;i++){if(ap[i]!==bp[i]){return siblingCheck(ap[i],bp[i])}}return i===al?siblingCheck(a,bp[i],-1):siblingCheck(ap[i],b,1)};[0,0].sort(sortOrder);baseHasDuplicate=!hasDuplicate;Sizzle.uniqueSort=function(results){var elem,duplicates=[],i=1,j=0;hasDuplicate=baseHasDuplicate;results.sort(sortOrder);if(hasDuplicate){for(;elem=results[i];i++){if(elem===results[i-1]){j=duplicates.push(i)}}while(j--){results.splice(duplicates[j],1)}}return results};Sizzle.error=function(msg){throw new Error("Syntax error, unrecognized expression: "+msg)};function tokenize(selector,parseOnly){var matched,match,tokens,type,soFar,groups,preFilters,cached=tokenCache[expando][selector+" "];if(cached){return parseOnly?0:cached.slice(0)}soFar=selector;groups=[];preFilters=Expr.preFilter;while(soFar){if(!matched||(match=rcomma.exec(soFar))){if(match){soFar=soFar.slice(match[0].length)||soFar}groups.push(tokens=[])}matched=false;if(match=rcombinators.exec(soFar)){tokens.push(matched=new Token(match.shift()));soFar=soFar.slice(matched.length);matched.type=match[0].replace(rtrim," ")}for(type in Expr.filter){if((match=matchExpr[type].exec(soFar))&&(!preFilters[type]||(match=preFilters[type](match)))){tokens.push(matched=new Token(match.shift()));soFar=soFar.slice(matched.length);matched.type=type;matched.matches=match}}if(!matched){break}}return parseOnly?soFar.length:soFar?Sizzle.error(selector):tokenCache(selector,groups).slice(0)}function addCombinator(matcher,combinator,base){var dir=combinator.dir,checkNonElements=base&&combinator.dir==="parentNode",doneName=done++;return combinator.first?function(elem,context,xml){while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){return matcher(elem,context,xml)}}}:function(elem,context,xml){if(!xml){var cache,dirkey=dirruns+" "+doneName+" ",cachedkey=dirkey+cachedruns;while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){if((cache=elem[expando])===cachedkey){return elem.sizset}else if(typeof cache==="string"&&cache.indexOf(dirkey)===0){if(elem.sizset){return elem}}else{elem[expando]=cachedkey;if(matcher(elem,context,xml)){elem.sizset=true;return elem}elem.sizset=false}}}}else{while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){if(matcher(elem,context,xml)){return elem}}}}}}function elementMatcher(matchers){return matchers.length>1?function(elem,context,xml){var i=matchers.length;while(i--){if(!matchers[i](elem,context,xml)){return false}}return true}:matchers[0]}function condense(unmatched,map,filter,context,xml){var elem,newUnmatched=[],i=0,len=unmatched.length,mapped=map!=null;for(;i<len;i++){if(elem=unmatched[i]){if(!filter||filter(elem,context,xml)){newUnmatched.push(elem);if(mapped){map.push(i)}}}}return newUnmatched}function setMatcher(preFilter,selector,matcher,postFilter,postFinder,postSelector){if(postFilter&&!postFilter[expando]){postFilter=setMatcher(postFilter)}if(postFinder&&!postFinder[expando]){postFinder=setMatcher(postFinder,postSelector)}return markFunction(function(seed,results,context,xml){var temp,i,elem,preMap=[],postMap=[],preexisting=results.length,elems=seed||multipleContexts(selector||"*",context.nodeType?[context]:context,[]),matcherIn=preFilter&&(seed||!selector)?condense(elems,preMap,preFilter,context,xml):elems,matcherOut=matcher?postFinder||(seed?preFilter:preexisting||postFilter)?[]:results:matcherIn;if(matcher){matcher(matcherIn,matcherOut,context,xml)}if(postFilter){temp=condense(matcherOut,postMap);postFilter(temp,[],context,xml);i=temp.length;while(i--){if(elem=temp[i]){matcherOut[postMap[i]]=!(matcherIn[postMap[i]]=elem)}}}if(seed){if(postFinder||preFilter){if(postFinder){temp=[];i=matcherOut.length;while(i--){if(elem=matcherOut[i]){temp.push(matcherIn[i]=elem)}}postFinder(null,matcherOut=[],temp,xml)}i=matcherOut.length;while(i--){if((elem=matcherOut[i])&&(temp=postFinder?indexOf.call(seed,elem):preMap[i])>-1){seed[temp]=!(results[temp]=elem)}}}}else{matcherOut=condense(matcherOut===results?matcherOut.splice(preexisting,matcherOut.length):matcherOut);if(postFinder){postFinder(null,results,matcherOut,xml)}else{push.apply(results,matcherOut)}}})}function matcherFromTokens(tokens){var checkContext,matcher,j,len=tokens.length,leadingRelative=Expr.relative[tokens[0].type],implicitRelative=leadingRelative||Expr.relative[" "],i=leadingRelative?1:0,matchContext=addCombinator(function(elem){return elem===checkContext},implicitRelative,true),matchAnyContext=addCombinator(function(elem){return indexOf.call(checkContext,elem)>-1},implicitRelative,true),matchers=[function(elem,context,xml){return!leadingRelative&&(xml||context!==outermostContext)||((checkContext=context).nodeType?matchContext(elem,context,xml):matchAnyContext(elem,context,xml))}];for(;i<len;i++){if(matcher=Expr.relative[tokens[i].type]){matchers=[addCombinator(elementMatcher(matchers),matcher)]}else{matcher=Expr.filter[tokens[i].type].apply(null,tokens[i].matches);if(matcher[expando]){j=++i;for(;j<len;j++){if(Expr.relative[tokens[j].type]){break}}return setMatcher(i>1&&elementMatcher(matchers),i>1&&tokens.slice(0,i-1).join("").replace(rtrim,"$1"),matcher,i<j&&matcherFromTokens(tokens.slice(i,j)),j<len&&matcherFromTokens(tokens=tokens.slice(j)),j<len&&tokens.join(""))}matchers.push(matcher)}}return elementMatcher(matchers)}function matcherFromGroupMatchers(elementMatchers,setMatchers){var bySet=setMatchers.length>0,byElement=elementMatchers.length>0,superMatcher=function(seed,context,xml,results,expandContext){var elem,j,matcher,setMatched=[],matchedCount=0,i="0",unmatched=seed&&[],outermost=expandContext!=null,contextBackup=outermostContext,elems=seed||byElement&&Expr.find["TAG"]("*",expandContext&&context.parentNode||context),dirrunsUnique=dirruns+=contextBackup==null?1:Math.E;if(outermost){outermostContext=context!==document&&context;cachedruns=superMatcher.el}for(;(elem=elems[i])!=null;i++){if(byElement&&elem){for(j=0;matcher=elementMatchers[j];j++){if(matcher(elem,context,xml)){results.push(elem);break}}if(outermost){dirruns=dirrunsUnique;cachedruns=++superMatcher.el}}if(bySet){if(elem=!matcher&&elem){matchedCount--}if(seed){unmatched.push(elem)}}}matchedCount+=i;if(bySet&&i!==matchedCount){for(j=0;matcher=setMatchers[j];j++){matcher(unmatched,setMatched,context,xml)}if(seed){if(matchedCount>0){while(i--){if(!(unmatched[i]||setMatched[i])){setMatched[i]=pop.call(results)}}}setMatched=condense(setMatched)}push.apply(results,setMatched);if(outermost&&!seed&&setMatched.length>0&&matchedCount+setMatchers.length>1){Sizzle.uniqueSort(results)}}if(outermost){dirruns=dirrunsUnique;outermostContext=contextBackup}return unmatched};superMatcher.el=0;return bySet?markFunction(superMatcher):superMatcher}compile=Sizzle.compile=function(selector,group){var i,setMatchers=[],elementMatchers=[],cached=compilerCache[expando][selector+" "];if(!cached){if(!group){group=tokenize(selector)}i=group.length;while(i--){cached=matcherFromTokens(group[i]);if(cached[expando]){setMatchers.push(cached)}else{elementMatchers.push(cached)}}cached=compilerCache(selector,matcherFromGroupMatchers(elementMatchers,setMatchers))}return cached};function multipleContexts(selector,contexts,results){var i=0,len=contexts.length;for(;i<len;i++){Sizzle(selector,contexts[i],results)}return results}function select(selector,context,results,seed,xml){var i,tokens,token,type,find,match=tokenize(selector),j=match.length;if(!seed){if(match.length===1){tokens=match[0]=match[0].slice(0);if(tokens.length>2&&(token=tokens[0]).type==="ID"&&context.nodeType===9&&!xml&&Expr.relative[tokens[1].type]){context=Expr.find["ID"](token.matches[0].replace(rbackslash,""),context,xml)[0];if(!context){return results}selector=selector.slice(tokens.shift().length)}for(i=matchExpr["POS"].test(selector)?-1:tokens.length-1;i>=0;i--){token=tokens[i];if(Expr.relative[type=token.type]){break}if(find=Expr.find[type]){if(seed=find(token.matches[0].replace(rbackslash,""),rsibling.test(tokens[0].type)&&context.parentNode||context,xml)){tokens.splice(i,1);selector=seed.length&&tokens.join("");if(!selector){push.apply(results,slice.call(seed,0));return results}break}}}}}compile(selector,match)(seed,context,xml,results,rsibling.test(selector));return results}if(document.querySelectorAll){(function(){var disconnectedMatch,oldSelect=select,rescape=/'|\\/g,rattributeQuotes=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,rbuggyQSA=[":focus"],rbuggyMatches=[":active"],matches=docElem.matchesSelector||docElem.mozMatchesSelector||docElem.webkitMatchesSelector||docElem.oMatchesSelector||docElem.msMatchesSelector;assert(function(div){div.innerHTML="<select><option selected=''></option></select>";if(!div.querySelectorAll("[selected]").length){rbuggyQSA.push("\\["+whitespace+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)")}if(!div.querySelectorAll(":checked").length){rbuggyQSA.push(":checked")}});assert(function(div){div.innerHTML="<p test=''></p>";if(div.querySelectorAll("[test^='']").length){rbuggyQSA.push("[*^$]="+whitespace+"*(?:\"\"|'')")}div.innerHTML="<input type='hidden'/>";if(!div.querySelectorAll(":enabled").length){rbuggyQSA.push(":enabled",":disabled")}});rbuggyQSA=new RegExp(rbuggyQSA.join("|"));select=function(selector,context,results,seed,xml){if(!seed&&!xml&&!rbuggyQSA.test(selector)){var groups,i,old=true,nid=expando,newContext=context,newSelector=context.nodeType===9&&selector;if(context.nodeType===1&&context.nodeName.toLowerCase()!=="object"){groups=tokenize(selector);if(old=context.getAttribute("id")){nid=old.replace(rescape,"\\$&")}else{context.setAttribute("id",nid)}nid="[id='"+nid+"'] ";i=groups.length;while(i--){groups[i]=nid+groups[i].join("")}newContext=rsibling.test(selector)&&context.parentNode||context;newSelector=groups.join(",")}if(newSelector){try{push.apply(results,slice.call(newContext.querySelectorAll(newSelector),0));return results}catch(qsaError){}finally{if(!old){context.removeAttribute("id")}}}}return oldSelect(selector,context,results,seed,xml)};if(matches){assert(function(div){disconnectedMatch=matches.call(div,"div");try{matches.call(div,"[test!='']:sizzle");rbuggyMatches.push("!=",pseudos)}catch(e){}});rbuggyMatches=new RegExp(rbuggyMatches.join("|"));Sizzle.matchesSelector=function(elem,expr){expr=expr.replace(rattributeQuotes,"='$1']");if(!isXML(elem)&&!rbuggyMatches.test(expr)&&!rbuggyQSA.test(expr)){try{var ret=matches.call(elem,expr);if(ret||disconnectedMatch||elem.document&&elem.document.nodeType!==11){return ret}}catch(e){}}return Sizzle(expr,null,null,[elem]).length>0}}})()}Expr.pseudos["nth"]=Expr.pseudos["eq"];function setFilters(){}Expr.filters=setFilters.prototype=Expr.pseudos;Expr.setFilters=new setFilters;Sizzle.attr=jQuery.attr;jQuery.find=Sizzle;jQuery.expr=Sizzle.selectors;jQuery.expr[":"]=jQuery.expr.pseudos;jQuery.unique=Sizzle.uniqueSort;jQuery.text=Sizzle.getText;jQuery.isXMLDoc=Sizzle.isXML;jQuery.contains=Sizzle.contains})(window);var runtil=/Until$/,rparentsprev=/^(?:parents|prev(?:Until|All))/,isSimple=/^.[^:#\[\.,]*$/,rneedsContext=jQuery.expr.match.needsContext,guaranteedUnique={children:true,contents:true,next:true,prev:true};jQuery.fn.extend({find:function(selector){var i,l,length,n,r,ret,self=this;if(typeof selector!=="string"){return jQuery(selector).filter(function(){for(i=0,l=self.length;i<l;i++){if(jQuery.contains(self[i],this)){return true}}})}ret=this.pushStack("","find",selector);for(i=0,l=this.length;i<l;i++){length=ret.length;jQuery.find(selector,this[i],ret);if(i>0){for(n=length;n<ret.length;n++){for(r=0;r<length;r++){if(ret[r]===ret[n]){ret.splice(n--,1);break}}}}}return ret},has:function(target){var i,targets=jQuery(target,this),len=targets.length;return this.filter(function(){for(i=0;i<len;i++){if(jQuery.contains(this,targets[i])){return true}}})},not:function(selector){return this.pushStack(winnow(this,selector,false),"not",selector)},filter:function(selector){return this.pushStack(winnow(this,selector,true),"filter",selector)},is:function(selector){return!!selector&&(typeof selector==="string"?rneedsContext.test(selector)?jQuery(selector,this.context).index(this[0])>=0:jQuery.filter(selector,this).length>0:this.filter(selector).length>0)},closest:function(selectors,context){var cur,i=0,l=this.length,ret=[],pos=rneedsContext.test(selectors)||typeof selectors!=="string"?jQuery(selectors,context||this.context):0;for(;i<l;i++){cur=this[i];while(cur&&cur.ownerDocument&&cur!==context&&cur.nodeType!==11){if(pos?pos.index(cur)>-1:jQuery.find.matchesSelector(cur,selectors)){ret.push(cur);break}cur=cur.parentNode}}ret=ret.length>1?jQuery.unique(ret):ret;return this.pushStack(ret,"closest",selectors)},index:function(elem){if(!elem){return this[0]&&this[0].parentNode?this.prevAll().length:-1}if(typeof elem==="string"){return jQuery.inArray(this[0],jQuery(elem))}return jQuery.inArray(elem.jquery?elem[0]:elem,this)},add:function(selector,context){var set=typeof selector==="string"?jQuery(selector,context):jQuery.makeArray(selector&&selector.nodeType?[selector]:selector),all=jQuery.merge(this.get(),set);return this.pushStack(isDisconnected(set[0])||isDisconnected(all[0])?all:jQuery.unique(all))},addBack:function(selector){return this.add(selector==null?this.prevObject:this.prevObject.filter(selector))}});jQuery.fn.andSelf=jQuery.fn.addBack;function isDisconnected(node){return!node||!node.parentNode||node.parentNode.nodeType===11}function sibling(cur,dir){do{cur=cur[dir]}while(cur&&cur.nodeType!==1);return cur}jQuery.each({parent:function(elem){var parent=elem.parentNode;return parent&&parent.nodeType!==11?parent:null},parents:function(elem){return jQuery.dir(elem,"parentNode")},parentsUntil:function(elem,i,until){return jQuery.dir(elem,"parentNode",until)},next:function(elem){return sibling(elem,"nextSibling")},prev:function(elem){return sibling(elem,"previousSibling")},nextAll:function(elem){return jQuery.dir(elem,"nextSibling")},prevAll:function(elem){return jQuery.dir(elem,"previousSibling")},nextUntil:function(elem,i,until){return jQuery.dir(elem,"nextSibling",until)},prevUntil:function(elem,i,until){return jQuery.dir(elem,"previousSibling",until)},siblings:function(elem){return jQuery.sibling((elem.parentNode||{}).firstChild,elem)},children:function(elem){return jQuery.sibling(elem.firstChild)},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.merge([],elem.childNodes)}},function(name,fn){jQuery.fn[name]=function(until,selector){var ret=jQuery.map(this,fn,until);if(!runtil.test(name)){selector=until}if(selector&&typeof selector==="string"){ret=jQuery.filter(selector,ret)}ret=this.length>1&&!guaranteedUnique[name]?jQuery.unique(ret):ret;if(this.length>1&&rparentsprev.test(name)){ret=ret.reverse()}return this.pushStack(ret,name,core_slice.call(arguments).join(","))}});jQuery.extend({filter:function(expr,elems,not){if(not){expr=":not("+expr+")"}return elems.length===1?jQuery.find.matchesSelector(elems[0],expr)?[elems[0]]:[]:jQuery.find.matches(expr,elems)},dir:function(elem,dir,until){var matched=[],cur=elem[dir];while(cur&&cur.nodeType!==9&&(until===undefined||cur.nodeType!==1||!jQuery(cur).is(until))){if(cur.nodeType===1){matched.push(cur)}cur=cur[dir]}return matched},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType===1&&n!==elem){r.push(n)}}return r}});function winnow(elements,qualifier,keep){qualifier=qualifier||0;if(jQuery.isFunction(qualifier)){return jQuery.grep(elements,function(elem,i){var retVal=!!qualifier.call(elem,i,elem);return retVal===keep})}else if(qualifier.nodeType){return jQuery.grep(elements,function(elem,i){return elem===qualifier===keep})}else if(typeof qualifier==="string"){var filtered=jQuery.grep(elements,function(elem){return elem.nodeType===1});if(isSimple.test(qualifier)){return jQuery.filter(qualifier,filtered,!keep)}else{qualifier=jQuery.filter(qualifier,filtered)}}return jQuery.grep(elements,function(elem,i){return jQuery.inArray(elem,qualifier)>=0===keep})}function createSafeFragment(document){var list=nodeNames.split("|"),safeFrag=document.createDocumentFragment();if(safeFrag.createElement){while(list.length){safeFrag.createElement(list.pop())}}return safeFrag}var nodeNames="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|"+"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",rinlinejQuery=/ jQuery\d+="(?:null|\d+)"/g,rleadingWhitespace=/^\s+/,rxhtmlTag=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,rtagName=/<([\w:]+)/,rtbody=/<tbody/i,rhtml=/<|&#?\w+;/,rnoInnerhtml=/<(?:script|style|link)/i,rnocache=/<(?:script|object|embed|option|style)/i,rnoshimcache=new RegExp("<(?:"+nodeNames+")[\\s/>]","i"),rcheckableType=/^(?:checkbox|radio)$/,rchecked=/checked\s*(?:[^=]|=\s*.checked.)/i,rscriptType=/\/(java|ecma)script/i,rcleanScript=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,wrapMap={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},safeFragment=createSafeFragment(document),fragmentDiv=safeFragment.appendChild(document.createElement("div"));wrapMap.optgroup=wrapMap.option;wrapMap.tbody=wrapMap.tfoot=wrapMap.colgroup=wrapMap.caption=wrapMap.thead;wrapMap.th=wrapMap.td;if(!jQuery.support.htmlSerialize){wrapMap._default=[1,"X<div>","</div>"]}jQuery.fn.extend({text:function(value){return jQuery.access(this,function(value){return value===undefined?jQuery.text(this):this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(value))},null,value,arguments.length)},wrapAll:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapAll(html.call(this,i))})}if(this[0]){var wrap=jQuery(html,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){wrap.insertBefore(this[0])}wrap.map(function(){var elem=this;while(elem.firstChild&&elem.firstChild.nodeType===1){elem=elem.firstChild}return elem}).append(this)}return this},wrapInner:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapInner(html.call(this,i))})}return this.each(function(){var self=jQuery(this),contents=self.contents();if(contents.length){contents.wrapAll(html)}else{self.append(html)}})},wrap:function(html){var isFunction=jQuery.isFunction(html);return this.each(function(i){jQuery(this).wrapAll(isFunction?html.call(this,i):html)})},unwrap:function(){return this.parent().each(function(){if(!jQuery.nodeName(this,"body")){jQuery(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1||this.nodeType===11){this.appendChild(elem)}})},prepend:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1||this.nodeType===11){this.insertBefore(elem,this.firstChild)}})},before:function(){if(!isDisconnected(this[0])){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this)})}if(arguments.length){var set=jQuery.clean(arguments);return this.pushStack(jQuery.merge(set,this),"before",this.selector)}},after:function(){if(!isDisconnected(this[0])){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this.nextSibling)})}if(arguments.length){var set=jQuery.clean(arguments);return this.pushStack(jQuery.merge(this,set),"after",this.selector)}},remove:function(selector,keepData){var elem,i=0;for(;(elem=this[i])!=null;i++){if(!selector||jQuery.filter(selector,[elem]).length){if(!keepData&&elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));jQuery.cleanData([elem])}if(elem.parentNode){elem.parentNode.removeChild(elem)}}}return this},empty:function(){var elem,i=0;for(;(elem=this[i])!=null;i++){if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"))}while(elem.firstChild){elem.removeChild(elem.firstChild)}}return this},clone:function(dataAndEvents,deepDataAndEvents){dataAndEvents=dataAndEvents==null?false:dataAndEvents;deepDataAndEvents=deepDataAndEvents==null?dataAndEvents:deepDataAndEvents;return this.map(function(){return jQuery.clone(this,dataAndEvents,deepDataAndEvents)})},html:function(value){return jQuery.access(this,function(value){var elem=this[0]||{},i=0,l=this.length;if(value===undefined){return elem.nodeType===1?elem.innerHTML.replace(rinlinejQuery,""):undefined}if(typeof value==="string"&&!rnoInnerhtml.test(value)&&(jQuery.support.htmlSerialize||!rnoshimcache.test(value))&&(jQuery.support.leadingWhitespace||!rleadingWhitespace.test(value))&&!wrapMap[(rtagName.exec(value)||["",""])[1].toLowerCase()]){value=value.replace(rxhtmlTag,"<$1></$2>");try{for(;i<l;i++){elem=this[i]||{};if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));elem.innerHTML=value}}elem=0}catch(e){}}if(elem){this.empty().append(value)}},null,value,arguments.length)},replaceWith:function(value){if(!isDisconnected(this[0])){if(jQuery.isFunction(value)){return this.each(function(i){var self=jQuery(this),old=self.html();self.replaceWith(value.call(this,i,old))})}if(typeof value!=="string"){value=jQuery(value).detach()}return this.each(function(){var next=this.nextSibling,parent=this.parentNode;jQuery(this).remove();if(next){jQuery(next).before(value)}else{jQuery(parent).append(value)}})}return this.length?this.pushStack(jQuery(jQuery.isFunction(value)?value():value),"replaceWith",value):this},detach:function(selector){return this.remove(selector,true)},domManip:function(args,table,callback){args=[].concat.apply([],args);var results,first,fragment,iNoClone,i=0,value=args[0],scripts=[],l=this.length;if(!jQuery.support.checkClone&&l>1&&typeof value==="string"&&rchecked.test(value)){return this.each(function(){jQuery(this).domManip(args,table,callback)})}if(jQuery.isFunction(value)){return this.each(function(i){var self=jQuery(this);args[0]=value.call(this,i,table?self.html():undefined);self.domManip(args,table,callback)})}if(this[0]){results=jQuery.buildFragment(args,this,scripts);fragment=results.fragment;first=fragment.firstChild;if(fragment.childNodes.length===1){fragment=first}if(first){table=table&&jQuery.nodeName(first,"tr");for(iNoClone=results.cacheable||l-1;i<l;i++){callback.call(table&&jQuery.nodeName(this[i],"table")?findOrAppend(this[i],"tbody"):this[i],i===iNoClone?fragment:jQuery.clone(fragment,true,true))}}fragment=first=null;if(scripts.length){jQuery.each(scripts,function(i,elem){if(elem.src){if(jQuery.ajax){jQuery.ajax({url:elem.src,type:"GET",dataType:"script",async:false,global:false,"throws":true})}else{jQuery.error("no ajax")}}else{jQuery.globalEval((elem.text||elem.textContent||elem.innerHTML||"").replace(rcleanScript,""))}if(elem.parentNode){elem.parentNode.removeChild(elem)}})}}return this}});function findOrAppend(elem,tag){return elem.getElementsByTagName(tag)[0]||elem.appendChild(elem.ownerDocument.createElement(tag))}function cloneCopyEvent(src,dest){if(dest.nodeType!==1||!jQuery.hasData(src)){return}var type,i,l,oldData=jQuery._data(src),curData=jQuery._data(dest,oldData),events=oldData.events;if(events){delete curData.handle;curData.events={};for(type in events){for(i=0,l=events[type].length;i<l;i++){jQuery.event.add(dest,type,events[type][i])}}}if(curData.data){curData.data=jQuery.extend({},curData.data)}}function cloneFixAttributes(src,dest){var nodeName;if(dest.nodeType!==1){return}if(dest.clearAttributes){dest.clearAttributes()}if(dest.mergeAttributes){dest.mergeAttributes(src)}nodeName=dest.nodeName.toLowerCase();if(nodeName==="object"){if(dest.parentNode){dest.outerHTML=src.outerHTML}if(jQuery.support.html5Clone&&(src.innerHTML&&!jQuery.trim(dest.innerHTML))){dest.innerHTML=src.innerHTML}}else if(nodeName==="input"&&rcheckableType.test(src.type)){dest.defaultChecked=dest.checked=src.checked;if(dest.value!==src.value){dest.value=src.value}}else if(nodeName==="option"){dest.selected=src.defaultSelected}else if(nodeName==="input"||nodeName==="textarea"){dest.defaultValue=src.defaultValue}else if(nodeName==="script"&&dest.text!==src.text){dest.text=src.text}dest.removeAttribute(jQuery.expando)}jQuery.buildFragment=function(args,context,scripts){var fragment,cacheable,cachehit,first=args[0];context=context||document;context=!context.nodeType&&context[0]||context;context=context.ownerDocument||context;if(args.length===1&&typeof first==="string"&&first.length<512&&context===document&&first.charAt(0)==="<"&&!rnocache.test(first)&&(jQuery.support.checkClone||!rchecked.test(first))&&(jQuery.support.html5Clone||!rnoshimcache.test(first))){cacheable=true;fragment=jQuery.fragments[first];cachehit=fragment!==undefined}if(!fragment){fragment=context.createDocumentFragment();jQuery.clean(args,context,fragment,scripts);if(cacheable){jQuery.fragments[first]=cachehit&&fragment}}return{fragment:fragment,cacheable:cacheable}};jQuery.fragments={};jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(selector){var elems,i=0,ret=[],insert=jQuery(selector),l=insert.length,parent=this.length===1&&this[0].parentNode;if((parent==null||parent&&parent.nodeType===11&&parent.childNodes.length===1)&&l===1){insert[original](this[0]);return this}else{for(;i<l;i++){elems=(i>0?this.clone(true):this).get();jQuery(insert[i])[original](elems);ret=ret.concat(elems)}return this.pushStack(ret,name,insert.selector)}}});function getAll(elem){if(typeof elem.getElementsByTagName!=="undefined"){return elem.getElementsByTagName("*")}else if(typeof elem.querySelectorAll!=="undefined"){return elem.querySelectorAll("*")}else{return[]}}function fixDefaultChecked(elem){if(rcheckableType.test(elem.type)){elem.defaultChecked=elem.checked}}jQuery.extend({clone:function(elem,dataAndEvents,deepDataAndEvents){var srcElements,destElements,i,clone;if(jQuery.support.html5Clone||jQuery.isXMLDoc(elem)||!rnoshimcache.test("<"+elem.nodeName+">")){clone=elem.cloneNode(true)}else{fragmentDiv.innerHTML=elem.outerHTML;fragmentDiv.removeChild(clone=fragmentDiv.firstChild)}if((!jQuery.support.noCloneEvent||!jQuery.support.noCloneChecked)&&(elem.nodeType===1||elem.nodeType===11)&&!jQuery.isXMLDoc(elem)){cloneFixAttributes(elem,clone);srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){if(destElements[i]){cloneFixAttributes(srcElements[i],destElements[i])}}}if(dataAndEvents){cloneCopyEvent(elem,clone);if(deepDataAndEvents){srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){cloneCopyEvent(srcElements[i],destElements[i])}}}srcElements=destElements=null;return clone},clean:function(elems,context,fragment,scripts){var i,j,elem,tag,wrap,depth,div,hasBody,tbody,len,handleScript,jsTags,safe=context===document&&safeFragment,ret=[];if(!context||typeof context.createDocumentFragment==="undefined"){context=document}for(i=0;(elem=elems[i])!=null;i++){if(typeof elem==="number"){elem+=""}if(!elem){continue}if(typeof elem==="string"){if(!rhtml.test(elem)){elem=context.createTextNode(elem)}else{safe=safe||createSafeFragment(context);div=context.createElement("div");safe.appendChild(div);elem=elem.replace(rxhtmlTag,"<$1></$2>");tag=(rtagName.exec(elem)||["",""])[1].toLowerCase();wrap=wrapMap[tag]||wrapMap._default;depth=wrap[0];div.innerHTML=wrap[1]+elem+wrap[2];while(depth--){div=div.lastChild -}if(!jQuery.support.tbody){hasBody=rtbody.test(elem);tbody=tag==="table"&&!hasBody?div.firstChild&&div.firstChild.childNodes:wrap[1]==="<table>"&&!hasBody?div.childNodes:[];for(j=tbody.length-1;j>=0;--j){if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length){tbody[j].parentNode.removeChild(tbody[j])}}}if(!jQuery.support.leadingWhitespace&&rleadingWhitespace.test(elem)){div.insertBefore(context.createTextNode(rleadingWhitespace.exec(elem)[0]),div.firstChild)}elem=div.childNodes;div.parentNode.removeChild(div)}}if(elem.nodeType){ret.push(elem)}else{jQuery.merge(ret,elem)}}if(div){elem=div=safe=null}if(!jQuery.support.appendChecked){for(i=0;(elem=ret[i])!=null;i++){if(jQuery.nodeName(elem,"input")){fixDefaultChecked(elem)}else if(typeof elem.getElementsByTagName!=="undefined"){jQuery.grep(elem.getElementsByTagName("input"),fixDefaultChecked)}}}if(fragment){handleScript=function(elem){if(!elem.type||rscriptType.test(elem.type)){return scripts?scripts.push(elem.parentNode?elem.parentNode.removeChild(elem):elem):fragment.appendChild(elem)}};for(i=0;(elem=ret[i])!=null;i++){if(!(jQuery.nodeName(elem,"script")&&handleScript(elem))){fragment.appendChild(elem);if(typeof elem.getElementsByTagName!=="undefined"){jsTags=jQuery.grep(jQuery.merge([],elem.getElementsByTagName("script")),handleScript);ret.splice.apply(ret,[i+1,0].concat(jsTags));i+=jsTags.length}}}}return ret},cleanData:function(elems,acceptData){var data,id,elem,type,i=0,internalKey=jQuery.expando,cache=jQuery.cache,deleteExpando=jQuery.support.deleteExpando,special=jQuery.event.special;for(;(elem=elems[i])!=null;i++){if(acceptData||jQuery.acceptData(elem)){id=elem[internalKey];data=id&&cache[id];if(data){if(data.events){for(type in data.events){if(special[type]){jQuery.event.remove(elem,type)}else{jQuery.removeEvent(elem,type,data.handle)}}}if(cache[id]){delete cache[id];if(deleteExpando){delete elem[internalKey]}else if(elem.removeAttribute){elem.removeAttribute(internalKey)}else{elem[internalKey]=null}jQuery.deletedIds.push(id)}}}}}});(function(){var matched,browser;jQuery.uaMatch=function(ua){ua=ua.toLowerCase();var match=/(chrome)[ \/]([\w.]+)/.exec(ua)||/(webkit)[ \/]([\w.]+)/.exec(ua)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua)||/(msie) ([\w.]+)/.exec(ua)||ua.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua)||[];return{browser:match[1]||"",version:match[2]||"0"}};matched=jQuery.uaMatch(navigator.userAgent);browser={};if(matched.browser){browser[matched.browser]=true;browser.version=matched.version}if(browser.chrome){browser.webkit=true}else if(browser.webkit){browser.safari=true}jQuery.browser=browser;jQuery.sub=function(){function jQuerySub(selector,context){return new jQuerySub.fn.init(selector,context)}jQuery.extend(true,jQuerySub,this);jQuerySub.superclass=this;jQuerySub.fn=jQuerySub.prototype=this();jQuerySub.fn.constructor=jQuerySub;jQuerySub.sub=this.sub;jQuerySub.fn.init=function init(selector,context){if(context&&context instanceof jQuery&&!(context instanceof jQuerySub)){context=jQuerySub(context)}return jQuery.fn.init.call(this,selector,context,rootjQuerySub)};jQuerySub.fn.init.prototype=jQuerySub.fn;var rootjQuerySub=jQuerySub(document);return jQuerySub}})();var curCSS,iframe,iframeDoc,ralpha=/alpha\([^)]*\)/i,ropacity=/opacity=([^)]*)/,rposition=/^(top|right|bottom|left)$/,rdisplayswap=/^(none|table(?!-c[ea]).+)/,rmargin=/^margin/,rnumsplit=new RegExp("^("+core_pnum+")(.*)$","i"),rnumnonpx=new RegExp("^("+core_pnum+")(?!px)[a-z%]+$","i"),rrelNum=new RegExp("^([-+])=("+core_pnum+")","i"),elemdisplay={BODY:"block"},cssShow={position:"absolute",visibility:"hidden",display:"block"},cssNormalTransform={letterSpacing:0,fontWeight:400},cssExpand=["Top","Right","Bottom","Left"],cssPrefixes=["Webkit","O","Moz","ms"],eventsToggle=jQuery.fn.toggle;function vendorPropName(style,name){if(name in style){return name}var capName=name.charAt(0).toUpperCase()+name.slice(1),origName=name,i=cssPrefixes.length;while(i--){name=cssPrefixes[i]+capName;if(name in style){return name}}return origName}function isHidden(elem,el){elem=el||elem;return jQuery.css(elem,"display")==="none"||!jQuery.contains(elem.ownerDocument,elem)}function showHide(elements,show){var elem,display,values=[],index=0,length=elements.length;for(;index<length;index++){elem=elements[index];if(!elem.style){continue}values[index]=jQuery._data(elem,"olddisplay");if(show){if(!values[index]&&elem.style.display==="none"){elem.style.display=""}if(elem.style.display===""&&isHidden(elem)){values[index]=jQuery._data(elem,"olddisplay",css_defaultDisplay(elem.nodeName))}}else{display=curCSS(elem,"display");if(!values[index]&&display!=="none"){jQuery._data(elem,"olddisplay",display)}}}for(index=0;index<length;index++){elem=elements[index];if(!elem.style){continue}if(!show||elem.style.display==="none"||elem.style.display===""){elem.style.display=show?values[index]||"":"none"}}return elements}jQuery.fn.extend({css:function(name,value){return jQuery.access(this,function(elem,name,value){return value!==undefined?jQuery.style(elem,name,value):jQuery.css(elem,name)},name,value,arguments.length>1)},show:function(){return showHide(this,true)},hide:function(){return showHide(this)},toggle:function(state,fn2){var bool=typeof state==="boolean";if(jQuery.isFunction(state)&&jQuery.isFunction(fn2)){return eventsToggle.apply(this,arguments)}return this.each(function(){if(bool?state:isHidden(this)){jQuery(this).show()}else{jQuery(this).hide()}})}});jQuery.extend({cssHooks:{opacity:{get:function(elem,computed){if(computed){var ret=curCSS(elem,"opacity");return ret===""?"1":ret}}}},cssNumber:{fillOpacity:true,fontWeight:true,lineHeight:true,opacity:true,orphans:true,widows:true,zIndex:true,zoom:true},cssProps:{"float":jQuery.support.cssFloat?"cssFloat":"styleFloat"},style:function(elem,name,value,extra){if(!elem||elem.nodeType===3||elem.nodeType===8||!elem.style){return}var ret,type,hooks,origName=jQuery.camelCase(name),style=elem.style;name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(value!==undefined){type=typeof value;if(type==="string"&&(ret=rrelNum.exec(value))){value=(ret[1]+1)*ret[2]+parseFloat(jQuery.css(elem,name));type="number"}if(value==null||type==="number"&&isNaN(value)){return}if(type==="number"&&!jQuery.cssNumber[origName]){value+="px"}if(!hooks||!("set"in hooks)||(value=hooks.set(elem,value,extra))!==undefined){try{style[name]=value}catch(e){}}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,false,extra))!==undefined){return ret}return style[name]}},css:function(elem,name,numeric,extra){var val,num,hooks,origName=jQuery.camelCase(name);name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(elem.style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(hooks&&"get"in hooks){val=hooks.get(elem,true,extra)}if(val===undefined){val=curCSS(elem,name)}if(val==="normal"&&name in cssNormalTransform){val=cssNormalTransform[name]}if(numeric||extra!==undefined){num=parseFloat(val);return numeric||jQuery.isNumeric(num)?num||0:val}return val},swap:function(elem,options,callback){var ret,name,old={};for(name in options){old[name]=elem.style[name];elem.style[name]=options[name]}ret=callback.call(elem);for(name in options){elem.style[name]=old[name]}return ret}});if(window.getComputedStyle){curCSS=function(elem,name){var ret,width,minWidth,maxWidth,computed=window.getComputedStyle(elem,null),style=elem.style;if(computed){ret=computed.getPropertyValue(name)||computed[name];if(ret===""&&!jQuery.contains(elem.ownerDocument,elem)){ret=jQuery.style(elem,name)}if(rnumnonpx.test(ret)&&rmargin.test(name)){width=style.width;minWidth=style.minWidth;maxWidth=style.maxWidth;style.minWidth=style.maxWidth=style.width=ret;ret=computed.width;style.width=width;style.minWidth=minWidth;style.maxWidth=maxWidth}}return ret}}else if(document.documentElement.currentStyle){curCSS=function(elem,name){var left,rsLeft,ret=elem.currentStyle&&elem.currentStyle[name],style=elem.style;if(ret==null&&style&&style[name]){ret=style[name]}if(rnumnonpx.test(ret)&&!rposition.test(name)){left=style.left;rsLeft=elem.runtimeStyle&&elem.runtimeStyle.left;if(rsLeft){elem.runtimeStyle.left=elem.currentStyle.left}style.left=name==="fontSize"?"1em":ret;ret=style.pixelLeft+"px";style.left=left;if(rsLeft){elem.runtimeStyle.left=rsLeft}}return ret===""?"auto":ret}}function setPositiveNumber(elem,value,subtract){var matches=rnumsplit.exec(value);return matches?Math.max(0,matches[1]-(subtract||0))+(matches[2]||"px"):value}function augmentWidthOrHeight(elem,name,extra,isBorderBox){var i=extra===(isBorderBox?"border":"content")?4:name==="width"?1:0,val=0;for(;i<4;i+=2){if(extra==="margin"){val+=jQuery.css(elem,extra+cssExpand[i],true)}if(isBorderBox){if(extra==="content"){val-=parseFloat(curCSS(elem,"padding"+cssExpand[i]))||0}if(extra!=="margin"){val-=parseFloat(curCSS(elem,"border"+cssExpand[i]+"Width"))||0}}else{val+=parseFloat(curCSS(elem,"padding"+cssExpand[i]))||0;if(extra!=="padding"){val+=parseFloat(curCSS(elem,"border"+cssExpand[i]+"Width"))||0}}}return val}function getWidthOrHeight(elem,name,extra){var val=name==="width"?elem.offsetWidth:elem.offsetHeight,valueIsBorderBox=true,isBorderBox=jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing")==="border-box";if(val<=0||val==null){val=curCSS(elem,name);if(val<0||val==null){val=elem.style[name]}if(rnumnonpx.test(val)){return val}valueIsBorderBox=isBorderBox&&(jQuery.support.boxSizingReliable||val===elem.style[name]);val=parseFloat(val)||0}return val+augmentWidthOrHeight(elem,name,extra||(isBorderBox?"border":"content"),valueIsBorderBox)+"px"}function css_defaultDisplay(nodeName){if(elemdisplay[nodeName]){return elemdisplay[nodeName]}var elem=jQuery("<"+nodeName+">").appendTo(document.body),display=elem.css("display");elem.remove();if(display==="none"||display===""){iframe=document.body.appendChild(iframe||jQuery.extend(document.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!iframeDoc||!iframe.createElement){iframeDoc=(iframe.contentWindow||iframe.contentDocument).document;iframeDoc.write("<!doctype html><html><body>");iframeDoc.close()}elem=iframeDoc.body.appendChild(iframeDoc.createElement(nodeName));display=curCSS(elem,"display");document.body.removeChild(iframe)}elemdisplay[nodeName]=display;return display}jQuery.each(["height","width"],function(i,name){jQuery.cssHooks[name]={get:function(elem,computed,extra){if(computed){if(elem.offsetWidth===0&&rdisplayswap.test(curCSS(elem,"display"))){return jQuery.swap(elem,cssShow,function(){return getWidthOrHeight(elem,name,extra)})}else{return getWidthOrHeight(elem,name,extra)}}},set:function(elem,value,extra){return setPositiveNumber(elem,value,extra?augmentWidthOrHeight(elem,name,extra,jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing")==="border-box"):0)}}});if(!jQuery.support.opacity){jQuery.cssHooks.opacity={get:function(elem,computed){return ropacity.test((computed&&elem.currentStyle?elem.currentStyle.filter:elem.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":computed?"1":""},set:function(elem,value){var style=elem.style,currentStyle=elem.currentStyle,opacity=jQuery.isNumeric(value)?"alpha(opacity="+value*100+")":"",filter=currentStyle&¤tStyle.filter||style.filter||"";style.zoom=1;if(value>=1&&jQuery.trim(filter.replace(ralpha,""))===""&&style.removeAttribute){style.removeAttribute("filter");if(currentStyle&&!currentStyle.filter){return}}style.filter=ralpha.test(filter)?filter.replace(ralpha,opacity):filter+" "+opacity}}}jQuery(function(){if(!jQuery.support.reliableMarginRight){jQuery.cssHooks.marginRight={get:function(elem,computed){return jQuery.swap(elem,{display:"inline-block"},function(){if(computed){return curCSS(elem,"marginRight")}})}}}if(!jQuery.support.pixelPosition&&jQuery.fn.position){jQuery.each(["top","left"],function(i,prop){jQuery.cssHooks[prop]={get:function(elem,computed){if(computed){var ret=curCSS(elem,prop);return rnumnonpx.test(ret)?jQuery(elem).position()[prop]+"px":ret}}}})}});if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.hidden=function(elem){return elem.offsetWidth===0&&elem.offsetHeight===0||!jQuery.support.reliableHiddenOffsets&&(elem.style&&elem.style.display||curCSS(elem,"display"))==="none"};jQuery.expr.filters.visible=function(elem){return!jQuery.expr.filters.hidden(elem)}}jQuery.each({margin:"",padding:"",border:"Width"},function(prefix,suffix){jQuery.cssHooks[prefix+suffix]={expand:function(value){var i,parts=typeof value==="string"?value.split(" "):[value],expanded={};for(i=0;i<4;i++){expanded[prefix+cssExpand[i]+suffix]=parts[i]||parts[i-2]||parts[0]}return expanded}};if(!rmargin.test(prefix)){jQuery.cssHooks[prefix+suffix].set=setPositiveNumber}});var r20=/%20/g,rbracket=/\[\]$/,rCRLF=/\r?\n/g,rinput=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,rselectTextarea=/^(?:select|textarea)/i;jQuery.fn.extend({serialize:function(){return jQuery.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?jQuery.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||rselectTextarea.test(this.nodeName)||rinput.test(this.type))}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:jQuery.isArray(val)?jQuery.map(val,function(val,i){return{name:elem.name,value:val.replace(rCRLF,"\r\n")}}):{name:elem.name,value:val.replace(rCRLF,"\r\n")}}).get()}});jQuery.param=function(a,traditional){var prefix,s=[],add=function(key,value){value=jQuery.isFunction(value)?value():value==null?"":value;s[s.length]=encodeURIComponent(key)+"="+encodeURIComponent(value)};if(traditional===undefined){traditional=jQuery.ajaxSettings&&jQuery.ajaxSettings.traditional}if(jQuery.isArray(a)||a.jquery&&!jQuery.isPlainObject(a)){jQuery.each(a,function(){add(this.name,this.value)})}else{for(prefix in a){buildParams(prefix,a[prefix],traditional,add)}}return s.join("&").replace(r20,"+")};function buildParams(prefix,obj,traditional,add){var name;if(jQuery.isArray(obj)){jQuery.each(obj,function(i,v){if(traditional||rbracket.test(prefix)){add(prefix,v)}else{buildParams(prefix+"["+(typeof v==="object"?i:"")+"]",v,traditional,add)}})}else if(!traditional&&jQuery.type(obj)==="object"){for(name in obj){buildParams(prefix+"["+name+"]",obj[name],traditional,add)}}else{add(prefix,obj)}}var ajaxLocParts,ajaxLocation,rhash=/#.*$/,rheaders=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,rlocalProtocol=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,rnoContent=/^(?:GET|HEAD)$/,rprotocol=/^\/\//,rquery=/\?/,rscript=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,rts=/([?&])_=[^&]*/,rurl=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,_load=jQuery.fn.load,prefilters={},transports={},allTypes=["*/"]+["*"];try{ajaxLocation=location.href}catch(e){ajaxLocation=document.createElement("a");ajaxLocation.href="";ajaxLocation=ajaxLocation.href}ajaxLocParts=rurl.exec(ajaxLocation.toLowerCase())||[];function addToPrefiltersOrTransports(structure){return function(dataTypeExpression,func){if(typeof dataTypeExpression!=="string"){func=dataTypeExpression;dataTypeExpression="*"}var dataType,list,placeBefore,dataTypes=dataTypeExpression.toLowerCase().split(core_rspace),i=0,length=dataTypes.length;if(jQuery.isFunction(func)){for(;i<length;i++){dataType=dataTypes[i];placeBefore=/^\+/.test(dataType);if(placeBefore){dataType=dataType.substr(1)||"*"}list=structure[dataType]=structure[dataType]||[];list[placeBefore?"unshift":"push"](func)}}}}function inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,dataType,inspected){dataType=dataType||options.dataTypes[0];inspected=inspected||{};inspected[dataType]=true;var selection,list=structure[dataType],i=0,length=list?list.length:0,executeOnly=structure===prefilters;for(;i<length&&(executeOnly||!selection);i++){selection=list[i](options,originalOptions,jqXHR);if(typeof selection==="string"){if(!executeOnly||inspected[selection]){selection=undefined}else{options.dataTypes.unshift(selection);selection=inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,selection,inspected)}}}if((executeOnly||!selection)&&!inspected["*"]){selection=inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,"*",inspected)}return selection}function ajaxExtend(target,src){var key,deep,flatOptions=jQuery.ajaxSettings.flatOptions||{};for(key in src){if(src[key]!==undefined){(flatOptions[key]?target:deep||(deep={}))[key]=src[key]}}if(deep){jQuery.extend(true,target,deep)}}jQuery.fn.load=function(url,params,callback){if(typeof url!=="string"&&_load){return _load.apply(this,arguments)}if(!this.length){return this}var selector,type,response,self=this,off=url.indexOf(" ");if(off>=0){selector=url.slice(off,url.length);url=url.slice(0,off)}if(jQuery.isFunction(params)){callback=params;params=undefined}else if(params&&typeof params==="object"){type="POST"}jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(jqXHR,status){if(callback){self.each(callback,response||[jqXHR.responseText,status,jqXHR])}}}).done(function(responseText){response=arguments;self.html(selector?jQuery("<div>").append(responseText.replace(rscript,"")).find(selector):responseText)});return this};jQuery.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(i,o){jQuery.fn[o]=function(f){return this.on(o,f)}});jQuery.each(["get","post"],function(i,method){jQuery[method]=function(url,data,callback,type){if(jQuery.isFunction(data)){type=type||callback;callback=data;data=undefined}return jQuery.ajax({type:method,url:url,data:data,success:callback,dataType:type})}});jQuery.extend({getScript:function(url,callback){return jQuery.get(url,undefined,callback,"script")},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json")},ajaxSetup:function(target,settings){if(settings){ajaxExtend(target,jQuery.ajaxSettings)}else{settings=target;target=jQuery.ajaxSettings}ajaxExtend(target,settings);return target},ajaxSettings:{url:ajaxLocation,isLocal:rlocalProtocol.test(ajaxLocParts[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":allTypes},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":window.String,"text html":true,"text json":jQuery.parseJSON,"text xml":jQuery.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:addToPrefiltersOrTransports(prefilters),ajaxTransport:addToPrefiltersOrTransports(transports),ajax:function(url,options){if(typeof url==="object"){options=url;url=undefined}options=options||{};var ifModifiedKey,responseHeadersString,responseHeaders,transport,timeoutTimer,parts,fireGlobals,i,s=jQuery.ajaxSetup({},options),callbackContext=s.context||s,globalEventContext=callbackContext!==s&&(callbackContext.nodeType||callbackContext instanceof jQuery)?jQuery(callbackContext):jQuery.event,deferred=jQuery.Deferred(),completeDeferred=jQuery.Callbacks("once memory"),statusCode=s.statusCode||{},requestHeaders={},requestHeadersNames={},state=0,strAbort="canceled",jqXHR={readyState:0,setRequestHeader:function(name,value){if(!state){var lname=name.toLowerCase();name=requestHeadersNames[lname]=requestHeadersNames[lname]||name;requestHeaders[name]=value}return this},getAllResponseHeaders:function(){return state===2?responseHeadersString:null},getResponseHeader:function(key){var match;if(state===2){if(!responseHeaders){responseHeaders={};while(match=rheaders.exec(responseHeadersString)){responseHeaders[match[1].toLowerCase()]=match[2]}}match=responseHeaders[key.toLowerCase()]}return match===undefined?null:match},overrideMimeType:function(type){if(!state){s.mimeType=type}return this},abort:function(statusText){statusText=statusText||strAbort;if(transport){transport.abort(statusText)}done(0,statusText);return this}};function done(status,nativeStatusText,responses,headers){var isSuccess,success,error,response,modified,statusText=nativeStatusText;if(state===2){return}state=2;if(timeoutTimer){clearTimeout(timeoutTimer)}transport=undefined;responseHeadersString=headers||"";jqXHR.readyState=status>0?4:0;if(responses){response=ajaxHandleResponses(s,jqXHR,responses)}if(status>=200&&status<300||status===304){if(s.ifModified){modified=jqXHR.getResponseHeader("Last-Modified");if(modified){jQuery.lastModified[ifModifiedKey]=modified}modified=jqXHR.getResponseHeader("Etag");if(modified){jQuery.etag[ifModifiedKey]=modified}}if(status===304){statusText="notmodified";isSuccess=true}else{isSuccess=ajaxConvert(s,response);statusText=isSuccess.state;success=isSuccess.data;error=isSuccess.error;isSuccess=!error}}else{error=statusText;if(!statusText||status){statusText="error";if(status<0){status=0}}}jqXHR.status=status;jqXHR.statusText=(nativeStatusText||statusText)+"";if(isSuccess){deferred.resolveWith(callbackContext,[success,statusText,jqXHR])}else{deferred.rejectWith(callbackContext,[jqXHR,statusText,error])}jqXHR.statusCode(statusCode);statusCode=undefined;if(fireGlobals){globalEventContext.trigger("ajax"+(isSuccess?"Success":"Error"),[jqXHR,s,isSuccess?success:error])}completeDeferred.fireWith(callbackContext,[jqXHR,statusText]);if(fireGlobals){globalEventContext.trigger("ajaxComplete",[jqXHR,s]);if(!--jQuery.active){jQuery.event.trigger("ajaxStop")}}}deferred.promise(jqXHR);jqXHR.success=jqXHR.done;jqXHR.error=jqXHR.fail;jqXHR.complete=completeDeferred.add;jqXHR.statusCode=function(map){if(map){var tmp;if(state<2){for(tmp in map){statusCode[tmp]=[statusCode[tmp],map[tmp]]}}else{tmp=map[jqXHR.status];jqXHR.always(tmp)}}return this};s.url=((url||s.url)+"").replace(rhash,"").replace(rprotocol,ajaxLocParts[1]+"//");s.dataTypes=jQuery.trim(s.dataType||"*").toLowerCase().split(core_rspace);if(s.crossDomain==null){parts=rurl.exec(s.url.toLowerCase());s.crossDomain=!!(parts&&(parts[1]!==ajaxLocParts[1]||parts[2]!==ajaxLocParts[2]||(parts[3]||(parts[1]==="http:"?80:443))!=(ajaxLocParts[3]||(ajaxLocParts[1]==="http:"?80:443))))}if(s.data&&s.processData&&typeof s.data!=="string"){s.data=jQuery.param(s.data,s.traditional)}inspectPrefiltersOrTransports(prefilters,s,options,jqXHR);if(state===2){return jqXHR}fireGlobals=s.global;s.type=s.type.toUpperCase();s.hasContent=!rnoContent.test(s.type);if(fireGlobals&&jQuery.active++===0){jQuery.event.trigger("ajaxStart")}if(!s.hasContent){if(s.data){s.url+=(rquery.test(s.url)?"&":"?")+s.data;delete s.data}ifModifiedKey=s.url;if(s.cache===false){var ts=jQuery.now(),ret=s.url.replace(rts,"$1_="+ts);s.url=ret+(ret===s.url?(rquery.test(s.url)?"&":"?")+"_="+ts:"")}}if(s.data&&s.hasContent&&s.contentType!==false||options.contentType){jqXHR.setRequestHeader("Content-Type",s.contentType)}if(s.ifModified){ifModifiedKey=ifModifiedKey||s.url;if(jQuery.lastModified[ifModifiedKey]){jqXHR.setRequestHeader("If-Modified-Since",jQuery.lastModified[ifModifiedKey])}if(jQuery.etag[ifModifiedKey]){jqXHR.setRequestHeader("If-None-Match",jQuery.etag[ifModifiedKey])}}jqXHR.setRequestHeader("Accept",s.dataTypes[0]&&s.accepts[s.dataTypes[0]]?s.accepts[s.dataTypes[0]]+(s.dataTypes[0]!=="*"?", "+allTypes+"; q=0.01":""):s.accepts["*"]);for(i in s.headers){jqXHR.setRequestHeader(i,s.headers[i])}if(s.beforeSend&&(s.beforeSend.call(callbackContext,jqXHR,s)===false||state===2)){return jqXHR.abort()}strAbort="abort";for(i in{success:1,error:1,complete:1}){jqXHR[i](s[i])}transport=inspectPrefiltersOrTransports(transports,s,options,jqXHR);if(!transport){done(-1,"No Transport")}else{jqXHR.readyState=1;if(fireGlobals){globalEventContext.trigger("ajaxSend",[jqXHR,s])}if(s.async&&s.timeout>0){timeoutTimer=setTimeout(function(){jqXHR.abort("timeout")},s.timeout)}try{state=1;transport.send(requestHeaders,done)}catch(e){if(state<2){done(-1,e)}else{throw e}}}return jqXHR},active:0,lastModified:{},etag:{}});function ajaxHandleResponses(s,jqXHR,responses){var ct,type,finalDataType,firstDataType,contents=s.contents,dataTypes=s.dataTypes,responseFields=s.responseFields;for(type in responseFields){if(type in responses){jqXHR[responseFields[type]]=responses[type]}}while(dataTypes[0]==="*"){dataTypes.shift();if(ct===undefined){ct=s.mimeType||jqXHR.getResponseHeader("content-type")}}if(ct){for(type in contents){if(contents[type]&&contents[type].test(ct)){dataTypes.unshift(type);break}}}if(dataTypes[0]in responses){finalDataType=dataTypes[0]}else{for(type in responses){if(!dataTypes[0]||s.converters[type+" "+dataTypes[0]]){finalDataType=type;break}if(!firstDataType){firstDataType=type}}finalDataType=finalDataType||firstDataType}if(finalDataType){if(finalDataType!==dataTypes[0]){dataTypes.unshift(finalDataType)}return responses[finalDataType]}}function ajaxConvert(s,response){var conv,conv2,current,tmp,dataTypes=s.dataTypes.slice(),prev=dataTypes[0],converters={},i=0;if(s.dataFilter){response=s.dataFilter(response,s.dataType)}if(dataTypes[1]){for(conv in s.converters){converters[conv.toLowerCase()]=s.converters[conv]}}for(;current=dataTypes[++i];){if(current!=="*"){if(prev!=="*"&&prev!==current){conv=converters[prev+" "+current]||converters["* "+current];if(!conv){for(conv2 in converters){tmp=conv2.split(" ");if(tmp[1]===current){conv=converters[prev+" "+tmp[0]]||converters["* "+tmp[0]];if(conv){if(conv===true){conv=converters[conv2]}else if(converters[conv2]!==true){current=tmp[0];dataTypes.splice(i--,0,current)}break}}}}if(conv!==true){if(conv&&s["throws"]){response=conv(response)}else{try{response=conv(response)}catch(e){return{state:"parsererror",error:conv?e:"No conversion from "+prev+" to "+current}}}}}prev=current}}return{state:"success",data:response}}var oldCallbacks=[],rquestion=/\?/,rjsonp=/(=)\?(?=&|$)|\?\?/,nonce=jQuery.now();jQuery.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var callback=oldCallbacks.pop()||jQuery.expando+"_"+nonce++;this[callback]=true;return callback}});jQuery.ajaxPrefilter("json jsonp",function(s,originalSettings,jqXHR){var callbackName,overwritten,responseContainer,data=s.data,url=s.url,hasCallback=s.jsonp!==false,replaceInUrl=hasCallback&&rjsonp.test(url),replaceInData=hasCallback&&!replaceInUrl&&typeof data==="string"&&!(s.contentType||"").indexOf("application/x-www-form-urlencoded")&&rjsonp.test(data);if(s.dataTypes[0]==="jsonp"||replaceInUrl||replaceInData){callbackName=s.jsonpCallback=jQuery.isFunction(s.jsonpCallback)?s.jsonpCallback():s.jsonpCallback;overwritten=window[callbackName];if(replaceInUrl){s.url=url.replace(rjsonp,"$1"+callbackName)}else if(replaceInData){s.data=data.replace(rjsonp,"$1"+callbackName)}else if(hasCallback){s.url+=(rquestion.test(url)?"&":"?")+s.jsonp+"="+callbackName}s.converters["script json"]=function(){if(!responseContainer){jQuery.error(callbackName+" was not called")}return responseContainer[0]};s.dataTypes[0]="json";window[callbackName]=function(){responseContainer=arguments};jqXHR.always(function(){window[callbackName]=overwritten;if(s[callbackName]){s.jsonpCallback=originalSettings.jsonpCallback;oldCallbacks.push(callbackName)}if(responseContainer&&jQuery.isFunction(overwritten)){overwritten(responseContainer[0])}responseContainer=overwritten=undefined});return"script"}});jQuery.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(text){jQuery.globalEval(text);return text}}});jQuery.ajaxPrefilter("script",function(s){if(s.cache===undefined){s.cache=false}if(s.crossDomain){s.type="GET";s.global=false}});jQuery.ajaxTransport("script",function(s){if(s.crossDomain){var script,head=document.head||document.getElementsByTagName("head")[0]||document.documentElement;return{send:function(_,callback){script=document.createElement("script");script.async="async";if(s.scriptCharset){script.charset=s.scriptCharset}script.src=s.url;script.onload=script.onreadystatechange=function(_,isAbort){if(isAbort||!script.readyState||/loaded|complete/.test(script.readyState)){script.onload=script.onreadystatechange=null;if(head&&script.parentNode){head.removeChild(script)}script=undefined;if(!isAbort){callback(200,"success")}}};head.insertBefore(script,head.firstChild)},abort:function(){if(script){script.onload(0,1)}}}}});var xhrCallbacks,xhrOnUnloadAbort=window.ActiveXObject?function(){for(var key in xhrCallbacks){xhrCallbacks[key](0,1)}}:false,xhrId=0;function createStandardXHR(){try{return new window.XMLHttpRequest}catch(e){}}function createActiveXHR(){try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(e){}}jQuery.ajaxSettings.xhr=window.ActiveXObject?function(){return!this.isLocal&&createStandardXHR()||createActiveXHR()}:createStandardXHR;(function(xhr){jQuery.extend(jQuery.support,{ajax:!!xhr,cors:!!xhr&&"withCredentials"in xhr})})(jQuery.ajaxSettings.xhr());if(jQuery.support.ajax){jQuery.ajaxTransport(function(s){if(!s.crossDomain||jQuery.support.cors){var callback;return{send:function(headers,complete){var handle,i,xhr=s.xhr();if(s.username){xhr.open(s.type,s.url,s.async,s.username,s.password)}else{xhr.open(s.type,s.url,s.async)}if(s.xhrFields){for(i in s.xhrFields){xhr[i]=s.xhrFields[i]}}if(s.mimeType&&xhr.overrideMimeType){xhr.overrideMimeType(s.mimeType)}if(!s.crossDomain&&!headers["X-Requested-With"]){headers["X-Requested-With"]="XMLHttpRequest"}try{for(i in headers){xhr.setRequestHeader(i,headers[i])}}catch(_){}xhr.send(s.hasContent&&s.data||null);callback=function(_,isAbort){var status,statusText,responseHeaders,responses,xml;try{if(callback&&(isAbort||xhr.readyState===4)){callback=undefined;if(handle){xhr.onreadystatechange=jQuery.noop;if(xhrOnUnloadAbort){delete xhrCallbacks[handle]}}if(isAbort){if(xhr.readyState!==4){xhr.abort()}}else{status=xhr.status;responseHeaders=xhr.getAllResponseHeaders();responses={};xml=xhr.responseXML;if(xml&&xml.documentElement){responses.xml=xml}try{responses.text=xhr.responseText}catch(e){}try{statusText=xhr.statusText}catch(e){statusText=""}if(!status&&s.isLocal&&!s.crossDomain){status=responses.text?200:404}else if(status===1223){status=204}}}}catch(firefoxAccessException){if(!isAbort){complete(-1,firefoxAccessException)}}if(responses){complete(status,statusText,responses,responseHeaders)}};if(!s.async){callback()}else if(xhr.readyState===4){setTimeout(callback,0)}else{handle=++xhrId;if(xhrOnUnloadAbort){if(!xhrCallbacks){xhrCallbacks={};jQuery(window).unload(xhrOnUnloadAbort)}xhrCallbacks[handle]=callback}xhr.onreadystatechange=callback}},abort:function(){if(callback){callback(0,1)}}}}})}var fxNow,timerId,rfxtypes=/^(?:toggle|show|hide)$/,rfxnum=new RegExp("^(?:([-+])=|)("+core_pnum+")([a-z%]*)$","i"),rrun=/queueHooks$/,animationPrefilters=[defaultPrefilter],tweeners={"*":[function(prop,value){var end,unit,tween=this.createTween(prop,value),parts=rfxnum.exec(value),target=tween.cur(),start=+target||0,scale=1,maxIterations=20;if(parts){end=+parts[2];unit=parts[3]||(jQuery.cssNumber[prop]?"":"px");if(unit!=="px"&&start){start=jQuery.css(tween.elem,prop,true)||end||1;do{scale=scale||".5";start=start/scale;jQuery.style(tween.elem,prop,start+unit)}while(scale!==(scale=tween.cur()/target)&&scale!==1&&--maxIterations)}tween.unit=unit;tween.start=start;tween.end=parts[1]?start+(parts[1]+1)*end:end}return tween}]};function createFxNow(){setTimeout(function(){fxNow=undefined},0);return fxNow=jQuery.now()}function createTweens(animation,props){jQuery.each(props,function(prop,value){var collection=(tweeners[prop]||[]).concat(tweeners["*"]),index=0,length=collection.length;for(;index<length;index++){if(collection[index].call(animation,prop,value)){return}}})}function Animation(elem,properties,options){var result,index=0,tweenerIndex=0,length=animationPrefilters.length,deferred=jQuery.Deferred().always(function(){delete tick.elem}),tick=function(){var currentTime=fxNow||createFxNow(),remaining=Math.max(0,animation.startTime+animation.duration-currentTime),temp=remaining/animation.duration||0,percent=1-temp,index=0,length=animation.tweens.length; -for(;index<length;index++){animation.tweens[index].run(percent)}deferred.notifyWith(elem,[animation,percent,remaining]);if(percent<1&&length){return remaining}else{deferred.resolveWith(elem,[animation]);return false}},animation=deferred.promise({elem:elem,props:jQuery.extend({},properties),opts:jQuery.extend(true,{specialEasing:{}},options),originalProperties:properties,originalOptions:options,startTime:fxNow||createFxNow(),duration:options.duration,tweens:[],createTween:function(prop,end,easing){var tween=jQuery.Tween(elem,animation.opts,prop,end,animation.opts.specialEasing[prop]||animation.opts.easing);animation.tweens.push(tween);return tween},stop:function(gotoEnd){var index=0,length=gotoEnd?animation.tweens.length:0;for(;index<length;index++){animation.tweens[index].run(1)}if(gotoEnd){deferred.resolveWith(elem,[animation,gotoEnd])}else{deferred.rejectWith(elem,[animation,gotoEnd])}return this}}),props=animation.props;propFilter(props,animation.opts.specialEasing);for(;index<length;index++){result=animationPrefilters[index].call(animation,elem,props,animation.opts);if(result){return result}}createTweens(animation,props);if(jQuery.isFunction(animation.opts.start)){animation.opts.start.call(elem,animation)}jQuery.fx.timer(jQuery.extend(tick,{anim:animation,queue:animation.opts.queue,elem:elem}));return animation.progress(animation.opts.progress).done(animation.opts.done,animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always)}function propFilter(props,specialEasing){var index,name,easing,value,hooks;for(index in props){name=jQuery.camelCase(index);easing=specialEasing[name];value=props[index];if(jQuery.isArray(value)){easing=value[1];value=props[index]=value[0]}if(index!==name){props[name]=value;delete props[index]}hooks=jQuery.cssHooks[name];if(hooks&&"expand"in hooks){value=hooks.expand(value);delete props[name];for(index in value){if(!(index in props)){props[index]=value[index];specialEasing[index]=easing}}}else{specialEasing[name]=easing}}}jQuery.Animation=jQuery.extend(Animation,{tweener:function(props,callback){if(jQuery.isFunction(props)){callback=props;props=["*"]}else{props=props.split(" ")}var prop,index=0,length=props.length;for(;index<length;index++){prop=props[index];tweeners[prop]=tweeners[prop]||[];tweeners[prop].unshift(callback)}},prefilter:function(callback,prepend){if(prepend){animationPrefilters.unshift(callback)}else{animationPrefilters.push(callback)}}});function defaultPrefilter(elem,props,opts){var index,prop,value,length,dataShow,toggle,tween,hooks,oldfire,anim=this,style=elem.style,orig={},handled=[],hidden=elem.nodeType&&isHidden(elem);if(!opts.queue){hooks=jQuery._queueHooks(elem,"fx");if(hooks.unqueued==null){hooks.unqueued=0;oldfire=hooks.empty.fire;hooks.empty.fire=function(){if(!hooks.unqueued){oldfire()}}}hooks.unqueued++;anim.always(function(){anim.always(function(){hooks.unqueued--;if(!jQuery.queue(elem,"fx").length){hooks.empty.fire()}})})}if(elem.nodeType===1&&("height"in props||"width"in props)){opts.overflow=[style.overflow,style.overflowX,style.overflowY];if(jQuery.css(elem,"display")==="inline"&&jQuery.css(elem,"float")==="none"){if(!jQuery.support.inlineBlockNeedsLayout||css_defaultDisplay(elem.nodeName)==="inline"){style.display="inline-block"}else{style.zoom=1}}}if(opts.overflow){style.overflow="hidden";if(!jQuery.support.shrinkWrapBlocks){anim.done(function(){style.overflow=opts.overflow[0];style.overflowX=opts.overflow[1];style.overflowY=opts.overflow[2]})}}for(index in props){value=props[index];if(rfxtypes.exec(value)){delete props[index];toggle=toggle||value==="toggle";if(value===(hidden?"hide":"show")){continue}handled.push(index)}}length=handled.length;if(length){dataShow=jQuery._data(elem,"fxshow")||jQuery._data(elem,"fxshow",{});if("hidden"in dataShow){hidden=dataShow.hidden}if(toggle){dataShow.hidden=!hidden}if(hidden){jQuery(elem).show()}else{anim.done(function(){jQuery(elem).hide()})}anim.done(function(){var prop;jQuery.removeData(elem,"fxshow",true);for(prop in orig){jQuery.style(elem,prop,orig[prop])}});for(index=0;index<length;index++){prop=handled[index];tween=anim.createTween(prop,hidden?dataShow[prop]:0);orig[prop]=dataShow[prop]||jQuery.style(elem,prop);if(!(prop in dataShow)){dataShow[prop]=tween.start;if(hidden){tween.end=tween.start;tween.start=prop==="width"||prop==="height"?1:0}}}}}function Tween(elem,options,prop,end,easing){return new Tween.prototype.init(elem,options,prop,end,easing)}jQuery.Tween=Tween;Tween.prototype={constructor:Tween,init:function(elem,options,prop,end,easing,unit){this.elem=elem;this.prop=prop;this.easing=easing||"swing";this.options=options;this.start=this.now=this.cur();this.end=end;this.unit=unit||(jQuery.cssNumber[prop]?"":"px")},cur:function(){var hooks=Tween.propHooks[this.prop];return hooks&&hooks.get?hooks.get(this):Tween.propHooks._default.get(this)},run:function(percent){var eased,hooks=Tween.propHooks[this.prop];if(this.options.duration){this.pos=eased=jQuery.easing[this.easing](percent,this.options.duration*percent,0,1,this.options.duration)}else{this.pos=eased=percent}this.now=(this.end-this.start)*eased+this.start;if(this.options.step){this.options.step.call(this.elem,this.now,this)}if(hooks&&hooks.set){hooks.set(this)}else{Tween.propHooks._default.set(this)}return this}};Tween.prototype.init.prototype=Tween.prototype;Tween.propHooks={_default:{get:function(tween){var result;if(tween.elem[tween.prop]!=null&&(!tween.elem.style||tween.elem.style[tween.prop]==null)){return tween.elem[tween.prop]}result=jQuery.css(tween.elem,tween.prop,false,"");return!result||result==="auto"?0:result},set:function(tween){if(jQuery.fx.step[tween.prop]){jQuery.fx.step[tween.prop](tween)}else if(tween.elem.style&&(tween.elem.style[jQuery.cssProps[tween.prop]]!=null||jQuery.cssHooks[tween.prop])){jQuery.style(tween.elem,tween.prop,tween.now+tween.unit)}else{tween.elem[tween.prop]=tween.now}}}};Tween.propHooks.scrollTop=Tween.propHooks.scrollLeft={set:function(tween){if(tween.elem.nodeType&&tween.elem.parentNode){tween.elem[tween.prop]=tween.now}}};jQuery.each(["toggle","show","hide"],function(i,name){var cssFn=jQuery.fn[name];jQuery.fn[name]=function(speed,easing,callback){return speed==null||typeof speed==="boolean"||!i&&jQuery.isFunction(speed)&&jQuery.isFunction(easing)?cssFn.apply(this,arguments):this.animate(genFx(name,true),speed,easing,callback)}});jQuery.fn.extend({fadeTo:function(speed,to,easing,callback){return this.filter(isHidden).css("opacity",0).show().end().animate({opacity:to},speed,easing,callback)},animate:function(prop,speed,easing,callback){var empty=jQuery.isEmptyObject(prop),optall=jQuery.speed(speed,easing,callback),doAnimation=function(){var anim=Animation(this,jQuery.extend({},prop),optall);if(empty){anim.stop(true)}};return empty||optall.queue===false?this.each(doAnimation):this.queue(optall.queue,doAnimation)},stop:function(type,clearQueue,gotoEnd){var stopQueue=function(hooks){var stop=hooks.stop;delete hooks.stop;stop(gotoEnd)};if(typeof type!=="string"){gotoEnd=clearQueue;clearQueue=type;type=undefined}if(clearQueue&&type!==false){this.queue(type||"fx",[])}return this.each(function(){var dequeue=true,index=type!=null&&type+"queueHooks",timers=jQuery.timers,data=jQuery._data(this);if(index){if(data[index]&&data[index].stop){stopQueue(data[index])}}else{for(index in data){if(data[index]&&data[index].stop&&rrun.test(index)){stopQueue(data[index])}}}for(index=timers.length;index--;){if(timers[index].elem===this&&(type==null||timers[index].queue===type)){timers[index].anim.stop(gotoEnd);dequeue=false;timers.splice(index,1)}}if(dequeue||!gotoEnd){jQuery.dequeue(this,type)}})}});function genFx(type,includeWidth){var which,attrs={height:type},i=0;includeWidth=includeWidth?1:0;for(;i<4;i+=2-includeWidth){which=cssExpand[i];attrs["margin"+which]=attrs["padding"+which]=type}if(includeWidth){attrs.opacity=attrs.width=type}return attrs}jQuery.each({slideDown:genFx("show"),slideUp:genFx("hide"),slideToggle:genFx("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(name,props){jQuery.fn[name]=function(speed,easing,callback){return this.animate(props,speed,easing,callback)}});jQuery.speed=function(speed,easing,fn){var opt=speed&&typeof speed==="object"?jQuery.extend({},speed):{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&!jQuery.isFunction(easing)&&easing};opt.duration=jQuery.fx.off?0:typeof opt.duration==="number"?opt.duration:opt.duration in jQuery.fx.speeds?jQuery.fx.speeds[opt.duration]:jQuery.fx.speeds._default;if(opt.queue==null||opt.queue===true){opt.queue="fx"}opt.old=opt.complete;opt.complete=function(){if(jQuery.isFunction(opt.old)){opt.old.call(this)}if(opt.queue){jQuery.dequeue(this,opt.queue)}};return opt};jQuery.easing={linear:function(p){return p},swing:function(p){return.5-Math.cos(p*Math.PI)/2}};jQuery.timers=[];jQuery.fx=Tween.prototype.init;jQuery.fx.tick=function(){var timer,timers=jQuery.timers,i=0;fxNow=jQuery.now();for(;i<timers.length;i++){timer=timers[i];if(!timer()&&timers[i]===timer){timers.splice(i--,1)}}if(!timers.length){jQuery.fx.stop()}fxNow=undefined};jQuery.fx.timer=function(timer){if(timer()&&jQuery.timers.push(timer)&&!timerId){timerId=setInterval(jQuery.fx.tick,jQuery.fx.interval)}};jQuery.fx.interval=13;jQuery.fx.stop=function(){clearInterval(timerId);timerId=null};jQuery.fx.speeds={slow:600,fast:200,_default:400};jQuery.fx.step={};if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.animated=function(elem){return jQuery.grep(jQuery.timers,function(fn){return elem===fn.elem}).length}}var rroot=/^(?:body|html)$/i;jQuery.fn.offset=function(options){if(arguments.length){return options===undefined?this:this.each(function(i){jQuery.offset.setOffset(this,options,i)})}var docElem,body,win,clientTop,clientLeft,scrollTop,scrollLeft,box={top:0,left:0},elem=this[0],doc=elem&&elem.ownerDocument;if(!doc){return}if((body=doc.body)===elem){return jQuery.offset.bodyOffset(elem)}docElem=doc.documentElement;if(!jQuery.contains(docElem,elem)){return box}if(typeof elem.getBoundingClientRect!=="undefined"){box=elem.getBoundingClientRect()}win=getWindow(doc);clientTop=docElem.clientTop||body.clientTop||0;clientLeft=docElem.clientLeft||body.clientLeft||0;scrollTop=win.pageYOffset||docElem.scrollTop;scrollLeft=win.pageXOffset||docElem.scrollLeft;return{top:box.top+scrollTop-clientTop,left:box.left+scrollLeft-clientLeft}};jQuery.offset={bodyOffset:function(body){var top=body.offsetTop,left=body.offsetLeft;if(jQuery.support.doesNotIncludeMarginInBodyOffset){top+=parseFloat(jQuery.css(body,"marginTop"))||0;left+=parseFloat(jQuery.css(body,"marginLeft"))||0}return{top:top,left:left}},setOffset:function(elem,options,i){var position=jQuery.css(elem,"position");if(position==="static"){elem.style.position="relative"}var curElem=jQuery(elem),curOffset=curElem.offset(),curCSSTop=jQuery.css(elem,"top"),curCSSLeft=jQuery.css(elem,"left"),calculatePosition=(position==="absolute"||position==="fixed")&&jQuery.inArray("auto",[curCSSTop,curCSSLeft])>-1,props={},curPosition={},curTop,curLeft;if(calculatePosition){curPosition=curElem.position();curTop=curPosition.top;curLeft=curPosition.left}else{curTop=parseFloat(curCSSTop)||0;curLeft=parseFloat(curCSSLeft)||0}if(jQuery.isFunction(options)){options=options.call(elem,i,curOffset)}if(options.top!=null){props.top=options.top-curOffset.top+curTop}if(options.left!=null){props.left=options.left-curOffset.left+curLeft}if("using"in options){options.using.call(elem,props)}else{curElem.css(props)}}};jQuery.fn.extend({position:function(){if(!this[0]){return}var elem=this[0],offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=rroot.test(offsetParent[0].nodeName)?{top:0,left:0}:offsetParent.offset();offset.top-=parseFloat(jQuery.css(elem,"marginTop"))||0;offset.left-=parseFloat(jQuery.css(elem,"marginLeft"))||0;parentOffset.top+=parseFloat(jQuery.css(offsetParent[0],"borderTopWidth"))||0;parentOffset.left+=parseFloat(jQuery.css(offsetParent[0],"borderLeftWidth"))||0;return{top:offset.top-parentOffset.top,left:offset.left-parentOffset.left}},offsetParent:function(){return this.map(function(){var offsetParent=this.offsetParent||document.body;while(offsetParent&&(!rroot.test(offsetParent.nodeName)&&jQuery.css(offsetParent,"position")==="static")){offsetParent=offsetParent.offsetParent}return offsetParent||document.body})}});jQuery.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(method,prop){var top=/Y/.test(prop);jQuery.fn[method]=function(val){return jQuery.access(this,function(elem,method,val){var win=getWindow(elem);if(val===undefined){return win?prop in win?win[prop]:win.document.documentElement[method]:elem[method]}if(win){win.scrollTo(!top?val:jQuery(win).scrollLeft(),top?val:jQuery(win).scrollTop())}else{elem[method]=val}},method,val,arguments.length,null)}});function getWindow(elem){return jQuery.isWindow(elem)?elem:elem.nodeType===9?elem.defaultView||elem.parentWindow:false}jQuery.each({Height:"height",Width:"width"},function(name,type){jQuery.each({padding:"inner"+name,content:type,"":"outer"+name},function(defaultExtra,funcName){jQuery.fn[funcName]=function(margin,value){var chainable=arguments.length&&(defaultExtra||typeof margin!=="boolean"),extra=defaultExtra||(margin===true||value===true?"margin":"border");return jQuery.access(this,function(elem,type,value){var doc;if(jQuery.isWindow(elem)){return elem.document.documentElement["client"+name]}if(elem.nodeType===9){doc=elem.documentElement;return Math.max(elem.body["scroll"+name],doc["scroll"+name],elem.body["offset"+name],doc["offset"+name],doc["client"+name])}return value===undefined?jQuery.css(elem,type,value,extra):jQuery.style(elem,type,value,extra)},type,chainable?margin:undefined,chainable,null)}})});window.jQuery=window.$=jQuery;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return jQuery})}})(window);
\ No newline at end of file +(function(window,undefined){var rootjQuery,readyList,document=window.document,location=window.location,navigator=window.navigator,_jQuery=window.jQuery,_$=window.$,core_push=Array.prototype.push,core_slice=Array.prototype.slice,core_indexOf=Array.prototype.indexOf,core_toString=Object.prototype.toString,core_hasOwn=Object.prototype.hasOwnProperty,core_trim=String.prototype.trim,jQuery=function(selector,context){return new jQuery.fn.init(selector,context,rootjQuery)},core_pnum=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,core_rnotwhite=/\S/,core_rspace=/\s+/,rtrim=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,rquickExpr=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,rsingleTag=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,rvalidchars=/^[\],:{}\s]*$/,rvalidbraces=/(?:^|:|,)(?:\s*\[)+/g,rvalidescape=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,rvalidtokens=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,rmsPrefix=/^-ms-/,rdashAlpha=/-([\da-z])/gi,fcamelCase=function(all,letter){return(letter+"").toUpperCase()},DOMContentLoaded=function(){if(document.addEventListener){document.removeEventListener("DOMContentLoaded",DOMContentLoaded,false);jQuery.ready()}else if(document.readyState==="complete"){document.detachEvent("onreadystatechange",DOMContentLoaded);jQuery.ready()}},class2type={};jQuery.fn=jQuery.prototype={constructor:jQuery,init:function(selector,context,rootjQuery){var match,elem,ret,doc;if(!selector){return this}if(selector.nodeType){this.context=this[0]=selector;this.length=1;return this}if(typeof selector==="string"){if(selector.charAt(0)==="<"&&selector.charAt(selector.length-1)===">"&&selector.length>=3){match=[null,selector,null]}else{match=rquickExpr.exec(selector)}if(match&&(match[1]||!context)){if(match[1]){context=context instanceof jQuery?context[0]:context;doc=context&&context.nodeType?context.ownerDocument||context:document;selector=jQuery.parseHTML(match[1],doc,true);if(rsingleTag.test(match[1])&&jQuery.isPlainObject(context)){this.attr.call(selector,context,true)}return jQuery.merge(this,selector)}else{elem=document.getElementById(match[2]);if(elem&&elem.parentNode){if(elem.id!==match[2]){return rootjQuery.find(selector)}this.length=1;this[0]=elem}this.context=document;this.selector=selector;return this}}else if(!context||context.jquery){return(context||rootjQuery).find(selector)}else{return this.constructor(context).find(selector)}}else if(jQuery.isFunction(selector)){return rootjQuery.ready(selector)}if(selector.selector!==undefined){this.selector=selector.selector;this.context=selector.context}return jQuery.makeArray(selector,this)},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return core_slice.call(this)},get:function(num){return num==null?this.toArray():num<0?this[this.length+num]:this[num]},pushStack:function(elems,name,selector){var ret=jQuery.merge(this.constructor(),elems);ret.prevObject=this;ret.context=this.context;if(name==="find"){ret.selector=this.selector+(this.selector?" ":"")+selector}else if(name){ret.selector=this.selector+"."+name+"("+selector+")"}return ret},each:function(callback,args){return jQuery.each(this,callback,args)},ready:function(fn){jQuery.ready.promise().done(fn);return this},eq:function(i){i=+i;return i===-1?this.slice(i):this.slice(i,i+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(core_slice.apply(this,arguments),"slice",core_slice.call(arguments).join(","))},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem)}))},end:function(){return this.prevObject||this.constructor(null)},push:core_push,sort:[].sort,splice:[].splice};jQuery.fn.init.prototype=jQuery.fn;jQuery.extend=jQuery.fn.extend=function(){var options,name,src,copy,copyIsArray,clone,target=arguments[0]||{},i=1,length=arguments.length,deep=false;if(typeof target==="boolean"){deep=target;target=arguments[1]||{};i=2}if(typeof target!=="object"&&!jQuery.isFunction(target)){target={}}if(length===i){target=this;--i}for(;i<length;i++){if((options=arguments[i])!=null){for(name in options){src=target[name];copy=options[name];if(target===copy){continue}if(deep&©&&(jQuery.isPlainObject(copy)||(copyIsArray=jQuery.isArray(copy)))){if(copyIsArray){copyIsArray=false;clone=src&&jQuery.isArray(src)?src:[]}else{clone=src&&jQuery.isPlainObject(src)?src:{}}target[name]=jQuery.extend(deep,clone,copy)}else if(copy!==undefined){target[name]=copy}}}}return target};jQuery.extend({noConflict:function(deep){if(window.$===jQuery){window.$=_$}if(deep&&window.jQuery===jQuery){window.jQuery=_jQuery}return jQuery},isReady:false,readyWait:1,holdReady:function(hold){if(hold){jQuery.readyWait++}else{jQuery.ready(true)}},ready:function(wait){if(wait===true?--jQuery.readyWait:jQuery.isReady){return}if(!document.body){return setTimeout(jQuery.ready,1)}jQuery.isReady=true;if(wait!==true&&--jQuery.readyWait>0){return}readyList.resolveWith(document,[jQuery]);if(jQuery.fn.trigger){jQuery(document).trigger("ready").off("ready")}},isFunction:function(obj){return jQuery.type(obj)==="function"},isArray:Array.isArray||function(obj){return jQuery.type(obj)==="array"},isWindow:function(obj){return obj!=null&&obj==obj.window},isNumeric:function(obj){return!isNaN(parseFloat(obj))&&isFinite(obj)},type:function(obj){return obj==null?String(obj):class2type[core_toString.call(obj)]||"object"},isPlainObject:function(obj){if(!obj||jQuery.type(obj)!=="object"||obj.nodeType||jQuery.isWindow(obj)){return false}try{if(obj.constructor&&!core_hasOwn.call(obj,"constructor")&&!core_hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){return false}}catch(e){return false}var key;for(key in obj){}return key===undefined||core_hasOwn.call(obj,key)},isEmptyObject:function(obj){var name;for(name in obj){return false}return true},error:function(msg){throw new Error(msg)},parseHTML:function(data,context,scripts){var parsed;if(!data||typeof data!=="string"){return null}if(typeof context==="boolean"){scripts=context;context=0}context=context||document;if(parsed=rsingleTag.exec(data)){return[context.createElement(parsed[1])]}parsed=jQuery.buildFragment([data],context,scripts?null:[]);return jQuery.merge([],(parsed.cacheable?jQuery.clone(parsed.fragment):parsed.fragment).childNodes)},parseJSON:function(data){if(!data||typeof data!=="string"){return null}data=jQuery.trim(data);if(window.JSON&&window.JSON.parse){return window.JSON.parse(data)}if(rvalidchars.test(data.replace(rvalidescape,"@").replace(rvalidtokens,"]").replace(rvalidbraces,""))){return new Function("return "+data)()}jQuery.error("Invalid JSON: "+data)},parseXML:function(data){var xml,tmp;if(!data||typeof data!=="string"){return null}try{if(window.DOMParser){tmp=new DOMParser;xml=tmp.parseFromString(data,"text/xml")}else{xml=new ActiveXObject("Microsoft.XMLDOM");xml.async="false";xml.loadXML(data)}}catch(e){xml=undefined}if(!xml||!xml.documentElement||xml.getElementsByTagName("parsererror").length){jQuery.error("Invalid XML: "+data)}return xml},noop:function(){},globalEval:function(data){if(data&&core_rnotwhite.test(data)){(window.execScript||function(data){window["eval"].call(window,data)})(data)}},camelCase:function(string){return string.replace(rmsPrefix,"ms-").replace(rdashAlpha,fcamelCase)},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toLowerCase()===name.toLowerCase()},each:function(obj,callback,args){var name,i=0,length=obj.length,isObj=length===undefined||jQuery.isFunction(obj);if(args){if(isObj){for(name in obj){if(callback.apply(obj[name],args)===false){break}}}else{for(;i<length;){if(callback.apply(obj[i++],args)===false){break}}}}else{if(isObj){for(name in obj){if(callback.call(obj[name],name,obj[name])===false){break}}}else{for(;i<length;){if(callback.call(obj[i],i,obj[i++])===false){break}}}}return obj},trim:core_trim&&!core_trim.call(" ")?function(text){return text==null?"":core_trim.call(text)}:function(text){return text==null?"":(text+"").replace(rtrim,"")},makeArray:function(arr,results){var type,ret=results||[];if(arr!=null){type=jQuery.type(arr);if(arr.length==null||type==="string"||type==="function"||type==="regexp"||jQuery.isWindow(arr)){core_push.call(ret,arr)}else{jQuery.merge(ret,arr)}}return ret},inArray:function(elem,arr,i){var len;if(arr){if(core_indexOf){return core_indexOf.call(arr,elem,i)}len=arr.length;i=i?i<0?Math.max(0,len+i):i:0;for(;i<len;i++){if(i in arr&&arr[i]===elem){return i}}}return-1},merge:function(first,second){var l=second.length,i=first.length,j=0;if(typeof l==="number"){for(;j<l;j++){first[i++]=second[j]}}else{while(second[j]!==undefined){first[i++]=second[j++]}}first.length=i;return first},grep:function(elems,callback,inv){var retVal,ret=[],i=0,length=elems.length;inv=!!inv;for(;i<length;i++){retVal=!!callback(elems[i],i);if(inv!==retVal){ret.push(elems[i])}}return ret},map:function(elems,callback,arg){var value,key,ret=[],i=0,length=elems.length,isArray=elems instanceof jQuery||length!==undefined&&typeof length==="number"&&(length>0&&elems[0]&&elems[length-1]||length===0||jQuery.isArray(elems));if(isArray){for(;i<length;i++){value=callback(elems[i],i,arg);if(value!=null){ret[ret.length]=value}}}else{for(key in elems){value=callback(elems[key],key,arg);if(value!=null){ret[ret.length]=value}}}return ret.concat.apply([],ret)},guid:1,proxy:function(fn,context){var tmp,args,proxy;if(typeof context==="string"){tmp=fn[context];context=fn;fn=tmp}if(!jQuery.isFunction(fn)){return undefined}args=core_slice.call(arguments,2);proxy=function(){return fn.apply(context,args.concat(core_slice.call(arguments)))};proxy.guid=fn.guid=fn.guid||jQuery.guid++;return proxy},access:function(elems,fn,key,value,chainable,emptyGet,pass){var exec,bulk=key==null,i=0,length=elems.length;if(key&&typeof key==="object"){for(i in key){jQuery.access(elems,fn,i,key[i],1,emptyGet,value)}chainable=1}else if(value!==undefined){exec=pass===undefined&&jQuery.isFunction(value);if(bulk){if(exec){exec=fn;fn=function(elem,key,value){return exec.call(jQuery(elem),value)}}else{fn.call(elems,value);fn=null}}if(fn){for(;i<length;i++){fn(elems[i],key,exec?value.call(elems[i],i,fn(elems[i],key)):value,pass)}}chainable=1}return chainable?elems:bulk?fn.call(elems):length?fn(elems[0],key):emptyGet},now:function(){return(new Date).getTime()}});jQuery.ready.promise=function(obj){if(!readyList){readyList=jQuery.Deferred();if(document.readyState==="complete"){setTimeout(jQuery.ready,1)}else if(document.addEventListener){document.addEventListener("DOMContentLoaded",DOMContentLoaded,false);window.addEventListener("load",jQuery.ready,false)}else{document.attachEvent("onreadystatechange",DOMContentLoaded);window.attachEvent("onload",jQuery.ready);var top=false;try{top=window.frameElement==null&&document.documentElement}catch(e){}if(top&&top.doScroll){(function doScrollCheck(){if(!jQuery.isReady){try{top.doScroll("left")}catch(e){return setTimeout(doScrollCheck,50)}jQuery.ready()}})()}}}return readyList.promise(obj)};jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(i,name){class2type["[object "+name+"]"]=name.toLowerCase()});rootjQuery=jQuery(document);var optionsCache={};function createOptions(options){var object=optionsCache[options]={};jQuery.each(options.split(core_rspace),function(_,flag){object[flag]=true});return object}jQuery.Callbacks=function(options){options=typeof options==="string"?optionsCache[options]||createOptions(options):jQuery.extend({},options);var memory,fired,firing,firingStart,firingLength,firingIndex,list=[],stack=!options.once&&[],fire=function(data){memory=options.memory&&data;fired=true;firingIndex=firingStart||0;firingStart=0;firingLength=list.length;firing=true;for(;list&&firingIndex<firingLength;firingIndex++){if(list[firingIndex].apply(data[0],data[1])===false&&options.stopOnFalse){memory=false;break}}firing=false;if(list){if(stack){if(stack.length){fire(stack.shift())}}else if(memory){list=[]}else{self.disable()}}},self={add:function(){if(list){var start=list.length;(function add(args){jQuery.each(args,function(_,arg){var type=jQuery.type(arg);if(type==="function"){if(!options.unique||!self.has(arg)){list.push(arg)}}else if(arg&&arg.length&&type!=="string"){add(arg)}})})(arguments);if(firing){firingLength=list.length}else if(memory){firingStart=start;fire(memory)}}return this},remove:function(){if(list){jQuery.each(arguments,function(_,arg){var index;while((index=jQuery.inArray(arg,list,index))>-1){list.splice(index,1);if(firing){if(index<=firingLength){firingLength--}if(index<=firingIndex){firingIndex--}}}})}return this},has:function(fn){return jQuery.inArray(fn,list)>-1},empty:function(){list=[];return this},disable:function(){list=stack=memory=undefined;return this},disabled:function(){return!list},lock:function(){stack=undefined;if(!memory){self.disable()}return this},locked:function(){return!stack},fireWith:function(context,args){args=args||[];args=[context,args.slice?args.slice():args];if(list&&(!fired||stack)){if(firing){stack.push(args)}else{fire(args)}}return this},fire:function(){self.fireWith(this,arguments);return this},fired:function(){return!!fired}};return self};jQuery.extend({Deferred:function(func){var tuples=[["resolve","done",jQuery.Callbacks("once memory"),"resolved"],["reject","fail",jQuery.Callbacks("once memory"),"rejected"],["notify","progress",jQuery.Callbacks("memory")]],state="pending",promise={state:function(){return state},always:function(){deferred.done(arguments).fail(arguments);return this},then:function(){var fns=arguments;return jQuery.Deferred(function(newDefer){jQuery.each(tuples,function(i,tuple){var action=tuple[0],fn=fns[i];deferred[tuple[1]](jQuery.isFunction(fn)?function(){var returned=fn.apply(this,arguments);if(returned&&jQuery.isFunction(returned.promise)){returned.promise().done(newDefer.resolve).fail(newDefer.reject).progress(newDefer.notify)}else{newDefer[action+"With"](this===deferred?newDefer:this,[returned])}}:newDefer[action])});fns=null}).promise()},promise:function(obj){return obj!=null?jQuery.extend(obj,promise):promise}},deferred={};promise.pipe=promise.then;jQuery.each(tuples,function(i,tuple){var list=tuple[2],stateString=tuple[3];promise[tuple[1]]=list.add;if(stateString){list.add(function(){state=stateString},tuples[i^1][2].disable,tuples[2][2].lock)}deferred[tuple[0]]=list.fire;deferred[tuple[0]+"With"]=list.fireWith});promise.promise(deferred);if(func){func.call(deferred,deferred)}return deferred},when:function(subordinate){var i=0,resolveValues=core_slice.call(arguments),length=resolveValues.length,remaining=length!==1||subordinate&&jQuery.isFunction(subordinate.promise)?length:0,deferred=remaining===1?subordinate:jQuery.Deferred(),updateFunc=function(i,contexts,values){return function(value){contexts[i]=this;values[i]=arguments.length>1?core_slice.call(arguments):value;if(values===progressValues){deferred.notifyWith(contexts,values)}else if(!--remaining){deferred.resolveWith(contexts,values)}}},progressValues,progressContexts,resolveContexts;if(length>1){progressValues=new Array(length);progressContexts=new Array(length);resolveContexts=new Array(length);for(;i<length;i++){if(resolveValues[i]&&jQuery.isFunction(resolveValues[i].promise)){resolveValues[i].promise().done(updateFunc(i,resolveContexts,resolveValues)).fail(deferred.reject).progress(updateFunc(i,progressContexts,progressValues))}else{--remaining}}}if(!remaining){deferred.resolveWith(resolveContexts,resolveValues)}return deferred.promise()}});jQuery.support=function(){var support,all,a,select,opt,input,fragment,eventName,i,isSupported,clickFn,div=document.createElement("div");div.setAttribute("className","t");div.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";all=div.getElementsByTagName("*");a=div.getElementsByTagName("a")[0];if(!all||!a||!all.length){return{}}select=document.createElement("select");opt=select.appendChild(document.createElement("option"));input=div.getElementsByTagName("input")[0];a.style.cssText="top:1px;float:left;opacity:.5";support={leadingWhitespace:div.firstChild.nodeType===3,tbody:!div.getElementsByTagName("tbody").length,htmlSerialize:!!div.getElementsByTagName("link").length,style:/top/.test(a.getAttribute("style")),hrefNormalized:a.getAttribute("href")==="/a",opacity:/^0.5/.test(a.style.opacity),cssFloat:!!a.style.cssFloat,checkOn:input.value==="on",optSelected:opt.selected,getSetAttribute:div.className!=="t",enctype:!!document.createElement("form").enctype,html5Clone:document.createElement("nav").cloneNode(true).outerHTML!=="<:nav></:nav>",boxModel:document.compatMode==="CSS1Compat",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true,boxSizingReliable:true,pixelPosition:false};input.checked=true;support.noCloneChecked=input.cloneNode(true).checked;select.disabled=true;support.optDisabled=!opt.disabled;try{delete div.test}catch(e){support.deleteExpando=false}if(!div.addEventListener&&div.attachEvent&&div.fireEvent){div.attachEvent("onclick",clickFn=function(){support.noCloneEvent=false});div.cloneNode(true).fireEvent("onclick");div.detachEvent("onclick",clickFn)}input=document.createElement("input");input.value="t";input.setAttribute("type","radio");support.radioValue=input.value==="t";input.setAttribute("checked","checked");input.setAttribute("name","t");div.appendChild(input);fragment=document.createDocumentFragment();fragment.appendChild(div.lastChild);support.checkClone=fragment.cloneNode(true).cloneNode(true).lastChild.checked;support.appendChecked=input.checked;fragment.removeChild(input);fragment.appendChild(div);if(div.attachEvent){for(i in{submit:true,change:true,focusin:true}){eventName="on"+i;isSupported=eventName in div;if(!isSupported){div.setAttribute(eventName,"return;");isSupported=typeof div[eventName]==="function"}support[i+"Bubbles"]=isSupported}}jQuery(function(){var container,div,tds,marginDiv,divReset="padding:0;margin:0;border:0;display:block;overflow:hidden;",body=document.getElementsByTagName("body")[0];if(!body){return}container=document.createElement("div");container.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";body.insertBefore(container,body.firstChild);div=document.createElement("div");container.appendChild(div);div.innerHTML="<table><tr><td></td><td>t</td></tr></table>";tds=div.getElementsByTagName("td");tds[0].style.cssText="padding:0;margin:0;border:0;display:none";isSupported=tds[0].offsetHeight===0;tds[0].style.display="";tds[1].style.display="none";support.reliableHiddenOffsets=isSupported&&tds[0].offsetHeight===0;div.innerHTML="";div.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";support.boxSizing=div.offsetWidth===4;support.doesNotIncludeMarginInBodyOffset=body.offsetTop!==1;if(window.getComputedStyle){support.pixelPosition=(window.getComputedStyle(div,null)||{}).top!=="1%";support.boxSizingReliable=(window.getComputedStyle(div,null)||{width:"4px"}).width==="4px";marginDiv=document.createElement("div");marginDiv.style.cssText=div.style.cssText=divReset;marginDiv.style.marginRight=marginDiv.style.width="0";div.style.width="1px";div.appendChild(marginDiv);support.reliableMarginRight=!parseFloat((window.getComputedStyle(marginDiv,null)||{}).marginRight)}if(typeof div.style.zoom!=="undefined"){div.innerHTML="";div.style.cssText=divReset+"width:1px;padding:1px;display:inline;zoom:1";support.inlineBlockNeedsLayout=div.offsetWidth===3;div.style.display="block";div.style.overflow="visible";div.innerHTML="<div></div>";div.firstChild.style.width="5px";support.shrinkWrapBlocks=div.offsetWidth!==3;container.style.zoom=1}body.removeChild(container);container=div=tds=marginDiv=null});fragment.removeChild(div);all=a=select=opt=input=fragment=div=null;return support}();var rbrace=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,rmultiDash=/([A-Z])/g;jQuery.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(jQuery.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(elem){elem=elem.nodeType?jQuery.cache[elem[jQuery.expando]]:elem[jQuery.expando];return!!elem&&!isEmptyDataObject(elem)},data:function(elem,name,data,pvt){if(!jQuery.acceptData(elem)){return}var thisCache,ret,internalKey=jQuery.expando,getByName=typeof name==="string",isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[internalKey]:elem[internalKey]&&internalKey;if((!id||!cache[id]||!pvt&&!cache[id].data)&&getByName&&data===undefined){return}if(!id){if(isNode){elem[internalKey]=id=jQuery.deletedIds.pop()||jQuery.guid++}else{id=internalKey}}if(!cache[id]){cache[id]={};if(!isNode){cache[id].toJSON=jQuery.noop}}if(typeof name==="object"||typeof name==="function"){if(pvt){cache[id]=jQuery.extend(cache[id],name)}else{cache[id].data=jQuery.extend(cache[id].data,name)}}thisCache=cache[id];if(!pvt){if(!thisCache.data){thisCache.data={}}thisCache=thisCache.data}if(data!==undefined){thisCache[jQuery.camelCase(name)]=data}if(getByName){ret=thisCache[name];if(ret==null){ret=thisCache[jQuery.camelCase(name)]}}else{ret=thisCache}return ret},removeData:function(elem,name,pvt){if(!jQuery.acceptData(elem)){return}var thisCache,i,l,isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[jQuery.expando]:jQuery.expando;if(!cache[id]){return}if(name){thisCache=pvt?cache[id]:cache[id].data;if(thisCache){if(!jQuery.isArray(name)){if(name in thisCache){name=[name]}else{name=jQuery.camelCase(name);if(name in thisCache){name=[name]}else{name=name.split(" ")}}}for(i=0,l=name.length;i<l;i++){delete thisCache[name[i]]}if(!(pvt?isEmptyDataObject:jQuery.isEmptyObject)(thisCache)){return}}}if(!pvt){delete cache[id].data;if(!isEmptyDataObject(cache[id])){return}}if(isNode){jQuery.cleanData([elem],true)}else if(jQuery.support.deleteExpando||cache!=cache.window){delete cache[id]}else{cache[id]=null}},_data:function(elem,name,data){return jQuery.data(elem,name,data,true)},acceptData:function(elem){var noData=elem.nodeName&&jQuery.noData[elem.nodeName.toLowerCase()];return!noData||noData!==true&&elem.getAttribute("classid")===noData}});jQuery.fn.extend({data:function(key,value){var parts,part,attr,name,l,elem=this[0],i=0,data=null;if(key===undefined){if(this.length){data=jQuery.data(elem);if(elem.nodeType===1&&!jQuery._data(elem,"parsedAttrs")){attr=elem.attributes;for(l=attr.length;i<l;i++){name=attr[i].name;if(!name.indexOf("data-")){name=jQuery.camelCase(name.substring(5));dataAttr(elem,name,data[name])}}jQuery._data(elem,"parsedAttrs",true)}}return data}if(typeof key==="object"){return this.each(function(){jQuery.data(this,key)})}parts=key.split(".",2);parts[1]=parts[1]?"."+parts[1]:"";part=parts[1]+"!";return jQuery.access(this,function(value){if(value===undefined){data=this.triggerHandler("getData"+part,[parts[0]]);if(data===undefined&&elem){data=jQuery.data(elem,key);data=dataAttr(elem,key,data)}return data===undefined&&parts[1]?this.data(parts[0]):data}parts[1]=value;this.each(function(){var self=jQuery(this);self.triggerHandler("setData"+part,parts);jQuery.data(this,key,value);self.triggerHandler("changeData"+part,parts)})},null,value,arguments.length>1,null,false)},removeData:function(key){return this.each(function(){jQuery.removeData(this,key)})}});function dataAttr(elem,key,data){if(data===undefined&&elem.nodeType===1){var name="data-"+key.replace(rmultiDash,"-$1").toLowerCase();data=elem.getAttribute(name);if(typeof data==="string"){try{data=data==="true"?true:data==="false"?false:data==="null"?null:+data+""===data?+data:rbrace.test(data)?jQuery.parseJSON(data):data}catch(e){}jQuery.data(elem,key,data)}else{data=undefined}}return data}function isEmptyDataObject(obj){var name;for(name in obj){if(name==="data"&&jQuery.isEmptyObject(obj[name])){continue}if(name!=="toJSON"){return false}}return true}jQuery.extend({queue:function(elem,type,data){var queue;if(elem){type=(type||"fx")+"queue";queue=jQuery._data(elem,type);if(data){if(!queue||jQuery.isArray(data)){queue=jQuery._data(elem,type,jQuery.makeArray(data))}else{queue.push(data)}}return queue||[]}},dequeue:function(elem,type){type=type||"fx";var queue=jQuery.queue(elem,type),startLength=queue.length,fn=queue.shift(),hooks=jQuery._queueHooks(elem,type),next=function(){jQuery.dequeue(elem,type)};if(fn==="inprogress"){fn=queue.shift();startLength--}if(fn){if(type==="fx"){queue.unshift("inprogress")}delete hooks.stop;fn.call(elem,next,hooks)}if(!startLength&&hooks){hooks.empty.fire()}},_queueHooks:function(elem,type){var key=type+"queueHooks";return jQuery._data(elem,key)||jQuery._data(elem,key,{empty:jQuery.Callbacks("once memory").add(function(){jQuery.removeData(elem,type+"queue",true);jQuery.removeData(elem,key,true)})})}});jQuery.fn.extend({queue:function(type,data){var setter=2;if(typeof type!=="string"){data=type;type="fx";setter--}if(arguments.length<setter){return jQuery.queue(this[0],type)}return data===undefined?this:this.each(function(){var queue=jQuery.queue(this,type,data);jQuery._queueHooks(this,type);if(type==="fx"&&queue[0]!=="inprogress"){jQuery.dequeue(this,type)}})},dequeue:function(type){return this.each(function(){jQuery.dequeue(this,type)})},delay:function(time,type){time=jQuery.fx?jQuery.fx.speeds[time]||time:time;type=type||"fx";return this.queue(type,function(next,hooks){var timeout=setTimeout(next,time);hooks.stop=function(){clearTimeout(timeout)}})},clearQueue:function(type){return this.queue(type||"fx",[])},promise:function(type,obj){var tmp,count=1,defer=jQuery.Deferred(),elements=this,i=this.length,resolve=function(){if(!--count){defer.resolveWith(elements,[elements])}};if(typeof type!=="string"){obj=type;type=undefined}type=type||"fx";while(i--){tmp=jQuery._data(elements[i],type+"queueHooks");if(tmp&&tmp.empty){count++;tmp.empty.add(resolve)}}resolve();return defer.promise(obj)}});var nodeHook,boolHook,fixSpecified,rclass=/[\t\r\n]/g,rreturn=/\r/g,rtype=/^(?:button|input)$/i,rfocusable=/^(?:button|input|object|select|textarea)$/i,rclickable=/^a(?:rea|)$/i,rboolean=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,getSetAttribute=jQuery.support.getSetAttribute;jQuery.fn.extend({attr:function(name,value){return jQuery.access(this,jQuery.attr,name,value,arguments.length>1)},removeAttr:function(name){return this.each(function(){jQuery.removeAttr(this,name)})},prop:function(name,value){return jQuery.access(this,jQuery.prop,name,value,arguments.length>1)},removeProp:function(name){name=jQuery.propFix[name]||name;return this.each(function(){try{this[name]=undefined;delete this[name]}catch(e){}})},addClass:function(value){var classNames,i,l,elem,setClass,c,cl;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).addClass(value.call(this,j,this.className))})}if(value&&typeof value==="string"){classNames=value.split(core_rspace);for(i=0,l=this.length;i<l;i++){elem=this[i];if(elem.nodeType===1){if(!elem.className&&classNames.length===1){elem.className=value}else{setClass=" "+elem.className+" ";for(c=0,cl=classNames.length;c<cl;c++){if(setClass.indexOf(" "+classNames[c]+" ")<0){setClass+=classNames[c]+" "}}elem.className=jQuery.trim(setClass)}}}}return this},removeClass:function(value){var removes,className,elem,c,cl,i,l;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).removeClass(value.call(this,j,this.className))})}if(value&&typeof value==="string"||value===undefined){removes=(value||"").split(core_rspace);for(i=0,l=this.length;i<l;i++){elem=this[i];if(elem.nodeType===1&&elem.className){className=(" "+elem.className+" ").replace(rclass," ");for(c=0,cl=removes.length;c<cl;c++){while(className.indexOf(" "+removes[c]+" ")>=0){className=className.replace(" "+removes[c]+" "," ")}}elem.className=value?jQuery.trim(className):""}}}return this},toggleClass:function(value,stateVal){var type=typeof value,isBool=typeof stateVal==="boolean";if(jQuery.isFunction(value)){return this.each(function(i){jQuery(this).toggleClass(value.call(this,i,this.className,stateVal),stateVal)})}return this.each(function(){if(type==="string"){var className,i=0,self=jQuery(this),state=stateVal,classNames=value.split(core_rspace);while(className=classNames[i++]){state=isBool?state:!self.hasClass(className);self[state?"addClass":"removeClass"](className)}}else if(type==="undefined"||type==="boolean"){if(this.className){jQuery._data(this,"__className__",this.className)}this.className=this.className||value===false?"":jQuery._data(this,"__className__")||""}})},hasClass:function(selector){var className=" "+selector+" ",i=0,l=this.length;for(;i<l;i++){if(this[i].nodeType===1&&(" "+this[i].className+" ").replace(rclass," ").indexOf(className)>=0){return true}}return false},val:function(value){var hooks,ret,isFunction,elem=this[0];if(!arguments.length){if(elem){hooks=jQuery.valHooks[elem.type]||jQuery.valHooks[elem.nodeName.toLowerCase()];if(hooks&&"get"in hooks&&(ret=hooks.get(elem,"value"))!==undefined){return ret}ret=elem.value;return typeof ret==="string"?ret.replace(rreturn,""):ret==null?"":ret}return}isFunction=jQuery.isFunction(value);return this.each(function(i){var val,self=jQuery(this);if(this.nodeType!==1){return}if(isFunction){val=value.call(this,i,self.val())}else{val=value}if(val==null){val=""}else if(typeof val==="number"){val+=""}else if(jQuery.isArray(val)){val=jQuery.map(val,function(value){return value==null?"":value+""})}hooks=jQuery.valHooks[this.type]||jQuery.valHooks[this.nodeName.toLowerCase()];if(!hooks||!("set"in hooks)||hooks.set(this,val,"value")===undefined){this.value=val}})}});jQuery.extend({valHooks:{option:{get:function(elem){var val=elem.attributes.value;return!val||val.specified?elem.value:elem.text}},select:{get:function(elem){var value,option,options=elem.options,index=elem.selectedIndex,one=elem.type==="select-one"||index<0,values=one?null:[],max=one?index+1:options.length,i=index<0?max:one?index:0;for(;i<max;i++){option=options[i];if((option.selected||i===index)&&(jQuery.support.optDisabled?!option.disabled:option.getAttribute("disabled")===null)&&(!option.parentNode.disabled||!jQuery.nodeName(option.parentNode,"optgroup"))){value=jQuery(option).val();if(one){return value}values.push(value)}}return values},set:function(elem,value){var values=jQuery.makeArray(value);jQuery(elem).find("option").each(function(){this.selected=jQuery.inArray(jQuery(this).val(),values)>=0});if(!values.length){elem.selectedIndex=-1}return values}}},attrFn:{},attr:function(elem,name,value,pass){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return}if(pass&&jQuery.isFunction(jQuery.fn[name])){return jQuery(elem)[name](value)}if(typeof elem.getAttribute==="undefined"){return jQuery.prop(elem,name,value)}notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=name.toLowerCase();hooks=jQuery.attrHooks[name]||(rboolean.test(name)?boolHook:nodeHook)}if(value!==undefined){if(value===null){jQuery.removeAttr(elem,name);return}else if(hooks&&"set"in hooks&¬xml&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{elem.setAttribute(name,value+"");return value}}else if(hooks&&"get"in hooks&¬xml&&(ret=hooks.get(elem,name))!==null){return ret}else{ret=elem.getAttribute(name);return ret===null?undefined:ret}},removeAttr:function(elem,value){var propName,attrNames,name,isBool,i=0;if(value&&elem.nodeType===1){attrNames=value.split(core_rspace);for(;i<attrNames.length;i++){name=attrNames[i];if(name){propName=jQuery.propFix[name]||name;isBool=rboolean.test(name);if(!isBool){jQuery.attr(elem,name,"")}elem.removeAttribute(getSetAttribute?name:propName);if(isBool&&propName in elem){elem[propName]=false}}}}},attrHooks:{type:{set:function(elem,value){if(rtype.test(elem.nodeName)&&elem.parentNode){jQuery.error("type property can't be changed") +}else if(!jQuery.support.radioValue&&value==="radio"&&jQuery.nodeName(elem,"input")){var val=elem.value;elem.setAttribute("type",value);if(val){elem.value=val}return value}}},value:{get:function(elem,name){if(nodeHook&&jQuery.nodeName(elem,"button")){return nodeHook.get(elem,name)}return name in elem?elem.value:null},set:function(elem,value,name){if(nodeHook&&jQuery.nodeName(elem,"button")){return nodeHook.set(elem,value,name)}elem.value=value}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(elem,name,value){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return}notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=jQuery.propFix[name]||name;hooks=jQuery.propHooks[name]}if(value!==undefined){if(hooks&&"set"in hooks&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{return elem[name]=value}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,name))!==null){return ret}else{return elem[name]}}},propHooks:{tabIndex:{get:function(elem){var attributeNode=elem.getAttributeNode("tabindex");return attributeNode&&attributeNode.specified?parseInt(attributeNode.value,10):rfocusable.test(elem.nodeName)||rclickable.test(elem.nodeName)&&elem.href?0:undefined}}}});boolHook={get:function(elem,name){var attrNode,property=jQuery.prop(elem,name);return property===true||typeof property!=="boolean"&&(attrNode=elem.getAttributeNode(name))&&attrNode.nodeValue!==false?name.toLowerCase():undefined},set:function(elem,value,name){var propName;if(value===false){jQuery.removeAttr(elem,name)}else{propName=jQuery.propFix[name]||name;if(propName in elem){elem[propName]=true}elem.setAttribute(name,name.toLowerCase())}return name}};if(!getSetAttribute){fixSpecified={name:true,id:true,coords:true};nodeHook=jQuery.valHooks.button={get:function(elem,name){var ret;ret=elem.getAttributeNode(name);return ret&&(fixSpecified[name]?ret.value!=="":ret.specified)?ret.value:undefined},set:function(elem,value,name){var ret=elem.getAttributeNode(name);if(!ret){ret=document.createAttribute(name);elem.setAttributeNode(ret)}return ret.value=value+""}};jQuery.each(["width","height"],function(i,name){jQuery.attrHooks[name]=jQuery.extend(jQuery.attrHooks[name],{set:function(elem,value){if(value===""){elem.setAttribute(name,"auto");return value}}})});jQuery.attrHooks.contenteditable={get:nodeHook.get,set:function(elem,value,name){if(value===""){value="false"}nodeHook.set(elem,value,name)}}}if(!jQuery.support.hrefNormalized){jQuery.each(["href","src","width","height"],function(i,name){jQuery.attrHooks[name]=jQuery.extend(jQuery.attrHooks[name],{get:function(elem){var ret=elem.getAttribute(name,2);return ret===null?undefined:ret}})})}if(!jQuery.support.style){jQuery.attrHooks.style={get:function(elem){return elem.style.cssText.toLowerCase()||undefined},set:function(elem,value){return elem.style.cssText=value+""}}}if(!jQuery.support.optSelected){jQuery.propHooks.selected=jQuery.extend(jQuery.propHooks.selected,{get:function(elem){var parent=elem.parentNode;if(parent){parent.selectedIndex;if(parent.parentNode){parent.parentNode.selectedIndex}}return null}})}if(!jQuery.support.enctype){jQuery.propFix.enctype="encoding"}if(!jQuery.support.checkOn){jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]={get:function(elem){return elem.getAttribute("value")===null?"on":elem.value}}})}jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]=jQuery.extend(jQuery.valHooks[this],{set:function(elem,value){if(jQuery.isArray(value)){return elem.checked=jQuery.inArray(jQuery(elem).val(),value)>=0}}})});var rformElems=/^(?:textarea|input|select)$/i,rtypenamespace=/^([^\.]*|)(?:\.(.+)|)$/,rhoverHack=/(?:^|\s)hover(\.\S+|)\b/,rkeyEvent=/^key/,rmouseEvent=/^(?:mouse|contextmenu)|click/,rfocusMorph=/^(?:focusinfocus|focusoutblur)$/,hoverHack=function(events){return jQuery.event.special.hover?events:events.replace(rhoverHack,"mouseenter$1 mouseleave$1")};jQuery.event={add:function(elem,types,handler,data,selector){var elemData,eventHandle,events,t,tns,type,namespaces,handleObj,handleObjIn,handlers,special;if(elem.nodeType===3||elem.nodeType===8||!types||!handler||!(elemData=jQuery._data(elem))){return}if(handler.handler){handleObjIn=handler;handler=handleObjIn.handler;selector=handleObjIn.selector}if(!handler.guid){handler.guid=jQuery.guid++}events=elemData.events;if(!events){elemData.events=events={}}eventHandle=elemData.handle;if(!eventHandle){elemData.handle=eventHandle=function(e){return typeof jQuery!=="undefined"&&(!e||jQuery.event.triggered!==e.type)?jQuery.event.dispatch.apply(eventHandle.elem,arguments):undefined};eventHandle.elem=elem}types=jQuery.trim(hoverHack(types)).split(" ");for(t=0;t<types.length;t++){tns=rtypenamespace.exec(types[t])||[];type=tns[1];namespaces=(tns[2]||"").split(".").sort();special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;special=jQuery.event.special[type]||{};handleObj=jQuery.extend({type:type,origType:tns[1],data:data,handler:handler,guid:handler.guid,selector:selector,needsContext:selector&&jQuery.expr.match.needsContext.test(selector),namespace:namespaces.join(".")},handleObjIn);handlers=events[type];if(!handlers){handlers=events[type]=[];handlers.delegateCount=0;if(!special.setup||special.setup.call(elem,data,namespaces,eventHandle)===false){if(elem.addEventListener){elem.addEventListener(type,eventHandle,false)}else if(elem.attachEvent){elem.attachEvent("on"+type,eventHandle)}}}if(special.add){special.add.call(elem,handleObj);if(!handleObj.handler.guid){handleObj.handler.guid=handler.guid}}if(selector){handlers.splice(handlers.delegateCount++,0,handleObj)}else{handlers.push(handleObj)}jQuery.event.global[type]=true}elem=null},global:{},remove:function(elem,types,handler,selector,mappedTypes){var t,tns,type,origType,namespaces,origCount,j,events,special,eventType,handleObj,elemData=jQuery.hasData(elem)&&jQuery._data(elem);if(!elemData||!(events=elemData.events)){return}types=jQuery.trim(hoverHack(types||"")).split(" ");for(t=0;t<types.length;t++){tns=rtypenamespace.exec(types[t])||[];type=origType=tns[1];namespaces=tns[2];if(!type){for(type in events){jQuery.event.remove(elem,type+types[t],handler,selector,true)}continue}special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;eventType=events[type]||[];origCount=eventType.length;namespaces=namespaces?new RegExp("(^|\\.)"+namespaces.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(j=0;j<eventType.length;j++){handleObj=eventType[j];if((mappedTypes||origType===handleObj.origType)&&(!handler||handler.guid===handleObj.guid)&&(!namespaces||namespaces.test(handleObj.namespace))&&(!selector||selector===handleObj.selector||selector==="**"&&handleObj.selector)){eventType.splice(j--,1);if(handleObj.selector){eventType.delegateCount--}if(special.remove){special.remove.call(elem,handleObj)}}}if(eventType.length===0&&origCount!==eventType.length){if(!special.teardown||special.teardown.call(elem,namespaces,elemData.handle)===false){jQuery.removeEvent(elem,type,elemData.handle)}delete events[type]}}if(jQuery.isEmptyObject(events)){delete elemData.handle;jQuery.removeData(elem,"events",true)}},customEvent:{getData:true,setData:true,changeData:true},trigger:function(event,data,elem,onlyHandlers){if(elem&&(elem.nodeType===3||elem.nodeType===8)){return}var cache,exclusive,i,cur,old,ontype,special,handle,eventPath,bubbleType,type=event.type||event,namespaces=[];if(rfocusMorph.test(type+jQuery.event.triggered)){return}if(type.indexOf("!")>=0){type=type.slice(0,-1);exclusive=true}if(type.indexOf(".")>=0){namespaces=type.split(".");type=namespaces.shift();namespaces.sort()}if((!elem||jQuery.event.customEvent[type])&&!jQuery.event.global[type]){return}event=typeof event==="object"?event[jQuery.expando]?event:new jQuery.Event(type,event):new jQuery.Event(type);event.type=type;event.isTrigger=true;event.exclusive=exclusive;event.namespace=namespaces.join(".");event.namespace_re=event.namespace?new RegExp("(^|\\.)"+namespaces.join("\\.(?:.*\\.|)")+"(\\.|$)"):null;ontype=type.indexOf(":")<0?"on"+type:"";if(!elem){cache=jQuery.cache;for(i in cache){if(cache[i].events&&cache[i].events[type]){jQuery.event.trigger(event,data,cache[i].handle.elem,true)}}return}event.result=undefined;if(!event.target){event.target=elem}data=data!=null?jQuery.makeArray(data):[];data.unshift(event);special=jQuery.event.special[type]||{};if(special.trigger&&special.trigger.apply(elem,data)===false){return}eventPath=[[elem,special.bindType||type]];if(!onlyHandlers&&!special.noBubble&&!jQuery.isWindow(elem)){bubbleType=special.delegateType||type;cur=rfocusMorph.test(bubbleType+type)?elem:elem.parentNode;for(old=elem;cur;cur=cur.parentNode){eventPath.push([cur,bubbleType]);old=cur}if(old===(elem.ownerDocument||document)){eventPath.push([old.defaultView||old.parentWindow||window,bubbleType])}}for(i=0;i<eventPath.length&&!event.isPropagationStopped();i++){cur=eventPath[i][0];event.type=eventPath[i][1];handle=(jQuery._data(cur,"events")||{})[event.type]&&jQuery._data(cur,"handle");if(handle){handle.apply(cur,data)}handle=ontype&&cur[ontype];if(handle&&jQuery.acceptData(cur)&&handle.apply&&handle.apply(cur,data)===false){event.preventDefault()}}event.type=type;if(!onlyHandlers&&!event.isDefaultPrevented()){if((!special._default||special._default.apply(elem.ownerDocument,data)===false)&&!(type==="click"&&jQuery.nodeName(elem,"a"))&&jQuery.acceptData(elem)){if(ontype&&elem[type]&&(type!=="focus"&&type!=="blur"||event.target.offsetWidth!==0)&&!jQuery.isWindow(elem)){old=elem[ontype];if(old){elem[ontype]=null}jQuery.event.triggered=type;elem[type]();jQuery.event.triggered=undefined;if(old){elem[ontype]=old}}}}return event.result},dispatch:function(event){event=jQuery.event.fix(event||window.event);var i,j,cur,ret,selMatch,matched,matches,handleObj,sel,related,handlers=(jQuery._data(this,"events")||{})[event.type]||[],delegateCount=handlers.delegateCount,args=core_slice.call(arguments),run_all=!event.exclusive&&!event.namespace,special=jQuery.event.special[event.type]||{},handlerQueue=[];args[0]=event;event.delegateTarget=this;if(special.preDispatch&&special.preDispatch.call(this,event)===false){return}if(delegateCount&&!(event.button&&event.type==="click")){for(cur=event.target;cur!=this;cur=cur.parentNode||this){if(cur.disabled!==true||event.type!=="click"){selMatch={};matches=[];for(i=0;i<delegateCount;i++){handleObj=handlers[i];sel=handleObj.selector;if(selMatch[sel]===undefined){selMatch[sel]=handleObj.needsContext?jQuery(sel,this).index(cur)>=0:jQuery.find(sel,this,null,[cur]).length}if(selMatch[sel]){matches.push(handleObj)}}if(matches.length){handlerQueue.push({elem:cur,matches:matches})}}}}if(handlers.length>delegateCount){handlerQueue.push({elem:this,matches:handlers.slice(delegateCount)})}for(i=0;i<handlerQueue.length&&!event.isPropagationStopped();i++){matched=handlerQueue[i];event.currentTarget=matched.elem;for(j=0;j<matched.matches.length&&!event.isImmediatePropagationStopped();j++){handleObj=matched.matches[j];if(run_all||!event.namespace&&!handleObj.namespace||event.namespace_re&&event.namespace_re.test(handleObj.namespace)){event.data=handleObj.data;event.handleObj=handleObj;ret=((jQuery.event.special[handleObj.origType]||{}).handle||handleObj.handler).apply(matched.elem,args);if(ret!==undefined){event.result=ret;if(ret===false){event.preventDefault();event.stopPropagation()}}}}}if(special.postDispatch){special.postDispatch.call(this,event)}return event.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(event,original){if(event.which==null){event.which=original.charCode!=null?original.charCode:original.keyCode}return event}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(event,original){var eventDoc,doc,body,button=original.button,fromElement=original.fromElement;if(event.pageX==null&&original.clientX!=null){eventDoc=event.target.ownerDocument||document;doc=eventDoc.documentElement;body=eventDoc.body;event.pageX=original.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc&&doc.clientLeft||body&&body.clientLeft||0);event.pageY=original.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc&&doc.clientTop||body&&body.clientTop||0)}if(!event.relatedTarget&&fromElement){event.relatedTarget=fromElement===event.target?original.toElement:fromElement}if(!event.which&&button!==undefined){event.which=button&1?1:button&2?3:button&4?2:0}return event}},fix:function(event){if(event[jQuery.expando]){return event}var i,prop,originalEvent=event,fixHook=jQuery.event.fixHooks[event.type]||{},copy=fixHook.props?this.props.concat(fixHook.props):this.props;event=jQuery.Event(originalEvent);for(i=copy.length;i;){prop=copy[--i];event[prop]=originalEvent[prop]}if(!event.target){event.target=originalEvent.srcElement||document}if(event.target.nodeType===3){event.target=event.target.parentNode}event.metaKey=!!event.metaKey;return fixHook.filter?fixHook.filter(event,originalEvent):event},special:{load:{noBubble:true},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(data,namespaces,eventHandle){if(jQuery.isWindow(this)){this.onbeforeunload=eventHandle}},teardown:function(namespaces,eventHandle){if(this.onbeforeunload===eventHandle){this.onbeforeunload=null}}}},simulate:function(type,elem,event,bubble){var e=jQuery.extend(new jQuery.Event,event,{type:type,isSimulated:true,originalEvent:{}});if(bubble){jQuery.event.trigger(e,null,elem)}else{jQuery.event.dispatch.call(elem,e)}if(e.isDefaultPrevented()){event.preventDefault()}}};jQuery.event.handle=jQuery.event.dispatch;jQuery.removeEvent=document.removeEventListener?function(elem,type,handle){if(elem.removeEventListener){elem.removeEventListener(type,handle,false)}}:function(elem,type,handle){var name="on"+type;if(elem.detachEvent){if(typeof elem[name]==="undefined"){elem[name]=null}elem.detachEvent(name,handle)}};jQuery.Event=function(src,props){if(!(this instanceof jQuery.Event)){return new jQuery.Event(src,props)}if(src&&src.type){this.originalEvent=src;this.type=src.type;this.isDefaultPrevented=src.defaultPrevented||src.returnValue===false||src.getPreventDefault&&src.getPreventDefault()?returnTrue:returnFalse}else{this.type=src}if(props){jQuery.extend(this,props)}this.timeStamp=src&&src.timeStamp||jQuery.now();this[jQuery.expando]=true};function returnFalse(){return false}function returnTrue(){return true}jQuery.Event.prototype={preventDefault:function(){this.isDefaultPrevented=returnTrue;var e=this.originalEvent;if(!e){return}if(e.preventDefault){e.preventDefault()}else{e.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=returnTrue;var e=this.originalEvent;if(!e){return}if(e.stopPropagation){e.stopPropagation()}e.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=returnTrue;this.stopPropagation()},isDefaultPrevented:returnFalse,isPropagationStopped:returnFalse,isImmediatePropagationStopped:returnFalse};jQuery.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(orig,fix){jQuery.event.special[orig]={delegateType:fix,bindType:fix,handle:function(event){var ret,target=this,related=event.relatedTarget,handleObj=event.handleObj,selector=handleObj.selector;if(!related||related!==target&&!jQuery.contains(target,related)){event.type=handleObj.origType;ret=handleObj.handler.apply(this,arguments);event.type=fix}return ret}}});if(!jQuery.support.submitBubbles){jQuery.event.special.submit={setup:function(){if(jQuery.nodeName(this,"form")){return false}jQuery.event.add(this,"click._submit keypress._submit",function(e){var elem=e.target,form=jQuery.nodeName(elem,"input")||jQuery.nodeName(elem,"button")?elem.form:undefined;if(form&&!jQuery._data(form,"_submit_attached")){jQuery.event.add(form,"submit._submit",function(event){event._submit_bubble=true});jQuery._data(form,"_submit_attached",true)}})},postDispatch:function(event){if(event._submit_bubble){delete event._submit_bubble;if(this.parentNode&&!event.isTrigger){jQuery.event.simulate("submit",this.parentNode,event,true)}}},teardown:function(){if(jQuery.nodeName(this,"form")){return false}jQuery.event.remove(this,"._submit")}}}if(!jQuery.support.changeBubbles){jQuery.event.special.change={setup:function(){if(rformElems.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio"){jQuery.event.add(this,"propertychange._change",function(event){if(event.originalEvent.propertyName==="checked"){this._just_changed=true}});jQuery.event.add(this,"click._change",function(event){if(this._just_changed&&!event.isTrigger){this._just_changed=false}jQuery.event.simulate("change",this,event,true)})}return false}jQuery.event.add(this,"beforeactivate._change",function(e){var elem=e.target;if(rformElems.test(elem.nodeName)&&!jQuery._data(elem,"_change_attached")){jQuery.event.add(elem,"change._change",function(event){if(this.parentNode&&!event.isSimulated&&!event.isTrigger){jQuery.event.simulate("change",this.parentNode,event,true)}});jQuery._data(elem,"_change_attached",true)}})},handle:function(event){var elem=event.target;if(this!==elem||event.isSimulated||event.isTrigger||elem.type!=="radio"&&elem.type!=="checkbox"){return event.handleObj.handler.apply(this,arguments)}},teardown:function(){jQuery.event.remove(this,"._change");return!rformElems.test(this.nodeName)}}}if(!jQuery.support.focusinBubbles){jQuery.each({focus:"focusin",blur:"focusout"},function(orig,fix){var attaches=0,handler=function(event){jQuery.event.simulate(fix,event.target,jQuery.event.fix(event),true)};jQuery.event.special[fix]={setup:function(){if(attaches++===0){document.addEventListener(orig,handler,true)}},teardown:function(){if(--attaches===0){document.removeEventListener(orig,handler,true)}}}})}jQuery.fn.extend({on:function(types,selector,data,fn,one){var origFn,type;if(typeof types==="object"){if(typeof selector!=="string"){data=data||selector;selector=undefined}for(type in types){this.on(type,selector,data,types[type],one)}return this}if(data==null&&fn==null){fn=selector;data=selector=undefined}else if(fn==null){if(typeof selector==="string"){fn=data;data=undefined}else{fn=data;data=selector;selector=undefined}}if(fn===false){fn=returnFalse}else if(!fn){return this}if(one===1){origFn=fn;fn=function(event){jQuery().off(event);return origFn.apply(this,arguments)};fn.guid=origFn.guid||(origFn.guid=jQuery.guid++)}return this.each(function(){jQuery.event.add(this,types,fn,data,selector)})},one:function(types,selector,data,fn){return this.on(types,selector,data,fn,1)},off:function(types,selector,fn){var handleObj,type;if(types&&types.preventDefault&&types.handleObj){handleObj=types.handleObj;jQuery(types.delegateTarget).off(handleObj.namespace?handleObj.origType+"."+handleObj.namespace:handleObj.origType,handleObj.selector,handleObj.handler);return this}if(typeof types==="object"){for(type in types){this.off(type,selector,types[type])}return this}if(selector===false||typeof selector==="function"){fn=selector;selector=undefined}if(fn===false){fn=returnFalse}return this.each(function(){jQuery.event.remove(this,types,fn,selector)})},bind:function(types,data,fn){return this.on(types,null,data,fn)},unbind:function(types,fn){return this.off(types,null,fn)},live:function(types,data,fn){jQuery(this.context).on(types,this.selector,data,fn);return this},die:function(types,fn){jQuery(this.context).off(types,this.selector||"**",fn);return this},delegate:function(selector,types,data,fn){return this.on(types,selector,data,fn)},undelegate:function(selector,types,fn){return arguments.length===1?this.off(selector,"**"):this.off(types,selector||"**",fn)},trigger:function(type,data){return this.each(function(){jQuery.event.trigger(type,data,this)})},triggerHandler:function(type,data){if(this[0]){return jQuery.event.trigger(type,data,this[0],true)}},toggle:function(fn){var args=arguments,guid=fn.guid||jQuery.guid++,i=0,toggler=function(event){var lastToggle=(jQuery._data(this,"lastToggle"+fn.guid)||0)%i;jQuery._data(this,"lastToggle"+fn.guid,lastToggle+1);event.preventDefault();return args[lastToggle].apply(this,arguments)||false};toggler.guid=guid;while(i<args.length){args[i++].guid=guid}return this.click(toggler)},hover:function(fnOver,fnOut){return this.mouseenter(fnOver).mouseleave(fnOut||fnOver)}});jQuery.each(("blur focus focusin focusout load resize scroll unload click dblclick "+"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave "+"change select submit keydown keypress keyup error contextmenu").split(" "),function(i,name){jQuery.fn[name]=function(data,fn){if(fn==null){fn=data;data=null}return arguments.length>0?this.on(name,null,data,fn):this.trigger(name)};if(rkeyEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.keyHooks}if(rmouseEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.mouseHooks}});(function(window,undefined){var cachedruns,assertGetIdNotName,Expr,getText,isXML,contains,compile,sortOrder,hasDuplicate,outermostContext,baseHasDuplicate=true,strundefined="undefined",expando=("sizcache"+Math.random()).replace(".",""),Token=String,document=window.document,docElem=document.documentElement,dirruns=0,done=0,pop=[].pop,push=[].push,slice=[].slice,indexOf=[].indexOf||function(elem){var i=0,len=this.length;for(;i<len;i++){if(this[i]===elem){return i}}return-1},markFunction=function(fn,value){fn[expando]=value==null||value;return fn},createCache=function(){var cache={},keys=[];return markFunction(function(key,value){if(keys.push(key)>Expr.cacheLength){delete cache[keys.shift()]}return cache[key+" "]=value},cache)},classCache=createCache(),tokenCache=createCache(),compilerCache=createCache(),whitespace="[\\x20\\t\\r\\n\\f]",characterEncoding="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",identifier=characterEncoding.replace("w","w#"),operators="([*^$|!~]?=)",attributes="\\["+whitespace+"*("+characterEncoding+")"+whitespace+"*(?:"+operators+whitespace+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+identifier+")|)|)"+whitespace+"*\\]",pseudos=":("+characterEncoding+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+attributes+")|[^:]|\\\\.)*|.*))\\)|)",pos=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+whitespace+"*((?:-\\d)?\\d*)"+whitespace+"*\\)|)(?=[^-]|$)",rtrim=new RegExp("^"+whitespace+"+|((?:^|[^\\\\])(?:\\\\.)*)"+whitespace+"+$","g"),rcomma=new RegExp("^"+whitespace+"*,"+whitespace+"*"),rcombinators=new RegExp("^"+whitespace+"*([\\x20\\t\\r\\n\\f>+~])"+whitespace+"*"),rpseudo=new RegExp(pseudos),rquickExpr=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,rnot=/^:not/,rsibling=/[\x20\t\r\n\f]*[+~]/,rendsWithNot=/:not\($/,rheader=/h\d/i,rinputs=/input|select|textarea|button/i,rbackslash=/\\(?!\\)/g,matchExpr={ID:new RegExp("^#("+characterEncoding+")"),CLASS:new RegExp("^\\.("+characterEncoding+")"),NAME:new RegExp("^\\[name=['\"]?("+characterEncoding+")['\"]?\\]"),TAG:new RegExp("^("+characterEncoding.replace("w","w*")+")"),ATTR:new RegExp("^"+attributes),PSEUDO:new RegExp("^"+pseudos),POS:new RegExp(pos,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+whitespace+"*(even|odd|(([+-]|)(\\d*)n|)"+whitespace+"*(?:([+-]|)"+whitespace+"*(\\d+)|))"+whitespace+"*\\)|)","i"),needsContext:new RegExp("^"+whitespace+"*[>+~]|"+pos,"i")},assert=function(fn){var div=document.createElement("div");try{return fn(div)}catch(e){return false}finally{div=null}},assertTagNameNoComments=assert(function(div){div.appendChild(document.createComment(""));return!div.getElementsByTagName("*").length}),assertHrefNotNormalized=assert(function(div){div.innerHTML="<a href='#'></a>";return div.firstChild&&typeof div.firstChild.getAttribute!==strundefined&&div.firstChild.getAttribute("href")==="#"}),assertAttributes=assert(function(div){div.innerHTML="<select></select>";var type=typeof div.lastChild.getAttribute("multiple");return type!=="boolean"&&type!=="string"}),assertUsableClassName=assert(function(div){div.innerHTML="<div class='hidden e'></div><div class='hidden'></div>";if(!div.getElementsByClassName||!div.getElementsByClassName("e").length){return false}div.lastChild.className="e";return div.getElementsByClassName("e").length===2}),assertUsableName=assert(function(div){div.id=expando+0;div.innerHTML="<a name='"+expando+"'></a><div name='"+expando+"'></div>";docElem.insertBefore(div,docElem.firstChild);var pass=document.getElementsByName&&document.getElementsByName(expando).length===2+document.getElementsByName(expando+0).length;assertGetIdNotName=!document.getElementById(expando);docElem.removeChild(div);return pass});try{slice.call(docElem.childNodes,0)[0].nodeType}catch(e){slice=function(i){var elem,results=[];for(;elem=this[i];i++){results.push(elem)}return results}}function Sizzle(selector,context,results,seed){results=results||[];context=context||document;var match,elem,xml,m,nodeType=context.nodeType;if(!selector||typeof selector!=="string"){return results}if(nodeType!==1&&nodeType!==9){return[]}xml=isXML(context);if(!xml&&!seed){if(match=rquickExpr.exec(selector)){if(m=match[1]){if(nodeType===9){elem=context.getElementById(m);if(elem&&elem.parentNode){if(elem.id===m){results.push(elem);return results}}else{return results}}else{if(context.ownerDocument&&(elem=context.ownerDocument.getElementById(m))&&contains(context,elem)&&elem.id===m){results.push(elem);return results}}}else if(match[2]){push.apply(results,slice.call(context.getElementsByTagName(selector),0));return results}else if((m=match[3])&&assertUsableClassName&&context.getElementsByClassName){push.apply(results,slice.call(context.getElementsByClassName(m),0));return results}}}return select(selector.replace(rtrim,"$1"),context,results,seed,xml)}Sizzle.matches=function(expr,elements){return Sizzle(expr,null,null,elements)};Sizzle.matchesSelector=function(elem,expr){return Sizzle(expr,null,null,[elem]).length>0};function createInputPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type===type}}function createButtonPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return(name==="input"||name==="button")&&elem.type===type}}function createPositionalPseudo(fn){return markFunction(function(argument){argument=+argument;return markFunction(function(seed,matches){var j,matchIndexes=fn([],seed.length,argument),i=matchIndexes.length;while(i--){if(seed[j=matchIndexes[i]]){seed[j]=!(matches[j]=seed[j])}}})})}getText=Sizzle.getText=function(elem){var node,ret="",i=0,nodeType=elem.nodeType;if(nodeType){if(nodeType===1||nodeType===9||nodeType===11){if(typeof elem.textContent==="string"){return elem.textContent}else{for(elem=elem.firstChild;elem;elem=elem.nextSibling){ret+=getText(elem)}}}else if(nodeType===3||nodeType===4){return elem.nodeValue}}else{for(;node=elem[i];i++){ret+=getText(node)}}return ret};isXML=Sizzle.isXML=function(elem){var documentElement=elem&&(elem.ownerDocument||elem).documentElement;return documentElement?documentElement.nodeName!=="HTML":false};contains=Sizzle.contains=docElem.contains?function(a,b){var adown=a.nodeType===9?a.documentElement:a,bup=b&&b.parentNode;return a===bup||!!(bup&&bup.nodeType===1&&adown.contains&&adown.contains(bup))}:docElem.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode){if(b===a){return true}}return false};Sizzle.attr=function(elem,name){var val,xml=isXML(elem);if(!xml){name=name.toLowerCase()}if(val=Expr.attrHandle[name]){return val(elem)}if(xml||assertAttributes){return elem.getAttribute(name)}val=elem.getAttributeNode(name);return val?typeof elem[name]==="boolean"?elem[name]?name:null:val.specified?val.value:null:null};Expr=Sizzle.selectors={cacheLength:50,createPseudo:markFunction,match:matchExpr,attrHandle:assertHrefNotNormalized?{}:{href:function(elem){return elem.getAttribute("href",2)},type:function(elem){return elem.getAttribute("type")}},find:{ID:assertGetIdNotName?function(id,context,xml){if(typeof context.getElementById!==strundefined&&!xml){var m=context.getElementById(id);return m&&m.parentNode?[m]:[]}}:function(id,context,xml){if(typeof context.getElementById!==strundefined&&!xml){var m=context.getElementById(id);return m?m.id===id||typeof m.getAttributeNode!==strundefined&&m.getAttributeNode("id").value===id?[m]:undefined:[]}},TAG:assertTagNameNoComments?function(tag,context){if(typeof context.getElementsByTagName!==strundefined){return context.getElementsByTagName(tag)}}:function(tag,context){var results=context.getElementsByTagName(tag);if(tag==="*"){var elem,tmp=[],i=0;for(;elem=results[i];i++){if(elem.nodeType===1){tmp.push(elem)}}return tmp}return results},NAME:assertUsableName&&function(tag,context){if(typeof context.getElementsByName!==strundefined){return context.getElementsByName(name)}},CLASS:assertUsableClassName&&function(className,context,xml){if(typeof context.getElementsByClassName!==strundefined&&!xml){return context.getElementsByClassName(className)}}},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(match){match[1]=match[1].replace(rbackslash,"");match[3]=(match[4]||match[5]||"").replace(rbackslash,"");if(match[2]==="~="){match[3]=" "+match[3]+" "}return match.slice(0,4)},CHILD:function(match){match[1]=match[1].toLowerCase();if(match[1]==="nth"){if(!match[2]){Sizzle.error(match[0])}match[3]=+(match[3]?match[4]+(match[5]||1):2*(match[2]==="even"||match[2]==="odd"));match[4]=+(match[6]+match[7]||match[2]==="odd")}else if(match[2]){Sizzle.error(match[0])}return match},PSEUDO:function(match){var unquoted,excess;if(matchExpr["CHILD"].test(match[0])){return null}if(match[3]){match[2]=match[3]}else if(unquoted=match[4]){if(rpseudo.test(unquoted)&&(excess=tokenize(unquoted,true))&&(excess=unquoted.indexOf(")",unquoted.length-excess)-unquoted.length)){unquoted=unquoted.slice(0,excess);match[0]=match[0].slice(0,excess)}match[2]=unquoted}return match.slice(0,3)}},filter:{ID:assertGetIdNotName?function(id){id=id.replace(rbackslash,"");return function(elem){return elem.getAttribute("id")===id}}:function(id){id=id.replace(rbackslash,"");return function(elem){var node=typeof elem.getAttributeNode!==strundefined&&elem.getAttributeNode("id");return node&&node.value===id}},TAG:function(nodeName){if(nodeName==="*"){return function(){return true}}nodeName=nodeName.replace(rbackslash,"").toLowerCase();return function(elem){return elem.nodeName&&elem.nodeName.toLowerCase()===nodeName}},CLASS:function(className){var pattern=classCache[expando][className+" "];return pattern||(pattern=new RegExp("(^|"+whitespace+")"+className+"("+whitespace+"|$)"))&&classCache(className,function(elem){return pattern.test(elem.className||typeof elem.getAttribute!==strundefined&&elem.getAttribute("class")||"")})},ATTR:function(name,operator,check){return function(elem,context){var result=Sizzle.attr(elem,name);if(result==null){return operator==="!="}if(!operator){return true}result+="";return operator==="="?result===check:operator==="!="?result!==check:operator==="^="?check&&result.indexOf(check)===0:operator==="*="?check&&result.indexOf(check)>-1:operator==="$="?check&&result.substr(result.length-check.length)===check:operator==="~="?(" "+result+" ").indexOf(check)>-1:operator==="|="?result===check||result.substr(0,check.length+1)===check+"-":false}},CHILD:function(type,argument,first,last){if(type==="nth"){return function(elem){var node,diff,parent=elem.parentNode;if(first===1&&last===0){return true}if(parent){diff=0;for(node=parent.firstChild;node;node=node.nextSibling){if(node.nodeType===1){diff++; +if(elem===node){break}}}}diff-=last;return diff===first||diff%first===0&&diff/first>=0}}return function(elem){var node=elem;switch(type){case"only":case"first":while(node=node.previousSibling){if(node.nodeType===1){return false}}if(type==="first"){return true}node=elem;case"last":while(node=node.nextSibling){if(node.nodeType===1){return false}}return true}}},PSEUDO:function(pseudo,argument){var args,fn=Expr.pseudos[pseudo]||Expr.setFilters[pseudo.toLowerCase()]||Sizzle.error("unsupported pseudo: "+pseudo);if(fn[expando]){return fn(argument)}if(fn.length>1){args=[pseudo,pseudo,"",argument];return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase())?markFunction(function(seed,matches){var idx,matched=fn(seed,argument),i=matched.length;while(i--){idx=indexOf.call(seed,matched[i]);seed[idx]=!(matches[idx]=matched[i])}}):function(elem){return fn(elem,0,args)}}return fn}},pseudos:{not:markFunction(function(selector){var input=[],results=[],matcher=compile(selector.replace(rtrim,"$1"));return matcher[expando]?markFunction(function(seed,matches,context,xml){var elem,unmatched=matcher(seed,null,xml,[]),i=seed.length;while(i--){if(elem=unmatched[i]){seed[i]=!(matches[i]=elem)}}}):function(elem,context,xml){input[0]=elem;matcher(input,null,xml,results);return!results.pop()}}),has:markFunction(function(selector){return function(elem){return Sizzle(selector,elem).length>0}}),contains:markFunction(function(text){return function(elem){return(elem.textContent||elem.innerText||getText(elem)).indexOf(text)>-1}}),enabled:function(elem){return elem.disabled===false},disabled:function(elem){return elem.disabled===true},checked:function(elem){var nodeName=elem.nodeName.toLowerCase();return nodeName==="input"&&!!elem.checked||nodeName==="option"&&!!elem.selected},selected:function(elem){if(elem.parentNode){elem.parentNode.selectedIndex}return elem.selected===true},parent:function(elem){return!Expr.pseudos["empty"](elem)},empty:function(elem){var nodeType;elem=elem.firstChild;while(elem){if(elem.nodeName>"@"||(nodeType=elem.nodeType)===3||nodeType===4){return false}elem=elem.nextSibling}return true},header:function(elem){return rheader.test(elem.nodeName)},text:function(elem){var type,attr;return elem.nodeName.toLowerCase()==="input"&&(type=elem.type)==="text"&&((attr=elem.getAttribute("type"))==null||attr.toLowerCase()===type)},radio:createInputPseudo("radio"),checkbox:createInputPseudo("checkbox"),file:createInputPseudo("file"),password:createInputPseudo("password"),image:createInputPseudo("image"),submit:createButtonPseudo("submit"),reset:createButtonPseudo("reset"),button:function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type==="button"||name==="button"},input:function(elem){return rinputs.test(elem.nodeName)},focus:function(elem){var doc=elem.ownerDocument;return elem===doc.activeElement&&(!doc.hasFocus||doc.hasFocus())&&!!(elem.type||elem.href||~elem.tabIndex)},active:function(elem){return elem===elem.ownerDocument.activeElement},first:createPositionalPseudo(function(){return[0]}),last:createPositionalPseudo(function(matchIndexes,length){return[length-1]}),eq:createPositionalPseudo(function(matchIndexes,length,argument){return[argument<0?argument+length:argument]}),even:createPositionalPseudo(function(matchIndexes,length){for(var i=0;i<length;i+=2){matchIndexes.push(i)}return matchIndexes}),odd:createPositionalPseudo(function(matchIndexes,length){for(var i=1;i<length;i+=2){matchIndexes.push(i)}return matchIndexes}),lt:createPositionalPseudo(function(matchIndexes,length,argument){for(var i=argument<0?argument+length:argument;--i>=0;){matchIndexes.push(i)}return matchIndexes}),gt:createPositionalPseudo(function(matchIndexes,length,argument){for(var i=argument<0?argument+length:argument;++i<length;){matchIndexes.push(i)}return matchIndexes})}};function siblingCheck(a,b,ret){if(a===b){return ret}var cur=a.nextSibling;while(cur){if(cur===b){return-1}cur=cur.nextSibling}return 1}sortOrder=docElem.compareDocumentPosition?function(a,b){if(a===b){hasDuplicate=true;return 0}return(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b){hasDuplicate=true;return 0}else if(a.sourceIndex&&b.sourceIndex){return a.sourceIndex-b.sourceIndex}var al,bl,ap=[],bp=[],aup=a.parentNode,bup=b.parentNode,cur=aup;if(aup===bup){return siblingCheck(a,b)}else if(!aup){return-1}else if(!bup){return 1}while(cur){ap.unshift(cur);cur=cur.parentNode}cur=bup;while(cur){bp.unshift(cur);cur=cur.parentNode}al=ap.length;bl=bp.length;for(var i=0;i<al&&i<bl;i++){if(ap[i]!==bp[i]){return siblingCheck(ap[i],bp[i])}}return i===al?siblingCheck(a,bp[i],-1):siblingCheck(ap[i],b,1)};[0,0].sort(sortOrder);baseHasDuplicate=!hasDuplicate;Sizzle.uniqueSort=function(results){var elem,duplicates=[],i=1,j=0;hasDuplicate=baseHasDuplicate;results.sort(sortOrder);if(hasDuplicate){for(;elem=results[i];i++){if(elem===results[i-1]){j=duplicates.push(i)}}while(j--){results.splice(duplicates[j],1)}}return results};Sizzle.error=function(msg){throw new Error("Syntax error, unrecognized expression: "+msg)};function tokenize(selector,parseOnly){var matched,match,tokens,type,soFar,groups,preFilters,cached=tokenCache[expando][selector+" "];if(cached){return parseOnly?0:cached.slice(0)}soFar=selector;groups=[];preFilters=Expr.preFilter;while(soFar){if(!matched||(match=rcomma.exec(soFar))){if(match){soFar=soFar.slice(match[0].length)||soFar}groups.push(tokens=[])}matched=false;if(match=rcombinators.exec(soFar)){tokens.push(matched=new Token(match.shift()));soFar=soFar.slice(matched.length);matched.type=match[0].replace(rtrim," ")}for(type in Expr.filter){if((match=matchExpr[type].exec(soFar))&&(!preFilters[type]||(match=preFilters[type](match)))){tokens.push(matched=new Token(match.shift()));soFar=soFar.slice(matched.length);matched.type=type;matched.matches=match}}if(!matched){break}}return parseOnly?soFar.length:soFar?Sizzle.error(selector):tokenCache(selector,groups).slice(0)}function addCombinator(matcher,combinator,base){var dir=combinator.dir,checkNonElements=base&&combinator.dir==="parentNode",doneName=done++;return combinator.first?function(elem,context,xml){while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){return matcher(elem,context,xml)}}}:function(elem,context,xml){if(!xml){var cache,dirkey=dirruns+" "+doneName+" ",cachedkey=dirkey+cachedruns;while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){if((cache=elem[expando])===cachedkey){return elem.sizset}else if(typeof cache==="string"&&cache.indexOf(dirkey)===0){if(elem.sizset){return elem}}else{elem[expando]=cachedkey;if(matcher(elem,context,xml)){elem.sizset=true;return elem}elem.sizset=false}}}}else{while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){if(matcher(elem,context,xml)){return elem}}}}}}function elementMatcher(matchers){return matchers.length>1?function(elem,context,xml){var i=matchers.length;while(i--){if(!matchers[i](elem,context,xml)){return false}}return true}:matchers[0]}function condense(unmatched,map,filter,context,xml){var elem,newUnmatched=[],i=0,len=unmatched.length,mapped=map!=null;for(;i<len;i++){if(elem=unmatched[i]){if(!filter||filter(elem,context,xml)){newUnmatched.push(elem);if(mapped){map.push(i)}}}}return newUnmatched}function setMatcher(preFilter,selector,matcher,postFilter,postFinder,postSelector){if(postFilter&&!postFilter[expando]){postFilter=setMatcher(postFilter)}if(postFinder&&!postFinder[expando]){postFinder=setMatcher(postFinder,postSelector)}return markFunction(function(seed,results,context,xml){var temp,i,elem,preMap=[],postMap=[],preexisting=results.length,elems=seed||multipleContexts(selector||"*",context.nodeType?[context]:context,[]),matcherIn=preFilter&&(seed||!selector)?condense(elems,preMap,preFilter,context,xml):elems,matcherOut=matcher?postFinder||(seed?preFilter:preexisting||postFilter)?[]:results:matcherIn;if(matcher){matcher(matcherIn,matcherOut,context,xml)}if(postFilter){temp=condense(matcherOut,postMap);postFilter(temp,[],context,xml);i=temp.length;while(i--){if(elem=temp[i]){matcherOut[postMap[i]]=!(matcherIn[postMap[i]]=elem)}}}if(seed){if(postFinder||preFilter){if(postFinder){temp=[];i=matcherOut.length;while(i--){if(elem=matcherOut[i]){temp.push(matcherIn[i]=elem)}}postFinder(null,matcherOut=[],temp,xml)}i=matcherOut.length;while(i--){if((elem=matcherOut[i])&&(temp=postFinder?indexOf.call(seed,elem):preMap[i])>-1){seed[temp]=!(results[temp]=elem)}}}}else{matcherOut=condense(matcherOut===results?matcherOut.splice(preexisting,matcherOut.length):matcherOut);if(postFinder){postFinder(null,results,matcherOut,xml)}else{push.apply(results,matcherOut)}}})}function matcherFromTokens(tokens){var checkContext,matcher,j,len=tokens.length,leadingRelative=Expr.relative[tokens[0].type],implicitRelative=leadingRelative||Expr.relative[" "],i=leadingRelative?1:0,matchContext=addCombinator(function(elem){return elem===checkContext},implicitRelative,true),matchAnyContext=addCombinator(function(elem){return indexOf.call(checkContext,elem)>-1},implicitRelative,true),matchers=[function(elem,context,xml){return!leadingRelative&&(xml||context!==outermostContext)||((checkContext=context).nodeType?matchContext(elem,context,xml):matchAnyContext(elem,context,xml))}];for(;i<len;i++){if(matcher=Expr.relative[tokens[i].type]){matchers=[addCombinator(elementMatcher(matchers),matcher)]}else{matcher=Expr.filter[tokens[i].type].apply(null,tokens[i].matches);if(matcher[expando]){j=++i;for(;j<len;j++){if(Expr.relative[tokens[j].type]){break}}return setMatcher(i>1&&elementMatcher(matchers),i>1&&tokens.slice(0,i-1).join("").replace(rtrim,"$1"),matcher,i<j&&matcherFromTokens(tokens.slice(i,j)),j<len&&matcherFromTokens(tokens=tokens.slice(j)),j<len&&tokens.join(""))}matchers.push(matcher)}}return elementMatcher(matchers)}function matcherFromGroupMatchers(elementMatchers,setMatchers){var bySet=setMatchers.length>0,byElement=elementMatchers.length>0,superMatcher=function(seed,context,xml,results,expandContext){var elem,j,matcher,setMatched=[],matchedCount=0,i="0",unmatched=seed&&[],outermost=expandContext!=null,contextBackup=outermostContext,elems=seed||byElement&&Expr.find["TAG"]("*",expandContext&&context.parentNode||context),dirrunsUnique=dirruns+=contextBackup==null?1:Math.E;if(outermost){outermostContext=context!==document&&context;cachedruns=superMatcher.el}for(;(elem=elems[i])!=null;i++){if(byElement&&elem){for(j=0;matcher=elementMatchers[j];j++){if(matcher(elem,context,xml)){results.push(elem);break}}if(outermost){dirruns=dirrunsUnique;cachedruns=++superMatcher.el}}if(bySet){if(elem=!matcher&&elem){matchedCount--}if(seed){unmatched.push(elem)}}}matchedCount+=i;if(bySet&&i!==matchedCount){for(j=0;matcher=setMatchers[j];j++){matcher(unmatched,setMatched,context,xml)}if(seed){if(matchedCount>0){while(i--){if(!(unmatched[i]||setMatched[i])){setMatched[i]=pop.call(results)}}}setMatched=condense(setMatched)}push.apply(results,setMatched);if(outermost&&!seed&&setMatched.length>0&&matchedCount+setMatchers.length>1){Sizzle.uniqueSort(results)}}if(outermost){dirruns=dirrunsUnique;outermostContext=contextBackup}return unmatched};superMatcher.el=0;return bySet?markFunction(superMatcher):superMatcher}compile=Sizzle.compile=function(selector,group){var i,setMatchers=[],elementMatchers=[],cached=compilerCache[expando][selector+" "];if(!cached){if(!group){group=tokenize(selector)}i=group.length;while(i--){cached=matcherFromTokens(group[i]);if(cached[expando]){setMatchers.push(cached)}else{elementMatchers.push(cached)}}cached=compilerCache(selector,matcherFromGroupMatchers(elementMatchers,setMatchers))}return cached};function multipleContexts(selector,contexts,results){var i=0,len=contexts.length;for(;i<len;i++){Sizzle(selector,contexts[i],results)}return results}function select(selector,context,results,seed,xml){var i,tokens,token,type,find,match=tokenize(selector),j=match.length;if(!seed){if(match.length===1){tokens=match[0]=match[0].slice(0);if(tokens.length>2&&(token=tokens[0]).type==="ID"&&context.nodeType===9&&!xml&&Expr.relative[tokens[1].type]){context=Expr.find["ID"](token.matches[0].replace(rbackslash,""),context,xml)[0];if(!context){return results}selector=selector.slice(tokens.shift().length)}for(i=matchExpr["POS"].test(selector)?-1:tokens.length-1;i>=0;i--){token=tokens[i];if(Expr.relative[type=token.type]){break}if(find=Expr.find[type]){if(seed=find(token.matches[0].replace(rbackslash,""),rsibling.test(tokens[0].type)&&context.parentNode||context,xml)){tokens.splice(i,1);selector=seed.length&&tokens.join("");if(!selector){push.apply(results,slice.call(seed,0));return results}break}}}}}compile(selector,match)(seed,context,xml,results,rsibling.test(selector));return results}if(document.querySelectorAll){(function(){var disconnectedMatch,oldSelect=select,rescape=/'|\\/g,rattributeQuotes=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,rbuggyQSA=[":focus"],rbuggyMatches=[":active"],matches=docElem.matchesSelector||docElem.mozMatchesSelector||docElem.webkitMatchesSelector||docElem.oMatchesSelector||docElem.msMatchesSelector;assert(function(div){div.innerHTML="<select><option selected=''></option></select>";if(!div.querySelectorAll("[selected]").length){rbuggyQSA.push("\\["+whitespace+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)")}if(!div.querySelectorAll(":checked").length){rbuggyQSA.push(":checked")}});assert(function(div){div.innerHTML="<p test=''></p>";if(div.querySelectorAll("[test^='']").length){rbuggyQSA.push("[*^$]="+whitespace+"*(?:\"\"|'')")}div.innerHTML="<input type='hidden'/>";if(!div.querySelectorAll(":enabled").length){rbuggyQSA.push(":enabled",":disabled")}});rbuggyQSA=new RegExp(rbuggyQSA.join("|"));select=function(selector,context,results,seed,xml){if(!seed&&!xml&&!rbuggyQSA.test(selector)){var groups,i,old=true,nid=expando,newContext=context,newSelector=context.nodeType===9&&selector;if(context.nodeType===1&&context.nodeName.toLowerCase()!=="object"){groups=tokenize(selector);if(old=context.getAttribute("id")){nid=old.replace(rescape,"\\$&")}else{context.setAttribute("id",nid)}nid="[id='"+nid+"'] ";i=groups.length;while(i--){groups[i]=nid+groups[i].join("")}newContext=rsibling.test(selector)&&context.parentNode||context;newSelector=groups.join(",")}if(newSelector){try{push.apply(results,slice.call(newContext.querySelectorAll(newSelector),0));return results}catch(qsaError){}finally{if(!old){context.removeAttribute("id")}}}}return oldSelect(selector,context,results,seed,xml)};if(matches){assert(function(div){disconnectedMatch=matches.call(div,"div");try{matches.call(div,"[test!='']:sizzle");rbuggyMatches.push("!=",pseudos)}catch(e){}});rbuggyMatches=new RegExp(rbuggyMatches.join("|"));Sizzle.matchesSelector=function(elem,expr){expr=expr.replace(rattributeQuotes,"='$1']");if(!isXML(elem)&&!rbuggyMatches.test(expr)&&!rbuggyQSA.test(expr)){try{var ret=matches.call(elem,expr);if(ret||disconnectedMatch||elem.document&&elem.document.nodeType!==11){return ret}}catch(e){}}return Sizzle(expr,null,null,[elem]).length>0}}})()}Expr.pseudos["nth"]=Expr.pseudos["eq"];function setFilters(){}Expr.filters=setFilters.prototype=Expr.pseudos;Expr.setFilters=new setFilters;Sizzle.attr=jQuery.attr;jQuery.find=Sizzle;jQuery.expr=Sizzle.selectors;jQuery.expr[":"]=jQuery.expr.pseudos;jQuery.unique=Sizzle.uniqueSort;jQuery.text=Sizzle.getText;jQuery.isXMLDoc=Sizzle.isXML;jQuery.contains=Sizzle.contains})(window);var runtil=/Until$/,rparentsprev=/^(?:parents|prev(?:Until|All))/,isSimple=/^.[^:#\[\.,]*$/,rneedsContext=jQuery.expr.match.needsContext,guaranteedUnique={children:true,contents:true,next:true,prev:true};jQuery.fn.extend({find:function(selector){var i,l,length,n,r,ret,self=this;if(typeof selector!=="string"){return jQuery(selector).filter(function(){for(i=0,l=self.length;i<l;i++){if(jQuery.contains(self[i],this)){return true}}})}ret=this.pushStack("","find",selector);for(i=0,l=this.length;i<l;i++){length=ret.length;jQuery.find(selector,this[i],ret);if(i>0){for(n=length;n<ret.length;n++){for(r=0;r<length;r++){if(ret[r]===ret[n]){ret.splice(n--,1);break}}}}}return ret},has:function(target){var i,targets=jQuery(target,this),len=targets.length;return this.filter(function(){for(i=0;i<len;i++){if(jQuery.contains(this,targets[i])){return true}}})},not:function(selector){return this.pushStack(winnow(this,selector,false),"not",selector)},filter:function(selector){return this.pushStack(winnow(this,selector,true),"filter",selector)},is:function(selector){return!!selector&&(typeof selector==="string"?rneedsContext.test(selector)?jQuery(selector,this.context).index(this[0])>=0:jQuery.filter(selector,this).length>0:this.filter(selector).length>0)},closest:function(selectors,context){var cur,i=0,l=this.length,ret=[],pos=rneedsContext.test(selectors)||typeof selectors!=="string"?jQuery(selectors,context||this.context):0;for(;i<l;i++){cur=this[i];while(cur&&cur.ownerDocument&&cur!==context&&cur.nodeType!==11){if(pos?pos.index(cur)>-1:jQuery.find.matchesSelector(cur,selectors)){ret.push(cur);break}cur=cur.parentNode}}ret=ret.length>1?jQuery.unique(ret):ret;return this.pushStack(ret,"closest",selectors)},index:function(elem){if(!elem){return this[0]&&this[0].parentNode?this.prevAll().length:-1}if(typeof elem==="string"){return jQuery.inArray(this[0],jQuery(elem))}return jQuery.inArray(elem.jquery?elem[0]:elem,this)},add:function(selector,context){var set=typeof selector==="string"?jQuery(selector,context):jQuery.makeArray(selector&&selector.nodeType?[selector]:selector),all=jQuery.merge(this.get(),set);return this.pushStack(isDisconnected(set[0])||isDisconnected(all[0])?all:jQuery.unique(all))},addBack:function(selector){return this.add(selector==null?this.prevObject:this.prevObject.filter(selector))}});jQuery.fn.andSelf=jQuery.fn.addBack;function isDisconnected(node){return!node||!node.parentNode||node.parentNode.nodeType===11}function sibling(cur,dir){do{cur=cur[dir]}while(cur&&cur.nodeType!==1);return cur}jQuery.each({parent:function(elem){var parent=elem.parentNode;return parent&&parent.nodeType!==11?parent:null},parents:function(elem){return jQuery.dir(elem,"parentNode")},parentsUntil:function(elem,i,until){return jQuery.dir(elem,"parentNode",until)},next:function(elem){return sibling(elem,"nextSibling")},prev:function(elem){return sibling(elem,"previousSibling")},nextAll:function(elem){return jQuery.dir(elem,"nextSibling")},prevAll:function(elem){return jQuery.dir(elem,"previousSibling")},nextUntil:function(elem,i,until){return jQuery.dir(elem,"nextSibling",until)},prevUntil:function(elem,i,until){return jQuery.dir(elem,"previousSibling",until)},siblings:function(elem){return jQuery.sibling((elem.parentNode||{}).firstChild,elem)},children:function(elem){return jQuery.sibling(elem.firstChild)},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.merge([],elem.childNodes)}},function(name,fn){jQuery.fn[name]=function(until,selector){var ret=jQuery.map(this,fn,until);if(!runtil.test(name)){selector=until}if(selector&&typeof selector==="string"){ret=jQuery.filter(selector,ret)}ret=this.length>1&&!guaranteedUnique[name]?jQuery.unique(ret):ret;if(this.length>1&&rparentsprev.test(name)){ret=ret.reverse()}return this.pushStack(ret,name,core_slice.call(arguments).join(","))}});jQuery.extend({filter:function(expr,elems,not){if(not){expr=":not("+expr+")"}return elems.length===1?jQuery.find.matchesSelector(elems[0],expr)?[elems[0]]:[]:jQuery.find.matches(expr,elems)},dir:function(elem,dir,until){var matched=[],cur=elem[dir];while(cur&&cur.nodeType!==9&&(until===undefined||cur.nodeType!==1||!jQuery(cur).is(until))){if(cur.nodeType===1){matched.push(cur)}cur=cur[dir]}return matched},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType===1&&n!==elem){r.push(n)}}return r}});function winnow(elements,qualifier,keep){qualifier=qualifier||0;if(jQuery.isFunction(qualifier)){return jQuery.grep(elements,function(elem,i){var retVal=!!qualifier.call(elem,i,elem);return retVal===keep})}else if(qualifier.nodeType){return jQuery.grep(elements,function(elem,i){return elem===qualifier===keep})}else if(typeof qualifier==="string"){var filtered=jQuery.grep(elements,function(elem){return elem.nodeType===1});if(isSimple.test(qualifier)){return jQuery.filter(qualifier,filtered,!keep)}else{qualifier=jQuery.filter(qualifier,filtered)}}return jQuery.grep(elements,function(elem,i){return jQuery.inArray(elem,qualifier)>=0===keep})}function createSafeFragment(document){var list=nodeNames.split("|"),safeFrag=document.createDocumentFragment();if(safeFrag.createElement){while(list.length){safeFrag.createElement(list.pop())}}return safeFrag}var nodeNames="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|"+"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",rinlinejQuery=/ jQuery\d+="(?:null|\d+)"/g,rleadingWhitespace=/^\s+/,rxhtmlTag=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,rtagName=/<([\w:]+)/,rtbody=/<tbody/i,rhtml=/<|&#?\w+;/,rnoInnerhtml=/<(?:script|style|link)/i,rnocache=/<(?:script|object|embed|option|style)/i,rnoshimcache=new RegExp("<(?:"+nodeNames+")[\\s/>]","i"),rcheckableType=/^(?:checkbox|radio)$/,rchecked=/checked\s*(?:[^=]|=\s*.checked.)/i,rscriptType=/\/(java|ecma)script/i,rcleanScript=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,wrapMap={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},safeFragment=createSafeFragment(document),fragmentDiv=safeFragment.appendChild(document.createElement("div"));wrapMap.optgroup=wrapMap.option;wrapMap.tbody=wrapMap.tfoot=wrapMap.colgroup=wrapMap.caption=wrapMap.thead;wrapMap.th=wrapMap.td;if(!jQuery.support.htmlSerialize){wrapMap._default=[1,"X<div>","</div>"]}jQuery.fn.extend({text:function(value){return jQuery.access(this,function(value){return value===undefined?jQuery.text(this):this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(value))},null,value,arguments.length)},wrapAll:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapAll(html.call(this,i))})}if(this[0]){var wrap=jQuery(html,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){wrap.insertBefore(this[0])}wrap.map(function(){var elem=this;while(elem.firstChild&&elem.firstChild.nodeType===1){elem=elem.firstChild}return elem}).append(this)}return this},wrapInner:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapInner(html.call(this,i))})}return this.each(function(){var self=jQuery(this),contents=self.contents();if(contents.length){contents.wrapAll(html)}else{self.append(html)}})},wrap:function(html){var isFunction=jQuery.isFunction(html);return this.each(function(i){jQuery(this).wrapAll(isFunction?html.call(this,i):html)})},unwrap:function(){return this.parent().each(function(){if(!jQuery.nodeName(this,"body")){jQuery(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1||this.nodeType===11){this.appendChild(elem)}})},prepend:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1||this.nodeType===11){this.insertBefore(elem,this.firstChild)}})},before:function(){if(!isDisconnected(this[0])){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this)})}if(arguments.length){var set=jQuery.clean(arguments);return this.pushStack(jQuery.merge(set,this),"before",this.selector)}},after:function(){if(!isDisconnected(this[0])){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this.nextSibling)})}if(arguments.length){var set=jQuery.clean(arguments);return this.pushStack(jQuery.merge(this,set),"after",this.selector)}},remove:function(selector,keepData){var elem,i=0;for(;(elem=this[i])!=null;i++){if(!selector||jQuery.filter(selector,[elem]).length){if(!keepData&&elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));jQuery.cleanData([elem])}if(elem.parentNode){elem.parentNode.removeChild(elem)}}}return this},empty:function(){var elem,i=0;for(;(elem=this[i])!=null;i++){if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"))}while(elem.firstChild){elem.removeChild(elem.firstChild)}}return this},clone:function(dataAndEvents,deepDataAndEvents){dataAndEvents=dataAndEvents==null?false:dataAndEvents;deepDataAndEvents=deepDataAndEvents==null?dataAndEvents:deepDataAndEvents;return this.map(function(){return jQuery.clone(this,dataAndEvents,deepDataAndEvents)})},html:function(value){return jQuery.access(this,function(value){var elem=this[0]||{},i=0,l=this.length;if(value===undefined){return elem.nodeType===1?elem.innerHTML.replace(rinlinejQuery,""):undefined}if(typeof value==="string"&&!rnoInnerhtml.test(value)&&(jQuery.support.htmlSerialize||!rnoshimcache.test(value))&&(jQuery.support.leadingWhitespace||!rleadingWhitespace.test(value))&&!wrapMap[(rtagName.exec(value)||["",""])[1].toLowerCase()]){value=value.replace(rxhtmlTag,"<$1></$2>");try{for(;i<l;i++){elem=this[i]||{};if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));elem.innerHTML=value}}elem=0}catch(e){}}if(elem){this.empty().append(value)}},null,value,arguments.length)},replaceWith:function(value){if(!isDisconnected(this[0])){if(jQuery.isFunction(value)){return this.each(function(i){var self=jQuery(this),old=self.html();self.replaceWith(value.call(this,i,old))})}if(typeof value!=="string"){value=jQuery(value).detach()}return this.each(function(){var next=this.nextSibling,parent=this.parentNode;jQuery(this).remove();if(next){jQuery(next).before(value)}else{jQuery(parent).append(value)}})}return this.length?this.pushStack(jQuery(jQuery.isFunction(value)?value():value),"replaceWith",value):this},detach:function(selector){return this.remove(selector,true)},domManip:function(args,table,callback){args=[].concat.apply([],args);var results,first,fragment,iNoClone,i=0,value=args[0],scripts=[],l=this.length;if(!jQuery.support.checkClone&&l>1&&typeof value==="string"&&rchecked.test(value)){return this.each(function(){jQuery(this).domManip(args,table,callback)})}if(jQuery.isFunction(value)){return this.each(function(i){var self=jQuery(this);args[0]=value.call(this,i,table?self.html():undefined);self.domManip(args,table,callback)})}if(this[0]){results=jQuery.buildFragment(args,this,scripts);fragment=results.fragment;first=fragment.firstChild;if(fragment.childNodes.length===1){fragment=first}if(first){table=table&&jQuery.nodeName(first,"tr");for(iNoClone=results.cacheable||l-1;i<l;i++){callback.call(table&&jQuery.nodeName(this[i],"table")?findOrAppend(this[i],"tbody"):this[i],i===iNoClone?fragment:jQuery.clone(fragment,true,true))}}fragment=first=null;if(scripts.length){jQuery.each(scripts,function(i,elem){if(elem.src){if(jQuery.ajax){jQuery.ajax({url:elem.src,type:"GET",dataType:"script",async:false,global:false,"throws":true})}else{jQuery.error("no ajax")}}else{jQuery.globalEval((elem.text||elem.textContent||elem.innerHTML||"").replace(rcleanScript,""))}if(elem.parentNode){elem.parentNode.removeChild(elem)}})}}return this}});function findOrAppend(elem,tag){return elem.getElementsByTagName(tag)[0]||elem.appendChild(elem.ownerDocument.createElement(tag))}function cloneCopyEvent(src,dest){if(dest.nodeType!==1||!jQuery.hasData(src)){return}var type,i,l,oldData=jQuery._data(src),curData=jQuery._data(dest,oldData),events=oldData.events;if(events){delete curData.handle;curData.events={};for(type in events){for(i=0,l=events[type].length;i<l;i++){jQuery.event.add(dest,type,events[type][i])}}}if(curData.data){curData.data=jQuery.extend({},curData.data)}}function cloneFixAttributes(src,dest){var nodeName;if(dest.nodeType!==1){return}if(dest.clearAttributes){dest.clearAttributes()}if(dest.mergeAttributes){dest.mergeAttributes(src)}nodeName=dest.nodeName.toLowerCase();if(nodeName==="object"){if(dest.parentNode){dest.outerHTML=src.outerHTML}if(jQuery.support.html5Clone&&(src.innerHTML&&!jQuery.trim(dest.innerHTML))){dest.innerHTML=src.innerHTML}}else if(nodeName==="input"&&rcheckableType.test(src.type)){dest.defaultChecked=dest.checked=src.checked;if(dest.value!==src.value){dest.value=src.value}}else if(nodeName==="option"){dest.selected=src.defaultSelected}else if(nodeName==="input"||nodeName==="textarea"){dest.defaultValue=src.defaultValue}else if(nodeName==="script"&&dest.text!==src.text){dest.text=src.text}dest.removeAttribute(jQuery.expando)}jQuery.buildFragment=function(args,context,scripts){var fragment,cacheable,cachehit,first=args[0];context=context||document;context=!context.nodeType&&context[0]||context;context=context.ownerDocument||context;if(args.length===1&&typeof first==="string"&&first.length<512&&context===document&&first.charAt(0)==="<"&&!rnocache.test(first)&&(jQuery.support.checkClone||!rchecked.test(first))&&(jQuery.support.html5Clone||!rnoshimcache.test(first))){cacheable=true;fragment=jQuery.fragments[first];cachehit=fragment!==undefined}if(!fragment){fragment=context.createDocumentFragment();jQuery.clean(args,context,fragment,scripts);if(cacheable){jQuery.fragments[first]=cachehit&&fragment}}return{fragment:fragment,cacheable:cacheable}};jQuery.fragments={};jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(selector){var elems,i=0,ret=[],insert=jQuery(selector),l=insert.length,parent=this.length===1&&this[0].parentNode;if((parent==null||parent&&parent.nodeType===11&&parent.childNodes.length===1)&&l===1){insert[original](this[0]);return this}else{for(;i<l;i++){elems=(i>0?this.clone(true):this).get();jQuery(insert[i])[original](elems);ret=ret.concat(elems)}return this.pushStack(ret,name,insert.selector)}}});function getAll(elem){if(typeof elem.getElementsByTagName!=="undefined"){return elem.getElementsByTagName("*")}else if(typeof elem.querySelectorAll!=="undefined"){return elem.querySelectorAll("*")}else{return[]}}function fixDefaultChecked(elem){if(rcheckableType.test(elem.type)){elem.defaultChecked=elem.checked}}jQuery.extend({clone:function(elem,dataAndEvents,deepDataAndEvents){var srcElements,destElements,i,clone;if(jQuery.support.html5Clone||jQuery.isXMLDoc(elem)||!rnoshimcache.test("<"+elem.nodeName+">")){clone=elem.cloneNode(true)}else{fragmentDiv.innerHTML=elem.outerHTML;fragmentDiv.removeChild(clone=fragmentDiv.firstChild)}if((!jQuery.support.noCloneEvent||!jQuery.support.noCloneChecked)&&(elem.nodeType===1||elem.nodeType===11)&&!jQuery.isXMLDoc(elem)){cloneFixAttributes(elem,clone);srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){if(destElements[i]){cloneFixAttributes(srcElements[i],destElements[i])}}}if(dataAndEvents){cloneCopyEvent(elem,clone);if(deepDataAndEvents){srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){cloneCopyEvent(srcElements[i],destElements[i])}}}srcElements=destElements=null;return clone},clean:function(elems,context,fragment,scripts){var i,j,elem,tag,wrap,depth,div,hasBody,tbody,len,handleScript,jsTags,safe=context===document&&safeFragment,ret=[];if(!context||typeof context.createDocumentFragment==="undefined"){context=document}for(i=0;(elem=elems[i])!=null;i++){if(typeof elem==="number"){elem+=""}if(!elem){continue}if(typeof elem==="string"){if(!rhtml.test(elem)){elem=context.createTextNode(elem)}else{safe=safe||createSafeFragment(context);div=context.createElement("div");safe.appendChild(div);elem=elem.replace(rxhtmlTag,"<$1></$2>");tag=(rtagName.exec(elem)||["",""])[1].toLowerCase();wrap=wrapMap[tag]||wrapMap._default;depth=wrap[0];div.innerHTML=wrap[1]+elem+wrap[2];while(depth--){div=div.lastChild +}if(!jQuery.support.tbody){hasBody=rtbody.test(elem);tbody=tag==="table"&&!hasBody?div.firstChild&&div.firstChild.childNodes:wrap[1]==="<table>"&&!hasBody?div.childNodes:[];for(j=tbody.length-1;j>=0;--j){if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length){tbody[j].parentNode.removeChild(tbody[j])}}}if(!jQuery.support.leadingWhitespace&&rleadingWhitespace.test(elem)){div.insertBefore(context.createTextNode(rleadingWhitespace.exec(elem)[0]),div.firstChild)}elem=div.childNodes;div.parentNode.removeChild(div)}}if(elem.nodeType){ret.push(elem)}else{jQuery.merge(ret,elem)}}if(div){elem=div=safe=null}if(!jQuery.support.appendChecked){for(i=0;(elem=ret[i])!=null;i++){if(jQuery.nodeName(elem,"input")){fixDefaultChecked(elem)}else if(typeof elem.getElementsByTagName!=="undefined"){jQuery.grep(elem.getElementsByTagName("input"),fixDefaultChecked)}}}if(fragment){handleScript=function(elem){if(!elem.type||rscriptType.test(elem.type)){return scripts?scripts.push(elem.parentNode?elem.parentNode.removeChild(elem):elem):fragment.appendChild(elem)}};for(i=0;(elem=ret[i])!=null;i++){if(!(jQuery.nodeName(elem,"script")&&handleScript(elem))){fragment.appendChild(elem);if(typeof elem.getElementsByTagName!=="undefined"){jsTags=jQuery.grep(jQuery.merge([],elem.getElementsByTagName("script")),handleScript);ret.splice.apply(ret,[i+1,0].concat(jsTags));i+=jsTags.length}}}}return ret},cleanData:function(elems,acceptData){var data,id,elem,type,i=0,internalKey=jQuery.expando,cache=jQuery.cache,deleteExpando=jQuery.support.deleteExpando,special=jQuery.event.special;for(;(elem=elems[i])!=null;i++){if(acceptData||jQuery.acceptData(elem)){id=elem[internalKey];data=id&&cache[id];if(data){if(data.events){for(type in data.events){if(special[type]){jQuery.event.remove(elem,type)}else{jQuery.removeEvent(elem,type,data.handle)}}}if(cache[id]){delete cache[id];if(deleteExpando){delete elem[internalKey]}else if(elem.removeAttribute){elem.removeAttribute(internalKey)}else{elem[internalKey]=null}jQuery.deletedIds.push(id)}}}}}});(function(){var matched,browser;jQuery.uaMatch=function(ua){ua=ua.toLowerCase();var match=/(chrome)[ \/]([\w.]+)/.exec(ua)||/(webkit)[ \/]([\w.]+)/.exec(ua)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua)||/(msie) ([\w.]+)/.exec(ua)||ua.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua)||[];return{browser:match[1]||"",version:match[2]||"0"}};matched=jQuery.uaMatch(navigator.userAgent);browser={};if(matched.browser){browser[matched.browser]=true;browser.version=matched.version}if(browser.chrome){browser.webkit=true}else if(browser.webkit){browser.safari=true}jQuery.browser=browser;jQuery.sub=function(){function jQuerySub(selector,context){return new jQuerySub.fn.init(selector,context)}jQuery.extend(true,jQuerySub,this);jQuerySub.superclass=this;jQuerySub.fn=jQuerySub.prototype=this();jQuerySub.fn.constructor=jQuerySub;jQuerySub.sub=this.sub;jQuerySub.fn.init=function init(selector,context){if(context&&context instanceof jQuery&&!(context instanceof jQuerySub)){context=jQuerySub(context)}return jQuery.fn.init.call(this,selector,context,rootjQuerySub)};jQuerySub.fn.init.prototype=jQuerySub.fn;var rootjQuerySub=jQuerySub(document);return jQuerySub}})();var curCSS,iframe,iframeDoc,ralpha=/alpha\([^)]*\)/i,ropacity=/opacity=([^)]*)/,rposition=/^(top|right|bottom|left)$/,rdisplayswap=/^(none|table(?!-c[ea]).+)/,rmargin=/^margin/,rnumsplit=new RegExp("^("+core_pnum+")(.*)$","i"),rnumnonpx=new RegExp("^("+core_pnum+")(?!px)[a-z%]+$","i"),rrelNum=new RegExp("^([-+])=("+core_pnum+")","i"),elemdisplay={BODY:"block"},cssShow={position:"absolute",visibility:"hidden",display:"block"},cssNormalTransform={letterSpacing:0,fontWeight:400},cssExpand=["Top","Right","Bottom","Left"],cssPrefixes=["Webkit","O","Moz","ms"],eventsToggle=jQuery.fn.toggle;function vendorPropName(style,name){if(name in style){return name}var capName=name.charAt(0).toUpperCase()+name.slice(1),origName=name,i=cssPrefixes.length;while(i--){name=cssPrefixes[i]+capName;if(name in style){return name}}return origName}function isHidden(elem,el){elem=el||elem;return jQuery.css(elem,"display")==="none"||!jQuery.contains(elem.ownerDocument,elem)}function showHide(elements,show){var elem,display,values=[],index=0,length=elements.length;for(;index<length;index++){elem=elements[index];if(!elem.style){continue}values[index]=jQuery._data(elem,"olddisplay");if(show){if(!values[index]&&elem.style.display==="none"){elem.style.display=""}if(elem.style.display===""&&isHidden(elem)){values[index]=jQuery._data(elem,"olddisplay",css_defaultDisplay(elem.nodeName))}}else{display=curCSS(elem,"display");if(!values[index]&&display!=="none"){jQuery._data(elem,"olddisplay",display)}}}for(index=0;index<length;index++){elem=elements[index];if(!elem.style){continue}if(!show||elem.style.display==="none"||elem.style.display===""){elem.style.display=show?values[index]||"":"none"}}return elements}jQuery.fn.extend({css:function(name,value){return jQuery.access(this,function(elem,name,value){return value!==undefined?jQuery.style(elem,name,value):jQuery.css(elem,name)},name,value,arguments.length>1)},show:function(){return showHide(this,true)},hide:function(){return showHide(this)},toggle:function(state,fn2){var bool=typeof state==="boolean";if(jQuery.isFunction(state)&&jQuery.isFunction(fn2)){return eventsToggle.apply(this,arguments)}return this.each(function(){if(bool?state:isHidden(this)){jQuery(this).show()}else{jQuery(this).hide()}})}});jQuery.extend({cssHooks:{opacity:{get:function(elem,computed){if(computed){var ret=curCSS(elem,"opacity");return ret===""?"1":ret}}}},cssNumber:{fillOpacity:true,fontWeight:true,lineHeight:true,opacity:true,orphans:true,widows:true,zIndex:true,zoom:true},cssProps:{"float":jQuery.support.cssFloat?"cssFloat":"styleFloat"},style:function(elem,name,value,extra){if(!elem||elem.nodeType===3||elem.nodeType===8||!elem.style){return}var ret,type,hooks,origName=jQuery.camelCase(name),style=elem.style;name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(value!==undefined){type=typeof value;if(type==="string"&&(ret=rrelNum.exec(value))){value=(ret[1]+1)*ret[2]+parseFloat(jQuery.css(elem,name));type="number"}if(value==null||type==="number"&&isNaN(value)){return}if(type==="number"&&!jQuery.cssNumber[origName]){value+="px"}if(!hooks||!("set"in hooks)||(value=hooks.set(elem,value,extra))!==undefined){try{style[name]=value}catch(e){}}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,false,extra))!==undefined){return ret}return style[name]}},css:function(elem,name,numeric,extra){var val,num,hooks,origName=jQuery.camelCase(name);name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(elem.style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(hooks&&"get"in hooks){val=hooks.get(elem,true,extra)}if(val===undefined){val=curCSS(elem,name)}if(val==="normal"&&name in cssNormalTransform){val=cssNormalTransform[name]}if(numeric||extra!==undefined){num=parseFloat(val);return numeric||jQuery.isNumeric(num)?num||0:val}return val},swap:function(elem,options,callback){var ret,name,old={};for(name in options){old[name]=elem.style[name];elem.style[name]=options[name]}ret=callback.call(elem);for(name in options){elem.style[name]=old[name]}return ret}});if(window.getComputedStyle){curCSS=function(elem,name){var ret,width,minWidth,maxWidth,computed=window.getComputedStyle(elem,null),style=elem.style;if(computed){ret=computed.getPropertyValue(name)||computed[name];if(ret===""&&!jQuery.contains(elem.ownerDocument,elem)){ret=jQuery.style(elem,name)}if(rnumnonpx.test(ret)&&rmargin.test(name)){width=style.width;minWidth=style.minWidth;maxWidth=style.maxWidth;style.minWidth=style.maxWidth=style.width=ret;ret=computed.width;style.width=width;style.minWidth=minWidth;style.maxWidth=maxWidth}}return ret}}else if(document.documentElement.currentStyle){curCSS=function(elem,name){var left,rsLeft,ret=elem.currentStyle&&elem.currentStyle[name],style=elem.style;if(ret==null&&style&&style[name]){ret=style[name]}if(rnumnonpx.test(ret)&&!rposition.test(name)){left=style.left;rsLeft=elem.runtimeStyle&&elem.runtimeStyle.left;if(rsLeft){elem.runtimeStyle.left=elem.currentStyle.left}style.left=name==="fontSize"?"1em":ret;ret=style.pixelLeft+"px";style.left=left;if(rsLeft){elem.runtimeStyle.left=rsLeft}}return ret===""?"auto":ret}}function setPositiveNumber(elem,value,subtract){var matches=rnumsplit.exec(value);return matches?Math.max(0,matches[1]-(subtract||0))+(matches[2]||"px"):value}function augmentWidthOrHeight(elem,name,extra,isBorderBox){var i=extra===(isBorderBox?"border":"content")?4:name==="width"?1:0,val=0;for(;i<4;i+=2){if(extra==="margin"){val+=jQuery.css(elem,extra+cssExpand[i],true)}if(isBorderBox){if(extra==="content"){val-=parseFloat(curCSS(elem,"padding"+cssExpand[i]))||0}if(extra!=="margin"){val-=parseFloat(curCSS(elem,"border"+cssExpand[i]+"Width"))||0}}else{val+=parseFloat(curCSS(elem,"padding"+cssExpand[i]))||0;if(extra!=="padding"){val+=parseFloat(curCSS(elem,"border"+cssExpand[i]+"Width"))||0}}}return val}function getWidthOrHeight(elem,name,extra){var val=name==="width"?elem.offsetWidth:elem.offsetHeight,valueIsBorderBox=true,isBorderBox=jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing")==="border-box";if(val<=0||val==null){val=curCSS(elem,name);if(val<0||val==null){val=elem.style[name]}if(rnumnonpx.test(val)){return val}valueIsBorderBox=isBorderBox&&(jQuery.support.boxSizingReliable||val===elem.style[name]);val=parseFloat(val)||0}return val+augmentWidthOrHeight(elem,name,extra||(isBorderBox?"border":"content"),valueIsBorderBox)+"px"}function css_defaultDisplay(nodeName){if(elemdisplay[nodeName]){return elemdisplay[nodeName]}var elem=jQuery("<"+nodeName+">").appendTo(document.body),display=elem.css("display");elem.remove();if(display==="none"||display===""){iframe=document.body.appendChild(iframe||jQuery.extend(document.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!iframeDoc||!iframe.createElement){iframeDoc=(iframe.contentWindow||iframe.contentDocument).document;iframeDoc.write("<!doctype html><html><body>");iframeDoc.close()}elem=iframeDoc.body.appendChild(iframeDoc.createElement(nodeName));display=curCSS(elem,"display");document.body.removeChild(iframe)}elemdisplay[nodeName]=display;return display}jQuery.each(["height","width"],function(i,name){jQuery.cssHooks[name]={get:function(elem,computed,extra){if(computed){if(elem.offsetWidth===0&&rdisplayswap.test(curCSS(elem,"display"))){return jQuery.swap(elem,cssShow,function(){return getWidthOrHeight(elem,name,extra)})}else{return getWidthOrHeight(elem,name,extra)}}},set:function(elem,value,extra){return setPositiveNumber(elem,value,extra?augmentWidthOrHeight(elem,name,extra,jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing")==="border-box"):0)}}});if(!jQuery.support.opacity){jQuery.cssHooks.opacity={get:function(elem,computed){return ropacity.test((computed&&elem.currentStyle?elem.currentStyle.filter:elem.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":computed?"1":""},set:function(elem,value){var style=elem.style,currentStyle=elem.currentStyle,opacity=jQuery.isNumeric(value)?"alpha(opacity="+value*100+")":"",filter=currentStyle&¤tStyle.filter||style.filter||"";style.zoom=1;if(value>=1&&jQuery.trim(filter.replace(ralpha,""))===""&&style.removeAttribute){style.removeAttribute("filter");if(currentStyle&&!currentStyle.filter){return}}style.filter=ralpha.test(filter)?filter.replace(ralpha,opacity):filter+" "+opacity}}}jQuery(function(){if(!jQuery.support.reliableMarginRight){jQuery.cssHooks.marginRight={get:function(elem,computed){return jQuery.swap(elem,{display:"inline-block"},function(){if(computed){return curCSS(elem,"marginRight")}})}}}if(!jQuery.support.pixelPosition&&jQuery.fn.position){jQuery.each(["top","left"],function(i,prop){jQuery.cssHooks[prop]={get:function(elem,computed){if(computed){var ret=curCSS(elem,prop);return rnumnonpx.test(ret)?jQuery(elem).position()[prop]+"px":ret}}}})}});if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.hidden=function(elem){return elem.offsetWidth===0&&elem.offsetHeight===0||!jQuery.support.reliableHiddenOffsets&&(elem.style&&elem.style.display||curCSS(elem,"display"))==="none"};jQuery.expr.filters.visible=function(elem){return!jQuery.expr.filters.hidden(elem)}}jQuery.each({margin:"",padding:"",border:"Width"},function(prefix,suffix){jQuery.cssHooks[prefix+suffix]={expand:function(value){var i,parts=typeof value==="string"?value.split(" "):[value],expanded={};for(i=0;i<4;i++){expanded[prefix+cssExpand[i]+suffix]=parts[i]||parts[i-2]||parts[0]}return expanded}};if(!rmargin.test(prefix)){jQuery.cssHooks[prefix+suffix].set=setPositiveNumber}});var r20=/%20/g,rbracket=/\[\]$/,rCRLF=/\r?\n/g,rinput=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,rselectTextarea=/^(?:select|textarea)/i;jQuery.fn.extend({serialize:function(){return jQuery.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?jQuery.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||rselectTextarea.test(this.nodeName)||rinput.test(this.type))}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:jQuery.isArray(val)?jQuery.map(val,function(val,i){return{name:elem.name,value:val.replace(rCRLF,"\r\n")}}):{name:elem.name,value:val.replace(rCRLF,"\r\n")}}).get()}});jQuery.param=function(a,traditional){var prefix,s=[],add=function(key,value){value=jQuery.isFunction(value)?value():value==null?"":value;s[s.length]=encodeURIComponent(key)+"="+encodeURIComponent(value)};if(traditional===undefined){traditional=jQuery.ajaxSettings&&jQuery.ajaxSettings.traditional}if(jQuery.isArray(a)||a.jquery&&!jQuery.isPlainObject(a)){jQuery.each(a,function(){add(this.name,this.value)})}else{for(prefix in a){buildParams(prefix,a[prefix],traditional,add)}}return s.join("&").replace(r20,"+")};function buildParams(prefix,obj,traditional,add){var name;if(jQuery.isArray(obj)){jQuery.each(obj,function(i,v){if(traditional||rbracket.test(prefix)){add(prefix,v)}else{buildParams(prefix+"["+(typeof v==="object"?i:"")+"]",v,traditional,add)}})}else if(!traditional&&jQuery.type(obj)==="object"){for(name in obj){buildParams(prefix+"["+name+"]",obj[name],traditional,add)}}else{add(prefix,obj)}}var ajaxLocParts,ajaxLocation,rhash=/#.*$/,rheaders=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,rlocalProtocol=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,rnoContent=/^(?:GET|HEAD)$/,rprotocol=/^\/\//,rquery=/\?/,rscript=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,rts=/([?&])_=[^&]*/,rurl=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,_load=jQuery.fn.load,prefilters={},transports={},allTypes=["*/"]+["*"];try{ajaxLocation=location.href}catch(e){ajaxLocation=document.createElement("a");ajaxLocation.href="";ajaxLocation=ajaxLocation.href}ajaxLocParts=rurl.exec(ajaxLocation.toLowerCase())||[];function addToPrefiltersOrTransports(structure){return function(dataTypeExpression,func){if(typeof dataTypeExpression!=="string"){func=dataTypeExpression;dataTypeExpression="*"}var dataType,list,placeBefore,dataTypes=dataTypeExpression.toLowerCase().split(core_rspace),i=0,length=dataTypes.length;if(jQuery.isFunction(func)){for(;i<length;i++){dataType=dataTypes[i];placeBefore=/^\+/.test(dataType);if(placeBefore){dataType=dataType.substr(1)||"*"}list=structure[dataType]=structure[dataType]||[];list[placeBefore?"unshift":"push"](func)}}}}function inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,dataType,inspected){dataType=dataType||options.dataTypes[0];inspected=inspected||{};inspected[dataType]=true;var selection,list=structure[dataType],i=0,length=list?list.length:0,executeOnly=structure===prefilters;for(;i<length&&(executeOnly||!selection);i++){selection=list[i](options,originalOptions,jqXHR);if(typeof selection==="string"){if(!executeOnly||inspected[selection]){selection=undefined}else{options.dataTypes.unshift(selection);selection=inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,selection,inspected)}}}if((executeOnly||!selection)&&!inspected["*"]){selection=inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,"*",inspected)}return selection}function ajaxExtend(target,src){var key,deep,flatOptions=jQuery.ajaxSettings.flatOptions||{};for(key in src){if(src[key]!==undefined){(flatOptions[key]?target:deep||(deep={}))[key]=src[key]}}if(deep){jQuery.extend(true,target,deep)}}jQuery.fn.load=function(url,params,callback){if(typeof url!=="string"&&_load){return _load.apply(this,arguments)}if(!this.length){return this}var selector,type,response,self=this,off=url.indexOf(" ");if(off>=0){selector=url.slice(off,url.length);url=url.slice(0,off)}if(jQuery.isFunction(params)){callback=params;params=undefined}else if(params&&typeof params==="object"){type="POST"}jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(jqXHR,status){if(callback){self.each(callback,response||[jqXHR.responseText,status,jqXHR])}}}).done(function(responseText){response=arguments;self.html(selector?jQuery("<div>").append(responseText.replace(rscript,"")).find(selector):responseText)});return this};jQuery.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(i,o){jQuery.fn[o]=function(f){return this.on(o,f)}});jQuery.each(["get","post"],function(i,method){jQuery[method]=function(url,data,callback,type){if(jQuery.isFunction(data)){type=type||callback;callback=data;data=undefined}return jQuery.ajax({type:method,url:url,data:data,success:callback,dataType:type})}});jQuery.extend({getScript:function(url,callback){return jQuery.get(url,undefined,callback,"script")},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json")},ajaxSetup:function(target,settings){if(settings){ajaxExtend(target,jQuery.ajaxSettings)}else{settings=target;target=jQuery.ajaxSettings}ajaxExtend(target,settings);return target},ajaxSettings:{url:ajaxLocation,isLocal:rlocalProtocol.test(ajaxLocParts[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":allTypes},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":window.String,"text html":true,"text json":jQuery.parseJSON,"text xml":jQuery.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:addToPrefiltersOrTransports(prefilters),ajaxTransport:addToPrefiltersOrTransports(transports),ajax:function(url,options){if(typeof url==="object"){options=url;url=undefined}options=options||{};var ifModifiedKey,responseHeadersString,responseHeaders,transport,timeoutTimer,parts,fireGlobals,i,s=jQuery.ajaxSetup({},options),callbackContext=s.context||s,globalEventContext=callbackContext!==s&&(callbackContext.nodeType||callbackContext instanceof jQuery)?jQuery(callbackContext):jQuery.event,deferred=jQuery.Deferred(),completeDeferred=jQuery.Callbacks("once memory"),statusCode=s.statusCode||{},requestHeaders={},requestHeadersNames={},state=0,strAbort="canceled",jqXHR={readyState:0,setRequestHeader:function(name,value){if(!state){var lname=name.toLowerCase();name=requestHeadersNames[lname]=requestHeadersNames[lname]||name;requestHeaders[name]=value}return this},getAllResponseHeaders:function(){return state===2?responseHeadersString:null},getResponseHeader:function(key){var match;if(state===2){if(!responseHeaders){responseHeaders={};while(match=rheaders.exec(responseHeadersString)){responseHeaders[match[1].toLowerCase()]=match[2]}}match=responseHeaders[key.toLowerCase()]}return match===undefined?null:match},overrideMimeType:function(type){if(!state){s.mimeType=type}return this},abort:function(statusText){statusText=statusText||strAbort;if(transport){transport.abort(statusText)}done(0,statusText);return this}};function done(status,nativeStatusText,responses,headers){var isSuccess,success,error,response,modified,statusText=nativeStatusText;if(state===2){return}state=2;if(timeoutTimer){clearTimeout(timeoutTimer)}transport=undefined;responseHeadersString=headers||"";jqXHR.readyState=status>0?4:0;if(responses){response=ajaxHandleResponses(s,jqXHR,responses)}if(status>=200&&status<300||status===304){if(s.ifModified){modified=jqXHR.getResponseHeader("Last-Modified");if(modified){jQuery.lastModified[ifModifiedKey]=modified}modified=jqXHR.getResponseHeader("Etag");if(modified){jQuery.etag[ifModifiedKey]=modified}}if(status===304){statusText="notmodified";isSuccess=true}else{isSuccess=ajaxConvert(s,response);statusText=isSuccess.state;success=isSuccess.data;error=isSuccess.error;isSuccess=!error}}else{error=statusText;if(!statusText||status){statusText="error";if(status<0){status=0}}}jqXHR.status=status;jqXHR.statusText=(nativeStatusText||statusText)+"";if(isSuccess){deferred.resolveWith(callbackContext,[success,statusText,jqXHR])}else{deferred.rejectWith(callbackContext,[jqXHR,statusText,error])}jqXHR.statusCode(statusCode);statusCode=undefined;if(fireGlobals){globalEventContext.trigger("ajax"+(isSuccess?"Success":"Error"),[jqXHR,s,isSuccess?success:error])}completeDeferred.fireWith(callbackContext,[jqXHR,statusText]);if(fireGlobals){globalEventContext.trigger("ajaxComplete",[jqXHR,s]);if(!--jQuery.active){jQuery.event.trigger("ajaxStop")}}}deferred.promise(jqXHR);jqXHR.success=jqXHR.done;jqXHR.error=jqXHR.fail;jqXHR.complete=completeDeferred.add;jqXHR.statusCode=function(map){if(map){var tmp;if(state<2){for(tmp in map){statusCode[tmp]=[statusCode[tmp],map[tmp]]}}else{tmp=map[jqXHR.status];jqXHR.always(tmp)}}return this};s.url=((url||s.url)+"").replace(rhash,"").replace(rprotocol,ajaxLocParts[1]+"//");s.dataTypes=jQuery.trim(s.dataType||"*").toLowerCase().split(core_rspace);if(s.crossDomain==null){parts=rurl.exec(s.url.toLowerCase());s.crossDomain=!!(parts&&(parts[1]!==ajaxLocParts[1]||parts[2]!==ajaxLocParts[2]||(parts[3]||(parts[1]==="http:"?80:443))!=(ajaxLocParts[3]||(ajaxLocParts[1]==="http:"?80:443))))}if(s.data&&s.processData&&typeof s.data!=="string"){s.data=jQuery.param(s.data,s.traditional)}inspectPrefiltersOrTransports(prefilters,s,options,jqXHR);if(state===2){return jqXHR}fireGlobals=s.global;s.type=s.type.toUpperCase();s.hasContent=!rnoContent.test(s.type);if(fireGlobals&&jQuery.active++===0){jQuery.event.trigger("ajaxStart")}if(!s.hasContent){if(s.data){s.url+=(rquery.test(s.url)?"&":"?")+s.data;delete s.data}ifModifiedKey=s.url;if(s.cache===false){var ts=jQuery.now(),ret=s.url.replace(rts,"$1_="+ts);s.url=ret+(ret===s.url?(rquery.test(s.url)?"&":"?")+"_="+ts:"")}}if(s.data&&s.hasContent&&s.contentType!==false||options.contentType){jqXHR.setRequestHeader("Content-Type",s.contentType)}if(s.ifModified){ifModifiedKey=ifModifiedKey||s.url;if(jQuery.lastModified[ifModifiedKey]){jqXHR.setRequestHeader("If-Modified-Since",jQuery.lastModified[ifModifiedKey])}if(jQuery.etag[ifModifiedKey]){jqXHR.setRequestHeader("If-None-Match",jQuery.etag[ifModifiedKey])}}jqXHR.setRequestHeader("Accept",s.dataTypes[0]&&s.accepts[s.dataTypes[0]]?s.accepts[s.dataTypes[0]]+(s.dataTypes[0]!=="*"?", "+allTypes+"; q=0.01":""):s.accepts["*"]);for(i in s.headers){jqXHR.setRequestHeader(i,s.headers[i])}if(s.beforeSend&&(s.beforeSend.call(callbackContext,jqXHR,s)===false||state===2)){return jqXHR.abort()}strAbort="abort";for(i in{success:1,error:1,complete:1}){jqXHR[i](s[i])}transport=inspectPrefiltersOrTransports(transports,s,options,jqXHR);if(!transport){done(-1,"No Transport")}else{jqXHR.readyState=1;if(fireGlobals){globalEventContext.trigger("ajaxSend",[jqXHR,s])}if(s.async&&s.timeout>0){timeoutTimer=setTimeout(function(){jqXHR.abort("timeout")},s.timeout)}try{state=1;transport.send(requestHeaders,done)}catch(e){if(state<2){done(-1,e)}else{throw e}}}return jqXHR},active:0,lastModified:{},etag:{}});function ajaxHandleResponses(s,jqXHR,responses){var ct,type,finalDataType,firstDataType,contents=s.contents,dataTypes=s.dataTypes,responseFields=s.responseFields;for(type in responseFields){if(type in responses){jqXHR[responseFields[type]]=responses[type]}}while(dataTypes[0]==="*"){dataTypes.shift();if(ct===undefined){ct=s.mimeType||jqXHR.getResponseHeader("content-type")}}if(ct){for(type in contents){if(contents[type]&&contents[type].test(ct)){dataTypes.unshift(type);break}}}if(dataTypes[0]in responses){finalDataType=dataTypes[0]}else{for(type in responses){if(!dataTypes[0]||s.converters[type+" "+dataTypes[0]]){finalDataType=type;break}if(!firstDataType){firstDataType=type}}finalDataType=finalDataType||firstDataType}if(finalDataType){if(finalDataType!==dataTypes[0]){dataTypes.unshift(finalDataType)}return responses[finalDataType]}}function ajaxConvert(s,response){var conv,conv2,current,tmp,dataTypes=s.dataTypes.slice(),prev=dataTypes[0],converters={},i=0;if(s.dataFilter){response=s.dataFilter(response,s.dataType)}if(dataTypes[1]){for(conv in s.converters){converters[conv.toLowerCase()]=s.converters[conv]}}for(;current=dataTypes[++i];){if(current!=="*"){if(prev!=="*"&&prev!==current){conv=converters[prev+" "+current]||converters["* "+current];if(!conv){for(conv2 in converters){tmp=conv2.split(" ");if(tmp[1]===current){conv=converters[prev+" "+tmp[0]]||converters["* "+tmp[0]];if(conv){if(conv===true){conv=converters[conv2]}else if(converters[conv2]!==true){current=tmp[0];dataTypes.splice(i--,0,current)}break}}}}if(conv!==true){if(conv&&s["throws"]){response=conv(response)}else{try{response=conv(response)}catch(e){return{state:"parsererror",error:conv?e:"No conversion from "+prev+" to "+current}}}}}prev=current}}return{state:"success",data:response}}var oldCallbacks=[],rquestion=/\?/,rjsonp=/(=)\?(?=&|$)|\?\?/,nonce=jQuery.now();jQuery.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var callback=oldCallbacks.pop()||jQuery.expando+"_"+nonce++;this[callback]=true;return callback}});jQuery.ajaxPrefilter("json jsonp",function(s,originalSettings,jqXHR){var callbackName,overwritten,responseContainer,data=s.data,url=s.url,hasCallback=s.jsonp!==false,replaceInUrl=hasCallback&&rjsonp.test(url),replaceInData=hasCallback&&!replaceInUrl&&typeof data==="string"&&!(s.contentType||"").indexOf("application/x-www-form-urlencoded")&&rjsonp.test(data);if(s.dataTypes[0]==="jsonp"||replaceInUrl||replaceInData){callbackName=s.jsonpCallback=jQuery.isFunction(s.jsonpCallback)?s.jsonpCallback():s.jsonpCallback;overwritten=window[callbackName];if(replaceInUrl){s.url=url.replace(rjsonp,"$1"+callbackName)}else if(replaceInData){s.data=data.replace(rjsonp,"$1"+callbackName)}else if(hasCallback){s.url+=(rquestion.test(url)?"&":"?")+s.jsonp+"="+callbackName}s.converters["script json"]=function(){if(!responseContainer){jQuery.error(callbackName+" was not called")}return responseContainer[0]};s.dataTypes[0]="json";window[callbackName]=function(){responseContainer=arguments};jqXHR.always(function(){window[callbackName]=overwritten;if(s[callbackName]){s.jsonpCallback=originalSettings.jsonpCallback;oldCallbacks.push(callbackName)}if(responseContainer&&jQuery.isFunction(overwritten)){overwritten(responseContainer[0])}responseContainer=overwritten=undefined});return"script"}});jQuery.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(text){jQuery.globalEval(text);return text}}});jQuery.ajaxPrefilter("script",function(s){if(s.cache===undefined){s.cache=false}if(s.crossDomain){s.type="GET";s.global=false}});jQuery.ajaxTransport("script",function(s){if(s.crossDomain){var script,head=document.head||document.getElementsByTagName("head")[0]||document.documentElement;return{send:function(_,callback){script=document.createElement("script");script.async="async";if(s.scriptCharset){script.charset=s.scriptCharset}script.src=s.url;script.onload=script.onreadystatechange=function(_,isAbort){if(isAbort||!script.readyState||/loaded|complete/.test(script.readyState)){script.onload=script.onreadystatechange=null;if(head&&script.parentNode){head.removeChild(script)}script=undefined;if(!isAbort){callback(200,"success")}}};head.insertBefore(script,head.firstChild)},abort:function(){if(script){script.onload(0,1)}}}}});var xhrCallbacks,xhrOnUnloadAbort=window.ActiveXObject?function(){for(var key in xhrCallbacks){xhrCallbacks[key](0,1)}}:false,xhrId=0;function createStandardXHR(){try{return new window.XMLHttpRequest}catch(e){}}function createActiveXHR(){try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(e){}}jQuery.ajaxSettings.xhr=window.ActiveXObject?function(){return!this.isLocal&&createStandardXHR()||createActiveXHR()}:createStandardXHR;(function(xhr){jQuery.extend(jQuery.support,{ajax:!!xhr,cors:!!xhr&&"withCredentials"in xhr})})(jQuery.ajaxSettings.xhr());if(jQuery.support.ajax){jQuery.ajaxTransport(function(s){if(!s.crossDomain||jQuery.support.cors){var callback;return{send:function(headers,complete){var handle,i,xhr=s.xhr();if(s.username){xhr.open(s.type,s.url,s.async,s.username,s.password)}else{xhr.open(s.type,s.url,s.async)}if(s.xhrFields){for(i in s.xhrFields){xhr[i]=s.xhrFields[i]}}if(s.mimeType&&xhr.overrideMimeType){xhr.overrideMimeType(s.mimeType)}if(!s.crossDomain&&!headers["X-Requested-With"]){headers["X-Requested-With"]="XMLHttpRequest"}try{for(i in headers){xhr.setRequestHeader(i,headers[i])}}catch(_){}xhr.send(s.hasContent&&s.data||null);callback=function(_,isAbort){var status,statusText,responseHeaders,responses,xml;try{if(callback&&(isAbort||xhr.readyState===4)){callback=undefined;if(handle){xhr.onreadystatechange=jQuery.noop;if(xhrOnUnloadAbort){delete xhrCallbacks[handle]}}if(isAbort){if(xhr.readyState!==4){xhr.abort()}}else{status=xhr.status;responseHeaders=xhr.getAllResponseHeaders();responses={};xml=xhr.responseXML;if(xml&&xml.documentElement){responses.xml=xml}try{responses.text=xhr.responseText}catch(e){}try{statusText=xhr.statusText}catch(e){statusText=""}if(!status&&s.isLocal&&!s.crossDomain){status=responses.text?200:404}else if(status===1223){status=204}}}}catch(firefoxAccessException){if(!isAbort){complete(-1,firefoxAccessException)}}if(responses){complete(status,statusText,responses,responseHeaders)}};if(!s.async){callback()}else if(xhr.readyState===4){setTimeout(callback,0)}else{handle=++xhrId;if(xhrOnUnloadAbort){if(!xhrCallbacks){xhrCallbacks={};jQuery(window).unload(xhrOnUnloadAbort)}xhrCallbacks[handle]=callback}xhr.onreadystatechange=callback}},abort:function(){if(callback){callback(0,1)}}}}})}var fxNow,timerId,rfxtypes=/^(?:toggle|show|hide)$/,rfxnum=new RegExp("^(?:([-+])=|)("+core_pnum+")([a-z%]*)$","i"),rrun=/queueHooks$/,animationPrefilters=[defaultPrefilter],tweeners={"*":[function(prop,value){var end,unit,tween=this.createTween(prop,value),parts=rfxnum.exec(value),target=tween.cur(),start=+target||0,scale=1,maxIterations=20;if(parts){end=+parts[2];unit=parts[3]||(jQuery.cssNumber[prop]?"":"px");if(unit!=="px"&&start){start=jQuery.css(tween.elem,prop,true)||end||1;do{scale=scale||".5";start=start/scale;jQuery.style(tween.elem,prop,start+unit)}while(scale!==(scale=tween.cur()/target)&&scale!==1&&--maxIterations)}tween.unit=unit;tween.start=start;tween.end=parts[1]?start+(parts[1]+1)*end:end}return tween}]};function createFxNow(){setTimeout(function(){fxNow=undefined},0);return fxNow=jQuery.now()}function createTweens(animation,props){jQuery.each(props,function(prop,value){var collection=(tweeners[prop]||[]).concat(tweeners["*"]),index=0,length=collection.length;for(;index<length;index++){if(collection[index].call(animation,prop,value)){return}}})}function Animation(elem,properties,options){var result,index=0,tweenerIndex=0,length=animationPrefilters.length,deferred=jQuery.Deferred().always(function(){delete tick.elem}),tick=function(){var currentTime=fxNow||createFxNow(),remaining=Math.max(0,animation.startTime+animation.duration-currentTime),temp=remaining/animation.duration||0,percent=1-temp,index=0,length=animation.tweens.length; +for(;index<length;index++){animation.tweens[index].run(percent)}deferred.notifyWith(elem,[animation,percent,remaining]);if(percent<1&&length){return remaining}else{deferred.resolveWith(elem,[animation]);return false}},animation=deferred.promise({elem:elem,props:jQuery.extend({},properties),opts:jQuery.extend(true,{specialEasing:{}},options),originalProperties:properties,originalOptions:options,startTime:fxNow||createFxNow(),duration:options.duration,tweens:[],createTween:function(prop,end,easing){var tween=jQuery.Tween(elem,animation.opts,prop,end,animation.opts.specialEasing[prop]||animation.opts.easing);animation.tweens.push(tween);return tween},stop:function(gotoEnd){var index=0,length=gotoEnd?animation.tweens.length:0;for(;index<length;index++){animation.tweens[index].run(1)}if(gotoEnd){deferred.resolveWith(elem,[animation,gotoEnd])}else{deferred.rejectWith(elem,[animation,gotoEnd])}return this}}),props=animation.props;propFilter(props,animation.opts.specialEasing);for(;index<length;index++){result=animationPrefilters[index].call(animation,elem,props,animation.opts);if(result){return result}}createTweens(animation,props);if(jQuery.isFunction(animation.opts.start)){animation.opts.start.call(elem,animation)}jQuery.fx.timer(jQuery.extend(tick,{anim:animation,queue:animation.opts.queue,elem:elem}));return animation.progress(animation.opts.progress).done(animation.opts.done,animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always)}function propFilter(props,specialEasing){var index,name,easing,value,hooks;for(index in props){name=jQuery.camelCase(index);easing=specialEasing[name];value=props[index];if(jQuery.isArray(value)){easing=value[1];value=props[index]=value[0]}if(index!==name){props[name]=value;delete props[index]}hooks=jQuery.cssHooks[name];if(hooks&&"expand"in hooks){value=hooks.expand(value);delete props[name];for(index in value){if(!(index in props)){props[index]=value[index];specialEasing[index]=easing}}}else{specialEasing[name]=easing}}}jQuery.Animation=jQuery.extend(Animation,{tweener:function(props,callback){if(jQuery.isFunction(props)){callback=props;props=["*"]}else{props=props.split(" ")}var prop,index=0,length=props.length;for(;index<length;index++){prop=props[index];tweeners[prop]=tweeners[prop]||[];tweeners[prop].unshift(callback)}},prefilter:function(callback,prepend){if(prepend){animationPrefilters.unshift(callback)}else{animationPrefilters.push(callback)}}});function defaultPrefilter(elem,props,opts){var index,prop,value,length,dataShow,toggle,tween,hooks,oldfire,anim=this,style=elem.style,orig={},handled=[],hidden=elem.nodeType&&isHidden(elem);if(!opts.queue){hooks=jQuery._queueHooks(elem,"fx");if(hooks.unqueued==null){hooks.unqueued=0;oldfire=hooks.empty.fire;hooks.empty.fire=function(){if(!hooks.unqueued){oldfire()}}}hooks.unqueued++;anim.always(function(){anim.always(function(){hooks.unqueued--;if(!jQuery.queue(elem,"fx").length){hooks.empty.fire()}})})}if(elem.nodeType===1&&("height"in props||"width"in props)){opts.overflow=[style.overflow,style.overflowX,style.overflowY];if(jQuery.css(elem,"display")==="inline"&&jQuery.css(elem,"float")==="none"){if(!jQuery.support.inlineBlockNeedsLayout||css_defaultDisplay(elem.nodeName)==="inline"){style.display="inline-block"}else{style.zoom=1}}}if(opts.overflow){style.overflow="hidden";if(!jQuery.support.shrinkWrapBlocks){anim.done(function(){style.overflow=opts.overflow[0];style.overflowX=opts.overflow[1];style.overflowY=opts.overflow[2]})}}for(index in props){value=props[index];if(rfxtypes.exec(value)){delete props[index];toggle=toggle||value==="toggle";if(value===(hidden?"hide":"show")){continue}handled.push(index)}}length=handled.length;if(length){dataShow=jQuery._data(elem,"fxshow")||jQuery._data(elem,"fxshow",{});if("hidden"in dataShow){hidden=dataShow.hidden}if(toggle){dataShow.hidden=!hidden}if(hidden){jQuery(elem).show()}else{anim.done(function(){jQuery(elem).hide()})}anim.done(function(){var prop;jQuery.removeData(elem,"fxshow",true);for(prop in orig){jQuery.style(elem,prop,orig[prop])}});for(index=0;index<length;index++){prop=handled[index];tween=anim.createTween(prop,hidden?dataShow[prop]:0);orig[prop]=dataShow[prop]||jQuery.style(elem,prop);if(!(prop in dataShow)){dataShow[prop]=tween.start;if(hidden){tween.end=tween.start;tween.start=prop==="width"||prop==="height"?1:0}}}}}function Tween(elem,options,prop,end,easing){return new Tween.prototype.init(elem,options,prop,end,easing)}jQuery.Tween=Tween;Tween.prototype={constructor:Tween,init:function(elem,options,prop,end,easing,unit){this.elem=elem;this.prop=prop;this.easing=easing||"swing";this.options=options;this.start=this.now=this.cur();this.end=end;this.unit=unit||(jQuery.cssNumber[prop]?"":"px")},cur:function(){var hooks=Tween.propHooks[this.prop];return hooks&&hooks.get?hooks.get(this):Tween.propHooks._default.get(this)},run:function(percent){var eased,hooks=Tween.propHooks[this.prop];if(this.options.duration){this.pos=eased=jQuery.easing[this.easing](percent,this.options.duration*percent,0,1,this.options.duration)}else{this.pos=eased=percent}this.now=(this.end-this.start)*eased+this.start;if(this.options.step){this.options.step.call(this.elem,this.now,this)}if(hooks&&hooks.set){hooks.set(this)}else{Tween.propHooks._default.set(this)}return this}};Tween.prototype.init.prototype=Tween.prototype;Tween.propHooks={_default:{get:function(tween){var result;if(tween.elem[tween.prop]!=null&&(!tween.elem.style||tween.elem.style[tween.prop]==null)){return tween.elem[tween.prop]}result=jQuery.css(tween.elem,tween.prop,false,"");return!result||result==="auto"?0:result},set:function(tween){if(jQuery.fx.step[tween.prop]){jQuery.fx.step[tween.prop](tween)}else if(tween.elem.style&&(tween.elem.style[jQuery.cssProps[tween.prop]]!=null||jQuery.cssHooks[tween.prop])){jQuery.style(tween.elem,tween.prop,tween.now+tween.unit)}else{tween.elem[tween.prop]=tween.now}}}};Tween.propHooks.scrollTop=Tween.propHooks.scrollLeft={set:function(tween){if(tween.elem.nodeType&&tween.elem.parentNode){tween.elem[tween.prop]=tween.now}}};jQuery.each(["toggle","show","hide"],function(i,name){var cssFn=jQuery.fn[name];jQuery.fn[name]=function(speed,easing,callback){return speed==null||typeof speed==="boolean"||!i&&jQuery.isFunction(speed)&&jQuery.isFunction(easing)?cssFn.apply(this,arguments):this.animate(genFx(name,true),speed,easing,callback)}});jQuery.fn.extend({fadeTo:function(speed,to,easing,callback){return this.filter(isHidden).css("opacity",0).show().end().animate({opacity:to},speed,easing,callback)},animate:function(prop,speed,easing,callback){var empty=jQuery.isEmptyObject(prop),optall=jQuery.speed(speed,easing,callback),doAnimation=function(){var anim=Animation(this,jQuery.extend({},prop),optall);if(empty){anim.stop(true)}};return empty||optall.queue===false?this.each(doAnimation):this.queue(optall.queue,doAnimation)},stop:function(type,clearQueue,gotoEnd){var stopQueue=function(hooks){var stop=hooks.stop;delete hooks.stop;stop(gotoEnd)};if(typeof type!=="string"){gotoEnd=clearQueue;clearQueue=type;type=undefined}if(clearQueue&&type!==false){this.queue(type||"fx",[])}return this.each(function(){var dequeue=true,index=type!=null&&type+"queueHooks",timers=jQuery.timers,data=jQuery._data(this);if(index){if(data[index]&&data[index].stop){stopQueue(data[index])}}else{for(index in data){if(data[index]&&data[index].stop&&rrun.test(index)){stopQueue(data[index])}}}for(index=timers.length;index--;){if(timers[index].elem===this&&(type==null||timers[index].queue===type)){timers[index].anim.stop(gotoEnd);dequeue=false;timers.splice(index,1)}}if(dequeue||!gotoEnd){jQuery.dequeue(this,type)}})}});function genFx(type,includeWidth){var which,attrs={height:type},i=0;includeWidth=includeWidth?1:0;for(;i<4;i+=2-includeWidth){which=cssExpand[i];attrs["margin"+which]=attrs["padding"+which]=type}if(includeWidth){attrs.opacity=attrs.width=type}return attrs}jQuery.each({slideDown:genFx("show"),slideUp:genFx("hide"),slideToggle:genFx("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(name,props){jQuery.fn[name]=function(speed,easing,callback){return this.animate(props,speed,easing,callback)}});jQuery.speed=function(speed,easing,fn){var opt=speed&&typeof speed==="object"?jQuery.extend({},speed):{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&!jQuery.isFunction(easing)&&easing};opt.duration=jQuery.fx.off?0:typeof opt.duration==="number"?opt.duration:opt.duration in jQuery.fx.speeds?jQuery.fx.speeds[opt.duration]:jQuery.fx.speeds._default;if(opt.queue==null||opt.queue===true){opt.queue="fx"}opt.old=opt.complete;opt.complete=function(){if(jQuery.isFunction(opt.old)){opt.old.call(this)}if(opt.queue){jQuery.dequeue(this,opt.queue)}};return opt};jQuery.easing={linear:function(p){return p},swing:function(p){return.5-Math.cos(p*Math.PI)/2}};jQuery.timers=[];jQuery.fx=Tween.prototype.init;jQuery.fx.tick=function(){var timer,timers=jQuery.timers,i=0;fxNow=jQuery.now();for(;i<timers.length;i++){timer=timers[i];if(!timer()&&timers[i]===timer){timers.splice(i--,1)}}if(!timers.length){jQuery.fx.stop()}fxNow=undefined};jQuery.fx.timer=function(timer){if(timer()&&jQuery.timers.push(timer)&&!timerId){timerId=setInterval(jQuery.fx.tick,jQuery.fx.interval)}};jQuery.fx.interval=13;jQuery.fx.stop=function(){clearInterval(timerId);timerId=null};jQuery.fx.speeds={slow:600,fast:200,_default:400};jQuery.fx.step={};if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.animated=function(elem){return jQuery.grep(jQuery.timers,function(fn){return elem===fn.elem}).length}}var rroot=/^(?:body|html)$/i;jQuery.fn.offset=function(options){if(arguments.length){return options===undefined?this:this.each(function(i){jQuery.offset.setOffset(this,options,i)})}var docElem,body,win,clientTop,clientLeft,scrollTop,scrollLeft,box={top:0,left:0},elem=this[0],doc=elem&&elem.ownerDocument;if(!doc){return}if((body=doc.body)===elem){return jQuery.offset.bodyOffset(elem)}docElem=doc.documentElement;if(!jQuery.contains(docElem,elem)){return box}if(typeof elem.getBoundingClientRect!=="undefined"){box=elem.getBoundingClientRect()}win=getWindow(doc);clientTop=docElem.clientTop||body.clientTop||0;clientLeft=docElem.clientLeft||body.clientLeft||0;scrollTop=win.pageYOffset||docElem.scrollTop;scrollLeft=win.pageXOffset||docElem.scrollLeft;return{top:box.top+scrollTop-clientTop,left:box.left+scrollLeft-clientLeft}};jQuery.offset={bodyOffset:function(body){var top=body.offsetTop,left=body.offsetLeft;if(jQuery.support.doesNotIncludeMarginInBodyOffset){top+=parseFloat(jQuery.css(body,"marginTop"))||0;left+=parseFloat(jQuery.css(body,"marginLeft"))||0}return{top:top,left:left}},setOffset:function(elem,options,i){var position=jQuery.css(elem,"position");if(position==="static"){elem.style.position="relative"}var curElem=jQuery(elem),curOffset=curElem.offset(),curCSSTop=jQuery.css(elem,"top"),curCSSLeft=jQuery.css(elem,"left"),calculatePosition=(position==="absolute"||position==="fixed")&&jQuery.inArray("auto",[curCSSTop,curCSSLeft])>-1,props={},curPosition={},curTop,curLeft;if(calculatePosition){curPosition=curElem.position();curTop=curPosition.top;curLeft=curPosition.left}else{curTop=parseFloat(curCSSTop)||0;curLeft=parseFloat(curCSSLeft)||0}if(jQuery.isFunction(options)){options=options.call(elem,i,curOffset)}if(options.top!=null){props.top=options.top-curOffset.top+curTop}if(options.left!=null){props.left=options.left-curOffset.left+curLeft}if("using"in options){options.using.call(elem,props)}else{curElem.css(props)}}};jQuery.fn.extend({position:function(){if(!this[0]){return}var elem=this[0],offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=rroot.test(offsetParent[0].nodeName)?{top:0,left:0}:offsetParent.offset();offset.top-=parseFloat(jQuery.css(elem,"marginTop"))||0;offset.left-=parseFloat(jQuery.css(elem,"marginLeft"))||0;parentOffset.top+=parseFloat(jQuery.css(offsetParent[0],"borderTopWidth"))||0;parentOffset.left+=parseFloat(jQuery.css(offsetParent[0],"borderLeftWidth"))||0;return{top:offset.top-parentOffset.top,left:offset.left-parentOffset.left}},offsetParent:function(){return this.map(function(){var offsetParent=this.offsetParent||document.body;while(offsetParent&&(!rroot.test(offsetParent.nodeName)&&jQuery.css(offsetParent,"position")==="static")){offsetParent=offsetParent.offsetParent}return offsetParent||document.body})}});jQuery.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(method,prop){var top=/Y/.test(prop);jQuery.fn[method]=function(val){return jQuery.access(this,function(elem,method,val){var win=getWindow(elem);if(val===undefined){return win?prop in win?win[prop]:win.document.documentElement[method]:elem[method]}if(win){win.scrollTo(!top?val:jQuery(win).scrollLeft(),top?val:jQuery(win).scrollTop())}else{elem[method]=val}},method,val,arguments.length,null)}});function getWindow(elem){return jQuery.isWindow(elem)?elem:elem.nodeType===9?elem.defaultView||elem.parentWindow:false}jQuery.each({Height:"height",Width:"width"},function(name,type){jQuery.each({padding:"inner"+name,content:type,"":"outer"+name},function(defaultExtra,funcName){jQuery.fn[funcName]=function(margin,value){var chainable=arguments.length&&(defaultExtra||typeof margin!=="boolean"),extra=defaultExtra||(margin===true||value===true?"margin":"border");return jQuery.access(this,function(elem,type,value){var doc;if(jQuery.isWindow(elem)){return elem.document.documentElement["client"+name]}if(elem.nodeType===9){doc=elem.documentElement;return Math.max(elem.body["scroll"+name],doc["scroll"+name],elem.body["offset"+name],doc["offset"+name],doc["client"+name])}return value===undefined?jQuery.css(elem,type,value,extra):jQuery.style(elem,type,value,extra)},type,chainable?margin:undefined,chainable,null)}})});window.jQuery=window.$=jQuery;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return jQuery})}})(window);
\ No newline at end of file diff --git a/ydb/library/schlab/mon/static/js/scharm-test0.js b/ydb/library/schlab/mon/static/js/scharm-test0.js index 7d543b63c1..ad41a4c446 100644 --- a/ydb/library/schlab/mon/static/js/scharm-test0.js +++ b/ydb/library/schlab/mon/static/js/scharm-test0.js @@ -1,29 +1,29 @@ -var cfg = [{ - "label": "mygen1", - "startTime": 0, +var cfg = [{ + "label": "mygen1", + "startTime": 0, "period": 50, - "periodCount": 0, + "periodCount": 0, "reqSizeBytes": 1000000, "reqCount": 1, "reqInterval": 1, - "user": "vdisk0", - "desc": "write-log" -},{ - "label": "mygen2", + "user": "vdisk0", + "desc": "write-log" +},{ + "label": "mygen2", "startTime": 0, "period": 50, "periodCount": 0, "reqSizeBytes": 1000000, - "reqCount": 5, + "reqCount": 5, "reqInterval": 1, - "user": "vdisk1", - "desc": "write-chunk" -}]; - -var scharm = d3.scharm().height(350).width(800); - -scharm.tableSelector('#cfg-table'); -scharm.chartSelector('#cfg-chart'); -scharm.applyUrl('?mode=setconfig'); -scharm.timeDomain([0, 1000]); -scharm(cfg); + "user": "vdisk1", + "desc": "write-chunk" +}]; + +var scharm = d3.scharm().height(350).width(800); + +scharm.tableSelector('#cfg-table'); +scharm.chartSelector('#cfg-chart'); +scharm.applyUrl('?mode=setconfig'); +scharm.timeDomain([0, 1000]); +scharm(cfg); diff --git a/ydb/library/schlab/mon/static/js/scharm.js b/ydb/library/schlab/mon/static/js/scharm.js index ae5911a1c6..b15be1bd2e 100644 --- a/ydb/library/schlab/mon/static/js/scharm.js +++ b/ydb/library/schlab/mon/static/js/scharm.js @@ -1,497 +1,497 @@ -d3.scharm = function() { - // main scharm object - function scharm(newCfg) { - createAll(); - - // configure stuff using given config - cfg = newCfg; - - var data = []; - for (var i = 0; i < cfg.length; i++) { - var row = []; - for (var a = 0; a < attributes.length; a++) { - if (attributes[a].type) { - row.push(cfg[i][attributes[a].name]); - } else { - row.push(i); // save row index for remove operation - } - } - data.push(row); - } - - var tr = table.select("tbody").selectAll("tr.scharm-table-row") - .data(data) - ; - tr.exit().remove(); - var trEnterUpd = tr.enter().append("tr") - .attr("class", "scharm-table-row") - .merge(tr) // enter + update - ; - - var td = trEnterUpd.selectAll("td") - .data(function(d) { return d; }) - ; - td.enter().append("td") - .merge(td) // enter + update - .attr("contenteditable", function(d, i) { return attributes[i].type? "true": null; }) - .text(function(d, i) { return attributes[i].type? d: null; }) - .on('keypress', onKeyPress) - .attr("class", function(d, i) { - return "scharm-cell scharm-cell-" + - (attributes[i].type? attributes[i].type: attributes[i].class) - ; - }) - ; - - table.select("tbody").selectAll("td.scharm-cell-btn-remove") - .each(function(d, i) { - d3.select(this) - .html("") // clear - .append("button") - .html("×") - .attr("type", "button") - .attr("class", "btn btn-default btn-xs") - .on("click", function() { - scharm.removeRow(d); - }) - ; - //d3.select(this).html('<button class="btn btn-default btn-xs">×</button>'); - }) - ; - - drawSeries(); - - return scharm; - } - - // private: - - var dataToCfg = function() { - var curCfg = []; - table.select("tbody").selectAll("tr.scharm-table-row") - .each(function() { - var row = {}; - d3.select(this).selectAll("td") - .each(function(d, i) { - if (attributes[i].type) { - if (isNumberType(attributes[i].type)) { - row[attributes[i].name] = +this.textContent; - } else { - row[attributes[i].name] = this.textContent; - } - } - }) - ; - curCfg.push(row); - }) - ; - return curCfg; - } - - var createAll = function() { - if (table) { - return; // ensure to create once - } - - // create empty generators table - table = d3.select(tableSelector).append("table") - .attr("class", "table scharm-table") - ; - - table.append("thead").append("tr").attr("class", "scharm-table-head") - .selectAll("td") - .data(attributes) - .enter().append("th") - .text(function(d) { return d.name; }) - ; - - table.append("tbody"); - - // initialize modal dialog for raw editing - $('#RawModal').on('shown.bs.modal', function (e) { - scharm(dataToCfg()); - $('#cfg-text').val(JSON.stringify(cfg, null, " ")); - }); - $('#cfg-save').on('click', function (e) { - $('#RawModal').modal('hide'); - var newCfg = JSON.parse($('#cfg-text').val()); - scharm(newCfg); - }); - - // initialize throughput editor - d3.select("input#throughput").on('keypress', onKeyPress); - - // init axis - x = d3.scaleLinear() - .domain([timeDomainStartMs, timeDomainEndMs]) - .range([0, width]); - //.clamp(true); // dosn't work with zoom/pan - xZoomed = x; - y = d3.scaleLinear() - .domain([bytesDomainMax, 0]) - .range([0, height - margin.top - margin.bottom]); - xAxis = d3.axisBottom() - .scale(x) - //.tickSubdivide(true) - .tickSize(8) - .tickPadding(8); - yAxis = d3.axisLeft() - .scale(y) - .tickSize(8) - .tickPadding(8); - - // create svg element - svg = d3.select(chartSelector) - .append("svg") - .attr("class", "chart") - .attr("width", width + margin.left + margin.right) - .attr("height",height + margin.top + margin.bottom) - ; - - // disable default page scrolling with mouse wheel - // because wheel is used for zooming - //window.onwheel = function(){ return false; } - - zoom = d3.zoom() - .scaleExtent([1/10, 100]) - //.translateExtent([0, 0], [1000,0]) - .on("zoom", function() { - var tr = d3.event.transform; - xZoomed = tr.rescaleX(x); - svg.select("g.x.axis").call(xAxis.scale(xZoomed)); - - zoomContainer1.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); - zoomContainer2.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); - - drawSeries(); - - //tr(x); - }) - ; - - svgChartContainer = svg.append('g') - .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") - ; - svgChart = svgChartContainer.append("svg") - .attr("top", 0) - .attr("left", 0) - .attr("width", width) - .attr("height", height) - .attr("viewBox", "0 0 " + width + " " + height) - ; - - zoomContainer1 = svgChart.append("g") - .attr("width", width) - .attr("height", height) - ; - - zoomPanel = svgChart.append("rect") - .attr("class", "zoom-panel") - .attr("width", width) - .attr("height", height) - .call(zoom) - ; - - zoomContainer2 = svgChart.append("g") - .attr("width", width) - .attr("height", height) - ; - - // draw chart - seriesSvg = zoomContainer1.append("g") - .attr("class", "gantt-chart") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - ; - seriesSvg.append("path"); - - // container for non-zoomable elements - fixedContainer = svg.append("g") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") - ; - - // create x axis - fixedContainer.append("g") - .attr("class", "x axis") - .attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")") - .call(xAxis) - .append("text") - .attr("fill", "#000") - .attr("transform", "translate(0,10)") - .attr("x", width / 2) - .attr("y", 32) - .attr("dy", "0.71em") - .attr("text-anchor", "middle") - .text("time (ms)"); - ; - - // create y axis - fixedContainer.append("g") - .attr("class", "y axis") - .call(yAxis) - .append("text") - .attr("fill", "#000") - .attr("y", -14) - .attr("x", 10) - .attr("dy", "0.71em") - .attr("text-anchor", "end") - .text("queue size (bytes)"); - ; - - // right margin - var rmargin = fixedContainer.append("g") - .attr("id", "right-margin") - .attr("transform", "translate(" + width + ", 0)") - ; - rmargin.append("rect") - .attr("x", 0) - .attr("y", 0) - .attr("width", 1) - .attr("height", height - margin.top - margin.bottom) - ; - - // top margin - var tmargin = fixedContainer.append("g") - .attr("id", "top-margin") - .attr("transform", "translate(0, 0)") - ; - tmargin.append("rect") - .attr("x", 0) - .attr("y", 0) - .attr("width", width) - .attr("height", 1) - ; - - } - - var drawSeries = function() { - // generate series data - var seriesEvents = []; - var tLeft = xZoomed.invert(0); - var tRight = xZoomed.invert(width); - for (var i = 0; i < cfg.length; i++) { - var gen = cfg[i]; - var period2 = Math.ceil((tRight - gen.startTime * timeUnit) / (gen.period * timeUnit)) + 1; - var pe = Math.min(period2, - gen.periodCount? gen.periodCount: period2); - for (var p = 0; p < pe; p++) { - for (var j = 0; j < gen.reqCount; j++) { - var t = gen.startTime * timeUnit - + p * gen.period * timeUnit - + j * gen.reqInterval * timeUnit; - var item = [t, gen]; - seriesEvents.push(item); - } - } - } - seriesEvents.sort(function(a, b) { - return a[0] - b[0]; - }); - - var seriesData = []; - var throughput = $("input#throughput").val() * 1024 * 1024 / 1000; - var t = 0; - var queueBytes = 0; - var queueBytesMax = 0; - - var lastPoint = null; - function addPoint(x, y) { - if (x >= tLeft) { - if (seriesData.length == 0 && lastPoint != null) { - seriesData.push(lastPoint); - } - seriesData.push([x, y]); - } else { - lastPoint = [x, y]; - } - } - - for (var i = 0; i < seriesEvents.length; i++) { - var e = seriesEvents[i]; - - var t0 = t + queueBytes / throughput; - var t1 = e[0]; - if (t0 < t1) { - queueBytes = 0; - t = t0; - addPoint(t, queueBytes); - } - - var dt = t1 - t; - queueBytes = Math.max(0, queueBytes - throughput * dt); - t = t1; - addPoint(t, queueBytes); - - queueBytes += e[1].reqSizeBytes; - addPoint(t, queueBytes); - - if (t > tLeft && queueBytesMax < queueBytes) { - queueBytesMax = queueBytes; - } - } - - // add final point with zero bytes queued - if (queueBytes > 0) { - var t0 = t + queueBytes / throughput; - queueBytes = 0; - t = t0; - addPoint(t, queueBytes); - } - - // update y scale - y.domain([queueBytesMax? queueBytesMax: bytesDomainMax, 0]); - svg.select("g.y.axis").call(yAxis); - - var area = d3.area() - .x(function(d) { return x(d[0]); }) - .y1(function(d) { return y(d[1]); }) - .y0(y(0)); - - seriesSvg.select("path") - .datum(seriesData) - .attr("fill", "steelblue") - .attr("d", area); - } - - var onKeyPress = function() { - if (d3.event.keyCode == 13) { - d3.event.preventDefault(); - scharm(dataToCfg()); - } - } - - // public: - - scharm.margin = function(value) { - if (!arguments.length) - return margin; - margin = value; - return scharm; - } - - scharm.timeDomain = function(value) { - if (!arguments.length) - return [timeDomainStartMs, timeDomainEndMs]; - timeDomainStartMs = value[0]; - timeDomainEndMs = value[1]; - return scharm; - } - - scharm.width = function(value) { - if (!arguments.length) - return width; - width = +value; - return scharm; - } - - scharm.height = function(value) { - if (!arguments.length) - return height; - height = +value; - return scharm; - } - - scharm.tableSelector = function(value) { - if (!arguments.length) - return tableSelector; - tableSelector = value; - return scharm; - } - - scharm.chartSelector = function(value) { - if (!arguments.length) - return chartSelector; - chartSelector = value; - return scharm; - } - - scharm.applyUrl = function(value) { - if (!arguments.length) - return applyUrl; - applyUrl = value; - return scharm; - } - - scharm.addRow = function() { - var newCfg = dataToCfg(); - var row = new Object(emptyRow); - row.label = "gen" + newCfg.length; - newCfg.push(row); - scharm(newCfg); - } - - scharm.removeRow = function(i) { - var newCfg = dataToCfg(); - newCfg.splice(i, 1); - scharm(newCfg); - } - - // should be called to regenerate chart on buttons clicks/etc - scharm.draw = function() { - scharm(dataToCfg()); - } - - // should be called to POST current config - scharm.sendCfg = function(callback) { - scharm(dataToCfg()); - d3.json(applyUrl, callback).post(JSON.stringify(cfg)); - } +d3.scharm = function() { + // main scharm object + function scharm(newCfg) { + createAll(); + + // configure stuff using given config + cfg = newCfg; + + var data = []; + for (var i = 0; i < cfg.length; i++) { + var row = []; + for (var a = 0; a < attributes.length; a++) { + if (attributes[a].type) { + row.push(cfg[i][attributes[a].name]); + } else { + row.push(i); // save row index for remove operation + } + } + data.push(row); + } + + var tr = table.select("tbody").selectAll("tr.scharm-table-row") + .data(data) + ; + tr.exit().remove(); + var trEnterUpd = tr.enter().append("tr") + .attr("class", "scharm-table-row") + .merge(tr) // enter + update + ; + + var td = trEnterUpd.selectAll("td") + .data(function(d) { return d; }) + ; + td.enter().append("td") + .merge(td) // enter + update + .attr("contenteditable", function(d, i) { return attributes[i].type? "true": null; }) + .text(function(d, i) { return attributes[i].type? d: null; }) + .on('keypress', onKeyPress) + .attr("class", function(d, i) { + return "scharm-cell scharm-cell-" + + (attributes[i].type? attributes[i].type: attributes[i].class) + ; + }) + ; + + table.select("tbody").selectAll("td.scharm-cell-btn-remove") + .each(function(d, i) { + d3.select(this) + .html("") // clear + .append("button") + .html("×") + .attr("type", "button") + .attr("class", "btn btn-default btn-xs") + .on("click", function() { + scharm.removeRow(d); + }) + ; + //d3.select(this).html('<button class="btn btn-default btn-xs">×</button>'); + }) + ; + + drawSeries(); + + return scharm; + } + + // private: + + var dataToCfg = function() { + var curCfg = []; + table.select("tbody").selectAll("tr.scharm-table-row") + .each(function() { + var row = {}; + d3.select(this).selectAll("td") + .each(function(d, i) { + if (attributes[i].type) { + if (isNumberType(attributes[i].type)) { + row[attributes[i].name] = +this.textContent; + } else { + row[attributes[i].name] = this.textContent; + } + } + }) + ; + curCfg.push(row); + }) + ; + return curCfg; + } + + var createAll = function() { + if (table) { + return; // ensure to create once + } + + // create empty generators table + table = d3.select(tableSelector).append("table") + .attr("class", "table scharm-table") + ; + + table.append("thead").append("tr").attr("class", "scharm-table-head") + .selectAll("td") + .data(attributes) + .enter().append("th") + .text(function(d) { return d.name; }) + ; + + table.append("tbody"); + + // initialize modal dialog for raw editing + $('#RawModal').on('shown.bs.modal', function (e) { + scharm(dataToCfg()); + $('#cfg-text').val(JSON.stringify(cfg, null, " ")); + }); + $('#cfg-save').on('click', function (e) { + $('#RawModal').modal('hide'); + var newCfg = JSON.parse($('#cfg-text').val()); + scharm(newCfg); + }); + + // initialize throughput editor + d3.select("input#throughput").on('keypress', onKeyPress); + + // init axis + x = d3.scaleLinear() + .domain([timeDomainStartMs, timeDomainEndMs]) + .range([0, width]); + //.clamp(true); // dosn't work with zoom/pan + xZoomed = x; + y = d3.scaleLinear() + .domain([bytesDomainMax, 0]) + .range([0, height - margin.top - margin.bottom]); + xAxis = d3.axisBottom() + .scale(x) + //.tickSubdivide(true) + .tickSize(8) + .tickPadding(8); + yAxis = d3.axisLeft() + .scale(y) + .tickSize(8) + .tickPadding(8); + + // create svg element + svg = d3.select(chartSelector) + .append("svg") + .attr("class", "chart") + .attr("width", width + margin.left + margin.right) + .attr("height",height + margin.top + margin.bottom) + ; + + // disable default page scrolling with mouse wheel + // because wheel is used for zooming + //window.onwheel = function(){ return false; } + + zoom = d3.zoom() + .scaleExtent([1/10, 100]) + //.translateExtent([0, 0], [1000,0]) + .on("zoom", function() { + var tr = d3.event.transform; + xZoomed = tr.rescaleX(x); + svg.select("g.x.axis").call(xAxis.scale(xZoomed)); + + zoomContainer1.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); + zoomContainer2.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); + + drawSeries(); + + //tr(x); + }) + ; + + svgChartContainer = svg.append('g') + .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") + ; + svgChart = svgChartContainer.append("svg") + .attr("top", 0) + .attr("left", 0) + .attr("width", width) + .attr("height", height) + .attr("viewBox", "0 0 " + width + " " + height) + ; + + zoomContainer1 = svgChart.append("g") + .attr("width", width) + .attr("height", height) + ; + + zoomPanel = svgChart.append("rect") + .attr("class", "zoom-panel") + .attr("width", width) + .attr("height", height) + .call(zoom) + ; + + zoomContainer2 = svgChart.append("g") + .attr("width", width) + .attr("height", height) + ; + + // draw chart + seriesSvg = zoomContainer1.append("g") + .attr("class", "gantt-chart") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + ; + seriesSvg.append("path"); + + // container for non-zoomable elements + fixedContainer = svg.append("g") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") + ; + + // create x axis + fixedContainer.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")") + .call(xAxis) + .append("text") + .attr("fill", "#000") + .attr("transform", "translate(0,10)") + .attr("x", width / 2) + .attr("y", 32) + .attr("dy", "0.71em") + .attr("text-anchor", "middle") + .text("time (ms)"); + ; + + // create y axis + fixedContainer.append("g") + .attr("class", "y axis") + .call(yAxis) + .append("text") + .attr("fill", "#000") + .attr("y", -14) + .attr("x", 10) + .attr("dy", "0.71em") + .attr("text-anchor", "end") + .text("queue size (bytes)"); + ; + + // right margin + var rmargin = fixedContainer.append("g") + .attr("id", "right-margin") + .attr("transform", "translate(" + width + ", 0)") + ; + rmargin.append("rect") + .attr("x", 0) + .attr("y", 0) + .attr("width", 1) + .attr("height", height - margin.top - margin.bottom) + ; + + // top margin + var tmargin = fixedContainer.append("g") + .attr("id", "top-margin") + .attr("transform", "translate(0, 0)") + ; + tmargin.append("rect") + .attr("x", 0) + .attr("y", 0) + .attr("width", width) + .attr("height", 1) + ; + + } + + var drawSeries = function() { + // generate series data + var seriesEvents = []; + var tLeft = xZoomed.invert(0); + var tRight = xZoomed.invert(width); + for (var i = 0; i < cfg.length; i++) { + var gen = cfg[i]; + var period2 = Math.ceil((tRight - gen.startTime * timeUnit) / (gen.period * timeUnit)) + 1; + var pe = Math.min(period2, + gen.periodCount? gen.periodCount: period2); + for (var p = 0; p < pe; p++) { + for (var j = 0; j < gen.reqCount; j++) { + var t = gen.startTime * timeUnit + + p * gen.period * timeUnit + + j * gen.reqInterval * timeUnit; + var item = [t, gen]; + seriesEvents.push(item); + } + } + } + seriesEvents.sort(function(a, b) { + return a[0] - b[0]; + }); + + var seriesData = []; + var throughput = $("input#throughput").val() * 1024 * 1024 / 1000; + var t = 0; + var queueBytes = 0; + var queueBytesMax = 0; + + var lastPoint = null; + function addPoint(x, y) { + if (x >= tLeft) { + if (seriesData.length == 0 && lastPoint != null) { + seriesData.push(lastPoint); + } + seriesData.push([x, y]); + } else { + lastPoint = [x, y]; + } + } + + for (var i = 0; i < seriesEvents.length; i++) { + var e = seriesEvents[i]; + + var t0 = t + queueBytes / throughput; + var t1 = e[0]; + if (t0 < t1) { + queueBytes = 0; + t = t0; + addPoint(t, queueBytes); + } + + var dt = t1 - t; + queueBytes = Math.max(0, queueBytes - throughput * dt); + t = t1; + addPoint(t, queueBytes); + + queueBytes += e[1].reqSizeBytes; + addPoint(t, queueBytes); + + if (t > tLeft && queueBytesMax < queueBytes) { + queueBytesMax = queueBytes; + } + } + + // add final point with zero bytes queued + if (queueBytes > 0) { + var t0 = t + queueBytes / throughput; + queueBytes = 0; + t = t0; + addPoint(t, queueBytes); + } + + // update y scale + y.domain([queueBytesMax? queueBytesMax: bytesDomainMax, 0]); + svg.select("g.y.axis").call(yAxis); + + var area = d3.area() + .x(function(d) { return x(d[0]); }) + .y1(function(d) { return y(d[1]); }) + .y0(y(0)); + + seriesSvg.select("path") + .datum(seriesData) + .attr("fill", "steelblue") + .attr("d", area); + } + + var onKeyPress = function() { + if (d3.event.keyCode == 13) { + d3.event.preventDefault(); + scharm(dataToCfg()); + } + } + + // public: + + scharm.margin = function(value) { + if (!arguments.length) + return margin; + margin = value; + return scharm; + } + + scharm.timeDomain = function(value) { + if (!arguments.length) + return [timeDomainStartMs, timeDomainEndMs]; + timeDomainStartMs = value[0]; + timeDomainEndMs = value[1]; + return scharm; + } + + scharm.width = function(value) { + if (!arguments.length) + return width; + width = +value; + return scharm; + } + + scharm.height = function(value) { + if (!arguments.length) + return height; + height = +value; + return scharm; + } + + scharm.tableSelector = function(value) { + if (!arguments.length) + return tableSelector; + tableSelector = value; + return scharm; + } + + scharm.chartSelector = function(value) { + if (!arguments.length) + return chartSelector; + chartSelector = value; + return scharm; + } + + scharm.applyUrl = function(value) { + if (!arguments.length) + return applyUrl; + applyUrl = value; + return scharm; + } + + scharm.addRow = function() { + var newCfg = dataToCfg(); + var row = new Object(emptyRow); + row.label = "gen" + newCfg.length; + newCfg.push(row); + scharm(newCfg); + } + + scharm.removeRow = function(i) { + var newCfg = dataToCfg(); + newCfg.splice(i, 1); + scharm(newCfg); + } + + // should be called to regenerate chart on buttons clicks/etc + scharm.draw = function() { + scharm(dataToCfg()); + } + + // should be called to POST current config + scharm.sendCfg = function(callback) { + scharm(dataToCfg()); + d3.json(applyUrl, callback).post(JSON.stringify(cfg)); + } // should be called to apply the current config scharm.applyCfg = function() { scharm(dataToCfg()); } - - // constructor - var attributes = [ - { name: "label", type: "string" }, - { name: "startTime", type: "time" }, - { name: "period", type: "time" }, - { name: "periodCount", type: "integer" }, - { name: "reqSizeBytes", type: "bytes" }, - { name: "reqCount", type: "integer" }, - { name: "reqInterval", type: "time" }, - { name: "user", type: "string" }, - { name: "desc", type: "string" }, - - // Remove button - { name: "", class: "btn-remove" } - ]; - - var isNumberType = function(t) { - return t === 'time' || t === 'integer' || t === 'bytes'; - } - - var margin = { - top: 20, - right: 40, - bottom: 20, - left: 80, - footer: 100, - }; - var emptyRow = { - label: "label", - startTime: 0, - period: 100, - periodCount: 0, // infinite generation - reqSizeBytes: 1024, - reqCount: 1, - reqInterval: 10, - user: "vdisk0", - desc: "write" - }; - var tableSelector = 'body', chartSelector = 'body', applyUrl = '?mode=setconfig', - height = document.body.clientHeight - margin.top - margin.bottom - 5, - width = document.body.clientWidth - margin.right - margin.left - 5, - timeDomainStartMs = 0, timeDomainEndMs = 1000, timeUnit = 1, - bytesDomainMax = 10e6, - cfg, - table, - x, y, xAxis, yAxis, xZoomed, - svg, svgChartContainer, svgChart, seriesSvg, - zoom, zoomContainer1, zoomPanel, zoomContainer2, fixedContainer - ; - - return scharm; -} + + // constructor + var attributes = [ + { name: "label", type: "string" }, + { name: "startTime", type: "time" }, + { name: "period", type: "time" }, + { name: "periodCount", type: "integer" }, + { name: "reqSizeBytes", type: "bytes" }, + { name: "reqCount", type: "integer" }, + { name: "reqInterval", type: "time" }, + { name: "user", type: "string" }, + { name: "desc", type: "string" }, + + // Remove button + { name: "", class: "btn-remove" } + ]; + + var isNumberType = function(t) { + return t === 'time' || t === 'integer' || t === 'bytes'; + } + + var margin = { + top: 20, + right: 40, + bottom: 20, + left: 80, + footer: 100, + }; + var emptyRow = { + label: "label", + startTime: 0, + period: 100, + periodCount: 0, // infinite generation + reqSizeBytes: 1024, + reqCount: 1, + reqInterval: 10, + user: "vdisk0", + desc: "write" + }; + var tableSelector = 'body', chartSelector = 'body', applyUrl = '?mode=setconfig', + height = document.body.clientHeight - margin.top - margin.bottom - 5, + width = document.body.clientWidth - margin.right - margin.left - 5, + timeDomainStartMs = 0, timeDomainEndMs = 1000, timeUnit = 1, + bytesDomainMax = 10e6, + cfg, + table, + x, y, xAxis, yAxis, xZoomed, + svg, svgChartContainer, svgChart, seriesSvg, + zoom, zoomContainer1, zoomPanel, zoomContainer2, fixedContainer + ; + + return scharm; +} diff --git a/ydb/library/schlab/mon/static/js/schviz-test0.js b/ydb/library/schlab/mon/static/js/schviz-test0.js index 43ebb738f6..bc88ae05c1 100644 --- a/ydb/library/schlab/mon/static/js/schviz-test0.js +++ b/ydb/library/schlab/mon/static/js/schviz-test0.js @@ -1,26 +1,26 @@ -d3.json("schviz-test0.json", function(hist) { - var linesCount = 100; - var lineHeight = 50; - for (var i = 4; i < linesCount; i++) { - hist[0].cbs.push({ - "idx": i, - "name": "vdisk" + i, - "max_budget": 250000000, - "period": 1000000000, - "cur_budget": 250000000, - "deadline": Math.random()*1000000000, - "state": "ACTIVE", - "req": [{ - "id": 1, - "cost": 125000000, - "state": "RUNNING", - "seqno": 1 - }] - }); - } - - var schviz = d3.schviz().height(lineHeight*linesCount).width(800); - - schviz.timeDomain([0, 1000]); - schviz(hist); -}); +d3.json("schviz-test0.json", function(hist) { + var linesCount = 100; + var lineHeight = 50; + for (var i = 4; i < linesCount; i++) { + hist[0].cbs.push({ + "idx": i, + "name": "vdisk" + i, + "max_budget": 250000000, + "period": 1000000000, + "cur_budget": 250000000, + "deadline": Math.random()*1000000000, + "state": "ACTIVE", + "req": [{ + "id": 1, + "cost": 125000000, + "state": "RUNNING", + "seqno": 1 + }] + }); + } + + var schviz = d3.schviz().height(lineHeight*linesCount).width(800); + + schviz.timeDomain([0, 1000]); + schviz(hist); +}); diff --git a/ydb/library/schlab/mon/static/js/schviz.js b/ydb/library/schlab/mon/static/js/schviz.js index 17f870d023..1f0165bb83 100644 --- a/ydb/library/schlab/mon/static/js/schviz.js +++ b/ydb/library/schlab/mon/static/js/schviz.js @@ -1,951 +1,951 @@ -d3.schviz = function() { - // main schviz object - function schviz(hist) { - data = parseHistory(hist); - - initAxis(); - - // create svg element - svg = d3.select(selector) - .append("svg") - .attr("class", "chart") - .attr("width", width + margin.left + margin.right) - .attr("height",height + margin.top + margin.bottom) - ; - - // create arrowhead marker - defs = svg.append("defs"); - defs.append("marker") - .attr("id", "arrow") - .attr("viewBox", "0 -5 10 10") - .attr("refX", 5) - .attr("refY", 0) - .attr("markerWidth", 4) - .attr("markerHeight", 4) - .attr("orient", "auto") - .append("path") - .attr("d", "M0,-5L10,0L0,5") - .attr("class","arrowHead") - ; - - // disable default page scrolling with mouse wheel - // because wheel is used for zooming - window.onwheel = function(){ return false; } - - zoom = d3.zoom() +d3.schviz = function() { + // main schviz object + function schviz(hist) { + data = parseHistory(hist); + + initAxis(); + + // create svg element + svg = d3.select(selector) + .append("svg") + .attr("class", "chart") + .attr("width", width + margin.left + margin.right) + .attr("height",height + margin.top + margin.bottom) + ; + + // create arrowhead marker + defs = svg.append("defs"); + defs.append("marker") + .attr("id", "arrow") + .attr("viewBox", "0 -5 10 10") + .attr("refX", 5) + .attr("refY", 0) + .attr("markerWidth", 4) + .attr("markerHeight", 4) + .attr("orient", "auto") + .append("path") + .attr("d", "M0,-5L10,0L0,5") + .attr("class","arrowHead") + ; + + // disable default page scrolling with mouse wheel + // because wheel is used for zooming + window.onwheel = function(){ return false; } + + zoom = d3.zoom() .scaleExtent([0.1, 1000]) - //.translateExtent([0, 0], [1000,0]) - .on("zoom", function() { - var tr = d3.event.transform; - xZoomed = tr.rescaleX(x); - svg.select("g.x.axis").call(xAxis.scale(xZoomed)); - - var dy = d3.event.sourceEvent.screenY - zoom.startScreenY; - var newScrollTop = documentBodyScrollTop() - dy; - window.scrollTo(documentBodyScrollLeft(), newScrollTop); - documentBodyScrollTop(newScrollTop); - zoom.startScreenY = d3.event.sourceEvent.screenY; - - zoomContainer1.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); - zoomContainer2.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); - - drawCbsStates(); - drawReqBands(); - drawReqArrivals(); - - //tr(x); - }) - .on("start", function() { - zoom.startScreenY = d3.event.sourceEvent.screenY; - }) - .on("end", function() { - }) - ; - - svgChartContainer = svg.append('g') - .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") - ; - svgChart = svgChartContainer.append("svg") - .attr("top", 0) - .attr("left", 0) - .attr("width", width) - .attr("height", height) - .attr("viewBox", "0 0 " + width + " " + height) - ; - - zoomContainer1 = svgChart.append("g") - .attr("width", width) - .attr("height", height) - ; - - zoomPanel = svgChart.append("rect") - .attr("class", "zoom-panel") - .attr("width", width) - .attr("height", height) - .call(zoom) - ; - - zoomContainer2 = svgChart.append("g") - .attr("width", width) - .attr("height", height) - ; - - cbsSvg = zoomContainer1.append("g") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - ; - - reqSvg = zoomContainer2.append("g") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - ; - - // tooltips for requests - var maxTipHeight = 130; - function tipDirection(d) { - var y0 = y(d[0].get('cbsName')); - return (y0 - maxTipHeight < documentBodyScrollTop()? 's': 'n'); - } - tip = d3.tip() - .attr("class", "d3-tip") - .offset(function(d) { - // compute x to return tip in chart region - var t0 = (d[0].get('ts') + d[1].get('ts')) / 2; - var t1 = Math.min(Math.max(t0, xZoomed.invert(0)), xZoomed.invert(width)); - var dir = tipDirection(d); - return [dir === 'n'? -10 : 10, xZoomed(t1) - xZoomed(t0)]; - }) - .direction(tipDirection) - .html(function(d) { - return "<table><tr><td class='tip-heading' colspan='2'>" - + "<u>" + d[0].get('kind') + " #" + d[0].get('id') + ":</u></td></tr>" - + "<tr><td class='tip-key'>part:</td><td class='tip-value'>" - + getPartNo(d) + "/" + getPartCount(d) - + "</td></tr>" - + "<tr><td class='tip-key'>est. cost:</td><td class='tip-value'>" - + costFmt(getEstCost(d)) + "/" + costFmt(getEstTotalCost(d)) - + "</td></tr>" - + "<tr><td class='tip-key'>real cost:</td><td class='tip-value'>" - + costFmt(getRealCost(d)) + "/" + costFmt(getRealTotalCost(d)) - + "</td></tr>" - + "<tr><td class='tip-key'>arrive:</td><td class='tip-value'>" - + timeFmt(d[0].get('arrived')) + " ms" - + "</td></tr>" - + "<tr><td class='tip-key'>begin:</td><td class='tip-value'>" - + timeFmt(d[0].get('ts')) + " ms" - + "</td></tr>" - + "<tr><td class='tip-key'>end:</td><td class='tip-value'>" - + timeFmt(d[1].get('ts')) + " ms" - + "</td></tr>" - + "<tr><td class='tip-key'>seqno:</td><td class='tip-value'>" - + d[0].get('seqno') - + "</td></tr>" - + "</table>" - ; - }) - ; - - reqSvg.call(tip); - - // create rectangles for cbs bands - cbsbands = cbsSvg.selectAll(".chart") - .data(data.cbsband, cbsKeyFunction) - .enter() - .append("rect") - .attr("class", function(d) { - return cbsStateClass[d[0].get('state')] || "bar"; - }) - .attr("y", 0) - .attr("transform", cbsRectTransform) - .attr("height", y.bandwidth()) - .attr("width", function(d) { - return Math.max(1*xPixel(), (x(d[1].get('ts')) - x(d[0].get('ts')))); - }) - ; - - cbsstates = zoomContainer1.append("g"); - drawCbsStates(0); - - drawReqBands(); - - drawReqArrivals(); - - // container for non-zoomable elements - fixedContainer = svg.append("g") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") - ; - - // create x axis - fixedContainer.append("g") - .attr("class", "x axis") - .attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")") - .transition() - .call(xAxis) - ; - - // create y axis - fixedContainer.append("g") - .attr("class", "y axis") - .transition() - .call(yAxis) - ; - - // make y axis ticks draggable - var ytickdrag = d3.drag() - .on("drag", function(d) { - var ypos = d3.event.y - margin.top; - var index = Math.floor((ypos / y.step())); - index = Math.min(Math.max(index, 0), this.initDomain.length - 1); - if (index != this.curIndex) { - var newDomain = []; - for (var i = 0; i < this.initDomain.length; ++i) { - newDomain.push(this.initDomain[i]); - } - newDomain.splice(this.initIndex, 1); - newDomain.splice(index, 0, this.initDomain[this.initIndex]); - - this.curIndex = index; - this.curDomain = newDomain; - y.domain(newDomain); - - // rearange y scale and axis - svg.select("g.y.axis").transition().call(yAxis); - - // rearange other stuff - cbsbands.transition().attr("transform", cbsRectTransform); - drawReqBands(); - drawReqArrivals(true); - drawCbsStates(-1, true); - } - }) - .on("start", function(d) { - var ypos = d3.event.y - margin.top; - this.initIndex = Math.floor((ypos / y.step())); - this.initDomain = y.domain(); - }) - .on("end", function(d) { - svg.select("g.y.axis").call(yAxis); - }) - ; - svg.selectAll("g.y.axis .tick") - .call(ytickdrag) - ; - - // right margin - var rmargin = fixedContainer.append("g") - .attr("id", "right-margin") - .attr("transform", "translate(" + width + ", 0)") - ; - rmargin.append("rect") - .attr("x", 0) - .attr("y", 0) - .attr("width", 1) - .attr("height", height - margin.top - margin.bottom) - ; - - // top margin - var tmargin = fixedContainer.append("g") - .attr("id", "top-margin") - .attr("transform", "translate(0, 0)") - ; - tmargin.append("rect") - .attr("x", 0) - .attr("y", 0) - .attr("width", width) - .attr("height", 1) - ; - - // ruler - ruler = fixedContainer.append("g") - .attr("id", "ruler") - .attr("transform", "translate(0, 0)") - ; - ruler.append("rect") - .attr("id", "ruler-line") - .attr("x", 0) - .attr("y", 0) - .attr("width", "1") - .attr("height", height - margin.top - margin.bottom + 8) - ; - ruler.append("rect") - .attr("id", "bgrect") - .attr("x", 0) - .attr("y", 0) - .attr("width", 0) - .attr("height", 0) - .style("fill", "white") - ; - ruler.append("text") - .attr("x", 0) - .attr("y", height - margin.top - margin.bottom + 16) - .attr("dy", "0.71em") - .text("0") - ; - - svg.on('mousemove', function() { - positionRuler(d3.event.pageX); - }); - - // scroll handling - window.onscroll = function myFunction() { - documentBodyScrollLeft(document.body.scrollLeft); - documentBodyScrollTop(document.body.scrollTop); - var scroll = scrollParams(); - - svgChartContainer - .attr("transform", "translate(" + margin.left - + ", " + (margin.top + scroll.y1) + ")"); - svgChart - .attr("viewBox", "0 " + scroll.y1 + " " + width + " " + scroll.h) - .attr("height", scroll.h); - tmargin - .attr("transform", "translate(0," + scroll.y1 + ")"); - fixedContainer.select(".x.axis") - .attr("transform", "translate(0," + scroll.y2 + ")"); - rmargin.select("rect") - .attr("y", scroll.y1) - .attr("height", scroll.h); - ruler.select("#ruler-line") - .attr("y", scroll.y1) - .attr("height", scroll.h); - - positionRuler(); - } - - // draw chart - schviz.draw(); - - // update to initiale state - window.onscroll(0); - - return schviz; - } - -// private: - - var cbsKeyFunction = function(d) { - return "cbs:" + - d[0].get('ts').toString() + - d[0].get('idx').toString() + - d[1].get('ts').toString(); - } - - var cbsStateKeyFunction = function(d) { - return "cbsState:" + d.get('idx').toString(); - } - - var reqKeyFunction = function(d) { - return "req:" + - d[0].get('ts').toString() + - d[0].get('id').toString() + - d[1].get('ts').toString(); - } - - var reqStateKeyFunction = function(d) { - return "reqState:" + d[0].get('id').toString(); - } - - var cbsRectTransform = function(d) { - return "translate(" + x(d[0].get('ts')) + "," + y(d[0].get('name')) + ")"; - } - - var xPixel = function(d) { - return xZoomed.invert(1) - xZoomed.invert(0); - } - - var getEstCost = function(d) { - return (d[1].get('state') == "DONE"? - d[0].get('cost') : - d[0].get('cost') - d[1].get('cost')); - } - - var getRealCost = function(d) { - return d[1].get('ts') - d[0].get('ts'); - } - - var getEstTotalCost = function(d) { - return d[0].get('initCost'); - } - - var getRealTotalCost = function(d) { - var realtotalcost = 0; - var id = d[0].get('id'); - data.reqband.filter(function(dd) { - return dd[0].get('id') == id && dd[0].get('state') == "RUNNING"; - }).forEach(function(dd) { - realtotalcost += getRealCost(dd); - }); - return realtotalcost; - } - - var getPartNo = function(d) { - return d[0].get('partNo'); - } - - var getPartCount = function(d) { - var partCount = 0; - var id = d[0].get('id'); - data.reqband.filter(function(dd) { - return dd[0].get('id') == id && dd[0].get('state') == "RUNNING"; - }).forEach(function(dd) { - partCount++; - }); - return partCount; - } - - var initAxis = function() { - x = d3.scaleLinear() - .domain([timeDomainStartMs, timeDomainEndMs]) - .range([0, width]) - //.clamp(true); // dosn't work with zoom/pan - xZoomed = x; - y = d3.scaleBand() - .domain(Object.values(data.cbs).map(x => x.name).sort()) - .rangeRound([0, height - margin.top - margin.bottom]) - .padding(0.5); - xAxis = d3.axisBottom() - .scale(x) - //.tickSubdivide(true) - .tickSize(8) - .tickPadding(8); - yAxis = d3.axisLeft() - .scale(y) - .tickSize(0); - } - - var drawCbsStates = function(t0, smoothIn) { - // Save/restore last t0 value - if (!arguments.length || t0 == -1) { - t0 = drawCbsStates.t0; - } - drawCbsStates.t0 = t0; - - var smooth = (arguments.length > 1? smoothIn: false); - - var pxl = xPixel(); - - // find cbsbands containing given instant t0 and return left state - function findCbsState(data) { - return data.cbsband.filter(function(d) { - return d[0].get('ts') <= t0 && t0 < d[1].get('ts'); - }).map(function(d) { - return d[0]; - }); - } - var cbsStateData = findCbsState(data); - - // create/update/remove bands for cbs max_budget - var updCurBudget = cbsstates.selectAll("rect.cbs-active") - .data(cbsStateData, cbsStateKeyFunction); - updCurBudget.exit().remove(); - updCurBudget.enter().append("rect") - .attr("class", "cbs-active") - .merge(updCurBudget) // enter + update - .transition().duration(smooth ? transDuration : 0) - .attr("transform", function(d) { - return "translate(" + x(t0) + "," + y(d.get('name')) + ")"; - }) - .attr("y", y.bandwidth() * (1+1/8) + 4) - .attr("height", y.bandwidth() / 8) - .attr("width", function(d) { - var budget = d.get('max_budget'); - return Math.max(0, x(budget) - x(0)); - }) - ; - - // create/update/remove bands for cbs cur_budget - var updCurBudget = cbsstates.selectAll("rect.cbs-running") - .data(cbsStateData, cbsStateKeyFunction); - updCurBudget.exit().remove(); - updCurBudget.enter().append("rect") - .attr("class", "cbs-running") - .merge(updCurBudget) // enter + update - .transition().duration(smooth ? transDuration : 0) - .attr("transform", function(d) { - return "translate(" + x(t0) + "," + y(d.get('name')) + ")"; - }) - .attr("y", y.bandwidth() * (1+1/8) + 4) - .attr("height", y.bandwidth() / 8) - .attr("width", function(d) { - var budget = d.get('cur_budget'); - if (d.get('state') == "RUNNING") { - budget -= t0 - d.get('ts'); - } - return Math.max(0, x(budget) - x(0)); - }) - ; - - // create/update/remove bars for cbs deadline - var updDeadline = cbsstates.selectAll("line") - .data(cbsStateData, cbsStateKeyFunction); - updDeadline.exit().remove(); - updDeadline.enter().append("line") - .attr("class", "arrow-deadline") - //.attr("marker-end", "url(#arrow)") - .attr("transform", function(d) { - return "translate(" - + x(d.get('deadline')) + "," - + y(d.get('name')) + ")scale(" + pxl + ",1)"; - }) - .merge(updDeadline) // enter + update - .transition().duration(smooth ? transDuration : 0) - .attr("x1", 0) - .attr("x2", 0) - .attr("y1", 0) + //.translateExtent([0, 0], [1000,0]) + .on("zoom", function() { + var tr = d3.event.transform; + xZoomed = tr.rescaleX(x); + svg.select("g.x.axis").call(xAxis.scale(xZoomed)); + + var dy = d3.event.sourceEvent.screenY - zoom.startScreenY; + var newScrollTop = documentBodyScrollTop() - dy; + window.scrollTo(documentBodyScrollLeft(), newScrollTop); + documentBodyScrollTop(newScrollTop); + zoom.startScreenY = d3.event.sourceEvent.screenY; + + zoomContainer1.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); + zoomContainer2.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)"); + + drawCbsStates(); + drawReqBands(); + drawReqArrivals(); + + //tr(x); + }) + .on("start", function() { + zoom.startScreenY = d3.event.sourceEvent.screenY; + }) + .on("end", function() { + }) + ; + + svgChartContainer = svg.append('g') + .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") + ; + svgChart = svgChartContainer.append("svg") + .attr("top", 0) + .attr("left", 0) + .attr("width", width) + .attr("height", height) + .attr("viewBox", "0 0 " + width + " " + height) + ; + + zoomContainer1 = svgChart.append("g") + .attr("width", width) + .attr("height", height) + ; + + zoomPanel = svgChart.append("rect") + .attr("class", "zoom-panel") + .attr("width", width) + .attr("height", height) + .call(zoom) + ; + + zoomContainer2 = svgChart.append("g") + .attr("width", width) + .attr("height", height) + ; + + cbsSvg = zoomContainer1.append("g") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + ; + + reqSvg = zoomContainer2.append("g") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + ; + + // tooltips for requests + var maxTipHeight = 130; + function tipDirection(d) { + var y0 = y(d[0].get('cbsName')); + return (y0 - maxTipHeight < documentBodyScrollTop()? 's': 'n'); + } + tip = d3.tip() + .attr("class", "d3-tip") + .offset(function(d) { + // compute x to return tip in chart region + var t0 = (d[0].get('ts') + d[1].get('ts')) / 2; + var t1 = Math.min(Math.max(t0, xZoomed.invert(0)), xZoomed.invert(width)); + var dir = tipDirection(d); + return [dir === 'n'? -10 : 10, xZoomed(t1) - xZoomed(t0)]; + }) + .direction(tipDirection) + .html(function(d) { + return "<table><tr><td class='tip-heading' colspan='2'>" + + "<u>" + d[0].get('kind') + " #" + d[0].get('id') + ":</u></td></tr>" + + "<tr><td class='tip-key'>part:</td><td class='tip-value'>" + + getPartNo(d) + "/" + getPartCount(d) + + "</td></tr>" + + "<tr><td class='tip-key'>est. cost:</td><td class='tip-value'>" + + costFmt(getEstCost(d)) + "/" + costFmt(getEstTotalCost(d)) + + "</td></tr>" + + "<tr><td class='tip-key'>real cost:</td><td class='tip-value'>" + + costFmt(getRealCost(d)) + "/" + costFmt(getRealTotalCost(d)) + + "</td></tr>" + + "<tr><td class='tip-key'>arrive:</td><td class='tip-value'>" + + timeFmt(d[0].get('arrived')) + " ms" + + "</td></tr>" + + "<tr><td class='tip-key'>begin:</td><td class='tip-value'>" + + timeFmt(d[0].get('ts')) + " ms" + + "</td></tr>" + + "<tr><td class='tip-key'>end:</td><td class='tip-value'>" + + timeFmt(d[1].get('ts')) + " ms" + + "</td></tr>" + + "<tr><td class='tip-key'>seqno:</td><td class='tip-value'>" + + d[0].get('seqno') + + "</td></tr>" + + "</table>" + ; + }) + ; + + reqSvg.call(tip); + + // create rectangles for cbs bands + cbsbands = cbsSvg.selectAll(".chart") + .data(data.cbsband, cbsKeyFunction) + .enter() + .append("rect") + .attr("class", function(d) { + return cbsStateClass[d[0].get('state')] || "bar"; + }) + .attr("y", 0) + .attr("transform", cbsRectTransform) + .attr("height", y.bandwidth()) + .attr("width", function(d) { + return Math.max(1*xPixel(), (x(d[1].get('ts')) - x(d[0].get('ts')))); + }) + ; + + cbsstates = zoomContainer1.append("g"); + drawCbsStates(0); + + drawReqBands(); + + drawReqArrivals(); + + // container for non-zoomable elements + fixedContainer = svg.append("g") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .attr("transform", "translate(" + margin.left + ", " + margin.top + ")") + ; + + // create x axis + fixedContainer.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")") + .transition() + .call(xAxis) + ; + + // create y axis + fixedContainer.append("g") + .attr("class", "y axis") + .transition() + .call(yAxis) + ; + + // make y axis ticks draggable + var ytickdrag = d3.drag() + .on("drag", function(d) { + var ypos = d3.event.y - margin.top; + var index = Math.floor((ypos / y.step())); + index = Math.min(Math.max(index, 0), this.initDomain.length - 1); + if (index != this.curIndex) { + var newDomain = []; + for (var i = 0; i < this.initDomain.length; ++i) { + newDomain.push(this.initDomain[i]); + } + newDomain.splice(this.initIndex, 1); + newDomain.splice(index, 0, this.initDomain[this.initIndex]); + + this.curIndex = index; + this.curDomain = newDomain; + y.domain(newDomain); + + // rearange y scale and axis + svg.select("g.y.axis").transition().call(yAxis); + + // rearange other stuff + cbsbands.transition().attr("transform", cbsRectTransform); + drawReqBands(); + drawReqArrivals(true); + drawCbsStates(-1, true); + } + }) + .on("start", function(d) { + var ypos = d3.event.y - margin.top; + this.initIndex = Math.floor((ypos / y.step())); + this.initDomain = y.domain(); + }) + .on("end", function(d) { + svg.select("g.y.axis").call(yAxis); + }) + ; + svg.selectAll("g.y.axis .tick") + .call(ytickdrag) + ; + + // right margin + var rmargin = fixedContainer.append("g") + .attr("id", "right-margin") + .attr("transform", "translate(" + width + ", 0)") + ; + rmargin.append("rect") + .attr("x", 0) + .attr("y", 0) + .attr("width", 1) + .attr("height", height - margin.top - margin.bottom) + ; + + // top margin + var tmargin = fixedContainer.append("g") + .attr("id", "top-margin") + .attr("transform", "translate(0, 0)") + ; + tmargin.append("rect") + .attr("x", 0) + .attr("y", 0) + .attr("width", width) + .attr("height", 1) + ; + + // ruler + ruler = fixedContainer.append("g") + .attr("id", "ruler") + .attr("transform", "translate(0, 0)") + ; + ruler.append("rect") + .attr("id", "ruler-line") + .attr("x", 0) + .attr("y", 0) + .attr("width", "1") + .attr("height", height - margin.top - margin.bottom + 8) + ; + ruler.append("rect") + .attr("id", "bgrect") + .attr("x", 0) + .attr("y", 0) + .attr("width", 0) + .attr("height", 0) + .style("fill", "white") + ; + ruler.append("text") + .attr("x", 0) + .attr("y", height - margin.top - margin.bottom + 16) + .attr("dy", "0.71em") + .text("0") + ; + + svg.on('mousemove', function() { + positionRuler(d3.event.pageX); + }); + + // scroll handling + window.onscroll = function myFunction() { + documentBodyScrollLeft(document.body.scrollLeft); + documentBodyScrollTop(document.body.scrollTop); + var scroll = scrollParams(); + + svgChartContainer + .attr("transform", "translate(" + margin.left + + ", " + (margin.top + scroll.y1) + ")"); + svgChart + .attr("viewBox", "0 " + scroll.y1 + " " + width + " " + scroll.h) + .attr("height", scroll.h); + tmargin + .attr("transform", "translate(0," + scroll.y1 + ")"); + fixedContainer.select(".x.axis") + .attr("transform", "translate(0," + scroll.y2 + ")"); + rmargin.select("rect") + .attr("y", scroll.y1) + .attr("height", scroll.h); + ruler.select("#ruler-line") + .attr("y", scroll.y1) + .attr("height", scroll.h); + + positionRuler(); + } + + // draw chart + schviz.draw(); + + // update to initiale state + window.onscroll(0); + + return schviz; + } + +// private: + + var cbsKeyFunction = function(d) { + return "cbs:" + + d[0].get('ts').toString() + + d[0].get('idx').toString() + + d[1].get('ts').toString(); + } + + var cbsStateKeyFunction = function(d) { + return "cbsState:" + d.get('idx').toString(); + } + + var reqKeyFunction = function(d) { + return "req:" + + d[0].get('ts').toString() + + d[0].get('id').toString() + + d[1].get('ts').toString(); + } + + var reqStateKeyFunction = function(d) { + return "reqState:" + d[0].get('id').toString(); + } + + var cbsRectTransform = function(d) { + return "translate(" + x(d[0].get('ts')) + "," + y(d[0].get('name')) + ")"; + } + + var xPixel = function(d) { + return xZoomed.invert(1) - xZoomed.invert(0); + } + + var getEstCost = function(d) { + return (d[1].get('state') == "DONE"? + d[0].get('cost') : + d[0].get('cost') - d[1].get('cost')); + } + + var getRealCost = function(d) { + return d[1].get('ts') - d[0].get('ts'); + } + + var getEstTotalCost = function(d) { + return d[0].get('initCost'); + } + + var getRealTotalCost = function(d) { + var realtotalcost = 0; + var id = d[0].get('id'); + data.reqband.filter(function(dd) { + return dd[0].get('id') == id && dd[0].get('state') == "RUNNING"; + }).forEach(function(dd) { + realtotalcost += getRealCost(dd); + }); + return realtotalcost; + } + + var getPartNo = function(d) { + return d[0].get('partNo'); + } + + var getPartCount = function(d) { + var partCount = 0; + var id = d[0].get('id'); + data.reqband.filter(function(dd) { + return dd[0].get('id') == id && dd[0].get('state') == "RUNNING"; + }).forEach(function(dd) { + partCount++; + }); + return partCount; + } + + var initAxis = function() { + x = d3.scaleLinear() + .domain([timeDomainStartMs, timeDomainEndMs]) + .range([0, width]) + //.clamp(true); // dosn't work with zoom/pan + xZoomed = x; + y = d3.scaleBand() + .domain(Object.values(data.cbs).map(x => x.name).sort()) + .rangeRound([0, height - margin.top - margin.bottom]) + .padding(0.5); + xAxis = d3.axisBottom() + .scale(x) + //.tickSubdivide(true) + .tickSize(8) + .tickPadding(8); + yAxis = d3.axisLeft() + .scale(y) + .tickSize(0); + } + + var drawCbsStates = function(t0, smoothIn) { + // Save/restore last t0 value + if (!arguments.length || t0 == -1) { + t0 = drawCbsStates.t0; + } + drawCbsStates.t0 = t0; + + var smooth = (arguments.length > 1? smoothIn: false); + + var pxl = xPixel(); + + // find cbsbands containing given instant t0 and return left state + function findCbsState(data) { + return data.cbsband.filter(function(d) { + return d[0].get('ts') <= t0 && t0 < d[1].get('ts'); + }).map(function(d) { + return d[0]; + }); + } + var cbsStateData = findCbsState(data); + + // create/update/remove bands for cbs max_budget + var updCurBudget = cbsstates.selectAll("rect.cbs-active") + .data(cbsStateData, cbsStateKeyFunction); + updCurBudget.exit().remove(); + updCurBudget.enter().append("rect") + .attr("class", "cbs-active") + .merge(updCurBudget) // enter + update + .transition().duration(smooth ? transDuration : 0) + .attr("transform", function(d) { + return "translate(" + x(t0) + "," + y(d.get('name')) + ")"; + }) + .attr("y", y.bandwidth() * (1+1/8) + 4) + .attr("height", y.bandwidth() / 8) + .attr("width", function(d) { + var budget = d.get('max_budget'); + return Math.max(0, x(budget) - x(0)); + }) + ; + + // create/update/remove bands for cbs cur_budget + var updCurBudget = cbsstates.selectAll("rect.cbs-running") + .data(cbsStateData, cbsStateKeyFunction); + updCurBudget.exit().remove(); + updCurBudget.enter().append("rect") + .attr("class", "cbs-running") + .merge(updCurBudget) // enter + update + .transition().duration(smooth ? transDuration : 0) + .attr("transform", function(d) { + return "translate(" + x(t0) + "," + y(d.get('name')) + ")"; + }) + .attr("y", y.bandwidth() * (1+1/8) + 4) + .attr("height", y.bandwidth() / 8) + .attr("width", function(d) { + var budget = d.get('cur_budget'); + if (d.get('state') == "RUNNING") { + budget -= t0 - d.get('ts'); + } + return Math.max(0, x(budget) - x(0)); + }) + ; + + // create/update/remove bars for cbs deadline + var updDeadline = cbsstates.selectAll("line") + .data(cbsStateData, cbsStateKeyFunction); + updDeadline.exit().remove(); + updDeadline.enter().append("line") + .attr("class", "arrow-deadline") + //.attr("marker-end", "url(#arrow)") + .attr("transform", function(d) { + return "translate(" + + x(d.get('deadline')) + "," + + y(d.get('name')) + ")scale(" + pxl + ",1)"; + }) + .merge(updDeadline) // enter + update + .transition().duration(smooth ? transDuration : 0) + .attr("x1", 0) + .attr("x2", 0) + .attr("y1", 0) .attr("y2", y.bandwidth() * 1.4) - .attr("transform", function(d) { - return "translate(" - + x(d.get('deadline')) + "," - + y(d.get('name')) + ")scale(" + pxl + ",1)"; - }) - ; - - // find reqbands containing given instant t0 and return left state - function findReqState(data) { - // find cbsbands containing given instant t0 and return left state - return data.reqband.filter(function(d) { - return d[0].get('ts') <= t0 && t0 < d[1].get('ts'); - }).map(function(d) { - var cbsIdx = d[0].get('cbsIdx'); - var curCbsState = cbsStateData.find(function(x) {return x.get('idx') == cbsIdx;}); - var realcost = curCbsState.get('band')[0].get('ts') - curCbsState.get('band')[1].get('ts'); - var estcost = curCbsState.get('band')[0].get('costOut') - curCbsState.get('band')[1].get('costOut'); - var estToRealCoef = estcost / realcost; - return [d[0], curCbsState, estToRealCoef]; - }); - } - var reqStateData = findReqState(data); - - // create/update/remove bands for req cost - var updReqCost = cbsstates.selectAll("rect.req-real") - .data(reqStateData, reqStateKeyFunction); - updReqCost.exit().remove(); - updReqCost.enter().append("rect") - .attr("class", "req-real") - .merge(updReqCost) // enter + update - .transition().duration(smooth ? transDuration : 0) - .attr("transform", function(d) { - var c = d[1]; - var costOut = c.get('costOut'); - if (c.get('hasRunningRequest')) { - costOut += d[2] * (t0 - c.get('ts')); - } - return "translate(" + x(t0 + d[0].get('queuePos') - costOut) - + "," + y(c.get('name')) + ")"; - }) - .attr("x", pxl) - .attr("y", y.bandwidth() * (1) + 2) - .attr("height", y.bandwidth() * (1/8)) - .attr("width", function(d) { - var initCost = d[0].get('initCost'); - return Math.max(1*pxl, x(initCost) - x(0) - 2*pxl); - }) - ; - } - - var drawReqBands = function() { - var pxl = xPixel(); - - function reqbandTransform(d) { - return "translate(" + x(d[0].get('ts')) + "," + y(d[0].get('cbsName')) + ")"; - } - - function cutPoints(x, dx, y, dy) { - return (x ) + "," + (y + 0.20 * dy) - + " " + (x - dx) + "," + (y + 0.35 * dy) - + " " + (x + dx) + "," + (y + 0.65 * dy) - + " " + (x ) + "," + (y + 0.80 * dy) - ; - } - - function cutHalfPoints(x, dx, y, dy) { - return (x + dx) + "," + (y + 0.30 * dy) - + " " + (x ) + "," + (y + 0.60 * dy) - ; - } - - var h = y.bandwidth() * 0.6; - var y0 = y.bandwidth() * 0.2; - var dx = 5*pxl; - function reqbandPoints(d) { - var w = Math.max(1*pxl, (x(d[1].get('ts')) - x(d[0].get('ts'))) - 2*pxl); - var x1 = pxl; - var x2 = x1 + w; - var y1 = y0; - var y2 = y1 + h; - var leftCut = (d[0].get('cost') != d[0].get('initCost')); - var rightCut = (d[1].get('state') != "DONE"); - - return x1 + "," + y1 - + " " + (leftCut? cutPoints(x1, dx, y1, y2-y1) : "") - + " " + x1 + "," + y2 - + " " + x2 + "," + y2 - + " " + (rightCut? cutPoints(x2, -dx, y2, y1-y2) : "") - + " " + x2 + "," + y1 - ; - } - - function reqband2Points(d) { - var w = Math.max(1*pxl, (x(d[1].get('ts')) - x(d[0].get('ts'))) - 2*pxl); - var x1 = pxl; - var x2 = x1 + w; - var y1 = y0; - var y2 = y1 + h; - var leftCut = (d[0].get('cost') != d[0].get('initCost')); - var rightCut = (d[1].get('state') != "DONE"); - - var estcost = getEstCost(d); - var realcost = getRealCost(d); - - var cutFunc = cutPoints; - var delta = estcost - realcost; - if (delta === 0) { - return ""; // do not draw anything - } else if (delta > 0) { // overestimation - x2 = x1 + delta / estcost * w; - y1 += h / 2; - rightCut = false; - cutFunc = cutHalfPoints; - } else { // overrun - x1 = x2 + delta / realcost * w; - leftCut = false; - } - - return x1 + "," + y1 - + " " + (leftCut? cutFunc(x1, dx, y1, y2-y1) : "") - + " " + x1 + "," + y2 - + " " + x2 + "," + y2 - + " " + (rightCut? cutFunc(x2, -dx, y2, y1-y2) : "") - + " " + x2 + "," + y1 - ; - } - - function reqbandKindPoints(d) { - var w = Math.max(1*pxl, Math.min(x(d[1].get('ts')) - x(d[0].get('ts')), 10*pxl)); - var x1 = pxl; - var x2 = x1 + w; - var y1 = y0; - var y2 = y1 + h; - - if (d[0].get('kind') == "WRITE") { - var cx = (x1 + x2) / 2; - var cy = (y1 * 3/4 + y2 * 1/4); - var dx = (cx - x1) * 0.8; - var dy = (cy - y1) * 0.8; - return (cx - dx) + "," + (cy ) - + " " + (cx ) + "," + (cy - dy) - + " " + (cx + dx) + "," + (cy ) - + " " + (cx ) + "," + (cy + dy) - ; - } else { - return ""; - } - } - - // create polygons for req bands (real part) - var reqbandsData = data.reqband.filter(function(d) { - return d[0].get('state') == "RUNNING";} - ); - var reqbandsUpd = reqSvg.selectAll("polygon.req-real") - .data(reqbandsData, reqKeyFunction); - reqbandsUpd.exit().remove(); - reqbandsUpd.enter().append("polygon") - .attr("class", function(d) { - return "req-real reqband-" + d[0].get('id'); - }) - .on('mouseover', function(d) { - tip.show(d); - reqSvg.selectAll(".reqband-" + d[0].get('id')) - .classed("req-real-hover", true); - reqSvg.selectAll(".reqband2-" + d[0].get('id')) - .classed("req-est-hover", true); - reqSvg.selectAll(".reqarrival-" + d[0].get('id')) - .classed("arrow-arrival-hover", true) - .raise(); - }) - .on('mouseout', function(d) { - tip.hide(d); - reqSvg.selectAll(".reqband-" + d[0].get('id')) - .classed("req-real-hover", false); - reqSvg.selectAll(".reqband2-" + d[0].get('id')) - .classed("req-est-hover", false); - reqSvg.selectAll(".reqarrival-" + d[0].get('id')) - .classed("arrow-arrival-hover", false); - }) - .attr("transform", reqbandTransform) - .merge(reqbandsUpd) // enter + update - .attr("points", reqbandPoints) - .transition() - .attr("transform", reqbandTransform) - ; - - // create polygons for req bands (real/est diff) - var reqbands2Upd = reqSvg.selectAll("polygon.req-est") - .data(reqbandsData, reqKeyFunction); - reqbands2Upd.exit().remove(); - reqbands2Upd.enter().append("polygon") - .attr("class", function(d) { - return "req-est reqband2-" + d[0].get('id'); - }) - .attr("transform", reqbandTransform) - .merge(reqbands2Upd) // enter + update - .attr("points", reqband2Points) - .transition() - .attr("transform", reqbandTransform) - ; - - // create polygons for req kind - var reqbandsKindUpd = reqSvg.selectAll("polygon.req-kind") - .data(reqbandsData, reqKeyFunction); - reqbandsKindUpd.exit().remove(); - reqbandsKindUpd.enter().append("polygon") - .attr("class", function(d) { - return "req-kind reqbandkind-" + d[0].get('id'); - }) - .attr("transform", reqbandTransform) - .merge(reqbandsKindUpd) // enter + update - .attr("points", reqbandKindPoints) - .transition() - .attr("transform", reqbandTransform) - ; - } - - var drawReqArrivals = function(smoothIn) { - var smooth = (arguments.length > 0? smoothIn: false); - - // create/update/remove bars for req arrivals - var updArrivals = reqSvg.selectAll("line.arrow-arrival") - .data(data.reqband.filter(function(d) { - return d[0].get('arrived') === d[0].get('ts'); - }), reqKeyFunction); - updArrivals.exit().remove(); - updArrivals.enter().append("line") - .attr("class", function(d) { - return "arrow-arrival reqarrival-" + d[0].get('id'); - }) - //.attr("marker-end", "url(#arrow)") - .attr("x1", 0) - .attr("x2", 0) - .attr("y1", y.bandwidth() * 0.5) + .attr("transform", function(d) { + return "translate(" + + x(d.get('deadline')) + "," + + y(d.get('name')) + ")scale(" + pxl + ",1)"; + }) + ; + + // find reqbands containing given instant t0 and return left state + function findReqState(data) { + // find cbsbands containing given instant t0 and return left state + return data.reqband.filter(function(d) { + return d[0].get('ts') <= t0 && t0 < d[1].get('ts'); + }).map(function(d) { + var cbsIdx = d[0].get('cbsIdx'); + var curCbsState = cbsStateData.find(function(x) {return x.get('idx') == cbsIdx;}); + var realcost = curCbsState.get('band')[0].get('ts') - curCbsState.get('band')[1].get('ts'); + var estcost = curCbsState.get('band')[0].get('costOut') - curCbsState.get('band')[1].get('costOut'); + var estToRealCoef = estcost / realcost; + return [d[0], curCbsState, estToRealCoef]; + }); + } + var reqStateData = findReqState(data); + + // create/update/remove bands for req cost + var updReqCost = cbsstates.selectAll("rect.req-real") + .data(reqStateData, reqStateKeyFunction); + updReqCost.exit().remove(); + updReqCost.enter().append("rect") + .attr("class", "req-real") + .merge(updReqCost) // enter + update + .transition().duration(smooth ? transDuration : 0) + .attr("transform", function(d) { + var c = d[1]; + var costOut = c.get('costOut'); + if (c.get('hasRunningRequest')) { + costOut += d[2] * (t0 - c.get('ts')); + } + return "translate(" + x(t0 + d[0].get('queuePos') - costOut) + + "," + y(c.get('name')) + ")"; + }) + .attr("x", pxl) + .attr("y", y.bandwidth() * (1) + 2) + .attr("height", y.bandwidth() * (1/8)) + .attr("width", function(d) { + var initCost = d[0].get('initCost'); + return Math.max(1*pxl, x(initCost) - x(0) - 2*pxl); + }) + ; + } + + var drawReqBands = function() { + var pxl = xPixel(); + + function reqbandTransform(d) { + return "translate(" + x(d[0].get('ts')) + "," + y(d[0].get('cbsName')) + ")"; + } + + function cutPoints(x, dx, y, dy) { + return (x ) + "," + (y + 0.20 * dy) + + " " + (x - dx) + "," + (y + 0.35 * dy) + + " " + (x + dx) + "," + (y + 0.65 * dy) + + " " + (x ) + "," + (y + 0.80 * dy) + ; + } + + function cutHalfPoints(x, dx, y, dy) { + return (x + dx) + "," + (y + 0.30 * dy) + + " " + (x ) + "," + (y + 0.60 * dy) + ; + } + + var h = y.bandwidth() * 0.6; + var y0 = y.bandwidth() * 0.2; + var dx = 5*pxl; + function reqbandPoints(d) { + var w = Math.max(1*pxl, (x(d[1].get('ts')) - x(d[0].get('ts'))) - 2*pxl); + var x1 = pxl; + var x2 = x1 + w; + var y1 = y0; + var y2 = y1 + h; + var leftCut = (d[0].get('cost') != d[0].get('initCost')); + var rightCut = (d[1].get('state') != "DONE"); + + return x1 + "," + y1 + + " " + (leftCut? cutPoints(x1, dx, y1, y2-y1) : "") + + " " + x1 + "," + y2 + + " " + x2 + "," + y2 + + " " + (rightCut? cutPoints(x2, -dx, y2, y1-y2) : "") + + " " + x2 + "," + y1 + ; + } + + function reqband2Points(d) { + var w = Math.max(1*pxl, (x(d[1].get('ts')) - x(d[0].get('ts'))) - 2*pxl); + var x1 = pxl; + var x2 = x1 + w; + var y1 = y0; + var y2 = y1 + h; + var leftCut = (d[0].get('cost') != d[0].get('initCost')); + var rightCut = (d[1].get('state') != "DONE"); + + var estcost = getEstCost(d); + var realcost = getRealCost(d); + + var cutFunc = cutPoints; + var delta = estcost - realcost; + if (delta === 0) { + return ""; // do not draw anything + } else if (delta > 0) { // overestimation + x2 = x1 + delta / estcost * w; + y1 += h / 2; + rightCut = false; + cutFunc = cutHalfPoints; + } else { // overrun + x1 = x2 + delta / realcost * w; + leftCut = false; + } + + return x1 + "," + y1 + + " " + (leftCut? cutFunc(x1, dx, y1, y2-y1) : "") + + " " + x1 + "," + y2 + + " " + x2 + "," + y2 + + " " + (rightCut? cutFunc(x2, -dx, y2, y1-y2) : "") + + " " + x2 + "," + y1 + ; + } + + function reqbandKindPoints(d) { + var w = Math.max(1*pxl, Math.min(x(d[1].get('ts')) - x(d[0].get('ts')), 10*pxl)); + var x1 = pxl; + var x2 = x1 + w; + var y1 = y0; + var y2 = y1 + h; + + if (d[0].get('kind') == "WRITE") { + var cx = (x1 + x2) / 2; + var cy = (y1 * 3/4 + y2 * 1/4); + var dx = (cx - x1) * 0.8; + var dy = (cy - y1) * 0.8; + return (cx - dx) + "," + (cy ) + + " " + (cx ) + "," + (cy - dy) + + " " + (cx + dx) + "," + (cy ) + + " " + (cx ) + "," + (cy + dy) + ; + } else { + return ""; + } + } + + // create polygons for req bands (real part) + var reqbandsData = data.reqband.filter(function(d) { + return d[0].get('state') == "RUNNING";} + ); + var reqbandsUpd = reqSvg.selectAll("polygon.req-real") + .data(reqbandsData, reqKeyFunction); + reqbandsUpd.exit().remove(); + reqbandsUpd.enter().append("polygon") + .attr("class", function(d) { + return "req-real reqband-" + d[0].get('id'); + }) + .on('mouseover', function(d) { + tip.show(d); + reqSvg.selectAll(".reqband-" + d[0].get('id')) + .classed("req-real-hover", true); + reqSvg.selectAll(".reqband2-" + d[0].get('id')) + .classed("req-est-hover", true); + reqSvg.selectAll(".reqarrival-" + d[0].get('id')) + .classed("arrow-arrival-hover", true) + .raise(); + }) + .on('mouseout', function(d) { + tip.hide(d); + reqSvg.selectAll(".reqband-" + d[0].get('id')) + .classed("req-real-hover", false); + reqSvg.selectAll(".reqband2-" + d[0].get('id')) + .classed("req-est-hover", false); + reqSvg.selectAll(".reqarrival-" + d[0].get('id')) + .classed("arrow-arrival-hover", false); + }) + .attr("transform", reqbandTransform) + .merge(reqbandsUpd) // enter + update + .attr("points", reqbandPoints) + .transition() + .attr("transform", reqbandTransform) + ; + + // create polygons for req bands (real/est diff) + var reqbands2Upd = reqSvg.selectAll("polygon.req-est") + .data(reqbandsData, reqKeyFunction); + reqbands2Upd.exit().remove(); + reqbands2Upd.enter().append("polygon") + .attr("class", function(d) { + return "req-est reqband2-" + d[0].get('id'); + }) + .attr("transform", reqbandTransform) + .merge(reqbands2Upd) // enter + update + .attr("points", reqband2Points) + .transition() + .attr("transform", reqbandTransform) + ; + + // create polygons for req kind + var reqbandsKindUpd = reqSvg.selectAll("polygon.req-kind") + .data(reqbandsData, reqKeyFunction); + reqbandsKindUpd.exit().remove(); + reqbandsKindUpd.enter().append("polygon") + .attr("class", function(d) { + return "req-kind reqbandkind-" + d[0].get('id'); + }) + .attr("transform", reqbandTransform) + .merge(reqbandsKindUpd) // enter + update + .attr("points", reqbandKindPoints) + .transition() + .attr("transform", reqbandTransform) + ; + } + + var drawReqArrivals = function(smoothIn) { + var smooth = (arguments.length > 0? smoothIn: false); + + // create/update/remove bars for req arrivals + var updArrivals = reqSvg.selectAll("line.arrow-arrival") + .data(data.reqband.filter(function(d) { + return d[0].get('arrived') === d[0].get('ts'); + }), reqKeyFunction); + updArrivals.exit().remove(); + updArrivals.enter().append("line") + .attr("class", function(d) { + return "arrow-arrival reqarrival-" + d[0].get('id'); + }) + //.attr("marker-end", "url(#arrow)") + .attr("x1", 0) + .attr("x2", 0) + .attr("y1", y.bandwidth() * 0.5) .attr("y2", -y.bandwidth() * 0.4) - .attr("transform", function(d) { - return "translate(" - + x(d[0].get('arrived')) + "," - + y(d[0].get('cbsName')) + ")scale(" + xPixel() + ",1)"; - }) - .merge(updArrivals) // enter + update - .transition().duration(smooth ? transDuration : 0) - .attr("transform", function(d) { - return "translate(" - + x(d[0].get('arrived')) + "," - + y(d[0].get('cbsName')) + ")scale(" + xPixel() + ",1)"; - }) - ; - } - - // slow function wrapper - var documentBodyScrollLeft = function(value) { - // return document.body.scrollLeft; - if (!arguments.length) { - if (documentBodyScrollLeft.value === undefined) { - documentBodyScrollLeft.value = document.body.scrollLeft; - } - return documentBodyScrollLeft.value; - } else { - documentBodyScrollLeft.value = value; - } - } - - // slow function wrapper - var documentBodyScrollTop = function(value) { - // return document.body.scrollTop; - if (!arguments.length) { - if (!documentBodyScrollTop.value === undefined) { - documentBodyScrollTop.value = document.body.scrollTop; - } - return documentBodyScrollTop.value; - } else { - documentBodyScrollTop.value = value; - } - } - - var scrollParams = function() { - var y1 = documentBodyScrollTop(); - var y2 = y1 + window.innerHeight - margin.footer; - y2 = Math.min(y2, height - margin.top - margin.bottom); - var h = y2 - y1; - return { - y1: y1, - y2: y2, - h: h - }; - } - - var posTextFormat = d3.format(".1f"); - - var positionRuler = function(pageX) { - if (!arguments.length) { - pageX = positionRuler.pageX || 0; - } else { - positionRuler.pageX = pageX; - } - - // x-coordinate - var xpos = pageX - margin.left + 1; - var tpos = xZoomed.invert(xpos); - tpos = Math.min(Math.max(tpos, xZoomed.invert(0)), xZoomed.invert(width)); - ruler.attr("transform", "translate(" + xZoomed(tpos) + ", 0)"); - var posText = posTextFormat(tpos); - - // scroll-related - var scroll = scrollParams(); - - var text = ruler.select("text") - .attr("y", scroll.y2 + 16) - ; + .attr("transform", function(d) { + return "translate(" + + x(d[0].get('arrived')) + "," + + y(d[0].get('cbsName')) + ")scale(" + xPixel() + ",1)"; + }) + .merge(updArrivals) // enter + update + .transition().duration(smooth ? transDuration : 0) + .attr("transform", function(d) { + return "translate(" + + x(d[0].get('arrived')) + "," + + y(d[0].get('cbsName')) + ")scale(" + xPixel() + ",1)"; + }) + ; + } + + // slow function wrapper + var documentBodyScrollLeft = function(value) { + // return document.body.scrollLeft; + if (!arguments.length) { + if (documentBodyScrollLeft.value === undefined) { + documentBodyScrollLeft.value = document.body.scrollLeft; + } + return documentBodyScrollLeft.value; + } else { + documentBodyScrollLeft.value = value; + } + } + + // slow function wrapper + var documentBodyScrollTop = function(value) { + // return document.body.scrollTop; + if (!arguments.length) { + if (!documentBodyScrollTop.value === undefined) { + documentBodyScrollTop.value = document.body.scrollTop; + } + return documentBodyScrollTop.value; + } else { + documentBodyScrollTop.value = value; + } + } + + var scrollParams = function() { + var y1 = documentBodyScrollTop(); + var y2 = y1 + window.innerHeight - margin.footer; + y2 = Math.min(y2, height - margin.top - margin.bottom); + var h = y2 - y1; + return { + y1: y1, + y2: y2, + h: h + }; + } + + var posTextFormat = d3.format(".1f"); + + var positionRuler = function(pageX) { + if (!arguments.length) { + pageX = positionRuler.pageX || 0; + } else { + positionRuler.pageX = pageX; + } + + // x-coordinate + var xpos = pageX - margin.left + 1; + var tpos = xZoomed.invert(xpos); + tpos = Math.min(Math.max(tpos, xZoomed.invert(0)), xZoomed.invert(width)); + ruler.attr("transform", "translate(" + xZoomed(tpos) + ", 0)"); + var posText = posTextFormat(tpos); + + // scroll-related + var scroll = scrollParams(); + + var text = ruler.select("text") + .attr("y", scroll.y2 + 16) + ; // getBBox() is very slow, so compute symbol width once - var xpadding = 5; - var ypadding = 5; - if (!positionRuler.bbox) { - positionRuler.bbox = text.node().getBBox(); - } - - text.text(posText); - var textWidth = 10 * posText.length; - ruler.select("#bgrect") - .attr("x", -textWidth/2 - xpadding) - .attr("y", positionRuler.bbox.y - ypadding) - .attr("width", textWidth + (xpadding*2)) - .attr("height", positionRuler.bbox.height + (ypadding*2)) - ; - - drawCbsStates(tpos); - } - - var beginParseCbs = function(data, frame, cbs) { - if (cbs.idx === undefined) { - alert("'idx' is not set for cbs in frame:\n" + JSON.stringify(frame)); - } - - // create cbs if required - var idx = +cbs.idx; - if (!data.cbs.hasOwnProperty(idx)) { - var c = {}; - - // initialize new cbs info - c.idx = idx; - c.band = null; - c.ts = +frame.ts * timeUnit; - c.name = cbs.name || ("cbs" + frame.idx); - c.max_budget = (+cbs.max_budget || 0) * timeUnit; - c.period = (+cbs.period || 0) * timeUnit; - c.cur_budget = (+cbs.cur_budget || 0) * timeUnit; - c.deadline = (+cbs.deadline || 0) * timeUnit; - c.state = cbs.state || "IDLE"; - c.reqIn = 0; - c.reqOut = 0; - c.costIn = 0; - c.costOut = 0; - c.runningTime = 0; - c.idleTime = 0; - c.activeTime = 0; - c.depletedTime = 0; - c.hasRunningRequest = false; - - data.cbs[idx] = c; - } else { - // update current req info - var c = data.cbs[idx]; - - // deep copy current request state as the first band's element - c.band = []; - c.band.push(d3.map(c)); - - // update current req info - c.ts = +frame.ts * timeUnit; - c.hasRunningRequest = false; - if (cbs.hasOwnProperty('name')) { c.name = cbs.name; } - if (cbs.hasOwnProperty('max_budget')) { c.max_budget = +cbs.max_budget * timeUnit; } - if (cbs.hasOwnProperty('period')) { c.period = +cbs.period * timeUnit; } - if (cbs.hasOwnProperty('cur_budget')) { c.cur_budget = +cbs.cur_budget * timeUnit; } - if (cbs.hasOwnProperty('deadline')) { c.deadline = +cbs.deadline * timeUnit; } - if (cbs.hasOwnProperty('state')) { c.state = cbs.state; } - } - } - - var endParseCbs = function(data, frame, cbs) { - // create cbs if required - var idx = +cbs.idx; - var c = data.cbs[idx]; - if (c.band !== null) { - // deep copy new request state as the second band's element - c.band.push(d3.map(c)); - if (c.band[0].get('ts') < c.band[1].get('ts')) { - data.cbsband.push(c.band); - } - } - } - - var beginParseCbsReq = function(data, frame, cbs, req) { - if (req.id === undefined) { - alert("'id' is not set for req in frame's cbs:\n" + JSON.stringify(cbs)); - } - - var idx = +cbs.idx; - var c = data.cbs[idx]; - - var id = +req.id; - if (!data.req.hasOwnProperty(id)) { - var r = {}; - - // initialize new req info - r.id = id; - r.band = null; - r.cbsIdx = idx; - r.cbsName = c.name; - r.ts = +frame.ts * timeUnit; - r.cost = (+req.cost || 0) * timeUnit; - r.initCost = r.cost; - r.seqno = +req.seqno || 0; - r.state = req.state || "PENDING"; - r.kind = req.kind || "REQUEST"; - r.queuePos = c.costIn; - r.arrived = r.ts; - r.partNo = 0; - - // update cbs statistics - c.reqIn++; - c.costIn += r.cost; - if (r.state == "RUNNING") { - c.hasRunningRequest = true; - } - - data.req[id] = r; - } else { - // update current req info - var r = data.req[id]; + var xpadding = 5; + var ypadding = 5; + if (!positionRuler.bbox) { + positionRuler.bbox = text.node().getBBox(); + } + + text.text(posText); + var textWidth = 10 * posText.length; + ruler.select("#bgrect") + .attr("x", -textWidth/2 - xpadding) + .attr("y", positionRuler.bbox.y - ypadding) + .attr("width", textWidth + (xpadding*2)) + .attr("height", positionRuler.bbox.height + (ypadding*2)) + ; + + drawCbsStates(tpos); + } + + var beginParseCbs = function(data, frame, cbs) { + if (cbs.idx === undefined) { + alert("'idx' is not set for cbs in frame:\n" + JSON.stringify(frame)); + } + + // create cbs if required + var idx = +cbs.idx; + if (!data.cbs.hasOwnProperty(idx)) { + var c = {}; + + // initialize new cbs info + c.idx = idx; + c.band = null; + c.ts = +frame.ts * timeUnit; + c.name = cbs.name || ("cbs" + frame.idx); + c.max_budget = (+cbs.max_budget || 0) * timeUnit; + c.period = (+cbs.period || 0) * timeUnit; + c.cur_budget = (+cbs.cur_budget || 0) * timeUnit; + c.deadline = (+cbs.deadline || 0) * timeUnit; + c.state = cbs.state || "IDLE"; + c.reqIn = 0; + c.reqOut = 0; + c.costIn = 0; + c.costOut = 0; + c.runningTime = 0; + c.idleTime = 0; + c.activeTime = 0; + c.depletedTime = 0; + c.hasRunningRequest = false; + + data.cbs[idx] = c; + } else { + // update current req info + var c = data.cbs[idx]; + + // deep copy current request state as the first band's element + c.band = []; + c.band.push(d3.map(c)); + + // update current req info + c.ts = +frame.ts * timeUnit; + c.hasRunningRequest = false; + if (cbs.hasOwnProperty('name')) { c.name = cbs.name; } + if (cbs.hasOwnProperty('max_budget')) { c.max_budget = +cbs.max_budget * timeUnit; } + if (cbs.hasOwnProperty('period')) { c.period = +cbs.period * timeUnit; } + if (cbs.hasOwnProperty('cur_budget')) { c.cur_budget = +cbs.cur_budget * timeUnit; } + if (cbs.hasOwnProperty('deadline')) { c.deadline = +cbs.deadline * timeUnit; } + if (cbs.hasOwnProperty('state')) { c.state = cbs.state; } + } + } + + var endParseCbs = function(data, frame, cbs) { + // create cbs if required + var idx = +cbs.idx; + var c = data.cbs[idx]; + if (c.band !== null) { + // deep copy new request state as the second band's element + c.band.push(d3.map(c)); + if (c.band[0].get('ts') < c.band[1].get('ts')) { + data.cbsband.push(c.band); + } + } + } + + var beginParseCbsReq = function(data, frame, cbs, req) { + if (req.id === undefined) { + alert("'id' is not set for req in frame's cbs:\n" + JSON.stringify(cbs)); + } + + var idx = +cbs.idx; + var c = data.cbs[idx]; + + var id = +req.id; + if (!data.req.hasOwnProperty(id)) { + var r = {}; + + // initialize new req info + r.id = id; + r.band = null; + r.cbsIdx = idx; + r.cbsName = c.name; + r.ts = +frame.ts * timeUnit; + r.cost = (+req.cost || 0) * timeUnit; + r.initCost = r.cost; + r.seqno = +req.seqno || 0; + r.state = req.state || "PENDING"; + r.kind = req.kind || "REQUEST"; + r.queuePos = c.costIn; + r.arrived = r.ts; + r.partNo = 0; + + // update cbs statistics + c.reqIn++; + c.costIn += r.cost; + if (r.state == "RUNNING") { + c.hasRunningRequest = true; + } + + data.req[id] = r; + } else { + // update current req info + var r = data.req[id]; if (r.state == "PENDING" && ( (req.hasOwnProperty('state') && req.state == "PENDING") || !req.hasOwnProperty('state'))) { // process the cost update ONLY while still in PENDING state and the update is stateless or still PENDING if (req.hasOwnProperty('cost')) { - c.costIn -= r.cost; + c.costIn -= r.cost; r.cost = +req.cost * timeUnit; r.initCost = r.cost; c.costIn += r.cost; } } else { r.band = []; - + // deep copy current request state as the first band's element r.band.push(d3.map(r)); - + // update current req info r.ts = +frame.ts * timeUnit; - - + + if (req.hasOwnProperty('cost')) { r.cost = +req.cost * timeUnit; } if (req.hasOwnProperty('seqno')) { r.seqno = +req.seqno; } if (req.hasOwnProperty('state')) { r.state = req.state; } @@ -963,277 +963,277 @@ d3.schviz = function() { if (r.state == "RUNNING") { c.hasRunningRequest = true; } - } - } - } - - var endParseCbsReq = function(data, frame, cbs, req) { - var idx = +cbs.idx; - var c = data.cbs[idx]; - - var id = +req.id; - var r = data.req[id]; - - if (r.band !== null) { - // deep copy new request state as the second band's element - r.band.push(d3.map(r)); - if (r.band[0].get('ts') < r.band[1].get('ts')) { - data.reqband.push(r.band); - } - } - } - - var finalizeCbs = function(data, ts, c) { - var band = []; - - // deep copy current request state as the first band's element - band.push(d3.map(c)); - - // update current req info - c.ts = ts * timeUnit; - - // deep copy new request state as the second band's element - band.push(d3.map(c)); - if (band[0].get('ts') < band[1].get('ts')) { - data.cbsband.push(band); - } - } - - var finalizeCbsReq = function(data, ts, r) { - var band = []; - - // deep copy current request state as the first band's element - band.push(d3.map(r)); - - // update current req info - r.ts = ts * timeUnit; - - // deep copy new request state as the second band's element - band.push(d3.map(r)); - if (band[0].get('ts') < band[1].get('ts')) { - data.reqband.push(band); - } - } - - var finalize = function(data, ts) { - for (var idx in data.cbs) { - finalizeCbs(data, ts, data.cbs[idx]); - } - for (var id in data.req) { - finalizeCbsReq(data, ts, data.req[id]); - } - } - - var parseFrame = function(data, frame) { - var i, j; - for (i = 0; i < frame.cbs.length; ++i) { - var cbs = frame.cbs[i]; - beginParseCbs(data, frame, cbs); - if (cbs.hasOwnProperty('req')) { - for (j = 0; j < cbs.req.length; ++j) { - var req = cbs.req[j]; - beginParseCbsReq(data, frame, cbs, req); - } - for (j = 0; j < cbs.req.length; ++j) { - var req = cbs.req[j]; - endParseCbsReq(data, frame, cbs, req); - } - } - endParseCbs(data, frame, cbs); - } - } - - var parseKeyframe = function(data, frame) { - // current state - data.cbs = {}; - data.req = {}; - - // data for vizualization - data.cbsband = []; - data.reqband = []; - - // regular frame parse - parseFrame(data, frame); - } - - var parseHistory = function(hist) { - var i, data = {}, - keyframeFound = false; - for (i = 0; i < hist.length; ++i) { - var frame = hist[i]; - if (!keyframeFound) { - if (frame.keyframe) { - keyframeFound = true; - parseKeyframe(data, frame); - } else { - // skip frames before keyframe - } - } else { - if (!frame.keyframe) { - parseFrame(data, frame); - } else { - // skip non-first keyframes - } - } - } - if (hist.length > 1) { - finalize(data, hist[hist.length-1].ts); - } - - // Erase every cbs that has no request - data.cbsband = data.cbsband.filter(x => data.cbs[x[0].get('idx')].band !== null); - Object.keys(data.cbs).forEach(function(key) { - if (data.cbs[key].band === null) { - delete data.cbs[key]; - } - }); - console.log(data); - return data; - } - -// public: - - schviz.draw = function(cbs) { - svg.select("g.x.axis").call(xAxis); - svg.select("g.y.axis").call(yAxis); - return schviz; - } - - schviz.update = function(cbs) { - - var svg = d3.select(".chart"); - var schvizChartGroup = svg.select(".gantt-chart"); - - // update task data attached to rect elements - var rect = schvizChartGroup.selectAll("rect") - .data(cbs, cbsKeyFunction); - - // attach new cbs state - rect.enter() - .insert("rect", ":first-child") - .attr("rx", 5) - .attr("ry", 5) - .attr("class", function(d) { - if (taskStatus[d.status] == null) { - return "bar"; - } - return taskStatus[d.status]; - }) - .transition() - .attr("y", 0) - .attr("transform", rectTransform) - .attr("height", function(d) { - return y.bandwidth(); - }) - .attr("width", function(d) { - return Math.max(1*xPixel, (x(d.endDate) - x(d.startDate))); - }); - - // rearrange current cbs states - rect.transition() - .attr("transform", rectTransform) - .attr("height", function(d) { - return y.bandwidth(); - }) - .attr("width", function(d) { - return Math.max(1*xPixel(), (x(d.endDate) - x(d.startDate))); - }); - - // remove deleted cbs states - rect.exit().remove(); - - // update axes - svg.select(".x").transition().call(xAxis); - svg.select(".y").transition().call(yAxis); - - return schviz; - } - - schviz.margin = function(value) { - if (!arguments.length) - return margin; - margin = value; - return schviz; - } - - schviz.timeDomain = function(value) { - if (!arguments.length) - return [timeDomainStartMs, timeDomainEndMs]; - timeDomainStartMs = value[0]; - timeDomainEndMs = value[1]; - return schviz; - } - - schviz.width = function(value) { - if (!arguments.length) - return width; - width = +value; - return schviz; - } - - schviz.height = function(value) { - if (!arguments.length) - return height; - height = +value; - return schviz; - } - - schviz.selector = function(value) { - if (!arguments.length) - return selector; - selector = value; - return schviz; - } - -// constructor - - var margin = { - top: 20, - right: 40, - bottom: 20, - left: 200, - footer: 100, - }; - var height = document.body.clientHeight - margin.top - margin.bottom - 5; - var width = document.body.clientWidth - margin.right - margin.left - 5; - - var selector = 'body'; - var timeDomainStartMs = 0; - var timeDomainEndMs = 1000; - var timeUnit = 1e-6; - var costFmt = d3.format('.4s'); - var timeFmt = d3.format(',.6r'); - var cbsStateClass = { - "IDLE": "cbs-idle", - "ACTIVE": "cbs-active", - "RUNNING": "cbs-running", - "DEPLETED": "cbs-depleted", - "DEAD": "cbs-dead" - }; - - var x = null, - xZoomed = null, - y = null, - xAxis = null, - yAxis = null, - svg = null, - defs = null, - svgChartContainer = null, - svgChart = null, - zoomPanel = null, - zoomContainer1 = null, - zoomContainer2 = null, - fixedContainer = null, - zoom = null, - cbsSvg = null, - reqSvg = null, - cbsbands = null, - cbsstates = null, - tip = null, - ruler = null, - data = { "bands": d3.map(), "states": d3.map() }, - transDuration = 250 - ; - - return schviz; -} + } + } + } + + var endParseCbsReq = function(data, frame, cbs, req) { + var idx = +cbs.idx; + var c = data.cbs[idx]; + + var id = +req.id; + var r = data.req[id]; + + if (r.band !== null) { + // deep copy new request state as the second band's element + r.band.push(d3.map(r)); + if (r.band[0].get('ts') < r.band[1].get('ts')) { + data.reqband.push(r.band); + } + } + } + + var finalizeCbs = function(data, ts, c) { + var band = []; + + // deep copy current request state as the first band's element + band.push(d3.map(c)); + + // update current req info + c.ts = ts * timeUnit; + + // deep copy new request state as the second band's element + band.push(d3.map(c)); + if (band[0].get('ts') < band[1].get('ts')) { + data.cbsband.push(band); + } + } + + var finalizeCbsReq = function(data, ts, r) { + var band = []; + + // deep copy current request state as the first band's element + band.push(d3.map(r)); + + // update current req info + r.ts = ts * timeUnit; + + // deep copy new request state as the second band's element + band.push(d3.map(r)); + if (band[0].get('ts') < band[1].get('ts')) { + data.reqband.push(band); + } + } + + var finalize = function(data, ts) { + for (var idx in data.cbs) { + finalizeCbs(data, ts, data.cbs[idx]); + } + for (var id in data.req) { + finalizeCbsReq(data, ts, data.req[id]); + } + } + + var parseFrame = function(data, frame) { + var i, j; + for (i = 0; i < frame.cbs.length; ++i) { + var cbs = frame.cbs[i]; + beginParseCbs(data, frame, cbs); + if (cbs.hasOwnProperty('req')) { + for (j = 0; j < cbs.req.length; ++j) { + var req = cbs.req[j]; + beginParseCbsReq(data, frame, cbs, req); + } + for (j = 0; j < cbs.req.length; ++j) { + var req = cbs.req[j]; + endParseCbsReq(data, frame, cbs, req); + } + } + endParseCbs(data, frame, cbs); + } + } + + var parseKeyframe = function(data, frame) { + // current state + data.cbs = {}; + data.req = {}; + + // data for vizualization + data.cbsband = []; + data.reqband = []; + + // regular frame parse + parseFrame(data, frame); + } + + var parseHistory = function(hist) { + var i, data = {}, + keyframeFound = false; + for (i = 0; i < hist.length; ++i) { + var frame = hist[i]; + if (!keyframeFound) { + if (frame.keyframe) { + keyframeFound = true; + parseKeyframe(data, frame); + } else { + // skip frames before keyframe + } + } else { + if (!frame.keyframe) { + parseFrame(data, frame); + } else { + // skip non-first keyframes + } + } + } + if (hist.length > 1) { + finalize(data, hist[hist.length-1].ts); + } + + // Erase every cbs that has no request + data.cbsband = data.cbsband.filter(x => data.cbs[x[0].get('idx')].band !== null); + Object.keys(data.cbs).forEach(function(key) { + if (data.cbs[key].band === null) { + delete data.cbs[key]; + } + }); + console.log(data); + return data; + } + +// public: + + schviz.draw = function(cbs) { + svg.select("g.x.axis").call(xAxis); + svg.select("g.y.axis").call(yAxis); + return schviz; + } + + schviz.update = function(cbs) { + + var svg = d3.select(".chart"); + var schvizChartGroup = svg.select(".gantt-chart"); + + // update task data attached to rect elements + var rect = schvizChartGroup.selectAll("rect") + .data(cbs, cbsKeyFunction); + + // attach new cbs state + rect.enter() + .insert("rect", ":first-child") + .attr("rx", 5) + .attr("ry", 5) + .attr("class", function(d) { + if (taskStatus[d.status] == null) { + return "bar"; + } + return taskStatus[d.status]; + }) + .transition() + .attr("y", 0) + .attr("transform", rectTransform) + .attr("height", function(d) { + return y.bandwidth(); + }) + .attr("width", function(d) { + return Math.max(1*xPixel, (x(d.endDate) - x(d.startDate))); + }); + + // rearrange current cbs states + rect.transition() + .attr("transform", rectTransform) + .attr("height", function(d) { + return y.bandwidth(); + }) + .attr("width", function(d) { + return Math.max(1*xPixel(), (x(d.endDate) - x(d.startDate))); + }); + + // remove deleted cbs states + rect.exit().remove(); + + // update axes + svg.select(".x").transition().call(xAxis); + svg.select(".y").transition().call(yAxis); + + return schviz; + } + + schviz.margin = function(value) { + if (!arguments.length) + return margin; + margin = value; + return schviz; + } + + schviz.timeDomain = function(value) { + if (!arguments.length) + return [timeDomainStartMs, timeDomainEndMs]; + timeDomainStartMs = value[0]; + timeDomainEndMs = value[1]; + return schviz; + } + + schviz.width = function(value) { + if (!arguments.length) + return width; + width = +value; + return schviz; + } + + schviz.height = function(value) { + if (!arguments.length) + return height; + height = +value; + return schviz; + } + + schviz.selector = function(value) { + if (!arguments.length) + return selector; + selector = value; + return schviz; + } + +// constructor + + var margin = { + top: 20, + right: 40, + bottom: 20, + left: 200, + footer: 100, + }; + var height = document.body.clientHeight - margin.top - margin.bottom - 5; + var width = document.body.clientWidth - margin.right - margin.left - 5; + + var selector = 'body'; + var timeDomainStartMs = 0; + var timeDomainEndMs = 1000; + var timeUnit = 1e-6; + var costFmt = d3.format('.4s'); + var timeFmt = d3.format(',.6r'); + var cbsStateClass = { + "IDLE": "cbs-idle", + "ACTIVE": "cbs-active", + "RUNNING": "cbs-running", + "DEPLETED": "cbs-depleted", + "DEAD": "cbs-dead" + }; + + var x = null, + xZoomed = null, + y = null, + xAxis = null, + yAxis = null, + svg = null, + defs = null, + svgChartContainer = null, + svgChart = null, + zoomPanel = null, + zoomContainer1 = null, + zoomContainer2 = null, + fixedContainer = null, + zoom = null, + cbsSvg = null, + reqSvg = null, + cbsbands = null, + cbsstates = null, + tip = null, + ruler = null, + data = { "bands": d3.map(), "states": d3.map() }, + transDuration = 250 + ; + + return schviz; +} diff --git a/ydb/library/schlab/mon/static/scharm.html b/ydb/library/schlab/mon/static/scharm.html index 469c22adff..279f5b7be9 100644 --- a/ydb/library/schlab/mon/static/scharm.html +++ b/ydb/library/schlab/mon/static/scharm.html @@ -1,89 +1,89 @@ -<!DOCTYPE html> -<html> -<head> - <title>SchArm</title> - <link type="text/css" href="css/bootstrap.min.css" rel="stylesheet" /> - <link type="text/css" href="css/scharm.css" rel="stylesheet" /> -</head> -<body> - -<div class="container"> - <h1>SchArm</h1> - <h3>Request generators</h3> - <div class="row"> - <div class="col-md-12"> - <div id="cfg-table"></div> - </div> - </div> - <div class="row"> - <div class="col-md-12"> - <button class="btn btn-default btn-block" type="button" onclick="scharm.addRow()">Add Generator</button> - </div> - </div> - <div class="row-fluid"> - <div class="form-group"> - <div class="pull-left"> - <div class="btn-group"> +<!DOCTYPE html> +<html> +<head> + <title>SchArm</title> + <link type="text/css" href="css/bootstrap.min.css" rel="stylesheet" /> + <link type="text/css" href="css/scharm.css" rel="stylesheet" /> +</head> +<body> + +<div class="container"> + <h1>SchArm</h1> + <h3>Request generators</h3> + <div class="row"> + <div class="col-md-12"> + <div id="cfg-table"></div> + </div> + </div> + <div class="row"> + <div class="col-md-12"> + <button class="btn btn-default btn-block" type="button" onclick="scharm.addRow()">Add Generator</button> + </div> + </div> + <div class="row-fluid"> + <div class="form-group"> + <div class="pull-left"> + <div class="btn-group"> <button class="btn btn-primary" type="button" onclick="scharm.applyCfg()">Apply</button> - </div> + </div> <div class="btn-group"> - <button id="btnArm" class="btn btn-primary" type="button" onclick="scharm.sendCfg()">Arm</button> + <button id="btnArm" class="btn btn-primary" type="button" onclick="scharm.sendCfg()">Arm</button> </div> - </div> - <div class="pull-right"> - <button class="btn btn-primary" type="button" data-toggle="modal" data-target="#RawModal">Raw</button> - </div> - </div> - </div> - <br/><br/> - <h3>Schedule</h3> - <div class="row"> - <div class="col-md-4"> - <div class="form-group"> - <label class="sr-only" for="throughput">Device throughput (in MBps)</label> - <div class="input-group"> - <div class="input-group-addon">Throughput</div> + </div> + <div class="pull-right"> + <button class="btn btn-primary" type="button" data-toggle="modal" data-target="#RawModal">Raw</button> + </div> + </div> + </div> + <br/><br/> + <h3>Schedule</h3> + <div class="row"> + <div class="col-md-4"> + <div class="form-group"> + <label class="sr-only" for="throughput">Device throughput (in MBps)</label> + <div class="input-group"> + <div class="input-group-addon">Throughput</div> <input type="text" class="form-control" id="throughput" style="text-align:right;" value="100"> - <div class="input-group-addon">MBps</div> - </div> - </div> - </div> - </div> - <div class="row"> - <div class="col-md-12"> - <div id="cfg-chart"></div> - </div> - </div> -</div> - -<div class="modal fade" id="RawModal" tabindex="-1" role="dialog" aria-labelledby="gridSystemModalLabel"> - <div class="modal-dialog" role="document"> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" - data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> - <h4 class="modal-title" id="gridSystemModalLabel">Generators Raw Config</h4> - </div> - <div class="modal-body"> - <div class="form-group"> - <label for="message-text" class="control-label">Raw Config:</label> - <textarea class="form-control" id="cfg-text" rows="25"></textarea> - </div> - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-default" data-dismiss="modal">Dismiss</button> - <button type="button" class="btn btn-primary" id="cfg-save">Save</button> - </div> - </div> - </div> -</div> - -</body> -</html> - -<script type="text/javascript" src="js/jquery.min.js"></script> -<script type="text/javascript" src="js/bootstrap.min.js"></script> -<script type="text/javascript" src="js/d3.v4.min.js"></script> -<script type="text/javascript" src="js/d3-tip-0.8.0-alpha.1.js"></script> -<script type="text/javascript" src="js/scharm.js"></script> -<script type="text/javascript" src="js/scharm-test0.js"></script> + <div class="input-group-addon">MBps</div> + </div> + </div> + </div> + </div> + <div class="row"> + <div class="col-md-12"> + <div id="cfg-chart"></div> + </div> + </div> +</div> + +<div class="modal fade" id="RawModal" tabindex="-1" role="dialog" aria-labelledby="gridSystemModalLabel"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" + data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="gridSystemModalLabel">Generators Raw Config</h4> + </div> + <div class="modal-body"> + <div class="form-group"> + <label for="message-text" class="control-label">Raw Config:</label> + <textarea class="form-control" id="cfg-text" rows="25"></textarea> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Dismiss</button> + <button type="button" class="btn btn-primary" id="cfg-save">Save</button> + </div> + </div> + </div> +</div> + +</body> +</html> + +<script type="text/javascript" src="js/jquery.min.js"></script> +<script type="text/javascript" src="js/bootstrap.min.js"></script> +<script type="text/javascript" src="js/d3.v4.min.js"></script> +<script type="text/javascript" src="js/d3-tip-0.8.0-alpha.1.js"></script> +<script type="text/javascript" src="js/scharm.js"></script> +<script type="text/javascript" src="js/scharm-test0.js"></script> diff --git a/ydb/library/schlab/mon/static/schviz-test0.json b/ydb/library/schlab/mon/static/schviz-test0.json index b687a508b7..8a682edebb 100644 --- a/ydb/library/schlab/mon/static/schviz-test0.json +++ b/ydb/library/schlab/mon/static/schviz-test0.json @@ -1,219 +1,219 @@ -[{ - "ts": 0, - "keyframe": true, - "epochtime": 1500390747, - "cbs": [{ - "idx": 0, - "name": "vdisk0", - "max_budget": 250000000, - "period": 1000000000, - "cur_budget": 250000000, - "deadline": 1000000000, - "state": "RUNNING", - "req": [{ - "id": 1, - "cost": 125000000, - "state": "RUNNING", - "seqno": 1 - }] - },{ - "idx": 1, - "name": "vdisk1", - "max_budget": 250000000, - "period": 1000000000, - "cur_budget": 250000000, - "deadline": 1000000000, - "state": "ACTIVE", - "req": [{ - "id": 2, - "cost": 150000000, - "state": "PENDING", - "kind": "WRITE", - "seqno": 1 - },{ - "id": 3, - "cost": 200000000, - "state": "PENDING", - "kind": "WRITE", - "seqno": 2 - },{ - "id": 4, - "cost": 300000000, - "state": "PENDING", - "kind": "WRITE", - "seqno": 3 - }] - },{ - "idx": 2, - "name": "vdisk2", - "max_budget": 250000000, - "period": 1000000000, - "cur_budget": 250000000, - "deadline": 1000000000, - "state": "ACTIVE", - "req": [{ - "id": 5, - "cost": 100000000, - "state": "PENDING", - "kind": "READ", - "seqno": 1 - },{ - "id": 6, - "cost": 100000000, - "state": "PENDING", - "kind": "READ", - "seqno": 2 - },{ - "id": 7, - "cost": 80000000, - "state": "PENDING", - "kind": "READ", - "seqno": 3 - }] - },{ - "idx": 3, - "name": "vdisk3", - "max_budget": 250000000, - "period": 1000000000, - "cur_budget": 250000000, - "deadline": 1000000000, - "state": "ACTIVE", - "req": [{ - "id": 8, - "cost": 20000000, - "state": "PENDING", - "kind": "READ", - "seqno": 1 - },{ - "id": 9, - "cost": 20000000, - "state": "PENDING", - "kind": "READ", - "seqno": 2 - },{ - "id": 10, - "cost": 20000000, - "state": "PENDING", - "kind": "READ", - "seqno": 3 - }] - }], - "hgrub": { - "uact": 1.0 - } -},{ - "ts": 150000000, - "cbs": [{ - "idx": 0, - "cur_budget": 0, - "state": "IDLE", - "req": [ { "id": 1, "state": "DONE" } ] - }] -},{ - "ts": 250000000, - "cbs": [{ - "idx": 1, - "state": "RUNNING", - "req": [ { "id": 2, "state": "RUNNING" } ] - }] -},{ - "ts": 350000000, - "cbs": [{ - "idx": 1, - "cur_budget": 150000000, - "req": [ { "id": 2, "state": "DONE"}, { "id": 3, "state": "RUNNING"} ] - }] -},{ - "ts": 450000000, - "cbs": [{ - "idx": 1, - "cur_budget": 50000000, - "req": [ { "id": 3, "state": "DONE" }, { "id": 4, "state": "RUNNING"} ] - }] -},{ - "ts": 500000000, - "cbs": [{ - "idx": 1, - "cur_budget": 0, - "state": "DEPLETED", - "req": [ { "id": 4, "cost": 50000000, "state": "PENDING" } ] - },{ - "idx": 2, - "state": "RUNNING", - "req": [ { "id": 5, "state": "RUNNING" } ] - }] -},{ - "ts": 600000000, - "cbs": [{ - "idx": 2, - "cur_budget": 150000000, - "req": [ { "id": 5, "state": "DONE" }, { "id": 6, "state": "RUNNING"} ] - }] -},{ - "ts": 700000000, - "cbs": [{ - "idx": 2, - "cur_budget": 50000000, - "req": [ { "id": 6, "state": "DONE" }, { "id": 7, "state": "RUNNING"} ] - }] -},{ - "ts": 750000000, - "cbs": [{ - "idx": 2, - "cur_budget": 0, - "state": "DEPLETED", - "req": [ { "id": 7, "cost": 60000000, "state": "PENDING" } ] - },{ - "idx": 3, - "state": "RUNNING", - "req": [ { "id": 8, "state": "RUNNING" } ] - }] -},{ - "ts": 770000000, - "cbs": [{ - "idx": 3, - "cur_budget": 230000000, - "req": [ { "id": 8, "state": "DONE" }, { "id": 9, "state": "RUNNING"} ] - }] -},{ - "ts": 790000000, - "cbs": [{ - "idx": 3, - "cur_budget": 210000000, - "req": [ { "id": 9, "state": "DONE" }, { "id": 10, "state": "RUNNING"} ] - }] -},{ - "ts": 810000000, - "cbs": [{ - "idx": 1, - "req": [ { "id": 4, "state": "RUNNING" } ] - },{ - "idx": 3, - "cur_budget": 190000000, - "req": [ { "id": 10, "state": "DONE" } ] - }] -},{ - "ts": 860000000, - "cbs": [{ - "idx": 1, - "state": "IDLE", - "req": [ { "id": 4, "state": "DONE" } ] - },{ - "idx": 2, - "req": [ { "id": 7, "state": "RUNNING" } ] - },{ - "idx": 3, - "cur_budget": 140000000 - }] -},{ - "ts": 910000000, - "cbs": [{ - "idx": 2, - "state": "IDLE", - "req": [ { "id": 7, "state": "DONE" } ] - },{ - "idx": 3, - "cur_budget": 90000000, - "state": "IDLE" - }] -}] +[{ + "ts": 0, + "keyframe": true, + "epochtime": 1500390747, + "cbs": [{ + "idx": 0, + "name": "vdisk0", + "max_budget": 250000000, + "period": 1000000000, + "cur_budget": 250000000, + "deadline": 1000000000, + "state": "RUNNING", + "req": [{ + "id": 1, + "cost": 125000000, + "state": "RUNNING", + "seqno": 1 + }] + },{ + "idx": 1, + "name": "vdisk1", + "max_budget": 250000000, + "period": 1000000000, + "cur_budget": 250000000, + "deadline": 1000000000, + "state": "ACTIVE", + "req": [{ + "id": 2, + "cost": 150000000, + "state": "PENDING", + "kind": "WRITE", + "seqno": 1 + },{ + "id": 3, + "cost": 200000000, + "state": "PENDING", + "kind": "WRITE", + "seqno": 2 + },{ + "id": 4, + "cost": 300000000, + "state": "PENDING", + "kind": "WRITE", + "seqno": 3 + }] + },{ + "idx": 2, + "name": "vdisk2", + "max_budget": 250000000, + "period": 1000000000, + "cur_budget": 250000000, + "deadline": 1000000000, + "state": "ACTIVE", + "req": [{ + "id": 5, + "cost": 100000000, + "state": "PENDING", + "kind": "READ", + "seqno": 1 + },{ + "id": 6, + "cost": 100000000, + "state": "PENDING", + "kind": "READ", + "seqno": 2 + },{ + "id": 7, + "cost": 80000000, + "state": "PENDING", + "kind": "READ", + "seqno": 3 + }] + },{ + "idx": 3, + "name": "vdisk3", + "max_budget": 250000000, + "period": 1000000000, + "cur_budget": 250000000, + "deadline": 1000000000, + "state": "ACTIVE", + "req": [{ + "id": 8, + "cost": 20000000, + "state": "PENDING", + "kind": "READ", + "seqno": 1 + },{ + "id": 9, + "cost": 20000000, + "state": "PENDING", + "kind": "READ", + "seqno": 2 + },{ + "id": 10, + "cost": 20000000, + "state": "PENDING", + "kind": "READ", + "seqno": 3 + }] + }], + "hgrub": { + "uact": 1.0 + } +},{ + "ts": 150000000, + "cbs": [{ + "idx": 0, + "cur_budget": 0, + "state": "IDLE", + "req": [ { "id": 1, "state": "DONE" } ] + }] +},{ + "ts": 250000000, + "cbs": [{ + "idx": 1, + "state": "RUNNING", + "req": [ { "id": 2, "state": "RUNNING" } ] + }] +},{ + "ts": 350000000, + "cbs": [{ + "idx": 1, + "cur_budget": 150000000, + "req": [ { "id": 2, "state": "DONE"}, { "id": 3, "state": "RUNNING"} ] + }] +},{ + "ts": 450000000, + "cbs": [{ + "idx": 1, + "cur_budget": 50000000, + "req": [ { "id": 3, "state": "DONE" }, { "id": 4, "state": "RUNNING"} ] + }] +},{ + "ts": 500000000, + "cbs": [{ + "idx": 1, + "cur_budget": 0, + "state": "DEPLETED", + "req": [ { "id": 4, "cost": 50000000, "state": "PENDING" } ] + },{ + "idx": 2, + "state": "RUNNING", + "req": [ { "id": 5, "state": "RUNNING" } ] + }] +},{ + "ts": 600000000, + "cbs": [{ + "idx": 2, + "cur_budget": 150000000, + "req": [ { "id": 5, "state": "DONE" }, { "id": 6, "state": "RUNNING"} ] + }] +},{ + "ts": 700000000, + "cbs": [{ + "idx": 2, + "cur_budget": 50000000, + "req": [ { "id": 6, "state": "DONE" }, { "id": 7, "state": "RUNNING"} ] + }] +},{ + "ts": 750000000, + "cbs": [{ + "idx": 2, + "cur_budget": 0, + "state": "DEPLETED", + "req": [ { "id": 7, "cost": 60000000, "state": "PENDING" } ] + },{ + "idx": 3, + "state": "RUNNING", + "req": [ { "id": 8, "state": "RUNNING" } ] + }] +},{ + "ts": 770000000, + "cbs": [{ + "idx": 3, + "cur_budget": 230000000, + "req": [ { "id": 8, "state": "DONE" }, { "id": 9, "state": "RUNNING"} ] + }] +},{ + "ts": 790000000, + "cbs": [{ + "idx": 3, + "cur_budget": 210000000, + "req": [ { "id": 9, "state": "DONE" }, { "id": 10, "state": "RUNNING"} ] + }] +},{ + "ts": 810000000, + "cbs": [{ + "idx": 1, + "req": [ { "id": 4, "state": "RUNNING" } ] + },{ + "idx": 3, + "cur_budget": 190000000, + "req": [ { "id": 10, "state": "DONE" } ] + }] +},{ + "ts": 860000000, + "cbs": [{ + "idx": 1, + "state": "IDLE", + "req": [ { "id": 4, "state": "DONE" } ] + },{ + "idx": 2, + "req": [ { "id": 7, "state": "RUNNING" } ] + },{ + "idx": 3, + "cur_budget": 140000000 + }] +},{ + "ts": 910000000, + "cbs": [{ + "idx": 2, + "state": "IDLE", + "req": [ { "id": 7, "state": "DONE" } ] + },{ + "idx": 3, + "cur_budget": 90000000, + "state": "IDLE" + }] +}] diff --git a/ydb/library/schlab/mon/static/schviz0.html b/ydb/library/schlab/mon/static/schviz0.html index 656b57f57e..05e8741977 100644 --- a/ydb/library/schlab/mon/static/schviz0.html +++ b/ydb/library/schlab/mon/static/schviz0.html @@ -1,258 +1,258 @@ -<!DOCTYPE html> -<html> -<head> - <title>SchViz</title> - <link type="text/css" href="css/schviz.css" rel="stylesheet" /> -</head> -<body> -</body> -</html> - -<script type="text/javascript" src="js/d3.v4.min.js"></script> -<script type="text/javascript" src="js/d3-tip-0.8.0-alpha.1.js"></script> -<script type="text/javascript" src="js/schviz.js"></script> -<script type="text/javascript"> - var hist = [{ - "ts": 0, - "keyframe": true, - "epochtime": 1500390747, - "cbs": [{ - "idx": 0, - "name": "vdisk0", - "max_budget": 250000000, - "period": 1000000000, - "cur_budget": 250000000, - "deadline": 1000000000, - "state": "RUNNING", - "req": [{ - "id": 1, - "cost": 125000000, - "state": "RUNNING", - "seqno": 1 - }] - },{ - "idx": 1, - "name": "vdisk1", - "max_budget": 250000000, - "period": 1000000000, - "cur_budget": 250000000, - "deadline": 1000000000, - "state": "ACTIVE", - "req": [{ - "id": 2, - "cost": 150000000, - "state": "PENDING", - "kind": "WRITE", - "seqno": 1 - },{ - "id": 3, - "cost": 200000000, - "state": "PENDING", - "kind": "WRITE", - "seqno": 2 - },{ - "id": 4, - "cost": 300000000, - "state": "PENDING", - "kind": "WRITE", - "seqno": 3 - }] - },{ - "idx": 2, - "name": "vdisk2", - "max_budget": 250000000, - "period": 1000000000, - "cur_budget": 250000000, - "deadline": 1000000000, - "state": "ACTIVE", - "req": [{ - "id": 5, - "cost": 100000000, - "state": "PENDING", - "kind": "READ", - "seqno": 1 - },{ - "id": 6, - "cost": 100000000, - "state": "PENDING", - "kind": "READ", - "seqno": 2 - },{ - "id": 7, - "cost": 80000000, - "state": "PENDING", - "kind": "READ", - "seqno": 3 - }] - },{ - "idx": 3, - "name": "vdisk3", - "max_budget": 250000000, - "period": 1000000000, - "cur_budget": 250000000, - "deadline": 1000000000, - "state": "ACTIVE", - "req": [{ - "id": 8, - "cost": 20000000, - "state": "PENDING", - "kind": "READ", - "seqno": 1 - },{ - "id": 9, - "cost": 20000000, - "state": "PENDING", - "kind": "READ", - "seqno": 2 - },{ - "id": 10, - "cost": 20000000, - "state": "PENDING", - "kind": "READ", - "seqno": 3 - }] - }], - "hgrub": { - "uact": 1.0 - } - },{ - "ts": 150000000, - "cbs": [{ - "idx": 0, - "cur_budget": 0, - "state": "IDLE", - "req": [ { "id": 1, "state": "DONE" } ] - }] - },{ - "ts": 250000000, - "cbs": [{ - "idx": 1, - "state": "RUNNING", - "req": [ { "id": 2, "state": "RUNNING" } ] - }] - },{ - "ts": 350000000, - "cbs": [{ - "idx": 1, - "cur_budget": 150000000, - "req": [ { "id": 2, "state": "DONE"}, { "id": 3, "state": "RUNNING"} ] - }] - },{ - "ts": 450000000, - "cbs": [{ - "idx": 1, - "cur_budget": 50000000, - "req": [ { "id": 3, "state": "DONE" }, { "id": 4, "state": "RUNNING"} ] - }] - },{ - "ts": 500000000, - "cbs": [{ - "idx": 1, - "cur_budget": 0, - "state": "DEPLETED", - "req": [ { "id": 4, "cost": 50000000, "state": "PENDING" } ] - },{ - "idx": 2, - "state": "RUNNING", - "req": [ { "id": 5, "state": "RUNNING" } ] - }] - },{ - "ts": 600000000, - "cbs": [{ - "idx": 2, - "cur_budget": 150000000, - "req": [ { "id": 5, "state": "DONE" }, { "id": 6, "state": "RUNNING"} ] - }] - },{ - "ts": 700000000, - "cbs": [{ - "idx": 2, - "cur_budget": 50000000, - "req": [ { "id": 6, "state": "DONE" }, { "id": 7, "state": "RUNNING"} ] - }] - },{ - "ts": 750000000, - "cbs": [{ - "idx": 2, - "cur_budget": 0, - "state": "DEPLETED", - "req": [ { "id": 7, "cost": 60000000, "state": "PENDING" } ] - },{ - "idx": 3, - "state": "RUNNING", - "req": [ { "id": 8, "state": "RUNNING" } ] - }] - },{ - "ts": 770000000, - "cbs": [{ - "idx": 3, - "cur_budget": 230000000, - "req": [ { "id": 8, "state": "DONE" }, { "id": 9, "state": "RUNNING"} ] - }] - },{ - "ts": 790000000, - "cbs": [{ - "idx": 3, - "cur_budget": 210000000, - "req": [ { "id": 9, "state": "DONE" }, { "id": 10, "state": "RUNNING"} ] - }] - },{ - "ts": 810000000, - "cbs": [{ - "idx": 1, - "req": [ { "id": 4, "state": "RUNNING" } ] - },{ - "idx": 3, - "cur_budget": 190000000, - "req": [ { "id": 10, "state": "DONE" } ] - }] - },{ - "ts": 860000000, - "cbs": [{ - "idx": 1, - "state": "IDLE", - "req": [ { "id": 4, "state": "DONE" } ] - },{ - "idx": 2, - "req": [ { "id": 7, "state": "RUNNING" } ] - },{ - "idx": 3, - "cur_budget": 140000000 - }] - },{ - "ts": 910000000, - "cbs": [{ - "idx": 2, - "state": "IDLE", - "req": [ { "id": 7, "state": "DONE" } ] - },{ - "idx": 3, - "cur_budget": 90000000, - "state": "IDLE" - }] - }]; - - var linesCount = 15; - for (var i = 4; i < linesCount; i++) { - hist[0].cbs.push({ - "idx": i, - "name": "vdisk" + i, - "max_budget": 250000000, - "period": 1000000000, - "cur_budget": 250000000, - "deadline": Math.random()*1000000000, - "state": "ACTIVE", - "req": [{ - "id": 1, - "cost": 125000000, - "state": "RUNNING", - "seqno": 1 - }] - }); - } - - var schviz = d3.schviz().height(600).width(800); - - schviz.timeDomain([0, 1000]); - schviz(hist); -</script> +<!DOCTYPE html> +<html> +<head> + <title>SchViz</title> + <link type="text/css" href="css/schviz.css" rel="stylesheet" /> +</head> +<body> +</body> +</html> + +<script type="text/javascript" src="js/d3.v4.min.js"></script> +<script type="text/javascript" src="js/d3-tip-0.8.0-alpha.1.js"></script> +<script type="text/javascript" src="js/schviz.js"></script> +<script type="text/javascript"> + var hist = [{ + "ts": 0, + "keyframe": true, + "epochtime": 1500390747, + "cbs": [{ + "idx": 0, + "name": "vdisk0", + "max_budget": 250000000, + "period": 1000000000, + "cur_budget": 250000000, + "deadline": 1000000000, + "state": "RUNNING", + "req": [{ + "id": 1, + "cost": 125000000, + "state": "RUNNING", + "seqno": 1 + }] + },{ + "idx": 1, + "name": "vdisk1", + "max_budget": 250000000, + "period": 1000000000, + "cur_budget": 250000000, + "deadline": 1000000000, + "state": "ACTIVE", + "req": [{ + "id": 2, + "cost": 150000000, + "state": "PENDING", + "kind": "WRITE", + "seqno": 1 + },{ + "id": 3, + "cost": 200000000, + "state": "PENDING", + "kind": "WRITE", + "seqno": 2 + },{ + "id": 4, + "cost": 300000000, + "state": "PENDING", + "kind": "WRITE", + "seqno": 3 + }] + },{ + "idx": 2, + "name": "vdisk2", + "max_budget": 250000000, + "period": 1000000000, + "cur_budget": 250000000, + "deadline": 1000000000, + "state": "ACTIVE", + "req": [{ + "id": 5, + "cost": 100000000, + "state": "PENDING", + "kind": "READ", + "seqno": 1 + },{ + "id": 6, + "cost": 100000000, + "state": "PENDING", + "kind": "READ", + "seqno": 2 + },{ + "id": 7, + "cost": 80000000, + "state": "PENDING", + "kind": "READ", + "seqno": 3 + }] + },{ + "idx": 3, + "name": "vdisk3", + "max_budget": 250000000, + "period": 1000000000, + "cur_budget": 250000000, + "deadline": 1000000000, + "state": "ACTIVE", + "req": [{ + "id": 8, + "cost": 20000000, + "state": "PENDING", + "kind": "READ", + "seqno": 1 + },{ + "id": 9, + "cost": 20000000, + "state": "PENDING", + "kind": "READ", + "seqno": 2 + },{ + "id": 10, + "cost": 20000000, + "state": "PENDING", + "kind": "READ", + "seqno": 3 + }] + }], + "hgrub": { + "uact": 1.0 + } + },{ + "ts": 150000000, + "cbs": [{ + "idx": 0, + "cur_budget": 0, + "state": "IDLE", + "req": [ { "id": 1, "state": "DONE" } ] + }] + },{ + "ts": 250000000, + "cbs": [{ + "idx": 1, + "state": "RUNNING", + "req": [ { "id": 2, "state": "RUNNING" } ] + }] + },{ + "ts": 350000000, + "cbs": [{ + "idx": 1, + "cur_budget": 150000000, + "req": [ { "id": 2, "state": "DONE"}, { "id": 3, "state": "RUNNING"} ] + }] + },{ + "ts": 450000000, + "cbs": [{ + "idx": 1, + "cur_budget": 50000000, + "req": [ { "id": 3, "state": "DONE" }, { "id": 4, "state": "RUNNING"} ] + }] + },{ + "ts": 500000000, + "cbs": [{ + "idx": 1, + "cur_budget": 0, + "state": "DEPLETED", + "req": [ { "id": 4, "cost": 50000000, "state": "PENDING" } ] + },{ + "idx": 2, + "state": "RUNNING", + "req": [ { "id": 5, "state": "RUNNING" } ] + }] + },{ + "ts": 600000000, + "cbs": [{ + "idx": 2, + "cur_budget": 150000000, + "req": [ { "id": 5, "state": "DONE" }, { "id": 6, "state": "RUNNING"} ] + }] + },{ + "ts": 700000000, + "cbs": [{ + "idx": 2, + "cur_budget": 50000000, + "req": [ { "id": 6, "state": "DONE" }, { "id": 7, "state": "RUNNING"} ] + }] + },{ + "ts": 750000000, + "cbs": [{ + "idx": 2, + "cur_budget": 0, + "state": "DEPLETED", + "req": [ { "id": 7, "cost": 60000000, "state": "PENDING" } ] + },{ + "idx": 3, + "state": "RUNNING", + "req": [ { "id": 8, "state": "RUNNING" } ] + }] + },{ + "ts": 770000000, + "cbs": [{ + "idx": 3, + "cur_budget": 230000000, + "req": [ { "id": 8, "state": "DONE" }, { "id": 9, "state": "RUNNING"} ] + }] + },{ + "ts": 790000000, + "cbs": [{ + "idx": 3, + "cur_budget": 210000000, + "req": [ { "id": 9, "state": "DONE" }, { "id": 10, "state": "RUNNING"} ] + }] + },{ + "ts": 810000000, + "cbs": [{ + "idx": 1, + "req": [ { "id": 4, "state": "RUNNING" } ] + },{ + "idx": 3, + "cur_budget": 190000000, + "req": [ { "id": 10, "state": "DONE" } ] + }] + },{ + "ts": 860000000, + "cbs": [{ + "idx": 1, + "state": "IDLE", + "req": [ { "id": 4, "state": "DONE" } ] + },{ + "idx": 2, + "req": [ { "id": 7, "state": "RUNNING" } ] + },{ + "idx": 3, + "cur_budget": 140000000 + }] + },{ + "ts": 910000000, + "cbs": [{ + "idx": 2, + "state": "IDLE", + "req": [ { "id": 7, "state": "DONE" } ] + },{ + "idx": 3, + "cur_budget": 90000000, + "state": "IDLE" + }] + }]; + + var linesCount = 15; + for (var i = 4; i < linesCount; i++) { + hist[0].cbs.push({ + "idx": i, + "name": "vdisk" + i, + "max_budget": 250000000, + "period": 1000000000, + "cur_budget": 250000000, + "deadline": Math.random()*1000000000, + "state": "ACTIVE", + "req": [{ + "id": 1, + "cost": 125000000, + "state": "RUNNING", + "seqno": 1 + }] + }); + } + + var schviz = d3.schviz().height(600).width(800); + + schviz.timeDomain([0, 1000]); + schviz(hist); +</script> diff --git a/ydb/library/schlab/mon/static/schviz1.html b/ydb/library/schlab/mon/static/schviz1.html index 3d7d6c8d96..766395700c 100644 --- a/ydb/library/schlab/mon/static/schviz1.html +++ b/ydb/library/schlab/mon/static/schviz1.html @@ -1,21 +1,21 @@ -<!DOCTYPE html> -<html> -<head> - <title>SchViz</title> - <link type="text/css" href="css/schviz.css" rel="stylesheet" /> -</head> -<body> -</body> -</html> - -<script type="text/javascript" src="js/d3.v4.min.js"></script> -<script type="text/javascript" src="js/d3-tip-0.8.0-alpha.1.js"></script> -<script type="text/javascript" src="js/schviz.js"></script> -<script type="text/javascript"> - var dataUrl = "http://kikimr0031.search.yandex.net:8765/actors/pdisks/pdisk000000001?mode=getschedule"; - d3.json(dataUrl, function(data) { - var schviz = d3.schviz(); - schviz.timeDomain([0, 1000]); - schviz(data); - }); -</script> +<!DOCTYPE html> +<html> +<head> + <title>SchViz</title> + <link type="text/css" href="css/schviz.css" rel="stylesheet" /> +</head> +<body> +</body> +</html> + +<script type="text/javascript" src="js/d3.v4.min.js"></script> +<script type="text/javascript" src="js/d3-tip-0.8.0-alpha.1.js"></script> +<script type="text/javascript" src="js/schviz.js"></script> +<script type="text/javascript"> + var dataUrl = "http://kikimr0031.search.yandex.net:8765/actors/pdisks/pdisk000000001?mode=getschedule"; + d3.json(dataUrl, function(data) { + var schviz = d3.schviz(); + schviz.timeDomain([0, 1000]); + schviz(data); + }); +</script> diff --git a/ydb/library/schlab/mon/test/test.cpp b/ydb/library/schlab/mon/test/test.cpp index 64bf719d9a..9133da1f28 100644 --- a/ydb/library/schlab/mon/test/test.cpp +++ b/ydb/library/schlab/mon/test/test.cpp @@ -3,63 +3,63 @@ #include <library/cpp/monlib/service/monservice.h> #include <library/cpp/monlib/service/pages/resource_mon_page.h> #include <library/cpp/resource/resource.h> - -namespace { - -// Config -int g_MonPort = 8080; - -} - -#define SCHLAB_STATIC_FILE(mon, file, type) \ - mon->Register(new TResourceMonPage(file, file, NMonitoring::TResourceMonPage::type)); \ - /**/ - -int main(int argc, char** argv) -{ - using namespace NMonitoring; - - try { -#if defined(_unix_) || defined(_darwin_) - signal(SIGPIPE, SIG_IGN); -#endif - -#ifdef _win32_ - WSADATA dummy; - WSAStartup(MAKEWORD(2,2), &dummy); -#endif - - // Configure - using TMonSrvc = NMonitoring::TMonService2; - THolder<TMonSrvc> MonSrvc; - NLastGetopt::TOpts opts = NLastGetopt::TOpts::Default(); - opts.AddLongOption(0, "mon-port", "port of monitoring service") - .RequiredArgument("port") - .StoreResult(&g_MonPort, g_MonPort); - NLastGetopt::TOptsParseResult res(&opts, argc, argv); - - // Init monservice + +namespace { + +// Config +int g_MonPort = 8080; + +} + +#define SCHLAB_STATIC_FILE(mon, file, type) \ + mon->Register(new TResourceMonPage(file, file, NMonitoring::TResourceMonPage::type)); \ + /**/ + +int main(int argc, char** argv) +{ + using namespace NMonitoring; + + try { +#if defined(_unix_) || defined(_darwin_) + signal(SIGPIPE, SIG_IGN); +#endif + +#ifdef _win32_ + WSADATA dummy; + WSAStartup(MAKEWORD(2,2), &dummy); +#endif + + // Configure + using TMonSrvc = NMonitoring::TMonService2; + THolder<TMonSrvc> MonSrvc; + NLastGetopt::TOpts opts = NLastGetopt::TOpts::Default(); + opts.AddLongOption(0, "mon-port", "port of monitoring service") + .RequiredArgument("port") + .StoreResult(&g_MonPort, g_MonPort); + NLastGetopt::TOptsParseResult res(&opts, argc, argv); + + // Init monservice TString schArmJson; - MonSrvc.Reset(new TMonSrvc(g_MonPort)); - SCHLAB_STATIC_FILE(MonSrvc.Get(), "schlab/schviz-test0.json", JSON); - NKikimr::CreateSchLabCommonPages(MonSrvc.Get()); - NKikimr::CreateSchArmPages(MonSrvc.Get(), "schlab/scharm", "/schlab/schviz"); + MonSrvc.Reset(new TMonSrvc(g_MonPort)); + SCHLAB_STATIC_FILE(MonSrvc.Get(), "schlab/schviz-test0.json", JSON); + NKikimr::CreateSchLabCommonPages(MonSrvc.Get()); + NKikimr::CreateSchArmPages(MonSrvc.Get(), "schlab/scharm", "/schlab/schviz"); NKikimr::CreateSchVizPages(MonSrvc.Get(), "schlab/schviz", "/schlab/scharm?mode=getschedule"); - - // Start monservice - MonSrvc->Start(); - - // Infinite loop - while (true) { - Sleep(TDuration::Seconds(1)); - } - - // Finish - Cout << "bye" << Endl; - return 0; - } catch (...) { - Cerr << "failure: " << CurrentExceptionMessage() << Endl; - return 1; - } -} + + // Start monservice + MonSrvc->Start(); + + // Infinite loop + while (true) { + Sleep(TDuration::Seconds(1)); + } + + // Finish + Cout << "bye" << Endl; + return 0; + } catch (...) { + Cerr << "failure: " << CurrentExceptionMessage() << Endl; + return 1; + } +} diff --git a/ydb/library/schlab/mon/test/ya.make b/ydb/library/schlab/mon/test/ya.make index bc282bfcf4..1dde888361 100644 --- a/ydb/library/schlab/mon/test/ya.make +++ b/ydb/library/schlab/mon/test/ya.make @@ -1,22 +1,22 @@ -PROGRAM() - +PROGRAM() + OWNER( serxa g:kikimr ) - -RESOURCE( - ../static/schviz-test0.json schlab/schviz-test0.json -) - -SRCS( - test.cpp -) - -PEERDIR( + +RESOURCE( + ../static/schviz-test0.json schlab/schviz-test0.json +) + +SRCS( + test.cpp +) + +PEERDIR( library/cpp/getopt library/cpp/monlib/dynamic_counters ydb/library/schlab/mon -) - -END() +) + +END() diff --git a/ydb/library/schlab/mon/ya.make b/ydb/library/schlab/mon/ya.make index ca05b8cdc3..ad89be6c5e 100644 --- a/ydb/library/schlab/mon/ya.make +++ b/ydb/library/schlab/mon/ya.make @@ -1,40 +1,40 @@ -LIBRARY() - +LIBRARY() + OWNER( serxa g:kikimr ) - -RESOURCE( - static/css/bootstrap.min.css schlab/css/bootstrap.min.css - static/css/scharm.css schlab/css/scharm.css - static/css/schviz.css schlab/css/schviz.css - static/js/jquery.min.js schlab/js/jquery.min.js - static/js/bootstrap.min.js schlab/js/bootstrap.min.js - static/js/d3-tip-0.8.0-alpha.1.js schlab/js/d3-tip-0.8.0-alpha.1.js - static/js/d3.v4.min.js schlab/js/d3.v4.min.js - static/js/scharm.js schlab/js/scharm.js - static/js/schviz.js schlab/js/schviz.js + +RESOURCE( + static/css/bootstrap.min.css schlab/css/bootstrap.min.css + static/css/scharm.css schlab/css/scharm.css + static/css/schviz.css schlab/css/schviz.css + static/js/jquery.min.js schlab/js/jquery.min.js + static/js/bootstrap.min.js schlab/js/bootstrap.min.js + static/js/d3-tip-0.8.0-alpha.1.js schlab/js/d3-tip-0.8.0-alpha.1.js + static/js/d3.v4.min.js schlab/js/d3.v4.min.js + static/js/scharm.js schlab/js/scharm.js + static/js/schviz.js schlab/js/schviz.js static/js/scharm-test0.js schlab/js/scharm-test0.js - static/scharm.html schlab/scharm.html -) - -SRCS( - mon.cpp -) - -PEERDIR( + static/scharm.html schlab/scharm.html +) + +SRCS( + mon.cpp +) + +PEERDIR( library/cpp/html/pcdata library/cpp/monlib/dynamic_counters library/cpp/resource ydb/library/schlab/schemu -) - -END() - -RECURSE( - test +) + +END() + +RECURSE( + test static static/css static/js -) +) diff --git a/ydb/library/schlab/probes/ya.make b/ydb/library/schlab/probes/ya.make index c3b87eb5df..38c2eaf60c 100644 --- a/ydb/library/schlab/probes/ya.make +++ b/ydb/library/schlab/probes/ya.make @@ -1,17 +1,17 @@ -LIBRARY() - +LIBRARY() + OWNER( cthulhu g:kikimr ) - -PEERDIR( + +PEERDIR( library/cpp/lwtrace -) - -SRCS( - probes.cpp - probes.h -) - -END() +) + +SRCS( + probes.cpp + probes.h +) + +END() diff --git a/ydb/library/schlab/schine/bin_log.h b/ydb/library/schlab/schine/bin_log.h index 8abe61ccd8..78d896bf13 100644 --- a/ydb/library/schlab/schine/bin_log.h +++ b/ydb/library/schlab/schine/bin_log.h @@ -75,5 +75,5 @@ public: }; -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/cbs.cpp b/ydb/library/schlab/schine/cbs.cpp index b0dcbae11f..71f646a7e3 100644 --- a/ydb/library/schlab/schine/cbs.cpp +++ b/ydb/library/schlab/schine/cbs.cpp @@ -82,5 +82,5 @@ void TCbs::DeleteJobs() { JobsSize = 0; } -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/cbs.h b/ydb/library/schlab/schine/cbs.h index c71073200b..59adc7a9a3 100644 --- a/ydb/library/schlab/schine/cbs.h +++ b/ydb/library/schlab/schine/cbs.h @@ -51,5 +51,5 @@ protected: void DeleteJobs(); }; -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/cbs_bin.cpp b/ydb/library/schlab/schine/cbs_bin.cpp index 37f5bafdb3..ed9d7b49d6 100644 --- a/ydb/library/schlab/schine/cbs_bin.cpp +++ b/ydb/library/schlab/schine/cbs_bin.cpp @@ -75,5 +75,5 @@ bool TCbsBin::AppendKeyframe(const TCbs &cur) { return false; } -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/cbs_bin.h b/ydb/library/schlab/schine/cbs_bin.h index 176649dca0..0e20fb717f 100644 --- a/ydb/library/schlab/schine/cbs_bin.h +++ b/ydb/library/schlab/schine/cbs_bin.h @@ -61,5 +61,5 @@ struct TCbsBin { }; }; -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/cbs_state.cpp b/ydb/library/schlab/schine/cbs_state.cpp index 32f4fbd16f..c0a6d8912b 100644 --- a/ydb/library/schlab/schine/cbs_state.cpp +++ b/ydb/library/schlab/schine/cbs_state.cpp @@ -20,5 +20,5 @@ const char* CbsStateName(ECbsState state) { } } -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/cbs_state.h b/ydb/library/schlab/schine/cbs_state.h index 19b6288a88..8f126268a2 100644 --- a/ydb/library/schlab/schine/cbs_state.h +++ b/ydb/library/schlab/schine/cbs_state.h @@ -14,5 +14,5 @@ enum ECbsState { const char* CbsStateName(ECbsState state); -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/job.cpp b/ydb/library/schlab/schine/job.cpp index 241bd5579e..c1ab6424f2 100644 --- a/ydb/library/schlab/schine/job.cpp +++ b/ydb/library/schlab/schine/job.cpp @@ -3,5 +3,5 @@ namespace NKikimr { namespace NSchLab { -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/job.h b/ydb/library/schlab/schine/job.h index 5f53be107a..586746e551 100644 --- a/ydb/library/schlab/schine/job.h +++ b/ydb/library/schlab/schine/job.h @@ -24,5 +24,5 @@ struct TJob : TSimpleRefCount<TJob> { bool IsNew = true; }; -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/job_kind.cpp b/ydb/library/schlab/schine/job_kind.cpp index b6285303e6..afbc7c0e19 100644 --- a/ydb/library/schlab/schine/job_kind.cpp +++ b/ydb/library/schlab/schine/job_kind.cpp @@ -14,5 +14,5 @@ const char* JobKindName(EJobKind kind) { } } -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/job_kind.h b/ydb/library/schlab/schine/job_kind.h index 6077f37468..b404e17cf9 100644 --- a/ydb/library/schlab/schine/job_kind.h +++ b/ydb/library/schlab/schine/job_kind.h @@ -12,5 +12,5 @@ enum EJobKind { const char* JobKindName(EJobKind kind); -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/job_state.cpp b/ydb/library/schlab/schine/job_state.cpp index 513a839d3f..f9b1d8b401 100644 --- a/ydb/library/schlab/schine/job_state.cpp +++ b/ydb/library/schlab/schine/job_state.cpp @@ -16,5 +16,5 @@ const char* JobStateName(EJobState state) { } } -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/job_state.h b/ydb/library/schlab/schine/job_state.h index cbe8aac0ca..4397b1961e 100644 --- a/ydb/library/schlab/schine/job_state.h +++ b/ydb/library/schlab/schine/job_state.h @@ -12,5 +12,5 @@ enum EJobState { const char* JobStateName(EJobState state); -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/name_table.h b/ydb/library/schlab/schine/name_table.h index 3653c0702d..3b35cc5374 100644 --- a/ydb/library/schlab/schine/name_table.h +++ b/ydb/library/schlab/schine/name_table.h @@ -33,5 +33,5 @@ public: }; -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/scheduler.cpp b/ydb/library/schlab/schine/scheduler.cpp index dfd012a41c..ec75b6868b 100644 --- a/ydb/library/schlab/schine/scheduler.cpp +++ b/ydb/library/schlab/schine/scheduler.cpp @@ -1,7 +1,7 @@ #include "scheduler.h" #include <library/cpp/lwtrace/all.h> - + #include <library/cpp/lwtrace/mon/mon_lwtrace.h> #include <ydb/library/schlab/probes/probes.h> @@ -555,5 +555,5 @@ bool TScheduler::IsEmpty() { return true; } -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/scheduler.h b/ydb/library/schlab/schine/scheduler.h index 684b9110ed..cbd7ce5b50 100644 --- a/ydb/library/schlab/schine/scheduler.h +++ b/ydb/library/schlab/schine/scheduler.h @@ -82,5 +82,5 @@ protected: ui32 NewCbs(); }; -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/schlog.cpp b/ydb/library/schlab/schine/schlog.cpp index 14b303603f..e7a75151fd 100644 --- a/ydb/library/schlab/schine/schlog.cpp +++ b/ydb/library/schlab/schine/schlog.cpp @@ -339,5 +339,5 @@ void TSchLog::Output(IOutputStream &out, const TNameTable &nameTable) { out << "]"; } -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/schlog.h b/ydb/library/schlab/schine/schlog.h index e127690ad0..1f4e40faa0 100644 --- a/ydb/library/schlab/schine/schlog.h +++ b/ydb/library/schlab/schine/schlog.h @@ -107,5 +107,5 @@ struct TSchLog { void Output(IOutputStream &out, const TNameTable &nameTable); }; -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/schine/schlog_frame.h b/ydb/library/schlab/schine/schlog_frame.h index cee85531eb..2fe5c14835 100644 --- a/ydb/library/schlab/schine/schlog_frame.h +++ b/ydb/library/schlab/schine/schlog_frame.h @@ -13,5 +13,5 @@ enum EFrameType { FrameTypeRemoveJob }; -} // NSchLab -} // NKikimr +} // NSchLab +} // NKikimr diff --git a/ydb/library/schlab/ya.make b/ydb/library/schlab/ya.make index 2a3a11b5f8..f2910cfc4d 100644 --- a/ydb/library/schlab/ya.make +++ b/ydb/library/schlab/ya.make @@ -16,10 +16,10 @@ SRCS( ) END() - -RECURSE( - mon - probes + +RECURSE( + mon + probes protos schemu schine @@ -28,4 +28,4 @@ RECURSE( RECURSE_FOR_TESTS( ut -) +) diff --git a/ydb/library/yql/utils/actor_log/ya.make b/ydb/library/yql/utils/actor_log/ya.make index cae3dcc827..e1c665db7b 100644 --- a/ydb/library/yql/utils/actor_log/ya.make +++ b/ydb/library/yql/utils/actor_log/ya.make @@ -7,7 +7,7 @@ SRCS( ) PEERDIR( - library/cpp/actors/core + library/cpp/actors/core library/cpp/actors/protos ydb/core/protos ) diff --git a/ydb/public/api/protos/ydb_clickhouse_internal.proto b/ydb/public/api/protos/ydb_clickhouse_internal.proto index 0f9e685ed3..17ecc9d1a1 100644 --- a/ydb/public/api/protos/ydb_clickhouse_internal.proto +++ b/ydb/public/api/protos/ydb_clickhouse_internal.proto @@ -23,11 +23,11 @@ message ScanRequest { uint64 max_bytes = 9; string snapshot_id = 10; -} +} message ScanResponse { Ydb.Operations.Operation operation = 1; -} +} message ScanResult { repeated bytes blocks = 1; @@ -35,18 +35,18 @@ message ScanResult { bool eos = 2; // no more rows bytes last_key = 3; bool last_key_inclusive = 4; -} +} message GetShardLocationsRequest { Ydb.Operations.OperationParams operation_params = 1; repeated uint64 tablet_ids = 2; -} +} message GetShardLocationsResponse { Ydb.Operations.Operation operation = 1; -} +} message TabletInfo { uint64 tablet_id = 1; @@ -56,7 +56,7 @@ message TabletInfo { message GetShardLocationsResult { repeated TabletInfo tablets = 1; -} +} message DescribeTableRequest { Ydb.Operations.OperationParams operation_params = 1; diff --git a/ydb/public/api/protos/ydb_cms.proto b/ydb/public/api/protos/ydb_cms.proto index 1a569c7081..2778ed08f0 100644 --- a/ydb/public/api/protos/ydb_cms.proto +++ b/ydb/public/api/protos/ydb_cms.proto @@ -133,12 +133,12 @@ message GetDatabaseStatusRequest { string path = 1; // Operation parameters Ydb.Operations.OperationParams operation_params = 2; -} +} message GetDatabaseStatusResponse { // operation.result holds GetDatabaseStatusResult Ydb.Operations.Operation operation = 1; -} +} message GetDatabaseStatusResult { enum State { @@ -171,7 +171,7 @@ message GetDatabaseStatusResult { SchemaOperationQuotas schema_operation_quotas = 9; // Current quotas for the database DatabaseQuotas database_quotas = 10; -} +} // Change resources allocated for database. message AlterDatabaseRequest { diff --git a/ydb/public/api/protos/ydb_common.proto b/ydb/public/api/protos/ydb_common.proto index a63e202f82..e12686040c 100644 --- a/ydb/public/api/protos/ydb_common.proto +++ b/ydb/public/api/protos/ydb_common.proto @@ -11,7 +11,7 @@ message FeatureFlag { ENABLED = 1; DISABLED = 2; } -} +} message CostInfo { // Total amount of request units (RU), consumed by the operation. diff --git a/ydb/public/api/protos/ydb_coordination.proto b/ydb/public/api/protos/ydb_coordination.proto index 378045e78e..57cbeaa8ff 100644 --- a/ydb/public/api/protos/ydb_coordination.proto +++ b/ydb/public/api/protos/ydb_coordination.proto @@ -460,7 +460,7 @@ message CreateNodeRequest { message CreateNodeResponse { Ydb.Operations.Operation operation = 1; -} +} message AlterNodeRequest { string path = 1; @@ -470,7 +470,7 @@ message AlterNodeRequest { message AlterNodeResponse { Ydb.Operations.Operation operation = 1; -} +} message DropNodeRequest { string path = 1; @@ -479,7 +479,7 @@ message DropNodeRequest { message DropNodeResponse { Ydb.Operations.Operation operation = 1; -} +} message DescribeNodeRequest { string path = 1; diff --git a/ydb/public/api/protos/ydb_discovery.proto b/ydb/public/api/protos/ydb_discovery.proto index 5577dafe36..db4ecd49d8 100644 --- a/ydb/public/api/protos/ydb_discovery.proto +++ b/ydb/public/api/protos/ydb_discovery.proto @@ -12,7 +12,7 @@ message ListEndpointsRequest { repeated string service = 2; // todo: feature flags -} +} message EndpointInfo { // This is an address (usually fqdn) and port of this node's grpc endpoint @@ -34,16 +34,16 @@ message EndpointInfo { // endpoint is using certificate chain valid for a balancer hostname, and // not this specific node hostname. string ssl_target_name_override = 10; -} +} message ListEndpointsResult { repeated EndpointInfo endpoints = 1; string self_location = 2; -} +} message ListEndpointsResponse { Ydb.Operations.Operation operation = 1; -} +} message WhoAmIRequest { // Include user groups in response diff --git a/ydb/public/api/protos/ydb_experimental.proto b/ydb/public/api/protos/ydb_experimental.proto index 94eed9671b..d204597bd6 100644 --- a/ydb/public/api/protos/ydb_experimental.proto +++ b/ydb/public/api/protos/ydb_experimental.proto @@ -23,13 +23,13 @@ message ExecuteStreamQueryRequest { ProfileMode profile_mode = 3; bool explain = 4; -} +} message ExecuteStreamQueryResponse { StatusIds.StatusCode status = 1; repeated Ydb.Issue.IssueMessage issues = 2; ExecuteStreamQueryResult result = 3; -} +} message StreamQueryProgress { } @@ -41,4 +41,4 @@ message ExecuteStreamQueryResult { StreamQueryProgress progress = 3; string query_plan = 4; } -} +} diff --git a/ydb/public/api/protos/ydb_rate_limiter.proto b/ydb/public/api/protos/ydb_rate_limiter.proto index c18430c32b..c192805580 100644 --- a/ydb/public/api/protos/ydb_rate_limiter.proto +++ b/ydb/public/api/protos/ydb_rate_limiter.proto @@ -32,17 +32,17 @@ message HierarchicalDrrSettings { // 0 is equivalent to not set. // Must be nonnegative. double max_burst_size_coefficient = 2; - - // Prefetch in local bucket up to prefetch_coefficient*max_units_per_second units (full size). - // Default value is inherited from parent or 0.2 for root. - // Disables prefetching if any negative value is set - // (It is useful to avoid bursts in case of large number of local buckets). - double prefetch_coefficient = 3; - - // Prefetching starts if there is less than prefetch_watermark fraction of full local bucket left. - // Default value is inherited from parent or 0.75 for root. - // Must be nonnegative and less than or equal to 1. - double prefetch_watermark = 4; + + // Prefetch in local bucket up to prefetch_coefficient*max_units_per_second units (full size). + // Default value is inherited from parent or 0.2 for root. + // Disables prefetching if any negative value is set + // (It is useful to avoid bursts in case of large number of local buckets). + double prefetch_coefficient = 3; + + // Prefetching starts if there is less than prefetch_watermark fraction of full local bucket left. + // Default value is inherited from parent or 0.75 for root. + // Must be nonnegative and less than or equal to 1. + double prefetch_watermark = 4; } // Rate limiter resource description. diff --git a/ydb/public/api/protos/ydb_s3_internal.proto b/ydb/public/api/protos/ydb_s3_internal.proto index 0f12fe6302..ff3626bf7e 100644 --- a/ydb/public/api/protos/ydb_s3_internal.proto +++ b/ydb/public/api/protos/ydb_s3_internal.proto @@ -18,14 +18,14 @@ message S3ListingRequest { repeated string columns_to_return = 7; Ydb.Operations.OperationParams operation_params = 8; -} +} message S3ListingResponse { Ydb.Operations.Operation operation = 1; -} +} message S3ListingResult { Ydb.ResultSet common_prefixes = 1; // Every Contents row starts with key suffix with KeySuffixSize columns Ydb.ResultSet contents = 2; // Every Contents row starts with key suffix with KeySuffixSize columns uint32 key_suffix_size = 3; // Number of key columns starting from path and up to the end -} +} diff --git a/ydb/public/api/protos/ydb_scheme.proto b/ydb/public/api/protos/ydb_scheme.proto index d66b765725..4f71e4c8a4 100644 --- a/ydb/public/api/protos/ydb_scheme.proto +++ b/ydb/public/api/protos/ydb_scheme.proto @@ -12,38 +12,38 @@ import "ydb/public/api/protos/ydb_operation.proto"; message MakeDirectoryRequest { Ydb.Operations.OperationParams operation_params = 1; string path = 2; -} +} message MakeDirectoryResponse { Ydb.Operations.Operation operation = 1; -} +} // Remove directory message RemoveDirectoryRequest { Ydb.Operations.OperationParams operation_params = 1; string path = 2; -} +} message RemoveDirectoryResponse { Ydb.Operations.Operation operation = 1; -} +} // List directory message ListDirectoryRequest { Ydb.Operations.OperationParams operation_params = 1; string path = 2; -} +} message ListDirectoryResponse { // Holds ListDirectoryResult in case of successful call Ydb.Operations.Operation operation = 1; -} +} message Permissions { // SID (Security ID) of user or group string subject = 1; repeated string permission_names = 2; -} +} message Entry { enum Type { @@ -57,7 +57,7 @@ message Entry { COORDINATION_NODE = 7; SEQUENCE = 15; REPLICATION = 16; - } + } // Name of scheme entry (dir2 of /dir1/dir2) string name = 1; @@ -72,27 +72,27 @@ message Entry { // - DATABASE. // Empty (zero) in other cases. uint64 size_bytes = 8; -} +} message ListDirectoryResult { Entry self = 1; repeated Entry children = 2; -} +} // Returns information about object with given path message DescribePathRequest { Ydb.Operations.OperationParams operation_params = 1; string path = 2; -} +} message DescribePathResponse { // Holds DescribePathResult in case of DescribePathResult Ydb.Operations.Operation operation = 1; -} +} message DescribePathResult { Entry self = 1; -} +} message PermissionsAction { oneof action { @@ -105,7 +105,7 @@ message PermissionsAction { // New owner for object string change_owner = 4; } -} +} // Modify permissions of given object message ModifyPermissionsRequest { @@ -114,8 +114,8 @@ message ModifyPermissionsRequest { repeated PermissionsAction actions = 3; // Clear all permissions on the object for all subjects bool clear_permissions = 4; -} +} message ModifyPermissionsResponse { Ydb.Operations.Operation operation = 1; -} +} diff --git a/ydb/public/api/protos/ydb_scripting.proto b/ydb/public/api/protos/ydb_scripting.proto index 4c1a295418..4a87d9e5af 100644 --- a/ydb/public/api/protos/ydb_scripting.proto +++ b/ydb/public/api/protos/ydb_scripting.proto @@ -19,16 +19,16 @@ message ExecuteYqlRequest { string script = 2; map<string, TypedValue> parameters = 3; Ydb.Table.QueryStatsCollection.Mode collect_stats = 4; -} +} message ExecuteYqlResponse { Ydb.Operations.Operation operation = 1; -} +} message ExecuteYqlResult { repeated Ydb.ResultSet result_sets = 1; Ydb.TableStats.QueryStats query_stats = 2; -} +} // Response for StreamExecuteYql is a stream of ExecuteYqlPartialResponse messages. // These responses can contain ExecuteYqlPartialResult messages with diff --git a/ydb/public/api/protos/ydb_table.proto b/ydb/public/api/protos/ydb_table.proto index c8063d9475..7a48ea8cce 100644 --- a/ydb/public/api/protos/ydb_table.proto +++ b/ydb/public/api/protos/ydb_table.proto @@ -20,32 +20,32 @@ option java_package = "com.yandex.ydb.table"; // Create new session message CreateSessionRequest { Ydb.Operations.OperationParams operation_params = 1; -} +} // Create new session message CreateSessionResponse { // Holds CreateSessionResult in case of CreateSessionResult Ydb.Operations.Operation operation = 1; -} +} message CreateSessionResult { // Session identifier string session_id = 1; -} +} // Delete session with given id string message DeleteSessionRequest { // Session identifier string session_id = 1; Ydb.Operations.OperationParams operation_params = 2; -} +} message DeleteSessionResponse { Ydb.Operations.Operation operation = 1; -} +} message GlobalIndex { -} +} message GlobalAsyncIndex { } @@ -63,7 +63,7 @@ message TableIndex { } // list of columns content to be copied in to index table repeated string data_columns = 5; -} +} // Represent secondary index with index state message TableIndexDescription { @@ -119,7 +119,7 @@ message IndexBuildMetadata { message StoragePool { string media = 1; -} +} message StoragePolicy { string preset_name = 1; @@ -129,7 +129,7 @@ message StoragePolicy { StoragePool external = 5; Ydb.FeatureFlag.Status keep_in_memory = 6; repeated ColumnFamilyPolicy column_families = 7; -} +} message ColumnFamilyPolicy { enum Compression { @@ -156,7 +156,7 @@ message ColumnFamilyPolicy { message CompactionPolicy { string preset_name = 1; -} +} message ExplicitPartitions { // Specify key values used to split table into partitions. @@ -165,7 +165,7 @@ message ExplicitPartitions { // Total number of created partitions is number of specified // keys + 1. repeated TypedValue split_points = 1; -} +} message PartitionStats { // Approximate number of rows in shard @@ -207,11 +207,11 @@ message PartitioningPolicy { // created partitions. ExplicitPartitions explicit_partitions = 4; } -} +} message ExecutionPolicy { string preset_name = 1; -} +} message ReplicationPolicy { string preset_name = 1; @@ -225,11 +225,11 @@ message ReplicationPolicy { // If this feature in enabled then read-only replicas can be promoted // to leader. Ydb.FeatureFlag.Status allow_promotion = 4; -} +} message CachingPolicy { string preset_name = 1; -} +} message TableProfile { string preset_name = 1; @@ -239,7 +239,7 @@ message TableProfile { ExecutionPolicy execution_policy = 5; ReplicationPolicy replication_policy = 6; CachingPolicy caching_policy = 7; -} +} message ColumnMeta { // Name of column @@ -248,7 +248,7 @@ message ColumnMeta { Type type = 2; // Column family name of the column string family = 3; -} +} message DateTypeColumnModeSettings { // The row will be considered as expired at the moment of time, when the value @@ -431,11 +431,11 @@ message CreateTableRequest { Ydb.FeatureFlag.Status key_bloom_filter = 16; // Read replicas settings for table ReadReplicasSettings read_replicas_settings = 17; -} +} message CreateTableResponse { Ydb.Operations.Operation operation = 1; -} +} // Drop table with given path message DropTableRequest { @@ -445,11 +445,11 @@ message DropTableRequest { string path = 2; reserved 3; Ydb.Operations.OperationParams operation_params = 4; -} +} message DropTableResponse { Ydb.Operations.Operation operation = 1; -} +} // Alter table with given path message AlterTableRequest { @@ -490,11 +490,11 @@ message AlterTableRequest { Ydb.FeatureFlag.Status set_key_bloom_filter = 17; // Set read replicas settings for table ReadReplicasSettings set_read_replicas_settings = 18; -} +} message AlterTableResponse { Ydb.Operations.Operation operation = 1; -} +} // Copy table with given path message CopyTableRequest { @@ -505,11 +505,11 @@ message CopyTableRequest { // Copy to path string destination_path = 3; Ydb.Operations.OperationParams operation_params = 4; -} +} message CopyTableResponse { Ydb.Operations.Operation operation = 1; -} +} message CopyTableItem { // Copy from path @@ -518,7 +518,7 @@ message CopyTableItem { string destination_path = 2; // Copy options bool omit_indexes = 3; -} +} // Creates consistent copy of given tables. message CopyTablesRequest { @@ -527,11 +527,11 @@ message CopyTablesRequest { string session_id = 2; // Source and destination paths which describe copies repeated CopyTableItem tables = 3; -} +} message CopyTablesResponse { Ydb.Operations.Operation operation = 1; -} +} message RenameTableItem { // Full path @@ -568,12 +568,12 @@ message DescribeTableRequest { bool include_table_stats = 6; // Includes partition statistics (required include_table_statistics) bool include_partition_stats = 7; -} +} message DescribeTableResponse { // Holds DescribeTableResult in case of successful call Ydb.Operations.Operation operation = 1; -} +} message DescribeTableResult { // Description of scheme object @@ -604,7 +604,7 @@ message DescribeTableResult { Ydb.FeatureFlag.Status key_bloom_filter = 13; // Read replicas settings for table ReadReplicasSettings read_replicas_settings = 14; -} +} message Query { // Text of query or id prepared query @@ -617,11 +617,11 @@ message Query { } message SerializableModeSettings { -} +} message OnlineModeSettings { bool allow_inconsistent_reads = 1; -} +} message StaleModeSettings { } @@ -645,7 +645,7 @@ message TransactionControl { message QueryCachePolicy { bool keep_in_cache = 1; -} +} // Collect and return query execution stats message QueryStatsCollection { @@ -667,11 +667,11 @@ message ExecuteDataQueryRequest { QueryCachePolicy query_cache_policy = 5; Ydb.Operations.OperationParams operation_params = 6; QueryStatsCollection.Mode collect_stats = 7; -} +} message ExecuteDataQueryResponse { Ydb.Operations.Operation operation = 1; -} +} message ExecuteSchemeQueryRequest { // Session identifier @@ -679,11 +679,11 @@ message ExecuteSchemeQueryRequest { // SQL text string yql_text = 2; Ydb.Operations.OperationParams operation_params = 3; -} +} message ExecuteSchemeQueryResponse { Ydb.Operations.Operation operation = 1; -} +} // Holds transaction id message TransactionMeta { @@ -709,7 +709,7 @@ message ExecuteQueryResult { QueryMeta query_meta = 3; // Query execution statistics Ydb.TableStats.QueryStats query_stats = 4; -} +} // Explain data query message ExplainDataQueryRequest { @@ -718,17 +718,17 @@ message ExplainDataQueryRequest { // SQL text to explain string yql_text = 2; Ydb.Operations.OperationParams operation_params = 3; -} +} message ExplainDataQueryResponse { // Holds ExplainQueryResult in case of successful call Ydb.Operations.Operation operation = 1; -} +} message ExplainQueryResult { string query_ast = 1; string query_plan = 2; -} +} // Prepare given program to execute message PrepareDataQueryRequest { @@ -737,30 +737,30 @@ message PrepareDataQueryRequest { // SQL text string yql_text = 2; Ydb.Operations.OperationParams operation_params = 3; -} +} message PrepareDataQueryResponse { // Holds PrepareQueryResult in case of successful call Ydb.Operations.Operation operation = 1; -} +} message PrepareQueryResult { // Query id, used to perform ExecuteDataQuery string query_id = 1; // Parameters type, used to fill in parameter values map<string, Type> parameters_types = 2; -} +} // Keep session alive message KeepAliveRequest { // Session identifier string session_id = 1; Ydb.Operations.OperationParams operation_params = 2; -} +} message KeepAliveResponse { Ydb.Operations.Operation operation = 1; -} +} message KeepAliveResult { enum SessionStatus { @@ -770,7 +770,7 @@ message KeepAliveResult { } SessionStatus session_status = 1; -} +} // Begin transaction on given session with given settings message BeginTransactionRequest { @@ -778,16 +778,16 @@ message BeginTransactionRequest { string session_id = 1; TransactionSettings tx_settings = 2; Ydb.Operations.OperationParams operation_params = 3; -} +} message BeginTransactionResponse { // Holds BeginTransactionResult in case of successful call Ydb.Operations.Operation operation = 1; -} +} message BeginTransactionResult { TransactionMeta tx_meta = 1; -} +} // Commit transaction with given session and tx id message CommitTransactionRequest { @@ -797,11 +797,11 @@ message CommitTransactionRequest { string tx_id = 2; Ydb.Operations.OperationParams operation_params = 3; QueryStatsCollection.Mode collect_stats = 4; -} +} message CommitTransactionResponse { Ydb.Operations.Operation operation = 1; -} +} message CommitTransactionResult { Ydb.TableStats.QueryStats query_stats = 1; @@ -814,11 +814,11 @@ message RollbackTransactionRequest { // Transaction identifier string tx_id = 2; Ydb.Operations.OperationParams operation_params = 3; -} +} message RollbackTransactionResponse { Ydb.Operations.Operation operation = 1; -} +} message StoragePolicyDescription { string name = 1; @@ -904,7 +904,7 @@ message KeyRange { // Specify if we want to include given key TypedValue less_or_equal = 4; } -} +} // Request to read table (without SQL) message ReadTableRequest { @@ -922,7 +922,7 @@ message ReadTableRequest { uint64 row_limit = 6; // Use a server-side snapshot Ydb.FeatureFlag.Status use_snapshot = 7; -} +} // ReadTable doesn't use Operation, returns result directly message ReadTableResponse { @@ -932,13 +932,13 @@ message ReadTableResponse { repeated Ydb.Issue.IssueMessage issues = 2; // Read table result ReadTableResult result = 3; -} +} // Result of read table request message ReadTableResult { // Result set (same as result of sql request) Ydb.ResultSet result_set = 1; -} +} message BulkUpsertRequest { string table = 1; diff --git a/ydb/public/api/protos/ydb_value.proto b/ydb/public/api/protos/ydb_value.proto index d885d73f8e..149014eeaa 100644 --- a/ydb/public/api/protos/ydb_value.proto +++ b/ydb/public/api/protos/ydb_value.proto @@ -148,14 +148,14 @@ message Value { message TypedValue { Type type = 1; Value value = 2; -} +} message Column { // Name of column string name = 1; // Type of column Type type = 2; -} +} // Represents table-like structure with ordered set of rows and columns message ResultSet { @@ -165,4 +165,4 @@ message ResultSet { repeated Value rows = 2; // Flag indicates the result was truncated bool truncated = 3; -} +} diff --git a/ydb/public/sdk/cpp/client/ydb_rate_limiter/rate_limiter.cpp b/ydb/public/sdk/cpp/client/ydb_rate_limiter/rate_limiter.cpp index bea557812c..61cdeb27bc 100644 --- a/ydb/public/sdk/cpp/client/ydb_rate_limiter/rate_limiter.cpp +++ b/ydb/public/sdk/cpp/client/ydb_rate_limiter/rate_limiter.cpp @@ -30,14 +30,14 @@ TDescribeResourceResult::THierarchicalDrrProps::THierarchicalDrrProps(const Ydb: if (settings.max_burst_size_coefficient()) { MaxBurstSizeCoefficient_ = settings.max_burst_size_coefficient(); } - - if (settings.prefetch_coefficient()) { - PrefetchCoefficient_ = settings.prefetch_coefficient(); - } - - if (settings.prefetch_watermark()) { - PrefetchWatermark_ = settings.prefetch_watermark(); - } + + if (settings.prefetch_coefficient()) { + PrefetchCoefficient_ = settings.prefetch_coefficient(); + } + + if (settings.prefetch_watermark()) { + PrefetchWatermark_ = settings.prefetch_watermark(); + } } class TRateLimiterClient::TImpl : public TClientImplCommon<TRateLimiterClient::TImpl> { @@ -62,12 +62,12 @@ public: if (settings.MaxBurstSizeCoefficient_) { hdrr.set_max_burst_size_coefficient(*settings.MaxBurstSizeCoefficient_); } - if (settings.PrefetchCoefficient_) { - hdrr.set_prefetch_coefficient(*settings.PrefetchCoefficient_); - } - if (settings.PrefetchWatermark_) { - hdrr.set_prefetch_watermark(*settings.PrefetchWatermark_); - } + if (settings.PrefetchCoefficient_) { + hdrr.set_prefetch_coefficient(*settings.PrefetchCoefficient_); + } + if (settings.PrefetchWatermark_) { + hdrr.set_prefetch_watermark(*settings.PrefetchWatermark_); + } return request; } diff --git a/ydb/public/sdk/cpp/client/ydb_rate_limiter/rate_limiter.h b/ydb/public/sdk/cpp/client/ydb_rate_limiter/rate_limiter.h index dca90fbe63..fe14a27834 100644 --- a/ydb/public/sdk/cpp/client/ydb_rate_limiter/rate_limiter.h +++ b/ydb/public/sdk/cpp/client/ydb_rate_limiter/rate_limiter.h @@ -27,21 +27,21 @@ struct THierarchicalDrrSettings : public TOperationRequestSettings<TDerived> { // This means that maximum burst size might be equal to max_units_per_second. // Must be nonnegative. FLUENT_SETTING_OPTIONAL(double, MaxBurstSizeCoefficient); - - // Prefetch in local bucket up to PrefetchCoefficient*MaxUnitsPerSecond units (full size). - // Default value is inherited from parent or 0.2 for root. - // Disables prefetching if any negative value is set - // (It is useful to avoid bursts in case of large number of local buckets). - FLUENT_SETTING_OPTIONAL(double, PrefetchCoefficient); - - void DisablePrefetching() { - PrefetchCoefficient_ = -1.0; - } - - // Prefetching starts if there is less than PrefetchWatermark fraction of full local bucket left. - // Default value is inherited from parent or 0.75 for root. - // Must be nonnegative and less than or equal to 1. - FLUENT_SETTING_OPTIONAL(double, PrefetchWatermark); + + // Prefetch in local bucket up to PrefetchCoefficient*MaxUnitsPerSecond units (full size). + // Default value is inherited from parent or 0.2 for root. + // Disables prefetching if any negative value is set + // (It is useful to avoid bursts in case of large number of local buckets). + FLUENT_SETTING_OPTIONAL(double, PrefetchCoefficient); + + void DisablePrefetching() { + PrefetchCoefficient_ = -1.0; + } + + // Prefetching starts if there is less than PrefetchWatermark fraction of full local bucket left. + // Default value is inherited from parent or 0.75 for root. + // Must be nonnegative and less than or equal to 1. + FLUENT_SETTING_OPTIONAL(double, PrefetchWatermark); }; // Settings for create resource request. @@ -105,21 +105,21 @@ struct TDescribeResourceResult : public TStatus { return MaxBurstSizeCoefficient_; } - // Prefetch in local bucket up to PrefetchCoefficient*MaxUnitsPerSecond units (full size). - TMaybe<double> GetPrefetchCoefficient() const { - return PrefetchCoefficient_; - } - - // Prefetching starts if there is less than PrefetchWatermark fraction of full local bucket left. - TMaybe<double> GetPrefetchWatermark() const { - return PrefetchWatermark_; - } - + // Prefetch in local bucket up to PrefetchCoefficient*MaxUnitsPerSecond units (full size). + TMaybe<double> GetPrefetchCoefficient() const { + return PrefetchCoefficient_; + } + + // Prefetching starts if there is less than PrefetchWatermark fraction of full local bucket left. + TMaybe<double> GetPrefetchWatermark() const { + return PrefetchWatermark_; + } + private: TMaybe<double> MaxUnitsPerSecond_; TMaybe<double> MaxBurstSizeCoefficient_; - TMaybe<double> PrefetchCoefficient_; - TMaybe<double> PrefetchWatermark_; + TMaybe<double> PrefetchCoefficient_; + TMaybe<double> PrefetchWatermark_; }; TDescribeResourceResult(TStatus status, const Ydb::RateLimiter::DescribeResourceResult& result); |