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 /library/cpp | |
parent | 8d57b69dee81198a59c39e64704f7dc9f04b4fbf (diff) | |
download | ydb-d6d7db348c2cc64e71243cab9940ee6778f4317d.tar.gz |
Restoring authorship annotation for <serxa@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'library/cpp')
172 files changed, 17873 insertions, 17873 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); } } |