aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/lwtrace
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/lwtrace
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/lwtrace')
-rw-r--r--library/cpp/lwtrace/all.h195
-rw-r--r--library/cpp/lwtrace/check.cpp18
-rw-r--r--library/cpp/lwtrace/check.h78
-rw-r--r--library/cpp/lwtrace/control.cpp97
-rw-r--r--library/cpp/lwtrace/control.h351
-rw-r--r--library/cpp/lwtrace/custom_action.cpp21
-rw-r--r--library/cpp/lwtrace/custom_action.h75
-rw-r--r--library/cpp/lwtrace/event.h29
-rw-r--r--library/cpp/lwtrace/example1/example_query.tr10
-rw-r--r--library/cpp/lwtrace/example1/lwtrace_example1.cpp39
-rwxr-xr-xlibrary/cpp/lwtrace/example1/start_with_query.sh3
-rw-r--r--library/cpp/lwtrace/example1/ya.make13
-rw-r--r--library/cpp/lwtrace/example2/destructive.tr36
-rw-r--r--library/cpp/lwtrace/example2/empty.tr0
-rw-r--r--library/cpp/lwtrace/example2/example_query.tr79
-rw-r--r--library/cpp/lwtrace/example2/lwtrace_example2.cpp117
-rw-r--r--library/cpp/lwtrace/example2/ya.make14
-rw-r--r--library/cpp/lwtrace/example3/example_query.tr13
-rw-r--r--library/cpp/lwtrace/example3/lwtrace_example3.cpp43
-rw-r--r--library/cpp/lwtrace/example3/my_action.h85
-rwxr-xr-xlibrary/cpp/lwtrace/example3/start_with_query.sh6
-rw-r--r--library/cpp/lwtrace/example3/ya.make13
-rw-r--r--library/cpp/lwtrace/example4/example_query.tr10
-rw-r--r--library/cpp/lwtrace/example4/lwtrace_example4.cpp49
-rwxr-xr-xlibrary/cpp/lwtrace/example4/start_with_query.sh3
-rw-r--r--library/cpp/lwtrace/example4/ya.make13
-rw-r--r--library/cpp/lwtrace/example5/example_query.tr9
-rw-r--r--library/cpp/lwtrace/example5/lwtrace_example5.cpp30
-rwxr-xr-xlibrary/cpp/lwtrace/example5/start_with_query.sh3
-rw-r--r--library/cpp/lwtrace/example5/ya.make13
-rw-r--r--library/cpp/lwtrace/kill_action.cpp21
-rw-r--r--library/cpp/lwtrace/kill_action.h15
-rw-r--r--library/cpp/lwtrace/log.h906
-rw-r--r--library/cpp/lwtrace/log_shuttle.cpp67
-rw-r--r--library/cpp/lwtrace/log_shuttle.h359
-rw-r--r--library/cpp/lwtrace/lwprobe.h110
-rw-r--r--library/cpp/lwtrace/mon/analytics/all.h8
-rw-r--r--library/cpp/lwtrace/mon/analytics/analytics.cpp5
-rw-r--r--library/cpp/lwtrace/mon/analytics/csv_output.h52
-rw-r--r--library/cpp/lwtrace/mon/analytics/data.h108
-rw-r--r--library/cpp/lwtrace/mon/analytics/html_output.h86
-rw-r--r--library/cpp/lwtrace/mon/analytics/json_output.h98
-rw-r--r--library/cpp/lwtrace/mon/analytics/transform.h204
-rw-r--r--library/cpp/lwtrace/mon/analytics/util.h122
-rw-r--r--library/cpp/lwtrace/mon/analytics/ya.make15
-rw-r--r--library/cpp/lwtrace/mon/mon_lwtrace.cpp4723
-rw-r--r--library/cpp/lwtrace/mon/mon_lwtrace.h27
-rw-r--r--library/cpp/lwtrace/mon/static/analytics.css68
-rw-r--r--library/cpp/lwtrace/mon/static/analytics.flot.html49
-rw-r--r--library/cpp/lwtrace/mon/static/analytics.gantt.html26
-rw-r--r--library/cpp/lwtrace/mon/static/analytics.header.html21
-rw-r--r--library/cpp/lwtrace/mon/static/analytics.js561
-rw-r--r--library/cpp/lwtrace/mon/static/common.css3
-rw-r--r--library/cpp/lwtrace/mon/static/common.js17
-rw-r--r--library/cpp/lwtrace/mon/static/css/bootstrap.min.css9
-rw-r--r--library/cpp/lwtrace/mon/static/css/d3-gantt.css68
-rw-r--r--library/cpp/lwtrace/mon/static/css/jquery.treegrid.css8
-rw-r--r--library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.eotbin0 -> 20127 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg288
-rw-r--r--library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttfbin0 -> 45404 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woffbin0 -> 23424 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2bin0 -> 18028 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/footer.html0
-rw-r--r--library/cpp/lwtrace/mon/static/header.html11
-rw-r--r--library/cpp/lwtrace/mon/static/img/collapse.pngbin0 -> 2886 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/img/expand.pngbin0 -> 2894 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/img/file.pngbin0 -> 342 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/img/folder.pngbin0 -> 537 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/js/bootstrap.min.js9
-rw-r--r--library/cpp/lwtrace/mon/static/js/d3-gantt.js759
-rw-r--r--library/cpp/lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js352
-rw-r--r--library/cpp/lwtrace/mon/static/js/d3.v4.min.js2
-rw-r--r--library/cpp/lwtrace/mon/static/js/filesaver.min.js1
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js196
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.flot.min.js8
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.flot.navigate.min.js7
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.flot.selection.min.js7
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.min.js5
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js4
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.treegrid.min.js2
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.url.min.js1
-rwxr-xr-xlibrary/cpp/lwtrace/mon/trace.sh81
-rw-r--r--library/cpp/lwtrace/mon/ya.make55
-rw-r--r--library/cpp/lwtrace/param_traits.h66
-rw-r--r--library/cpp/lwtrace/perf.cpp84
-rw-r--r--library/cpp/lwtrace/perf.h63
-rw-r--r--library/cpp/lwtrace/preprocessor.h295
-rw-r--r--library/cpp/lwtrace/probe.h266
-rw-r--r--library/cpp/lwtrace/probes.cpp3
-rw-r--r--library/cpp/lwtrace/probes.h23
-rw-r--r--library/cpp/lwtrace/protos/lwtrace.proto266
-rw-r--r--library/cpp/lwtrace/protos/ya.make11
-rw-r--r--library/cpp/lwtrace/rwspinlock.h88
-rw-r--r--library/cpp/lwtrace/shuttle.cpp20
-rw-r--r--library/cpp/lwtrace/shuttle.h358
-rw-r--r--library/cpp/lwtrace/signature.h772
-rw-r--r--library/cpp/lwtrace/sleep_action.cpp15
-rw-r--r--library/cpp/lwtrace/sleep_action.h21
-rw-r--r--library/cpp/lwtrace/start.cpp69
-rw-r--r--library/cpp/lwtrace/start.h11
-rw-r--r--library/cpp/lwtrace/stderr_writer.cpp19
-rw-r--r--library/cpp/lwtrace/stderr_writer.h19
-rw-r--r--library/cpp/lwtrace/symbol.cpp15
-rw-r--r--library/cpp/lwtrace/symbol.h68
-rwxr-xr-xlibrary/cpp/lwtrace/tests/test_all_parallel.sh29
-rw-r--r--library/cpp/lwtrace/tests/trace_tests.cpp715
-rw-r--r--library/cpp/lwtrace/tests/ya.make15
-rw-r--r--library/cpp/lwtrace/trace.cpp1051
-rw-r--r--library/cpp/lwtrace/trace_ut.cpp880
-rw-r--r--library/cpp/lwtrace/ut/ya.make11
-rw-r--r--library/cpp/lwtrace/ya.make29
111 files changed, 16291 insertions, 0 deletions
diff --git a/library/cpp/lwtrace/all.h b/library/cpp/lwtrace/all.h
new file mode 100644
index 0000000000..d7aa57c49d
--- /dev/null
+++ b/library/cpp/lwtrace/all.h
@@ -0,0 +1,195 @@
+#pragma once
+
+#include "control.h"
+#include "event.h"
+#include "preprocessor.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
+// 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__)
+#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 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 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
diff --git a/library/cpp/lwtrace/check.cpp b/library/cpp/lwtrace/check.cpp
new file mode 100644
index 0000000000..4e34fc5d49
--- /dev/null
+++ b/library/cpp/lwtrace/check.cpp
@@ -0,0 +1,18 @@
+#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);
+}
diff --git a/library/cpp/lwtrace/check.h b/library/cpp/lwtrace/check.h
new file mode 100644
index 0000000000..71503cbc7b
--- /dev/null
+++ b/library/cpp/lwtrace/check.h
@@ -0,0 +1,78 @@
+#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;
+ }
+ };
+
+}
diff --git a/library/cpp/lwtrace/control.cpp b/library/cpp/lwtrace/control.cpp
new file mode 100644
index 0000000000..d9404ff269
--- /dev/null
+++ b/library/cpp/lwtrace/control.cpp
@@ -0,0 +1,97 @@
+#include "probes.h"
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#include <util/generic/string.h>
+
+namespace NLWTrace {
+
+LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER);
+
+TProbeMap TManager::GetProbesMap() {
+ class TProbeReader
+ {
+ private:
+ TProbeMap& Result;
+
+ public:
+ TProbeReader(TProbeMap& result)
+ : Result(result)
+ {}
+
+ void Push(NLWTrace::TProbe* probe)
+ {
+ Result[std::make_pair(probe->Event.Name, probe->Event.GetProvider())] = probe;
+ }
+ };
+
+ TProbeMap result;
+
+ auto reader = TProbeReader(result);
+ ReadProbes(reader);
+ return result;
+}
+
+void TManager::CreateTraceRequest(TTraceRequest& msg, TOrbit& orbit)
+{
+ msg.SetIsTraced(orbit.HasShuttles());
+}
+
+bool TManager::HandleTraceRequest(
+ const TTraceRequest& msg,
+ TOrbit& orbit)
+{
+ if (!msg.GetIsTraced()) {
+ return false;
+ }
+ TParams params;
+ SerializingExecutor->Execute(orbit, params);
+ return true;
+}
+
+TTraceDeserializeStatus TManager::HandleTraceResponse(
+ const TTraceResponse& msg,
+ const TProbeMap& probesMap,
+ TOrbit& orbit,
+ i64 timeOffset,
+ double timeScale)
+{
+ TTraceDeserializeStatus result;
+ if (!msg.GetTrace().GetEvents().size()) {
+ return result;
+ }
+
+ ui64 prev = EpochNanosecondsToCycles(
+ msg.GetTrace().GetEvents()[0].GetTimestampNanosec());
+
+ for (auto& v : msg.GetTrace().GetEvents()) {
+ auto it = probesMap.find(std::make_pair(v.GetName(), v.GetProvider()));
+ if (it != probesMap.end()) {
+ TProbe* probe = it->second;
+ TParams params;
+ if(!probe->Event.Signature.DeserializeFromPb(params, v.GetParams())) {
+ LWTRACK(DeserializationError, orbit, probe->Event.Name, probe->Event.GetProvider());
+ result.AddFailedEventName(v.GetName());
+ } else {
+ ui64 timestamp = EpochNanosecondsToCycles(v.GetTimestampNanosec());
+ orbit.AddProbe(
+ probe,
+ params,
+ prev + (timestamp-prev)*timeScale + timeOffset);
+ probe->Event.Signature.DestroyParams(params);
+ prev = timestamp;
+ }
+ } else {
+ result.AddFailedEventName(v.GetName());
+ }
+ }
+ return result;
+}
+
+void TManager::CreateTraceResponse(TTraceResponse& msg, TOrbit& orbit)
+{
+ orbit.Serialize(0, *msg.MutableTrace());
+}
+
+}
+
diff --git a/library/cpp/lwtrace/control.h b/library/cpp/lwtrace/control.h
new file mode 100644
index 0000000000..16b24eafd2
--- /dev/null
+++ b/library/cpp/lwtrace/control.h
@@ -0,0 +1,351 @@
+#pragma once
+
+#include "custom_action.h"
+#include "event.h"
+#include "log.h"
+#include "log_shuttle.h"
+#include "probe.h"
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#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 {
+
+ using TProbeMap = THashMap<std::pair<TString, TString>, TProbe*>;
+
+ // Interface for probe ownership management
+ class IBox: public virtual TThrRefBase {
+ private:
+ bool Owns;
+
+ 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)
+ {
+ }
+
+ 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(&registry)
+ {}
+
+ 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;
+ };
+
+ // Deserialization result.
+ // Either IsSuccess is true or FailedEventNames contains event names
+ // we were not able to deserialize.
+ struct TTraceDeserializeStatus
+ {
+ bool IsSuccess = true;
+ TVector<TString> FailedEventNames;
+
+ void AddFailedEventName(const TString& name)
+ {
+ IsSuccess = false;
+ FailedEventNames.emplace_back(name);
+ }
+ };
+
+ // 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;
+ THolder<TRunLogShuttleActionExecutor<TCyclicDepot>> SerializingExecutor;
+
+ 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);
+ });
+ }
+
+ TProbeMap GetProbesMap();
+
+ void CreateTraceRequest(TTraceRequest& msg, TOrbit& orbit);
+
+ bool HandleTraceRequest(
+ const TTraceRequest& msg,
+ TOrbit& orbit);
+
+ TTraceDeserializeStatus HandleTraceResponse(
+ const TTraceResponse& msg,
+ const TProbeMap& probesMap,
+ TOrbit& orbit,
+ i64 timeOffset = 0,
+ double timeScale = 1);
+
+ void CreateTraceResponse(
+ TTraceResponse& msg,
+ TOrbit& orbit);
+
+ 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
new file mode 100644
index 0000000000..a379b34ec0
--- /dev/null
+++ b/library/cpp/lwtrace/custom_action.cpp
@@ -0,0 +1,21 @@
+#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;
+ }
+}
+
+void TCustomActionFactory::Register(const TString& name, const TCustomActionFactory::TCallback& callback) {
+ if (Callbacks.contains(name)) {
+ 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
new file mode 100644
index 0000000000..92a3c66b84
--- /dev/null
+++ b/library/cpp/lwtrace/custom_action.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include "probe.h"
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#include <util/generic/hash.h>
+
+#include <functional>
+
+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>;
+
+ // 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;
+ };
+
+}
diff --git a/library/cpp/lwtrace/event.h b/library/cpp/lwtrace/event.h
new file mode 100644
index 0000000000..e53a620c45
--- /dev/null
+++ b/library/cpp/lwtrace/event.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "preprocessor.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);
+ }
+ };
+
+}
diff --git a/library/cpp/lwtrace/example1/example_query.tr b/library/cpp/lwtrace/example1/example_query.tr
new file mode 100644
index 0000000000..a06e2a922d
--- /dev/null
+++ b/library/cpp/lwtrace/example1/example_query.tr
@@ -0,0 +1,10 @@
+Blocks {
+ ProbeDesc {
+ Name: "IterationProbe"
+ Provider: "LWTRACE_EXAMPLE_PROVIDER"
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
diff --git a/library/cpp/lwtrace/example1/lwtrace_example1.cpp b/library/cpp/lwtrace/example1/lwtrace_example1.cpp
new file mode 100644
index 0000000000..6b32c405ee
--- /dev/null
+++ b/library/cpp/lwtrace/example1/lwtrace_example1.cpp
@@ -0,0 +1,39 @@
+#include <library/cpp/lwtrace/all.h>
+
+#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(IterationProbe, GROUPS(), TYPES(i32, double), NAMES("n", "result")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+LWTRACE_DEFINE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+
+void InitLWTrace() {
+ NLWTrace::StartLwtraceFromEnv();
+}
+
+long double Fact(int n) {
+ if (n < 0) {
+ ythrow yexception() << "N! is undefined for negative N (" << n << ")";
+ }
+ double result = 1;
+ for (; n > 1; --n) {
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, IterationProbe, n, result);
+ result *= n;
+ }
+ return result;
+}
+
+void FactorialCalculator() {
+ i32 n;
+ Cout << "Enter a number: ";
+ TString str;
+ Cin >> n;
+ double factN = Fact(n);
+ Cout << n << "! = " << factN << Endl << Endl;
+}
+
+int main() {
+ InitLWTrace();
+ FactorialCalculator();
+ return 0;
+}
diff --git a/library/cpp/lwtrace/example1/start_with_query.sh b/library/cpp/lwtrace/example1/start_with_query.sh
new file mode 100755
index 0000000000..2b456d7be7
--- /dev/null
+++ b/library/cpp/lwtrace/example1/start_with_query.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+export LWTRACE="example_query.tr"
+./lwtrace-example1
diff --git a/library/cpp/lwtrace/example1/ya.make b/library/cpp/lwtrace/example1/ya.make
new file mode 100644
index 0000000000..5ae8c4a48e
--- /dev/null
+++ b/library/cpp/lwtrace/example1/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(lwtrace-example1)
+
+OWNER(cthulhu)
+
+SRCS(
+ lwtrace_example1.cpp
+)
+
+PEERDIR(
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/lwtrace/example2/destructive.tr b/library/cpp/lwtrace/example2/destructive.tr
new file mode 100644
index 0000000000..ad955db018
--- /dev/null
+++ b/library/cpp/lwtrace/example2/destructive.tr
@@ -0,0 +1,36 @@
+Blocks {
+ ProbeDesc { Name: "IterationProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ SleepAction {
+ NanoSeconds: 100000000
+ }
+ }
+}
+
+Blocks {
+ ProbeDesc { Name: "AfterInputProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ StatementAction {
+ Type: ST_MOD
+ Argument { Variable: "nMod2" }
+ Argument { Param: "n" }
+ Argument { Value: "2" }
+ }
+ }
+}
+Blocks {
+ ProbeDesc { Name: "AfterInputProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Predicate {
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "nMod2" }
+ Argument { Value: "0" }
+ }
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+ Action {
+ KillAction { }
+ }
+}
diff --git a/library/cpp/lwtrace/example2/empty.tr b/library/cpp/lwtrace/example2/empty.tr
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/library/cpp/lwtrace/example2/empty.tr
diff --git a/library/cpp/lwtrace/example2/example_query.tr b/library/cpp/lwtrace/example2/example_query.tr
new file mode 100644
index 0000000000..31b5465860
--- /dev/null
+++ b/library/cpp/lwtrace/example2/example_query.tr
@@ -0,0 +1,79 @@
+Blocks {
+ ProbeDesc {
+ Name: "StartupProbe"
+ Provider: "LWTRACE_EXAMPLE_PROVIDER"
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
+Blocks {
+ ProbeDesc { Name: "IterationProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ LogAction {
+ LogTimestamp: true
+ MaxRecords: 2
+ }
+ }
+}
+
+Blocks {
+ ProbeDesc { Name: "ByrefDurationProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ LogAction {
+ LogTimestamp: true
+ MaxRecords: 1
+ }
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
+Blocks {
+ ProbeDesc { Name: "DurationProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ LogAction {
+ LogTimestamp: true
+ MaxRecords: 1
+ }
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
+Blocks {
+ ProbeDesc { Name: "ResultProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ PrintToStderrAction { }
+ }
+ Action {
+ LogAction { LogTimestamp: true }
+ }
+}
+
+
+Blocks {
+ ProbeDesc { Name: "AfterInputProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ StatementAction {
+ Type: ST_MOD
+ Argument { Variable: "nMod2" }
+ Argument { Param: "n" }
+ Argument { Value: "2" }
+ }
+ }
+}
+Blocks {
+ ProbeDesc { Name: "AfterInputProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Predicate {
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "nMod2" }
+ Argument { Value: "0" }
+ }
+ }
+ Action { LogAction { } }
+}
diff --git a/library/cpp/lwtrace/example2/lwtrace_example2.cpp b/library/cpp/lwtrace/example2/lwtrace_example2.cpp
new file mode 100644
index 0000000000..7a4f7a1daf
--- /dev/null
+++ b/library/cpp/lwtrace/example2/lwtrace_example2.cpp
@@ -0,0 +1,117 @@
+#include <library/cpp/lwtrace/control.h>
+#include <library/cpp/lwtrace/all.h>
+
+#include <library/cpp/getopt/last_getopt.h>
+#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")) \
+ 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")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+LWTRACE_DEFINE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+
+THolder<NLWTrace::TManager> traceManager;
+
+struct TConfig {
+ bool UnsafeLWTrace;
+ TString TraceRequestPath;
+};
+
+void InitLWTrace(TConfig& cfg) {
+ traceManager.Reset(new NLWTrace::TManager(*Singleton<NLWTrace::TProbeRegistry>(), cfg.UnsafeLWTrace));
+}
+
+void AddLWTraceRequest(TConfig& cfg) {
+ TString queryStr = TUnbufferedFileInput(cfg.TraceRequestPath).ReadAll();
+ NLWTrace::TQuery query;
+ google::protobuf::TextFormat::ParseFromString(queryStr, &query);
+ traceManager->New("TraceRequest1", query);
+}
+
+class TLogReader {
+public:
+ 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;
+ }
+ if (item.SavedParamsCount > 0) {
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ item.Probe->Event.Signature.SerializeParams(item.Params, paramValues);
+ Cout << " params: ";
+ for (size_t i = 0; i < item.SavedParamsCount; ++i) {
+ Cout << " " << item.Probe->Event.Signature.ParamNames[i] << "=" << paramValues[i];
+ }
+ }
+ Cout << Endl;
+ }
+};
+
+void DisplayLWTraceLog() {
+ Cout << "LWTrace log:" << Endl;
+ TLogReader reader;
+ traceManager->ReadLog("TraceRequest1", reader);
+}
+
+long double Fact(i64 n) {
+ if (n < 0) {
+ ythrow yexception() << "N! is undefined for negative N (" << n << ")";
+ }
+ double result = 1;
+ for (; n > 1; --n) {
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, IterationProbe, n, result);
+ GLOBAL_LWPROBE_DURATION(LWTRACE_EXAMPLE_PROVIDER, DurationProbe, n, result);
+
+ result *= n;
+ }
+ return result;
+}
+
+void FactorialCalculator() {
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, StartupProbe);
+
+ i32 n;
+ Cout << "Enter a number: ";
+ TString str;
+ Cin >> n;
+
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, AfterInputProbe, n);
+
+ double factN = Fact(n);
+ Cout << n << "! = " << factN << Endl << Endl;
+
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, ResultProbe, factN);
+}
+
+int main(int argc, char** argv) {
+ TConfig cfg;
+ 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);
+ opts.AddLongOption('f', "trace-request",
+ "specify a file containing LWTrace request")
+ .DefaultValue("example_query.tr")
+ .StoreResult(&cfg.TraceRequestPath);
+ opts.AddHelpOption('h');
+ TOptsParseResult res(&opts, argc, argv);
+
+ InitLWTrace(cfg);
+
+ AddLWTraceRequest(cfg);
+
+ FactorialCalculator();
+
+ DisplayLWTraceLog();
+
+ return 0;
+}
diff --git a/library/cpp/lwtrace/example2/ya.make b/library/cpp/lwtrace/example2/ya.make
new file mode 100644
index 0000000000..22e34239c8
--- /dev/null
+++ b/library/cpp/lwtrace/example2/ya.make
@@ -0,0 +1,14 @@
+PROGRAM(lwtrace-example2)
+
+OWNER(cthulhu)
+
+SRCS(
+ lwtrace_example2.cpp
+)
+
+PEERDIR(
+ library/cpp/lwtrace
+ library/cpp/getopt
+)
+
+END()
diff --git a/library/cpp/lwtrace/example3/example_query.tr b/library/cpp/lwtrace/example3/example_query.tr
new file mode 100644
index 0000000000..1f841b0932
--- /dev/null
+++ b/library/cpp/lwtrace/example3/example_query.tr
@@ -0,0 +1,13 @@
+Blocks {
+ ProbeDesc {
+ Name: "IterationProbe"
+ Provider: "LWTRACE_EXAMPLE_PROVIDER"
+ }
+ Action {
+ CustomAction {
+ Name: "MyAction"
+ Opts: "/dev/stdout"
+ }
+ }
+}
+
diff --git a/library/cpp/lwtrace/example3/lwtrace_example3.cpp b/library/cpp/lwtrace/example3/lwtrace_example3.cpp
new file mode 100644
index 0000000000..4493dc0077
--- /dev/null
+++ b/library/cpp/lwtrace/example3/lwtrace_example3.cpp
@@ -0,0 +1,43 @@
+#include <library/cpp/lwtrace/all.h>
+#include <google/protobuf/text_format.h>
+#include "my_action.h"
+
+#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(IterationProbe, GROUPS(), TYPES(i32, double), NAMES("n", "result")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+LWTRACE_DEFINE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+
+void InitLWTrace() {
+ NLWTrace::StartLwtraceFromEnv([=](NLWTrace::TManager& mngr) {
+ mngr.RegisterCustomAction<TMyActionExecutor>();
+ });
+}
+
+long double Fact(int n) {
+ if (n < 0) {
+ ythrow yexception() << "N! is undefined for negative N (" << n << ")";
+ }
+ double result = 1;
+ for (; n > 1; --n) {
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, IterationProbe, n, result);
+ result *= n;
+ }
+ return result;
+}
+
+void FactorialCalculator() {
+ i32 n;
+ Cout << "Enter a number: ";
+ TString str;
+ Cin >> n;
+ double factN = Fact(n);
+ Cout << n << "! = " << factN << Endl << Endl;
+}
+
+int main() {
+ InitLWTrace();
+ FactorialCalculator();
+ return 0;
+}
diff --git a/library/cpp/lwtrace/example3/my_action.h b/library/cpp/lwtrace/example3/my_action.h
new file mode 100644
index 0000000000..9a04293ba2
--- /dev/null
+++ b/library/cpp/lwtrace/example3/my_action.h
@@ -0,0 +1,85 @@
+#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;
+ 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;
+ }
+ 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
+ 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;
+ }
+};
diff --git a/library/cpp/lwtrace/example3/start_with_query.sh b/library/cpp/lwtrace/example3/start_with_query.sh
new file mode 100755
index 0000000000..5cd221856f
--- /dev/null
+++ b/library/cpp/lwtrace/example3/start_with_query.sh
@@ -0,0 +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
diff --git a/library/cpp/lwtrace/example3/ya.make b/library/cpp/lwtrace/example3/ya.make
new file mode 100644
index 0000000000..c5b31586e9
--- /dev/null
+++ b/library/cpp/lwtrace/example3/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(lwtrace-example3)
+
+OWNER(serxa)
+
+SRCS(
+ lwtrace_example3.cpp
+)
+
+PEERDIR(
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/lwtrace/example4/example_query.tr b/library/cpp/lwtrace/example4/example_query.tr
new file mode 100644
index 0000000000..46cd25ce91
--- /dev/null
+++ b/library/cpp/lwtrace/example4/example_query.tr
@@ -0,0 +1,10 @@
+Blocks {
+ ProbeDesc {
+ Name: "BackTrack"
+ Provider: "LWTRACE_EXAMPLE_PROVIDER"
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
diff --git a/library/cpp/lwtrace/example4/lwtrace_example4.cpp b/library/cpp/lwtrace/example4/lwtrace_example4.cpp
new file mode 100644
index 0000000000..7b55a07c75
--- /dev/null
+++ b/library/cpp/lwtrace/example4/lwtrace_example4.cpp
@@ -0,0 +1,49 @@
+#include <library/cpp/lwtrace/all.h>
+
+#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)
+
+void InitLWTrace() {
+ NLWTrace::StartLwtraceFromEnv();
+}
+
+long double Fact(int n) {
+ MY_BACKTRACK();
+ if (n < 0) {
+ MY_BACKTRACK();
+ ythrow yexception() << "N! is undefined for negative N (" << n << ")";
+ }
+ double result = 1;
+ for (; n > 1; --n) {
+ MY_BACKTRACK();
+ result *= n;
+ }
+ MY_BACKTRACK();
+ return result;
+}
+
+void FactorialCalculator() {
+ MY_BACKTRACK();
+ i32 n;
+ Cout << "Enter a number: ";
+ TString str;
+ Cin >> n;
+ double factN = Fact(n);
+ Cout << n << "! = " << factN << Endl << Endl;
+}
+
+int main() {
+ InitLWTrace();
+ MY_BACKTRACK();
+ FactorialCalculator();
+ MY_BACKTRACK();
+ return 0;
+}
diff --git a/library/cpp/lwtrace/example4/start_with_query.sh b/library/cpp/lwtrace/example4/start_with_query.sh
new file mode 100755
index 0000000000..5bc195c1ae
--- /dev/null
+++ b/library/cpp/lwtrace/example4/start_with_query.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+export LWTRACE="example_query.tr"
+./lwtrace-example4
diff --git a/library/cpp/lwtrace/example4/ya.make b/library/cpp/lwtrace/example4/ya.make
new file mode 100644
index 0000000000..a3004340a8
--- /dev/null
+++ b/library/cpp/lwtrace/example4/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(lwtrace-example4)
+
+OWNER(serxa)
+
+SRCS(
+ lwtrace_example4.cpp
+)
+
+PEERDIR(
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/lwtrace/example5/example_query.tr b/library/cpp/lwtrace/example5/example_query.tr
new file mode 100644
index 0000000000..90887d4ddf
--- /dev/null
+++ b/library/cpp/lwtrace/example5/example_query.tr
@@ -0,0 +1,9 @@
+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
new file mode 100644
index 0000000000..1c324473c2
--- /dev/null
+++ b/library/cpp/lwtrace/example5/lwtrace_example5.cpp
@@ -0,0 +1,30 @@
+#include <library/cpp/lwtrace/all.h>
+#include <library/cpp/lwtrace/lwprobe.h>
+
+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);
+#endif // LWTRACE_DISABLE
+ 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
+ Cout << Fact<6>() << Endl; // actually trigger probes
+ return 0;
+}
diff --git a/library/cpp/lwtrace/example5/start_with_query.sh b/library/cpp/lwtrace/example5/start_with_query.sh
new file mode 100755
index 0000000000..4df5e4e47c
--- /dev/null
+++ b/library/cpp/lwtrace/example5/start_with_query.sh
@@ -0,0 +1,3 @@
+#!/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
new file mode 100644
index 0000000000..06dd4dc569
--- /dev/null
+++ b/library/cpp/lwtrace/example5/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(lwtrace-example5)
+
+OWNER(serxa)
+
+SRCS(
+ lwtrace_example5.cpp
+)
+
+PEERDIR(
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/lwtrace/kill_action.cpp b/library/cpp/lwtrace/kill_action.cpp
new file mode 100644
index 0000000000..2b74dc4587
--- /dev/null
+++ b/library/cpp/lwtrace/kill_action.cpp
@@ -0,0 +1,21 @@
+#include "kill_action.h"
+
+#ifndef _win_
+#include <sys/types.h>
+#include <signal.h>
+#endif
+
+#include <stdlib.h>
+
+using namespace NLWTrace;
+using namespace NLWTrace::NPrivate;
+
+bool TKillActionExecutor::DoExecute(TOrbit&, const TParams&) {
+#ifdef _win_
+ abort();
+#else
+ int r = kill(getpid(), SIGABRT);
+ Y_VERIFY(r == 0, "kill failed");
+ return true;
+#endif
+}
diff --git a/library/cpp/lwtrace/kill_action.h b/library/cpp/lwtrace/kill_action.h
new file mode 100644
index 0000000000..14da9ffd50
--- /dev/null
+++ b/library/cpp/lwtrace/kill_action.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "probe.h"
+
+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
new file mode 100644
index 0000000000..56981a97f8
--- /dev/null
+++ b/library/cpp/lwtrace/log.h
@@ -0,0 +1,906 @@
+#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/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/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;
+
+ 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
+
+}
diff --git a/library/cpp/lwtrace/log_shuttle.cpp b/library/cpp/lwtrace/log_shuttle.cpp
new file mode 100644
index 0000000000..695aa90b31
--- /dev/null
+++ b/library/cpp/lwtrace/log_shuttle.cpp
@@ -0,0 +1,67 @@
+#include "log_shuttle.h"
+#include "probes.h"
+
+namespace NLWTrace {
+ LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER);
+
+#ifdef LWTRACE_DISABLE
+
+ template <class TDepot>
+ bool TLogShuttle<TDepot>::DoFork(TShuttlePtr& child) {
+ Y_UNUSED(child);
+ return false;
+ }
+
+ template <class TDepot>
+ 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);
+ TParams params;
+ params.Param[0].CopyConstruct<ui64>(child->GetSpanId());
+ bool result = DoAddProbe(&LWTRACE_GET_NAME(Fork).Probe, params, 0);
+ TUserSignature<ui64>::DestroyParams(params);
+ return result;
+ }
+ AtomicIncrement(ForkFailed);
+ return false;
+ }
+
+ template <class TDepot>
+ bool TLogShuttle<TDepot>::DoJoin(const TShuttlePtr& shuttle) {
+ auto* child = Executor->Cast(shuttle);
+ TParams params;
+ params.Param[0].CopyConstruct<ui64>(child->GetSpanId());
+ params.Param[1].CopyConstruct<ui64>(child->TrackLog.Items.size());
+ bool result = DoAddProbe(&LWTRACE_GET_NAME(Join).Probe, params, 0);
+ TUserSignature<ui64, ui64>::DestroyParams(params);
+ if (result) {
+ with_lock (Lock) {
+ ssize_t n = MaxTrackLength - TrackLog.Items.size();
+ for (auto& item: child->TrackLog.Items) {
+ if (n-- <= 0) {
+ TrackLog.Truncated = true;
+ break;
+ }
+ TrackLog.Items.emplace_back(item);
+ }
+ }
+ }
+ AtomicAdd(ForkFailed, AtomicGet(child->ForkFailed));
+ Executor->ParkShuttle(child);
+ return result;
+ }
+
+#endif
+
+ template class TLogShuttle<TDurationDepot>;
+ template class TLogShuttle<TCyclicDepot>;
+}
diff --git a/library/cpp/lwtrace/log_shuttle.h b/library/cpp/lwtrace/log_shuttle.h
new file mode 100644
index 0000000000..729a38615f
--- /dev/null
+++ b/library/cpp/lwtrace/log_shuttle.h
@@ -0,0 +1,359 @@
+#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 {
+ double K = 0;
+ ui64 B = 0;
+
+ THostTimeCalculator() {
+ TInstant now = TInstant::Now();
+ ui64 tsNow = GetCycleCount();
+ K = 1000000000 / NHPTimer::GetClockRate();
+ B = now.NanoSeconds() - K * tsNow;
+ }
+
+ ui64 CyclesToEpochNanoseconds(ui64 cycles) const {
+ return K*cycles + B;
+ }
+
+ ui64 EpochNanosecondsToCycles(ui64 ns) const {
+ return (ns - B) / K;
+ }
+ };
+
+ inline ui64 CyclesToEpochNanoseconds(ui64 cycles) {
+ return Singleton<THostTimeCalculator>()->CyclesToEpochNanoseconds(cycles);
+ }
+
+ inline ui64 EpochNanosecondsToCycles(ui64 ns) {
+ return Singleton<THostTimeCalculator>()->EpochNanosecondsToCycles(ns);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TDepot>
+ class TLogShuttle: public IShuttle {
+ private:
+ using TExecutor = TRunLogShuttleActionExecutor<TDepot>;
+ TTrackLog TrackLog;
+ TExecutor* Executor;
+ bool Ignore = false;
+ size_t MaxTrackLength;
+ TAdaptiveLock Lock;
+ TAtomic ForkFailed = 0;
+
+ 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 DoSerialize(TShuttleTrace& msg) 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;
+ TAtomic* LastSpanId;
+
+ 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);
+ 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>
+ bool TLogShuttle<TDepot>::DoAddProbe(TProbe* probe, const TParams& params, ui64 timestamp) {
+ with_lock (Lock) {
+ if (TrackLog.Items.size() >= MaxTrackLength) {
+ TrackLog.Truncated = true;
+ return true;
+ }
+ TrackLog.Items.emplace_back();
+ TTrackLog::TItem* item = &TrackLog.Items.back();
+ item->ThreadId = 0; // TODO[serxa]: check if it is fast to run TThread::CurrentThreadId();
+ item->Probe = probe;
+ if ((item->SavedParamsCount = probe->Event.Signature.ParamCount) > 0) {
+ 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) {
+ 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
+ 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>
+ void TLogShuttle<TDepot>::DoSerialize(TShuttleTrace& msg)
+ {
+ with_lock (Lock)
+ {
+ if (!GetTrackLog().Items.size()) {
+ return ;
+ }
+ for (auto& record : GetTrackLog().Items) {
+ auto *rec = msg.AddEvents();
+ rec->SetName(record.Probe->Event.Name);
+ rec->SetProvider(record.Probe->Event.GetProvider());
+ rec->SetTimestampNanosec(
+ CyclesToEpochNanoseconds(record.TimestampCycles));
+ record.Probe->Event.Signature.SerializeToPb(record.Params, *rec->MutableParams());
+ }
+ }
+ }
+
+ 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,
+ TAtomic* lastTrackId,
+ TAtomic* lastSpanId)
+ : 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>
+ void TRunLogShuttleActionExecutor<TDepot>::DiscardShuttle() {
+ AtomicIncrement(MissedTracks);
+ }
+
+ template <class TDepot>
+ 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);
+ }
+
+ 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;
+ }
+
+}
diff --git a/library/cpp/lwtrace/lwprobe.h b/library/cpp/lwtrace/lwprobe.h
new file mode 100644
index 0000000000..801fc3861b
--- /dev/null
+++ b/library/cpp/lwtrace/lwprobe.h
@@ -0,0 +1,110 @@
+#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
+ 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();
+ 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) {
+ 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",
+ 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) {
+ 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.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);
+ 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
new file mode 100644
index 0000000000..02ddfb83f2
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/all.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "csv_output.h"
+#include "data.h"
+#include "html_output.h"
+#include "json_output.h"
+#include "transform.h"
+#include "util.h"
diff --git a/library/cpp/lwtrace/mon/analytics/analytics.cpp b/library/cpp/lwtrace/mon/analytics/analytics.cpp
new file mode 100644
index 0000000000..1b25263386
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/analytics.cpp
@@ -0,0 +1,5 @@
+#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
new file mode 100644
index 0000000000..90ded32f5d
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/csv_output.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <util/string/printf.h>
+#include <util/stream/str.h>
+#include <util/generic/set.h>
+#include "data.h"
+
+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) {
+ ss << (first? TString(): sep) << "Name";
+ 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) {
+ ss << (first? TString(): sep) << row.Name;
+ first = false;
+ }
+ for (const TString& c : cols) {
+ ss << (first? TString(): sep);
+ first = false;
+ TString value;
+ ss << (row.GetAsString(c, value) ? value : TString("-"));
+ }
+ ss << Endl;
+ }
+ return ss.Str();
+}
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/data.h b/library/cpp/lwtrace/mon/analytics/data.h
new file mode 100644
index 0000000000..4b643fe20b
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/data.h
@@ -0,0 +1,108 @@
+#pragma once
+
+#include <util/generic/string.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 {
+
+using TRowValue = std::variant<i64, ui64, double, TString>;
+
+TString ToString(const TRowValue& val) {
+ TStringBuilder builder;
+ std::visit([&builder] (auto&& arg) {
+ builder << arg;
+ }, val);
+ return builder;
+}
+
+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>) {
+ if (name == "_count") { // Special values
+ value = 1.0;
+ return true;
+ }
+ }
+ auto iter = find(name);
+ if (iter != end()) {
+ try {
+ value = std::get<T>(iter->second);
+ return true;
+ } catch (...) {}
+ }
+ return false;
+ }
+
+ template<typename T = double>
+ T GetOrDefault(const TString& name, T dflt = T()) {
+ Get(name, dflt);
+ return dflt;
+ }
+
+ bool GetAsString(const TString& name, TString& value) const {
+ auto iter = find(name);
+ if (iter != end()) {
+ value = ToString(iter->second);
+ return true;
+ }
+ return false;
+ }
+};
+
+using TAttributes = THashMap<TString, TString>;
+
+struct TTable : public TVector<TRow> {
+ TAttributes Attributes;
+};
+
+struct TMatrix : public TVector<double> {
+ 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;
+ }
+};
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/html_output.h b/library/cpp/lwtrace/mon/analytics/html_output.h
new file mode 100644
index 0000000000..f775f216b9
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/html_output.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <util/string/printf.h>
+#include <util/stream/str.h>
+#include <util/generic/set.h>
+#include "data.h"
+
+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>";
+ }
+ 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>";
+ }
+ for (const TString& c : cols) {
+ TString value;
+ ss << "<td>" << (row.GetAsString(c, value) ? value : TString("-")) << "</td>";
+ }
+ 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>";
+
+ for (const TString& c : cols) {
+ 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();
+}
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/json_output.h b/library/cpp/lwtrace/mon/analytics/json_output.h
new file mode 100644
index 0000000000..189f9802d3
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/json_output.h
@@ -0,0 +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>
+#include "data.h"
+#include "util.h"
+
+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;
+
+ TString xn;
+ THashSet<TString> xopts;
+ ParseNameAndOpts(xno, xn, xopts);
+ bool xstack = xopts.contains("stack");
+
+ for (const TString& yno : ynos) {
+ TString yn;
+ THashSet<TString> yopts;
+ ParseNameAndOpts(yno, yn, yopts);
+ bool ystackOpt = yopts.contains("stack");
+
+ 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();
+}
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/transform.h b/library/cpp/lwtrace/mon/analytics/transform.h
new file mode 100644
index 0000000000..f7dc9adb5b
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/transform.h
@@ -0,0 +1,204 @@
+#pragma once
+
+#include "data.h"
+
+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;
+ 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) {
+ out[i][yn_sum] = y + out[i].GetOrDefault(yn_sum, 0.0);
+ }
+ }
+ for (TRow& row : out) {
+ if (ysum != 0.0) {
+ row[yn_share] = row.GetOrDefault(yn_sum, 0.0) / ysum;
+ }
+ }
+ 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;
+ THashMap<TString, double> colSum;
+ 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 (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;
+ 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) {
+ const TString& yn = kv.first;
+ if (yn == xn) {
+ continue;
+ }
+ double y;
+ if (!row_in.Get(yn, y)) {
+ continue;
+ }
+ 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;
+ }
+ 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) {
+ out[i]["_count_sum"] = out[i].GetOrDefault("_count_sum") + 1;
+ }
+ }
+ for (TRow& row : out) {
+ for (const TString& col : cols) {
+ 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) {
+ row[col + "_share"] = row.GetOrDefault(col + "_sum") / ysum;
+ }
+ }
+ }
+ 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;
+ };
+
+ 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;
+ 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) {
+ double x;
+ if (!row.Get(kv1.first, x)) {
+ continue;
+ }
+ 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;
+}
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/util.h b/library/cpp/lwtrace/mon/analytics/util.h
new file mode 100644
index 0000000000..e07d06cc43
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/util.h
@@ -0,0 +1,122 @@
+#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
+inline double Finitize(double x, double notFiniteValue = 0.0)
+{
+ return isfinite(x)? x: notFiniteValue;
+}
+
+inline void ParseNameAndOpts(const TString& nameAndOpts, TString& name, THashSet<TString>& opts)
+{
+ 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);
+ }
+ }
+}
+
+inline TString ParseName(const TString& nameAndOpts)
+{
+ auto vs = SplitString(nameAndOpts, "-");
+ if (vs.empty()) {
+ return TString();
+ } 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;
+}
+
+inline double MinValue(const TString& nameAndOpts, const TTable& table)
+{
+ TString name;
+ THashSet<TString> opts;
+ ParseNameAndOpts(nameAndOpts, name, opts);
+ bool stack = opts.contains("stack");
+ 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);
+ });
+ }
+}
+
+inline double MaxValue(const TString& nameAndOpts, const TTable& table)
+{
+ TString name;
+ THashSet<TString> 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 {
+ auto zero = 0.0;
+
+ return AccumulateIfExist(name, table, -1.0 / zero /*-inf*/, [] (double x, double y) {
+ 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);
+ });
+}
+
+inline std::function<bool(const TRow&)> HasNoValueFor(TString name)
+{
+ 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;
+ };
+}
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/ya.make b/library/cpp/lwtrace/mon/analytics/ya.make
new file mode 100644
index 0000000000..c18e23c8e1
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(serxa g:kikimr)
+
+PEERDIR(
+)
+
+SRCS(
+ analytics.cpp
+)
+
+END()
+
+RECURSE(
+)
diff --git a/library/cpp/lwtrace/mon/mon_lwtrace.cpp b/library/cpp/lwtrace/mon/mon_lwtrace.cpp
new file mode 100644
index 0000000000..a61ee9ce22
--- /dev/null
+++ b/library/cpp/lwtrace/mon/mon_lwtrace.cpp
@@ -0,0 +1,4723 @@
+#include "mon_lwtrace.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include <google/protobuf/text_format.h>
+#include <library/cpp/lwtrace/mon/analytics/all.h>
+#include <library/cpp/lwtrace/all.h>
+#include <library/cpp/monlib/service/pages/mon_page.h>
+#include <library/cpp/monlib/service/pages/resource_mon_page.h>
+#include <library/cpp/monlib/service/pages/templates.h>
+#include <library/cpp/resource/resource.h>
+#include <library/cpp/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/system/hostname.h>
+
+using namespace NMonitoring;
+
+#define WWW_CHECK(cond, ...) \
+ do { \
+ if (!(cond)) { \
+ ythrow yexception() << Sprintf(__VA_ARGS__); \
+ } \
+ } 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; }
+ };
+
+ 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;
+ }
+ }
+ };
+
+ 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() {}
+
+ 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);
+ }
+
+ void ParseQuery(const TString& s)
+ {
+ auto parts = SplitString(s, ".");
+ 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]);
+ }
+ }
+
+ void ParseParamSelector(const TString& s)
+ {
+ 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);
+ WWW_CHECK(bracket2 != TString::npos, "closing braket ']' is missing");
+ Index = FromString<i64>(s.substr(bracket + 1, bracket2 - bracket - 1));
+ }
+ }
+
+ void ParseParamName(const TString& 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;
+ paramName.erase(0, p.first.size());
+ 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;
+ paramName.erase(paramName.size() - p.first.size());
+ 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;
+ paramName.erase(paramName.size() - p.first.size());
+ 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;
+ }
+
+ void ParseProviderSelector(const TString& 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();
+ }
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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();
+ if (pdesc.GetProvider()) {
+ 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";
+ }
+ if (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";
+ }
+ }
+ }
+ if (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;
+ }
+
+ bool ParseId(const TString& id)
+ {
+ if (IsAdHocId(id)) {
+ for (const TString& block : SplitString(id, "/")) {
+ 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) {
+ 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;
+ 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:
+ static bool IsAdHocId(const TString& id)
+ {
+ return !id.empty() && id[0] == '.';
+ }
+
+ void ParsePredicate(NLWTrace::TOperator* op, const TString& p)
+ {
+ 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 '!': {
+ 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 '<': {
+ 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 '>': {
+ 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;
+ }
+ default: WWW_CHECK(false, "wrong predicate operator format in adhoc trace: %s", p.data());
+ }
+ 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();
+ 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;
+ 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();
+ for (const TString& opt : SplitString(a.substr(3), "-")) {
+ 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();
+ 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;
+ default: WWW_CHECK(false, "unknown adhoc trace log opt '%s' in '%s'", opt.data(), a.data());
+ }
+ }
+ }
+ } 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;
+ 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
+ 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
+ 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
+ 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;) {
+ 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)
+ {
+ TString name = "LWTraceCleaner";
+ // Copy-pasted from kikimr/core/util/thread.h
+#if defined(_linux_)
+ TStringStream linuxName;
+ linuxName << TStringBuf(GetExecPath()).RNextTok('/') << "." << name;
+ TThread::SetCurrentThreadName(linuxName.Str().data());
+#else
+ TThread::SetCurrentThreadName(name.data());
+#endif
+ static_cast<TTraceCleaner*>(_this)->Exec();
+ return nullptr;
+ }
+};
+
+class TChromeTrace {
+private:
+ TMultiMap<double, TString> TraceEvents;
+ THashMap<TThread::TId, TString> Tids;
+public:
+ void Add(TThread::TId tid, ui64 tsCycles, const TString& ph, const TString& cat,
+ 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;
+ }
+ const TString& shortId = tidIter->second;
+ 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:
+ static TString Event(const TString& tid, double ts, const TString& ph, const TString& cat,
+ 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\":{";
+ 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 << ",";
+ }
+ 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();
+}
+
+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();
+}
+
+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();
+}
+
+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();
+}
+
+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();
+}
+
+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;
+}
+
+TString UnescapeSubvalue(const TString& s)
+{
+ TString ret;
+ ret.reserve(s.size());
+ for (size_t i = 0; i < s.size(); 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;
+}
+
+TVector<TString> Subvalues(const TCgiParameters& e, const TString& key)
+{
+ if (!e.Has(key)) {
+ return TVector<TString>();
+ } 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;
+ }
+}
+
+TString ParseTagsOut(const TString& taggedStr, TTags& tags)
+{
+ auto vec = SplitString(taggedStr, "-");
+ if (vec.empty()) {
+ return "";
+ }
+ auto iter = vec.begin();
+ TString value = *iter++;
+ 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));
+ }
+ 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));
+}
+
+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));
+}
+
+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));
+ }
+}
+
+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);
+}
+template <> TString UrlAdd<true>(const TCgiParameters& e, const TString& key, const TString& 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);
+}
+template <> TString UrlReplace<true>(const TCgiParameters& e, const TString& key, const TString& oldValue, const TString& 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);
+}
+template <> TString UrlErase<true>(const TCgiParameters& e, const TString& key, const TString& value) {
+ return MakeUrlEraseSub(e, key, value);
+}
+
+void OutputCommonHeader(IOutputStream& out)
+{
+ out << NResource::Find("lwtrace/mon/static/header.html") << Endl;
+}
+
+void OutputCommonFooter(IOutputStream& out)
+{
+ 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; }
+
+ IOutputStream &Str;
+};
+
+TString NavbarHeader()
+{
+ 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(...) {}
+ }
+
+ IOutputStream& Str;
+};
+
+struct TNullContainer {
+ TNullContainer(IOutputStream&) {}
+};
+
+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();
+ }
+
+ explicit TPageGen(const TString& content = TString())
+ : Content(content)
+ {
+ BuildResponse();
+ }
+
+ void Append(const TString& moreContent)
+ {
+ Content.append(moreContent);
+ BuildResponse();
+ }
+
+ void Prepend(const TString& moreContent)
+ {
+ 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>
+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";
+}
+
+void SelectorTitle(IOutputStream& os, const TString& text)
+{
+ 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>";
+ }
+}
+
+void DropdownBeginSublist(IOutputStream& os, const TString& text)
+{
+ os << "<li>" << text << "<ul class=\"dropdown-menu\">";
+}
+
+void DropdownEndSublist(IOutputStream& os)
+{
+ 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>";
+}
+
+TString SuggestSelection()
+{
+ return "--- ";
+}
+
+TString RemoveSelection()
+{
+ 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>
+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>";
+ }
+}
+
+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());
+ }
+}
+
+void RequireMultipleSelection(TStringStream& ss, const TCgiParameters& e, const TString& param,
+ const TString& text, const TVariants& variants)
+{
+ SelectorTitle(ss, text);
+ TSet<TString> selectedValues;
+ for (const TString& subvalue : Subvalues(e, param)) {
+ selectedValues.insert(subvalue);
+ }
+ for (const TString& subvalue : Subvalues(e, param)) {
+ 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());
+ }
+ }
+}
+
+void OptionalSelection(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);
+ }
+ for (const TString& subvalue : Subvalues(e, param)) {
+ DropdownSelector<Erasable, true>(ss, e, param, subvalue, "", variants);
+ }
+ if (selectedValues.empty()) {
+ BtnHref<Button|ExtraSmall>(ss, text, MakeUrlAddSub(e, param, ""));
+ }
+}
+
+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);
+ }
+ for (const TString& subvalue : Subvalues(e, param)) {
+ 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)
+{
+ 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;
+}
+
+TString TaggedValue(const TString& value, const TString& 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 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,
+ const TString& xparam, const TString& yparam, const NAnalytics::TTable& data)
+{
+ 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()));
+ }
+
+ TString yns = e.Get(yparam);
+ 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());
+ }
+}
+
+class TProbesHtmlPrinter {
+private:
+ TVector<TVector<TString>> TableData;
+ static constexpr int TimeoutSec = 15 * 60; // default timeout
+public:
+ void Push(const NLWTrace::TProbe* probe)
+ {
+ TableData.emplace_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.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]);
+ }
+
+ 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() {
+ for (TString& cell : row) {
+ 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();
+ }
+
+ 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();
+ }
+};
+
+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 TString& dashText) {
+ 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) {
+ TGuard<TMutex> g(Mutex);
+ if (!Dashboards.contains(name)) {
+ return false;
+ }
+ dash = Dashboards[name];
+ return true;
+}
+
+void TDashboardRegistry::Output(TStringStream& ss) {
+ HTML(ss) {
+ TABLE() {
+ TABLEHEAD() {
+ TABLEH() { ss << "Name"; }
+ }
+ TABLEBODY() {
+ TGuard<TMutex> g(Mutex);
+ for (auto& kv : Dashboards) {
+ const auto& dash = kv.second;
+ TABLER() {
+ TABLED() {
+ ss << "<a href='?mode=dashboard&name=" << dash.GetName() << "'>" << dash.GetName() << "</a>";
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+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:
+ 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)
+ {}
+
+ 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:
+ 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
+ TSnapshotLogSource(const TString& sid, const TAtomicSharedPtr<NLWTrace::TLogPb>& 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;
+ using TLogSourcePtr = std::unique_ptr<ILogSource>;
+ TMap<TString, TLogSourcePtr> LogSources;
+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));
+ LogSources.emplace(ls->GetId(), std::move(ls));
+ }
+
+ 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) {
+ func.Push(kv.second.get());
+ }
+ }
+
+ 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;
+public:
+ explicit TTracesHtmlPrinter(IOutputStream& os)
+ : Os(os)
+ , Now(TInstant::Now())
+ {}
+
+ void Push(ILogSource* src)
+ {
+ TString id = src->GetId();
+ Os << "<tr>";
+ Os << "<td>";
+ try {
+ 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>" << EncodeHtmlPcdata(id) << "</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>"
+ << "</tr>\n";
+ }
+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();
+ }
+};
+
+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);
+ }
+ }
+};
+
+class TLogFilter {
+private:
+ struct TFilter {
+ TString ParamName;
+ TString ParamValue;
+ 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 (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);
+ }
+ };
+ TVector<TFilter> Filters;
+ THashSet<const NLWTrace::TSignature*> Signatures; // Just to list param names
+ 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);
+ }
+ }
+ }
+
+ 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;
+ }
+ }
+ return true;
+ }
+
+ void FilterSelectors(TStringStream& ss, const TCgiParameters& e, const TString& fparam)
+ {
+ 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()) {
+ 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;
+ }
+
+ 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) {
+ 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);
+ }
+ }
+
+ TVariants ListParamValues(const TString& paramName) const
+ {
+ 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;
+ }
+};
+
+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;
+ bool FirstThread;
+ bool FirstItem;
+public:
+ explicit TLogJsonPrinter(IOutputStream& os)
+ : Os(os)
+ , FirstThread(true)
+ , FirstItem(true)
+ {}
+
+ void OutputHeader()
+ {
+ Os << "{\n\t\"source\": \"" << HostName() << "\""
+ "\n\t, \"items\": ["
+ ;
+ }
+
+ void OutputFooter(const NLWTrace::TSession* trace)
+ {
+ Os << "\n\t\t]"
+ "\n\t, \"threads\": ["
+ ;
+ trace->ReadThreads(*this);
+ Os << "]"
+ "\n\t, \"events_count\": " << trace->GetEventsCount() <<
+ "\n\t, \"threads_count\": " << trace->GetThreadsCount() <<
+ "\n\t, \"timestamp\": " << Now().GetValue() <<
+ "\n}"
+ ;
+ }
+
+ void PushThread(TThread::TId tid)
+ {
+ Os << (FirstThread? "": ", ") << tid;
+ FirstThread = false;
+ }
+
+ void Push(TThread::TId tid, const NLWTrace::TLogItem& item)
+ {
+ Os << "\n\t\t" << (FirstItem? "": ", ");
+ FirstItem = false;
+
+ Os << "[" << tid <<
+ ", " << item.Timestamp.GetValue() <<
+ ", \"" << item.Probe->Event.GetProvider() << "\""
+ ", \"" << item.Probe->Event.Name << "\""
+ ", {"
+ ;
+ 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 << "}]";
+ }
+};
+
+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;
+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 TCgiParameters& e)
+ : TLogTextPrinter(
+ 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",
+ e.Get("cutts") == "y",
+ e.Get("showts") == "y")
+ {}
+
+ 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);
+ 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);
+ }
+ }
+
+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 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>
+ 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";
+ }
+};
+
+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;
+ TVector<TString> GroupBy;
+ TTimestampCutter CutTs;
+public:
+ TLogAnalyzer(const TVector<TString>& filters, const TVector<TString>& groupBy, bool 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) {
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ 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;
+ } 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];
+ }
+ }
+ return TString();
+ }
+
+ TString GetGroup(const NLWTrace::TLogItem& item, TString* paramValues)
+ {
+ 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;
+ }
+ 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)) {
+ 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) {
+ const TString& group = v.first;
+ 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 {
+ 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 {
+ 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;
+ 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)
+ {}
+ };
+
+ TVector<TTrackEntry> Tracks;
+
+ ui64 ResTotalSum = 0;
+ ui64 ResTotalMax = 0;
+ TVector<ui64> ResTotalAll;
+
+ ui64 ResLastSum = 0;
+ ui64 ResLastMax = 0;
+ TVector<ui64> ResLastAll;
+
+ TVector<ui64> TimelineSum;
+ 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) {
+ ret.emplace_back();
+ 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;
+ }
+
+ 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 {
+ 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;
+ }
+ }
+
+ NLWTrace::TTrackLog tl;
+ for (TTrackIter i = TTrackTr::begin(*track), e = TTrackTr::end(*track); i != e; ++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:
+ using TChildren = THashMap<NLWTrace::TProbe*, TPatternNode>;
+ 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
+ TString ParamName;
+ using TChildren = THashMap<TString, TPatternNode>;
+ TChildren Children;
+ TVector<TChildren::value_type*> SortedChildren;
+ 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'",
+ 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'",
+ 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 = &paramValues[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;
+ THashMap<TString, std::pair<size_t, TString>> ParamClassifiers; // path -> (rollbacks, param)
+ TString SelectedPattern;
+ TPatternNode* SelectedNode = nullptr;
+ TVector<ui64> Timeline; // Just to avoid reallocations
+public:
+ TPatternTree(const TCgiParameters& e)
+ {
+ for (const TString& cl : Subvalues(e, "classify")) {
+ size_t at = cl.find_last_of('@');
+ if (at != TString::npos) {
+ 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();
+ }
+ }
+
+ template <typename TReader>
+ void OutputSelectedSample(const TString& bn, double b1, double b2, const TSampleOpts& opts, TReader& reader)
+ {
+ if (SelectedNode) {
+ SelectedNode->OutputSample(bn, b1, b2, opts, reader);
+ }
+ }
+
+ // 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; }
+
+ 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;
+ }
+ 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 = &paramValues[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
+ THashMap<TString, TTrack> Tracks;
+ TVector<TTrack> TracksFromDepot;
+
+ // Analysis
+ TVector<TString> GroupBy;
+ THashSet<TString> TrackIds; // The same content as in GroupBy
+ 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)
+ {
+ 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
+ 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
+ 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;
+ 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) {
+ TString parentClass;
+ 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
+ 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);
+
+ 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));
+
+ 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);
+ }
+
+ 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&nbsp;ms<sup>2</sup>&nbsp;(%.3lf&nbsp;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
+ 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++) {
+ 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>";
+ }
+ }
+
+ 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>";
+ }
+
+ 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) {
+ WWW_CHECK(n, "internal bug: wrong timeline length at pattern node '%s'", node->GetPath().data());
+ 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>";
+ }
+
+ TString FormatTimelineTooltip(double time, double prevTime, TPatternNode* node)
+ {
+ 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);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ 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];
+ }
+ }
+ return TString();
+ }
+
+ TString GetGroup(const NLWTrace::TLogItem& item, TString* paramValues)
+ {
+ 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)) {
+ 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;
+TString g_sanitizerTest("TString g_sanitizerTest");
+NLWTrace::TManager g_SafeManager(g_Probes, false);
+NLWTrace::TManager g_UnsafeManager(g_Probes, true);
+TDashboardRegistry g_DashboardRegistry;
+
+class TLWTraceMonPage : public NMonitoring::IMonPage {
+private:
+ NLWTrace::TManager* TraceMngr;
+ TString StartTime;
+ TTraceCleaner Cleaner;
+ TMutex SnapshotsMtx;
+ THashMap<TString, TAtomicSharedPtr<NLWTrace::TLogPb>> Snapshots;
+public:
+ explicit TLWTraceMonPage(bool allowUnsafe = false)
+ : NMonitoring::IMonPage("trace", "Tracing")
+ , TraceMngr(&TraceManager(allowUnsafe))
+ , Cleaner(TraceMngr)
+ {
+ time_t stime = TInstant::Now().TimeT();
+ StartTime = CTimeR(&stime);
+ }
+
+ virtual void Output(NMonitoring::IMonHttpRequest& request) {
+ TStringStream out;
+ try {
+ if (request.GetParams().Get("mode") == "") {
+ OutputTracesAndSnapshots(request, out);
+ } else if (request.GetParams().Get("mode") == "probes") {
+ 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);
+ } 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);
+ } else if (request.GetParams().Get("mode") == "new") {
+ 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);
+ } 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;
+ }
+ }
+ }
+ request.Output() << out.Str();
+ }
+
+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>"
+ "<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><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);
+ }
+ }
+
+ 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;
+ }
+ }
+
+ 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();
+ }
+ }
+
+ void OutputDashboards(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ TStringStream ss;
+ g_DashboardRegistry.Output(ss);
+
+ WWW_HTML(out) {
+ OutputNavbar(request, out);
+ out << ss.Str();
+ }
+ }
+
+ void OutputDashboard(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) {
+ if (!request.GetParams().Has("name")) {
+ ythrow yexception() << "Cgi-parameter 'name' is not specified";
+ } else {
+ auto name = request.GetParams().Get("name");
+ 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>";
+ }
+ } 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);
+ }
+ }
+
+ void OutputLog(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ 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();
+ } else if (e.Get("format") == "analytics" && e.Get("aggr") == "tracks") {
+ TLogTrackExtractor logTrackExtractor(e,
+ Subvalues(e, "f"),
+ Subvalues(e, "g")
+ );
+ for (const TString& id : Subvalues(e, "id")) {
+ CheckAdHocTrace(id, TDuration::Minutes(1));
+ TraceMngr->ReadLog(id, logTrackExtractor);
+ TraceMngr->ReadDepot(id, logTrackExtractor);
+ }
+ TString patternAnalyzer;
+ if (e.Get("pattern")) {
+ patternAnalyzer = e.Get("ptrn_anlz");
+ }
+ logTrackExtractor.Run();
+
+ 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;
+ TSampleOpts opts;
+ opts.ShowProvider = (e.Get("show_provider") == "y");
+ if (e.Get("size_limit")) {
+ opts.SizeLimit = FromString<size_t>(e.Get("size_limit"));
+ }
+ logTrackExtractor.OutputSample(distBy, sel_x1, sel_x2, opts, printer);
+ printer.Output(ss);
+ out << HTTPOKTEXT;
+ out << ss.Str();
+ } 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();
+ }
+ }
+ }
+
+ void OutputQuery(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ 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();
+ TString queryStr = query.DebugString();
+ 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>";
+ }
+ }
+
+ 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")
+ ));
+ 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"
+ ));
+ 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());
+ {
+ auto paramNamesList = logFilter->ListParamNames();
+ if (e.Get("aggr") == "tracks") {
+ paramNamesList.emplace_back("_trackMs", "_trackMs");
+ }
+ OptionalSelection(out, e, "s", "order by", paramNamesList);
+ }
+
+ if (e.Get("s")) {
+ TVariants variants;
+ variants.emplace_back("", "asc");
+ variants.emplace_back("y", "desc");
+ DropdownSelector<Link>(out, e, "reverse", e.Get("reverse"), "", variants);
+ }
+
+ 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;
+ 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;
+ 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"));
+ }
+ 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) {
+ static const THashSet<TString> keepParams = {
+ "f",
+ "g",
+ "head",
+ "tail",
+ "s",
+ "reverse",
+ "cutts",
+ "showts",
+ "show_provider",
+ "size_limit",
+ "aggr",
+ "id",
+ "pattern",
+ "ptrn_anlz",
+ "sel_x1",
+ "sel_x2"
+ };
+ TCgiParameters cgiParams;
+ for (const auto& kv : request.GetParams()) {
+ if (keepParams.count(kv.first)) {
+ cgiParams.insert(kv);
+ }
+ }
+ cgiParams.insert(std::pair<TString, TString>("mode", "log"));
+ BtnHref<Button|Medium>(out, "Open logs", MakeUrlAdd(cgiParams, "format", "analytics"));
+ 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();
+ 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
+ }
+ }
+
+ 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") {
+ 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") {
+ 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 << ToJsonFlot(data, xn, SplitString(e.Get("yns"), ":"));
+ } 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;
+ }
+ }
+ }
+ } else if (outFormat = "text") {
+ out << " <input type='text' id='logsLimit' size='2' placeholder='Limit'>" << Endl;
+ out <<
+ R"END(<script>
+ {
+ var url = new URL(window.location.href);
+ if (url.searchParams.has('head')) {
+ document.getElementById('logsLimit').value = url.searchParams.get('head');
+ }
+ }
+
+ $('#logsLimit').on('keypress', function(ev) {
+ if (ev.keyCode == 13) {
+ var url = new URL(window.location.href);
+ var limit_value = document.getElementById('logsLimit').value;
+ if (limit_value && !isNaN(limit_value)) {
+ url.searchParams.set('head', limit_value);
+ window.location.href = url.toString();
+ } else if (!limit_value) {
+ url.searchParams.delete('head');
+ window.location.href = url.toString();
+ }
+ }
+ });
+ </script>)END";
+ TString selectors = out.Str();
+ TLogTextPrinter printer(e);
+ TStringStream ss;
+ for (const TString& id : Subvalues(e, "id")) {
+ CheckAdHocTrace(id, TDuration::Minutes(1));
+ TraceMngr->ReadLog(id, printer);
+ TraceMngr->ReadDepot(id, printer);
+ }
+ printer.Output(ss);
+
+ out.Clear();
+ out << NMonitoring::HTTPOKHTML;
+ out << "<!DOCTYPE html>" << Endl;
+ HTML(out) {
+ HTML_TAG() {
+ HEAD() {
+ out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl;
+ }
+ BODY() {
+ // Wrap selectors with navbar
+ { TSelectorsContainer sc(out);
+ out << selectors;
+ }
+ static const THashSet<TString> keepParams = {
+ "s",
+ "head",
+ "reverse",
+ "cutts",
+ "showts",
+ "id",
+ "out"
+ };
+ TCgiParameters cgiParams;
+ for (const auto& kv : request.GetParams()) {
+ if (keepParams.count(kv.first)) {
+ cgiParams.insert(kv);
+ }
+ }
+ cgiParams.insert(std::pair<TString, TString>("mode", "analytics"));
+
+ auto toggledButton = [&out, &e, &cgiParams] (const TString& label, const TString& cgiKey) {
+ if (e.Get(cgiKey) == "y") {
+ BtnHref<Button|Medium>(out, label, MakeUrlErase(cgiParams, cgiKey, "y"), true);
+ } else {
+ BtnHref<Button|Medium>(out, label, MakeUrlAdd(cgiParams, cgiKey, "y"));
+ }
+ };
+ toggledButton("Cut Tails", "cutts");
+ toggledButton("Relative Time", "showts");
+
+ cgiParams.erase("mode");
+ cgiParams.insert(std::pair<TString, TString>("mode", "log"));
+ BtnHref<Button|Medium>(out, "Fullscreen", MakeUrlAdd(cgiParams, "format", "text"));
+ out << "<pre>\n";
+ out << ss.Str() << Endl;
+ out << "</pre>\n";
+ }
+ }
+ }
+ }
+ }
+ }
+
+ TDuration GetGetTimeout(const NMonitoring::IMonHttpRequest& request)
+ {
+ 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");
+ 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;
+ 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 {
+ 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";
+ }
+ }
+
+ void PostDelete(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ 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";
+ }
+ }
+
+ void PostSnapshot(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ 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;
+ 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";
+ }
+ }
+
+ void PostSetTimeout(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ 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";
+ }
+ }
+
+ void RegisterDashboard(const TString& dashConfig) {
+ g_DashboardRegistry.Register(dashConfig);
+ }
+
+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;
+ }
+};
+
+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
+}
+
+NLWTrace::TProbeRegistry& ProbeRegistry() {
+ return g_Probes;
+}
+
+NLWTrace::TManager& TraceManager(bool allowUnsafe) {
+ return allowUnsafe? g_UnsafeManager: g_SafeManager;
+}
+
+TDashboardRegistry& DashboardRegistry() {
+ return g_DashboardRegistry;
+}
+
+} // namespace NLwTraceMonPage
diff --git a/library/cpp/lwtrace/mon/mon_lwtrace.h b/library/cpp/lwtrace/mon/mon_lwtrace.h
new file mode 100644
index 0000000000..8030f6ea61
--- /dev/null
+++ b/library/cpp/lwtrace/mon/mon_lwtrace.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#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 {
+
+class TDashboardRegistry {
+ THashMap<TString, NLWTrace::TDashboard> Dashboards;
+ TMutex Mutex;
+public:
+ 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);
+ 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);
+TDashboardRegistry& DashboardRegistry();
+
+} // namespace NLwTraceMonPage
diff --git a/library/cpp/lwtrace/mon/static/analytics.css b/library/cpp/lwtrace/mon/static/analytics.css
new file mode 100644
index 0000000000..1b0c268e43
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/analytics.css
@@ -0,0 +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;
+}
diff --git a/library/cpp/lwtrace/mon/static/analytics.flot.html b/library/cpp/lwtrace/mon/static/analytics.flot.html
new file mode 100644
index 0000000000..ea0a2880a5
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/analytics.flot.html
@@ -0,0 +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">&times;</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
new file mode 100644
index 0000000000..cf41008900
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/analytics.gantt.html
@@ -0,0 +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>
diff --git a/library/cpp/lwtrace/mon/static/analytics.header.html b/library/cpp/lwtrace/mon/static/analytics.header.html
new file mode 100644
index 0000000000..0a6790e232
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/analytics.header.html
@@ -0,0 +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>
diff --git a/library/cpp/lwtrace/mon/static/analytics.js b/library/cpp/lwtrace/mon/static/analytics.js
new file mode 100644
index 0000000000..7b66cca4c0
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/analytics.js
@@ -0,0 +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();
+}
diff --git a/library/cpp/lwtrace/mon/static/common.css b/library/cpp/lwtrace/mon/static/common.css
new file mode 100644
index 0000000000..e0f68e1213
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/common.css
@@ -0,0 +1,3 @@
+/* theme.bootstrap.css 2.18.4 */ .tablesorter-bootstrap{width:100%}.tablesorter-bootstrap tfoot td,.tablesorter-bootstrap tfoot th,.tablesorter-bootstrap thead td,.tablesorter-bootstrap thead th{font:700 14px/20px Arial,Sans-serif;padding:4px;margin:0 0 18px;background-color:#eee}.tablesorter-bootstrap .tablesorter-header{cursor:pointer}.tablesorter-bootstrap .tablesorter-header-inner{position:relative;padding:4px 18px 4px 4px}.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon{font-size:11px;position:absolute;right:2px;top:50%;margin-top:-7px;width:14px;height:14px;background-repeat:no-repeat;line-height:14px;display:inline-block}.tablesorter-bootstrap>tbody>tr.odd>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~tr.tablesorter-hasChildRow.odd~.tablesorter-childRow.odd>td{background-color:#f9f9f9}.tablesorter-bootstrap>tbody>tr.even:hover>td,.tablesorter-bootstrap>tbody>tr.odd:hover>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~.tablesorter-childRow.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~.tablesorter-childRow.odd>td{background-color:#f5f5f5}.tablesorter-bootstrap>tbody>tr.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~tr.tablesorter-hasChildRow.even~.tablesorter-childRow.even>td{background-color:#fff}.tablesorter-bootstrap .tablesorter-processing{background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=);background-position:center center!important;background-repeat:no-repeat!important}.caption{background:#fff}.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter,.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter{width:98%;margin:0 auto;padding:4px 6px;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled{background-color:#eee;color:#555;cursor:not-allowed;border:1px solid #ccc;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.075) inset;box-sizing:border-box;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row td{background:#efefef;line-height:normal;text-align:center;padding:4px 6px;vertical-align:middle;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0}.tablesorter-bootstrap .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter .filtered{display:none}.tablesorter-bootstrap .tablesorter-pager select{padding:4px 6px}.tablesorter-bootstrap .tablesorter-pager .pagedisplay{border:0}.tablesorter-bootstrap tfoot i{font-size:11px}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
+/* colored table cells */ .table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5!important}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8!important;color:#468847!important}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6!important;color:#356635!important}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede!important;color:#b94a48!important}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc!important;color:#953b39!important}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3!important;color:#c09853!important}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc!important;color:#a47e3c!important}
+/* custom */ body{padding:4px;}tbody td{padding:2px 8px;}.counter-header{border-bottom: 1px solid #ccc;}.tablesorter-icon{top:2px!important;right:-6px!important;}.tablesorter-headerAsc,.tablesorter-headerDesc{background-color:#fafafa!important;}.gray-right-border{border-right:1px gray solid;}.rotate{-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg);-webkit-transform-origin:50% 50%;-moz-transform-origin:50% 50%;-ms-transform-origin:50% 50%;-o-transform-origin:50% 50%;transform-origin:50% 50%;filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);white-space:nowrap;height:140px;width: 20px;margin: 65px 0 -60px 0;padding-top:73px;}
diff --git a/library/cpp/lwtrace/mon/static/common.js b/library/cpp/lwtrace/mon/static/common.js
new file mode 100644
index 0000000000..42b93a6836
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/common.js
@@ -0,0 +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,"&quot;"),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();
+ }
+});
diff --git a/library/cpp/lwtrace/mon/static/css/bootstrap.min.css b/library/cpp/lwtrace/mon/static/css/bootstrap.min.css
new file mode 100644
index 0000000000..f602cacbf8
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/css/bootstrap.min.css
@@ -0,0 +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}}
diff --git a/library/cpp/lwtrace/mon/static/css/d3-gantt.css b/library/cpp/lwtrace/mon/static/css/d3-gantt.css
new file mode 100644
index 0000000000..25ba8fae6e
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/css/d3-gantt.css
@@ -0,0 +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
diff --git a/library/cpp/lwtrace/mon/static/css/jquery.treegrid.css b/library/cpp/lwtrace/mon/static/css/jquery.treegrid.css
new file mode 100644
index 0000000000..3980272607
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/css/jquery.treegrid.css
@@ -0,0 +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;}
diff --git a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000000..b93a4953ff
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000000..94fb5490a2
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +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="&#xa0;" />
+<glyph unicode="&#xa5;" 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="&#x2000;" horiz-adv-x="650" />
+<glyph unicode="&#x2001;" horiz-adv-x="1300" />
+<glyph unicode="&#x2002;" horiz-adv-x="650" />
+<glyph unicode="&#x2003;" horiz-adv-x="1300" />
+<glyph unicode="&#x2004;" horiz-adv-x="433" />
+<glyph unicode="&#x2005;" horiz-adv-x="325" />
+<glyph unicode="&#x2006;" horiz-adv-x="216" />
+<glyph unicode="&#x2007;" horiz-adv-x="216" />
+<glyph unicode="&#x2008;" horiz-adv-x="162" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="325" />
+<glyph unicode="&#x20ac;" 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="&#x20bd;" 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="&#x2212;" 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="&#x231b;" 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="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" 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="&#x26fa;" 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="&#x2709;" 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="&#x270f;" 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="&#xe001;" 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="&#xe002;" 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="&#xe003;" 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="&#xe005;" 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="&#xe006;" 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="&#xe007;" 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="&#xe008;" 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="&#xe009;" 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="&#xe010;" 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="&#xe011;" 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="&#xe012;" 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="&#xe013;" 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="&#xe014;" 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="&#xe015;" 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="&#xe016;" 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="&#xe017;" 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="&#xe018;" 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="&#xe019;" 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="&#xe020;" 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="&#xe021;" 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="&#xe022;" 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="&#xe023;" 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="&#xe024;" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" 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="&#xe026;" 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="&#xe027;" 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="&#xe028;" 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="&#xe029;" 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="&#xe030;" 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="&#xe031;" 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="&#xe032;" 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="&#xe033;" 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="&#xe034;" 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="&#xe035;" 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="&#xe036;" 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="&#xe037;" 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="&#xe038;" 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="&#xe039;" 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="&#xe040;" 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="&#xe041;" 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="&#xe042;" 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="&#xe043;" 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="&#xe044;" 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="&#xe045;" 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="&#xe046;" 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="&#xe047;" 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="&#xe048;" 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="&#xe049;" 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="&#xe050;" 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="&#xe051;" 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="&#xe052;" 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="&#xe053;" 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="&#xe054;" 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="&#xe055;" 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="&#xe056;" 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="&#xe057;" 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="&#xe058;" 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="&#xe059;" 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="&#xe060;" 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="&#xe062;" 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="&#xe063;" 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="&#xe064;" 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="&#xe065;" 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="&#xe066;" 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="&#xe067;" 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="&#xe068;" 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="&#xe069;" 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="&#xe070;" 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="&#xe071;" 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="&#xe072;" 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="&#xe073;" 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="&#xe074;" 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="&#xe075;" 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="&#xe076;" 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="&#xe077;" 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="&#xe078;" 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="&#xe079;" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
+<glyph unicode="&#xe080;" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
+<glyph unicode="&#xe081;" 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="&#xe082;" 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="&#xe083;" 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="&#xe084;" 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="&#xe085;" 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="&#xe086;" 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="&#xe087;" 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="&#xe088;" 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="&#xe089;" 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="&#xe090;" 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="&#xe091;" 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="&#xe092;" 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="&#xe093;" 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="&#xe094;" 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="&#xe095;" 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="&#xe096;" 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="&#xe097;" 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="&#xe101;" 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="&#xe102;" 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="&#xe103;" 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="&#xe104;" 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="&#xe105;" 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="&#xe106;" 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="&#xe107;" 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="&#xe108;" 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="&#xe109;" 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="&#xe110;" 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="&#xe111;" 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="&#xe112;" 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="&#xe113;" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
+<glyph unicode="&#xe114;" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
+<glyph unicode="&#xe115;" 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="&#xe116;" 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="&#xe117;" 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="&#xe118;" 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="&#xe119;" 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="&#xe120;" 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="&#xe121;" 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="&#xe122;" 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="&#xe123;" 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="&#xe124;" 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="&#xe125;" 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="&#xe126;" 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="&#xe127;" 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="&#xe128;" 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="&#xe129;" 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="&#xe130;" 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="&#xe131;" 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="&#xe132;" 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="&#xe133;" 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="&#xe134;" 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="&#xe135;" 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="&#xe136;" 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="&#xe137;" 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="&#xe138;" 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="&#xe139;" 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="&#xe140;" 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="&#xe141;" 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="&#xe142;" 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="&#xe143;" 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="&#xe144;" 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="&#xe145;" 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="&#xe146;" 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="&#xe148;" 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="&#xe149;" 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="&#xe150;" 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="&#xe151;" 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="&#xe152;" 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="&#xe153;" 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="&#xe154;" 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="&#xe155;" 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="&#xe156;" 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="&#xe157;" 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="&#xe158;" 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="&#xe159;" 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="&#xe160;" 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="&#xe161;" 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="&#xe162;" 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="&#xe163;" 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="&#xe164;" 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="&#xe165;" 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="&#xe166;" 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="&#xe167;" 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="&#xe168;" 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="&#xe169;" 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="&#xe170;" 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="&#xe171;" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
+<glyph unicode="&#xe172;" 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="&#xe173;" 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="&#xe174;" 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="&#xe175;" 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="&#xe176;" 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="&#xe177;" 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="&#xe178;" 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="&#xe179;" 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="&#xe180;" 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="&#xe181;" 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="&#xe182;" 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="&#xe183;" 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="&#xe184;" 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="&#xe185;" 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="&#xe186;" 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="&#xe187;" 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="&#xe188;" 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="&#xe189;" 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="&#xe190;" 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="&#xe191;" 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="&#xe192;" 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="&#xe193;" 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="&#xe194;" 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="&#xe195;" 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="&#xe197;" 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="&#xe198;" 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="&#xe199;" 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="&#xe200;" 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="&#xe201;" 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="&#xe202;" 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="&#xe203;" 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="&#xe204;" 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="&#xe205;" 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="&#xe206;" 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="&#xe209;" 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="&#xe210;" 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="&#xe211;" 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="&#xe212;" 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="&#xe213;" 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="&#xe214;" 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="&#xe215;" 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="&#xe216;" 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="&#xe218;" 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="&#xe219;" 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="&#xe221;" 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="&#xe223;" 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="&#xe224;" 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="&#xe225;" 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="&#xe226;" 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="&#xe227;" 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="&#xe230;" 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="&#xe231;" 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="&#xe232;" 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="&#xe233;" 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="&#xe234;" 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="&#xe235;" 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="&#xe236;" 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="&#xe237;" 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="&#xe238;" 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="&#xe239;" 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="&#xe240;" 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="&#xe241;" 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="&#xe242;" 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="&#xe243;" 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="&#xe244;" 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="&#xe245;" 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="&#xe246;" 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="&#xe247;" 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="&#xe248;" 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="&#xe249;" 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="&#xe250;" 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="&#xe251;" 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="&#xe252;" 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="&#xe253;" 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="&#xe254;" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
+<glyph unicode="&#xe255;" 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="&#xe256;" 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="&#xe257;" 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="&#xe258;" 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="&#xe259;" 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="&#xe260;" 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="&#xf8ff;" 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="&#x1f511;" 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="&#x1f6aa;" 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/fonts/glyphicons-halflings-regular.ttf b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000000..1413fc609a
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000000..9e612858f8
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2 b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2
new file mode 100644
index 0000000000..64539b54c3
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/footer.html b/library/cpp/lwtrace/mon/static/footer.html
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/footer.html
diff --git a/library/cpp/lwtrace/mon/static/header.html b/library/cpp/lwtrace/mon/static/header.html
new file mode 100644
index 0000000000..9a263673d3
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/header.html
@@ -0,0 +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>
diff --git a/library/cpp/lwtrace/mon/static/img/collapse.png b/library/cpp/lwtrace/mon/static/img/collapse.png
new file mode 100644
index 0000000000..76577a57a2
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/img/collapse.png
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/img/expand.png b/library/cpp/lwtrace/mon/static/img/expand.png
new file mode 100644
index 0000000000..cfb42a4512
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/img/expand.png
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/img/file.png b/library/cpp/lwtrace/mon/static/img/file.png
new file mode 100644
index 0000000000..813f712f72
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/img/file.png
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/img/folder.png b/library/cpp/lwtrace/mon/static/img/folder.png
new file mode 100644
index 0000000000..784e8fa482
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/img/folder.png
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/js/bootstrap.min.js b/library/cpp/lwtrace/mon/static/js/bootstrap.min.js
new file mode 100644
index 0000000000..80e40418f2
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/bootstrap.min.js
@@ -0,0 +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);
diff --git a/library/cpp/lwtrace/mon/static/js/d3-gantt.js b/library/cpp/lwtrace/mon/static/js/d3-gantt.js
new file mode 100644
index 0000000000..54ec38ae57
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/d3-gantt.js
@@ -0,0 +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
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
new file mode 100644
index 0000000000..ad3a6c0d19
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js
@@ -0,0 +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
+}));
diff --git a/library/cpp/lwtrace/mon/static/js/d3.v4.min.js b/library/cpp/lwtrace/mon/static/js/d3.v4.min.js
new file mode 100644
index 0000000000..6a2705865c
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/d3.v4.min.js
@@ -0,0 +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
diff --git a/library/cpp/lwtrace/mon/static/js/filesaver.min.js b/library/cpp/lwtrace/mon/static/js/filesaver.min.js
new file mode 100644
index 0000000000..b431d9bc5b
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/filesaver.min.js
@@ -0,0 +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)});
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js b/library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js
new file mode 100644
index 0000000000..c17018b4f6
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js
@@ -0,0 +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);
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.flot.min.js b/library/cpp/lwtrace/mon/static/js/jquery.flot.min.js
new file mode 100644
index 0000000000..81083f1819
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.min.js
@@ -0,0 +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);
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
new file mode 100644
index 0000000000..af5ecd21e1
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.navigate.min.js
@@ -0,0 +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);
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
new file mode 100644
index 0000000000..a0154fbc5b
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.selection.min.js
@@ -0,0 +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
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.min.js b/library/cpp/lwtrace/mon/static/js/jquery.min.js
new file mode 100644
index 0000000000..ee48790811
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.min.js
@@ -0,0 +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&&copy&&(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&&notxml&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{elem.setAttribute(name,value+"");return value}}else if(hooks&&"get"in hooks&&notxml&&(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&&currentStyle.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
new file mode 100644
index 0000000000..ac4a835205
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js
@@ -0,0 +1,4 @@
+$.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
new file mode 100644
index 0000000000..7b7566f323
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.treegrid.min.js
@@ -0,0 +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
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.url.min.js b/library/cpp/lwtrace/mon/static/js/jquery.url.min.js
new file mode 100644
index 0000000000..8ac9051a2a
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.url.min.js
@@ -0,0 +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)}});
diff --git a/library/cpp/lwtrace/mon/trace.sh b/library/cpp/lwtrace/mon/trace.sh
new file mode 100755
index 0000000000..8414a9b0ca
--- /dev/null
+++ b/library/cpp/lwtrace/mon/trace.sh
@@ -0,0 +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"
diff --git a/library/cpp/lwtrace/mon/ya.make b/library/cpp/lwtrace/mon/ya.make
new file mode 100644
index 0000000000..bdcb315754
--- /dev/null
+++ b/library/cpp/lwtrace/mon/ya.make
@@ -0,0 +1,55 @@
+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(
+ library/cpp/html/pcdata
+ library/cpp/lwtrace
+ library/cpp/lwtrace/mon/analytics
+ library/cpp/monlib/dynamic_counters
+ library/cpp/resource
+ library/cpp/string_utils/base64
+)
+
+END()
diff --git a/library/cpp/lwtrace/param_traits.h b/library/cpp/lwtrace/param_traits.h
new file mode 100644
index 0000000000..a0faeb50db
--- /dev/null
+++ b/library/cpp/lwtrace/param_traits.h
@@ -0,0 +1,66 @@
+#pragma once
+#include "signature.h"
+
+#include <util/datetime/base.h>
+#include <util/string/builder.h>
+
+#include <limits>
+
+#ifndef LWTRACE_DISABLE
+
+namespace NLWTrace {
+
+ template <>
+ struct TParamTraits<TInstant> {
+ using TStoreType = double;
+ using TFuncParam = TInstant;
+
+ inline static void ToString(TStoreType value, TString* out) {
+ *out = TParamConv<TStoreType>::ToString(value);
+ }
+
+ inline static TStoreType ToStoreType(TInstant value) {
+ if (value == TInstant::Max()) {
+ return std::numeric_limits<TStoreType>::infinity();
+ } else {
+ return static_cast<TStoreType>(value.MicroSeconds()) / 1000000.0; // seconds count
+ }
+ }
+ };
+
+ template <>
+ struct TParamTraits<TDuration> {
+ using TStoreType = double;
+ using TFuncParam = TDuration;
+
+ inline static void ToString(TStoreType value, TString* out) {
+ *out = TParamConv<TStoreType>::ToString(value);
+ }
+
+ inline static TStoreType ToStoreType(TDuration value) {
+ if (value == TDuration::Max()) {
+ return std::numeric_limits<TStoreType>::infinity();
+ } else {
+ return static_cast<TStoreType>(value.MicroSeconds()) / 1000.0; // milliseconds count
+ }
+ }
+ };
+
+ // Param for enum with GENERATE_ENUM_SERIALIZATION enabled or operator<< implemented
+ template <class TEnum>
+ struct TEnumParamWithSerialization {
+ using TStoreType = typename TParamTraits<std::underlying_type_t<TEnum>>::TStoreType;
+ using TFuncParam = TEnum;
+
+ inline static void ToString(TStoreType stored, TString* out) {
+ *out = TStringBuilder() << static_cast<TEnum>(stored) << " (" << stored << ")";
+ }
+
+ inline static TStoreType ToStoreType(TFuncParam v) {
+ return static_cast<TStoreType>(v);
+ }
+ };
+
+} // namespace NLWTrace
+
+#endif // LWTRACE_DISABLE
diff --git a/library/cpp/lwtrace/perf.cpp b/library/cpp/lwtrace/perf.cpp
new file mode 100644
index 0000000000..03b68586ea
--- /dev/null
+++ b/library/cpp/lwtrace/perf.cpp
@@ -0,0 +1,84 @@
+#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;
+ }
+
+}
diff --git a/library/cpp/lwtrace/perf.h b/library/cpp/lwtrace/perf.h
new file mode 100644
index 0000000000..d535247196
--- /dev/null
+++ b/library/cpp/lwtrace/perf.h
@@ -0,0 +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);
+ }
+ };
+
+}
diff --git a/library/cpp/lwtrace/preprocessor.h b/library/cpp/lwtrace/preprocessor.h
new file mode 100644
index 0000000000..40865467b2
--- /dev/null
+++ b/library/cpp/lwtrace/preprocessor.h
@@ -0,0 +1,295 @@
+#pragma once
+
+#include "check.h"
+#include "perf.h"
+#include "symbol.h"
+
+#include <util/generic/hide_ptr.h>
+#include <util/system/platform.h>
+
+#include <stddef.h> //size_t
+
+#ifdef _win_
+#ifndef LWTRACE_DISABLE
+#define LWTRACE_DISABLE
+#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
+// 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__) \
+ /**/
+
+// 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__) \
+ /**/
+
+// 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_LEFT_TYPE(MACRO, ...) \
+ 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) \
+ /**/
+
+#define FOREACH_DESTINATION_TYPE(MACRO, ...) \
+ 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))
+#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_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, \
+ /* 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) /**/
+
+#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
diff --git a/library/cpp/lwtrace/probe.h b/library/cpp/lwtrace/probe.h
new file mode 100644
index 0000000000..31fa282da3
--- /dev/null
+++ b/library/cpp/lwtrace/probe.h
@@ -0,0 +1,266 @@
+#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*&) {
+ }
+
+#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);
+ 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);
+ 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
+
+}
diff --git a/library/cpp/lwtrace/probes.cpp b/library/cpp/lwtrace/probes.cpp
new file mode 100644
index 0000000000..6f19da0cc8
--- /dev/null
+++ b/library/cpp/lwtrace/probes.cpp
@@ -0,0 +1,3 @@
+#include "probes.h"
+
+LWTRACE_DEFINE_PROVIDER(LWTRACE_INTERNAL_PROVIDER)
diff --git a/library/cpp/lwtrace/probes.h b/library/cpp/lwtrace/probes.h
new file mode 100644
index 0000000000..68810bd118
--- /dev/null
+++ b/library/cpp/lwtrace/probes.h
@@ -0,0 +1,23 @@
+#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"), \
+ TYPES(TString, TString), \
+ NAMES("probeName", "providerName")) \
+ PROBE(Fork, GROUPS(), \
+ TYPES(ui64), \
+ NAMES("spanId")) \
+ PROBE(Join, GROUPS(), \
+ TYPES(ui64, ui64), \
+ NAMES("spanId", "trackLength")) \
+ 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
new file mode 100644
index 0000000000..0051095719
--- /dev/null
+++ b/library/cpp/lwtrace/protos/lwtrace.proto
@@ -0,0 +1,266 @@
+/*
+ * This file defines language for trace queries and serialization format for trace logs
+ */
+syntax = "proto3";
+
+package NLWTrace;
+
+option go_package = "a.yandex-team.ru/library/cpp/lwtrace/protos";
+
+message TProbeDesc {
+ string Name = 1; // Use either name+provider
+ string Provider = 3;
+ string Group = 2; // or group
+}
+
+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;
+ string Variable = 3;
+}
+
+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 {
+ 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 {
+ string Name = 1;
+ repeated string Opts = 2;
+}
+
+enum EStatementType {
+ ST_MOV = 0;
+ ST_ADD = 1;
+ ST_SUB = 2;
+ ST_MUL = 3;
+ ST_DIV = 4;
+ ST_MOD = 5;
+ ST_ADD_EQ = 6;
+ ST_SUB_EQ = 7;
+ ST_INC = 8;
+ ST_DEC = 9;
+}
+
+message TStatementAction {
+ EStatementType Type = 1;
+ repeated TArgument Argument = 2;
+}
+
+message TRunLogShuttleAction {
+ bool Ignore = 1;
+ uint64 ShuttlesCount = 2;
+ uint64 MaxTrackLength = 3;
+}
+
+message TEditLogShuttleAction {
+ bool Ignore = 1;
+}
+
+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 {
+ 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)
+ uint32 PerThreadLogSize = 1;
+
+ // 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 {
+ string Name = 1;
+ 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;
+ uint64 Timestamp = 5; // microseconds since epoch
+ uint64 TimestampCycles = 6; // cycles since machine boot
+}
+
+message TThreadLogPb {
+ uint64 ThreadId = 1;
+ 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
+ string Hostname = 101;
+
+ // Traced process info
+ string ProcessName = 201;
+ bytes CommandLine = 202;
+ uint64 ProcessStartTime = 203;
+ uint64 Pid = 204;
+ string VersionInfo = 205; // Svn info
+
+ // Trace query and results
+ TQuery Query = 301;
+ repeated TEventPb Events = 302;
+ repeated TThreadLogPb ThreadLogs = 303;
+}
+
+message TShuttlePb {
+ repeated TLogPb Parts = 1;
+ TQuery Query = 2;
+}
+
+message TOrbitPb {
+ repeated TShuttlePb Shuttles = 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Trace parameter.
+
+message TTraceParam
+{
+ // Value.
+ oneof Value
+ {
+ int64 IntValue = 2;
+ uint64 UintValue = 3;
+ double DoubleValue = 4;
+ bytes StrValue = 5;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Trace Event .
+
+message TTraceEvent
+{
+ // Probe name.
+ string Name = 1;
+
+ // Provider name.
+ string Provider = 2;
+
+ // Probe parameters.
+ repeated TTraceParam Params = 3;
+
+ // Event timestamp in nanosec since epoch.
+ uint64 TimestampNanosec = 4;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Shuttle trace .
+
+message TShuttleTrace
+{
+ // Request events.
+ repeated TTraceEvent Events = 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Trace request.
+
+message TTraceRequest
+{
+ // trace id of remote trace session
+ bool IsTraced = 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Trace response.
+
+message TTraceResponse
+{
+ // traced events
+ TShuttleTrace Trace = 1;
+}
diff --git a/library/cpp/lwtrace/protos/ya.make b/library/cpp/lwtrace/protos/ya.make
new file mode 100644
index 0000000000..503d5e515f
--- /dev/null
+++ b/library/cpp/lwtrace/protos/ya.make
@@ -0,0 +1,11 @@
+PROTO_LIBRARY()
+
+OWNER(serxa)
+
+INCLUDE_TAGS(GO_PROTO)
+
+SRCS(
+ lwtrace.proto
+)
+
+END()
diff --git a/library/cpp/lwtrace/rwspinlock.h b/library/cpp/lwtrace/rwspinlock.h
new file mode 100644
index 0000000000..7c518ec49e
--- /dev/null
+++ b/library/cpp/lwtrace/rwspinlock.h
@@ -0,0 +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();
+ }
+
+ 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();
+ }
+};
+
+using TReadSpinLockGuard = TGuard<TRWSpinLock, TRWSpinLockReadOps>;
+using TWriteSpinLockGuard = TGuard<TRWSpinLock, TRWSpinLockWriteOps>;
diff --git a/library/cpp/lwtrace/shuttle.cpp b/library/cpp/lwtrace/shuttle.cpp
new file mode 100644
index 0000000000..6ef6982aea
--- /dev/null
+++ b/library/cpp/lwtrace/shuttle.cpp
@@ -0,0 +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
diff --git a/library/cpp/lwtrace/shuttle.h b/library/cpp/lwtrace/shuttle.h
new file mode 100644
index 0000000000..85c6e4da61
--- /dev/null
+++ b/library/cpp/lwtrace/shuttle.h
@@ -0,0 +1,358 @@
+#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 <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;
+ ui64 SpanId;
+ ui64 ParentSpanId = 0;
+ TAtomic Status = 0;
+ static constexpr ui64 DeadFlag = 0x1ull;
+ TShuttlePtr Next;
+
+ public:
+ explicit IShuttle(ui64 traceIdx, ui64 spanId)
+ : TraceIdx(traceIdx)
+ , SpanId(spanId)
+ {
+ }
+
+ virtual ~IShuttle() {
+ }
+
+ ui64 GetTraceIdx() const {
+ return TraceIdx;
+ }
+
+ ui64 GetSpanId() const {
+ return SpanId;
+ }
+
+ ui64 GetParentSpanId() const {
+ return ParentSpanId;
+ }
+
+ void SetParentSpanId(ui64 parentSpanId) {
+ 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;
+ }
+ }
+ }
+
+ 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 Detach(); // Detached from orbit on Drop
+ }
+
+ TShuttlePtr Detach() {
+ 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);
+ }
+
+ bool Join(TShuttlePtr& child) {
+ return UnlessDead([&] {
+ return DoJoin(child);
+ }, false);
+ }
+
+ bool IsDead() {
+ return AtomicGet(Status) & DeadFlag;
+ }
+
+ protected:
+ virtual bool DoAddProbe(TProbe* probe, const TParams& params, ui64 timestamp) = 0;
+ virtual void DoEndOfTrack() = 0;
+ virtual void DoDrop() = 0;
+ virtual void DoSerialize(TShuttleTrace& msg) = 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:
+ TOrbit() = default;
+ TOrbit(const TOrbit&) = delete;
+ TOrbit(TOrbit&&) = default;
+
+ 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();
+ }
+ });
+ });
+ }
+
+ 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) {
+ 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();
+ }
+ }
+ 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;
+ });
+ });
+ }
+
+ 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;
+ while (IShuttle* child = ref->Get()) {
+ if (parent->GetTraceIdx() == child->GetTraceIdx() && parent->GetSpanId() == child->GetParentSpanId()) {
+ TShuttlePtr next = child->Detach();
+ parent->Join(*ref);
+ *ref = next;
+ } else {
+ ref = &child->GetNext();
+ }
+ }
+ }
+
+ 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
new file mode 100644
index 0000000000..868bd9bcf2
--- /dev/null
+++ b/library/cpp/lwtrace/signature.h
@@ -0,0 +1,772 @@
+#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/string/builder.h>
+#include <util/string/cast.h>
+#include <util/string/printf.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_enum_reflection.h>
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#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 {
+ return *reinterpret_cast<const T*>(Data);
+ }
+
+ 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];
+ };
+
+ 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);
+ 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);
+ }
+
+ void SerializeToPb(const TParams& params, TSerializedParams& arr) const
+ {
+ (*SerializeToPbFunc)(params, arr);
+ }
+
+ bool DeserializeFromPb(TParams& params, const TSerializedParams& arr) const
+ {
+ 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>
+ struct TParamTraits;
+
+ // Enum types traits impl.
+ template <class TEnum, class = std::enable_if_t<std::is_enum_v<TEnum>>>
+ struct TEnumParamTraitsImpl {
+ using TStoreType = typename TParamTraits<std::underlying_type_t<TEnum>>::TStoreType;
+ using TFuncParam = TEnum;
+
+ 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) {
+ *out = TStringBuilder() << valueDescriptor->name() << " (" << stored << ")";
+ } else {
+ *out = TParamConv<TStoreType>::ToString(stored);
+ }
+ } 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
+ using TFuncParam = typename TCustomType::TFuncParam;
+
+ inline static void ToString(typename TTypeTraits<TStoreType>::TFuncParam stored, TString* out) {
+ TCustomType::ToString(stored, out);
+ }
+
+ inline static TStoreType ToStoreType(TFuncParam v) {
+ return TCustomType::ToStoreType(v);
+ }
+ };
+
+ template <class T, bool isEnum>
+ struct TParamTraitsImpl;
+
+ template <class TEnum>
+ struct TParamTraitsImpl<TEnum, true> : TEnumParamTraitsImpl<TEnum> {
+ };
+
+ template <class TCustomType>
+ struct TParamTraitsImpl<TCustomType, false> : TCustomTraitsImpl<TCustomType> {
+ };
+
+ template <class T>
+ struct TParamTraits : TParamTraitsImpl<T, std::is_enum_v<T>> {
+ };
+
+ // Standard stored types traits.
+
+#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); \
+ } \
+ \
+ 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);
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) STORE_TYPE_AS(t, t)
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef STORE_TYPE_AS
+#undef FOREACH_PARAMTYPE_MACRO
+
+ // Nil type staits.
+ 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) { \
+ return PT_##v; \
+ } \
+ /**/
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+ return PT_UNKNOWN;
+ }
+
+ template <typename T>
+ inline void SaveParamToPb(TSerializedParams& msg, const TParam& param);
+
+ template <>
+ inline void SaveParamToPb<TNil>(TSerializedParams& msg, const TParam& param)
+ {
+ Y_UNUSED(msg);
+ Y_UNUSED(param);
+ }
+
+ template <>
+ inline void SaveParamToPb<i64>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetIntValue(param.Get<typename TParamTraits<i64>::TStoreType>());
+ }
+
+ template <>
+ inline void SaveParamToPb<ui64>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetUintValue(param.Get<typename TParamTraits<ui64>::TStoreType>());
+ }
+
+ template <>
+ inline void SaveParamToPb<double>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetDoubleValue(param.Get<typename TParamTraits<double>::TStoreType>());
+ }
+
+ template <>
+ inline void SaveParamToPb<TString>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetStrValue(param.Get<typename TParamTraits<TString>::TStoreType>());
+ }
+
+ template <>
+ inline void SaveParamToPb<TSymbol>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetStrValue(*param.Get<typename TParamTraits<TSymbol>::TStoreType>().Str);
+ }
+
+ template <>
+ inline void SaveParamToPb<TCheck>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetIntValue(param.Get<typename TParamTraits<TCheck>::TStoreType>().Value);
+ }
+
+ template <typename T>
+ inline void LoadParamFromPb(const TTraceParam& msg, TParam& param);
+
+ template <>
+ inline void LoadParamFromPb<i64>(const TTraceParam& msg, TParam& param)
+ {
+ param.DefaultConstruct<i64>();
+ param.Get<i64>() = msg.GetIntValue();
+ }
+
+ template <>
+ inline void LoadParamFromPb<ui64>(const TTraceParam& msg, TParam& param)
+ {
+ param.DefaultConstruct<ui64>();
+ param.Get<ui64>() = msg.GetUintValue();
+ }
+
+ template <>
+ inline void LoadParamFromPb<double>(const TTraceParam& msg, TParam& param)
+ {
+ param.DefaultConstruct<double>();
+ param.Get<double>() = msg.GetDoubleValue();
+ }
+
+ template <>
+ inline void LoadParamFromPb<TCheck>(const TTraceParam& msg, TParam& param)
+ {
+ param.CopyConstruct<TCheck>(TCheck(msg.GetIntValue()));
+ }
+
+ template <>
+ inline void LoadParamFromPb<TSymbol>(const TTraceParam& msg, TParam& param)
+ {
+ Y_UNUSED(msg);
+ Y_UNUSED(param);
+ static TString unsupported("unsupported");
+ // so far TSymbol deserialization is not supported
+ // since it is not used for probes, it is ok
+ param.CopyConstruct<TSymbol>(TSymbol(&unsupported));
+ }
+
+ template <>
+ inline void LoadParamFromPb<TString>(const TTraceParam& msg, TParam& param)
+ {
+ param.DefaultConstruct<TString>();
+ param.Get<TString>() = msg.GetStrValue();
+ }
+
+ template <>
+ inline void LoadParamFromPb<TNil>(const TTraceParam& msg, TParam& param)
+ {
+ Y_UNUSED(msg);
+ 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
+ }
+
+ // Implementation of virtual function (TSignature derived classes vtable emulation)
+ inline static void SerializeToPb(const TParams& params, TSerializedParams& arr)
+ {
+#define FOREACH_PARAMNUM_MACRO(i) \
+ SaveParamToPb<typename TParamTraits<TP##i>::TStoreType>( \
+ arr, \
+ params.Param[i]); \
+// FOREACH_PARAMNUM_MACRO
+ FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO);
+#undef FOREACH_PARAMNUM_MACRO
+ }
+
+ // Implementation of virtual function (TSignature derived classes vtable emulation)
+ inline static bool DeserializeFromPb(TParams& params, const TSerializedParams& arr) {
+ if (arr.size() != ParamCount) {
+ return false;
+ }
+ if (!ParamCount) {
+ return true;
+ }
+
+ int paramIdx = 0;
+#define FOREACH_PARAMNUM_MACRO(i) \
+ if (paramIdx >= arr.size()) { \
+ return true; \
+ }; \
+ LoadParamFromPb<typename TParamTraits<TP##i>::TStoreType>( \
+ arr.Get(paramIdx), \
+ params.Param[paramIdx]); \
+ ++paramIdx; \
+// FOREACH_PARAMNUM_MACRO
+ FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO);
+#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
+
+}
diff --git a/library/cpp/lwtrace/sleep_action.cpp b/library/cpp/lwtrace/sleep_action.cpp
new file mode 100644
index 0000000000..74977528db
--- /dev/null
+++ b/library/cpp/lwtrace/sleep_action.cpp
@@ -0,0 +1,15 @@
+#include "sleep_action.h"
+
+#include "control.h"
+
+#include <util/system/datetime.h>
+
+#include <stdlib.h>
+
+using namespace NLWTrace;
+using namespace NLWTrace::NPrivate;
+
+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
new file mode 100644
index 0000000000..26f89bd88c
--- /dev/null
+++ b/library/cpp/lwtrace/sleep_action.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "probe.h"
+
+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;
+ };
+
+ }
+}
diff --git a/library/cpp/lwtrace/start.cpp b/library/cpp/lwtrace/start.cpp
new file mode 100644
index 0000000000..121d5472b6
--- /dev/null
+++ b/library/cpp/lwtrace/start.cpp
@@ -0,0 +1,69 @@
+#include "start.h"
+
+#include "all.h"
+
+#include <google/protobuf/text_format.h>
+
+#include <util/generic/singleton.h>
+#include <util/stream/file.h>
+#include <util/stream/output.h>
+#include <util/system/env.h>
+
+#include <stdlib.h>
+
+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;
+ }
+
+ TString path = GetEnv("LWTRACE");
+ if (!path) {
+ return;
+ }
+
+ try {
+ TraceFromEnv(path);
+ } catch (...) {
+ Cerr << "failed to load lwtrace script: " << CurrentExceptionMessage() << "\n";
+ abort();
+ }
+}
+
+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();
+ }
+}
diff --git a/library/cpp/lwtrace/start.h b/library/cpp/lwtrace/start.h
new file mode 100644
index 0000000000..2755212bff
--- /dev/null
+++ b/library/cpp/lwtrace/start.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <functional>
+
+namespace NLWTrace {
+ class TManager;
+
+ 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
new file mode 100644
index 0000000000..6e5654c338
--- /dev/null
+++ b/library/cpp/lwtrace/stderr_writer.cpp
@@ -0,0 +1,19 @@
+#include "stderr_writer.h"
+
+#include <util/stream/str.h>
+
+using namespace NLWTrace;
+
+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;
+ for (ui32 i = 0; i < Probe->Event.Signature.ParamCount; ++i) {
+ ss << " " << Probe->Event.Signature.ParamNames[i] << "=" << ParamValues[i];
+ }
+ ss << "\n";
+ Cerr << ss.Str();
+ return true;
+}
diff --git a/library/cpp/lwtrace/stderr_writer.h b/library/cpp/lwtrace/stderr_writer.h
new file mode 100644
index 0000000000..b17fc3136e
--- /dev/null
+++ b/library/cpp/lwtrace/stderr_writer.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "probe.h"
+
+namespace NLWTrace {
+ class TStderrActionExecutor: public IExecutor {
+ private:
+ TProbe* const Probe;
+
+ 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
new file mode 100644
index 0000000000..456652bcd0
--- /dev/null
+++ b/library/cpp/lwtrace/symbol.cpp
@@ -0,0 +1,15 @@
+#include "symbol.h"
+
+#include <util/stream/output.h>
+#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) {
+ Out<TString>(o, *t.Str);
+}
diff --git a/library/cpp/lwtrace/symbol.h b/library/cpp/lwtrace/symbol.h
new file mode 100644
index 0000000000..ef9e6cdf94
--- /dev/null
+++ b/library/cpp/lwtrace/symbol.h
@@ -0,0 +1,68 @@
+#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) { \
+ 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;
+ }
+ };
+
+}
diff --git a/library/cpp/lwtrace/tests/test_all_parallel.sh b/library/cpp/lwtrace/tests/test_all_parallel.sh
new file mode 100755
index 0000000000..8020783d67
--- /dev/null
+++ b/library/cpp/lwtrace/tests/test_all_parallel.sh
@@ -0,0 +1,29 @@
+
+mkdir -p out
+
+echo "
+ LogIntModFilter
+ SleepCheck
+ MultipleActionsCheck
+ KillCheck
+ InMemoryLog
+ InMemoryLogCheck
+ NoExec
+ Log
+ LogTs
+ FalseIntFilter
+ LogIntAfterFilter
+ LogInt
+ FalseStringFilter
+ FalseStringFilterPartialMatch
+ LogStringAfterFilter
+ LogString
+ LogCheck
+" | awk NF | ( while read l; do ./tests --unsafe-lwtrace 1 $l > out/out_$l.txt 2>out/err_$l.txt && echo done $l & done ; wait )
+
+
+grep . out/out_*.txt
+grep . out/err_*.txt --color=always
+
+
+
diff --git a/library/cpp/lwtrace/tests/trace_tests.cpp b/library/cpp/lwtrace/tests/trace_tests.cpp
new file mode 100644
index 0000000000..6762e344a7
--- /dev/null
+++ b/library/cpp/lwtrace/tests/trace_tests.cpp
@@ -0,0 +1,715 @@
+#include <library/cpp/lwtrace/all.h>
+
+#include <library/cpp/getopt/last_getopt.h>
+
+#include <google/protobuf/text_format.h>
+
+#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")) \
+ 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) {
+#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();
+ }
+#else
+ 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 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;
+ }
+}
diff --git a/library/cpp/lwtrace/tests/ya.make b/library/cpp/lwtrace/tests/ya.make
new file mode 100644
index 0000000000..6225ab1fa0
--- /dev/null
+++ b/library/cpp/lwtrace/tests/ya.make
@@ -0,0 +1,15 @@
+OWNER(serxa)
+
+PROGRAM()
+
+SRCS(
+ trace_tests.cpp
+)
+
+PEERDIR(
+ contrib/libs/protobuf
+ library/cpp/getopt
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/lwtrace/trace.cpp b/library/cpp/lwtrace/trace.cpp
new file mode 100644
index 0000000000..3c974c85a0
--- /dev/null
+++ b/library/cpp/lwtrace/trace.cpp
@@ -0,0 +1,1051 @@
+#include "all.h"
+#include "kill_action.h"
+#include "log_shuttle.h"
+#include "preprocessor.h"
+#include "sleep_action.h"
+#include "stderr_writer.h"
+#include "google/protobuf/repeated_field.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();
+ if (Probes.contains(probe)) {
+ 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);
+ }
+
+ 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())
+ , 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);
+ if (arg.GetVariable()) {
+ operand.Type = OT_VARIABLE;
+ } else if (arg.GetValue()) {
+ operand.Type = OT_LITERAL;
+ } else if (arg.GetParam()) {
+ 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";
+ }
+ 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) {
+ 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);
+
+ 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());
+ }
+
+#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()) {
+ actExec.Reset(new TRunLogShuttleActionExecutor<TDurationDepot>(TraceIdx, action.GetRunLogShuttleAction(), &DurationDepot, &LastTrackId, &LastSpanId));
+ } 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();
+ 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 {
+ 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.";
+ }
+ } 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) { \
+ 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) \
+ 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; \
+ }
+
+#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());
+ }
+ }
+ 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
+#undef PARSE_TERNARY_STATEMENT_MACRO
+#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()))
+ , CyclicLog(query.GetPerThreadLogSize() ? query.GetPerThreadLogSize() : 1000)
+ , DurationLog(StoreDuration)
+ , CyclicDepot(query.GetPerThreadLogSize() ? query.GetPerThreadLogSize() : 1000)
+ , 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();
+ 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() << "'";
+ }
+ } 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)
+ , 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);
+ 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();
+ }
+ }
+}
diff --git a/library/cpp/lwtrace/trace_ut.cpp b/library/cpp/lwtrace/trace_ut.cpp
new file mode 100644
index 0000000000..cb03e4fbde
--- /dev/null
+++ b/library/cpp/lwtrace/trace_ut.cpp
@@ -0,0 +1,880 @@
+#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,
+};
+
+enum class EEnumClass {
+ ValueC,
+ ValueD,
+};
+
+#define LWTRACE_UT_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(NoParam, 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")) \
+ PROBE(EnumParams, GROUPS("Group"), TYPES(ESimpleEnum, EEnumClass), NAMES("simpleEnum", "enumClass")) \
+ PROBE(InstantParam, GROUPS("Group"), TYPES(TInstant), NAMES("value")) \
+ 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;
+
+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);
+
+ 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 {
+ Name: "IntParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Predicate {
+ Operators {
+ Type: OT_NE
+ Argument { Param: "value" }
+ Argument { Value: "1" }
+ }
+ }
+ Action {
+ LogAction { }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("QueryName", q);
+ LWPROBE(IntParam, 3);
+ LWPROBE(IntParam, 1);
+ LWPROBE(IntParam, 4);
+ LWPROBE(IntParam, 1);
+ LWPROBE(IntParam, 1);
+ LWPROBE(IntParam, 5);
+ struct {
+ ui32 expected = 3;
+ ui32 logsCount = 0;
+ void Push(TThread::TId, const TLogItem& item) {
+ UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntParam");
+ ui32 value = item.GetParam("value").GetParam().Get<ui32>();
+ UNIT_ASSERT(value == expected);
+ expected++;
+ logsCount++;
+ }
+ } reader;
+ mngr.ReadLog("QueryName", reader);
+ UNIT_ASSERT(reader.logsCount == 3);
+ }
+
+ Y_UNIT_TEST(StatementAction) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "IntParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ StatementAction {
+ Type: ST_INC
+ Argument { Variable: "varInc" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_DEC
+ Argument { Variable: "varDec" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_MOV
+ Argument { Variable: "varMov" }
+ Argument { Value: "3" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_ADD_EQ
+ Argument { Variable: "varAddEq" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_ADD_EQ
+ Argument { Variable: "varAddEq" }
+ Argument { Value: "3" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_SUB_EQ
+ Argument { Variable: "varSubEq" }
+ Argument { Value: "5" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_ADD
+ Argument { Variable: "varAdd" }
+ Argument { Value: "3" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_SUB
+ Argument { Variable: "varSub" }
+ Argument { Value: "3" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_MUL
+ Argument { Variable: "varMul" }
+ Argument { Value: "6" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_DIV
+ Argument { Variable: "varDiv" }
+ Argument { Value: "6" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_MOD
+ Argument { Variable: "varMod" }
+ Argument { Value: "17" }
+ Argument { Value: "5" }
+ }
+ }
+ }
+ Blocks {
+ ProbeDesc {
+ Name: "IntParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Predicate {
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varInc" }
+ Argument { Value: "1" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varDec" }
+ Argument { Value: "-1" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMov" }
+ Argument { Value: "3" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varAddEq" }
+ Argument { Value: "5" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varSubEq" }
+ Argument { Value: "-5" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varAdd" }
+ Argument { Value: "5" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varSub" }
+ Argument { Value: "1" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMul" }
+ Argument { Value: "12" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varDiv" }
+ Argument { Value: "3" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMod" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ LogAction { }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("QueryName", q);
+ LWPROBE(IntParam, 1);
+ LWPROBE(IntParam, 2);
+ struct {
+ int logsCount = 0;
+ void Push(TThread::TId, const TLogItem& item) {
+ UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntParam");
+ ui32 value = item.GetParam("value").GetParam().Get<ui32>();
+ UNIT_ASSERT(value == 1);
+ logsCount++;
+ }
+ } reader;
+ mngr.ReadLog("QueryName", reader);
+ UNIT_ASSERT(reader.logsCount == 1);
+ }
+
+ Y_UNIT_TEST(StatementActionWithParams) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "IntIntParams"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ StatementAction {
+ Type: ST_MOV
+ Argument { Variable: "varMov" }
+ Argument { Param: "value1" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_ADD_EQ
+ Argument { Variable: "varAddEq" }
+ Argument { Param: "value1" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_SUB_EQ
+ Argument { Variable: "varSubEq" }
+ Argument { Param: "value1" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_ADD
+ Argument { Variable: "varAdd" }
+ Argument { Param: "value1" }
+ Argument { Param: "value2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_SUB
+ Argument { Variable: "varSub" }
+ Argument { Param: "value1" }
+ Argument { Param: "value2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_MUL
+ Argument { Variable: "varMul" }
+ Argument { Param: "value1" }
+ Argument { Param: "value2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_DIV
+ Argument { Variable: "varDiv" }
+ Argument { Param: "value1" }
+ Argument { Param: "value2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_MOD
+ Argument { Variable: "varMod" }
+ Argument { Param: "value1" }
+ Argument { Param: "value2" }
+ }
+ }
+ }
+ Blocks {
+ ProbeDesc {
+ Name: "IntIntParams"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Predicate {
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMov" }
+ Argument { Param: "value1" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varAddEq" }
+ Argument { Param: "value1" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varSubEq" }
+ Argument { Value: "-22" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varAdd" }
+ Argument { Value: "25" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varSub" }
+ Argument { Value: "19" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMul" }
+ Argument { Value: "66" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varDiv" }
+ Argument { Value: "7" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMod" }
+ Argument { Value: "1" }
+ }
+ }
+ Action {
+ LogAction { }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("QueryName", q);
+ LWPROBE(IntIntParams, 22, 3);
+ struct {
+ int logsCount = 0;
+ void Push(TThread::TId, const TLogItem& item) {
+ UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntIntParams");
+ logsCount++;
+ }
+ } reader;
+ mngr.ReadLog("QueryName", reader);
+ UNIT_ASSERT(reader.logsCount == 1);
+ }
+
+ Y_UNIT_TEST(PerThreadLogSize) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ PerThreadLogSize: 3
+ Blocks {
+ ProbeDesc {
+ Name: "IntParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ LogAction { }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("QueryRandom", q);
+ LWPROBE(IntParam, 1);
+ LWPROBE(IntParam, 2);
+ LWPROBE(IntParam, 3);
+ LWPROBE(IntParam, 4);
+ struct {
+ ui32 logsCount = 0;
+ ui32 expected = 2;
+ void Push(TThread::TId, const TLogItem& item) {
+ UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntParam");
+ ui32 value = item.GetParam("value").GetParam().Get<ui32>();
+ UNIT_ASSERT(value == expected);
+ logsCount++;
+ expected++;
+ }
+ } reader;
+ mngr.ReadLog("QueryRandom", reader);
+ UNIT_ASSERT(reader.logsCount == 3);
+ }
+
+ Y_UNIT_TEST(CustomAction) {
+ static ui32 nCustomActionsCalls = 0;
+ class TMyActionExecutor: public TCustomActionExecutor {
+ public:
+ TMyActionExecutor(TProbe* probe, const TCustomAction&, TSession*)
+ : TCustomActionExecutor(probe, false /* not destructive */)
+ {}
+ private:
+ bool DoExecute(TOrbit&, const TParams& params) override {
+ (void)params;
+ nCustomActionsCalls++;
+ return true;
+ }
+ };
+
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ mngr.RegisterCustomAction("MyCustomAction", [](TProbe* probe,
+ const TCustomAction& action,
+ TSession* session) {
+ return new TMyActionExecutor(probe, action, session);
+ }
+ );
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ CustomAction {
+ Name: "MyCustomAction"
+ }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("Query1", q);
+ LWPROBE(NoParam);
+ UNIT_ASSERT(nCustomActionsCalls == 1);
+ }
+
+ Y_UNIT_TEST(SafeModeSleepException) {
+ TManager mngr(*Singleton<TProbeRegistry>(), false);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ SleepAction {
+ NanoSeconds: 1000000000
+ }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ UNIT_ASSERT_EXCEPTION(mngr.New("QueryName", q), yexception);
+ }
+
+ Y_UNIT_TEST(Sleep) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ SleepAction {
+ NanoSeconds: 1000
+ }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("QueryName", q);
+ const ui64 sleepTimeNs = 1000; // 1 us
+
+ TInstant t0 = Now();
+ LWPROBE(NoParam);
+ TInstant t1 = Now();
+ UNIT_ASSERT(t1.NanoSeconds() - t0.NanoSeconds() >= sleepTimeNs);
+ }
+
+ Y_UNIT_TEST(ProtoEnumTraits) {
+ using TPbEnumTraits = TParamTraits<EOperatorType>;
+ TString str;
+ TPbEnumTraits::ToString(TPbEnumTraits::ToStoreType(OT_EQ), &str);
+ UNIT_ASSERT_STRINGS_EQUAL(str, "OT_EQ (0)");
+ }
+
+ 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 { }
+ }
+ }
+ )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);
+ }
+
+ Y_UNIT_TEST(ShouldSerializeTracks)
+ {
+ TManager manager(*Singleton<TProbeRegistry>(), false);
+
+ TOrbit orbit;
+ TTraceRequest req;
+ req.SetIsTraced(true);
+ manager.HandleTraceRequest(req, orbit);
+
+ LWTRACK(NoParam, orbit);
+ LWTRACK(IntParam, orbit, 1);
+ LWTRACK(StringParam, orbit, "str");
+ LWTRACK(EnumParams, orbit, ValueA, EEnumClass::ValueC);
+ LWTRACK(InstantParam, orbit, TInstant::Seconds(42));
+ LWTRACK(DurationParam, orbit, TDuration::MilliSeconds(146));
+ LWTRACK(ProtoEnum, orbit, OT_EQ);
+ LWTRACK(IntIntParams, orbit, 1, 2);
+
+ TTraceResponse resp;
+ orbit.Serialize(0, *resp.MutableTrace());
+ auto& r = resp.GetTrace();
+
+ UNIT_ASSERT_VALUES_EQUAL(8, r.EventsSize());
+
+ const auto& p0 = r.GetEvents(0);
+ UNIT_ASSERT_VALUES_EQUAL("NoParam", p0.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p0.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL(0 , p0.ParamsSize());
+
+ const auto& p1 = r.GetEvents(1);
+ UNIT_ASSERT_VALUES_EQUAL("IntParam", p1.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p1.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL(1, p1.GetParams(0).GetUintValue());
+
+ const auto& p2 = r.GetEvents(2);
+ UNIT_ASSERT_VALUES_EQUAL("StringParam", p2.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p2.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL("str", p2.GetParams(0).GetStrValue());
+
+ const auto& p3 = r.GetEvents(3);
+ UNIT_ASSERT_VALUES_EQUAL("EnumParams", p3.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p3.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL((ui32)ValueA, p3.GetParams(0).GetIntValue());
+ UNIT_ASSERT_VALUES_EQUAL((ui32)EEnumClass::ValueC, p3.GetParams(1).GetIntValue());
+
+ const auto& p4 = r.GetEvents(4);
+ UNIT_ASSERT_VALUES_EQUAL("InstantParam", p4.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p4.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL(42, p4.GetParams(0).GetDoubleValue());
+
+ const auto& p5 = r.GetEvents(5);
+ UNIT_ASSERT_VALUES_EQUAL("DurationParam", p5.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p5.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL(146, p5.GetParams(0).GetDoubleValue());
+
+ const auto& p6 = r.GetEvents(6);
+ UNIT_ASSERT_VALUES_EQUAL("ProtoEnum", p6.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p6.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL((int)OT_EQ, p6.GetParams(0).GetIntValue());
+
+ const auto& p7 = r.GetEvents(7);
+ UNIT_ASSERT_VALUES_EQUAL("IntIntParams", p7.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p7.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL(1, p7.GetParams(0).GetUintValue());
+ UNIT_ASSERT_VALUES_EQUAL(2, p7.GetParams(1).GetUintValue());
+ }
+
+ Y_UNIT_TEST(ShouldDeserializeTracks)
+ {
+ TManager manager(*Singleton<TProbeRegistry>(), false);
+
+ TTraceResponse resp;
+ auto& r = *resp.MutableTrace()->MutableEvents();
+
+ auto& p0 = *r.Add();
+ p0.SetName("NoParam");
+ p0.SetProvider("LWTRACE_UT_PROVIDER");
+
+ auto& p1 = *r.Add();
+ p1.SetName("IntParam");
+ p1.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p1param = *p1.MutableParams()->Add();
+ p1param.SetUintValue(1);
+
+ auto& p2 = *r.Add();
+ p2.SetName("StringParam");
+ p2.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p2param = *p2.MutableParams()->Add();
+ p2param.SetStrValue("str");
+
+ auto& p3 = *r.Add();
+ p3.SetName("EnumParams");
+ p3.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p3param1 = *p3.MutableParams()->Add();
+ p3param1.SetUintValue((ui64)EEnumClass::ValueC);
+ auto& p3param2 = *p3.MutableParams()->Add();
+ p3param2.SetIntValue((ui64)EEnumClass::ValueC);
+
+ auto& p4 = *r.Add();
+ p4.SetName("InstantParam");
+ p4.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p4param = *p4.MutableParams()->Add();
+ p4param.SetDoubleValue(42);
+
+ auto& p5 = *r.Add();
+ p5.SetName("DurationParam");
+ p5.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p5param = *p5.MutableParams()->Add();
+ p5param.SetDoubleValue(146);
+
+ auto& p6 = *r.Add();
+ p6.SetName("ProtoEnum");
+ p6.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p6param = *p6.MutableParams()->Add();
+ p6param.SetIntValue((i64)OT_EQ);
+
+ auto& p7 = *r.Add();
+ p7.SetName("IntIntParams");
+ p7.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p7param1 = *p7.MutableParams()->Add();
+ p7param1.SetIntValue(1);
+ auto& p7param2 = *p7.MutableParams()->Add();
+ p7param2.SetIntValue(2);
+
+ TOrbit orbit;
+ UNIT_ASSERT_VALUES_EQUAL(
+ manager.HandleTraceResponse(resp, manager.GetProbesMap(), orbit).IsSuccess,
+ true);
+ }
+
+ Y_UNIT_TEST(ShouldDeserializeWhatSerialized)
+ {
+ TManager manager(*Singleton<TProbeRegistry>(), false);
+
+ TOrbit orbit;
+ TTraceRequest req;
+ req.SetIsTraced(true);
+ manager.HandleTraceRequest(req, orbit);
+
+ LWTRACK(NoParam, orbit);
+ LWTRACK(IntParam, orbit, 1);
+ LWTRACK(StringParam, orbit, "str");
+ LWTRACK(EnumParams, orbit, ValueA, EEnumClass::ValueC);
+ LWTRACK(InstantParam, orbit, TInstant::Seconds(42));
+ LWTRACK(DurationParam, orbit, TDuration::MilliSeconds(146));
+ LWTRACK(ProtoEnum, orbit, OT_EQ);
+ LWTRACK(IntIntParams, orbit, 1, 2);
+
+ TTraceResponse resp;
+ auto& r = *resp.MutableTrace();
+ orbit.Serialize(0, r);
+
+ TOrbit orbit1;
+ UNIT_ASSERT_VALUES_EQUAL(
+ manager.HandleTraceResponse(resp, manager.GetProbesMap(), orbit1).IsSuccess,
+ true);
+ }
+
+ Y_UNIT_TEST(TrackForkJoin) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ RunLogShuttleAction { }
+ }
+ }
+ )END", &q);
+
+ UNIT_ASSERT(parsed);
+ mngr.New("Query1", q);
+
+ {
+ TOrbit a, b, c, d;
+
+ // Graph:
+ // c
+ // / \
+ // b-f-b-j-b
+ // / \
+ // a-f-a-f-a-j-a-j-a
+ // \ /
+ // d
+ //
+ // Merged track:
+ // a-f(b)-a-f(d)-a-j(d,1)-d-a-j(b,6)-b-f(c)-b-j(c,1)-c-b-a
+
+ LWTRACK(NoParam, a);
+ a.Fork(b);
+ LWTRACK(IntParam, a, 1);
+ a.Fork(d);
+ LWTRACK(IntParam, a, 2);
+
+ LWTRACK(IntParam, b, 3);
+ b.Fork(c);
+ LWTRACK(IntParam, b, 4);
+
+ LWTRACK(IntParam, c, 5);
+ b.Join(c);
+ LWTRACK(IntParam, b, 6);
+
+ LWTRACK(IntParam, d, 7);
+ a.Join(d);
+ LWTRACK(IntParam, a, 8);
+
+ a.Join(b);
+ LWTRACK(IntParam, a, 9);
+ }
+
+ struct {
+ void Push(TThread::TId, const TTrackLog& tl) {
+ UNIT_ASSERT(tl.Items.size() == 16);
+ UNIT_ASSERT(TString(tl.Items[0].Probe->Event.Name) == "NoParam");
+ UNIT_ASSERT(TString(tl.Items[1].Probe->Event.Name) == "Fork");
+ UNIT_ASSERT(tl.Items[2].Params.Param[0].Get<ui64>() == 1);
+ UNIT_ASSERT(TString(tl.Items[3].Probe->Event.Name) == "Fork");
+ UNIT_ASSERT(tl.Items[4].Params.Param[0].Get<ui64>() == 2);
+ UNIT_ASSERT(TString(tl.Items[5].Probe->Event.Name) == "Join");
+ UNIT_ASSERT(tl.Items[6].Params.Param[0].Get<ui64>() == 7);
+ UNIT_ASSERT(tl.Items[7].Params.Param[0].Get<ui64>() == 8);
+ UNIT_ASSERT(TString(tl.Items[8].Probe->Event.Name) == "Join");
+ UNIT_ASSERT(tl.Items[9].Params.Param[0].Get<ui64>() == 3);
+ UNIT_ASSERT(TString(tl.Items[10].Probe->Event.Name) == "Fork");
+ UNIT_ASSERT(tl.Items[11].Params.Param[0].Get<ui64>() == 4);
+ UNIT_ASSERT(TString(tl.Items[12].Probe->Event.Name) == "Join");
+ UNIT_ASSERT(tl.Items[13].Params.Param[0].Get<ui64>() == 5);
+ UNIT_ASSERT(tl.Items[14].Params.Param[0].Get<ui64>() == 6);
+ UNIT_ASSERT(tl.Items[15].Params.Param[0].Get<ui64>() == 9);
+ }
+ } reader;
+ mngr.ReadDepot("Query1", reader);
+ }
+
+ Y_UNIT_TEST(TrackForkError) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ RunLogShuttleAction {
+ MaxTrackLength: 100
+ }
+ }
+ }
+ )END", &q);
+
+ UNIT_ASSERT(parsed);
+ mngr.New("Query1", q);
+
+ constexpr size_t n = (100 + 2) / 3 + 1;
+
+ {
+ TVector<TVector<TOrbit>> span;
+
+ while (1) {
+ TVector<TOrbit> orbit(n);
+
+ LWTRACK(NoParam, orbit[0]);
+ if (!orbit[0].HasShuttles()) {
+ break;
+ }
+ for (size_t i = 1; i < n; i++) {
+ if (!orbit[i - 1].Fork(orbit[i])) {
+ break;
+ }
+ LWTRACK(IntParam, orbit[i], i);
+ }
+
+ span.emplace_back(std::move(orbit));
+ }
+
+ for (auto& orbit: span) {
+ for (auto it = orbit.rbegin(); it + 1 != orbit.rend(); it++) {
+ (it + 1)->Join(*it);
+ }
+ }
+ }
+
+ struct {
+ void Push(TThread::TId, const TTrackLog& tl) {
+ UNIT_ASSERT(tl.Items.size() == 100);
+ UNIT_ASSERT(tl.Truncated);
+ }
+ } reader;
+ mngr.ReadDepot("Query1", reader);
+ }
+#endif // LWTRACE_DISABLE
+}
diff --git a/library/cpp/lwtrace/ut/ya.make b/library/cpp/lwtrace/ut/ya.make
new file mode 100644
index 0000000000..f43118bab7
--- /dev/null
+++ b/library/cpp/lwtrace/ut/ya.make
@@ -0,0 +1,11 @@
+UNITTEST_FOR(library/cpp/lwtrace)
+
+OWNER(serxa)
+
+FORK_SUBTESTS()
+
+SRCS(
+ trace_ut.cpp
+)
+
+END()
diff --git a/library/cpp/lwtrace/ya.make b/library/cpp/lwtrace/ya.make
new file mode 100644
index 0000000000..d9accb3006
--- /dev/null
+++ b/library/cpp/lwtrace/ya.make
@@ -0,0 +1,29 @@
+LIBRARY()
+
+OWNER(serxa)
+
+PEERDIR(
+ library/cpp/lwtrace/protos
+)
+
+SRCS(
+ check.cpp
+ control.cpp
+ custom_action.cpp
+ kill_action.cpp
+ log_shuttle.cpp
+ perf.cpp
+ probes.cpp
+ shuttle.cpp
+ sleep_action.cpp
+ start.cpp
+ stderr_writer.cpp
+ symbol.cpp
+ trace.cpp
+)
+
+END()
+
+RECURSE(mon)
+
+RECURSE_FOR_TESTS(ut)