Repository: google/cadvisor Branch: master Commit: 711f2becad6c Files: 2683 Total size: 3.0 MB Directory structure: gitextract_t01xuxby/ ├── .github/ │ └── workflows/ │ ├── publish-container.yml │ ├── release-binaries.yml │ ├── stale.yaml │ └── test.yml ├── .gitignore ├── .golangci.yml ├── AUTHORS ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── build/ │ ├── assets.sh │ ├── boilerplate/ │ │ ├── boilerplate.go.txt │ │ ├── boilerplate.py │ │ ├── boilerplate.py.txt │ │ └── boilerplate.sh.txt │ ├── build.sh │ ├── check_boilerplate.sh │ ├── check_container.sh │ ├── check_gotidy.sh │ ├── config/ │ │ ├── crio.sh │ │ ├── libipmctl.sh │ │ ├── libpfm4.sh │ │ └── plain.sh │ ├── integration-crio.sh │ ├── integration-in-docker-crio.sh │ ├── integration-in-docker.sh │ ├── integration.sh │ ├── prow_e2e.sh │ ├── release.sh │ └── unit-in-container.sh ├── cache/ │ ├── cache.go │ └── memory/ │ ├── memory.go │ └── memory_test.go ├── client/ │ ├── README.md │ ├── client.go │ ├── client_test.go │ ├── clientexample/ │ │ └── main.go │ └── v2/ │ ├── README.md │ ├── client.go │ └── client_test.go ├── cmd/ │ ├── cadvisor.go │ ├── cadvisor_test.go │ ├── go.mod │ ├── go.sum │ ├── internal/ │ │ ├── api/ │ │ │ ├── handler.go │ │ │ ├── versions.go │ │ │ └── versions_test.go │ │ ├── container/ │ │ │ └── install/ │ │ │ └── install.go │ │ ├── healthz/ │ │ │ └── healthz.go │ │ ├── http/ │ │ │ ├── handlers.go │ │ │ └── mux/ │ │ │ └── mux.go │ │ ├── pages/ │ │ │ ├── assets/ │ │ │ │ ├── html/ │ │ │ │ │ └── containers.html │ │ │ │ ├── js/ │ │ │ │ │ ├── containers.js │ │ │ │ │ └── loader.js │ │ │ │ └── styles/ │ │ │ │ └── containers.css │ │ │ ├── containers.go │ │ │ ├── docker.go │ │ │ ├── pages.go │ │ │ ├── podman.go │ │ │ ├── static/ │ │ │ │ ├── assets.go │ │ │ │ └── static.go │ │ │ └── templates.go │ │ └── storage/ │ │ ├── bigquery/ │ │ │ ├── README.md │ │ │ ├── bigquery.go │ │ │ └── client/ │ │ │ ├── client.go │ │ │ └── example/ │ │ │ └── example.go │ │ ├── elasticsearch/ │ │ │ └── elasticsearch.go │ │ ├── influxdb/ │ │ │ ├── influxdb.go │ │ │ └── influxdb_test.go │ │ ├── kafka/ │ │ │ └── kafka.go │ │ ├── redis/ │ │ │ └── redis.go │ │ ├── statsd/ │ │ │ ├── client/ │ │ │ │ └── client.go │ │ │ └── statsd.go │ │ ├── stdout/ │ │ │ └── stdout.go │ │ └── test/ │ │ ├── mock.go │ │ └── storagetests.go │ └── storagedriver.go ├── collector/ │ ├── collector_manager.go │ ├── collector_manager_test.go │ ├── config/ │ │ ├── sample_config.json │ │ ├── sample_config_endpoint_config.json │ │ ├── sample_config_prometheus.json │ │ ├── sample_config_prometheus_endpoint_config.json │ │ └── sample_config_prometheus_filtered.json │ ├── config.go │ ├── fakes.go │ ├── generic_collector.go │ ├── generic_collector_test.go │ ├── prometheus_collector.go │ ├── prometheus_collector_test.go │ ├── types.go │ └── util.go ├── container/ │ ├── common/ │ │ ├── container_hints.go │ │ ├── container_hints_test.go │ │ ├── fsHandler.go │ │ ├── helpers.go │ │ ├── helpers_test.go │ │ ├── inotify_watcher.go │ │ └── test_resources/ │ │ ├── cgroup_v1/ │ │ │ └── test1/ │ │ │ ├── cpu/ │ │ │ │ ├── cpu.cfs_period_us │ │ │ │ ├── cpu.cfs_quota_us │ │ │ │ └── cpu.shares │ │ │ ├── cpuset/ │ │ │ │ └── cpuset.cpus │ │ │ ├── memory/ │ │ │ │ ├── memory.limit_in_bytes │ │ │ │ ├── memory.memsw.limit_in_bytes │ │ │ │ └── memory.soft_limit_in_bytes │ │ │ └── pids/ │ │ │ └── pids.max │ │ ├── cgroup_v2/ │ │ │ ├── test1/ │ │ │ │ ├── cpu.max │ │ │ │ ├── cpu.weight │ │ │ │ ├── cpuset.cpus.effective │ │ │ │ ├── memory.max │ │ │ │ ├── memory.min │ │ │ │ ├── memory.swap.max │ │ │ │ └── pids.max │ │ │ └── test2/ │ │ │ ├── cpu.max │ │ │ ├── cpu.weight │ │ │ ├── memory.max │ │ │ ├── memory.min │ │ │ ├── memory.swap.max │ │ │ └── pids.max │ │ └── container_hints.json │ ├── container.go │ ├── containerd/ │ │ ├── client.go │ │ ├── client_test.go │ │ ├── containers/ │ │ │ └── containers.go │ │ ├── factory.go │ │ ├── factory_test.go │ │ ├── grpc.go │ │ ├── handler.go │ │ ├── handler_test.go │ │ ├── identifiers/ │ │ │ ├── validate.go │ │ │ └── validate_test.go │ │ ├── install/ │ │ │ └── install.go │ │ ├── namespaces/ │ │ │ ├── context.go │ │ │ ├── context_test.go │ │ │ ├── grpc.go │ │ │ ├── store.go │ │ │ ├── ttrpc.go │ │ │ └── ttrpc_test.go │ │ ├── pkg/ │ │ │ └── dialer/ │ │ │ ├── dialer.go │ │ │ ├── dialer_unix.go │ │ │ └── dialer_windows.go │ │ └── plugin.go │ ├── crio/ │ │ ├── client.go │ │ ├── client_test.go │ │ ├── factory.go │ │ ├── factory_test.go │ │ ├── handler.go │ │ ├── handler_test.go │ │ ├── install/ │ │ │ └── install.go │ │ └── plugin.go │ ├── docker/ │ │ ├── client.go │ │ ├── docker.go │ │ ├── docker_test.go │ │ ├── factory.go │ │ ├── factory_test.go │ │ ├── fs.go │ │ ├── handler.go │ │ ├── handler_test.go │ │ ├── install/ │ │ │ └── install.go │ │ ├── plugin.go │ │ └── utils/ │ │ ├── docker.go │ │ └── docker_test.go │ ├── factory.go │ ├── factory_test.go │ ├── libcontainer/ │ │ ├── handler.go │ │ ├── handler_test.go │ │ ├── helpers.go │ │ ├── helpers_test.go │ │ └── testdata/ │ │ ├── clear_refs4 │ │ ├── clear_refs6 │ │ ├── clear_refs8 │ │ ├── docker-v1.8.3/ │ │ │ └── execdriver/ │ │ │ └── native/ │ │ │ └── 1/ │ │ │ └── state.json │ │ ├── docker-v1.9.1/ │ │ │ └── execdriver/ │ │ │ └── native/ │ │ │ └── 1/ │ │ │ └── state.json │ │ ├── limits │ │ ├── procnetdev │ │ ├── procnetudp │ │ ├── smaps4 │ │ ├── smaps6 │ │ └── smaps8 │ ├── podman/ │ │ ├── client.go │ │ ├── factory.go │ │ ├── fs.go │ │ ├── handler.go │ │ ├── install/ │ │ │ └── install.go │ │ ├── plugin.go │ │ ├── podman.go │ │ └── podman_test.go │ ├── raw/ │ │ ├── factory.go │ │ ├── handler.go │ │ ├── handler_test.go │ │ └── watcher.go │ ├── systemd/ │ │ ├── factory.go │ │ ├── install/ │ │ │ └── install.go │ │ └── plugin.go │ └── testing/ │ └── mock_handler.go ├── deploy/ │ ├── Dockerfile │ ├── Dockerfile.ppc64le │ ├── build.sh │ ├── canary/ │ │ └── Dockerfile │ ├── entrypoint.sh │ ├── healthcheck.sh │ ├── kubernetes/ │ │ ├── README.md │ │ ├── base/ │ │ │ ├── daemonset.yaml │ │ │ ├── kustomization.yaml │ │ │ ├── namespace.yaml │ │ │ └── serviceaccount.yaml │ │ └── overlays/ │ │ ├── examples/ │ │ │ ├── cadvisor-args.yaml │ │ │ ├── critical-priority.yaml │ │ │ ├── kustomization.yaml │ │ │ └── stackdriver-sidecar.yaml │ │ └── examples_perf/ │ │ ├── cadvisor-perf.yaml │ │ ├── configmap.yaml │ │ └── kustomization.yaml │ └── snap/ │ └── snapcraft.yaml ├── devicemapper/ │ ├── dmsetup_client.go │ ├── doc.go │ ├── fake/ │ │ ├── dmsetup_client_fake.go │ │ └── thin_ls_client_fake.go │ ├── thin_ls_client.go │ ├── thin_ls_client_test.go │ ├── thin_pool_watcher.go │ ├── thin_pool_watcher_test.go │ └── util.go ├── doc.go ├── docs/ │ ├── api.md │ ├── api_v2.md │ ├── application_metrics.md │ ├── clients.md │ ├── deploy.md │ ├── development/ │ │ ├── README.md │ │ ├── build.md │ │ ├── integration_testing.md │ │ ├── issues.md │ │ └── releasing.md │ ├── roadmap.md │ ├── running.md │ ├── runtime_options.md │ ├── storage/ │ │ ├── README.md │ │ ├── elasticsearch.md │ │ ├── influxdb.md │ │ ├── kafka.md │ │ ├── prometheus.md │ │ └── statsd.md │ └── web.md ├── events/ │ ├── handler.go │ └── handler_test.go ├── fs/ │ ├── btrfs/ │ │ ├── install/ │ │ │ └── install.go │ │ ├── mount.go │ │ └── plugin.go │ ├── devicemapper/ │ │ ├── install/ │ │ │ └── install.go │ │ ├── plugin.go │ │ ├── stats.go │ │ └── stats_test.go │ ├── fs.go │ ├── fs_test.go │ ├── nfs/ │ │ ├── install/ │ │ │ └── install.go │ │ └── plugin.go │ ├── overlay/ │ │ ├── install/ │ │ │ └── install.go │ │ └── plugin.go │ ├── plugin.go │ ├── test_resources/ │ │ └── diskstats │ ├── tmpfs/ │ │ ├── install/ │ │ │ └── install.go │ │ └── plugin.go │ ├── types.go │ ├── vfs/ │ │ ├── install/ │ │ │ └── install.go │ │ ├── plugin.go │ │ └── stats.go │ └── zfs/ │ ├── install/ │ │ └── install.go │ ├── plugin.go │ ├── stats.go │ └── watcher.go ├── go.mod ├── go.sum ├── info/ │ ├── v1/ │ │ ├── container.go │ │ ├── container_test.go │ │ ├── docker.go │ │ ├── machine.go │ │ ├── machine_test.go │ │ ├── metric.go │ │ └── test/ │ │ └── datagen.go │ └── v2/ │ ├── container.go │ ├── conversion.go │ ├── conversion_test.go │ └── machine.go ├── integration/ │ ├── framework/ │ │ ├── framework.go │ │ └── metrics.go │ ├── runner/ │ │ ├── retrywhitelist.txt │ │ ├── run.sh │ │ └── runner.go │ └── tests/ │ ├── TODO.md │ ├── api/ │ │ ├── containerd_test.go │ │ ├── docker_test.go │ │ ├── event_test.go │ │ ├── perf_test.go │ │ └── test_utils.go │ ├── common/ │ │ ├── attributes_test.go │ │ ├── healthz_test.go │ │ ├── machine_test.go │ │ └── machinestats_test.go │ ├── crio/ │ │ ├── crio_test.go │ │ └── test_utils.go │ ├── healthz/ │ │ ├── doc.go │ │ ├── healthz_test.go │ │ └── test_utils.go │ └── metrics/ │ ├── containerd_metrics_test.go │ ├── docker_metrics_test.go │ └── prometheus_test.go ├── machine/ │ ├── info.go │ ├── machine.go │ ├── operatingsystem_unix.go │ ├── operatingsystem_windows.go │ ├── testdata/ │ │ ├── cpu9999/ │ │ │ ├── online │ │ │ └── topology/ │ │ │ ├── core_id │ │ │ └── physical_package_id │ │ ├── cpuinfo │ │ ├── cpuinfo_arm │ │ ├── cpuinfo_lower_case │ │ ├── cpuinfo_onesocket_many_NUMAs │ │ ├── cpuinfo_rpi4 │ │ ├── cpuinfo_upper_case │ │ ├── edac/ │ │ │ └── mc/ │ │ │ ├── mc0/ │ │ │ │ ├── dimm0/ │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ └── size │ │ │ │ ├── dimm1/ │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ └── size │ │ │ │ └── dimm_is_fake/ │ │ │ │ ├── dimm_mem_type │ │ │ │ └── size │ │ │ ├── mc1/ │ │ │ │ └── dimm0/ │ │ │ │ ├── dimm_mem_type │ │ │ │ └── size │ │ │ └── mc_fake/ │ │ │ ├── dimm0/ │ │ │ │ ├── dimm0/ │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ └── size │ │ │ │ ├── dimm1/ │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ └── size │ │ │ │ ├── dimm_mem_type │ │ │ │ └── size │ │ │ └── dimm1/ │ │ │ ├── dimm_mem_type │ │ │ └── size │ │ ├── sysfs_cpus/ │ │ │ ├── cpu0/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ └── physical_package_id │ │ │ └── cpu1/ │ │ │ └── .gitkeep │ │ └── wrong_sysfs/ │ │ └── cpu0/ │ │ └── .gitkeep │ ├── testdata_rpi4/ │ │ ├── cpu0/ │ │ │ ├── hotplug/ │ │ │ │ ├── fail │ │ │ │ ├── state │ │ │ │ └── target │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu1/ │ │ │ ├── cpu_capacity │ │ │ ├── hotplug/ │ │ │ │ ├── fail │ │ │ │ ├── state │ │ │ │ └── target │ │ │ ├── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ └── uevent │ │ ├── cpu2/ │ │ │ ├── hotplug/ │ │ │ │ ├── fail │ │ │ │ ├── state │ │ │ │ └── target │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu3/ │ │ │ ├── hotplug/ │ │ │ │ ├── fail │ │ │ │ ├── state │ │ │ │ └── target │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ └── hotplug/ │ │ └── states │ └── topology_test.go ├── manager/ │ ├── container.go │ ├── container_test.go │ ├── manager.go │ ├── manager_bench_test.go │ └── manager_test.go ├── metrics/ │ ├── metrics.go │ ├── prometheus.go │ ├── prometheus_fake.go │ ├── prometheus_machine.go │ ├── prometheus_machine_test.go │ ├── prometheus_test.go │ └── testdata/ │ ├── prometheus_machine_metrics │ ├── prometheus_machine_metrics_failure │ ├── prometheus_metrics │ ├── prometheus_metrics_failure │ ├── prometheus_metrics_perf_aggregated │ └── prometheus_metrics_whitelist_filtered ├── nvm/ │ ├── machine_libipmctl.go │ └── machine_no_libipmctl.go ├── perf/ │ ├── collector_libpfm.go │ ├── collector_libpfm_test.go │ ├── collector_no_libpfm.go │ ├── config.go │ ├── config_test.go │ ├── manager_libpfm.go │ ├── manager_libpfm_test.go │ ├── manager_no_libpfm.go │ ├── testing/ │ │ ├── perf-no-events.json │ │ ├── perf-non-hardware.json │ │ ├── perf.json │ │ └── this-is-some-random.json │ ├── types_libpfm.go │ ├── uncore_libpfm.go │ └── uncore_libpfm_test.go ├── resctrl/ │ ├── factory.go │ └── intel/ │ ├── collector.go │ ├── collector_test.go │ ├── install/ │ │ └── install.go │ ├── manager.go │ ├── manager_test.go │ ├── testing/ │ │ ├── tasks_empty │ │ ├── tasks_invalid │ │ ├── tasks_one │ │ └── tasks_two │ ├── utils.go │ └── utils_test.go ├── stats/ │ ├── noop.go │ └── types.go ├── storage/ │ ├── common_flags.go │ └── storage.go ├── summary/ │ ├── buffer.go │ ├── buffer_test.go │ ├── percentiles.go │ ├── percentiles_test.go │ └── summary.go ├── test.htdigest ├── test.htpasswd ├── utils/ │ ├── cloudinfo/ │ │ ├── aws/ │ │ │ └── aws.go │ │ ├── azure/ │ │ │ └── azure.go │ │ ├── cloudinfo.go │ │ └── gce/ │ │ └── gce.go │ ├── container/ │ │ └── container.go │ ├── cpuload/ │ │ ├── cpuload.go │ │ ├── cpuload_unsupported.go │ │ └── netlink/ │ │ ├── conn.go │ │ ├── example/ │ │ │ └── example.go │ │ ├── netlink.go │ │ └── reader.go │ ├── oomparser/ │ │ ├── oomexample/ │ │ │ └── main.go │ │ ├── oomparser.go │ │ └── oomparser_test.go │ ├── path.go │ ├── sysfs/ │ │ ├── fakesysfs/ │ │ │ └── fake.go │ │ ├── sysfs.go │ │ ├── sysfs_notx86.go │ │ ├── sysfs_test.go │ │ ├── sysfs_x86.go │ │ ├── testdata/ │ │ │ ├── edac/ │ │ │ │ └── mc/ │ │ │ │ ├── mc0/ │ │ │ │ │ ├── dimm0/ │ │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ │ └── size │ │ │ │ │ ├── dimm1/ │ │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ │ └── size │ │ │ │ │ └── dimm_is_fake/ │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ └── size │ │ │ │ ├── mc1/ │ │ │ │ │ └── dimm0/ │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ └── size │ │ │ │ └── mc_fake/ │ │ │ │ ├── dimm0/ │ │ │ │ │ ├── dimm0/ │ │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ │ └── size │ │ │ │ │ ├── dimm1/ │ │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ │ └── size │ │ │ │ │ ├── dimm_mem_type │ │ │ │ │ └── size │ │ │ │ └── dimm1/ │ │ │ │ ├── dimm_mem_type │ │ │ │ └── size │ │ │ ├── missing_online/ │ │ │ │ └── node0/ │ │ │ │ ├── cpu0/ │ │ │ │ │ └── .gitkeep │ │ │ │ └── cpu33/ │ │ │ │ └── .gitkeep │ │ │ ├── node0/ │ │ │ │ ├── cpu0/ │ │ │ │ │ └── topology/ │ │ │ │ │ └── core_id │ │ │ │ ├── cpu1/ │ │ │ │ │ └── topology/ │ │ │ │ │ └── .gitkeep │ │ │ │ ├── distance │ │ │ │ ├── hugepages/ │ │ │ │ │ ├── hugepages-1048576kB/ │ │ │ │ │ │ └── nr_hugepages │ │ │ │ │ └── hugepages-2048kB/ │ │ │ │ │ └── nr_hugepages │ │ │ │ └── meminfo │ │ │ └── node1/ │ │ │ └── .gitkeep │ │ ├── testdata_epyc7402/ │ │ │ ├── cpu0/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu1/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu10/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu11/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu12/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu13/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu14/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu15/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu16/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu17/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu18/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu19/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu2/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu20/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu21/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu22/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu23/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu24/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu25/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu26/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu27/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu28/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu29/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu3/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu30/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu31/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu32/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu33/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu34/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu35/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu36/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu37/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu38/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu39/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu4/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu40/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu41/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu42/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu43/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu44/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu45/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu46/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu47/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu5/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu6/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu7/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu8/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu9/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ └── online │ │ ├── testdata_epyc7402_nohyperthreading/ │ │ │ ├── cpu0/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu1/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu10/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu11/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu12/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu13/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu14/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu15/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu16/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu17/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu18/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu19/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu2/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu20/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu21/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu22/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu23/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu3/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu4/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu5/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu6/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu7/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu8/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu9/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ └── online │ │ ├── testdata_graviton2/ │ │ │ ├── cpu0/ │ │ │ │ ├── online │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu1/ │ │ │ │ ├── online │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu2/ │ │ │ │ └── online │ │ │ ├── cpu3/ │ │ │ │ ├── online │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ └── online │ │ ├── testdata_rpi4/ │ │ │ ├── cpu0/ │ │ │ │ ├── hotplug/ │ │ │ │ │ └── state │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu1/ │ │ │ │ ├── hotplug/ │ │ │ │ │ └── state │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu2/ │ │ │ │ ├── hotplug/ │ │ │ │ │ └── state │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu3/ │ │ │ │ ├── hotplug/ │ │ │ │ │ └── state │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ └── hotplug/ │ │ │ └── states │ │ ├── testdata_single_socket_many_NUMAs/ │ │ │ ├── cpu0/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu1/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu10/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu11/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu12/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu13/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu14/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu15/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu16/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu17/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu18/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu19/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu2/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu20/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu21/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu22/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu23/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu24/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu25/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu26/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu27/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu28/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu29/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu3/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu30/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu31/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu4/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu5/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu6/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu7/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu8/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu9/ │ │ │ │ └── topology/ │ │ │ │ ├── core_cpus │ │ │ │ ├── core_cpus_list │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── die_cpus │ │ │ │ ├── die_cpus_list │ │ │ │ ├── die_id │ │ │ │ ├── package_cpus │ │ │ │ ├── package_cpus_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ └── online │ │ ├── testdata_xeon4214_2socket/ │ │ │ ├── cpu0/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu1/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu10/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu11/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu12/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu13/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu14/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu15/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu16/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu17/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu18/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu19/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu2/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu20/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu21/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu22/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu23/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu24/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu25/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu26/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu27/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu28/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu29/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu3/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu30/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu31/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu32/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu33/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu34/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu35/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu36/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu37/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu38/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu39/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu4/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu40/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu41/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu42/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu43/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu44/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu45/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu46/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu47/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu5/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu6/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu7/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu8/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ ├── cpu9/ │ │ │ │ └── topology/ │ │ │ │ ├── core_id │ │ │ │ ├── core_siblings │ │ │ │ ├── core_siblings_list │ │ │ │ ├── physical_package_id │ │ │ │ ├── thread_siblings │ │ │ │ └── thread_siblings_list │ │ │ └── online │ │ └── testdata_xeon5218_nohyperthread_2socket_nohotplug/ │ │ ├── cpu0/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu1/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu10/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu11/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu12/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu13/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu14/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu15/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu16/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu17/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu18/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu19/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu2/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu20/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu21/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu22/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu23/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu24/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu25/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu26/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu27/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu28/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu29/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu3/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu30/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu31/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu4/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu5/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu6/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu7/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ ├── cpu8/ │ │ │ └── topology/ │ │ │ ├── core_cpus │ │ │ ├── core_cpus_list │ │ │ ├── core_id │ │ │ ├── core_siblings │ │ │ ├── core_siblings_list │ │ │ ├── die_cpus │ │ │ ├── die_cpus_list │ │ │ ├── die_id │ │ │ ├── package_cpus │ │ │ ├── package_cpus_list │ │ │ ├── physical_package_id │ │ │ ├── thread_siblings │ │ │ └── thread_siblings_list │ │ └── cpu9/ │ │ └── topology/ │ │ ├── core_cpus │ │ ├── core_cpus_list │ │ ├── core_id │ │ ├── core_siblings │ │ ├── core_siblings_list │ │ ├── die_cpus │ │ ├── die_cpus_list │ │ ├── die_id │ │ ├── package_cpus │ │ ├── package_cpus_list │ │ ├── physical_package_id │ │ ├── thread_siblings │ │ └── thread_siblings_list │ ├── sysinfo/ │ │ ├── sysinfo.go │ │ └── sysinfo_test.go │ ├── timed_store.go │ ├── timed_store_test.go │ └── utils.go ├── validate/ │ ├── validate.go │ └── validate_test.go ├── version/ │ └── version.go ├── watcher/ │ └── watcher.go └── zfs/ └── watcher.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/publish-container.yml ================================================ name: Publish Container Image on: push: tags: - 'v*' workflow_dispatch: inputs: tag: description: 'Tag to build and publish' required: true type: string jobs: build-and-push: runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout repository uses: actions/checkout@v6 with: ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }} - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Free disk space run: | echo "Disk space before cleanup:" df -h sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL sudo docker image prune --all --force sudo docker builder prune -a -f echo "Disk space after cleanup:" df -h - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata for Docker id: meta uses: docker/metadata-action@v5 with: images: ghcr.io/${{ github.repository }} tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=raw,value=latest,enable=${{ github.event_name != 'workflow_dispatch' && github.ref == format('refs/tags/{0}', github.ref_name) }} type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' }} type=sha,prefix=,suffix=-${{ github.sha }} - name: Build and push Docker image uses: docker/build-push-action@v6 with: context: . file: ./deploy/Dockerfile platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | VERSION=${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} ================================================ FILE: .github/workflows/release-binaries.yml ================================================ name: Release Binaries on: push: tags: - 'v*' workflow_dispatch: inputs: tag: description: 'Tag to build and publish' required: true type: string jobs: build-linux-binaries: runs-on: ubuntu-latest strategy: matrix: arch: [amd64, arm64] steps: - name: Checkout repository uses: actions/checkout@v6 with: ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }} fetch-depth: 0 # Fetch all history for proper versioning - name: Set up Docker uses: docker/setup-buildx-action@v3 - name: Set up QEMU uses: docker/setup-qemu-action@v3 with: platforms: linux/amd64,linux/arm64 - name: Set VERSION environment variable run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "VERSION=${INPUTS_TAG}" >> $GITHUB_ENV else echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV fi env: INPUTS_TAG: ${{ inputs.tag }} - name: Build Linux ${{ matrix.arch }} binary env: GOARCH: ${{ matrix.arch }} OUTPUT_NAME_WITH_ARCH: "true" VERSION: ${{ env.VERSION }} run: | # Create a Docker container with the appropriate architecture docker run --rm -v ${PWD}:/go/src/github.com/google/cadvisor \ --platform linux/${{ matrix.arch }} \ golang:1.25 \ /bin/bash -c "cd /go/src/github.com/google/cadvisor && GOARCH=${{ matrix.arch }} OUTPUT_NAME_WITH_ARCH=true VERSION=${VERSION} GO_FLAGS='-buildvcs=false -tags=netgo' GO_CGO_ENABLED=0 ./build/build.sh" - name: Generate SHA256 checksums run: | cd _output # List all files in the output directory ls -la # Generate SHA256 checksums for all binaries find . -name "cadvisor*" -type f -not -name "*.sha256" -exec sh -c 'sha256sum "$1" > "$1.sha256"' _ {} \; - name: Upload artifacts uses: actions/upload-artifact@v6 with: name: cadvisor-linux-${{ matrix.arch }} path: | _output/cadvisor* retention-days: 1 create-release: needs: build-linux-binaries runs-on: ubuntu-latest permissions: contents: write # Needed for creating GitHub releases steps: - name: Checkout repository uses: actions/checkout@v6 with: ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }} - name: Set VERSION environment variable run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "VERSION=${INPUTS_TAG}" >> $GITHUB_ENV else echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV fi env: INPUTS_TAG: ${{ inputs.tag }} - name: Download all artifacts uses: actions/download-artifact@v7 with: path: artifacts - name: Display structure of downloaded files run: ls -R artifacts - name: Create Release id: create_release uses: softprops/action-gh-release@v2 with: tag_name: ${{ env.VERSION }} name: cAdvisor ${{ env.VERSION }} draft: false prerelease: ${{ contains(env.VERSION, 'alpha') || contains(env.VERSION, 'beta') || contains(env.VERSION, 'rc') }} generate_release_notes: true files: | artifacts/**/* ================================================ FILE: .github/workflows/stale.yaml ================================================ name: Stale issues and pull requests on: schedule: - cron: "21 4 * * *" workflow_dispatch: jobs: stale: permissions: issues: write pull-requests: write runs-on: ubuntu-latest steps: - uses: actions/stale@v10 with: stale-issue-message: 'This issue is stale because it has been open 90 days with no activity. This issue will be closed in 30 days unless new comments are made or the stale label is removed. To skip these checks, apply the "lifecycle/frozen" label.' stale-pr-message: 'This PR is stale because it has been open 90 days with no activity. This PR will be closed in 30 days unless new comments are made or the stale label is removed. To skip these checks, apply the "lifecycle/frozen" label.' stale-issue-label: 'lifecycle/stale' stale-pr-label: 'lifecycle/stale' exempt-issue-labels: 'lifecycle/frozen' exempt-pr-labels: 'lifecycle/frozen' days-before-stale: 90 close-issue-message: 'This issue was automatically closed due to inactivity.' close-pr-message: 'This pull request was automatically closed due to inactivity.' days-before-issue-close: 30 days-before-pr-close: 30 remove-stale-when-updated: true operations-per-run: 300 ================================================ FILE: .github/workflows/test.yml ================================================ name: Test on: [push, pull_request] jobs: test: strategy: matrix: go-versions: ['1.25'] platform: [ubuntu-24.04] environment-variables: [build/config/plain.sh, build/config/libpfm4.sh, build/config/libipmctl.sh] runs-on: ${{ matrix.platform }} timeout-minutes: 30 steps: - name: Install Go uses: actions/setup-go@v6 with: go-version: ${{ matrix.go-versions }} check-latest: true - name: Checkout code uses: actions/checkout@v6 - name: Run presubmit checks run: | source ${{ matrix.environment-variables }} if [[ "${BUILD_PACKAGES}" != "" ]]; then sudo apt-get update; sudo apt-get install ${BUILD_PACKAGES}; fi make -e presubmit - name: Run tests env: GOLANG_VERSION: ${{ matrix.go-versions }} run: | source ${{ matrix.environment-variables }} make test test-integration: strategy: matrix: include: # bookworm: all environment configs - go-versions: '1.25' platform: ubuntu-24.04 environment-variables: build/config/plain.sh debian-version: bookworm - go-versions: '1.25' platform: ubuntu-24.04 environment-variables: build/config/libpfm4.sh debian-version: bookworm - go-versions: '1.25' platform: ubuntu-24.04 environment-variables: build/config/libipmctl.sh debian-version: bookworm # trixie: only plain config - go-versions: '1.25' platform: ubuntu-24.04 environment-variables: build/config/plain.sh debian-version: trixie runs-on: ${{ matrix.platform }} timeout-minutes: 30 steps: - name: Checkout code uses: actions/checkout@v6 - name: Run integration tests env: GOLANG_VERSION: ${{ matrix.go-versions }} DEBIAN_VERSION: ${{ matrix.debian-version }} run: | set -ex source ${{ matrix.environment-variables }} make docker-test-integration - name: Upload cAdvisor log file uses: actions/upload-artifact@v6 if: failure() with: name: cadvisor-${{ matrix.debian-version }}.log path: ${{ github.workspace }}/go/src/github.com/google/cadvisor/cadvisor.log test-integration-crio: strategy: matrix: go-versions: ['1.25'] platform: [ubuntu-24.04] runs-on: ${{ matrix.platform }} timeout-minutes: 30 steps: - name: Checkout code uses: actions/checkout@v6 - name: Run CRI-O integration tests env: GOLANG_VERSION: ${{ matrix.go-versions }} run: | set -ex source build/config/crio.sh make docker-test-integration-crio - name: Upload cAdvisor log file uses: actions/upload-artifact@v6 if: failure() with: name: cadvisor-crio.log path: ${{ github.workspace }}/go/src/github.com/google/cadvisor/cadvisor.log ================================================ FILE: .gitignore ================================================ cadvisor /release .vscode _output/ # Log files *.log # Go test binaries *.test # Files generated by JetBrains IDEs, e.g. IntelliJ IDEA .idea/ *.iml *.swp ================================================ FILE: .golangci.yml ================================================ version: "2" run: timeout: 5m linters: default: none enable: - govet - errcheck - staticcheck - unused - ineffassign settings: govet: disable: - fieldalignment # too noisy, requires significant refactoring errcheck: exclude-functions: - (io.Closer).Close - (net.Conn).Close - (*os.File).Close - (net/http.ResponseWriter).Write - os.Remove - os.RemoveAll - os.Setenv - fmt.Fprint - fmt.Fprintf - fmt.Fprintln - syscall.Close staticcheck: checks: - "all" - "-ST1000" # package comments - too noisy for existing codebase - "-ST1003" # naming conventions (e.g., CrioId vs CrioID) - would break public API - "-ST1020" # comment format on exported methods - too many to fix - "-ST1021" # comment format on exported types - too many to fix - "-ST1022" # comment format on exported consts - too many to fix - "-QF*" # disable quickfix suggestions exclusions: rules: # Exclude errcheck in test files for cleaner test code - linters: - errcheck path: "_test\\.go$" # Exclude errcheck for Close() calls on any type - linters: - errcheck text: "Error return value of .*.Close.* is not checked" # Exclude govet printf check false positives - linters: - govet text: "printf: non-constant format string" formatters: enable: - gofmt - goimports issues: max-issues-per-linter: 0 max-same-issues: 0 ================================================ FILE: AUTHORS ================================================ # This is the official list of cAdvisor authors for copyright purposes. # Names should be added to this file as # Name or Organization # The email address is not required for organizations. # Please keep the list sorted. Google Inc. ================================================ FILE: CHANGELOG.md ================================================ # Changelog ### 0.39.0 (2021-03-08) - [do not initialize libipmctl package when getting an error from nvm_init()](https://github.com/google/cadvisor/pull/2723) - [Don't fail permenantly when nvml isn't installed](https://github.com/google/cadvisor/pull/2732) - [Update libpfm to 4.11.0](https://github.com/google/cadvisor/pull/2746) - [Fix race between `OnDemandHousekeeping` and `housekeepingTick`](https://github.com/google/cadvisor/pull/2755) - [Fix timeout flooding issue after containerd restart](https://github.com/google/cadvisor/pull/2749) - [Refactor process parsing to accommodate commands with spaces + Memory cgroup is not available on some systems](https://github.com/google/cadvisor/pull/2751) - [Switch from k8s utils/mount to moby/sys mount](https://github.com/google/cadvisor/pull/2782) - [Support nfs in processMounts](https://github.com/google/cadvisor/pull/2787) - [Update docker/runc and a few other dependencies](https://github.com/google/cadvisor/pull/2790) - [Add container_blkio_device_usage metric](https://github.com/google/cadvisor/pull/2795) - [Update heuristic for container creation time](https://github.com/google/cadvisor/pull/2800) - [Fix incorrect CPU topology on single NUMA and multi socket platform.](https://github.com/google/cadvisor/pull/2799) - [Added support for filesystem metrics on Docker](https://github.com/google/cadvisor/pull/2768) - [sched_getaffinity does not return number of online CPUs](https://github.com/google/cadvisor/pull/2805) - [Add libipmctl to the docker image.](https://github.com/google/cadvisor/pull/2674) - [Add cgroup_memory_migrate metric](https://github.com/google/cadvisor/pull/2796) - [bump runc to v1.0.0-rc93](https://github.com/google/cadvisor/pull/2809) - [Fix memory stats for cgroup v2](https://github.com/google/cadvisor/pull/2810) - [Allow gathering of stats for root cgroup on v2](https://github.com/google/cadvisor/pull/2801) - [Remove trailing \0 from values read from ppc64le device-tree](https://github.com/google/cadvisor/pull/2811) - [Fix oomparser regex for kernels 5.0 and higher](https://github.com/google/cadvisor/pull/2817) - [Handling arm64: topology and online information](https://github.com/google/cadvisor/pull/2744) - [Bump golang to 1.16](https://github.com/google/cadvisor/pull/2818) - [Bump containerd to 1.4.4](https://github.com/google/cadvisor/pull/2826) - [Conditionally gathering FS usage metrics](https://github.com/google/cadvisor/pull/2828) ### 0.38.8 (2021-02-18) - [Cherrypick to v0.38 - Fix incorrect CPU topology on single NUMA and multi socket platform](https://github.com/google/cadvisor/pulls/2799) - [Cherrypick to v0.38 - sched_getaffinity does not return number of online CPUs](https://github.com/google/cadvisor/pulls/2805) ### 0.37.5 (2021-02-18) - [Cherrypick to v0.37 - Fix incorrect CPU topology on single NUMA and multi socket platform](https://github.com/google/cadvisor/pulls/2799) - [Cherrypick to v0.37 - sched_getaffinity does not return number of online CPUs](https://github.com/google/cadvisor/pulls/2805) ### 0.38.7 (2021-01-13) - [Cherrypick to v0.37: Return correct DeviceInfo from GetDirFsDevice on / path for Btrfs - Fix kubernetes issue #94335](https://github.com/google/cadvisor/pulls/2775) ### 0.37.4 (2021-01-13) - [Cherrypick to v0.37: Return correct DeviceInfo from GetDirFsDevice on / path for Btrfs - Fix kubernetes issue #94335](https://github.com/google/cadvisor/pulls/2776) ### 0.38.6 (2020-12-9) - [Cherrypick to v0.37: Fix timeout flooding issue after containerd restart](https://github.com/google/cadvisor/pulls/2759) ### 0.37.3 (2020-12-9) - [Cherrypick to v0.37: Fix timeout flooding issue after containerd restart](https://github.com/google/cadvisor/pulls/2758) ### 0.38.5 (2020-11-23) - [Cherrypick to v0.37: don't fail permenantly when nvml isn't installed](https://github.com/google/cadvisor/pulls/2735) ### 0.37.2 (2020-11-23) - [Cherrypick to v0.37 - update docker client method](https://github.com/google/cadvisor/pulls/2734) ### 0.37.1 (2020-11-18) - [Cherrypick to v0.37: don't fail permenantly when nvml isn't installed](https://github.com/google/cadvisor/pulls/2737) ### 0.38.4 (2020-11-12) - [vendor: run go mod tidy](https://github.com/google/cadvisor/pulls/2731) ### 0.38.3 (2020-11-12) - [vendor: Rollback gopkg.in/yaml.v2 to v2.2.8](https://github.com/google/cadvisor/pulls/2728) ### 0.38.2 (2020-11-10) - [Revert mount-utils back to utils/mount](https://github.com/google/cadvisor/pulls/2726) ### 0.38.1 (2020-11-10) - [deps: Rollback grpc from v1.33.2 to v1.27.1](https://github.com/google/cadvisor/pull/2724) - [do not initialize libipmctl package when getting an error from nvm_init()](https://github.com/google/cadvisor/pull/2723) ### 0.38.0 (2020-11-09) - [#1594 - chore: add storage_driver_buffer_duration in Influxdb storage docs](https://github.com/google/cadvisor/pull/1594) - [#1924 - add hugepages info to attributes](https://github.com/google/cadvisor/pull/1924) - [#2578 - Add perf event grouping.](https://github.com/google/cadvisor/pull/2578) - [#2590 - Use current Docker registry](https://github.com/google/cadvisor/pull/2590) - [#2611 - Aggregate perf metrics](https://github.com/google/cadvisor/pull/2611) - [#2612 - Add stats to stdout storage](https://github.com/google/cadvisor/pull/2612) - [#2618 - Update to containerd v1.4.0-beta.2 and runc v1.0.0-rc91](https://github.com/google/cadvisor/pull/2618) - [#2621 - Memory numa stats](https://github.com/google/cadvisor/pull/2621) - [#2627 - use Google Charts loader and not jsapi](https://github.com/google/cadvisor/pull/2627) - [#2631 - Add entry for libpfm related tests to Makefile](https://github.com/google/cadvisor/pull/2631) - [#2632 - Handling zeros in readPerfStat](https://github.com/google/cadvisor/pull/2632) - [#2638 - Add stats to statsd storage](https://github.com/google/cadvisor/pull/2638) - [#2639 - Add logs and simplify setup of raw perf events](https://github.com/google/cadvisor/pull/2639) - [#2640 - Remove exclude guest flag from perf event attrs. ](https://github.com/google/cadvisor/pull/2640) - [#2644 - Use perf attributes from unix lib.](https://github.com/google/cadvisor/pull/2644) - [#2646 - Fixed https proxy issue by installing 'full' wget in Docker alpine-based build stage](https://github.com/google/cadvisor/pull/2646) - [#2655 - Update readme to point to discuss.kubernetes.io](https://github.com/google/cadvisor/pull/2655) - [#2659 - Fix ordering of processes table](https://github.com/google/cadvisor/pull/2659) - [#2665 - add clean operation when watchForNewContainers/Start failed](https://github.com/google/cadvisor/pull/2665) - [#2669 - Update release documentation and process](https://github.com/google/cadvisor/pull/2669) - [#2676 - Fix runtime error when there are no NVM devices.](https://github.com/google/cadvisor/pull/2676) - [#2678 - Add checking checksum of libpfm4](https://github.com/google/cadvisor/pull/2678) - [#2679 - Fix typo in libipmctl](https://github.com/google/cadvisor/pull/2679) - [#2682 - Add missing flag to runtime_options.md](https://github.com/google/cadvisor/pull/2682) - [#2683 - Add flags that were not previously published](https://github.com/google/cadvisor/pull/2683) - [#2687 - Move mount library dependency from utils/mount to mount-utils](https://github.com/google/cadvisor/pull/2687) - [#2689 - Increase the readability of perf event logs.](https://github.com/google/cadvisor/pull/2689) - [#2690 - Try to read from sysfs before giving up on non-x86_64](https://github.com/google/cadvisor/pull/2690) - [#2691 - Broken build configuration when custom build tags are used](https://github.com/google/cadvisor/pull/2691) - [#2695 - Add information about limits of opened perf event files.](https://github.com/google/cadvisor/pull/2695) - [#2697 - Update to new docker(v19.03.13) and containerd(1.4.1)](https://github.com/google/cadvisor/pull/2697) - [#2702 - Increase golang ci lint timeout to 5 minutes](https://github.com/google/cadvisor/pull/2702) - [#2706 - Add a badge for the current e2e test result](https://github.com/google/cadvisor/pull/2706) - [#2707 - Fix Avoid random values in unix.PerfEventAttr{}](https://github.com/google/cadvisor/pull/2707) - [#2711 - validateMemoryAccounting: fix for cgroup v2](https://github.com/google/cadvisor/pull/2711) - [#2713 - Bump golang to 1.15](https://github.com/google/cadvisor/pull/2713) - [#2714 - update docker client method](https://github.com/google/cadvisor/pull/2714) - [#2716 - Update dependencies](https://github.com/google/cadvisor/pull/2716) ### 0.35.1 (2020-11-05) - [Make a copy of MachineInfo in GetMachineInfo()](https://github.com/google/cadvisor/pull/2490) ### 0.37.0 (2020-07-07) - Add on-demand collection for prometheus metrics - Fix detection of image filesystem - Fix disk metrics for devicemapper devices - Add NVM Power and NVM, Dimm, memory information to machine info - Fix detection of OOM Kills on 5.0 linux kernels - Add support for perf core and uncore event monitoring - Add hugetlb container metrics - Split into multiple go modules - Add referenced memory metrics - Publish images to gcr.io/cadvisor instead of gcr.io/google_containers - Add socket id to numa topology in machine info - Add resource control (Resctlr) metrics ### 0.36.0 (2020-02-28) - Add support for risc and mips CPUs - Add advanced TCP stats - Fix bug in which cAdvisor could fail to discover docker's root directory - The stdout storage driver now supports metric timestamps - Add ulimit metrics - Support multi-arch container builds - Switch to go modules ### 0.35.0 (2019-11-27) - Add hugepage info per-numa-node - Add support for cgoups v2 unified higherarchy - Drop support for rkt - Fix a bug that prevented running with multiple tmpfs mounts ### 0.34.0 (2019-08-26) - Fix disk stats in LXD using ZFS storage pool - Support monitoring non-k8s containerd namespaces - The `storage_driver` flag now supports comma-separated inputs - Add `container_sockets`, `container_threads`, and `container_threads_max` metrics - Fix CRI-O missing network metris bug - Add `disable_root_cgroup_stats` flag to allow not collecting stats from the root cgroup. ### 0.33.0 (2019-02-26) - Add --raw_cgroup_prefix_whitelist flag to allow configuring which raw cgroup trees cAdvisor monitors - Replace `du` and `find` with a golang implementation - Periodically update MachineInfo to support hot-add/remove - Add explicit timestamps to prometheus metrics to fix rate calculations - Add --url_base_prefix flag to provide better support for reverse proxies - Add --white_listed_container_labels flag to allow specifying the container labels added as prometheus labels ### 0.32.0 (2018-11-12) - Add container process and file descriptor metrics (disabled by default) - Rename `type` label to `failure_type` for prometheus `memory_failures_total` metric - Reduce mesos error logging when mesos not present ### 0.31.0 (2018-09-07) - Fix NVML initialization race condition - Fix brtfs filesystem discovery - Fix race condition with AllDockerContainers - Don't watch .mount cgroups - Reduce lock contention during list containers - Don't produce prometheus metrics for ignored metrics - Add option to not export container labels as prometheus labels - Docs: Publish cAdvisor daemonset - Docs: Add documentation for exported prometheus metrics ### 0.30.1 (2018-06-11) - Revert switch from inotify to fsnotify ### 0.30.0 (2018-06-05) - Use IONice to reduce IO priority of `du` and `find` - BREAKING API CHANGE: ContainerReference no longer contains Labels. Use ContainerSpec instead. - Add schedstat metrics, disabled by default. - Fix a bug where cadvisor failed to discover a sub-cgroup that was created soon after the parent cgroup. ### 0.29.0 (2018-02-20) - Disable per-cpu metrics by default for scalability - Fix disk usage monitoring of overlayFs - Retry docker connection on startup timeout ### 0.28.3 (2017-12-7) - Add timeout for docker calls - Fix prometheus label consistency ### 0.28.2 (2017-11-21) - Fix GPU init race condition ### 0.28.1 (2017-11-20) - Add containerd support - Fix fsnotify regression from 0.28.0 - Add on demand metrics ### 0.28.0 (2017-11-06) - Add container nvidia GPU metrics - Expose container memory max_usage_in_bytes - Add container memory reservation to prometheus ### 0.27.1 (2017-09-06) - Add CRI-O support ### 0.27.0 (2017-09-01) - Fix journalctl leak - Fix container memory rss - Add hugepages support - Fix incorrect CPU usage with 4.7 kernel - OOM parser uses kmsg - Add tmpfs support ### 0.26.1 (2017-06-21) - Fix prometheus metrics. ### 0.26.0 (2017-05-31) - Fix disk partition discovery for brtfs - Add ZFS support - Add UDP metrics (collection disabled by default) - Improve diskio prometheus metrics - Update Prometheus godeps to v0.8 - Add overlay2 storage driver support ### 0.25.0 (2017-03-09) - Disable thin_ls due to excessive iops - Ignore .mount cgroups, fixing dissappearing stats - Fix wc goroutine leak - Update aws-sdk-go dependency to 1.6.10 - Update to go 1.7 for releases ### 0.24.1 (2016-10-10) - Fix issue with running cAdvisor in a container on some distributions. ### 0.24.0 (2016-09-19) - Added host-level inode stats (total & available) - Improved robustness to partial failures - Metrics collector improvements - Added ability to directly use endpoints from the container itself - Allow SSL endpoint access - Ability to provide a certificate which is exposed to custom endpoints - Lots of bug fixes, including: - Devicemapper thin_ls fixes - Prometheus metrics fixes - Fixes for missing stats (memory reservation, FS usage, etc.) ### 0.23.9 (2016-08-09) - Cherry-pick release: - Ensure minimum kernel version for thin_ls ### 0.23.8 (2016-08-02) - Cherry-pick release: - Prefix Docker labels & env vars in Prometheus metrics to prevent conflicts ### 0.23.7 (2016-07-18) - Cherry-pick release: - Modify working set memory stats calculation ### 0.23.6 (2016-06-23) - Cherry-pick release: - Updating inotify to fix memory leak v0.23 cherrypick ### 0.23.5 (2016-06-22) - Cherry-pick release: - support LVM based device mapper storage drivers ### 0.23.4 (2016-06-16) - Cherry-pick release: - Check for thin_is binary in path for devicemapper when using ThinPoolWatcher - Fix uint64 overflow issue for CPU stats ### 0.23.3 (2016-06-08) - Cherry-pick release: - Cap the maximum consecutive du commands - Fix a panic when a prometheus endpoint ends with a newline ### 0.23.2 (2016-05-18) - Handle kernel log rotation - More rkt support: poll rkt service for new containers - Better handling of partial failures when fetching subcontainers - Devicemapper thin_ls support (requires Device Mapper kernel module and supporting utilities) ### 0.23.1 (2016-05-11) - Add multi-container charts to the UI - Add TLS options for Kafka storage driver - Switch to official Docker client - Systemd: - Ignore .mount cgroups on systemd - Better OOM monitoring - Bug: Fix broken -disable_metrics flag - Bug: Fix openstack identified as AWS - Bug: Fix EventStore when limit is 0 ### 0.23.0 (2016-04-21) - Docker v1.11 support - Preliminary rkt support - Bug: Fix file descriptor leak ### 0.22.0 (2016-02-25) - Disk usage calculation bug fixes - Systemd integration bug fixes - Instance ID support for Azure and AWS - Limit number of custom metrics - Support opt out for disk and network metrics ### 0.21.0 (2016-02-03) - Support for filesystem stats with docker v1.10 - Bug fixes. ### 0.20.5 (2016-01-27) - Breaking: Use uint64 for memory stats - Bug: Fix devicemapper partition labelling - Bug: Fix network stats when using new Docker network functionality - Bug: Fix env var label mapping initialization - Dependencies: libcontainer update ### 0.20.4 (2016-01-20) - Godep updates ### 0.20.3 (2016-01-19) - Bug fixes - Jitter added to housekeeping to smooth CPU usage. ### 0.20.2 (2016-01-15) - New v2.1 API with better filesystem stats - Internal refactoring - Bug fixes. ### 0.18.0 (2015-09-23) - Large bunch of bug-fixes - Fixed networking stats for newer docker versions using libnetwork. - Added application-specific metrics ## 0.16.0 (2015-06-26) - Misc fixes. ## 0.15.1 (2015-06-10) - Fix longstanding memory leak. - Fix UI on newest Chrome. ## 0.15.0 (2015-06-08) - Expose multiple network intefaces in UI and API. - Add support for XFS. - Fixes in inotify watches. - Fixes on PowerPC machines. - Fixes for newer systems with systemd. - Extra debuging informaiton in /validate. ## 0.14.0 (2015-05-21) - Add process stats to container pages in the UI. - Serve UI from relative paths (allows reverse proxying). - Minor fixes to events API. - Add bytes available to FS info. - Adding Docker status and image information to UI. - Basic Redis storage backend. - Misc reliability improvements. ## 0.13.0 (2015-05-01) - Added `--docker_only` to limit monitoring to only Docker containers. - Added support for Docker labels. - Added limit for events storage. - Fixes for OOM event monitoring. - Changed event type to a string in the API. - Misc fixes. ## 0.12.0 (2015-04-15) - Added support for Docker 1.6. - Split OOM event into OOM kill and OOM. - Made EventData a concrete type in returned events. - Enabled CPU load tracking (experimental). ## 0.11.0 (2015-03-27) - Export all stats as [Prometheus](https://prometheus.io/) metrics. - Initial support for [events](docs/api.md): creation, deletion, and OOM. - Adding machine UUID information. - Beta release of the cAdvisor [2.0 API](docs/api_v2.md). - Improve handling of error conditions. - Misc fixes and improvements. ## 0.10.1 (2015-02-27) - Disable OOM monitoring which is using too much CPU. - Fix break in summary stats. ## 0.10.0 (2015-02-24) - Adding Start and End time for ContainerInfoRequest. - Various misc fixes. ## 0.9.0 (2015-02-06) - Support for more network devices (all non-eth). - Support for more partition types (btrfs, device-mapper, whole-disk). - Added reporting of DiskIO stats. - Adding container creation time to ContainerSpec. - More robust handling of stats failures. - Various misc fixes. ## 0.8.0 (2015-01-09) - Added ethernet device information. - Added machine-wide networking statistics. - Misc UI fixes. - Fixes for partially-isolated containers. ## 0.7.1 (2014-12-23) - Avoid repeated logging of container errors. - Handle non identify mounts for cgroups. ## 0.7.0 (2014-12-18) - Support for HTTP basic auth. - Added /validate to perform basic checks and determine support for cAdvisor. - All stats in the UI are now updated. - Added gauges for filesystem usage. - Added device information to machine info. - Fixes to container detection. - Fixes for systemd detection. - ContainerSpecs are now cached. - Performance improvements. ## 0.6.2 (2014-11-20) - Fixes for Docker API and UI endpoints. - Misc UI bugfixes. ## 0.6.1 (2014-11-18) - Bug fix in InfluxDB storage driver. Container name and hostname will be exported. ## 0.6.0 (2014-11-17) - Adding /docker UI endpoint for Docker containers. - Fixes around handling Docker containers. - Performance enhancements. - Embed all external dependencies. - ContainerStats Go struct has been flattened. The wire format remains unchanged. - Misc bugfixes and cleanups. ## 0.5.0 (2014-10-28) - Added disk space stats. On by default for root, available on AUFS Docker containers. - Introduced v1.2 remote API with new "docker" resource for Docker containers. - Added "ContainerHints" file based interface to inject extra information about containers. ## 0.4.1 (2014-09-29) - Support for Docker containers in systemd systems. - Adding DiskIO stats - Misc bugfixes and cleanups ## 0.4.0 (2014-09-19) - Various performance enhancements: brings CPU usage down 85%+ - Implemented dynamic sampling through dynamic housekeeping. - Memory storage driver is always on, BigQuery and InfluxDB are now optional storage backends. - Fix for DNS resolution crashes when contacting InfluxDB. - New containers are now detected using inotify. - Added pprof HTTP endpoint. - UI bugfixes. ## 0.3.0 (2014-09-05) - Support for Docker with LXC backend. - Added BigQuery storage driver. - Performance and stability fixes for InfluxDB storage driver. - UI fixes and improvements. - Configurable stats gathering interval (default: 1s). - Improvements to startup and CPU utilization. - Added /healthz endpoint for determining whether cAdvisor is healthy. - Bugfixes and performance improvements. ## 0.2.2 (2014-08-13) - Improvements to influxDB plugin. Table name is now 'stats'. Network stats added. Detailed cpu and memory stats are no longer exported to reduce the load on the DB. Docker container alias now exported - It is now possible to aggregate stats across multiple nodes. - Make the UI independent of the storage backend by caching recent stats in memory. - Switched to glog. - Bugfixes and performance improvements. - Introduced v1.1 remote API with new "subcontainers" resource. ## 0.2.1 (2014-07-25) - Handle old Docker versions. - UI fixes and other bugfixes. ## 0.2.0 (2014-07-24) - Added network stats to the UI. - Added support for CoreOS and RHEL. - Bugfixes and reliability fixes. ## 0.1.4 (2014-07-22) - Add network statistics to REST API. - Add "raw" driver to handle non-Docker containers. - Remove lmctfy in favor of the raw driver. - Bugfixes for Docker containers and logging. ## 0.1.3 (2014-07-14) - Add support for systemd systems. - Fixes for UI with InfluxDB storage driver. ## 0.1.2 (2014-07-10) - Added Storage Driver concept (flag: storage_driver), default is the in-memory driver - Implemented InfluxDB storage driver - Support in REST API for specifying number of stats to return - Allow running without lmctfy (flag: allow_lmctfy) - Bugfixes ## 0.1.0 (2014-06-14) - Support for container aliases - Sampling historical usage and exporting that in the REST API - Bugfixes for UI ## 0.0.0 (2014-06-10) - Initial version of cAdvisor - Web UI with auto-updating stats - v1.0 REST API with container and machine information - Support for Docker containers - Support for lmctfy containers ================================================ FILE: CONTRIBUTING.md ================================================ ## How to contribute Open an issue or a pull request, its that easy! ## Contributor License Agreements We'd love to accept your pull requests! Before we can merge them, we have to jump a couple of legal hurdles. Please fill out either the individual or corporate Contributor License Agreement (CLA). * If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html). * If you work for a company that wants to allow you to contribute your work, then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html). Follow either of the two links above to access the appropriate CLA and instructions for how to sign and return it. Once we receive it, we'll be able to accept your pull requests. ================================================ FILE: LICENSE ================================================ Copyright 2014 The cAdvisor Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS ================================================ FILE: Makefile ================================================ # Copyright 2015 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. GO := go GOLANGCI_VER := 2.6.2 GO_TEST ?= $(GO) test $(or $(GO_FLAGS),-race) arch ?= $(shell go env GOARCH) all: presubmit build test test: @echo ">> running tests" @# Filter out integration. $(GO) list ./... | grep -vw integration | xargs $(GO_TEST) cd cmd && $(GO_TEST) ./... test-with-libpfm: GO_FLAGS=-race -tags libpfm test-with-libpfm: test container-test: @echo ">> runinng tests in a container" @./build/unit-in-container.sh docker-test: container-test @echo "docker-test target is deprecated, use container-test instead" test-integration: GO_FLAGS=$(or $(GO_FLAGS),-race) ./build/build.sh $(GO_TEST) -c github.com/google/cadvisor/integration/tests/api $(GO_TEST) -c github.com/google/cadvisor/integration/tests/common $(GO_TEST) -c github.com/google/cadvisor/integration/tests/metrics @./build/integration.sh docker-test-integration: @./build/integration-in-docker.sh docker-test-integration-crio: @./build/integration-in-docker-crio.sh test-integration-crio: GO_FLAGS=$(or $(GO_FLAGS),-race) ./build/build.sh $(GO_TEST) -c github.com/google/cadvisor/integration/tests/crio $(GO_TEST) -c github.com/google/cadvisor/integration/tests/common @./build/integration-crio.sh test-runner: @$(GO) build github.com/google/cadvisor/integration/runner tidy: @$(GO) mod tidy @cd cmd && $(GO) mod tidy format: @echo ">> formatting code" @# goimports is a superset of gofmt. @goimports -w -local github.com/google/cadvisor . build: assets @echo ">> building binaries" @./build/build.sh $(arch) assets: @echo ">> building assets" @./build/assets.sh release: @echo ">> building release binaries" @./build/release.sh docker-%: @docker build -t cadvisor:$(shell git rev-parse --short HEAD) -f deploy/Dockerfile . docker-build: @docker run --rm -w /go/src/github.com/google/cadvisor -v ${PWD}:/go/src/github.com/google/cadvisor golang:1.25 make build presubmit: lint @echo ">> checking go mod tidy" @./build/check_gotidy.sh @echo ">> checking file boilerplate" @./build/check_boilerplate.sh lint: @# This assumes GOPATH/bin is in $PATH -- if not, the target will fail. @# Extract the current golangci-lint version (empty if not installed), @# then use GNU sort to check if GOT >= GOLANGCI_VER. @GOT=$$(golangci-lint version 2>/dev/null | sed 's/^.* version \([^ ]*\) .*$$/\1/'); \ if ! printf $(GOLANGCI_VER)\\n$$GOT\\n | sort --version-sort --check=quiet; then \ echo ">> upgrading golangci-lint from $$GOT to $(GOLANGCI_VER)"; \ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $$(go env GOPATH)/bin v$(GOLANGCI_VER); \ GOT=$(GOLANGCI_VER); \ else \ echo ">> using installed golangci-lint $$GOT >= $(GOLANGCI_VER)"; \ fi @echo ">> running golangci-lint using configuration at .golangci.yml" @golangci-lint run @cd cmd && golangci-lint run clean: @rm -f *.test cadvisor @rm -rf _output/ .PHONY: all build docker format release test test-integration test-integration-crio lint presubmit tidy ================================================ FILE: README.md ================================================ ![cAdvisor](logo.png "cAdvisor") ![test status](https://github.com/google/cadvisor/workflows/Test/badge.svg) cAdvisor (Container Advisor) provides container users an understanding of the resource usage and performance characteristics of their running containers. It is a running daemon that collects, aggregates, processes, and exports information about running containers. Specifically, for each container it keeps resource isolation parameters, historical resource usage, histograms of complete historical resource usage and network statistics. This data is exported by container and machine-wide. cAdvisor has native support for [Docker](https://github.com/docker/docker) containers and should support just about any other container type out of the box. We strive for support across the board so feel free to open an issue if that is not the case. cAdvisor's container abstraction is based on [lmctfy](https://github.com/google/lmctfy)'s so containers are inherently nested hierarchically. #### Quick Start: Running cAdvisor in a Docker Container To quickly tryout cAdvisor on your machine with Docker, we have a Docker image that includes everything you need to get started. You can run a single cAdvisor to monitor the whole machine. Simply run: ``` VERSION=0.55.1 # use the latest release version from https://github.com/google/cadvisor/releases sudo docker run \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:ro \ --volume=/sys:/sys:ro \ --volume=/var/lib/docker/:/var/lib/docker:ro \ --volume=/dev/disk/:/dev/disk:ro \ --publish=8080:8080 \ --detach=true \ --name=cadvisor \ --privileged \ --device=/dev/kmsg \ ghcr.io/google/cadvisor:$VERSION # for versions prior to v0.53.0, use gcr.io/cadvisor/cadvisor instead ``` cAdvisor is now running (in the background) on `http://localhost:8080`. The setup includes directories with Docker state cAdvisor needs to observe. **Note**: If you're running on CentOS, Fedora, or RHEL (or are using LXC), take a look at our [running instructions](docs/running.md). We have detailed [instructions](docs/running.md#standalone) on running cAdvisor standalone outside of Docker. cAdvisor [running options](docs/runtime_options.md) may also be interesting for advanced usecases. If you want to build your own cAdvisor Docker image, see our [deployment](docs/deploy.md) page. For [Kubernetes](https://github.com/kubernetes/kubernetes) users, cAdvisor can be run as a daemonset. See the [instructions](deploy/kubernetes) for how to get started, and for how to [kustomize](https://github.com/kubernetes-sigs/kustomize#kustomize) it to fit your needs. ## Building and Testing See the more detailed instructions in the [build page](docs/development/build.md). This includes instructions for building and deploying the cAdvisor Docker image. ## Exporting stats cAdvisor supports exporting stats to various storage plugins. See the [documentation](docs/storage/README.md) for more details and examples. ## Web UI cAdvisor exposes a web UI at its port: `http://:/` See the [documentation](docs/web.md) for more details. ## Remote REST API & Clients cAdvisor exposes its raw and processed stats via a versioned remote REST API. See the API's [documentation](docs/api.md) for more information. There is also an official Go client implementation in the [client](client/) directory. See the [documentation](docs/clients.md) for more information. ## Roadmap cAdvisor aims to improve the resource usage and performance characteristics of running containers. Today, we gather and expose this information to users. In our roadmap: - Advise on the performance of a container (e.g.: when it is being negatively affected by another, when it is not receiving the resources it requires, etc). - Auto-tune the performance of the container based on previous advise. - Provide usage prediction to cluster schedulers and orchestration layers. ## Community Contributions, questions, and comments are all welcomed and encouraged! cAdvisor developers hang out on [Slack](https://kubernetes.slack.com) in the #sig-node channel (get an invitation [here](http://slack.kubernetes.io/)). We also have [discuss.kubernetes.io](https://discuss.kubernetes.io/). Please reach out and get involved in the project, we're actively looking for more contributors to bring on board! ### Core Team * [@bobbypage, Google](https://github.com/bobbypage) * [@iwankgb, Independent](https://github.com/iwankgb) * [@creatone, Independent](https://github.com/creatone) * [@dims, VMWare](https://github.com/dims) * [@mrunalp, RedHat](https://github.com/mrunalp) ### Frequent Collaborators * [@haircommander, RedHat](https://github.com/haircommander) ### Emeritus * [@dashpole, Google](https://github.com/dashpole) * [@dchen1107, Google](https://github.com/dchen1107) * [@derekwaynecarr, RedHat](https://github.com/derekwaynecarr) ================================================ FILE: build/assets.sh ================================================ #!/bin/bash # Copyright 2015 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -e GIT_ROOT=$(dirname "${BASH_SOURCE}")/.. ASSETS_INPUT_DIRS="$GIT_ROOT/cmd/internal/pages/assets/js/... $GIT_ROOT/cmd/internal/pages/assets/styles/..." ASSETS_OUTPUT_PATH="$GIT_ROOT/cmd/internal/pages/static/assets.go" ASSETS_PACKAGE="static" TEMPLATES_INPUT_DIRS="$GIT_ROOT/cmd/internal/pages/assets/html/..." TEMPLATES_OUTPUT_PATH="$GIT_ROOT/cmd/internal/pages/templates.go" TEMPLATES_PACKAGE="pages" FORCE="${FORCE:-}" # Force assets to be rebuilt if FORCE=true # Install while in a temp dir to avoid polluting go.mod/go.sum pushd "${TMPDIR:-/tmp}" > /dev/null go install github.com/kevinburke/go-bindata/go-bindata@v3.24.0 popd > /dev/null build_asset () { local package=$1 local output_path=$2 local input_dirs=${@:3} local tmp_output=$(mktemp) local year="$(git log -1 --date=format:'%Y' --format=%cd -- ${output_path})" go-bindata -nometadata -o $output_path -pkg $package $input_dirs cat build/boilerplate/boilerplate.go.txt | sed "s/YEAR/$year/" > "${tmp_output}" echo -e "// generated by build/assets.sh; DO NOT EDIT\n" >> "${tmp_output}" cat "${output_path}" >> "${tmp_output}" gofmt -w -s "${tmp_output}" mv "${tmp_output}" "${output_path}" } for f in $GIT_ROOT/cmd/internal/pages/assets/js/* $GIT_ROOT/cmd/internal/pages/assets/styles/*; do if [ "$FORCE" == "true" ] || [ "$f" -nt $ASSETS_OUTPUT_PATH -o ! -e $ASSETS_OUTPUT_PATH ]; then build_asset "$ASSETS_PACKAGE" "$ASSETS_OUTPUT_PATH" "$ASSETS_INPUT_DIRS" break; fi done for f in $GIT_ROOT/cmd/internal/pages/assets/html/*; do if [ "$FORCE" == "true" ] || [ "$f" -nt $TEMPLATES_OUTPUT_PATH -o ! -e $TEMPLATES_OUTPUT_PATH ]; then build_asset "$TEMPLATES_PACKAGE" "$TEMPLATES_OUTPUT_PATH" "$TEMPLATES_INPUT_DIRS" break; fi done exit 0 ================================================ FILE: build/boilerplate/boilerplate.go.txt ================================================ // Copyright YEAR Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. ================================================ FILE: build/boilerplate/boilerplate.py ================================================ #!/usr/bin/env python3 # Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import print_function import argparse import glob import json import mmap import os import re import sys parser = argparse.ArgumentParser() parser.add_argument("filenames", help="list of files to check, all files if unspecified", nargs='*') args = parser.parse_args() rootdir = os.path.dirname(__file__) + "/../../" rootdir = os.path.abspath(rootdir) def get_refs(): refs = {} for path in glob.glob(os.path.join(rootdir, "build/boilerplate/boilerplate.*.txt")): extension = os.path.basename(path).split(".")[1] ref_file = open(path, 'r') ref = ref_file.read().splitlines() ref_file.close() refs[extension] = ref return refs def file_passes(filename, refs, regexs): try: f = open(filename, 'r') except: return False data = f.read() f.close() extension = file_extension(filename) ref = refs[extension] # remove build tags from the top of Go files if extension == "go": p = regexs["go_build_constraints"] (data, found) = p.subn("", data, 1) # remove shebang from the top of shell files if extension == "sh": p = regexs["shebang"] (data, found) = p.subn("", data, 1) data = data.splitlines() # if our test file is smaller than the reference it surely fails! if len(ref) > len(data): return False # trim our file to the same number of lines as the reference file data = data[:len(ref)] p = regexs["year"] for d in data: if p.search(d): return False # Replace all occurrences of the regex "2016|2015|2014" with "YEAR" p = regexs["date"] for i, d in enumerate(data): (data[i], found) = p.subn('YEAR', d) if found != 0: break # if we don't match the reference at this point, fail if ref != data: return False return True def file_extension(filename): return os.path.splitext(filename)[1].split(".")[-1].lower() skipped_dirs = ['Godeps', 'vendor', 'third_party', '_gopath', '_output', '.git'] def normalize_files(files): newfiles = [] for pathname in files: if any(x in pathname for x in skipped_dirs): continue newfiles.append(pathname) for i, pathname in enumerate(newfiles): if not os.path.isabs(pathname): newfiles[i] = os.path.join(rootdir, pathname) return newfiles def get_files(extensions): files = [] if len(args.filenames) > 0: files = args.filenames else: for root, dirs, walkfiles in os.walk(rootdir): # don't visit certain dirs. This is just a performance improvement # as we would prune these later in normalize_files(). But doing it # cuts down the amount of filesystem walking we do and cuts down # the size of the file list for d in skipped_dirs: if d in dirs: dirs.remove(d) for name in walkfiles: pathname = os.path.join(root, name) files.append(pathname) files = normalize_files(files) outfiles = [] for pathname in files: extension = file_extension(pathname) if extension in extensions: outfiles.append(pathname) return outfiles def get_regexs(): regexs = {} # Search for "YEAR" which exists in the boilerplate, but shouldn't in the real thing regexs["year"] = re.compile( 'YEAR' ) # dates can be something in the 21st century regexs["date"] = re.compile( '20[0-9][0-9]' ) # strip // +build \n\n build and //go:build constraints regexs["go_build_constraints"] = re.compile(r"^(//\s*(\+build|go:build).*\n)+\n", re.MULTILINE) # strip #!.* from shell scripts regexs["shebang"] = re.compile(r"^(#!.*\n)\n*", re.MULTILINE) return regexs def main(): regexs = get_regexs() refs = get_refs() filenames = get_files(refs.keys()) for filename in filenames: if not file_passes(filename, refs, regexs): print(filename, file=sys.stdout) if __name__ == "__main__": sys.exit(main()) ================================================ FILE: build/boilerplate/boilerplate.py.txt ================================================ #!/usr/bin/env python3 # Copyright YEAR Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ================================================ FILE: build/boilerplate/boilerplate.sh.txt ================================================ # Copyright YEAR Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ================================================ FILE: build/build.sh ================================================ #!/usr/bin/env bash # Copyright 2015 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -e export GOOS=${GOOS:-$(go env GOOS)} export GOARCH=${GOARCH:-$(go env GOARCH)} export CGO_ENABLED=${GO_CGO_ENABLED:-"1"} GO_FLAGS=${GO_FLAGS:-"-tags=netgo"} # Extra go flags to use in the build. BUILD_USER=${BUILD_USER:-"${USER}@${HOSTNAME}"} BUILD_DATE=${BUILD_DATE:-$( date +%Y%m%d-%H:%M:%S )} VERBOSE=${VERBOSE:-} OUTPUT_NAME_WITH_ARCH=${OUTPUT_NAME_WITH_ARCH:-"false"} repo_path="github.com/google/cadvisor" version=${VERSION:-$( git describe --tags --dirty --abbrev=14 | sed -E 's/-([0-9]+)-g/.\1+/' )} revision=$( git rev-parse --short HEAD 2> /dev/null || echo 'unknown' ) branch=$( git rev-parse --abbrev-ref HEAD 2> /dev/null || echo 'unknown' ) go_version=$( go version | sed -e 's/^[^0-9.]*\([0-9.]*\).*/\1/' ) # go 1.4 requires ldflags format to be "-X key value", not "-X key=value" ldseparator="=" if [ "${go_version:0:3}" = "1.4" ]; then ldseparator=" " fi ldflags=" -X ${repo_path}/version.Version${ldseparator}${version} -X ${repo_path}/version.Revision${ldseparator}${revision} -X ${repo_path}/version.Branch${ldseparator}${branch} -X ${repo_path}/version.BuildUser${ldseparator}${BUILD_USER} -X ${repo_path}/version.BuildDate${ldseparator}${BUILD_DATE} -X ${repo_path}/version.GoVersion${ldseparator}${go_version}" echo ">> building cadvisor" if [ -n "$VERBOSE" ]; then echo "Building with -ldflags $ldflags" fi mkdir -p "$PWD/_output" output_file="$PWD/_output/cadvisor" if [ "${OUTPUT_NAME_WITH_ARCH}" = "true" ] ; then output_file="${output_file}-${version}-${GOOS}-${GOARCH}" fi # Since github.com/google/cadvisor/cmd is a submodule, we must build from inside that directory pushd cmd > /dev/null go build ${GO_FLAGS} -ldflags "${ldflags}" -o "${output_file}" "${repo_path}/cmd" popd > /dev/null exit 0 ================================================ FILE: build/check_boilerplate.sh ================================================ #!/bin/bash # Copyright 2015 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -o errexit set -o nounset set -o pipefail GIT_ROOT=$(dirname "${BASH_SOURCE}")/.. boiler="${GIT_ROOT}/build/boilerplate/boilerplate.py" files_need_boilerplate=($(${boiler} "$@")) if [[ ${#files_need_boilerplate[@]} -gt 0 ]]; then for file in "${files_need_boilerplate[@]}"; do echo "Boilerplate header is wrong for: ${file}" done exit 1 fi ================================================ FILE: build/check_container.sh ================================================ #!/usr/bin/env bash # Copyright 2015 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Description: # This script is meant to run a basic test against each of the CPU architectures # cadvisor should support. # # This script requires that you have run qemu-user-static so that your machine # can interpret ELF binaries for other architectures using QEMU: # https://github.com/multiarch/qemu-user-static#getting-started # # $ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes # # Usage: # ./check_container.sh gcr.io/tstapler-gke-dev/cadvisor:v0.44.1-test-4 target_image=$1 # Architectures officially supported by cadvisor arches=( "amd64" "arm" "arm64" "s390x" ) # Docker doesn't handle images with different architectures but the same tag. # Remove the container and the image use by it to avoid problems. cleanup() { echo Cleaning up the container $1 docker stop $1 docker rmi $target_image echo } for arch in "${arches[@]}"; do echo Testing that we can run $1 on $arch and curl the /healthz endpoint echo container_id=$(docker run --platform "linux/$arch" -p 8080:8080 --rm --detach "$target_image") docker_exit_code=$? if [ $docker_exit_code -ne 0 ]; then echo Failed to run container docker exited with $docker_exit_code cleanup $container_id exit $docker_exit_code fi sleep 10 echo echo Testing the container with curl: curl --show-error --retry 5 --fail -L 127.0.0.1:8080/healthz echo echo curl_exit=$? if [ $curl_exit -ne 0 ]; then echo Curling $target_image did not work cleanup $container_id exit $curl_exit fi echo Success! echo cleanup $container_id done ================================================ FILE: build/check_gotidy.sh ================================================ #!/bin/bash # Copyright 2020 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # TODO(bobbypage): Replace this with `go mod tidy --check` when it exists: # https://github.com/golang/go/issues/27005. # Checks if go mod tidy changes are needed for a given go module. # If changes are needed, prints the diff and exits 1 status code. # Arguments: # Directory of go module function lint_gotidy() { MODULE_DIRECTORY="$1" pushd "${MODULE_DIRECTORY}" > /dev/null TMP_GOMOD=$(mktemp) TMP_GOSUM=$(mktemp) # Make a copy of the current files cp go.mod "${TMP_GOMOD}" cp go.sum "${TMP_GOSUM}" go mod tidy DIFF_MOD=$(diff -u "${TMP_GOMOD}" go.mod) DIFF_SUM=$(diff -u "${TMP_GOSUM}" go.sum) # Copy the files back cp "${TMP_GOMOD}" go.mod cp "${TMP_GOSUM}" go.sum if [[ -n "${DIFF_MOD}" || -n "${DIFF_SUM}" ]]; then echo "go tidy changes are needed; please run make tidy" echo "go.mod diff:" echo "${DIFF_MOD}" echo "go.sum diff:" echo "${DIFF_SUM}" exit 1 fi popd > /dev/null } # Check if go mod tidy changes needed on main module lint_gotidy "." # Check if go mod tidy changes needed on cmd module lint_gotidy "cmd" ================================================ FILE: build/config/crio.sh ================================================ # Copyright 2024 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # CRI-O plain configuration - no special build flags unset GO_FLAGS unset PACKAGES unset BUILD_PACKAGES unset CADVISOR_ARGS ================================================ FILE: build/config/libipmctl.sh ================================================ # Copyright 2020 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. export GO_FLAGS="-tags=libipmctl,cgo -race" export PACKAGES="sudo libipmctl5" export BUILD_PACKAGES="libipmctl5 libipmctl-dev" export CADVISOR_ARGS="-perf_events_config=perf/testing/perf-non-hardware.json" ================================================ FILE: build/config/libpfm4.sh ================================================ # Copyright 2020 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. export GO_FLAGS="-tags=libpfm,netgo -race" export PACKAGES="sudo libpfm4" export BUILD_PACKAGES="libpfm4 libpfm4-dev" export CADVISOR_ARGS="-perf_events_config=perf/testing/perf-non-hardware.json" ================================================ FILE: build/config/plain.sh ================================================ # Copyright 2020 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Unsetting all the important variables. unset GO_FLAGS unset PACKAGES unset BUILD_PACKAGES unset CADVISOR_ARGS ================================================ FILE: build/integration-crio.sh ================================================ #!/usr/bin/env bash # Copyright 2024 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -e # When running this script locally, you may need to run cadvisor with sudo # permissions if cadvisor can't find containers. # USE_SUDO=true make test-integration-crio USE_SUDO=${USE_SUDO:-false} cadvisor_bin=${CADVISOR_BIN:-"./_output/cadvisor"} if ! [ -f "$cadvisor_bin" ]; then echo Failed to find cadvisor binary for integration test at path $cadvisor_bin exit 1 fi log_file="cadvisor.log" if [ "$#" -gt 0 ]; then log_file="$1" fi TEST_PID=$$ printf "" # Refresh sudo credentials if necessary. # Check if CRI-O is available and start it if not running CRIO_SOCK="/var/run/crio/crio.sock" # Function to start CRI-O if not running (for CI environments) start_crio_if_needed() { if [ -S "$CRIO_SOCK" ]; then echo ">> CRI-O already running" return 0 fi echo ">> CRI-O not running, attempting to start..." # Check if crio binary exists CRIO_BIN="" if command -v crio >/dev/null 2>&1; then CRIO_BIN="crio" elif [ -x /usr/local/bin/crio ]; then CRIO_BIN="/usr/local/bin/crio" fi if [ -z "$CRIO_BIN" ]; then echo "!! crio binary not found" return 1 fi # Create required directories mkdir -p /var/run/crio /var/lib/containers/storage /var/log/crio/pods /run/containers/storage /etc/crio # Install conmon if not available (CRI-O requires it) if ! command -v conmon >/dev/null 2>&1 && [ ! -x /usr/local/bin/conmon ]; then echo ">> Installing conmon..." CONMON_VERSION=v2.1.8 curl -L https://github.com/containers/conmon/releases/download/${CONMON_VERSION}/conmon.amd64 -o /usr/local/bin/conmon 2>/dev/null && \ chmod +x /usr/local/bin/conmon fi # Ensure conmon is in PATH if [ -x /usr/local/bin/conmon ]; then export PATH=/usr/local/bin:$PATH fi # Install CNI plugins if not available if [ ! -d /opt/cni/bin ] || [ -z "$(ls -A /opt/cni/bin 2>/dev/null)" ]; then echo ">> Installing CNI plugins..." CNI_VERSION=v1.3.0 mkdir -p /opt/cni/bin curl -L "https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-linux-amd64-${CNI_VERSION}.tgz" | tar -xz -C /opt/cni/bin fi # Create CNI config for bridge networking mkdir -p /etc/cni/net.d if [ ! -f /etc/cni/net.d/10-bridge.conf ]; then echo '{"cniVersion":"0.4.0","name":"bridge","type":"bridge","bridge":"cni0","isGateway":true,"ipMasq":true,"ipam":{"type":"host-local","subnet":"10.88.0.0/16","routes":[{"dst":"0.0.0.0/0"}]}}' > /etc/cni/net.d/10-bridge.conf echo '{"cniVersion":"0.4.0","name":"loopback","type":"loopback"}' > /etc/cni/net.d/99-loopback.conf fi # Create CRI-O config (always recreate to ensure correct settings) echo ">> Creating CRI-O config..." # Use vfs storage driver for Docker-in-Docker (overlay on overlay doesn't work) cat > /etc/crio/crio.conf << 'EOF' [crio] root = "/var/lib/containers/storage" runroot = "/var/run/containers/storage" log_dir = "/var/log/crio/pods" version_file = "/var/run/crio/version" storage_driver = "vfs" [crio.api] listen = "/var/run/crio/crio.sock" [crio.runtime] default_runtime = "crun" [crio.runtime.runtimes.crun] runtime_path = "/usr/bin/crun" runtime_type = "oci" runtime_root = "/run/crun" [crio.image] pause_image = "registry.k8s.io/pause:3.9" EOF # Also configure containers storage mkdir -p /etc/containers cat > /etc/containers/storage.conf << 'EOF' [storage] driver = "vfs" runroot = "/var/run/containers/storage" graphroot = "/var/lib/containers/storage" EOF # Create containers policy (allow all images) if it doesn't exist if [ ! -f /etc/containers/policy.json ]; then echo '{"default":[{"type":"insecureAcceptAnything"}]}' > /etc/containers/policy.json fi # Verify policy.json exists and is valid echo ">> Verifying /etc/containers/policy.json..." cat /etc/containers/policy.json # Start CRI-O echo ">> Starting CRI-O daemon..." $CRIO_BIN --log-level debug & CRIO_PID=$! sleep 2 # Wait for CRI-O to be ready echo ">> Waiting for CRI-O to start..." CRICTL_BIN="crictl" if [ -x /usr/local/bin/crictl ]; then CRICTL_BIN="/usr/local/bin/crictl" fi for i in $(seq 1 60); do if $CRICTL_BIN info >/dev/null 2>&1; then echo ">> CRI-O is ready" return 0 fi echo "Waiting for CRI-O... attempt $i" sleep 1 done echo "!! CRI-O failed to start" return 1 } # Try to start CRI-O if in Docker-in-Docker environment if [[ "${DOCKER_IN_DOCKER_ENABLED:-}" == "true" ]]; then start_crio_if_needed fi # Diagnostic logging for CRI-O debugging echo ">> Diagnostic information:" echo "=== CRI-O version ===" crio --version 2>/dev/null || /usr/local/bin/crio --version 2>/dev/null || echo "crio --version failed" echo "=== crictl version ===" crictl version 2>/dev/null || /usr/local/bin/crictl version 2>/dev/null || echo "crictl version failed" echo "=== CRI-O socket check ===" ls -la /var/run/crio/ 2>/dev/null || echo "/var/run/crio/ not found" ls -la /run/crio/ 2>/dev/null || echo "/run/crio/ not found" echo "=== CRI-O info ===" crictl info 2>/dev/null || /usr/local/bin/crictl info 2>/dev/null || echo "crictl info failed" echo "=== Running processes (crio) ===" ps aux | grep -E "crio" | grep -v grep || echo "No crio processes found" echo "=== Kernel version ===" uname -r echo "=== End diagnostic information ===" # CRI-O socket is hardcoded in cAdvisor to /var/run/crio/crio.sock if [ -S "$CRIO_SOCK" ]; then echo ">> CRI-O socket found at: $CRIO_SOCK" else echo "!! CRI-O socket not found at: $CRIO_SOCK" echo "!! CRI-O may not be running" fi function start { set +e # We want to handle errors if cAdvisor crashes. echo ">> starting cAdvisor locally" cadvisor_prereqs="" if [ $USE_SUDO = true ]; then cadvisor_prereqs=sudo fi # cpu, cpuset, percpu, memory, disk, diskIO, network metrics should be enabled. GORACE="halt_on_error=1" $cadvisor_prereqs $cadvisor_bin --enable_metrics="cpu,cpuset,percpu,memory,disk,diskIO,network" --env_metadata_whitelist=TEST_VAR --v=6 --logtostderr $CADVISOR_ARGS &> "$log_file" exit_code=$? if [ $exit_code != 0 ]; then echo "!! cAdvisor exited unexpectedly with Exit $exit_code" cat $log_file kill $TEST_PID # cAdvisor crashed: abort testing. fi } start & RUNNER_PID=$! function cleanup { if pgrep cadvisor > /dev/null; then echo ">> stopping cAdvisor" pkill -SIGINT cadvisor wait $RUNNER_PID fi } trap cleanup EXIT SIGINT TERM readonly TIMEOUT=30 # Timeout to wait for cAdvisor, in seconds. START=$(date +%s) while [ "$(curl -Gs http://localhost:8080/healthz)" != "ok" ]; do if (( $(date +%s) - $START > $TIMEOUT )); then echo "Timed out waiting for cAdvisor to start" exit 1 fi echo "Waiting for cAdvisor to start ..." sleep 1 done if [[ "${DOCKER_IN_DOCKER_ENABLED:-}" == "true" ]]; then # see https://github.com/moby/moby/blob/master/hack/dind # cgroup v2: enable nesting if [ -f /sys/fs/cgroup/cgroup.controllers ]; then echo ">> configuring cgroupsv2 for crio in container..." # move the processes from the root group to the /init group, # otherwise writing subtree_control fails with EBUSY. # An error during moving non-existent process (i.e., "cat") is ignored. mkdir -p /sys/fs/cgroup/init xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || : # enable controllers sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ > /sys/fs/cgroup/cgroup.subtree_control fi fi echo ">> running CRI-O integration tests against local cAdvisor" if ! [ -f ./crio.test ]; then echo You must compile the ./crio.test binary before echo running the integration tests. exit 1 fi ./crio.test --vmodule=*=2 -test.v echo ">> running common integration tests against local cAdvisor" if [ -f ./common.test ]; then ./common.test -test.v else echo "Skipping common tests (./common.test not found)" fi ================================================ FILE: build/integration-in-docker-crio.sh ================================================ #!/usr/bin/env bash # Copyright 2024 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -ex ROOT="$(cd "$(dirname "${BASH_SOURCE}")/.." && pwd -P)" TMPDIR=$(mktemp -d) function delete() { echo "Deleting ${TMPDIR}..." if [[ $EUID -ne 0 ]]; then sudo rm -rf "${TMPDIR}" else rm -rf "${TMPDIR}" fi } trap delete EXIT INT TERM function run_tests() { # Detect architecture - the bootstrap image is amd64-only DOCKER_PLATFORM="linux/amd64" # Add safe.directory as workaround for https://github.com/actions/runner/issues/2033 # Build for amd64 to match the test container BUILD_CMD="git config --global safe.directory /go/src/github.com/google/cadvisor && env GOOS=linux GOARCH=amd64 GO_FLAGS='$GO_FLAGS' CGO_ENABLED=0 ./build/build.sh && \ env GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go test -c github.com/google/cadvisor/integration/tests/crio && \ env GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go test -c github.com/google/cadvisor/integration/tests/common" if [ "$BUILD_PACKAGES" != "" ]; then BUILD_CMD="apt update && apt install -y $BUILD_PACKAGES && \ $BUILD_CMD" fi # Build in amd64 container to match test environment docker run --rm \ --platform ${DOCKER_PLATFORM} \ -w /go/src/github.com/google/cadvisor \ -v ${PWD}:/go/src/github.com/google/cadvisor \ golang:"$GOLANG_VERSION-bookworm" \ bash -c "$BUILD_CMD" EXTRA_DOCKER_OPTS="-e DOCKER_IN_DOCKER_ENABLED=true" if [[ "${OSTYPE}" == "linux"* ]]; then EXTRA_DOCKER_OPTS+=" -v ${TMPDIR}/crio-graph:/var/lib/containers" fi mkdir -p ${TMPDIR}/crio-graph # Run tests in a privileged container with CRI-O # Use --platform to ensure consistent architecture # Use --cgroupns=host and --pid=host to share host namespaces (required for systemd cgroup manager) # Mount host's systemd and dbus sockets so CRI-O can use systemd cgroup manager docker run --rm \ --platform ${DOCKER_PLATFORM} \ -w /go/src/github.com/google/cadvisor \ -v ${ROOT}:/go/src/github.com/google/cadvisor \ -v /sys/fs/cgroup:/sys/fs/cgroup:rw \ -v /run/systemd:/run/systemd:ro \ -v /run/dbus:/run/dbus:ro \ ${EXTRA_DOCKER_OPTS} \ --privileged \ --cap-add="sys_admin" \ --cgroupns=host \ --pid=host \ --entrypoint="" \ gcr.io/k8s-staging-test-infra/bootstrap:v20250702-52f5173c3a \ bash -c "export DEBIAN_FRONTEND=noninteractive && \ apt-get update && \ apt-get install -y $PACKAGES curl conntrack iptables dbus && \ # Check if host systemd and dbus are available echo 'Checking host systemd and dbus...' && \ ls -la /run/systemd/ || true && \ ls -la /run/dbus/ || true && \ systemctl --version || true && \ # Install CRI-O and crictl from static binaries (more reliable than apt) CRIO_VERSION=v1.28.0 && \ CRICTL_VERSION=v1.28.0 && \ # Download and install crictl echo 'Installing crictl...' && \ curl -L https://github.com/kubernetes-sigs/cri-tools/releases/download/\${CRICTL_VERSION}/crictl-\${CRICTL_VERSION}-linux-amd64.tar.gz | tar -C /usr/local/bin -xz && \ chmod +x /usr/local/bin/crictl && \ # Download and install CRI-O from Google Cloud Storage echo 'Installing CRI-O...' && \ mkdir -p /tmp/crio-install && \ curl -L https://storage.googleapis.com/cri-o/artifacts/cri-o.amd64.\${CRIO_VERSION}.tar.gz | tar -xz -C /tmp/crio-install && \ mkdir -p /usr/local/bin /etc/crio /etc/containers && \ ls -la /tmp/crio-install/cri-o/bin/ && \ cp /tmp/crio-install/cri-o/bin/crio /usr/local/bin/ && \ cp /tmp/crio-install/cri-o/bin/crio-status /usr/local/bin/ 2>/dev/null || true && \ cp /tmp/crio-install/cri-o/bin/pinns /usr/local/bin/ 2>/dev/null || true && \ cp /tmp/crio-install/cri-o/bin/conmon /usr/local/bin/ 2>/dev/null || true && \ cp /tmp/crio-install/cri-o/bin/conmonrs /usr/local/bin/ 2>/dev/null || true && \ chmod +x /usr/local/bin/crio* /usr/local/bin/pinns /usr/local/bin/conmon* 2>/dev/null || true && \ ls -la /usr/local/bin/crio* /usr/local/bin/conmon* /usr/local/bin/pinns 2>/dev/null && \ # Create CRI-O config with systemd cgroup manager (using host systemd via mounted socket) mkdir -p /etc/crio/crio.conf.d && \ cat > /etc/crio/crio.conf < /etc/containers/policy.json && \ echo 'Created /etc/containers/policy.json:' && \ cat /etc/containers/policy.json && \ # Install CNI plugins echo 'Installing CNI plugins...' && \ CNI_VERSION=v1.3.0 && \ mkdir -p /opt/cni/bin && \ curl -L \"https://github.com/containernetworking/plugins/releases/download/\${CNI_VERSION}/cni-plugins-linux-amd64-\${CNI_VERSION}.tgz\" | tar -xz -C /opt/cni/bin && \ ls -la /opt/cni/bin/ && \ # Create CNI config for bridge networking mkdir -p /etc/cni/net.d && \ echo '{\"cniVersion\":\"0.4.0\",\"name\":\"bridge\",\"type\":\"bridge\",\"bridge\":\"cni0\",\"isGateway\":true,\"ipMasq\":true,\"ipam\":{\"type\":\"host-local\",\"subnet\":\"10.88.0.0/16\",\"routes\":[{\"dst\":\"0.0.0.0/0\"}]}}' > /etc/cni/net.d/10-bridge.conf && \ echo '{\"cniVersion\":\"0.4.0\",\"name\":\"loopback\",\"type\":\"loopback\"}' > /etc/cni/net.d/99-loopback.conf && \ echo 'CNI config created:' && \ cat /etc/cni/net.d/10-bridge.conf && \ # Configure crictl to use CRI-O socket cat > /etc/crictl.yaml </dev/null 2>&1; then \ echo 'CRI-O is ready'; \ break; \ fi; \ echo \"Waiting for CRI-O... attempt \$i\"; \ sleep 1; \ done && \ # Verify CRI-O is running /usr/local/bin/crictl info && \ # Pull required images echo 'Pulling test images...' && \ /usr/local/bin/crictl pull registry.k8s.io/pause:3.9 || true && \ /usr/local/bin/crictl pull registry.k8s.io/busybox:1.27 || true && \ # Add /usr/local/bin to PATH for the test runner export PATH=/usr/local/bin:\$PATH && \ # Run the integration tests CADVISOR_ARGS='$CADVISOR_ARGS' /usr/local/bin/runner.sh build/integration-crio.sh" } # Note: -race requires CGO, but cross-compilation with CGO is problematic # So we use -tags=netgo without -race for cross-platform compatibility GO_FLAGS=${GO_FLAGS:-"-tags=netgo"} PACKAGES=${PACKAGES:-"sudo"} BUILD_PACKAGES=${BUILD_PACKAGES:-} CADVISOR_ARGS=${CADVISOR_ARGS:-} GOLANG_VERSION=${GOLANG_VERSION:-"1.25"} run_tests ================================================ FILE: build/integration-in-docker.sh ================================================ #!/usr/bin/env bash # Copyright 2020 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -ex ROOT="$(cd "$(dirname "${BASH_SOURCE}")/.." && pwd -P)" TMPDIR=$(mktemp -d) function delete() { echo "Deleting ${TMPDIR}..." if [[ $EUID -ne 0 ]]; then sudo rm -rf "${TMPDIR}" else rm -rf "${TMPDIR}" fi } trap delete EXIT INT TERM function run_tests() { # Add safe.directory as workaround for https://github.com/actions/runner/issues/2033 BUILD_CMD="git config --global safe.directory /go/src/github.com/google/cadvisor && env GOOS=linux GOARCH=amd64 GO_FLAGS='$GO_FLAGS' ./build/build.sh && \ env GOOS=linux GOFLAGS='$GO_FLAGS' go test -c github.com/google/cadvisor/integration/tests/api && \ env GOOS=linux GOFLAGS='$GO_FLAGS' go test -c github.com/google/cadvisor/integration/tests/common && \ env GOOS=linux GOFLAGS='$GO_FLAGS' go test -c github.com/google/cadvisor/integration/tests/metrics" if [ "$BUILD_PACKAGES" != "" ]; then BUILD_CMD="apt update && apt install -y $BUILD_PACKAGES && \ $BUILD_CMD" fi docker run --rm \ --platform linux/amd64 \ -w /go/src/github.com/google/cadvisor \ -v ${PWD}:/go/src/github.com/google/cadvisor \ golang:"$GOLANG_VERSION-$DEBIAN_VERSION" \ bash -c "$BUILD_CMD" EXTRA_DOCKER_OPTS="-e DOCKER_IN_DOCKER_ENABLED=true" if [[ "${OSTYPE}" == "linux"* ]]; then EXTRA_DOCKER_OPTS+=" -v ${TMPDIR}/docker-graph:/docker-graph" fi mkdir ${TMPDIR}/docker-graph docker run --rm \ --platform linux/amd64 \ -w /go/src/github.com/google/cadvisor \ -v ${ROOT}:/go/src/github.com/google/cadvisor \ ${EXTRA_DOCKER_OPTS} \ --privileged \ --cap-add="sys_admin" \ --entrypoint="" \ gcr.io/k8s-staging-test-infra/bootstrap:v20250702-52f5173c3a \ bash -c "export DEBIAN_FRONTEND=noninteractive && \ apt update && \ apt install -y $PACKAGES && \ CADVISOR_ARGS=$CADVISOR_ARGS /usr/local/bin/runner.sh build/integration.sh" } GO_FLAGS=${GO_FLAGS:-"-tags=netgo -race"} PACKAGES=${PACKAGES:-"sudo"} BUILD_PACKAGES=${BUILD_PACKAGES:-} CADVISOR_ARGS=${CADVISOR_ARGS:-} GOLANG_VERSION=${GOLANG_VERSION:-"1.25"} DEBIAN_VERSION=${DEBIAN_VERSION:-"trixie"} run_tests ================================================ FILE: build/integration.sh ================================================ #!/usr/bin/env bash # Copyright 2016 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -e # When running this script locally, you may need to run cadvisor with sudo # permissions if you cadvisor can't find containers. # USE_SUDO=true make test-integration USE_SUDO=${USE_SUDO:-false} cadvisor_bin=${CADVISOR_BIN:-"./_output/cadvisor"} if ! [ -f "$cadvisor_bin" ]; then echo Failed to find cadvisor binary for integration test at path $cadvisor_bin exit 1 fi log_file="cadvisor.log" if [ "$#" -gt 0 ]; then log_file="$1" fi TEST_PID=$$ printf "" # Refresh sudo credentials if necessary. # Diagnostic logging for docker/containerd debugging echo ">> Diagnostic information:" echo "=== Docker version ===" docker version || echo "docker version failed" echo "=== Docker info ===" docker info || echo "docker info failed" echo "=== Containerd socket check ===" ls -la /run/containerd/ 2>/dev/null || echo "/run/containerd/ not found" ls -la /var/run/containerd/ 2>/dev/null || echo "/var/run/containerd/ not found" ls -la /var/run/docker/containerd/ 2>/dev/null || echo "/var/run/docker/containerd/ not found" echo "=== Find all containerd sockets ===" find /var/run /run -name "*.sock" 2>/dev/null | head -20 || echo "No sockets found" echo "=== Docker socket check ===" ls -la /var/run/docker.sock 2>/dev/null || echo "/var/run/docker.sock not found" echo "=== Running processes (docker/containerd) ===" ps aux | grep -E "(docker|containerd)" | grep -v grep || echo "No docker/containerd processes found" echo "=== Kernel version ===" uname -r echo "=== End diagnostic information ===" # Install ctr (containerd CLI) if not available - needed for containerd integration tests if ! command -v ctr &> /dev/null; then CTR_VERSION="1.7.24" CTR_ARCH="amd64" [ "$(uname -m)" = "aarch64" ] && CTR_ARCH="arm64" curl -sL "https://github.com/containerd/containerd/releases/download/v${CTR_VERSION}/containerd-${CTR_VERSION}-linux-${CTR_ARCH}.tar.gz" | sudo tar -xz -C /usr/local fi # Detect containerd socket path - Docker-in-Docker uses a different path export CONTAINERD_SOCK="/run/containerd/containerd.sock" if [ -S "/run/docker/containerd/containerd.sock" ]; then export CONTAINERD_SOCK="/run/docker/containerd/containerd.sock" echo ">> Using Docker-embedded containerd socket: $CONTAINERD_SOCK" fi # Set up cgroup delegation for containerd k8s.io namespace (cgroups v2) sudo mkdir -p /sys/fs/cgroup/init xargs -rn1 < /sys/fs/cgroup/cgroup.procs 2>/dev/null | sudo tee /sys/fs/cgroup/init/cgroup.procs > /dev/null 2>&1 || true sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers | sudo tee /sys/fs/cgroup/cgroup.subtree_control > /dev/null 2>&1 || true sudo mkdir -p /sys/fs/cgroup/k8s.io sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers | sudo tee /sys/fs/cgroup/k8s.io/cgroup.subtree_control > /dev/null 2>&1 || true function start { set +e # We want to handle errors if cAdvisor crashes. echo ">> starting cAdvisor locally" cadvisor_prereqs="" if [ $USE_SUDO = true ]; then cadvisor_prereqs=sudo fi # cpu, cpuset, percpu, memory, disk, diskIO, network, perf_event metrics should be enabled. GORACE="halt_on_error=1" $cadvisor_prereqs $cadvisor_bin --enable_metrics="cpu,cpuset,percpu,memory,disk,diskIO,network,perf_event" --env_metadata_whitelist=TEST_VAR --containerd="$CONTAINERD_SOCK" --v=6 --logtostderr $CADVISOR_ARGS &> "$log_file" exit_code=$? if [ $exit_code != 0 ]; then echo "!! cAdvisor exited unexpectedly with Exit $exit_code" cat $log_file kill $TEST_PID # cAdvisor crashed: abort testing. fi } start & RUNNER_PID=$! function cleanup { if pgrep cadvisor > /dev/null; then echo ">> stopping cAdvisor" pkill -SIGINT cadvisor wait $RUNNER_PID fi } trap cleanup EXIT SIGINT TERM readonly TIMEOUT=30 # Timeout to wait for cAdvisor, in seconds. START=$(date +%s) while [ "$(curl -Gs http://localhost:8080/healthz)" != "ok" ]; do if (( $(date +%s) - $START > $TIMEOUT )); then echo "Timed out waiting for cAdvisor to start" exit 1 fi echo "Waiting for cAdvisor to start ..." sleep 1 done if [[ "${DOCKER_IN_DOCKER_ENABLED:-}" == "true" ]]; then # see https://github.com/moby/moby/blob/master/hack/dind # cgroup v2: enable nesting if [ -f /sys/fs/cgroup/cgroup.controllers ]; then echo ">> configuring cgroupsv2 for docker in docker..." # move the processes from the root group to the /init group, # otherwise writing subtree_control fails with EBUSY. # An error during moving non-existent process (i.e., "cat") is ignored. mkdir -p /sys/fs/cgroup/init xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || : # enable controllers sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ > /sys/fs/cgroup/cgroup.subtree_control fi fi echo ">> running integration tests against local cAdvisor" if ! [ -f ./api.test ] || ! [ -f ./common.test ] || ! [ -f ./metrics.test ]; then echo You must compile the ./api.test, ./common.test, and ./metrics.test binaries echo before running the integration tests. exit 1 fi ./api.test --vmodule=*=2 -test.v ./common.test -test.v ./metrics.test -test.v ================================================ FILE: build/prow_e2e.sh ================================================ #!/usr/bin/env bash # Copyright 2018 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -e set -x BUILDER=${BUILDER:-false} # Whether this is running a PR builder job. export GO_FLAGS="-race" export GORACE="halt_on_error=1" # cd to cadvisor directory parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) cd "$parent_path/.." # Check whether assets need to be rebuilt. FORCE=true build/assets.sh if [[ ! -z "$(git diff --name-only -- cmd/internal/pages)" ]]; then echo "Found changes to UI assets:" git diff --name-only -- cmd/internal/pages echo "Run: 'make assets FORCE=true'" exit 1 fi make build test # compile integration tests so they can be run without go installed go test -c github.com/google/cadvisor/integration/tests/api go test -c github.com/google/cadvisor/integration/tests/healthz ================================================ FILE: build/release.sh ================================================ #!/usr/bin/env bash # Copyright 2015 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -e if [ -z "$VERSION" ]; then VERSION=$( git describe --tags --dirty --abbrev=14 | sed -E 's/-([0-9]+)-g/.\1+/' ) # Only allow releases of tagged versions. TAGGED='^v[0-9]+\.[0-9]+\.[0-9]+(-(alpha|beta|rc)\.?[0-9]*)?$' if [[ ! "$VERSION" =~ $TAGGED ]]; then echo "Error: Only tagged versions are allowed for releases" >&2 echo "Found: $VERSION" >&2 exit 1 fi fi read -p "Please confirm: $VERSION is the desired version (Type y/n to continue):" -n 1 -r echo if ! [[ $REPLY =~ ^[Yy]$ ]]; then exit 1 fi # Don't include hostname with release builds if ! git_user="$(git config --get user.email)"; then echo "Error: git user not set, use:" echo "git config user.email " exit 1 fi export BUILD_USER="$git_user" export BUILD_DATE=$( date +%Y%m%d ) # Release date is only to day-granularity export VERBOSE=true # Build the docker image echo ">> building cadvisor docker image" image_name=${IMAGE_NAME:-"gcr.io/cadvisor/cadvisor"} final_image="$image_name:${VERSION}" docker buildx inspect cadvisor-builder > /dev/null \ || docker buildx create --name cadvisor-builder --use # Build binaries # A mapping of the docker arch name to the qemu arch name declare -A arches=( ["amd64"]="x86_64" ["arm"]="arm" ["arm64"]="aarch64" ["s390x"]="s390x" ) for arch in "${arches[@]}"; do if ! hash "qemu-${arch}-static"; then echo Releasing multi arch containers requires qemu-user-static. echo echo Please install using apt-get install qemu-user-static or echo a similar package for your OS. exit 1 fi done for arch in "${!arches[@]}"; do GOARCH="$arch" GO_CGO_ENABLED="0" OUTPUT_NAME_WITH_ARCH="true" build/build.sh arch_specific_image="${image_name}-${arch}:${VERSION}" docker buildx build --platform "linux/${arch}" --provenance=false --build-arg VERSION="$VERSION" -f deploy/Dockerfile -t "$arch_specific_image" --progress plain --push . docker manifest create --amend "$final_image" "$arch_specific_image" docker manifest annotate --os=linux --arch="$arch" "$final_image" "$arch_specific_image" done docker manifest push "$final_image" echo echo "Release info (copy to the release page)": echo echo Multi Arch Container Image: echo $final_image echo echo Architecture Specific Container Images: for arch in "${!arches[@]}"; do echo "${image_name}-${arch}:${VERSION}" done echo echo Binaries: (cd _output && find . -name "cadvisor-${VERSION}*" -exec sha256sum --tag {} \;) exit 0 ================================================ FILE: build/unit-in-container.sh ================================================ #!/usr/bin/env bash # Copyright 2020 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -ex if ! CONTAINER_ENGINE=$(command -v docker || command -v podman); then echo "Neither docker nor podman found. Exiting." exit 1 fi function run_tests() { BUILD_CMD="make test" if [ "$BUILD_PACKAGES" != "" ]; then BUILD_CMD="echo 'deb http://deb.debian.org/debian buster-backports main'>/etc/apt/sources.list.d/buster.list apt update apt install -y -t buster-backports $BUILD_PACKAGES $BUILD_CMD" fi $CONTAINER_ENGINE run --rm \ -w /go/src/github.com/google/cadvisor \ -v ${PWD}:/go/src/github.com/google/cadvisor \ -e GO_FLAGS \ golang:${GOLANG_VERSION} \ bash -e -c "$BUILD_CMD" } GO_FLAGS=${GO_FLAGS:-"-tags=netgo -race"} BUILD_PACKAGES=${BUILD_PACKAGES:-} GOLANG_VERSION=${GOLANG_VERSION:-"1.25"} run_tests ================================================ FILE: cache/cache.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cache import info "github.com/google/cadvisor/info/v1" type Cache interface { // Add a ContainerStats for the specified container. AddStats(ref info.ContainerReference, stats *info.ContainerStats) error // Remove all cached information for the specified container. RemoveContainer(containerName string) error // Read most recent stats. numStats indicates max number of stats // returned. The returned stats must be consecutive observed stats. If // numStats < 0, then return all stats stored in the storage. The // returned stats should be sorted in time increasing order, i.e. Most // recent stats should be the last. RecentStats(containerName string, numStats int) ([]*info.ContainerStats, error) // Close will clear the state of the storage driver. The elements // stored in the underlying storage may or may not be deleted depending // on the implementation of the storage driver. Close() error } ================================================ FILE: cache/memory/memory.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package memory import ( "errors" "sync" "time" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/storage" "github.com/google/cadvisor/utils" "k8s.io/klog/v2" ) // ErrDataNotFound is the error resulting if failed to find a container in memory cache. var ErrDataNotFound = errors.New("unable to find data in memory cache") // containerCacheMap is a typed wrapper around sync.Map that eliminates the need // for type assertions at every call site. It stores container name strings // mapped to *containerCache values. type containerCacheMap struct { m sync.Map } // Load retrieves a container cache by name. Returns nil, false if not found. func (c *containerCacheMap) Load(name string) (*containerCache, bool) { v, ok := c.m.Load(name) if !ok { return nil, false } return v.(*containerCache), true } // Store saves a container cache with the given name. func (c *containerCacheMap) Store(name string, cache *containerCache) { c.m.Store(name, cache) } // LoadOrStore returns the existing cache if present, otherwise stores and returns the given one. func (c *containerCacheMap) LoadOrStore(name string, cache *containerCache) (*containerCache, bool) { v, loaded := c.m.LoadOrStore(name, cache) return v.(*containerCache), loaded } // Delete removes a container cache by name. func (c *containerCacheMap) Delete(name string) { c.m.Delete(name) } // TODO(vmarmol): See about refactoring this class, we have an unnecessary redirection of containerCache and InMemoryCache. // containerCache is used to store per-container information type containerCache struct { ref info.ContainerReference recentStats *utils.TimedStore maxAge time.Duration lock sync.RWMutex } func (c *containerCache) AddStats(stats *info.ContainerStats) error { c.lock.Lock() defer c.lock.Unlock() // Add the stat to storage. c.recentStats.Add(stats.Timestamp, stats) return nil } func (c *containerCache) RecentStats(start, end time.Time, maxStats int) ([]*info.ContainerStats, error) { c.lock.RLock() defer c.lock.RUnlock() result := c.recentStats.InTimeRange(start, end, maxStats) converted := make([]*info.ContainerStats, len(result)) for i, el := range result { converted[i] = el.(*info.ContainerStats) } return converted, nil } func newContainerStore(ref info.ContainerReference, maxAge time.Duration) *containerCache { return &containerCache{ ref: ref, recentStats: utils.NewTimedStore(maxAge, -1), maxAge: maxAge, } } type InMemoryCache struct { containerCacheMap containerCacheMap maxAge time.Duration backend []storage.StorageDriver } func (c *InMemoryCache) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error { name := cInfo.ContainerReference.Name cstore, ok := c.containerCacheMap.Load(name) if !ok { newStore := newContainerStore(cInfo.ContainerReference, c.maxAge) cstore, _ = c.containerCacheMap.LoadOrStore(name, newStore) } for _, backend := range c.backend { // TODO(monnand): To deal with long delay write operations, we // may want to start a pool of goroutines to do write // operations. if err := backend.AddStats(cInfo, stats); err != nil { klog.Error(err) } } return cstore.AddStats(stats) } func (c *InMemoryCache) RecentStats(name string, start, end time.Time, maxStats int) ([]*info.ContainerStats, error) { cstore, ok := c.containerCacheMap.Load(name) if !ok { return nil, ErrDataNotFound } return cstore.RecentStats(start, end, maxStats) } func (c *InMemoryCache) Close() error { c.containerCacheMap = containerCacheMap{} return nil } func (c *InMemoryCache) RemoveContainer(containerName string) error { c.containerCacheMap.Delete(containerName) return nil } func New( maxAge time.Duration, backend []storage.StorageDriver, ) *InMemoryCache { return &InMemoryCache{ maxAge: maxAge, backend: backend, } } ================================================ FILE: cache/memory/memory_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package memory import ( "testing" "time" info "github.com/google/cadvisor/info/v1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const containerName = "/container" var ( cInfo = info.ContainerInfo{ ContainerReference: info.ContainerReference{Name: containerName}, } zero time.Time ) // Make stats with the specified identifier. func makeStat(i int) *info.ContainerStats { return &info.ContainerStats{ Timestamp: zero.Add(time.Duration(i) * time.Second), Cpu: info.CpuStats{ LoadAverage: int32(i), }, } } func getRecentStats(t *testing.T, memoryCache *InMemoryCache, numStats int) []*info.ContainerStats { stats, err := memoryCache.RecentStats(containerName, zero, zero, numStats) require.Nil(t, err) return stats } func TestAddStats(t *testing.T) { memoryCache := New(60*time.Second, nil) assert := assert.New(t) assert.Nil(memoryCache.AddStats(&cInfo, makeStat(0))) assert.Nil(memoryCache.AddStats(&cInfo, makeStat(1))) assert.Nil(memoryCache.AddStats(&cInfo, makeStat(2))) assert.Nil(memoryCache.AddStats(&cInfo, makeStat(0))) cInfo2 := info.ContainerInfo{ ContainerReference: info.ContainerReference{ Name: "/container2", }, } assert.Nil(memoryCache.AddStats(&cInfo2, makeStat(0))) assert.Nil(memoryCache.AddStats(&cInfo2, makeStat(1))) } func TestRecentStatsNoRecentStats(t *testing.T) { memoryCache := makeWithStats(t, 0) _, err := memoryCache.RecentStats(containerName, zero, zero, 60) assert.NotNil(t, err) } // Make an instance of InMemoryCache with n stats. func makeWithStats(t *testing.T, n int) *InMemoryCache { memoryCache := New(60*time.Second, nil) for i := 0; i < n; i++ { assert.NoError(t, memoryCache.AddStats(&cInfo, makeStat(i))) } return memoryCache } func TestRecentStatsGetZeroStats(t *testing.T) { memoryCache := makeWithStats(t, 10) assert.Len(t, getRecentStats(t, memoryCache, 0), 0) } func TestRecentStatsGetSomeStats(t *testing.T) { memoryCache := makeWithStats(t, 10) assert.Len(t, getRecentStats(t, memoryCache, 5), 5) } func TestRecentStatsGetAllStats(t *testing.T) { memoryCache := makeWithStats(t, 10) assert.Len(t, getRecentStats(t, memoryCache, -1), 10) } ================================================ FILE: client/README.md ================================================ # Example REST API Client This is an implementation of a cAdvisor REST API in Go. You can use it like this: ```go client, err := client.NewClient("http://192.168.59.103:8080/") ``` Obviously, replace the URL with the path to your actual cAdvisor REST endpoint. ### MachineInfo ```go client.MachineInfo() ``` This method returns a cadvisor/v1.MachineInfo struct with all the fields filled in. Here is an example return value: ``` (*v1.MachineInfo)(0xc208022b10)({ NumCores: (int) 4, MemoryCapacity: (int64) 2106028032, Filesystems: ([]v1.FsInfo) (len=1 cap=4) { (v1.FsInfo) { Device: (string) (len=9) "/dev/sda1", Capacity: (uint64) 19507089408 } } }) ``` You can see the full specification of the [MachineInfo struct in the source](../info/v1/machine.go#L131) ### ContainerInfo Given a container name and a [ContainerInfoRequest](../info/v1/container.go#L101), will return all information about the specified container. See the [ContainerInfoRequest struct in the source](../info/v1/container.go#L101) for the full specification. ```go request := v1.ContainerInfoRequest{NumStats: 10} sInfo, err := client.ContainerInfo("/docker/d9d3eb10179e6f93a...", &request) ``` Returns a [ContainerInfo struct](../info/v1/container.go#L128) ### SubcontainersInfo Given a container name and a [ContainerInfoRequest](../info/v1/container.go#L101), will recursively return all info about the container and all subcontainers contained within the container. See the [ContainerInfoRequest struct in the source](../info/v1/container.go#L101) for the full specification. ```go request := v1.ContainerInfoRequest{NumStats: 10} sInfo, err := client.SubcontainersInfo("/docker", &request) ``` Returns a [ContainerInfo struct](../info/v1/container.go#L128) with the Subcontainers field populated. ================================================ FILE: client/client.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // This is an implementation of a cAdvisor REST API in Go. // To use it, create a client (replace the URL with your actual cAdvisor REST endpoint): // // client, err := client.NewClient("http://192.168.59.103:8080/") // // Then, the client interface exposes go methods corresponding to the REST endpoints. package client import ( "bytes" "encoding/json" "fmt" "io" "net/http" "path" "strings" v1 "github.com/google/cadvisor/info/v1" "k8s.io/klog/v2" ) // Client represents the base URL for a cAdvisor client. type Client struct { baseURL string httpClient *http.Client } // NewClient returns a new v1.3 client with the specified base URL. func NewClient(url string) (*Client, error) { return newClient(url, http.DefaultClient) } func newClient(url string, client *http.Client) (*Client, error) { if !strings.HasSuffix(url, "/") { url += "/" } return &Client{ baseURL: fmt.Sprintf("%sapi/v1.3/", url), httpClient: client, }, nil } // Returns all past events that satisfy the request func (c *Client) EventStaticInfo(name string) (einfo []*v1.Event, err error) { u := c.eventsInfoURL(name) ret := new([]*v1.Event) if err = c.httpGetJSONData(ret, nil, u, "event info"); err != nil { return } einfo = *ret return } // Streams all events that occur that satisfy the request into the channel // that is passed func (c *Client) EventStreamingInfo(name string, einfo chan *v1.Event) (err error) { u := c.eventsInfoURL(name) if err = c.getEventStreamingData(u, einfo); err != nil { return } return nil } // MachineInfo returns the JSON machine information for this client. // A non-nil error result indicates a problem with obtaining // the JSON machine information data. func (c *Client) MachineInfo() (minfo *v1.MachineInfo, err error) { u := c.machineInfoURL() ret := new(v1.MachineInfo) if err = c.httpGetJSONData(ret, nil, u, "machine info"); err != nil { return } minfo = ret return } // ContainerInfo returns the JSON container information for the specified // container and request. func (c *Client) ContainerInfo(name string, query *v1.ContainerInfoRequest) (cinfo *v1.ContainerInfo, err error) { u := c.containerInfoURL(name) ret := new(v1.ContainerInfo) if err = c.httpGetJSONData(ret, query, u, fmt.Sprintf("container info for %q", name)); err != nil { return } cinfo = ret return } // Returns the information about all subcontainers (recursive) of the specified container (including itself). func (c *Client) SubcontainersInfo(name string, query *v1.ContainerInfoRequest) ([]v1.ContainerInfo, error) { var response []v1.ContainerInfo url := c.subcontainersInfoURL(name) err := c.httpGetJSONData(&response, query, url, fmt.Sprintf("subcontainers container info for %q", name)) if err != nil { return []v1.ContainerInfo{}, err } return response, nil } // Returns the JSON container information for the specified // Docker container and request. func (c *Client) DockerContainer(name string, query *v1.ContainerInfoRequest) (cinfo v1.ContainerInfo, err error) { u := c.dockerInfoURL(name) ret := make(map[string]v1.ContainerInfo) if err = c.httpGetJSONData(&ret, query, u, fmt.Sprintf("Docker container info for %q", name)); err != nil { return } if len(ret) != 1 { err = fmt.Errorf("expected to only receive 1 Docker container: %+v", ret) return } for _, cont := range ret { cinfo = cont } return } // Returns the JSON container information for all Docker containers. func (c *Client) AllDockerContainers(query *v1.ContainerInfoRequest) (cinfo []v1.ContainerInfo, err error) { u := c.dockerInfoURL("/") ret := make(map[string]v1.ContainerInfo) if err = c.httpGetJSONData(&ret, query, u, "all Docker containers info"); err != nil { return } cinfo = make([]v1.ContainerInfo, 0, len(ret)) for _, cont := range ret { cinfo = append(cinfo, cont) } return } func (c *Client) machineInfoURL() string { return c.baseURL + path.Join("machine") } func (c *Client) containerInfoURL(name string) string { return c.baseURL + path.Join("containers", name) } func (c *Client) subcontainersInfoURL(name string) string { return c.baseURL + path.Join("subcontainers", name) } func (c *Client) dockerInfoURL(name string) string { return c.baseURL + path.Join("docker", name) } func (c *Client) eventsInfoURL(name string) string { return c.baseURL + path.Join("events", name) } func (c *Client) httpGetJSONData(data, postData interface{}, url, infoName string) error { var resp *http.Response var err error if postData != nil { data, marshalErr := json.Marshal(postData) if marshalErr != nil { return fmt.Errorf("unable to marshal data: %v", marshalErr) } resp, err = c.httpClient.Post(url, "application/json", bytes.NewBuffer(data)) } else { resp, err = c.httpClient.Get(url) } if err != nil { return fmt.Errorf("unable to get %q from %q: %v", infoName, url, err) } if resp == nil { return fmt.Errorf("received empty response for %q from %q", infoName, url) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { err = fmt.Errorf("unable to read all %q from %q: %v", infoName, url, err) return err } if resp.StatusCode != 200 { return fmt.Errorf("request %q failed with error: %q", url, strings.TrimSpace(string(body))) } if err = json.Unmarshal(body, data); err != nil { err = fmt.Errorf("unable to unmarshal %q (Body: %q) from %q with error: %v", infoName, string(body), url, err) return err } return nil } func (c *Client) getEventStreamingData(url string, einfo chan *v1.Event) error { req, err := http.NewRequest("GET", url, nil) if err != nil { return err } resp, err := c.httpClient.Do(req) if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("status code is not OK: %v (%s)", resp.StatusCode, resp.Status) } dec := json.NewDecoder(resp.Body) m := &v1.Event{} for { err := dec.Decode(m) if err != nil { if err == io.EOF { break } // if called without &stream=true will not be able to parse event and will trigger fatal klog.Fatalf("Received error %v", err) } einfo <- m } return nil } ================================================ FILE: client/client_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package client import ( "encoding/json" "fmt" "net/http" "net/http/httptest" "path" "reflect" "strings" "testing" "time" info "github.com/google/cadvisor/info/v1" itest "github.com/google/cadvisor/info/v1/test" "github.com/stretchr/testify/assert" ) func cadvisorTestClient(path string, expectedPostObj *info.ContainerInfoRequest, replyObj interface{}, t *testing.T) (*Client, *httptest.Server, error) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == path { if expectedPostObj != nil { expectedPostObjEmpty := new(info.ContainerInfoRequest) decoder := json.NewDecoder(r.Body) if err := decoder.Decode(expectedPostObjEmpty); err != nil { t.Errorf("Received invalid object: %v", err) } if expectedPostObj.NumStats != expectedPostObjEmpty.NumStats || expectedPostObj.Start.Unix() != expectedPostObjEmpty.Start.Unix() || expectedPostObj.End.Unix() != expectedPostObjEmpty.End.Unix() { t.Errorf("Received unexpected object: %+v, expected: %+v", expectedPostObjEmpty, expectedPostObj) } } encoder := json.NewEncoder(w) err := encoder.Encode(replyObj) assert.NoError(t, err) } else { w.WriteHeader(http.StatusNotFound) fmt.Fprintf(w, "Page not found.") } })) client, err := NewClient(ts.URL) if err != nil { ts.Close() return nil, nil, err } return client, ts, err } // TestGetMachineInfo performs one test to check if MachineInfo() // in a cAdvisor client returns the correct result. func TestGetMachineinfo(t *testing.T) { minfo := &info.MachineInfo{ NumCores: 8, MemoryCapacity: 31625871360, DiskMap: map[string]info.DiskInfo{ "8:0": { Name: "sda", Major: 8, Minor: 0, Size: 10737418240, }, }, } client, server, err := cadvisorTestClient("/api/v1.3/machine", nil, minfo, t) if err != nil { t.Fatalf("unable to get a client %v", err) } defer server.Close() returned, err := client.MachineInfo() if err != nil { t.Fatal(err) } if !reflect.DeepEqual(returned, minfo) { t.Fatalf("received unexpected machine info") } } // TestGetContainerInfo generates a random container information object // and then checks that ContainerInfo returns the expected result. func TestGetContainerInfo(t *testing.T) { query := &info.ContainerInfoRequest{ NumStats: 3, } containerName := "/some/container" cinfo := itest.GenerateRandomContainerInfo(containerName, 4, query, 1*time.Second) client, server, err := cadvisorTestClient(fmt.Sprintf("/api/v1.3/containers%v", containerName), query, cinfo, t) if err != nil { t.Fatalf("unable to get a client %v", err) } defer server.Close() returned, err := client.ContainerInfo(containerName, query) if err != nil { t.Fatal(err) } if !returned.Eq(cinfo) { t.Error("received unexpected ContainerInfo") } } // Test a request failing func TestRequestFails(t *testing.T) { errorText := "there was an error" // Setup a server that simply fails. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, errorText, 500) })) client, err := NewClient(ts.URL) if err != nil { ts.Close() t.Fatal(err) } defer ts.Close() _, err = client.ContainerInfo("/", &info.ContainerInfoRequest{NumStats: 3}) if err == nil { t.Fatalf("Expected non-nil error") } expectedError := fmt.Sprintf("request failed with error: %q", errorText) if strings.Contains(err.Error(), expectedError) { t.Fatalf("Expected error %q but received %q", expectedError, err) } } func TestGetSubcontainersInfo(t *testing.T) { query := &info.ContainerInfoRequest{ NumStats: 3, } containerName := "/some/container" cinfo := itest.GenerateRandomContainerInfo(containerName, 4, query, 1*time.Second) cinfo1 := itest.GenerateRandomContainerInfo(path.Join(containerName, "sub1"), 4, query, 1*time.Second) cinfo2 := itest.GenerateRandomContainerInfo(path.Join(containerName, "sub2"), 4, query, 1*time.Second) response := []info.ContainerInfo{ *cinfo, *cinfo1, *cinfo2, } client, server, err := cadvisorTestClient(fmt.Sprintf("/api/v1.3/subcontainers%v", containerName), query, response, t) if err != nil { t.Fatalf("unable to get a client %v", err) } defer server.Close() returned, err := client.SubcontainersInfo(containerName, query) if err != nil { t.Fatal(err) } if len(returned) != 3 { t.Errorf("unexpected number of results: got %d, expected 3", len(returned)) } if !returned[0].Eq(cinfo) { t.Error("received unexpected ContainerInfo") } if !returned[1].Eq(cinfo1) { t.Error("received unexpected ContainerInfo") } if !returned[2].Eq(cinfo2) { t.Error("received unexpected ContainerInfo") } } ================================================ FILE: client/clientexample/main.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "flag" "github.com/google/cadvisor/client" info "github.com/google/cadvisor/info/v1" "k8s.io/klog/v2" ) func staticClientExample() { staticClient, err := client.NewClient("http://localhost:8080/") if err != nil { klog.Errorf("tried to make client and got error %v", err) return } einfo, err := staticClient.EventStaticInfo("?oom_events=true") if err != nil { klog.Errorf("got error retrieving event info: %v", err) return } for idx, ev := range einfo { klog.Infof("static einfo %v: %v", idx, ev) } } func streamingClientExample(url string) { streamingClient, err := client.NewClient("http://localhost:8080/") if err != nil { klog.Errorf("tried to make client and got error %v", err) return } einfo := make(chan *info.Event) go func() { err = streamingClient.EventStreamingInfo(url, einfo) if err != nil { klog.Errorf("got error retrieving event info: %v", err) return } }() for ev := range einfo { klog.Infof("streaming einfo: %v\n", ev) } } // demonstrates how to use event clients func main() { klog.InitFlags(nil) flag.Parse() staticClientExample() streamingClientExample("?creation_events=true&stream=true&oom_events=true&deletion_events=true") } ================================================ FILE: client/v2/README.md ================================================ # Example REST API Client This is an implementation of a cAdvisor REST API in Go. You can use it like this: ```go client, err := client.NewClient("http://192.168.59.103:8080/") ``` Obviously, replace the URL with the path to your actual cAdvisor REST endpoint. ### MachineInfo ```go client.MachineInfo() ``` There is no v2 MachineInfo API, so the v2 client exposes the [v1 MachineInfo](../../info/v1/machine.go#L131) ``` (*v1.MachineInfo)(0xc208022b10)({ NumCores: (int) 4, MemoryCapacity: (int64) 2106028032, Filesystems: ([]v1.FsInfo) (len=1 cap=4) { (v1.FsInfo) { Device: (string) (len=9) "/dev/sda1", Capacity: (uint64) 19507089408 } } }) ``` You can see the full specification of the [MachineInfo struct in the source](../../info/v1/machine.go#L131) ### VersionInfo ```go client.VersionInfo() ``` This method returns the cAdvisor version. ### Attributes ```go client.Attributes() ``` This method returns a [cadvisor/info/v2/Attributes](../../info/v2/machine.go#L24) struct with all the fields filled in. Attributes includes hardware attributes (as returned by MachineInfo) as well as software attributes (eg. software versions). Here is an example return value: ``` (*v2.Attributes)({ KernelVersion: (string) (len=17) "3.13.0-44-generic" ContainerOsVersion: (string) (len=18) "Ubuntu 14.04.1 LTS" DockerVersion: (string) (len=9) "1.5.0-rc4" CadvisorVersion: (string) (len=6) "0.10.1" NumCores: (int) 4, MemoryCapacity: (int64) 2106028032, Filesystems: ([]v2.FsInfo) (len=1 cap=4) { (v2.FsInfo) { Device: (string) (len=9) "/dev/sda1", Capacity: (uint64) 19507089408 } } }) ``` You can see the full specification of the [Attributes struct in the source](../../info/v2/machine.go#L24) ================================================ FILE: client/v2/client.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Client library to programmatically access cAdvisor API. package v2 import ( "bytes" "encoding/json" "fmt" "io" "net/http" "net/url" "path" "strconv" "strings" v1 "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" ) // Client represents the base URL for a cAdvisor client. type Client struct { baseURL string } // NewClient returns a new client with the specified base URL. func NewClient(url string) (*Client, error) { if !strings.HasSuffix(url, "/") { url += "/" } return &Client{ baseURL: fmt.Sprintf("%sapi/v2.1/", url), }, nil } // MachineInfo returns the JSON machine information for this client. // A non-nil error result indicates a problem with obtaining // the JSON machine information data. func (c *Client) MachineInfo() (minfo *v1.MachineInfo, err error) { u := c.machineInfoURL() ret := new(v1.MachineInfo) if err = c.httpGetJSONData(ret, nil, u, "machine info"); err != nil { return } minfo = ret return } // MachineStats returns the JSON machine statistics for this client. // A non-nil error result indicates a problem with obtaining // the JSON machine information data. func (c *Client) MachineStats() ([]v2.MachineStats, error) { var ret []v2.MachineStats u := c.machineStatsURL() err := c.httpGetJSONData(&ret, nil, u, "machine stats") return ret, err } // VersionInfo returns the version info for cAdvisor. func (c *Client) VersionInfo() (version string, err error) { u := c.versionInfoURL() version, err = c.httpGetString(u, "version info") return } // Attributes returns hardware and software attributes of the machine. func (c *Client) Attributes() (attr *v2.Attributes, err error) { u := c.attributesURL() ret := new(v2.Attributes) if err = c.httpGetJSONData(ret, nil, u, "attributes"); err != nil { return } attr = ret return } // Stats returns stats for the requested container. func (c *Client) Stats(name string, request *v2.RequestOptions) (map[string]v2.ContainerInfo, error) { u := c.statsURL(name) ret := make(map[string]v2.ContainerInfo) data := url.Values{ "type": []string{request.IdType}, "count": []string{strconv.Itoa(request.Count)}, "recursive": []string{strconv.FormatBool(request.Recursive)}, } if request.MaxAge != nil { data.Set("max_age", request.MaxAge.String()) } u = fmt.Sprintf("%s?%s", u, data.Encode()) if err := c.httpGetJSONData(&ret, nil, u, "stats"); err != nil { return nil, err } return ret, nil } func (c *Client) machineInfoURL() string { return c.baseURL + path.Join("machine") } func (c *Client) machineStatsURL() string { return c.baseURL + path.Join("machinestats") } func (c *Client) versionInfoURL() string { return c.baseURL + path.Join("version") } func (c *Client) attributesURL() string { return c.baseURL + path.Join("attributes") } func (c *Client) statsURL(name string) string { return c.baseURL + path.Join("stats", name) } func (c *Client) httpGetResponse(postData interface{}, urlPath, infoName string) ([]byte, error) { var resp *http.Response var err error if postData != nil { data, marshalErr := json.Marshal(postData) if marshalErr != nil { return nil, fmt.Errorf("unable to marshal data: %v", marshalErr) } resp, err = http.Post(urlPath, "application/json", bytes.NewBuffer(data)) } else { resp, err = http.Get(urlPath) } if err != nil { return nil, fmt.Errorf("unable to post %q to %q: %v", infoName, urlPath, err) } if resp == nil { return nil, fmt.Errorf("received empty response for %q from %q", infoName, urlPath) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { err = fmt.Errorf("unable to read all %q from %q: %v", infoName, urlPath, err) return nil, err } if resp.StatusCode != 200 { return nil, fmt.Errorf("request %q failed with error: %q", urlPath, strings.TrimSpace(string(body))) } return body, nil } func (c *Client) httpGetString(url, infoName string) (string, error) { body, err := c.httpGetResponse(nil, url, infoName) if err != nil { return "", err } return string(body), nil } func (c *Client) httpGetJSONData(data, postData interface{}, url, infoName string) error { body, err := c.httpGetResponse(postData, url, infoName) if err != nil { return err } if err = json.Unmarshal(body, data); err != nil { err = fmt.Errorf("unable to unmarshal %q (Body: %q) from %q with error: %v", infoName, string(body), url, err) return err } return nil } ================================================ FILE: client/v2/client_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package v2 import ( "encoding/json" "fmt" "net/http" "net/http/httptest" "reflect" "strings" "testing" "time" "github.com/stretchr/testify/assert" v1 "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" ) func cadvisorTestClient(path string, expectedPostObj *v1.ContainerInfoRequest, replyObj interface{}, t *testing.T) (*Client, *httptest.Server, error) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == path { if expectedPostObj != nil { expectedPostObjEmpty := new(v1.ContainerInfoRequest) decoder := json.NewDecoder(r.Body) if err := decoder.Decode(expectedPostObjEmpty); err != nil { t.Errorf("Received invalid object: %v", err) } if expectedPostObj.NumStats != expectedPostObjEmpty.NumStats || expectedPostObj.Start.Unix() != expectedPostObjEmpty.Start.Unix() || expectedPostObj.End.Unix() != expectedPostObjEmpty.End.Unix() { t.Errorf("Received unexpected object: %+v, expected: %+v", expectedPostObjEmpty, expectedPostObj) } } encoder := json.NewEncoder(w) err := encoder.Encode(replyObj) assert.NoError(t, err) } else if r.URL.Path == "/api/v2.1/version" { fmt.Fprintf(w, "0.1.2") } else { w.WriteHeader(http.StatusNotFound) fmt.Fprintf(w, "Page not found.") } })) client, err := NewClient(ts.URL) if err != nil { ts.Close() return nil, nil, err } return client, ts, err } // TestGetMachineInfo performs one test to check if MachineInfo() // in a cAdvisor client returns the correct result. func TestGetMachineInfo(t *testing.T) { mv1 := &v1.MachineInfo{ NumCores: 8, MemoryCapacity: 31625871360, DiskMap: map[string]v1.DiskInfo{ "8:0": { Name: "sda", Major: 8, Minor: 0, Size: 10737418240, }, }, } client, server, err := cadvisorTestClient("/api/v2.1/machine", nil, mv1, t) if err != nil { t.Fatalf("unable to get a client %v", err) } defer server.Close() returned, err := client.MachineInfo() if err != nil { t.Fatal(err) } if !reflect.DeepEqual(returned, mv1) { t.Fatalf("received unexpected machine v1") } } // TestGetVersionV1 performs one test to check if VersionV1() // in a cAdvisor client returns the correct result. func TestGetVersionv1(t *testing.T) { version := "0.1.2" client, server, err := cadvisorTestClient("", nil, version, t) if err != nil { t.Fatalf("unable to get a client %v", err) } defer server.Close() returned, err := client.VersionInfo() if err != nil { t.Fatal(err) } if returned != version { t.Fatalf("received unexpected version v1") } } // TestAttributes performs one test to check if Attributes() // in a cAdvisor client returns the correct result. func TestGetAttributes(t *testing.T) { attr := &v2.Attributes{ KernelVersion: "3.3.0", ContainerOsVersion: "Ubuntu 14.4", DockerVersion: "Docker 1.5", CadvisorVersion: "0.1.2", NumCores: 8, MemoryCapacity: 31625871360, DiskMap: map[string]v1.DiskInfo{ "8:0": { Name: "sda", Major: 8, Minor: 0, Size: 10737418240, }, }, } client, server, err := cadvisorTestClient("/api/v2.1/attributes", nil, attr, t) if err != nil { t.Fatalf("unable to get a client %v", err) } defer server.Close() returned, err := client.Attributes() if err != nil { t.Fatal(err) } if !reflect.DeepEqual(returned, attr) { t.Fatalf("received unexpected attributes") } } // TestMachineStats performs one test to check if MachineStats() // in a cAdvisor client returns the correct result. func TestMachineStats(t *testing.T) { machineStats := []v2.MachineStats{ { Timestamp: time.Now(), Cpu: &v1.CpuStats{ Usage: v1.CpuUsage{ Total: 100000, }, LoadAverage: 10, }, Filesystem: []v2.MachineFsStats{ { Device: "sda1", }, }, }, } client, server, err := cadvisorTestClient("/api/v2.1/machinestats", nil, &machineStats, t) if err != nil { t.Fatalf("unable to get a client %v", err) } defer server.Close() returned, err := client.MachineStats() if err != nil { t.Fatal(err) } assert.Len(t, returned, len(machineStats)) if !reflect.DeepEqual(returned[0].Cpu, machineStats[0].Cpu) { t.Fatalf("received unexpected machine stats\nExp: %+v\nAct: %+v", machineStats, returned) } if !reflect.DeepEqual(returned[0].Filesystem, machineStats[0].Filesystem) { t.Fatalf("received unexpected machine stats\nExp: %+v\nAct: %+v", machineStats, returned) } } func TestRequestFails(t *testing.T) { errorText := "there was an error" // Setup a server that simply fails. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, errorText, 500) })) client, err := NewClient(ts.URL) if err != nil { ts.Close() t.Fatal(err) } defer ts.Close() _, err = client.MachineInfo() if err == nil { t.Fatalf("Expected non-nil error") } expectedError := fmt.Sprintf("request failed with error: %q", errorText) if strings.Contains(err.Error(), expectedError) { t.Fatalf("Expected error %q but received %q", expectedError, err) } } ================================================ FILE: cmd/cadvisor.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "crypto/tls" "flag" "fmt" "net/http" "net/http/pprof" "os" "os/signal" "runtime" "strings" "syscall" cadvisorhttp "github.com/google/cadvisor/cmd/internal/http" "github.com/google/cadvisor/container" "github.com/google/cadvisor/manager" "github.com/google/cadvisor/metrics" "github.com/google/cadvisor/utils/sysfs" "github.com/google/cadvisor/version" // Register container providers _ "github.com/google/cadvisor/cmd/internal/container/install" // Register CloudProviders _ "github.com/google/cadvisor/utils/cloudinfo/aws" _ "github.com/google/cadvisor/utils/cloudinfo/azure" _ "github.com/google/cadvisor/utils/cloudinfo/gce" // Register resctrl plugin _ "github.com/google/cadvisor/resctrl/intel/install" "k8s.io/klog/v2" ) var argIP = flag.String("listen_ip", "", "IP to listen on, defaults to all IPs") var argPort = flag.Int("port", 8080, "port to listen") var maxProcs = flag.Int("max_procs", 0, "max number of CPUs that can be used simultaneously. Less than 1 for default (number of cores).") var versionFlag = flag.Bool("version", false, "print cAdvisor version and exit") var httpAuthFile = flag.String("http_auth_file", "", "HTTP auth file for the web UI") var httpAuthRealm = flag.String("http_auth_realm", "localhost", "HTTP auth realm for the web UI") var httpDigestFile = flag.String("http_digest_file", "", "HTTP digest file for the web UI") var httpDigestRealm = flag.String("http_digest_realm", "localhost", "HTTP digest file for the web UI") var prometheusEndpoint = flag.String("prometheus_endpoint", "/metrics", "Endpoint to expose Prometheus metrics on") var enableProfiling = flag.Bool("profiling", false, "Enable profiling via web interface host:port/debug/pprof/") var collectorCert = flag.String("collector_cert", "", "Collector's certificate, exposed to endpoints for certificate based authentication.") var collectorKey = flag.String("collector_key", "", "Key for the collector's certificate") var storeContainerLabels = flag.Bool("store_container_labels", true, "convert container labels and environment variables into labels on prometheus metrics for each container. If flag set to false, then only metrics exported are container name, first alias, and image name") var whitelistedContainerLabels = flag.String("whitelisted_container_labels", "", "comma separated list of container labels to be converted to labels on prometheus metrics for each container. store_container_labels must be set to false for this to take effect.") var envMetadataWhiteList = flag.String("env_metadata_whitelist", "", "a comma-separated list of environment variable keys matched with specified prefix that needs to be collected for containers, only support containerd and docker runtime for now.") var urlBasePrefix = flag.String("url_base_prefix", "", "prefix path that will be prepended to all paths to support some reverse proxies") var rawCgroupPrefixWhiteList = flag.String("raw_cgroup_prefix_whitelist", "", "A comma-separated list of cgroup path prefix that needs to be collected even when -docker_only is specified") var perfEvents = flag.String("perf_events_config", "", "Path to a JSON file containing configuration of perf events to measure. Empty value disabled perf events measuring.") var resctrlInterval = flag.Duration("resctrl_interval", 0, "Resctrl mon groups updating interval. Zero value disables updating mon groups.") var ( // Metrics to be ignored. // Tcp metrics are ignored by default. ignoreMetrics = container.MetricSet{ container.MemoryNumaMetrics: struct{}{}, container.NetworkTcpUsageMetrics: struct{}{}, container.NetworkUdpUsageMetrics: struct{}{}, container.NetworkAdvancedTcpUsageMetrics: struct{}{}, container.ProcessSchedulerMetrics: struct{}{}, container.ProcessMetrics: struct{}{}, container.HugetlbUsageMetrics: struct{}{}, container.ReferencedMemoryMetrics: struct{}{}, container.CPUTopologyMetrics: struct{}{}, container.ResctrlMetrics: struct{}{}, container.CPUSetMetrics: struct{}{}, } // Metrics to be enabled. Used only if non-empty. enableMetrics = container.MetricSet{} ) func init() { optstr := container.AllMetrics.String() flag.Var(&ignoreMetrics, "disable_metrics", fmt.Sprintf("comma-separated list of `metrics` to be disabled. Options are %s.", optstr)) flag.Var(&enableMetrics, "enable_metrics", fmt.Sprintf("comma-separated list of `metrics` to be enabled. If set, overrides 'disable_metrics'. Options are %s.", optstr)) } func main() { klog.InitFlags(nil) defer klog.Flush() // Default logging verbosity to V(2) _ = flag.Set("v", "2") flag.Parse() if *versionFlag { fmt.Printf("cAdvisor version %s (%s)\n", version.Info["version"], version.Info["revision"]) os.Exit(0) } var includedMetrics container.MetricSet if len(enableMetrics) > 0 { includedMetrics = enableMetrics } else { includedMetrics = container.AllMetrics.Difference(ignoreMetrics) } klog.V(1).Infof("enabled metrics: %s", includedMetrics.String()) setMaxProcs() memoryStorage, err := NewMemoryStorage() if err != nil { klog.Fatalf("Failed to initialize storage driver: %s", err) } sysFs := sysfs.NewRealSysFs() collectorHTTPClient := createCollectorHTTPClient(*collectorCert, *collectorKey) resourceManager, err := manager.New(memoryStorage, sysFs, manager.HousekeepingConfigFlags, includedMetrics, &collectorHTTPClient, strings.Split(*rawCgroupPrefixWhiteList, ","), strings.Split(*envMetadataWhiteList, ","), *perfEvents, *resctrlInterval) if err != nil { klog.Fatalf("Failed to create a manager: %s", err) } mux := http.NewServeMux() if *enableProfiling { mux.HandleFunc("/debug/pprof/", pprof.Index) mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) mux.HandleFunc("/debug/pprof/profile", pprof.Profile) mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) } // Register all HTTP handlers. err = cadvisorhttp.RegisterHandlers(mux, resourceManager, *httpAuthFile, *httpAuthRealm, *httpDigestFile, *httpDigestRealm, *urlBasePrefix) if err != nil { klog.Fatalf("Failed to register HTTP handlers: %v", err) } containerLabelFunc := metrics.DefaultContainerLabels if !*storeContainerLabels { whitelistedLabels := strings.Split(*whitelistedContainerLabels, ",") // Trim spacing in labels for i := range whitelistedLabels { whitelistedLabels[i] = strings.TrimSpace(whitelistedLabels[i]) } containerLabelFunc = metrics.BaseContainerLabels(whitelistedLabels) } // Register Prometheus collector to gather information about containers, Go runtime, processes, and machine cadvisorhttp.RegisterPrometheusHandler(mux, resourceManager, *prometheusEndpoint, containerLabelFunc, includedMetrics) // Start the manager. if err := resourceManager.Start(); err != nil { klog.Fatalf("Failed to start manager: %v", err) } // Install signal handler. installSignalHandler(resourceManager) klog.V(1).Infof("Starting cAdvisor version: %s-%s on port %d", version.Info["version"], version.Info["revision"], *argPort) rootMux := http.NewServeMux() rootMux.Handle(*urlBasePrefix+"/", http.StripPrefix(*urlBasePrefix, mux)) addr := fmt.Sprintf("%s:%d", *argIP, *argPort) klog.Fatal(http.ListenAndServe(addr, rootMux)) } func setMaxProcs() { // TODO(vmarmol): Consider limiting if we have a CPU mask in effect. // Allow as many threads as we have cores unless the user specified a value. var numProcs int if *maxProcs < 1 { numProcs = runtime.NumCPU() } else { numProcs = *maxProcs } runtime.GOMAXPROCS(numProcs) // Check if the setting was successful. actualNumProcs := runtime.GOMAXPROCS(0) if actualNumProcs != numProcs { klog.Warningf("Specified max procs of %v but using %v", numProcs, actualNumProcs) } } func installSignalHandler(containerManager manager.Manager) { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) // Block until a signal is received. go func() { sig := <-c if err := containerManager.Stop(); err != nil { klog.Errorf("Failed to stop container manager: %v", err) } klog.Infof("Exiting given signal: %v", sig) os.Exit(0) }() } func createCollectorHTTPClient(collectorCert, collectorKey string) http.Client { //Enable accessing insecure endpoints. We should be able to access metrics from any endpoint tlsConfig := &tls.Config{ InsecureSkipVerify: true, } if collectorCert != "" { if collectorKey == "" { klog.Fatal("The collector_key value must be specified if the collector_cert value is set.") } cert, err := tls.LoadX509KeyPair(collectorCert, collectorKey) if err != nil { klog.Fatalf("Failed to use the collector certificate and key: %s", err) } tlsConfig.Certificates = []tls.Certificate{cert} tlsConfig.BuildNameToCertificate() //nolint: staticcheck } transport := &http.Transport{ TLSClientConfig: tlsConfig, } return http.Client{Transport: transport} } ================================================ FILE: cmd/cadvisor_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "flag" "testing" "github.com/stretchr/testify/assert" "github.com/google/cadvisor/container" ) func TestTcpMetricsAreDisabledByDefault(t *testing.T) { assert.True(t, ignoreMetrics.Has(container.NetworkTcpUsageMetrics)) flag.Parse() assert.True(t, ignoreMetrics.Has(container.NetworkTcpUsageMetrics)) } func TestAdvancedTcpMetricsAreDisabledByDefault(t *testing.T) { assert.True(t, ignoreMetrics.Has(container.NetworkAdvancedTcpUsageMetrics)) flag.Parse() assert.True(t, ignoreMetrics.Has(container.NetworkAdvancedTcpUsageMetrics)) } func TestUdpMetricsAreDisabledByDefault(t *testing.T) { assert.True(t, ignoreMetrics.Has(container.NetworkUdpUsageMetrics)) flag.Parse() assert.True(t, ignoreMetrics.Has(container.NetworkUdpUsageMetrics)) } func TestReferencedMemoryMetricsIsDisabledByDefault(t *testing.T) { assert.True(t, ignoreMetrics.Has(container.ReferencedMemoryMetrics)) flag.Parse() assert.True(t, ignoreMetrics.Has(container.ReferencedMemoryMetrics)) } func TestCPUTopologyMetricsAreDisabledByDefault(t *testing.T) { assert.True(t, ignoreMetrics.Has(container.CPUTopologyMetrics)) flag.Parse() assert.True(t, ignoreMetrics.Has(container.CPUTopologyMetrics)) } func TestMemoryNumaMetricsAreDisabledByDefault(t *testing.T) { assert.True(t, ignoreMetrics.Has(container.MemoryNumaMetrics)) flag.Parse() assert.True(t, ignoreMetrics.Has(container.MemoryNumaMetrics)) } func TestEnableAndIgnoreMetrics(t *testing.T) { tests := []struct { value string expected []container.MetricKind }{ {"", []container.MetricKind{}}, {"disk", []container.MetricKind{container.DiskUsageMetrics}}, {"disk,tcp,network", []container.MetricKind{container.DiskUsageMetrics, container.NetworkTcpUsageMetrics, container.NetworkUsageMetrics}}, } for _, test := range tests { for _, sets := range []container.MetricSet{enableMetrics, ignoreMetrics} { assert.NoError(t, sets.Set(test.value)) assert.Equal(t, len(test.expected), len(sets)) for _, expected := range test.expected { assert.True(t, sets.Has(expected), "Missing %s", expected) } } } } func TestToIncludedMetrics(t *testing.T) { ignores := []container.MetricSet{ { container.CpuUsageMetrics: struct{}{}, }, {}, container.AllMetrics, } expected := []container.MetricSet{ { container.ProcessSchedulerMetrics: struct{}{}, container.PerCpuUsageMetrics: struct{}{}, container.MemoryUsageMetrics: struct{}{}, container.MemoryNumaMetrics: struct{}{}, container.CpuLoadMetrics: struct{}{}, container.DiskIOMetrics: struct{}{}, container.DiskUsageMetrics: struct{}{}, container.NetworkUsageMetrics: struct{}{}, container.NetworkTcpUsageMetrics: struct{}{}, container.NetworkAdvancedTcpUsageMetrics: struct{}{}, container.NetworkUdpUsageMetrics: struct{}{}, container.ProcessMetrics: struct{}{}, container.AppMetrics: struct{}{}, container.HugetlbUsageMetrics: struct{}{}, container.PerfMetrics: struct{}{}, container.ReferencedMemoryMetrics: struct{}{}, container.CPUTopologyMetrics: struct{}{}, container.ResctrlMetrics: struct{}{}, container.CPUSetMetrics: struct{}{}, container.OOMMetrics: struct{}{}, container.PressureMetrics: struct{}{}, }, container.AllMetrics, {}, } for idx, ignore := range ignores { actual := container.AllMetrics.Difference(ignore) assert.Equal(t, actual, expected[idx]) } } ================================================ FILE: cmd/go.mod ================================================ module github.com/google/cadvisor/cmd go 1.24.0 // Record that the cmd module requires the cadvisor library module. // The github.com/google/cadvisor/cmd module is built using the Makefile // from a clone of the github.com/google/cadvisor repository, so we // always use the relative local source rather than specifying a module version. require github.com/google/cadvisor v0.0.0 // Use the relative local source of the github.com/google/cadvisor library to build replace github.com/google/cadvisor => ../ require ( github.com/SeanDolphin/bqschema v1.0.0 github.com/Shopify/sarama v1.38.1 github.com/abbot/go-http-auth v0.4.0 github.com/gomodule/redigo v1.9.2 github.com/influxdb/influxdb v1.7.9 github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.24.1 // indirect github.com/prometheus/client_golang v1.22.0 github.com/stretchr/testify v1.11.1 golang.org/x/oauth2 v0.30.0 google.golang.org/api v0.235.0 gopkg.in/olivere/elastic.v2 v2.0.61 k8s.io/klog/v2 v2.130.1 k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 ) require ( cloud.google.com/go/auth v0.16.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect github.com/aws/aws-sdk-go-v2/config v1.29.14 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.67 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect github.com/aws/smithy-go v1.22.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/containerd/api v1.10.0 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/ttrpc v1.2.7 // indirect github.com/containerd/typeurl/v2 v2.2.3 // indirect github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/cyphar/filepath-securejoin v0.6.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/eapache/go-resiliency v1.7.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/euank/go-kmsg-parser v2.0.0+incompatible // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.14.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/influxdata/influxdb v1.12.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/moby/api v1.52.0 // indirect github.com/moby/moby/client v0.2.1 // indirect github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/cgroups v0.0.6 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/opencontainers/runc v1.4.0 // indirect github.com/opencontainers/runtime-spec v1.3.0 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.64.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/stretchr/objx v0.5.2 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect go.opentelemetry.io/otel/metric v1.36.0 // indirect go.opentelemetry.io/otel/trace v1.36.0 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.39.0 // indirect golang.org/x/telemetry v0.0.0-20251215142616-e75fd47794af // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect google.golang.org/grpc v1.72.2 // indirect google.golang.org/protobuf v1.36.8 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ================================================ FILE: cmd/go.sum ================================================ cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU= cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/SeanDolphin/bqschema v1.0.0 h1:iCYFd5Qsw6caM2k5/SsITSL9+3kQCr+oz6pnNjWTq90= github.com/SeanDolphin/bqschema v1.0.0/go.mod h1:TYInVncsPIZH7kybQoIUNJ4pFX1cUc8LoP9RSOxIs6c= github.com/Shopify/sarama v1.38.1 h1:lqqPUPQZ7zPqYlWpTh+LQ9bhYNu2xJL6k1SJN4WVe2A= github.com/Shopify/sarama v1.38.1/go.mod h1:iwv9a67Ha8VNa+TifujYoWGxWnu2kNVAQdSdZ4X2o5g= github.com/Shopify/toxiproxy/v2 v2.5.0 h1:i4LPT+qrSlKNtQf5QliVjdP08GyAH8+BUIc9gT0eahc= github.com/Shopify/toxiproxy/v2 v2.5.0/go.mod h1:yhM2epWtAmel9CB8r2+L+PCmhH6yH2pITaPAo7jxJl0= github.com/abbot/go-http-auth v0.4.0 h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0= github.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/apache/arrow/go/v7 v7.0.1 h1:WpCfq+AQxvXaI6/KplHE27MPMFx5av0o5NbPCTAGfy4= github.com/apache/arrow/go/v7 v7.0.1/go.mod h1:JxDpochJbCVxqbX4G8i1jRqMrnTCQdf8pTccAfLD8Es= github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM= github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g= github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM= github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8= github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY= github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k= github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/benbjohnson/immutable v0.4.3 h1:GYHcksoJ9K6HyAUpGxwZURrbTkXA0Dh4otXGqbhdrjA= github.com/benbjohnson/immutable v0.4.3/go.mod h1:qJIKKSmdqz1tVzNtst1DZzvaqOU1onk1rc03IeM3Owk= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/containerd/containerd/api v1.10.0 h1:5n0oHYVBwN4VhoX9fFykCV9dF1/BvAXeg2F8W6UYq1o= github.com/containerd/containerd/api v1.10.0/go.mod h1:NBm1OAk8ZL+LG8R0ceObGxT5hbUYj7CzTmR3xh0DlMM= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRqQ= github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40= github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk= github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/euank/go-kmsg-parser v2.0.0+incompatible h1:cHD53+PLQuuQyLZeriD1V/esuG4MuU0Pjs5y6iknohY= github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s= github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/influxdata/flux v0.196.1 h1:RZypfrrAZeIixD/2As+qoyrwfs6Gx7VcnTRNGNjBfUA= github.com/influxdata/flux v0.196.1/go.mod h1:+Y4mBygx6q98onpdKJd6vJPrTNjHriQhwh/gM+3IvUQ= github.com/influxdata/influxdb v1.12.0 h1:hVFeHtEUh/MkI6YCmB1TAXlPgV4ZNh/V5FP6z7ywRLo= github.com/influxdata/influxdb v1.12.0/go.mod h1:11RjLuBNkuWaJQFViRF/rpNzICfU6X0nuO003yeleKY= github.com/influxdata/influxql v1.4.1 h1:UB+TMc9cB6mDdkPmH/5sBU8FQ+ZCWRX2JPcPDIFrLcs= github.com/influxdata/influxql v1.4.1/go.mod h1:VqxAKyQz5p8GzgGsxWalCWYGxEqw6kvJo2IickMQiQk= github.com/influxdb/influxdb v1.7.9 h1:KMBwwvyJyBppIwrg5t0662p+Yei/ucnIkqUl8txiQdQ= github.com/influxdb/influxdb v1.7.9/go.mod h1:GpjLgHRqWhDGlPAg7+Rj6NAYuzPojBM8XLG5Ouvvq+Q= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible h1:aKW/4cBs+yK6gpqU3K/oIwk9Q/XICqd3zOX/UFuvqmk= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg= github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc= github.com/moby/moby/client v0.2.1 h1:1Grh1552mvv6i+sYOdY+xKKVTvzJegcVMhuXocyDz/k= github.com/moby/moby/client v0.2.1/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= github.com/opencontainers/cgroups v0.0.6 h1:tfZFWTIIGaUUFImTyuTg+Mr5x8XRiSdZESgEBW7UxuI= github.com/opencontainers/cgroups v0.0.6/go.mod h1:oWVzJsKK0gG9SCRBfTpnn16WcGEqDI8PAcpMGbqWxcs= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/opencontainers/runc v1.4.0 h1:FG1Hw0GBYPsNki+mBz1QOrSzbwbAcerhrAD2r097QCc= github.com/opencontainers/runc v1.4.0/go.mod h1:sch3Bh3c1NlyAkALoAUz5Br9ubMLZzFcxuovZbnkErk= github.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg= github.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/uber/jaeger-client-go v2.28.0+incompatible h1:G4QSBfvPKvg5ZM2j9MrJFdfI5iSljY/WnJqOGFao6HI= github.com/uber/jaeger-client-go v2.28.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6 h1:YdYsPAZ2pC6Tow/nPZOPQ96O3hm/ToAkGsPLzedXERk= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM= golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20251215142616-e75fd47794af h1:JLNgZmN0uDGV+zlgKknvmvX9+atzn9b7S6M1L6J5tQs= golang.org/x/telemetry v0.0.0-20251215142616-e75fd47794af/go.mod h1:ArQvPJS723nJQietgilmZA+shuB3CZxH1n2iXq9VSfs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.235.0 h1:C3MkpQSRxS1Jy6AkzTGKKrpSCOd2WOGrezZ+icKSkKo= google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78= google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0= google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/olivere/elastic.v2 v2.0.61 h1:7cpl3MW8ysa4GYFBXklpo5mspe4NK0rpZTdyZ+QcD4U= gopkg.in/olivere/elastic.v2 v2.0.61/go.mod h1:CTVyl1gckiFw1aLZYxC00g3f9jnHmhoOKcWF7W3c6n4= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97RvvF3a8J3fP/Lg= k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= ================================================ FILE: cmd/internal/api/handler.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package api provides a handler for /api/ package api import ( "encoding/json" "errors" "fmt" "io" "net/http" "path" "regexp" "sort" "strconv" "strings" "time" httpmux "github.com/google/cadvisor/cmd/internal/http/mux" "github.com/google/cadvisor/events" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/manager" "k8s.io/klog/v2" ) const ( apiResource = "/api/" ) func RegisterHandlers(mux httpmux.Mux, m manager.Manager) error { apiVersions := getAPIVersions() supportedAPIVersions := make(map[string]ApiVersion, len(apiVersions)) for _, v := range apiVersions { supportedAPIVersions[v.Version()] = v } mux.HandleFunc(apiResource, func(w http.ResponseWriter, r *http.Request) { err := handleRequest(supportedAPIVersions, m, w, r) if err != nil { http.Error(w, err.Error(), 500) } }) return nil } // Captures the API version, requestType [optional], and remaining request [optional]. var apiRegexp = regexp.MustCompile(`/api/([^/]+)/?([^/]+)?(.*)`) const ( apiVersion = iota + 1 apiRequestType apiRequestArgs ) func handleRequest(supportedAPIVersions map[string]ApiVersion, m manager.Manager, w http.ResponseWriter, r *http.Request) error { start := time.Now() defer func() { klog.V(4).Infof("Request took %s", time.Since(start)) }() request := r.URL.Path const apiPrefix = "/api" if !strings.HasPrefix(request, apiPrefix) { return fmt.Errorf("incomplete API request %q", request) } // If the request doesn't have an API version, list those. if request == apiPrefix || request == apiResource { versions := make([]string, 0, len(supportedAPIVersions)) for v := range supportedAPIVersions { versions = append(versions, v) } sort.Strings(versions) http.Error(w, fmt.Sprintf("Supported API versions: %s", strings.Join(versions, ",")), http.StatusBadRequest) return nil } // Verify that we have all the elements we expect: // //[/] requestElements := apiRegexp.FindStringSubmatch(request) if len(requestElements) == 0 { return fmt.Errorf("malformed request %q", request) } version := requestElements[apiVersion] requestType := requestElements[apiRequestType] requestArgs := strings.Split(requestElements[apiRequestArgs], "/") // Check supported versions. versionHandler, ok := supportedAPIVersions[version] if !ok { return fmt.Errorf("unsupported API version %q", version) } // If no request type, list possible request types. if requestType == "" { requestTypes := versionHandler.SupportedRequestTypes() sort.Strings(requestTypes) http.Error(w, fmt.Sprintf("Supported request types: %q", strings.Join(requestTypes, ",")), http.StatusBadRequest) return nil } // Trim the first empty element from the request. if len(requestArgs) > 0 && requestArgs[0] == "" { requestArgs = requestArgs[1:] } return versionHandler.HandleRequest(requestType, requestArgs, m, w, r) } func writeResult(res interface{}, w http.ResponseWriter) error { out, err := json.Marshal(res) if err != nil { return fmt.Errorf("failed to marshall response %+v with error: %s", res, err) } w.Header().Set("Content-Type", "application/json") _, err = w.Write(out) return err } func streamResults(eventChannel *events.EventChannel, w http.ResponseWriter, r *http.Request, m manager.Manager) error { flusher, ok := w.(http.Flusher) if !ok { return errors.New("could not access http.Flusher") } w.Header().Set("Transfer-Encoding", "chunked") w.WriteHeader(http.StatusOK) flusher.Flush() enc := json.NewEncoder(w) for { select { case <-r.Context().Done(): m.CloseEventChannel(eventChannel.GetWatchId()) return nil case ev := <-eventChannel.GetChannel(): err := enc.Encode(ev) if err != nil { klog.Errorf("error encoding message %+v for result stream: %v", ev, err) } flusher.Flush() } } } func getContainerInfoRequest(body io.ReadCloser) (*info.ContainerInfoRequest, error) { query := info.DefaultContainerInfoRequest() decoder := json.NewDecoder(body) err := decoder.Decode(&query) if err != nil && err != io.EOF { return nil, fmt.Errorf("unable to decode the json value: %s", err) } return &query, nil } // The user can set any or none of the following arguments in any order // with any twice defined arguments being assigned the first value. // If the value type for the argument is wrong the field will be assumed to be // unassigned // bools: stream, subcontainers, oom_events, creation_events, deletion_events // ints: max_events, start_time (unix timestamp), end_time (unix timestamp) // example r.URL: http://localhost:8080/api/v1.3/events?oom_events=true&stream=true func getEventRequest(r *http.Request) (*events.Request, bool, error) { query := events.NewRequest() stream := false urlMap := r.URL.Query() if val, ok := urlMap["stream"]; ok { newBool, err := strconv.ParseBool(val[0]) if err == nil { stream = newBool } } if val, ok := urlMap["subcontainers"]; ok { newBool, err := strconv.ParseBool(val[0]) if err == nil { query.IncludeSubcontainers = newBool } } eventTypes := map[string]info.EventType{ "oom_events": info.EventOom, "oom_kill_events": info.EventOomKill, "creation_events": info.EventContainerCreation, "deletion_events": info.EventContainerDeletion, } allEventTypes := false if val, ok := urlMap["all_events"]; ok { newBool, err := strconv.ParseBool(val[0]) if err == nil { allEventTypes = newBool } } for opt, eventType := range eventTypes { if allEventTypes { query.EventType[eventType] = true } else if val, ok := urlMap[opt]; ok { newBool, err := strconv.ParseBool(val[0]) if err == nil { query.EventType[eventType] = newBool } } } if val, ok := urlMap["max_events"]; ok { newInt, err := strconv.Atoi(val[0]) if err == nil { query.MaxEventsReturned = int(newInt) } } if val, ok := urlMap["start_time"]; ok { newTime, err := time.Parse(time.RFC3339, val[0]) if err == nil { query.StartTime = newTime } } if val, ok := urlMap["end_time"]; ok { newTime, err := time.Parse(time.RFC3339, val[0]) if err == nil { query.EndTime = newTime } } return query, stream, nil } func getContainerName(request []string) string { return path.Join("/", strings.Join(request, "/")) } ================================================ FILE: cmd/internal/api/versions.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package api import ( "fmt" "net/http" "path" "strconv" "time" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" "github.com/google/cadvisor/manager" "k8s.io/klog/v2" ) const ( containersAPI = "containers" subcontainersAPI = "subcontainers" machineAPI = "machine" machineStatsAPI = "machinestats" dockerAPI = "docker" summaryAPI = "summary" statsAPI = "stats" specAPI = "spec" eventsAPI = "events" storageAPI = "storage" attributesAPI = "attributes" versionAPI = "version" psAPI = "ps" customMetricsAPI = "appmetrics" ) // Interface for a cAdvisor API version type ApiVersion interface { // Returns the version string. Version() string // List of supported API endpoints. SupportedRequestTypes() []string // Handles a request. The second argument is the parameters after /api// HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error } // Gets all supported API versions. func getAPIVersions() []ApiVersion { v1_0 := &version1_0{} v1_1 := newVersion1_1(v1_0) v1_2 := newVersion1_2(v1_1) v1_3 := newVersion1_3(v1_2) v2_0 := newVersion2_0() v2_1 := newVersion2_1(v2_0) return []ApiVersion{v1_0, v1_1, v1_2, v1_3, v2_0, v2_1} } // API v1.0 type version1_0 struct { } func (api *version1_0) Version() string { return "v1.0" } func (api *version1_0) SupportedRequestTypes() []string { return []string{containersAPI, machineAPI} } func (api *version1_0) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { switch requestType { case machineAPI: klog.V(4).Infof("Api - Machine") // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { return err } err = writeResult(machineInfo, w) if err != nil { return err } case containersAPI: containerName := getContainerName(request) klog.V(4).Infof("Api - Container(%s)", containerName) // Get the query request. query, err := getContainerInfoRequest(r.Body) if err != nil { return err } // Get the container. cont, err := m.GetContainerInfo(containerName, query) if err != nil { return fmt.Errorf("failed to get container %q with error: %s", containerName, err) } // Only output the container as JSON. err = writeResult(cont, w) if err != nil { return err } default: return fmt.Errorf("unknown request type %q", requestType) } return nil } // API v1.1 type version1_1 struct { baseVersion *version1_0 } // v1.1 builds on v1.0. func newVersion1_1(v *version1_0) *version1_1 { return &version1_1{ baseVersion: v, } } func (api *version1_1) Version() string { return "v1.1" } func (api *version1_1) SupportedRequestTypes() []string { return append(api.baseVersion.SupportedRequestTypes(), subcontainersAPI) } func (api *version1_1) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { switch requestType { case subcontainersAPI: containerName := getContainerName(request) klog.V(4).Infof("Api - Subcontainers(%s)", containerName) // Get the query request. query, err := getContainerInfoRequest(r.Body) if err != nil { return err } // Get the subcontainers. containers, err := m.SubcontainersInfo(containerName, query) if err != nil { return fmt.Errorf("failed to get subcontainers for container %q with error: %s", containerName, err) } // Only output the containers as JSON. err = writeResult(containers, w) if err != nil { return err } return nil default: return api.baseVersion.HandleRequest(requestType, request, m, w, r) } } // API v1.2 type version1_2 struct { baseVersion *version1_1 } // v1.2 builds on v1.1. func newVersion1_2(v *version1_1) *version1_2 { return &version1_2{ baseVersion: v, } } func (api *version1_2) Version() string { return "v1.2" } func (api *version1_2) SupportedRequestTypes() []string { return append(api.baseVersion.SupportedRequestTypes(), dockerAPI) } func (api *version1_2) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { switch requestType { case dockerAPI: klog.V(4).Infof("Api - Docker(%v)", request) // Get the query request. query, err := getContainerInfoRequest(r.Body) if err != nil { return err } var containers map[string]info.ContainerInfo // map requests for "docker/" to "docker" if len(request) == 1 && len(request[0]) == 0 { request = request[:0] } switch len(request) { case 0: // Get all Docker containers. containers, err = m.AllDockerContainers(query) if err != nil { return fmt.Errorf("failed to get all Docker containers with error: %v", err) } case 1: // Get one Docker container. var cont info.ContainerInfo cont, err = m.DockerContainer(request[0], query) if err != nil { return fmt.Errorf("failed to get Docker container %q with error: %v", request[0], err) } containers = map[string]info.ContainerInfo{ cont.Name: cont, } default: return fmt.Errorf("unknown request for Docker container %v", request) } // Only output the containers as JSON. err = writeResult(containers, w) if err != nil { return err } return nil default: return api.baseVersion.HandleRequest(requestType, request, m, w, r) } } // API v1.3 type version1_3 struct { baseVersion *version1_2 } // v1.3 builds on v1.2. func newVersion1_3(v *version1_2) *version1_3 { return &version1_3{ baseVersion: v, } } func (api *version1_3) Version() string { return "v1.3" } func (api *version1_3) SupportedRequestTypes() []string { return append(api.baseVersion.SupportedRequestTypes(), eventsAPI) } func (api *version1_3) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { switch requestType { case eventsAPI: return handleEventRequest(request, m, w, r) default: return api.baseVersion.HandleRequest(requestType, request, m, w, r) } } func handleEventRequest(request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { query, stream, err := getEventRequest(r) if err != nil { return err } query.ContainerName = path.Join("/", getContainerName(request)) klog.V(4).Infof("Api - Events(%v)", query) if !stream { pastEvents, err := m.GetPastEvents(query) if err != nil { return err } return writeResult(pastEvents, w) } eventChannel, err := m.WatchForEvents(query) if err != nil { return err } return streamResults(eventChannel, w, r, m) } // API v2.0 type version2_0 struct { } func newVersion2_0() *version2_0 { return &version2_0{} } func (api *version2_0) Version() string { return "v2.0" } func (api *version2_0) SupportedRequestTypes() []string { return []string{versionAPI, attributesAPI, eventsAPI, machineAPI, summaryAPI, statsAPI, specAPI, storageAPI, psAPI, customMetricsAPI} } func (api *version2_0) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { opt, err := GetRequestOptions(r) if err != nil { return err } switch requestType { case versionAPI: klog.V(4).Infof("Api - Version") versionInfo, err := m.GetVersionInfo() if err != nil { return err } return writeResult(versionInfo.CadvisorVersion, w) case attributesAPI: klog.V(4).Info("Api - Attributes") machineInfo, err := m.GetMachineInfo() if err != nil { return err } versionInfo, err := m.GetVersionInfo() if err != nil { return err } info := v2.GetAttributes(machineInfo, versionInfo) return writeResult(info, w) case machineAPI: klog.V(4).Info("Api - Machine") // TODO(rjnagal): Move machineInfo from v1. machineInfo, err := m.GetMachineInfo() if err != nil { return err } return writeResult(machineInfo, w) case summaryAPI: containerName := getContainerName(request) klog.V(4).Infof("Api - Summary for container %q, options %+v", containerName, opt) stats, err := m.GetDerivedStats(containerName, opt) if err != nil { return err } return writeResult(stats, w) case statsAPI: name := getContainerName(request) klog.V(4).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, opt) infos, err := m.GetRequestedContainersInfo(name, opt) if err != nil { if len(infos) == 0 { return err } klog.Errorf("Error calling GetRequestedContainersInfo: %v", err) } contStats := make(map[string][]v2.DeprecatedContainerStats) for name, cinfo := range infos { contStats[name] = v2.DeprecatedStatsFromV1(cinfo) } return writeResult(contStats, w) case customMetricsAPI: containerName := getContainerName(request) klog.V(4).Infof("Api - Custom Metrics: Looking for metrics for container %q, options %+v", containerName, opt) infos, err := m.GetContainerInfoV2(containerName, opt) if err != nil { return err } contMetrics := make(map[string]map[string]map[string][]info.MetricValBasic) for _, cinfo := range infos { metrics := make(map[string]map[string][]info.MetricValBasic) for _, contStat := range cinfo.Stats { if len(contStat.CustomMetrics) == 0 { continue } for name, allLabels := range contStat.CustomMetrics { metricLabels := make(map[string][]info.MetricValBasic) for _, metric := range allLabels { if !metric.Timestamp.IsZero() { metVal := info.MetricValBasic{ Timestamp: metric.Timestamp, IntValue: metric.IntValue, FloatValue: metric.FloatValue, } labels := metrics[name] if labels != nil { values := labels[metric.Label] values = append(values, metVal) labels[metric.Label] = values metrics[name] = labels } else { metricLabels[metric.Label] = []info.MetricValBasic{metVal} metrics[name] = metricLabels } } } } } contMetrics[containerName] = metrics } return writeResult(contMetrics, w) case specAPI: containerName := getContainerName(request) klog.V(4).Infof("Api - Spec for container %q, options %+v", containerName, opt) specs, err := m.GetContainerSpec(containerName, opt) if err != nil { return err } return writeResult(specs, w) case storageAPI: label := r.URL.Query().Get("label") uuid := r.URL.Query().Get("uuid") switch { case uuid != "": fi, err := m.GetFsInfoByFsUUID(uuid) if err != nil { return err } return writeResult(fi, w) case label != "": // Get a specific label. fi, err := m.GetFsInfo(label) if err != nil { return err } return writeResult(fi, w) default: // Get all global filesystems info. fi, err := m.GetFsInfo("") if err != nil { return err } return writeResult(fi, w) } case eventsAPI: return handleEventRequest(request, m, w, r) case psAPI: // reuse container type from request. // ignore recursive. // TODO(rjnagal): consider count to limit ps output. name := getContainerName(request) klog.V(4).Infof("Api - Spec for container %q, options %+v", name, opt) ps, err := m.GetProcessList(name, opt) if err != nil { return fmt.Errorf("process listing failed: %v", err) } return writeResult(ps, w) default: return fmt.Errorf("unknown request type %q", requestType) } } type version2_1 struct { baseVersion *version2_0 } func newVersion2_1(v *version2_0) *version2_1 { return &version2_1{ baseVersion: v, } } func (api *version2_1) Version() string { return "v2.1" } func (api *version2_1) SupportedRequestTypes() []string { return append([]string{machineStatsAPI}, api.baseVersion.SupportedRequestTypes()...) } func (api *version2_1) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error { // Get the query request. opt, err := GetRequestOptions(r) if err != nil { return err } switch requestType { case machineStatsAPI: klog.V(4).Infof("Api - MachineStats(%v)", request) cont, err := m.GetRequestedContainersInfo("/", opt) if err != nil { if len(cont) == 0 { return err } klog.Errorf("Error calling GetRequestedContainersInfo: %v", err) } return writeResult(v2.MachineStatsFromV1(cont["/"]), w) case statsAPI: name := getContainerName(request) klog.V(4).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, opt) conts, err := m.GetRequestedContainersInfo(name, opt) if err != nil { if len(conts) == 0 { return err } klog.Errorf("Error calling GetRequestedContainersInfo: %v", err) } contStats := make(map[string]v2.ContainerInfo, len(conts)) for name, cont := range conts { if name == "/" { // Root cgroup stats should be exposed as machine stats continue } contStats[name] = v2.ContainerInfo{ Spec: v2.ContainerSpecFromV1(&cont.Spec, cont.Aliases, cont.Namespace), Stats: v2.ContainerStatsFromV1(name, &cont.Spec, cont.Stats), } } return writeResult(contStats, w) default: return api.baseVersion.HandleRequest(requestType, request, m, w, r) } } // GetRequestOptions returns the metrics request options from a HTTP request. func GetRequestOptions(r *http.Request) (v2.RequestOptions, error) { supportedTypes := map[string]bool{ v2.TypeName: true, v2.TypeDocker: true, v2.TypePodman: true, } // fill in the defaults. opt := v2.RequestOptions{ IdType: v2.TypeName, Count: 64, Recursive: false, } idType := r.URL.Query().Get("type") if len(idType) != 0 { if !supportedTypes[idType] { return opt, fmt.Errorf("unknown 'type' %q", idType) } opt.IdType = idType } count := r.URL.Query().Get("count") if len(count) != 0 { n, err := strconv.Atoi(count) if err != nil { return opt, fmt.Errorf("failed to parse 'count' option: %v", count) } if n < -1 { return opt, fmt.Errorf("invalid 'count' option: only -1 and larger values allowed, not %d", n) } opt.Count = n } recursive := r.URL.Query().Get("recursive") if recursive == "true" { opt.Recursive = true } if maxAgeString := r.URL.Query().Get("max_age"); len(maxAgeString) > 0 { maxAge, err := time.ParseDuration(maxAgeString) if err != nil { return opt, fmt.Errorf("failed to parse 'max_age' option: %v", err) } opt.MaxAge = &maxAge } return opt, nil } ================================================ FILE: cmd/internal/api/versions_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package api import ( "io" "net/http" "reflect" "testing" "github.com/google/cadvisor/events" info "github.com/google/cadvisor/info/v1" "github.com/stretchr/testify/assert" ) // returns an http.Request pointer for an input url test string func makeHTTPRequest(requestURL string, t *testing.T) *http.Request { dummyReader, _ := io.Pipe() r, err := http.NewRequest("GET", requestURL, dummyReader) assert.Nil(t, err) return r } func TestGetEventRequestBasicRequest(t *testing.T) { r := makeHTTPRequest("http://localhost:8080/api/v1.3/events?oom_events=true&stream=false&max_events=20", t) expectedQuery := events.NewRequest() expectedQuery.EventType = map[info.EventType]bool{ info.EventOom: true, } expectedQuery.MaxEventsReturned = 20 receivedQuery, stream, err := getEventRequest(r) if !reflect.DeepEqual(expectedQuery, receivedQuery) { t.Errorf("expected %#v but received %#v", expectedQuery, receivedQuery) } assert.False(t, stream) assert.Nil(t, err) } func TestGetEventEmptyRequest(t *testing.T) { r := makeHTTPRequest("", t) expectedQuery := events.NewRequest() receivedQuery, stream, err := getEventRequest(r) if !reflect.DeepEqual(expectedQuery, receivedQuery) { t.Errorf("expected %#v but received %#v", expectedQuery, receivedQuery) } assert.False(t, stream) assert.Nil(t, err) } func TestGetEventRequestDoubleArgument(t *testing.T) { r := makeHTTPRequest("http://localhost:8080/api/v1.3/events?stream=true&oom_events=true&oom_events=false", t) expectedQuery := events.NewRequest() expectedQuery.EventType = map[info.EventType]bool{ info.EventOom: true, } receivedQuery, stream, err := getEventRequest(r) if !reflect.DeepEqual(expectedQuery, receivedQuery) { t.Errorf("expected %#v but received %#v", expectedQuery, receivedQuery) } assert.True(t, stream) assert.Nil(t, err) } ================================================ FILE: cmd/internal/container/install/install.go ================================================ // Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // The install package registers all included container providers when imported package install import ( // Register all included container providers. _ "github.com/google/cadvisor/container/containerd/install" _ "github.com/google/cadvisor/container/crio/install" _ "github.com/google/cadvisor/container/docker/install" _ "github.com/google/cadvisor/container/podman/install" _ "github.com/google/cadvisor/container/systemd/install" // Register all filesystem plugins. _ "github.com/google/cadvisor/fs/btrfs/install" _ "github.com/google/cadvisor/fs/devicemapper/install" _ "github.com/google/cadvisor/fs/nfs/install" _ "github.com/google/cadvisor/fs/overlay/install" _ "github.com/google/cadvisor/fs/tmpfs/install" _ "github.com/google/cadvisor/fs/vfs/install" _ "github.com/google/cadvisor/fs/zfs/install" ) ================================================ FILE: cmd/internal/healthz/healthz.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package healthz import ( "net/http" httpmux "github.com/google/cadvisor/cmd/internal/http/mux" ) func handleHealthz(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("ok")) } // Register simple HTTP /healthz handler to return "ok". func RegisterHandler(mux httpmux.Mux) error { mux.HandleFunc("/healthz", handleHealthz) return nil } ================================================ FILE: cmd/internal/http/handlers.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package http import ( "fmt" "net/http" "github.com/google/cadvisor/cmd/internal/api" "github.com/google/cadvisor/cmd/internal/healthz" httpmux "github.com/google/cadvisor/cmd/internal/http/mux" "github.com/google/cadvisor/cmd/internal/pages" "github.com/google/cadvisor/cmd/internal/pages/static" "github.com/google/cadvisor/container" "github.com/google/cadvisor/manager" "github.com/google/cadvisor/metrics" "github.com/google/cadvisor/validate" auth "github.com/abbot/go-http-auth" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" "k8s.io/klog/v2" "k8s.io/utils/clock" ) func RegisterHandlers(mux httpmux.Mux, containerManager manager.Manager, httpAuthFile, httpAuthRealm, httpDigestFile, httpDigestRealm string, urlBasePrefix string) error { // Basic health handler. if err := healthz.RegisterHandler(mux); err != nil { return fmt.Errorf("failed to register healthz handler: %s", err) } // Validation/Debug handler. mux.HandleFunc(validate.ValidatePage, func(w http.ResponseWriter, r *http.Request) { err := validate.HandleRequest(w, containerManager) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }) // Register API handler. if err := api.RegisterHandlers(mux, containerManager); err != nil { return fmt.Errorf("failed to register API handlers: %s", err) } // Redirect / to containers page. mux.Handle("/", http.RedirectHandler(urlBasePrefix+pages.ContainersPage, http.StatusTemporaryRedirect)) var authenticated bool // Setup the authenticator object if httpAuthFile != "" { klog.V(1).Infof("Using auth file %s", httpAuthFile) secrets := auth.HtpasswdFileProvider(httpAuthFile) authenticator := auth.NewBasicAuthenticator(httpAuthRealm, secrets) mux.HandleFunc(static.StaticResource, authenticator.Wrap(staticHandler)) if err := pages.RegisterHandlersBasic(mux, containerManager, authenticator, urlBasePrefix); err != nil { return fmt.Errorf("failed to register pages auth handlers: %s", err) } authenticated = true } if httpAuthFile == "" && httpDigestFile != "" { klog.V(1).Infof("Using digest file %s", httpDigestFile) secrets := auth.HtdigestFileProvider(httpDigestFile) authenticator := auth.NewDigestAuthenticator(httpDigestRealm, secrets) mux.HandleFunc(static.StaticResource, authenticator.Wrap(staticHandler)) if err := pages.RegisterHandlersDigest(mux, containerManager, authenticator, urlBasePrefix); err != nil { return fmt.Errorf("failed to register pages digest handlers: %s", err) } authenticated = true } // Change handler based on authenticator initialization if !authenticated { mux.HandleFunc(static.StaticResource, staticHandlerNoAuth) if err := pages.RegisterHandlersBasic(mux, containerManager, nil, urlBasePrefix); err != nil { return fmt.Errorf("failed to register pages handlers: %s", err) } } return nil } // RegisterPrometheusHandler creates a new PrometheusCollector and configures // the provided HTTP mux to handle the given Prometheus endpoint. func RegisterPrometheusHandler(mux httpmux.Mux, resourceManager manager.Manager, prometheusEndpoint string, f metrics.ContainerLabelsFunc, includedMetrics container.MetricSet) { goCollector := collectors.NewGoCollector() processCollector := collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}) machineCollector := metrics.NewPrometheusMachineCollector(resourceManager, includedMetrics) mux.Handle(prometheusEndpoint, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { opts, err := api.GetRequestOptions(req) if err != nil { http.Error(w, "No metrics gathered, last error:\n\n"+err.Error(), http.StatusInternalServerError) return } opts.Count = 1 // we only want the latest datapoint opts.Recursive = true // get all child containers r := prometheus.NewRegistry() r.MustRegister( metrics.NewPrometheusCollector(resourceManager, f, includedMetrics, clock.RealClock{}, opts), machineCollector, goCollector, processCollector, ) promhttp.HandlerFor(r, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError}).ServeHTTP(w, req) })) } func staticHandlerNoAuth(w http.ResponseWriter, r *http.Request) { static.HandleRequest(w, r.URL) } func staticHandler(w http.ResponseWriter, r *auth.AuthenticatedRequest) { static.HandleRequest(w, r.URL) } ================================================ FILE: cmd/internal/http/mux/mux.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package mux import ( "net/http" ) // Mux interface expected by cAdvisor components. type Mux interface { HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) Handler(r *http.Request) (http.Handler, string) Handle(pattern string, handler http.Handler) } ================================================ FILE: cmd/internal/pages/assets/html/containers.html ================================================ cAdvisor - {{.DisplayName}}
{{if .IsRoot}} {{end}} {{if .Subcontainers}}
{{range $subcontainer := .Subcontainers}} {{$subcontainer.Text}} {{end}}
{{end}} {{if .DockerStatus}}
    {{range $dockerstatus := .DockerStatus}}
  • {{$dockerstatus.Key}} {{$dockerstatus.Value}}
  • {{end}} {{if .DockerDriverStatus}}
  • Storage
      {{range $driverstatus := .DockerDriverStatus}}
    • {{$driverstatus.Key}} {{$driverstatus.Value}}
    • {{end}}
{{end}}
{{end}} {{if .DockerImages}}


{{end}} {{if .ResourcesAvailable}}
{{if .CpuAvailable}}
  • CPU
  • {{if .Spec.Cpu.Limit}}
  • Shares {{printShares .Spec.Cpu.Limit}} shares
  • {{end}} {{if .Spec.Cpu.MaxLimit}}
  • Max Limit {{printCores .Spec.Cpu.MaxLimit}} cores
  • {{end}} {{if .Spec.Cpu.Mask}}
  • Allowed Cores {{printMask .Spec.Cpu.Mask .MachineInfo.NumCores}}
  • {{end}}
{{end}} {{if .MemoryAvailable}}
  • Memory
  • {{if .Spec.Memory.Reservation}}
  • Reservation {{printSize .Spec.Memory.Reservation}} {{printUnit .Spec.Memory.Reservation}}
  • {{end}} {{if .Spec.Memory.Limit}}
  • Limit {{printSize .Spec.Memory.Limit}} {{printUnit .Spec.Memory.Limit}}
  • {{end}} {{if .Spec.Memory.SwapLimit}}
  • Swap Limit {{printSize .Spec.Memory.SwapLimit}} {{printUnit .Spec.Memory.SwapLimit}}
  • {{end}}
{{end}}

Overview

Processes

{{if .CpuAvailable}}

CPU

Total Usage

Usage per Core

Usage Breakdown

{{end}} {{if .MemoryAvailable}}

Memory

Total Usage


Usage Breakdown

Hot Memory
Cold Memory
{{end}} {{if .NetworkAvailable}}

Network

Throughput

Errors

{{end}} {{if .FsAvailable}}

Filesystem

{{end}} {{if .CustomMetricsAvailable}}

Application Metrics

{{end}} {{if .SubcontainersAvailable}}

Subcontainers

Top CPU Usage:

Top Memory Usage:

{{end}}
{{end}}
================================================ FILE: cmd/internal/pages/assets/js/containers.js ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. google.charts.load('current', {packages: ['corechart', 'gauge', 'default', 'format', 'ui', 'table']}); function humanize(num, size, units) { var unit; for (unit = units.pop(); units.length && num >= size; unit = units.pop()) { num /= size; } return [num, unit]; } // Following the IEC naming convention function humanizeIEC(num) { var ret = humanize(num, 1024, ['TiB', 'GiB', 'MiB', 'KiB', 'B']); return ret[0].toFixed(2) + ' ' + ret[1]; } // Following the Metric naming convention function humanizeMetric(num) { var ret = humanize(num, 1000, ['TB', 'GB', 'MB', 'KB', 'Bytes']); return ret[0].toFixed(2) + ' ' + ret[1]; } // Draw a table. function drawTable( seriesTitles, titleTypes, data, elementId, numPages, sortIndex) { var dataTable = new google.visualization.DataTable(); for (var i = 0; i < seriesTitles.length; i++) { dataTable.addColumn(titleTypes[i], seriesTitles[i]); } dataTable.addRows(data); if (!(elementId in window.charts)) { window.charts[elementId] = new google.visualization.Table(document.getElementById(elementId)); } var cssClassNames = { 'headerRow': '', 'tableRow': 'table-row', 'oddTableRow': 'table-row' }; var opts = { alternatingRowStyle: true, page: 'enable', pageSize: numPages, allowHtml: true, sortColumn: sortIndex, sortAscending: false, cssClassNames: cssClassNames }; window.charts[elementId].draw(dataTable, opts); } // Draw a line chart. function drawLineChart(seriesTitles, data, elementId, unit) { var min = Infinity; var max = -Infinity; for (var i = 0; i < data.length; i++) { // Convert the first column to a Date. if (data[i] != null) { data[i][0] = new Date(data[i][0]); } // Find min, max. for (var j = 1; j < data[i].length; j++) { var val = data[i][j]; if (val < min) { min = val; } if (val > max) { max = val; } } } // We don't want to show any values less than 0 so cap the min value at that. // At the same time, show 10% of the graph below the min value if we can. var minWindow = min - (max - min) / 10; if (minWindow < 0) { minWindow = 0; } // Add the definition of each column and the necessary data. var dataTable = new google.visualization.DataTable(); dataTable.addColumn('datetime', seriesTitles[0]); for (var i = 1; i < seriesTitles.length; i++) { dataTable.addColumn('number', seriesTitles[i]); } dataTable.addRows(data); // Create and draw the visualization. if (!(elementId in window.charts)) { window.charts[elementId] = new google.visualization.LineChart(document.getElementById(elementId)); } // TODO(vmarmol): Look into changing the view window to get a smoother // animation. var opts = { curveType: 'function', height: 300, legend: {position: 'none'}, focusTarget: 'category', vAxis: { title: unit, viewWindow: { min: minWindow, } }, legend: { position: 'bottom' } }; // If the whole data series has the same value, try to center it in the chart. if (min == max) { opts.vAxis.viewWindow.max = 1.1 * max; opts.vAxis.viewWindow.min = 0.9 * max; } window.charts[elementId].draw(dataTable, opts); } // Gets the length of the interval in nanoseconds. function getInterval(current, previous) { var cur = new Date(current); var prev = new Date(previous); // ms -> ns. return (cur.getTime() - prev.getTime()) * 1000000; } // Checks if the specified stats include the specified resource. function hasResource(stats, resource) { return stats.stats.length > 0 && stats.stats[0][resource]; } // Checks if all containers in provided list include the specified resource. function hasResourceForAll(containerInfos, resource) { if (containerInfos.length === 0) { return false; } for (var i = 0; i < containerInfos.length; i++) { if (!hasResource(containerInfos[i], resource)) { return false; } } return true; } // Draw a set of gauges. Data is comprised of an array of arrays with two // elements: // a string label and a numeric value for the gauge. function drawGauges(elementId, gauges) { gauges.unshift(['Label', 'Value']); // Create and populate the data table. var data = google.visualization.arrayToDataTable(gauges); // Create and draw the visualization. var options = { height: 100, redFrom: 90, redTo: 100, yellowFrom: 75, yellowTo: 90, minorTicks: 5, animation: {duration: 900, easing: 'linear'} }; var chart = new google.visualization.Gauge(document.getElementById(elementId)); chart.draw(data, options); } // Get the machine info. function getMachineInfo(rootDir, callback) { $.getJSON(rootDir + 'api/v1.0/machine', function(data) { callback(data); }); } // Get ps info. function getProcessInfo(rootDir, containerName, callback) { $.getJSON(rootDir + 'api/v2.0/ps' + containerName) .done(function(data) { callback(data); }) .fail(function(jqhxr, textStatus, error) { callback([]); }); } // Get the container stats for the specified container. function getStats(rootDir, containerName, callback) { // Request 60s of container history and no samples. var request = JSON.stringify({ // Update main.statsRequestedByUI while updating "num_stats" here. 'num_stats': 60, 'num_samples': 0 }); $.when( $.post(rootDir + 'api/v1.0/containers' + containerName, request), $.post(rootDir + 'api/v1.1/subcontainers' + containerName, request)) .done(function(containersResp, subcontainersResp) { callback(containersResp[0], subcontainersResp[0]); }); } // Draw the graph for CPU usage. function drawCpuTotalUsage(elementId, machineInfo, stats) { if (stats.spec.has_cpu && !hasResource(stats, 'cpu')) { return; } var titles = ['Time', 'Total']; var data = []; for (var i = 1; i < stats.stats.length; i++) { var cur = stats.stats[i]; var prev = stats.stats[i - 1]; var intervalNs = getInterval(cur.timestamp, prev.timestamp); var elements = []; elements.push(cur.timestamp); elements.push((cur.cpu.usage.total - prev.cpu.usage.total) / intervalNs); data.push(elements); } drawLineChart(titles, data, elementId, 'Cores'); } // Draw the graph for CPU load. function drawCpuLoad(elementId, machineInfo, stats) { var titles = ['Time', 'Average']; var data = []; for (var i = 1; i < stats.stats.length; i++) { var cur = stats.stats[i]; var elements = []; elements.push(cur.timestamp); elements.push(cur.cpu.load_average / 1000); data.push(elements); } drawLineChart(titles, data, elementId, 'Runnable threads'); } // Draw the graph for per-core CPU usage. function drawCpuPerCoreUsage(elementId, machineInfo, stats) { if (stats.spec.has_cpu && !hasResource(stats, 'cpu')) { return; } // Add a title for each core. var titles = ['Time']; for (var i = 0; i < machineInfo.num_cores; i++) { titles.push('Core ' + i); } var data = []; for (var i = 1; i < stats.stats.length; i++) { var cur = stats.stats[i]; var prev = stats.stats[i - 1]; var intervalNs = getInterval(cur.timestamp, prev.timestamp); if (cur.cpu.usage.per_cpu_usage == undefined) { return; } var elements = []; elements.push(cur.timestamp); for (var j = 0; j < machineInfo.num_cores; j++) { elements.push( (cur.cpu.usage.per_cpu_usage[j] - prev.cpu.usage.per_cpu_usage[j]) / intervalNs); } data.push(elements); } drawLineChart(titles, data, elementId, 'Cores'); } // Draw the graph for CPU usage breakdown. function drawCpuUsageBreakdown(elementId, machineInfo, containerInfo) { if (containerInfo.spec.has_cpu && !hasResource(containerInfo, 'cpu')) { return; } var titles = ['Time', 'User', 'Kernel']; var data = []; for (var i = 1; i < containerInfo.stats.length; i++) { var cur = containerInfo.stats[i]; var prev = containerInfo.stats[i - 1]; var intervalNs = getInterval(cur.timestamp, prev.timestamp); var elements = []; elements.push(cur.timestamp); elements.push((cur.cpu.usage.user - prev.cpu.usage.user) / intervalNs); elements.push( (cur.cpu.usage.system - prev.cpu.usage.system) / intervalNs); data.push(elements); } drawLineChart(titles, data, elementId, 'Cores'); } // Return chart titles and data from an array of subcontainerInfos, using the // passed dataFn to return the individual data points. function getSubcontainerChartData(subcontainerInfos, dataFn) { var titles = ['Time']; var data = []; for (var i = 0; i < subcontainerInfos.length; i++) { titles.push(subcontainerInfos[i].name); for (var j = 1; j < subcontainerInfos[i].stats.length; j++) { var cur = subcontainerInfos[i].stats[j]; var prev = subcontainerInfos[i].stats[j - 1]; // Generate a sparse array with timestamp at index zero and data point at // index i+1, to be used as a DataTable row. var elements = [cur.timestamp]; subcontainerInfos.forEach(function() { elements.push(null); }); elements[i+1] = dataFn(cur, prev); data.push(elements); } } return { titles: titles, data: data, } } // Draw the graph for per-subcontainer CPU usage. function drawCpuPerSubcontainerUsage(elementId, subcontainerInfos) { if (!hasResourceForAll(subcontainerInfos, 'cpu')) { return; } var chartData = getSubcontainerChartData(subcontainerInfos, function(cur, prev) { var intervalNs = getInterval(cur.timestamp, prev.timestamp); return (cur.cpu.usage.total - prev.cpu.usage.total) / intervalNs; }); drawLineChart(chartData.titles, chartData.data, elementId, 'Cores'); } // Draw the graph for per-subcontainer memory usage. function drawMemoryPerSubcontainerUsage(elementId, subcontainerInfos) { if (!hasResourceForAll(subcontainerInfos, 'memory')) { return; } var chartData = getSubcontainerChartData(subcontainerInfos, function(cur, prev) { return cur.memory.usage / oneMegabyte; }); drawLineChart(chartData.titles, chartData.data, elementId, 'Megabytes'); } // Draw the gauges for overall resource usage. function drawOverallUsage(elementId, machineInfo, containerInfo) { var cur = containerInfo.stats[containerInfo.stats.length - 1]; var gauges = []; var cpuUsage = 0; if (containerInfo.spec.has_cpu && containerInfo.stats.length >= 2) { var prev = containerInfo.stats[containerInfo.stats.length - 2]; var rawUsage = cur.cpu.usage.total - prev.cpu.usage.total; var intervalNs = getInterval(cur.timestamp, prev.timestamp); // Convert to millicores and take the percentage cpuUsage = Math.round(((rawUsage / intervalNs) / machineInfo.num_cores) * 100); if (cpuUsage > 100) { cpuUsage = 100; } gauges.push(['CPU', cpuUsage]); } var memoryUsage = 0; if (containerInfo.spec.has_memory) { // Saturate to the machine size. var limit = containerInfo.spec.memory.limit; if (limit > machineInfo.memory_capacity) { limit = machineInfo.memory_capacity; } memoryUsage = Math.round((cur.memory.usage / limit) * 100); gauges.push(['Memory', memoryUsage]); } var numGauges = gauges.length; if (cur.filesystem) { for (var i = 0; i < cur.filesystem.length; i++) { var data = cur.filesystem[i]; var totalUsage = Math.floor((data.usage * 100.0) / data.capacity); var els = window.cadvisor.fsUsage.elements[data.device]; // Update the gauges in the right order. gauges[numGauges + els.index] = ['FS #' + (els.index + 1), totalUsage]; } // Limit the number of filesystem gauges displayed to 5. // 'Filesystem details' section still shows information for all filesystems. var max_gauges = numGauges + 5; if (gauges.length > max_gauges) { gauges = gauges.slice(0, max_gauges); } } drawGauges(elementId, gauges); } var oneMegabyte = 1024 * 1024; var oneGigabyte = 1024 * oneMegabyte; function drawMemoryUsage(elementId, machineInfo, containerInfo) { if (containerInfo.spec.has_memory && !hasResource(containerInfo, 'memory')) { return; } var titles = ['Time', 'Total', 'Hot']; var data = []; for (var i = 0; i < containerInfo.stats.length; i++) { var cur = containerInfo.stats[i]; var elements = []; elements.push(cur.timestamp); elements.push(cur.memory.usage / oneMegabyte); elements.push(cur.memory.working_set / oneMegabyte); data.push(elements); } // Get the memory limit, saturate to the machine size. var memory_limit = machineInfo.memory_capacity; if (containerInfo.spec.memory.limit && (containerInfo.spec.memory.limit < memory_limit)) { memory_limit = containerInfo.spec.memory.limit; } // Updating the progress bar. var cur = containerInfo.stats[containerInfo.stats.length - 1]; var hotMemory = Math.floor((cur.memory.working_set * 100.0) / memory_limit); var totalMemory = Math.floor((cur.memory.usage * 100.0) / memory_limit); var coldMemory = totalMemory - hotMemory; $('#progress-hot-memory').width(hotMemory + '%'); $('#progress-cold-memory').width(coldMemory + '%'); $('#memory-text') .text( humanizeIEC(cur.memory.usage) + ' / ' + humanizeIEC(memory_limit) + ' (' + totalMemory + '%)'); drawLineChart(titles, data, elementId, 'Megabytes'); } // Get the index of the interface with the specified name. function getNetworkInterfaceIndex(interfaceName, interfaces) { for (var i = 0; i < interfaces.length; i++) { if (interfaces[i].name == interfaceName) { return i; } } return -1; } // Draw the graph for network tx/rx bytes. function drawNetworkBytes(elementId, machineInfo, stats) { if (stats.spec.has_network && !hasResource(stats, 'network')) { return; } // Get interface index. var interfaceIndex = -1; if (stats.stats.length > 0) { interfaceIndex = getNetworkInterfaceIndex( window.cadvisor.network.interface, stats.stats[0].network.interfaces); } if (interfaceIndex < 0) { console.log( 'Unable to find interface"', interfaceName, '" in ', stats.stats.network); return; } var titles = ['Time', 'Tx bytes', 'Rx bytes']; var data = []; for (var i = 1; i < stats.stats.length; i++) { var cur = stats.stats[i]; var prev = stats.stats[i - 1]; var intervalInSec = getInterval(cur.timestamp, prev.timestamp) / 1000000000; var elements = []; elements.push(cur.timestamp); elements.push( (cur.network.interfaces[interfaceIndex].tx_bytes - prev.network.interfaces[interfaceIndex].tx_bytes) / intervalInSec); elements.push( (cur.network.interfaces[interfaceIndex].rx_bytes - prev.network.interfaces[interfaceIndex].rx_bytes) / intervalInSec); data.push(elements); } drawLineChart(titles, data, elementId, 'Bytes per second'); } // Draw the graph for network errors function drawNetworkErrors(elementId, machineInfo, stats) { if (stats.spec.has_network && !hasResource(stats, 'network')) { return; } // Get interface index. var interfaceIndex = -1; if (stats.stats.length > 0) { interfaceIndex = getNetworkInterfaceIndex( window.cadvisor.network.interface, stats.stats[0].network.interfaces); } if (interfaceIndex < 0) { console.log( 'Unable to find interface"', interfaceName, '" in ', stats.stats.network); return; } var titles = ['Time', 'Tx', 'Rx']; var data = []; for (var i = 1; i < stats.stats.length; i++) { var cur = stats.stats[i]; var prev = stats.stats[i - 1]; var intervalInSec = getInterval(cur.timestamp, prev.timestamp) / 1000000000; var elements = []; elements.push(cur.timestamp); elements.push( (cur.network.interfaces[interfaceIndex].tx_errors - prev.network.interfaces[interfaceIndex].tx_errors) / intervalInSec); elements.push( (cur.network.interfaces[interfaceIndex].rx_errors - prev.network.interfaces[interfaceIndex].rx_errors) / intervalInSec); data.push(elements); } drawLineChart(titles, data, elementId, 'Errors per second'); } // Update the filesystem usage values. function drawFileSystemUsage(machineInfo, stats) { var cur = stats.stats[stats.stats.length - 1]; if (!cur.filesystem) { return; } var el = $('
'); for (var i = 0; i < cur.filesystem.length; i++) { var data = cur.filesystem[i]; var totalUsage = Math.floor((data.usage * 100.0) / data.capacity); // Update DOM elements. var els = window.cadvisor.fsUsage.elements[data.device]; els.progressElement.width(totalUsage + '%'); els.textElement.text( humanizeMetric(data.usage) + ' / ' + humanizeMetric(data.capacity) + ' (' + totalUsage + '%)'); } } function drawImages(images) { if (images == null || images.length == 0) { return; } window.charts = {}; var titles = ['Repository', 'Tags', 'ID', 'Virtual Size', 'Creation Time']; var titleTypes = ['string', 'string', 'string', 'number', 'number']; var sortIndex = 0; var data = []; for (var i = 0; i < images.length; i++) { var elements = []; var tags = []; var repos = images[i].repo_tags[0].split(':'); repos.splice(-1, 1); for (var j = 0; j < images[i].repo_tags.length; j++) { var splits = images[i].repo_tags[j].split(':'); if (splits.length > 1) { tags.push(splits[splits.length - 1]); } } elements.push(repos.join(':')); elements.push(tags.join(', ')); elements.push(images[i].id.substr(0, 24)); elements.push( {v: images[i].virtual_size, f: humanizeIEC(images[i].virtual_size)}); var d = new Date(images[i].created * 1000); elements.push({v: images[i].created, f: d.toLocaleString()}); data.push(elements); } drawTable(titles, titleTypes, data, 'docker-images', 30, sortIndex); } function drawProcesses(isRoot, rootDir, processInfo) { if (processInfo.length == 0) { $('#processes-top').text('No processes found'); return; } var titles = [ 'User', 'PID', 'PPID', 'Start Time', 'CPU %', 'MEM %', 'RSS', 'Virtual Size', 'Status', 'Running Time', 'Command', 'PSR' ]; var titleTypes = [ 'string', 'number', 'number', 'string', 'number', 'number', 'number', 'number', 'string', 'string', 'string', 'number' ]; var sortIndex = 4; if (isRoot) { titles.push('Container'); titleTypes.push('string'); } var data = []; for (var i = 0; i < processInfo.length; i++) { var elements = []; elements.push(processInfo[i].user); elements.push(processInfo[i].pid); elements.push(processInfo[i].parent_pid); elements.push(processInfo[i].start_time); elements.push({ v: processInfo[i].percent_cpu, f: processInfo[i].percent_cpu.toFixed(2) }); elements.push({ v: processInfo[i].percent_mem, f: processInfo[i].percent_mem.toFixed(2) }); elements.push({v: processInfo[i].rss, f: humanizeIEC(processInfo[i].rss)}); elements.push({ v: processInfo[i].virtual_size, f: humanizeIEC(processInfo[i].virtual_size) }); elements.push(processInfo[i].status); elements.push(processInfo[i].running_time); elements.push(processInfo[i].cmd); elements.push(processInfo[i].psr); if (isRoot) { var cgroup = processInfo[i].cgroup_path; // Use the raw cgroup link as it works for all containers. var cgroupLink = '' + cgroup.substr(0, 30) + ' '; elements.push({v: cgroup, f: cgroupLink}); } data.push(elements); } drawTable(titles, titleTypes, data, 'processes-top', 25, sortIndex); } // Draw the filesystem usage nodes. function startFileSystemUsage(elementId, machineInfo, stats) { window.cadvisor.fsUsage = {}; // A map of device name to DOM elements. window.cadvisor.fsUsage.elements = {}; var cur = stats.stats[stats.stats.length - 1]; var el = $('
'); if (!cur.filesystem) { return; } for (var i = 0; i < cur.filesystem.length; i++) { var data = cur.filesystem[i]; el.append( $('
') .addClass('row col-sm-12') .append($('

').text('FS #' + (i + 1) + ': ' + data.device))); var progressElement = $('
').addClass('progress-bar progress-bar-danger'); el.append( $('
') .addClass('col-sm-9') .append($('
').addClass('progress').append(progressElement))); var textElement = $('
').addClass('col-sm-3'); el.append(textElement); window.cadvisor.fsUsage.elements[data.device] = { 'progressElement': progressElement, 'textElement': textElement, 'index': i, }; } $('#' + elementId).empty().append(el); drawFileSystemUsage(machineInfo, stats); } // Expects an array of closures to call. After each execution the JS runtime is // given control back before continuing. // This function returns asynchronously function stepExecute(steps) { // No steps, stop. if (steps.length == 0) { return; } // Get a step and execute it. var step = steps.shift(); step(); // Schedule the next step. setTimeout(function() { stepExecute(steps); }, 0); } // Draw all the charts on the page. function drawCharts(machineInfo, containerInfo, subcontainers) { var steps = []; if (containerInfo.spec.has_cpu || containerInfo.spec.has_memory) { steps.push(function() { drawOverallUsage('usage-gauge', machineInfo, containerInfo); }); } // CPU. if (containerInfo.spec.has_cpu) { steps.push(function() { drawCpuTotalUsage('cpu-total-usage-chart', machineInfo, containerInfo); }); // TODO(rjnagal): Re-enable CPU Load after understanding resource usage. // steps.push(function() { // drawCpuLoad("cpu-load-chart", machineInfo, containerInfo); // }); steps.push(function() { drawCpuPerCoreUsage( 'cpu-per-core-usage-chart', machineInfo, containerInfo); }); steps.push(function() { drawCpuUsageBreakdown( 'cpu-usage-breakdown-chart', machineInfo, containerInfo); }); } // Memory. if (containerInfo.spec.has_memory) { steps.push(function() { drawMemoryUsage('memory-usage-chart', machineInfo, containerInfo); }); } // Network. if (containerInfo.spec.has_network) { steps.push(function() { drawNetworkBytes('network-bytes-chart', machineInfo, containerInfo); }); steps.push(function() { drawNetworkErrors('network-errors-chart', machineInfo, containerInfo); }); } // Filesystem. if (containerInfo.spec.has_filesystem) { steps.push(function() { drawFileSystemUsage(machineInfo, containerInfo); }); } // Custom Metrics if (containerInfo.spec.has_custom_metrics) { steps.push(function() { getCustomMetrics( window.cadvisor.rootDir, window.cadvisor.containerName, function(metricsInfo) { drawCustomMetrics( 'custom-metrics-chart', containerInfo, metricsInfo); }); }); } // Subcontainers. var subcontainerInfos = filterSubcontainers(containerInfo, subcontainers); if (subcontainerInfos.length > 0) { if (hasResourceForAll(subcontainerInfos, 'cpu')) { steps.push(function() { var displayCount = $('#cpu-per-subcontainer-display-count').val(); drawCpuPerSubcontainerUsage( 'cpu-per-subcontainer-usage-chart', sliceByCpu(subcontainerInfos, displayCount)); }); } if (hasResourceForAll(subcontainerInfos, 'memory')) { steps.push(function() { var displayCount = $('#memory-per-subcontainer-display-count').val(); drawMemoryPerSubcontainerUsage( 'memory-per-subcontainer-usage-chart', sliceByMemory(subcontainerInfos, displayCount)); }); } } stepExecute(steps); } // Return an slice of subcontainers sorted by CPU, with at most 'count' entries. function sliceByCpu(subcontainerInfos, count) { subcontainerInfos.sort(function(a, b) { if (a.averages.cpu > b.averages.cpu) { return -1; } else if (a.averages.cpu < b.averages.cpu) { return 1; } else { return compareByName(a, b); } }); return subcontainerInfos.slice(0, Math.min(subcontainerInfos.length, count)) .sort(compareByName); } // Return an slice of subcontainers sorted by memory, with at most 'count' // entries. function sliceByMemory(subcontainerInfos, count) { subcontainerInfos.sort(function(a, b) { if (a.averages.memory > b.averages.memory) { return -1; } else if (a.averages.memory < b.averages.memory) { return 1; } else { return compareByName(a, b); } }); return subcontainerInfos.slice(0, Math.min(subcontainerInfos.length, count)) .sort(compareByName); } // Return sort comparitor based on subcontroller name. function compareByName(subA, subB) { if (subA.name > subB.name) { return 1; } else if (subA.name < subB.name) { return -1; } else { return 0; } } // Return a map of the averages of the subcontainer stats. function getSubcontainerAverages(subcontainer) { var cpuSum = 0; var memorySum = 0; subcontainer.stats.forEach(function(stat) { cpuSum += stat.cpu.usage.total; memorySum += stat.memory.usage / oneMegabyte; }); return { cpu: cpuSum / subcontainer.stats.length, memory: memorySum / subcontainer.stats.length, } } // Return a list of immediate subcontainers, including metric averages. function filterSubcontainers(containerInfo, subcontainers) { if (!containerInfo.subcontainers || containerInfo.subcontainers.length === 0 || !subcontainers) { return []; } var subcontainerNames = {}; containerInfo.subcontainers.forEach(function(subcontainer) { subcontainerNames[subcontainer.name] = subcontainer.name; }); var subcontainerInfos = []; subcontainers.forEach(function(subcontainer) { if (subcontainerNames[subcontainer.name] !== undefined) { subcontainer.averages = getSubcontainerAverages(subcontainer); subcontainerInfos.push(subcontainer); } }); return subcontainerInfos; } function setNetwork(interfaceName) { $('#network-selection-text') .empty() .append($('').text('Interface: ')) .append($('').text(interfaceName)); window.cadvisor.network.interface = interfaceName; // Draw the new stats. refreshStats(); } // Creates the network selection dropdown. function startNetwork(selectionElement, containerInfo) { if (!hasResource(containerInfo, 'network') || containerInfo.stats.length == 0 || !containerInfo.stats[0].network.interfaces || containerInfo.stats[0].network.interfaces.length == 0) { return; } window.cadvisor.network = {}; window.cadvisor.network.interface = ''; // Add all interfaces to the dropdown. var el = $('#' + selectionElement); for (var i = 0; i < containerInfo.stats[0].network.interfaces.length; i++) { var interfaceName = containerInfo.stats[0].network.interfaces[i].name; el.append($('
  • ') .attr('role', 'presentation') .append($('') .attr('role', 'menuitem') .attr('tabindex', -1) .click(setNetwork.bind(null, interfaceName)) .text(interfaceName))); } setNetwork(containerInfo.stats[0].network.interfaces[0].name); } // Refresh the stats on the page. function refreshStats() { var machineInfo = window.cadvisor.machineInfo; getStats( window.cadvisor.rootDir, window.cadvisor.containerName, function(containerInfo, subcontainers) { if (window.cadvisor.firstRun) { window.cadvisor.firstRun = false; if (containerInfo.spec.has_filesystem) { startFileSystemUsage( 'filesystem-usage', machineInfo, containerInfo); } if (containerInfo.spec.has_network) { startNetwork('network-selection', containerInfo); } if (containerInfo.spec.has_custom_metrics) { startCustomMetrics('custom-metrics-chart', containerInfo); } } drawCharts(machineInfo, containerInfo, subcontainers); }); } function addAllLabels(containerInfo, metricsInfo) { if (metricsInfo.length == 0) { return; } var metricSpec = containerInfo.spec.custom_metrics; for (var containerName in metricsInfo) { var container = metricsInfo[containerName]; for (i = 0; i < metricSpec.length; i++) { metricName = metricSpec[i].name; metricLabelVal = container[metricName]; firstLabel = true; for (var label in metricLabelVal) { if (label == '') { $('#button-' + metricName).hide(); } $('#' + metricName + '_labels') .append( $('
  • ') .attr('role', 'presentation') .append($('') .attr('role', 'menuitem') .click(setLabel.bind(null, metricName, label)) .text(label))); if (firstLabel) { firstLabel = false; setLabel(metricName, label); } } } } } function getMetricIndex(metricName) { for (i = 0; i < window.cadvisor.metricLabelPair.length; ++i) { if (window.cadvisor.metricLabelPair[i][0] == metricName) { return i; } } return -1; } function setLabel(metric, label) { $('#' + metric + '-selection-text') .empty() .append($('').text('Label: ')) .append($('').text(label)); index = getMetricIndex(metric); if (index == -1) { window.cadvisor.metricLabelPair.push([metric, label]); } else { window.cadvisor.metricLabelPair[index][1] = label; } refreshStats(); } function getSelectedLabel(metricName) { index = getMetricIndex(metricName); if (index == -1) { return ''; } return window.cadvisor.metricLabelPair[index][1]; } function startCustomMetrics(elementId, containerInfo) { var metricSpec = containerInfo.spec.custom_metrics; var metricStats = containerInfo.stats.custom_metrics; var el = $('
    '); if (metricSpec.length < window.cadvisor.maxCustomMetrics) { window.cadvisor.maxCustomMetrics = metricSpec.length; for (i = 0; i < window.cadvisor.maxCustomMetrics; i++) { metricName = metricSpec[i].name; var divText = '
    '; divText += '
    '; divText += '
    '; el.append($(divText)); } } el.append($('
    ')); $('#' + elementId).append(el); } function getCustomMetrics(rootDir, containerName, callback) { $.getJSON(rootDir + 'api/v2.0/appmetrics/' + containerName) .done(function(data) { callback(data); }) .fail(function(jqhxr, textStatus, error) { callback([]); }); } function drawCustomMetrics(elementId, containerInfo, metricsInfo) { if (metricsInfo.length == 0) { return; } var metricSpec = containerInfo.spec.custom_metrics; for (var containerName in metricsInfo) { var container = metricsInfo[containerName]; for (i = 0; i < window.cadvisor.maxCustomMetrics; i++) { metricName = metricSpec[i].name; metricUnits = metricSpec[i].units; var titles = ['Time', metricName]; metricLabelVal = container[metricName]; if (window.cadvisor.firstCustomCollection) { window.cadvisor.firstCustomCollection = false; addAllLabels(containerInfo, metricsInfo); } var data = []; selectedLabel = getSelectedLabel(metricName); metricVal = metricLabelVal[selectedLabel]; for (var index in metricVal) { metric = metricVal[index]; var elements = []; for (var attribute in metric) { value = metric[attribute]; elements.push(value); } if (elements.length < 2) { elements.push(0); } data.push(elements); } drawLineChart(titles, data, elementId + '-' + metricName, metricUnits); } } } // Executed when the page finishes loading. function startPage(containerName, hasCpu, hasMemory, rootDir, isRoot) { // Don't fetch data if we don't have any resource. if (!hasCpu && !hasMemory) { return; } window.charts = {}; window.cadvisor = {}; window.cadvisor.firstRun = true; window.cadvisor.rootDir = rootDir; window.cadvisor.containerName = containerName; window.cadvisor.firstCustomCollection = true; window.cadvisor.metricLabelPair = []; window.cadvisor.maxCustomMetrics = 10; // Draw process information at start and refresh every 60s. getProcessInfo(rootDir, containerName, function(processInfo) { drawProcesses(isRoot, rootDir, processInfo); }); setInterval(function() { getProcessInfo(rootDir, containerName, function(processInfo) { drawProcesses(isRoot, rootDir, processInfo); }); }, 60000); // Get machine info, then get the stats every 1s. getMachineInfo(rootDir, function(machineInfo) { window.cadvisor.machineInfo = machineInfo; setInterval(function() { refreshStats(); }, 1000); }); } ================================================ FILE: cmd/internal/pages/assets/js/loader.js ================================================ (function(){/* Copyright The Closure Library Authors. SPDX-License-Identifier: Apache-2.0 */ 'use strict';var m;function aa(a){var b=0;return function(){return b=e}}); q("String.prototype.startsWith",function(a){return a?a:function(b,c){var d=r(this,b,"startsWith"),e=d.length,f=b.length;c=Math.max(0,Math.min(c|0,d.length));for(var g=0;g=f}});q("String.prototype.repeat",function(a){return a?a:function(b){var c=r(this,null,"repeat");if(0>b||1342177279>>=1)c+=c;return d}}); q("String.prototype.trimLeft",function(a){function b(){return this.replace(/^[\s\xa0]+/,"")}return a||b});q("String.prototype.trimStart",function(a){return a||String.prototype.trimLeft}); q("Promise",function(a){function b(g){this.b=0;this.c=void 0;this.a=[];var h=this.g();try{g(h.resolve,h.reject)}catch(k){h.reject(k)}}function c(){this.a=null}function d(g){return g instanceof b?g:new b(function(h){h(g)})}if(a)return a;c.prototype.b=function(g){if(null==this.a){this.a=[];var h=this;this.c(function(){h.h()})}this.a.push(g)};var e=fa.setTimeout;c.prototype.c=function(g){e(g,0)};c.prototype.h=function(){for(;this.a&&this.a.length;){var g=this.a;this.a=[];for(var h=0;hc&&(c=Math.max(c+e,0));cc?Math.max(f+c,0):Math.min(c,f);d=0>d?Math.max(f+d,0):Math.min(d,f);e=0>e?Math.max(f+e,0):Math.min(e,f);if(cd;)--e in this?this[--c]=this[e]:delete this[--c];return this}}); q("Symbol",function(a){function b(e){if(this instanceof b)throw new TypeError("Symbol is not a constructor");return new c("jscomp_symbol_"+(e||"")+"_"+d++,e)}function c(e,f){this.a=e;da(this,"description",{configurable:!0,writable:!0,value:f})}if(a)return a;c.prototype.toString=function(){return this.a};var d=0;return b}); q("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),c=0;cc&&(c=Math.max(0,e+c));if(null==d||d>e)d=e;d=Number(d);0>d&&(d=Math.max(0,e+d));for(c=Number(c||0);cb?-c:c}}); q("Math.log1p",function(a){return a?a:function(b){b=Number(b);if(.25>b&&-.25b?-c:c}}); q("Math.clz32",function(a){return a?a:function(b){b=Number(b)>>>0;if(0===b)return 32;var c=0;0===(b&4294901760)&&(b<<=16,c+=16);0===(b&4278190080)&&(b<<=8,c+=8);0===(b&4026531840)&&(b<<=4,c+=4);0===(b&3221225472)&&(b<<=2,c+=2);0===(b&2147483648)&&c++;return c}});q("Math.cosh",function(a){if(a)return a;var b=Math.exp;return function(c){c=Number(c);return(b(c)+b(-c))/2}}); q("Math.expm1",function(a){return a?a:function(b){b=Number(b);if(.25>b&&-.25arguments.length)return arguments.length?Math.abs(arguments[0]):0;var c,d,e;for(c=e=0;ce){if(!e)return e;for(c=d=0;c>>16&65535)*e+d*(c>>>16&65535)<<16>>>0)|0}});q("Math.log10",function(a){return a?a:function(b){return Math.log(b)/Math.LN10}});q("Math.log2",function(a){return a?a:function(b){return Math.log(b)/Math.LN2}});q("Math.sign",function(a){return a?a:function(b){b=Number(b);return 0===b||isNaN(b)?b:0b?-c:c}});q("Math.trunc",function(a){return a?a:function(b){b=Number(b);if(isNaN(b)||Infinity===b||-Infinity===b||0===b)return b;var c=Math.floor(Math.abs(b));return 0>b?-c:c}});q("Number.EPSILON",function(){return Math.pow(2,-52)}); q("Number.MAX_SAFE_INTEGER",function(){return 9007199254740991});q("Number.MIN_SAFE_INTEGER",function(){return-9007199254740991});q("Number.isFinite",function(a){return a?a:function(b){return"number"!==typeof b?!1:!isNaN(b)&&Infinity!==b&&-Infinity!==b}});q("Number.isInteger",function(a){return a?a:function(b){return Number.isFinite(b)?b===Math.floor(b):!1}});q("Number.isNaN",function(a){return a?a:function(b){return"number"===typeof b&&isNaN(b)}}); q("Number.isSafeInteger",function(a){return a?a:function(b){return Number.isInteger(b)&&Math.abs(b)<=Number.MAX_SAFE_INTEGER}});q("Number.parseFloat",function(a){return a||parseFloat});q("Number.parseInt",function(a){return a||parseInt});var oa="function"==typeof Object.assign?Object.assign:function(a,b){for(var c=1;c=arguments.length)return b[c];var e=ra(b,c);if(e)return e.get?e.get.call(d):e.value}});q("Reflect.has",function(a){return a?a:function(b,c){return c in b}}); q("Reflect.isExtensible",function(a){return a?a:"function"==typeof Object.isExtensible?Object.isExtensible:function(){return!0}});q("Reflect.preventExtensions",function(a){return a?a:"function"!=typeof Object.preventExtensions?function(){return!1}:function(b){Object.preventExtensions(b);return!Object.isExtensible(b)}}); q("Reflect.set",function(a){return a?a:function(b,c,d,e){var f=ra(b,c);return f?f.set?(f.set.call(3e||56319b||57343e||1114111=e?c+=String.fromCharCode(e):(e-=65536,c+=String.fromCharCode(e>>>10&1023|55296),c+=String.fromCharCode(e&1023|56320))}return c}}); q("String.prototype.matchAll",function(a){return a?a:function(b){if(b instanceof RegExp&&!b.global)throw new TypeError("RegExp passed into String.prototype.matchAll() must have global tag.");var c=new RegExp(b,b instanceof RegExp?void 0:"g"),d=this,e=!1,f={next:function(){var g={},h=c.lastIndex;if(e)return{value:void 0,done:!0};var k=c.exec(d);if(!k)return e=!0,{value:void 0,done:!0};c.lastIndex===h&&(c.lastIndex+=1);g.value=k;g.done=!1;return g}};f[Symbol.iterator]=function(){return f};return f}}); function sa(a,b){a=void 0!==a?String(a):" ";return 0a.length?"&":"")+encodeURIComponent(d)+"="+encodeURIComponent(String(g)))}}return b}var Na={};var Xa=String.prototype.trim?function(a){return a.trim()}:function(a){return/^[\s\xa0]*([\s\S]*?)[\s\xa0]*$/.exec(a)[1]};function Ya(a,b){return ab?1:0};var J;a:{var Za=u.navigator;if(Za){var $a=Za.userAgent;if($a){J=$a;break a}}J=""}function K(a){return-1!=J.indexOf(a)};function ab(a,b){for(var c in a)b.call(void 0,a[c],c,a)}var bb="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" ");function cb(a,b){for(var c,d,e=1;eparseFloat(mb)){lb=String(ob);break a}}lb=mb}var qb=lb,fb={}; function rb(){return eb(function(){for(var a=0,b=Xa(String(qb)).split("."),c=Xa("11").split("."),d=Math.max(b.length,c.length),e=0;0==a&&ea.b&&(a.b++,b.next=a.a,a.a=b)};function xb(a){u.setTimeout(function(){throw a;},0)}var yb; function zb(){var a=u.MessageChannel;"undefined"===typeof a&&"undefined"!==typeof window&&window.postMessage&&window.addEventListener&&!K("Presto")&&(a=function(){var e=ub("IFRAME");e.style.display="none";document.documentElement.appendChild(e);var f=e.contentWindow;e=f.document;e.open();e.close();var g="callImmediate"+Math.random(),h="file:"==f.location.protocol?"*":f.location.protocol+"//"+f.location.host;e=z(function(k){if(("*"==h||k.origin==h)&&k.data==g)this.port1.onmessage()},this);f.addEventListener("message", e,!1);this.port1={};this.port2={postMessage:function(){f.postMessage(g,h)}}});if("undefined"!==typeof a&&!K("Trident")&&!K("MSIE")){var b=new a,c={},d=c;b.port1.onmessage=function(){if(void 0!==c.next){c=c.next;var e=c.L;c.L=null;e()}};return function(e){d.next={L:e};d=d.next;b.port2.postMessage(0)}}return function(e){u.setTimeout(e,0)}};function Ab(){this.b=this.a=null}var Cb=new vb(function(){return new Bb},function(a){a.reset()});Ab.prototype.add=function(a,b){var c=Cb.get();c.set(a,b);this.b?this.b.next=c:this.a=c;this.b=c};function Db(){var a=Eb,b=null;a.a&&(b=a.a,a.a=a.a.next,a.a||(a.b=null),b.next=null);return b}function Bb(){this.next=this.b=this.a=null}Bb.prototype.set=function(a,b){this.a=a;this.b=b;this.next=null};Bb.prototype.reset=function(){this.next=this.b=this.a=null};function Fb(a,b){Gb||Hb();Ib||(Gb(),Ib=!0);Eb.add(a,b)}var Gb;function Hb(){if(u.Promise&&u.Promise.resolve){var a=u.Promise.resolve(void 0);Gb=function(){a.then(Jb)}}else Gb=function(){var b=Jb;!y(u.setImmediate)||u.Window&&u.Window.prototype&&!K("Edge")&&u.Window.prototype.setImmediate==u.setImmediate?(yb||(yb=zb()),yb(b)):u.setImmediate(b)}}var Ib=!1,Eb=new Ab;function Jb(){for(var a;a=Db();){try{a.a.call(a.b)}catch(b){xb(b)}wb(Cb,a)}Ib=!1};function Kb(a){if(!a)return!1;try{return!!a.$goog_Thenable}catch(b){return!1}};function L(a){this.a=0;this.j=void 0;this.g=this.b=this.c=null;this.h=this.i=!1;if(a!=w)try{var b=this;a.call(void 0,function(c){M(b,2,c)},function(c){M(b,3,c)})}catch(c){M(this,3,c)}}function Lb(){this.next=this.c=this.b=this.g=this.a=null;this.h=!1}Lb.prototype.reset=function(){this.c=this.b=this.g=this.a=null;this.h=!1};var Mb=new vb(function(){return new Lb},function(a){a.reset()});function Nb(a,b,c){var d=Mb.get();d.g=a;d.b=b;d.c=c;return d} L.prototype.then=function(a,b,c){return Ob(this,y(a)?a:null,y(b)?b:null,c)};L.prototype.$goog_Thenable=!0;L.prototype.cancel=function(a){if(0==this.a){var b=new N(a);Fb(function(){Pb(this,b)},this)}};function Pb(a,b){if(0==a.a)if(a.c){var c=a.c;if(c.b){for(var d=0,e=null,f=null,g=c.b;g&&(g.h||(d++,g.a==a&&(e=g),!(e&&1=b.m&&b.cancel())}this.F?this.F.call(this.H,this):this.A=!0;this.a||(a=new P(this),Q(this),R(this,!1,a))}};O.prototype.B=function(a,b){this.j=!1;R(this,a,b)};function R(a,b,c){a.a=!0;a.c=c;a.g=!b;Yb(a)} function Q(a){if(a.a){if(!a.A)throw new Zb(a);a.A=!1}}function $b(a,b,c,d){a.h.push([b,c,d]);a.a&&Yb(a);return a}O.prototype.then=function(a,b,c){var d,e,f=new L(function(g,h){d=g;e=h});$b(this,d,function(g){g instanceof P?f.cancel():e(g)});return f.then(a,b,c)};O.prototype.$goog_Thenable=!0;function ac(a){return Ia(a.h,function(b){return y(b[1])})} function Yb(a){if(a.i&&a.a&&ac(a)){var b=a.i,c=bc[b];c&&(u.clearTimeout(c.a),delete bc[b]);a.i=0}a.b&&(a.b.m--,delete a.b);b=a.c;for(var d=c=!1;a.h.length&&!a.j;){var e=a.h.shift(),f=e[0],g=e[1];e=e[2];if(f=a.g?g:f)try{var h=f.call(e||a.H,b);void 0!==h&&(a.g=a.g&&(h==b||h instanceof Error),a.c=b=h);if(Kb(b)||"function"===typeof u.Promise&&b instanceof u.Promise)d=!0,a.j=!0}catch(k){b=k,a.g=!0,ac(a)||(c=!0)}}a.c=b;d&&(h=z(a.B,a,!0),d=z(a.B,a,!1),b instanceof O?($b(b,h,d),b.U=!0):b.then(h,d));c&&(b= new cc(b),bc[b.a]=b,a.i=b.a)}function dc(){var a=new O;Q(a);R(a,!0,null);return a}function Zb(){D.call(this)}C(Zb,D);Zb.prototype.message="Deferred has already fired";Zb.prototype.name="AlreadyCalledError";function P(){D.call(this)}C(P,D);P.prototype.message="Deferred was canceled";P.prototype.name="CanceledError";function cc(a){this.a=u.setTimeout(z(this.c,this),0);this.b=a}cc.prototype.c=function(){delete bc[this.a];throw this.b;};var bc={};var ec,fc=[];function gc(a,b){function c(){var e=a.shift();e=hc(e,b);a.length&&$b(e,c,c,void 0);return e}if(!a.length)return dc();var d=fc.length;La(fc,a);if(d)return ec;a=fc;return ec=c()} function hc(a,b){var c=b||{};b=c.document||document;var d=Pa(a).toString(),e=ub("SCRIPT"),f={P:e,S:void 0},g=new O(ic,f),h=null,k=null!=c.timeout?c.timeout:5E3;0b)throw Error("Bad port number "+b);a.m=b}else a.m=null}function xc(a,b,c){b instanceof U?(a.c=b,Fc(a.c,a.i)):(c||(b=Ac(b,Gc)),a.c=new U(b,a.i))} function zc(a,b){return a?b?decodeURI(a.replace(/%25/g,"%2525")):decodeURIComponent(a):""}function Ac(a,b,c){return"string"===typeof a?(a=encodeURI(a).replace(b,Hc),c&&(a=a.replace(/%25([0-9a-fA-F]{2})/g,"%$1")),a):null}function Hc(a){a=a.charCodeAt(0);return"%"+(a>>4&15).toString(16)+(a&15).toString(16)}var Bc=/[#\/\?@]/g,Dc=/[#\?:]/g,Cc=/[#\?]/g,Gc=/[#\?@]/g,Ec=/#/g;function U(a,b){this.b=this.a=null;this.c=a||null;this.g=!!b} function V(a){a.a||(a.a=new qc,a.b=0,a.c&&tc(a.c,function(b,c){a.add(decodeURIComponent(b.replace(/\+/g," ")),c)}))}m=U.prototype;m.add=function(a,b){V(this);this.c=null;a=W(this,a);var c=this.a.get(a);c||this.a.set(a,c=[]);c.push(b);this.b+=1;return this};function Ic(a,b){V(a);b=W(a,b);T(a.a.b,b)&&(a.c=null,a.b-=a.a.get(b).length,a=a.a,T(a.b,b)&&(delete a.b[b],a.c--,a.a.length>2*a.c&&rc(a)))}function Jc(a,b){V(a);b=W(a,b);return T(a.a.b,b)} m.forEach=function(a,b){V(this);this.a.forEach(function(c,d){Ga(c,function(e){a.call(b,e,d,this)},this)},this)};m.C=function(){V(this);for(var a=this.a.D(),b=this.a.C(),c=[],d=0;d= i { return fmt.Sprintf("%.2f", b/i) } } return fmt.Sprintf("%.2f", b) } func (b ByteSize) Unit() string { switch { case b >= YB: return "YB" case b >= ZB: return "ZB" case b >= EB: return "EB" case b >= PB: return "PB" case b >= TB: return "TB" case b >= GB: return "GB" case b >= MB: return "MB" case b >= KB: return "KB" } return "B" } var funcMap = template.FuncMap{ "printMask": printMask, "printCores": printCores, "printShares": printShares, "printSize": printSize, "printUnit": printUnit, } func printMask(mask string, numCores int) interface{} { masks := make([]string, numCores) activeCores := getActiveCores(mask) for i := 0; i < numCores; i++ { coreClass := "inactive-cpu" if activeCores[i] { coreClass = "active-cpu" } masks[i] = fmt.Sprintf("%d", coreClass, i) } return template.HTML(strings.Join(masks, " ")) } func getActiveCores(mask string) map[int]bool { activeCores := make(map[int]bool) for _, corebits := range strings.Split(mask, ",") { cores := strings.Split(corebits, "-") if len(cores) == 1 { index, err := strconv.Atoi(cores[0]) if err != nil { // Ignore malformed strings. continue } activeCores[index] = true } else if len(cores) == 2 { start, err := strconv.Atoi(cores[0]) if err != nil { continue } end, err := strconv.Atoi(cores[1]) if err != nil { continue } for i := start; i <= end; i++ { activeCores[i] = true } } } return activeCores } func printCores(millicores *uint64) string { cores := float64(*millicores) / 1000 return strconv.FormatFloat(cores, 'f', 3, 64) } func printShares(shares *uint64) string { return fmt.Sprintf("%d", *shares) } // Size after which we consider memory to be "unlimited". This is not // MaxInt64 due to rounding by the kernel. const maxMemorySize = uint64(1 << 62) func printSize(bytes uint64) string { if bytes >= maxMemorySize { return "unlimited" } return ByteSize(bytes).Size() } func printUnit(bytes uint64) string { if bytes >= maxMemorySize { return "" } return ByteSize(bytes).Unit() } func serveContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) { start := time.Now() // The container name is the path after the handler containerName := u.Path[len(ContainersPage)-1:] // Get the container. reqParams := info.ContainerInfoRequest{ NumStats: 60, } cont, err := m.GetContainerInfo(containerName, &reqParams) if err != nil { http.Error(w, fmt.Sprintf("failed to get container %q with error: %v", containerName, err), http.StatusNotFound) return } displayName := getContainerDisplayName(cont.ContainerReference) // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { http.Error(w, fmt.Sprintf("failed to get machine info: %v", err), http.StatusInternalServerError) return } rootDir := getRootDir(containerName) // Make a list of the parent containers and their links pathParts := strings.Split(string(cont.Name), "/") parentContainers := make([]link, 0, len(pathParts)) parentContainers = append(parentContainers, link{ Text: "root", Link: path.Join(rootDir, ContainersPage), }) for i := 1; i < len(pathParts); i++ { // Skip empty parts. if pathParts[i] == "" { continue } parentContainers = append(parentContainers, link{ Text: pathParts[i], Link: path.Join(rootDir, ContainersPage, path.Join(pathParts[1:i+1]...)), }) } // Build the links for the subcontainers. subcontainerLinks := make([]link, 0, len(cont.Subcontainers)) for _, sub := range cont.Subcontainers { if !m.Exists(sub.Name) { continue } subcontainerLinks = append(subcontainerLinks, link{ Text: getContainerDisplayName(sub), Link: path.Join(rootDir, ContainersPage, sub.Name), }) } data := &pageData{ DisplayName: displayName, ContainerName: escapeContainerName(cont.Name), ParentContainers: parentContainers, Subcontainers: subcontainerLinks, Spec: cont.Spec, Stats: cont.Stats, MachineInfo: machineInfo, IsRoot: cont.Name == "/", ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork || cont.Spec.HasFilesystem, CpuAvailable: cont.Spec.HasCpu, MemoryAvailable: cont.Spec.HasMemory, NetworkAvailable: cont.Spec.HasNetwork, FsAvailable: cont.Spec.HasFilesystem, CustomMetricsAvailable: cont.Spec.HasCustomMetrics, SubcontainersAvailable: len(subcontainerLinks) > 0, Root: rootDir, } err = pageTemplate.Execute(w, data) if err != nil { klog.Errorf("Failed to apply template: %s", err) } klog.V(5).Infof("Request took %s", time.Since(start)) } // Build a relative path to the root of the container page. func getRootDir(containerName string) string { // The root is at: container depth levels := (strings.Count(containerName, "/")) return strings.Repeat("../", levels) } ================================================ FILE: cmd/internal/pages/docker.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package pages import ( "fmt" "net/http" "net/url" "path" "strconv" "time" "github.com/google/cadvisor/container/docker" dockerutil "github.com/google/cadvisor/container/docker/utils" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/manager" "k8s.io/klog/v2" ) const DockerPage = "/docker/" func toStatusKV(status info.DockerStatus) ([]keyVal, []keyVal) { ds := []keyVal{ {Key: "Driver", Value: status.Driver}, } for k, v := range status.DriverStatus { ds = append(ds, keyVal{Key: k, Value: v}) } return []keyVal{ {Key: "Version", Value: status.Version}, {Key: "API Version", Value: status.APIVersion}, {Key: "Kernel Version", Value: status.KernelVersion}, {Key: "OS Version", Value: status.OS}, {Key: "Host Name", Value: status.Hostname}, {Key: "Root Directory", Value: status.RootDir}, {Key: "Execution Driver", Value: status.ExecDriver}, {Key: "Number of Images", Value: strconv.Itoa(status.NumImages)}, {Key: "Number of Containers", Value: strconv.Itoa(status.NumContainers)}, }, ds } func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) { start := time.Now() // The container name is the path after the handler containerName := u.Path[len(DockerPage)-1:] rootDir := getRootDir(containerName) var data *pageData if containerName == "/" { // Get the containers. reqParams := info.ContainerInfoRequest{ NumStats: 0, } conts, err := m.AllDockerContainers(&reqParams) if err != nil { http.Error(w, fmt.Sprintf("failed to get container %q with error: %v", containerName, err), http.StatusNotFound) return } subcontainers := make([]link, 0, len(conts)) for _, cont := range conts { subcontainers = append(subcontainers, link{ Text: getContainerDisplayName(cont.ContainerReference), Link: path.Join(rootDir, DockerPage, dockerutil.ContainerNameToId(cont.ContainerReference.Name)), }) } // Get Docker status status, err := docker.Status() if err != nil { http.Error(w, fmt.Sprintf("failed to get docker info: %v", err), http.StatusInternalServerError) return } dockerStatus, driverStatus := toStatusKV(status) // Get Docker Images images, err := docker.Images() if err != nil { http.Error(w, fmt.Sprintf("failed to get docker images: %v", err), http.StatusInternalServerError) return } dockerContainersText := "Docker Containers" data = &pageData{ DisplayName: dockerContainersText, ParentContainers: []link{ { Text: dockerContainersText, Link: path.Join(rootDir, DockerPage), }}, Subcontainers: subcontainers, Root: rootDir, DockerStatus: dockerStatus, DockerDriverStatus: driverStatus, DockerImages: images, } } else { // Get the container. reqParams := info.ContainerInfoRequest{ NumStats: 60, } cont, err := m.DockerContainer(containerName[1:], &reqParams) if err != nil { http.Error(w, fmt.Sprintf("failed to get container %q with error: %v", containerName, err), http.StatusNotFound) return } displayName := getContainerDisplayName(cont.ContainerReference) // Make a list of the parent containers and their links var parentContainers []link parentContainers = append(parentContainers, link{ Text: "Docker Containers", Link: path.Join(rootDir, DockerPage), }) parentContainers = append(parentContainers, link{ Text: displayName, Link: path.Join(rootDir, DockerPage, dockerutil.ContainerNameToId(cont.Name)), }) // Get the MachineInfo machineInfo, err := m.GetMachineInfo() if err != nil { http.Error(w, fmt.Sprintf("failed to get machine info: %v", err), http.StatusInternalServerError) return } data = &pageData{ DisplayName: displayName, ContainerName: escapeContainerName(cont.Name), ParentContainers: parentContainers, Spec: cont.Spec, Stats: cont.Stats, MachineInfo: machineInfo, ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork, CpuAvailable: cont.Spec.HasCpu, MemoryAvailable: cont.Spec.HasMemory, NetworkAvailable: cont.Spec.HasNetwork, FsAvailable: cont.Spec.HasFilesystem, CustomMetricsAvailable: cont.Spec.HasCustomMetrics, Root: rootDir, } } err := pageTemplate.Execute(w, data) if err != nil { klog.Errorf("Failed to apply template: %s", err) } klog.V(5).Infof("Request took %s", time.Since(start)) } ================================================ FILE: cmd/internal/pages/pages.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package pages import ( "fmt" "html/template" "net/http" "net/url" "strings" httpmux "github.com/google/cadvisor/cmd/internal/http/mux" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/manager" auth "github.com/abbot/go-http-auth" "k8s.io/klog/v2" ) var pageTemplate *template.Template type link struct { // Text to show in the link. Text string // Web address to link to. Link string } type keyVal struct { Key string Value string } type pageData struct { DisplayName string ContainerName string ParentContainers []link Subcontainers []link Spec info.ContainerSpec Stats []*info.ContainerStats MachineInfo *info.MachineInfo IsRoot bool ResourcesAvailable bool CpuAvailable bool MemoryAvailable bool NetworkAvailable bool FsAvailable bool CustomMetricsAvailable bool SubcontainersAvailable bool Root string DockerStatus []keyVal DockerDriverStatus []keyVal DockerImages []info.DockerImage } func init() { containersHTMLTemplate, _ := Asset("cmd/internal/pages/assets/html/containers.html") pageTemplate = template.New("containersTemplate").Funcs(funcMap) _, err := pageTemplate.Parse(string(containersHTMLTemplate)) if err != nil { klog.Fatalf("Failed to parse template: %s", err) } } func containerHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { serveContainersPage(containerManager, w, r.URL) } } func containerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc { return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) { serveContainersPage(containerManager, w, r.URL) } } func dockerHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { serveDockerPage(containerManager, w, r.URL) } } func dockerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc { return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) { serveDockerPage(containerManager, w, r.URL) } } func podmanHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { servePodmanPage(containerManager, w, r.URL) } } func podmanHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc { return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) { servePodmanPage(containerManager, w, r.URL) } } // Register http handlers func RegisterHandlersDigest(mux httpmux.Mux, containerManager manager.Manager, authenticator *auth.DigestAuth, urlBasePrefix string) error { // Register the handler for the containers page. if authenticator != nil { mux.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager))) mux.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager))) mux.HandleFunc(PodmanPage, authenticator.Wrap(podmanHandler(containerManager))) } else { mux.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager)) mux.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager)) mux.HandleFunc(PodmanPage, podmanHandlerNoAuth(containerManager)) } if ContainersPage[len(ContainersPage)-1] == '/' { redirectHandler := http.RedirectHandler(urlBasePrefix+ContainersPage, http.StatusMovedPermanently) mux.Handle(ContainersPage[0:len(ContainersPage)-1], redirectHandler) } if DockerPage[len(DockerPage)-1] == '/' { redirectHandler := http.RedirectHandler(urlBasePrefix+DockerPage, http.StatusMovedPermanently) mux.Handle(DockerPage[0:len(DockerPage)-1], redirectHandler) } if PodmanPage[len(PodmanPage)-1] == '/' { redirectHandler := http.RedirectHandler(urlBasePrefix+PodmanPage, http.StatusMovedPermanently) mux.Handle(PodmanPage[0:len(PodmanPage)-1], redirectHandler) } return nil } func RegisterHandlersBasic(mux httpmux.Mux, containerManager manager.Manager, authenticator *auth.BasicAuth, urlBasePrefix string) error { // Register the handler for the containers and docker age. if authenticator != nil { mux.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager))) mux.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager))) mux.HandleFunc(PodmanPage, authenticator.Wrap(podmanHandler(containerManager))) } else { mux.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager)) mux.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager)) mux.HandleFunc(PodmanPage, podmanHandlerNoAuth(containerManager)) } if ContainersPage[len(ContainersPage)-1] == '/' { redirectHandler := http.RedirectHandler(urlBasePrefix+ContainersPage, http.StatusMovedPermanently) mux.Handle(ContainersPage[0:len(ContainersPage)-1], redirectHandler) } if DockerPage[len(DockerPage)-1] == '/' { redirectHandler := http.RedirectHandler(urlBasePrefix+DockerPage, http.StatusMovedPermanently) mux.Handle(DockerPage[0:len(DockerPage)-1], redirectHandler) } return nil } func getContainerDisplayName(cont info.ContainerReference) string { // Pick a user-added alias as display name. displayName := "" for _, alias := range cont.Aliases { // ignore container id as alias. if strings.Contains(cont.Name, alias) { continue } // pick shortest display name if multiple aliases are available. if displayName == "" || len(displayName) >= len(alias) { displayName = alias } } if displayName == "" { displayName = cont.Name } else if len(displayName) > 50 { // truncate display name to fit in one line. displayName = displayName[:50] + "..." } // Add the full container name to the display name. if displayName != cont.Name { displayName = fmt.Sprintf("%s (%s)", displayName, cont.Name) } return displayName } // Escape the non-path characters on a container name. func escapeContainerName(containerName string) string { parts := strings.Split(containerName, "/") for i := range parts { parts[i] = url.QueryEscape(parts[i]) } return strings.Join(parts, "/") } ================================================ FILE: cmd/internal/pages/podman.go ================================================ // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package pages import ( "fmt" "net/http" "net/url" "path" "time" dockerutil "github.com/google/cadvisor/container/docker/utils" "github.com/google/cadvisor/container/podman" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/manager" "k8s.io/klog/v2" ) const PodmanPage = "/podman/" func servePodmanPage(m manager.Manager, w http.ResponseWriter, u *url.URL) { start := time.Now() containerName := u.Path[len(PodmanPage)-1:] rootDir := getRootDir(containerName) var data *pageData if containerName == "/" { // Scenario for all containers. status, err := podman.Status() if err != nil { http.Error(w, fmt.Sprintf("failed to get podman info: %v", err), http.StatusInternalServerError) return } images, err := podman.Images() if err != nil { http.Error(w, fmt.Sprintf("failed to get podman images: %v", err), http.StatusInternalServerError) return } reqParams := info.ContainerInfoRequest{ NumStats: 0, } conts, err := m.AllPodmanContainers(&reqParams) if err != nil { http.Error(w, fmt.Sprintf("failed to get container %q with error: %v", containerName, err), http.StatusNotFound) return } subcontainers := make([]link, 0, len(conts)) for _, cont := range conts { subcontainers = append(subcontainers, link{ Text: getContainerDisplayName(cont.ContainerReference), Link: path.Join(rootDir, PodmanPage, dockerutil.ContainerNameToId(cont.ContainerReference.Name)), }) } podmanStatus, driverStatus := toStatusKV(status) podmanContainerText := "Podman Containers" data = &pageData{ DisplayName: podmanContainerText, ParentContainers: []link{ { Text: podmanContainerText, Link: path.Join(rootDir, PodmanPage), }}, Subcontainers: subcontainers, Root: rootDir, DockerStatus: podmanStatus, DockerDriverStatus: driverStatus, DockerImages: images, } } else { // Scenario for specific container. machineInfo, err := m.GetMachineInfo() if err != nil { http.Error(w, fmt.Sprintf("failed to get machine info: %v", err), http.StatusInternalServerError) return } reqParams := info.ContainerInfoRequest{ NumStats: 60, } cont, err := m.PodmanContainer(containerName[1:], &reqParams) if err != nil { http.Error(w, fmt.Sprintf("failed to get container %v with error: %v", containerName, err), http.StatusNotFound) return } displayName := getContainerDisplayName(cont.ContainerReference) var parentContainers []link parentContainers = append(parentContainers, link{ Text: "Podman Containers", Link: path.Join(rootDir, PodmanPage), }) parentContainers = append(parentContainers, link{ Text: displayName, Link: path.Join(rootDir, PodmanPage, dockerutil.ContainerNameToId(cont.Name)), }) data = &pageData{ DisplayName: displayName, ContainerName: escapeContainerName(cont.Name), ParentContainers: parentContainers, Spec: cont.Spec, Stats: cont.Stats, MachineInfo: machineInfo, ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork, CpuAvailable: cont.Spec.HasCpu, MemoryAvailable: cont.Spec.HasMemory, NetworkAvailable: cont.Spec.HasNetwork, FsAvailable: cont.Spec.HasFilesystem, CustomMetricsAvailable: cont.Spec.HasCustomMetrics, Root: rootDir, } } err := pageTemplate.Execute(w, data) if err != nil { klog.Errorf("Failed to apply template: %s", err) } klog.V(5).Infof("Request took %s", time.Since(start)) } ================================================ FILE: cmd/internal/pages/static/assets.go ================================================ // Copyright 2022 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // generated by build/assets.sh; DO NOT EDIT // Code generated by go-bindata. DO NOT EDIT. // sources: // cmd/internal/pages/assets/js/bootstrap-4.0.0-beta.2.min.js (50.564kB) // cmd/internal/pages/assets/js/containers.js (34.605kB) // cmd/internal/pages/assets/js/jquery-3.5.1.min.js (89.475kB) // cmd/internal/pages/assets/js/loader.js (65.121kB) // cmd/internal/pages/assets/js/popper.min.js (19.188kB) // cmd/internal/pages/assets/styles/bootstrap-4.0.0-beta.2.min.css (127.343kB) // cmd/internal/pages/assets/styles/bootstrap-theme-3.1.1.min.css (13.186kB) // cmd/internal/pages/assets/styles/containers.css (132.925kB) package static import ( "bytes" "compress/gzip" "crypto/sha256" "fmt" "io" "os" "path/filepath" "strings" "time" ) func bindataRead(data []byte, name string) ([]byte, error) { gz, err := gzip.NewReader(bytes.NewBuffer(data)) if err != nil { return nil, fmt.Errorf("read %q: %w", name, err) } var buf bytes.Buffer _, err = io.Copy(&buf, gz) clErr := gz.Close() if err != nil { return nil, fmt.Errorf("read %q: %w", name, err) } if clErr != nil { return nil, err } return buf.Bytes(), nil } type asset struct { bytes []byte info os.FileInfo digest [sha256.Size]byte } type bindataFileInfo struct { name string size int64 mode os.FileMode modTime time.Time } func (fi bindataFileInfo) Name() string { return fi.name } func (fi bindataFileInfo) Size() int64 { return fi.size } func (fi bindataFileInfo) Mode() os.FileMode { return fi.mode } func (fi bindataFileInfo) ModTime() time.Time { return fi.modTime } func (fi bindataFileInfo) IsDir() bool { return false } func (fi bindataFileInfo) Sys() interface{} { return nil } var _cmdInternalPagesAssetsJsBootstrap400Beta2MinJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xdc\xbd\x6b\x77\xe3\xb6\x76\x30\xfc\xbd\xbf\x42\xe2\xe9\xab\x21\x6a\x98\x23\x27\xa7\x3d\x3d\xd4\x70\xbc\x3c\xb6\x92\xf8\x8d\xc7\x76\x6d\x39\x69\xea\xa3\x7a\xd1\x22\x24\x21\x43\x01\x2a\x09\x8d\xc7\xb5\xd8\xdf\xfe\x2c\x5c\x09\x90\xa0\x6c\x4f\x92\xf3\x74\x3d\x5f\x66\x2c\x60\x13\xd7\x8d\x7d\xc3\xde\x1b\x6f\xff\xa9\xff\x0f\xbd\xde\x3f\xf5\x3e\x50\xca\x4a\x56\xa4\xeb\xde\xe7\x3f\x47\xc3\x68\xb8\x7f\x8f\x58\x1a\x7d\xd3\x0b\x97\x8c\xad\xcb\xf8\xed\xdb\x05\x62\xf7\x1a\x26\x9a\xd1\x15\x10\x9f\x1d\xd3\xf5\x63\x81\x17\x4b\xd6\xfb\x66\x78\x70\xb0\xff\xcd\xf0\xe0\x2f\xbd\xc9\x12\x59\xcd\x1d\x6d\xd8\x92\x16\xa5\xd5\x10\x66\xcb\xcd\x3d\x6f\xe2\x2d\x7b\xb8\x2f\xdf\x9a\x56\xdf\x2e\x8a\x74\xbd\x2c\xdf\xce\x28\x61\x05\xbe\xdf\x30\x5a\x94\xb2\x97\x33\x3c\x43\xa4\x44\x59\x6f\x43\x32\x54\xf4\x3e\x9e\x4e\x5e\xd2\xdc\x7d\x4e\xef\xdf\xae\xd2\x92\xa1\xe2\xed\xd9\xe9\xf1\xf8\xfc\x7a\x2c\x9a\x7b\xfb\x0f\x9f\xd3\xa2\x67\xe0\x92\xf9\x86\xcc\x18\xa6\x24\x64\x10\x41\x02\x9e\x82\x4d\x89\x7a\x25\x2b\xf0\x8c\x05\x23\x5d\xd9\xc3\xbc\x1a\x3c\xcd\x69\x11\xf2\xcf\x49\x32\x1c\x91\x77\x28\xca\x11\x59\xb0\xe5\x88\xec\xed\x81\x27\x5e\x8e\x13\x74\x4b\xa6\x23\x1c\x21\xb2\x59\xa1\x22\xbd\xcf\x51\x62\xff\xd8\x6e\xfb\x07\x10\x47\x33\x4a\xe6\x78\xb1\x91\xf5\xfd\x21\x0c\x3e\xa7\xf9\x06\x05\x98\xf4\xf0\x60\x10\xe2\xe8\xa1\xc0\x4c\xd5\x01\x78\x71\xff\x2b\x9a\xb1\x28\x43\x73\x4c\xd0\x65\x41\xd7\xa8\x60\x8f\x21\x83\x38\xfa\x84\x1e\x21\x06\x55\x85\x12\x34\x18\xa0\x68\x99\x96\x17\x0f\xc4\x40\x04\x19\x9a\xa7\x9b\x9c\x05\xe0\x10\x45\xea\xef\x18\x41\x92\x90\xc1\x80\xec\x00\x26\x06\x98\x8c\xf8\x9c\xca\x7a\x89\xc0\x93\x59\x10\x16\x32\xf0\x54\x20\xb6\x29\xc8\x53\x15\x31\x7a\xcd\x0a\x4c\x16\xd1\x2c\xcd\xf3\x90\x81\x68\x95\xb2\xd9\x32\x7c\xfb\xb7\x32\xbc\x4d\xf7\xff\xfb\x68\xff\x3f\xa6\x7b\xe0\x2d\xb8\x3d\x98\x46\x8c\x9e\xd1\x07\x54\x1c\xa7\x25\x0a\x41\x65\xda\xe3\x8d\xab\xe6\xee\x31\xc9\x26\x8f\x6b\x14\x17\x11\x22\x19\xcc\x50\x8e\x16\x29\x43\x56\xd1\x32\x25\x59\x8e\xe2\x7a\xeb\xc0\x13\x9e\x87\x28\x64\x11\x4b\x8b\x05\x62\x20\xc2\x65\xc8\x96\xb8\x04\x40\xb6\xd9\x63\x91\xfc\xe6\xe2\xfe\x57\xf5\x57\x11\xa5\xeb\x75\xfe\x28\xc0\x60\x5a\x2c\x36\x2b\x44\x58\x09\xaa\xaa\xb2\x36\x5d\xb4\xfb\x80\x49\x46\x1f\xa2\x7f\xbb\x21\x98\xa9\xf6\xfa\x07\x62\x69\x58\x92\xd1\x99\xf8\x30\x9a\x15\x28\x65\x68\x9c\x23\xfe\x2b\x0c\x0c\x7e\x05\x60\xa4\x91\x06\xf5\x30\xe9\x51\x80\xe7\x61\xc0\x31\x99\x6f\x67\x16\xf4\x13\xf6\xb8\x46\x74\xde\x63\x51\xc9\x1e\x73\x74\x8b\xa6\xaa\x8f\x27\x44\xb2\x98\xde\xa2\x69\x35\xd2\x9d\xd6\x43\x2b\xf9\x9c\x25\x26\x8a\x09\xe0\xa4\x7f\xa0\xc0\x7a\x48\x4e\x3d\xa2\x04\x85\x69\x34\xb9\x3a\x3a\xbf\x3e\x9d\x9c\x5e\x9c\xdf\x8d\xcf\x4f\xa0\xb5\x97\x38\xe9\x0f\x2b\x00\x4b\xc4\x26\x78\x85\xe8\x86\x85\x76\xe5\x76\x9b\x46\xac\xc0\x8b\x05\x2a\x26\x45\x4a\x4a\xcc\x2b\xc6\x24\x0b\x09\xa8\x20\x03\x90\xf7\x51\xf1\x11\x14\x49\xff\x00\xd2\xe4\xe9\x67\x74\xff\x09\xb3\x1a\x36\x0e\x1e\x1a\x25\x63\x92\x05\xf0\x23\xfd\x6f\x1b\x86\x99\xbf\x11\xaf\xbd\xb0\xeb\xa8\xf3\x69\x8f\x36\x60\x59\x67\x33\x15\x4c\x93\x27\x77\xe2\x71\x70\x5f\x36\x46\xb2\x40\xec\xe6\xf4\xc4\xc1\xa2\x8c\x3e\xb1\xbd\xe4\x7f\xfe\x27\x3c\x40\xff\xf2\x4f\x1f\x53\xb6\x8c\x8a\x94\x64\x74\x15\x02\x50\x3d\x2c\x71\x8e\x42\xb3\xe1\x0b\xc4\xd4\x6e\x7f\x78\x3c\xcd\x42\x06\x80\x5e\x7f\x56\xf1\xa6\xaf\x51\x8e\x66\x8c\x16\xdf\x15\x74\xa5\x00\x9d\xae\xd4\xe6\xf1\x76\x8e\x98\xa4\x78\x28\x0c\xb2\x94\xa5\xfb\x12\x89\x03\x30\x22\x83\x41\xf0\xa7\xa0\x9f\x24\x64\xbb\x0d\xdb\xc0\xcb\x02\xcd\x03\xb0\xdd\x06\x01\x18\xb1\xe2\xf1\xc9\xec\xbf\x1e\x24\x88\xe6\x58\xec\x98\x22\x54\xef\x87\x87\x24\x26\x9b\x3c\xaf\x66\xe2\x7c\x9a\x23\xdc\x13\x85\x15\x2c\xd0\x3c\xa7\x0f\xce\x38\xcd\x01\xa2\xf3\x79\x89\xd8\x0f\x88\xd3\xfb\x0a\xfa\x50\xc3\xf9\x0e\x71\x32\xa0\xa0\x42\x71\x6c\x41\x05\xcb\xcd\x7a\x4d\x0b\x56\x76\x7c\x66\x7a\xfb\x40\x69\x8e\x52\x12\x16\xa0\x82\xb8\xf4\x2d\x9f\x04\x0c\xd9\xed\x70\xba\xdd\x32\x10\x11\x9a\x09\x0a\x51\x41\x7e\x9e\x8e\x97\x68\xf6\xe9\x58\x50\xd9\xfa\x2b\x04\x09\xc4\x35\x0d\x2f\xf9\x71\xc4\xfc\x38\x2a\x0a\xbb\x2e\x28\xa3\xfc\xeb\x06\x71\x94\x44\x0d\xc3\x12\xc8\x5d\x2b\x12\x7c\x5b\x4e\x21\x4d\x08\xff\x2f\x4f\xe8\x60\x90\x46\x66\x94\x21\x05\x87\x01\x92\x7f\x07\x31\xff\x39\xc2\xf3\xb0\x4f\xd0\x43\xef\x0a\x2d\xc6\x5f\xd6\x61\x01\x22\x86\x4a\x16\xe6\x00\xb0\x65\x41\x1f\x7a\xbc\x6e\x5c\x14\xb4\x08\x51\xc4\xe8\xcd\x7a\xad\xc9\xe3\xde\x9b\xb8\x77\xb1\x16\x07\x3e\x78\xb3\x57\xee\xbd\x09\x7a\xeb\x82\x7e\xc6\x19\xca\x7a\x7c\xa0\xbc\x34\xe7\xa5\xf7\x1b\xd6\x43\x5f\xd6\x68\xc6\xac\x9a\x62\xef\x4d\x10\xbd\xe1\x14\x4d\x63\x66\x91\xe0\x10\x40\x14\xcd\x49\x84\x56\x9b\x9c\x13\x55\x7b\x23\x92\x12\xa6\x91\x77\x8b\x42\x30\x18\x84\x28\x42\x9f\x39\xe6\x97\x6b\x34\xc3\x69\x7e\xdb\xa4\x2d\xd3\x84\x84\x00\xc0\xb4\x0a\x01\x2c\x5a\x7c\x55\x23\xe7\x60\x80\x43\x6b\xad\x21\x02\x90\x88\x32\x48\x00\x64\x15\xa4\xce\x97\xe0\xc9\x82\x4d\xd4\x46\x49\x5a\x1b\xa2\xba\x06\x40\x7b\xfb\x66\x94\x94\xac\xd8\xf0\xd3\x97\x30\xc8\xa2\xbb\x3b\x51\x77\x77\x97\x20\x4e\x19\x2c\x74\x93\x44\x3c\x48\x73\x54\xb0\x00\x92\x84\x2f\xcd\x2d\x9b\x42\x9c\x3c\x1d\x9f\x5d\x5c\x8f\xe3\x60\x96\xd3\x12\x45\xf7\x65\xa4\x60\x44\xf1\x89\x2a\xcf\x9c\x8a\xd3\xe3\x1f\xef\x4e\x8e\x26\x47\x77\x47\x97\xa7\x1c\x00\xcf\x3e\x99\xfa\x48\x1c\xec\x74\x8d\x03\x3e\xc3\xa7\xa3\xb3\xf1\xd5\x24\xd6\xfd\x7e\x77\x74\x32\x8e\x83\x79\x9a\xa1\x00\x5e\xff\x70\xf1\x73\x1c\x94\x4b\xfa\x10\x34\xc6\xea\xb2\x5e\x4e\x7e\xa3\x3b\x85\x67\x09\xab\x34\x39\x31\xab\xa0\xf7\x9c\x44\x62\xa8\x89\x7d\x78\x58\xc2\xb6\x5b\xa7\x05\xc1\xce\x50\x22\xcb\x16\x88\x5d\x51\xaa\xc9\x5b\xc8\xc0\x48\x96\xab\xd3\x7c\xcc\xdb\x1b\x73\x54\x08\x11\xe7\xb4\x27\x52\x5c\xb8\x2c\x04\x7a\xa0\x2c\x04\xba\xf1\x02\xad\xe8\x67\xc3\x14\x11\xa8\x20\x89\x32\x5c\xae\x9d\xf1\x80\x27\x14\x49\xc0\x93\x94\xa5\xa1\x33\x2c\x18\x98\x05\x96\x1c\xa7\x9e\xb2\xa0\x58\x90\x34\x47\x9b\xb4\x69\x6c\x19\xf9\xc9\x71\xc8\x80\xc3\x37\x09\x97\xbd\x12\x14\x12\x70\x3b\x9c\x02\x88\xb7\x5b\xf1\x93\x01\xb9\x82\x25\x0b\x83\x28\xd8\xa3\x91\xd8\x3c\x05\x23\x46\xd0\x5a\x17\xcf\x20\x50\x24\x57\x0c\x47\x02\x83\x80\xc5\xac\x6b\x32\x49\x00\x24\xa2\x45\x67\xe1\x3c\xad\xf1\xa5\x18\x89\x4f\x25\xe4\x71\x9e\x96\x65\x48\x23\x8e\x3d\x00\x96\xdd\x87\x58\x7c\xb3\x4c\x4b\xfd\x01\x47\x3d\x70\x28\x4a\xb9\xb8\x50\x76\x8a\x0b\xa8\x66\x15\xd1\x5d\x86\x4a\x56\xd0\x47\xb3\x8e\x10\x81\x0a\x78\x49\x4a\x78\xf0\xcf\x43\x10\xcb\x9d\x6b\x7e\x25\xd0\xa1\x51\x9a\xb4\x58\x48\x86\x58\x3a\x5b\x86\xf5\x22\xa9\x15\x3c\xd1\x73\x0f\xb9\x3c\x12\xdd\xfd\xfa\x6f\x1b\x54\x3c\x9e\x12\x86\x8a\x79\x3a\xb3\xf0\xab\xa6\x3d\x62\x18\x88\xb7\xd6\x20\x01\x62\x9b\xb9\xcc\x04\xcb\x04\x8b\xa3\x1a\x5a\x88\x37\x2a\xb7\xdb\xb0\x4c\x38\x95\x66\x0a\xac\x05\xc4\x99\x03\x94\x44\x21\x48\x12\x2e\x62\x97\xb7\x64\x2a\xa1\x2b\x39\x40\x29\x76\x9e\xe0\x72\x85\xcb\x32\xf1\xb0\x58\x7b\xad\x85\x40\xbf\x96\x27\x4a\x9d\xaf\x90\x13\x39\xd1\x83\x6a\xb6\x82\x05\xa7\x9a\x9b\x3c\x87\xb7\x4f\x9f\xd0\x63\x1c\xfc\x34\xbe\xba\x3e\xbd\x38\x17\xa2\x4d\x9b\xab\x06\xb6\x6a\x17\x54\xd5\x94\xd3\xdb\xd0\xc2\xc4\x5a\x6c\xa0\x44\x2c\xb3\x4d\xd1\xe0\xd3\xc9\xe9\xf5\xc7\xd3\xeb\xeb\xf8\xcd\xad\x20\x66\x99\x9a\x89\xa2\x62\xd3\x37\x55\xa4\x20\x60\xda\x98\x6d\xc8\xd7\x2e\x05\x92\xf5\xdc\xb2\x69\x92\xb6\xf6\x4b\x57\x45\xc7\x16\xf1\x4e\x4d\x29\xa1\x9c\x9b\xe7\x78\xc6\x92\xb6\xb4\xa0\x5b\x25\xb0\xdd\x6e\x25\xf9\x51\xee\xa1\xfa\xf7\x1b\xc6\x28\x69\x90\xfd\xa3\xe3\xc9\xe9\x4f\xe3\x38\x48\x67\x0c\x7f\x46\x01\xfc\x70\x33\x99\x5c\x9c\xc7\xc1\x3d\x23\x01\xfc\xee\xe2\xf8\xe6\x3a\x0e\xe6\x74\xb6\x29\x83\x0a\x96\xc9\x93\x58\x9d\xc9\xc5\xf7\xdf\x9f\x8d\xef\x8e\x8f\xae\xae\x2e\x26\x7a\x79\x18\x5d\x2c\x72\xf4\x9f\xa6\x9b\xe9\x1b\x68\x01\xbb\x50\x1a\xa8\xe4\x50\xa7\xe7\x97\x37\x93\x38\xc0\x64\xbd\x61\x01\xd4\xe3\x89\x9a\x03\x8a\xf8\x88\x04\x33\xe9\xe4\x3c\xb2\xd1\x9a\xf5\xc8\xf1\xdf\x7d\x38\xbb\xb9\xb2\xc0\xc5\x6c\x3c\xe0\xbd\xfb\x7c\x53\xf8\x9a\xf9\xbd\xf8\x92\x9a\x7b\x6b\x63\xfa\x43\x48\xf8\x3f\x85\x3a\x95\xa6\xb9\x9a\x10\x97\x91\xb5\x96\x9c\x14\x73\x19\xab\x90\x0d\xd0\xf6\x67\x42\x0a\x2e\x23\xb1\xb2\x1a\x9a\x0a\xdd\x2e\x28\xd2\x0c\x53\x7e\x64\x69\x24\x04\x09\x5e\x13\xcd\xb8\xf8\x88\x32\x41\x2e\xdd\x96\x0c\xe9\xc4\x91\xdc\x19\x00\x18\x67\x21\x28\x2f\x91\xe8\x3d\x4d\x10\x17\xf0\x54\x8f\x0a\x86\x77\x99\xf2\xd6\x52\x97\x60\x9b\x46\x2a\x3c\x57\x4a\x2c\xe5\x5d\xd8\x0a\x01\x2e\xd3\xfb\x1c\x65\x5c\xce\x2f\x76\xd4\xd1\x68\xc6\x9b\x3c\xc3\x25\xe3\xf2\x0f\x4b\x31\x29\x9b\x5f\xef\x86\x50\x6a\xe7\xc8\x4c\x3f\xe9\xbf\x60\xfa\x10\x85\xb4\xa6\xcd\xc1\x6c\x99\x92\x05\x0a\x40\x45\x23\x81\x57\x21\xe0\x7b\x79\x50\x55\x64\x30\x70\xda\x8a\x4a\x47\x95\x49\x0b\x9c\xee\xaf\x0b\x54\x96\x28\x0b\xe0\x4b\x3a\x06\x90\x79\xf6\x47\xe2\x54\x73\x75\xbf\x4a\xec\x50\xe7\xd6\x2f\x77\xfc\x5e\x0c\xa7\xe6\x23\xba\xbb\x91\x94\x3b\x6c\x6e\xd3\x05\x0b\x31\x67\x3a\x72\xca\x8a\xeb\x60\xce\x75\x04\xc7\xf9\x23\x79\x03\x6d\xf2\x06\xe7\x3c\x2a\x42\x08\x1d\x89\xb3\xc5\xcc\x46\x9a\x32\x48\x6d\x77\xc4\xe5\x2e\x7b\x9b\x25\x9d\x03\x42\xf1\x15\x75\xf5\xd9\x57\x55\xc0\x43\xee\xa5\xae\xc6\xe1\xcd\xc2\x70\xd1\x44\x8c\xd9\x43\xfd\x9e\x1f\xb8\x92\xde\x2c\xd3\x52\x6b\x1c\xfc\x74\x8b\x11\xba\xc8\x27\xba\x83\x6f\xff\x53\x9e\x03\x4c\xc0\xe1\x3f\xbe\x95\x8a\x1f\x93\xa4\x06\x54\xff\x17\x19\xe2\xd2\xc3\x10\x67\x69\x41\x37\x25\xca\x39\x4b\xe4\x68\x56\xff\xc6\x09\x17\x7d\x09\xa4\x86\x55\xa6\xc9\x13\xe6\x4d\x7e\x4e\xf3\xf8\x9f\xd1\xb7\xf0\x13\x7a\xbc\xa7\x69\x91\xc5\xfd\x21\x2c\x73\x9c\xa1\xb8\x7f\x00\xd7\xe9\xa6\x44\x71\xb0\xa4\x9f\x51\x11\xc0\x87\x22\x5d\xc7\xfd\x61\x05\x73\xeb\xdb\x20\x24\x9b\xd5\x3d\x2a\xb6\xf7\x52\xe5\x07\x41\xdd\x54\xa0\xca\x02\xd5\x62\x10\xaa\x82\x6d\x29\xac\x8d\x20\xd0\x3d\x84\xb2\xc0\x6a\x44\x74\x66\x1a\xa8\xe0\x32\x79\x3a\x1f\xff\xfb\x24\x0e\x08\xfa\xc2\x02\x78\x79\x35\xfe\x29\x0e\x38\x4e\x06\xf0\x6c\xfc\xdd\x24\x0e\x72\x34\x67\x01\xbc\x3a\xfd\xfe\x87\x49\x1c\x08\xa3\x76\x50\xc1\x59\xf2\x74\x7d\x76\xca\xb5\x33\x31\x82\x60\x0f\x43\xfe\x5b\xfe\xe4\xbf\x7e\x1c\xff\x72\x72\xf1\xf3\x79\x1c\x7c\x42\x8f\x19\x7d\x20\xbc\xec\xe3\xc5\xcd\xf5\x78\x7c\x3e\x19\x5f\xc5\xc1\x8a\x2f\x20\xd7\x8a\x0a\x53\x73\x36\x3e\xe2\x0c\x5d\xd4\xe4\x28\xfd\x2c\x5a\x9d\x5c\xdc\x1c\xff\x20\xcc\x54\x8c\x6e\x66\x4b\x44\x44\xeb\x67\x17\x47\x27\x16\xa7\xce\x69\x2a\x34\x4e\xbd\x2f\x16\x67\xef\x94\x01\xda\xb0\x15\xdc\x24\x4f\xc7\x47\x57\x62\x2c\xb1\xb5\xe9\x4d\xd1\xc7\x99\xb9\x5e\x19\x0d\xbe\x8f\x19\x5a\xed\xcb\x75\x52\x2b\xe8\x56\xc9\xf5\x94\x6b\xee\xd6\xd8\x3b\xe0\xd6\xc8\xfd\x38\x9d\x8c\x3f\x36\x6a\x82\x0a\x66\xb5\x6c\x66\x64\x21\x59\x70\x27\x3f\x50\xa5\x91\xfb\xa1\x6a\xad\x59\xca\xc7\x75\x27\x87\x10\xb5\x47\x07\x7b\x91\x77\x60\xe7\x27\xa7\xc7\x47\x93\x8b\xab\x6b\xe7\x2b\x92\xe1\x59\xca\x68\x51\x06\x52\xc2\x53\xeb\x26\x05\x3c\xb1\x7a\x53\xd8\xb3\x7e\xed\x33\x3a\x55\xa0\x57\x1c\x52\x89\x82\x05\xce\x90\x75\x06\xa7\x6f\x2a\x38\xf7\xca\x59\x54\xd8\x4a\x94\xa4\xc5\x87\x57\x0a\xa6\xa4\xf8\x94\x3e\x59\x76\x99\x5c\x99\xb1\xc5\xc1\x34\x70\x79\xc9\x0f\x50\x96\xf4\x0f\x4c\xc9\x75\x8e\x33\x4c\x16\xa6\x48\x20\xa4\xb2\x10\xdb\xdf\xca\x4b\x8c\xda\x64\x20\xcd\x6d\x9c\xf2\xba\x0c\x93\x6b\x71\xb7\xc3\xa9\x19\x9e\x5e\xad\x71\x5d\xef\x91\xd6\xb2\xa8\x5e\x6d\xeb\xf3\x34\xcb\x84\x1e\xcd\xa5\x18\x44\x50\x51\x86\x40\x88\x98\xf3\x84\xb6\x45\xcc\x79\xc4\x37\xd3\x5e\xc3\xc6\x1c\xb5\x9d\x42\x6c\x4b\xb8\x8c\x38\x56\x80\x0a\xca\xef\x7e\x5e\x22\xf2\x13\x2e\xf1\xbd\x2b\xa3\xf6\x8d\x05\x78\x89\xb3\x0c\x11\x8f\x10\x82\xcb\x30\x88\x3f\xcb\x4f\x03\x30\x18\x04\x12\x32\xe8\x27\x1e\x89\xb6\x2c\xc3\x40\xc0\xe2\x1c\xb3\x47\x0e\x2e\x20\xf8\x08\x42\x31\x16\x8e\x7b\xaf\x98\x03\x47\x6a\xf9\x1d\xdf\x59\xd7\xec\xb3\xdd\x86\xcd\x7d\x1f\x6a\xf1\xa2\xbd\x01\xe6\x8c\xf0\xf5\x1f\x0c\x76\x58\x15\xc2\xd2\x7f\x55\xe0\xb6\x2b\xb7\x70\xf6\x38\xcb\x51\xd8\x1f\x02\x00\x67\x39\x4a\x8b\x53\x85\xaf\xa1\x8b\xbe\xc0\x87\xce\x7c\x5a\xe2\xfb\x67\xa7\x75\xd0\xfc\x7e\x30\x08\x5f\xdd\x1d\x70\x30\x3d\xaa\x9b\xea\xbb\xdd\x0d\x06\x8d\xd6\x92\x12\x31\xd3\x51\x7d\x65\x50\x6f\xf3\x35\x4b\x19\x3a\x34\x1b\x6d\xa1\x5a\x6c\x0a\x41\x74\x8f\xd5\x1a\x76\x0c\x04\x88\x7d\x66\xb4\xcb\x40\xe4\x3b\xfc\x5d\x9b\x6d\x91\x52\x21\xd0\x48\x29\xd5\x1c\xee\x53\x86\x56\xa7\x24\x43\x5f\x42\x4f\xa3\xd2\xc2\x1d\xb2\xf7\x16\x49\x52\x37\x0e\xfb\x07\xdb\x2d\x7b\x37\x04\x5c\xaf\x6a\x20\x2e\x68\x0d\x85\x12\x14\xce\x22\x4e\x3e\x61\x5b\xa6\xe1\xfa\x62\xc8\x40\x05\xa4\xae\x85\xe7\x21\x4e\x92\x84\x01\x5b\xd4\x16\x28\x1f\x02\xf8\x99\xe2\xac\x67\x61\x1b\x50\x17\x99\xec\x3d\x3e\x94\xa7\x3c\x96\x07\x65\x64\x9f\x9d\x12\x5a\xe3\xbf\x65\x53\x50\xf1\xe5\xf5\x29\x0e\xad\x81\xcf\xe7\x21\xe6\xc2\x5c\xa7\x42\x61\xa8\x62\x8b\x5e\x2b\x32\x6a\x95\x20\x0f\x9d\xf6\x10\x75\x83\xec\x4e\x99\xa6\xde\x2f\xa2\xfe\x2d\x5a\xac\x0f\x59\x4d\xcf\x7d\x6a\x0d\x49\x50\x84\xbe\x30\x44\xb2\xf0\xa9\x82\x29\x9f\x5c\x19\x35\xae\x5d\x38\x8f\x82\xb9\xb0\x67\xce\x3d\x64\xbb\x2d\x7d\x5a\x18\xab\xd0\x5c\xcb\x81\x1e\x0a\x4b\x49\x38\x8b\x94\xec\xe5\xb3\x51\xb2\xe8\x4e\x09\x64\x21\xe2\x62\xb6\x12\x41\x39\xc2\xd8\x3d\x08\x7c\x19\x0c\x42\x7f\xfb\xb5\x1c\xe7\xef\x42\x62\x1b\x52\xfa\x85\x82\x17\xd2\x9d\x1f\x5e\xe2\xa2\x1c\x0f\x25\x82\xad\x96\x2c\x2d\x58\x80\x49\xcf\xd0\x08\xfd\x87\xda\x91\xae\xb9\x6b\x79\xd1\x3e\x28\xcc\xe0\x3f\x73\x98\xf6\x60\x20\x28\x9f\xbe\xe4\x75\x2b\x9b\xc0\x89\xef\x3a\xd8\x3b\x0b\xf8\xcf\xc3\xe1\x1e\x6b\x13\xa5\x4a\x92\x25\xbd\x01\x49\xe3\x96\xbe\xff\x56\x58\xb6\xb6\x0c\x7d\x61\x69\x81\xd2\xb7\xd8\x28\x45\x42\xc1\x8a\x58\xba\x38\x4f\x57\x08\x80\xf2\x01\x8b\x4b\xca\xe8\x61\x89\x67\x4b\xf0\x34\x4b\x4b\xd4\xfb\xf6\x2f\x71\x5b\x97\x94\xf8\xcc\x4b\x43\x30\xba\x2f\x50\xfa\x69\x24\x81\xff\xda\x09\x2c\xf9\xab\x02\xd6\x0e\x0f\x72\x92\x95\x3e\x01\x86\xe8\xf9\xac\xb5\xf6\x71\x46\xd1\x2a\xfd\x84\x8e\x8a\x22\x7d\x0c\x85\xd1\x7a\x9d\x16\x88\xb0\xb0\x96\x65\x38\x59\x75\x48\x40\x84\x79\xc3\x17\x73\x61\x06\xaf\xbb\xfb\xf0\x78\x82\x0b\x24\xfa\x6a\xdc\x83\x29\xba\x9e\x24\x89\xa4\x60\x10\xab\x1f\x9c\x8e\xc1\xd2\x47\xaa\x11\x80\x45\xe2\xa3\xc9\x9c\x5e\x87\x78\x30\x18\x26\x49\x52\x6e\xb7\x64\x30\x28\x93\x24\x29\x80\xe1\x6c\x6a\x4f\xb9\x12\xa5\x09\x2c\x1a\x49\xe3\x5a\x58\xee\x85\x75\xc7\x87\xfb\x07\xf1\x01\x00\xff\x5f\xbb\x17\x25\x84\xed\x1f\x24\x49\x42\x0f\x1d\xca\xea\x19\xd1\x34\xb6\x21\xe8\x54\xac\x89\x92\x29\x38\x49\x6b\xdd\xab\x70\x09\xb8\x9b\x47\x81\x8e\x05\x79\x19\xf3\xe3\xcb\xa6\xef\x6b\x24\x3f\x1a\xc3\xa7\x02\xe5\x29\x43\xd9\x44\x20\x69\xcc\x60\xa6\xf7\x29\x26\x70\x5e\xd0\x55\x5c\x42\x46\x63\x5c\x01\xd7\x0d\xc3\xb6\x4d\xe9\xcb\x70\x00\x0b\x31\xbf\x12\xb1\x23\x41\x9b\x4f\x35\x21\xf6\xdd\x82\xd4\x9c\xb3\x49\xae\x6b\x4e\xd4\xae\x72\xa7\xe6\x9a\x1d\x37\xba\x74\x54\x0b\x0b\x9e\x36\xa2\xd9\x12\xe7\x59\x81\xc8\xad\x77\x89\xa7\x23\x21\xfb\x12\x10\xa5\x59\xd6\x68\x58\x1e\x21\xc1\x56\x7d\x7b\x06\x0b\x48\x61\x2a\x3d\x57\xf2\x97\x8a\x24\x70\xee\xdb\xd2\x1c\xc0\xbb\x84\x6c\xb7\xb9\xb6\x2f\xb6\x0f\x52\xc8\x38\x23\x5a\xf8\xbe\xbe\x03\x70\x95\x68\x67\x83\x86\x44\xc8\x0f\x49\x7d\xdc\x0e\x43\x9c\x6c\x22\xae\xe8\xc2\x22\xd9\xc8\x13\x48\x93\xa5\x28\x01\xb1\xa8\x14\x1a\xb2\xa8\x15\x47\x92\xd7\x8a\x22\x00\xef\xf8\x42\xdd\x59\xe6\xad\x4d\x6d\x3d\x6e\x69\x5d\x42\xbe\xe9\x71\x4a\xe9\xdc\xba\xd6\xa7\x20\xbc\x83\xd4\x7f\xef\x3a\x18\xe4\x83\xc1\x5d\x4b\x45\x48\xfa\x43\xb8\x52\xeb\x63\x58\x84\x14\x7c\xba\x30\x30\xbc\x93\xc8\xb1\x6e\x1c\x84\xe6\x39\xb8\xb3\xce\x01\x95\xe7\x60\xce\xcf\xc1\xa2\x02\xa3\xdd\xd7\x90\x1d\xf6\xdd\x8d\x3c\x6f\xe0\x30\x14\x2b\x66\x50\xab\xe0\x32\x86\x74\x4f\xe1\xbb\x86\xc2\xdc\xaa\xe4\xb2\x97\x03\x8d\x15\xc4\xee\x3b\x4d\x7e\x7e\xee\x1a\x16\xf9\xbd\xa0\x17\xec\x15\x3e\x9c\x96\x2d\xfa\xce\x91\xfc\x46\xfc\x8b\x85\x51\xd2\x51\xa2\xfd\xfe\x55\x86\x48\xa4\x1e\x0a\xb1\x06\x15\x1c\x76\x5e\xa9\xfe\xcb\x70\x08\x40\x1c\x76\x0e\xa7\xb9\x18\x75\xb9\x47\xc5\xef\xa4\x52\x6b\x00\x0c\xd2\x28\x29\xba\xaa\x20\xdd\x61\xf7\x66\xaf\xb6\x7b\x73\xc1\xb1\x21\x4b\x3a\xf5\x00\x8c\x02\x2a\x7c\x3e\x82\xc4\xf8\xc9\x0d\x06\xe6\x8b\x12\x32\x89\xa6\x45\x12\x48\x0b\xa0\x05\x77\xc8\xe2\x32\x12\x24\x88\x9f\xe4\xda\xaa\x4e\xa5\xcb\x5f\xd3\xae\x4e\xa4\x35\x5d\x5a\x23\xad\x66\x00\x96\x8a\x87\x39\x96\xad\x9e\x0a\x79\x93\x54\xfb\xf4\x99\x1a\x7c\x5b\x4c\x5b\x3e\x3e\x6f\xce\x69\x6f\x85\xd8\x92\x66\x3d\x92\xae\x50\xa6\x5d\x75\xde\x80\x11\x87\x0f\x41\x25\x7a\x2a\x2d\x7d\x33\xc4\xe6\xdc\x62\xbd\x19\xc2\xc8\x4f\xa3\x3b\x3e\xf8\xa3\x35\x3e\xce\xf1\xec\xd3\x0f\xd2\xb3\xb1\xa5\x0f\xe2\x1d\x3e\x10\x7c\x05\xc4\x02\x69\xe7\x26\x14\x62\x73\xa3\xc6\x4f\x6a\xe1\x9c\x4e\x6d\x38\x54\xbe\x50\xa9\xb3\x7d\x02\x58\xee\x5c\x73\x23\x61\x2e\xe9\xaf\xc7\xdd\x4d\x1b\xc5\x02\x30\xe2\x73\x4d\xcd\xc4\x85\x1a\xdf\xc6\x38\x6d\xe3\x2f\x00\x4c\x01\xcc\xd5\x18\x15\x42\xf1\xcd\xca\xa5\x3b\x90\x2b\xf6\x55\xe2\xbe\x9c\xfe\x86\x3b\x11\x28\x3f\x52\x2d\x76\x7c\xd4\x4b\xc5\xe5\x09\xed\xbe\x3c\x99\x35\x2f\x4f\xb2\xa8\x36\x1b\x72\xb6\xe9\xd9\x51\xbe\x9c\xd2\x0d\x55\x35\xe1\x58\x86\x5d\x8a\xa6\x9a\xbb\xe2\x54\xd4\x7b\x08\xb5\x11\x00\x8c\xe6\x1d\x6b\xcb\x20\xd3\xfb\x56\xd9\xb7\x14\x6d\x78\xef\x2d\xc5\xfc\x75\xb7\x14\x14\xb6\xdb\xad\xe0\xbc\x0a\x01\x9c\xf9\x6e\x29\x68\x9e\xa7\xeb\x12\x99\x5b\x0a\xf3\x1b\x9b\xdb\x09\x9a\x3c\xc9\xcb\x98\xb8\x3f\x84\x52\x18\x8f\x03\xe9\x16\xaa\xca\xeb\xbb\x05\x5d\xad\xef\x10\x34\x25\x0c\xc4\x45\x45\xed\x8f\x15\x39\x7d\xf1\xf2\x73\x59\x41\xdc\x9a\x1f\x84\xf5\x77\x89\x33\xd4\x2a\x3f\x19\x9f\xc7\xca\x18\xe8\xd6\x75\x9b\xef\x15\x88\x6d\xbe\x5f\xda\xa3\x0a\xe0\xf1\xc5\xd9\xd9\xd1\xa5\xf0\x55\xab\xdb\x93\x65\xa7\xe7\xdf\x9b\x52\x4e\xb2\x0c\xec\x49\x0d\x9c\xc9\x6b\x8e\x9f\x4f\x4f\x26\x3f\xc4\xc1\x03\xce\xd8\x32\x80\x3f\x8c\xa5\xb5\x7f\x89\xd4\x45\xc8\x46\x5b\xdf\xaf\xe3\x20\xe2\xfd\xc2\x5e\x64\x37\xbc\xc3\xb5\xc1\x8c\x6a\xfa\xa6\x82\x99\xd7\xa2\x8d\x1d\x8b\xb6\x25\x2e\xd8\x76\xe8\xda\xa9\xe0\x85\x06\x68\xc5\xc9\x84\x5a\xd6\x50\xd1\x3a\x87\x78\xbb\x2c\xd0\x3c\x09\xfe\xf4\x66\x8f\x45\x38\xdb\x7b\x13\x4c\x61\x27\xa8\xe5\xab\xeb\x7c\xf1\x06\xd4\x3e\xdf\x9c\xe1\x6d\x1c\x67\x05\x58\x24\xc3\x51\xf1\x0e\x1b\x35\x49\xc7\x0e\xd0\x84\x93\x7f\x98\x76\xd3\x6a\x0a\x46\x9c\x7a\xf5\x93\x44\x3b\x13\xcc\x71\xce\x50\xc1\x35\x4e\xed\xe0\xab\xc5\x60\x7b\xf2\xd1\x7a\x53\x2e\x43\x0a\x2a\x59\x25\x11\xbe\x69\x09\xe1\x65\x87\x66\x2d\x2f\x95\x02\x1b\xb7\x2c\x55\x0a\x54\x9b\x9d\xd3\x2c\x3b\x2a\x70\x7a\x44\xb2\x63\x8d\x50\x92\x55\xb8\xf6\xaf\xf6\xa0\x1a\x36\x4d\xb9\xbe\x6a\xf4\xf2\x87\x32\xed\x67\x09\x6e\x9b\xf6\x33\x8f\xf7\x48\xb7\x50\xb9\x94\x8e\x71\x72\x7a\xfc\x64\x86\xca\x27\x8d\x63\x72\x08\x2a\x98\x89\xbf\x3a\x8c\x52\xb5\x28\xde\x40\xcd\xc1\x60\x87\xa3\x82\xea\x53\x71\x55\x48\x47\x46\x8f\x93\x0b\x38\x18\x84\x61\xd1\xb4\x1c\x58\xf5\xc0\xa8\x5f\xa1\xf5\xa7\x96\xe5\xae\x01\xd0\x7b\xbe\xdd\x86\x85\x34\x57\x03\xd8\xe7\x2c\x3b\xa4\x89\xcd\x11\xc1\x60\x40\x5b\x43\xb7\xd8\xb7\x14\xef\x73\x39\xdc\x91\x8c\xa3\xf0\x8b\x84\x29\x80\xfd\xd4\xab\x78\x80\xa7\x42\x48\x29\x3b\x58\xb5\xa0\x88\x01\x80\x74\xbb\xb5\x46\x07\xe5\xc0\x85\x10\x37\xab\x8f\xf2\x09\x5e\x21\x52\x8a\x9d\x18\xb5\x86\x63\xcb\xbc\xcb\x48\x93\x34\x4b\xe0\x35\x85\xa7\xe7\xdf\x37\x6e\xa3\x54\x90\xc5\x6c\x9a\x0c\x3d\x38\xa9\x56\xb4\xd6\x4f\x1c\x84\xed\xe8\xf8\x04\x44\x29\x63\x85\xf2\x61\x41\x5f\xd6\x29\xc9\x84\x13\xcb\x50\xf5\xcd\x15\x00\x7b\xed\xc3\xfe\x50\x4e\x38\x6b\x60\xef\x73\x73\xe4\xd3\xf1\xcc\xd2\x9d\xba\x74\x01\x65\x9e\x19\x07\x01\x64\x9e\xc1\x1c\x08\x59\xcd\xb3\xdd\x12\x25\xce\x41\xc5\x91\xa2\x53\x99\x93\x88\x34\x4f\x82\x72\x56\xd0\x3c\x0f\xf6\xc2\xd9\xed\x70\xda\xf0\x63\x9f\x71\x41\x7c\x86\xc2\x03\xe0\xd9\x4f\xaf\x92\x96\xed\x50\x7e\xba\xb6\xd4\x29\xbe\x9d\x4f\xf7\x82\xf5\x97\x40\x4a\xd3\x99\x10\x00\xf9\x41\x5f\x3a\x36\x89\x97\x1e\xf4\x17\x9e\x73\x62\x9d\x27\x2e\x07\xec\x3e\x4f\x04\xc0\x3e\xe9\x38\x4f\x0d\xdb\x96\x7d\x20\x0c\x21\x71\x17\x00\x37\x16\x80\x73\x91\x0f\x74\x43\xb8\xa6\x77\x9c\x63\x44\xd8\x15\x9a\xb1\x10\xdc\x62\xb9\x30\xb5\x3e\xdd\xb8\xa6\x6b\x8d\xd7\x7f\xb0\x3a\xcf\xa1\x5b\xae\xf0\xb1\xeb\xac\x01\xcd\x29\x25\x5b\xec\x84\xb3\xf9\x64\x1b\xe8\x35\x8c\x33\x14\x9c\xb3\xb9\x7f\x9c\x2a\x51\xef\xe9\xea\x3c\xdf\x07\x40\x71\xd4\xce\x03\xee\x88\xaf\x2f\x3a\x7b\xaf\x3c\xf7\xf5\x51\x95\xd2\x25\xa8\x46\x1d\xa8\x11\x04\xdd\x6e\xe1\x87\x2f\x3b\x92\xb3\x1d\x47\x32\x9e\x49\x0d\x2b\x6b\x4d\xd2\xbd\xaa\xf5\x4a\x78\x8c\x7f\xf7\x3a\x07\x3d\x02\x3a\xaf\xcf\x94\x78\xb3\xfb\x42\xcd\x91\x0d\x9d\x0b\x34\x77\x68\xf2\x42\x2c\x7b\xd5\x85\x18\xe5\xa3\x33\xee\xad\xda\xba\xa8\x0b\xba\xee\xca\x52\x71\x57\x96\xb9\xa7\xdd\xa7\x35\x75\x52\xa2\x59\x24\x84\x78\x70\xa8\xfe\x88\x67\x91\x94\xe3\x75\xb3\x52\xa8\xf3\x13\x3f\x48\xc4\x5c\x47\xa5\x15\xc9\xe4\x11\xfb\xc0\x61\x48\x7c\x92\x23\xf4\x86\x34\xb6\xe1\xa2\x5f\xff\x8b\x0b\x08\x83\x81\xbf\x99\xdb\xe1\x14\x80\x98\x18\x93\xb0\xdb\xb7\xbe\x97\x2e\x92\x6e\xf9\x5d\x94\x2b\x14\x08\xde\xec\x79\x9a\x11\x22\x7a\xad\x9b\x13\x65\x6f\x2e\x9a\xca\xb2\x88\x5a\x62\x3b\x24\x5c\x2c\x16\x55\x1a\x42\x6d\x6a\x43\x00\xbc\x25\x53\xae\x37\xcb\x0d\xed\x6a\xa0\x61\x19\x97\x2e\xc0\xc6\x4a\xd6\x26\x51\x23\x62\xc9\x27\x0d\x77\x43\x8b\x5c\xc1\x3e\xee\xa0\x58\x18\x54\x15\xec\x18\xf5\xeb\xe2\x66\x8c\x13\xf7\xa1\x0a\x97\x91\x51\x85\xb0\x2d\x01\xbe\xca\x3c\x58\x9a\x38\x8c\x22\x29\x8d\x89\x30\x6d\x9c\xae\x52\x9b\x98\x7c\xb6\x41\xe5\x8c\x50\x0c\x06\xa9\xd1\x29\xde\x72\xe1\x7e\xcb\x19\xbf\x76\xc0\x04\xc2\xce\xa4\xd0\x87\x53\xe1\x42\x4a\xd1\xe8\x81\xeb\xa2\x22\x22\x18\xe8\x7e\x08\x2c\x00\x80\x6d\xfb\x62\xa7\xd5\xaf\xb8\x65\x2f\xb3\xfa\x31\x69\xf5\xe3\xf0\x9c\x7a\x0a\xa7\x5d\xfc\x87\x1b\xa8\xa8\x30\x50\xe1\x6e\x03\x55\xde\x34\x50\x39\x0a\xac\xe3\x1d\x1b\x1c\x89\x3b\xf5\x68\xb6\x29\xf8\xd1\x9a\x38\x37\xb8\x83\x41\x87\xd7\x2f\x76\xb6\x79\xa7\x61\x12\xb5\xcf\x65\xc3\x88\x05\xcb\x84\x69\x54\x39\xd4\x3e\xbf\xb1\x0a\xd0\x01\xa3\xac\xd3\xc4\x55\xba\xb6\xad\x36\xa0\xd7\xb6\x95\xbd\xce\xb6\x85\x61\xbb\xdd\x0a\x66\x55\x08\xe0\xc6\xfe\xac\x03\x95\x48\x0b\x8f\x82\x3a\xb7\x42\x56\xd0\x75\x46\x1f\x48\xaf\x40\xff\xb5\xc1\x05\xea\x5d\x52\x2e\x72\x47\xbf\x5a\xe9\x16\xd6\xba\x28\xa2\xc5\x02\x04\x40\x85\xad\x07\xfa\x5b\xe1\xda\x7b\x5f\x46\xf5\x6f\x2a\x5c\x7d\xb1\x38\x75\xd2\x98\x96\x27\x56\xf0\x6a\xf0\xed\xbf\x6e\xff\x3c\xdc\x7e\xf3\x97\x00\xc0\x65\xf2\x54\x1b\xbb\x82\x3d\xda\x30\x71\xf1\x12\xcb\x50\xa5\x7e\x69\xa3\x19\xff\x2d\xf0\x4c\x59\xbb\xcc\x6f\x9f\x19\x4c\x0f\xcf\xf2\x78\x55\xde\x1f\x16\xb4\x72\x38\xe8\x86\xbf\xb9\x74\xa1\x37\x6b\x3f\xac\x30\x88\x9d\x9c\x5e\x1f\x7d\x38\x1b\x9f\xc4\x75\x88\x84\x3d\x1b\x78\x72\x75\x71\x79\x73\x19\x8b\x95\xdc\xac\x03\xf8\x71\x7c\x7e\xa3\x7c\x64\x75\x8b\xfb\x2b\x44\x36\xda\x47\x96\xd7\x4b\x3f\x59\xb7\x5a\xf8\xc9\x0a\x03\xdb\x0e\x1b\x9a\xd9\x9e\xe9\x1b\xf8\xdd\xc5\xd5\xc7\xbb\xe3\x1f\x4e\xcf\x4e\xe2\xc0\x0c\xbe\x37\xa7\xc5\x4a\x76\x62\x95\x8a\x1e\x02\x78\x7e\xf4\xd3\x87\xa3\xab\xbb\xf3\xa3\x9f\xe2\x20\x22\xe9\xe7\xfb\xb4\xd8\x27\xe9\xe7\x00\xfe\x74\x7a\x7d\xfa\xe1\x4c\x5e\xb1\x5e\x37\xbf\xeb\xd5\x3f\x31\x43\xab\x98\x50\x16\x46\x7a\x2d\x80\xf4\xc8\x9d\x5c\x5c\xc6\x01\xa3\xeb\x7d\xe9\xc8\x02\x27\x17\x97\xca\x89\x79\xbd\x2f\x62\xf4\x3f\x5c\x4c\x26\x17\x1f\xe3\xe0\x9e\x32\x46\x57\x1a\x4c\x96\xca\xa8\x7c\x59\x21\xa3\xf6\xe7\xc9\x93\x8c\x32\x8f\x87\x70\x9e\x63\xe9\x2d\x7e\x67\x0a\x8d\xaf\xb8\xb2\xd4\xea\xf3\x03\x02\x09\x6d\xb9\x7b\x2f\xbc\x76\xc6\x54\x85\x14\x7b\xcd\x89\xf2\xa8\xbc\xc0\xc3\x15\x69\xd9\x93\xaf\x52\x5d\xfb\x11\x91\x8d\x26\x5e\xb5\x3b\xe1\xb9\x58\x6e\x05\x95\x21\x86\x66\x4c\x16\x19\x98\x2e\x97\xd6\x45\x92\xb6\xed\x5e\x0b\x8f\xdd\xab\x56\x5b\xb5\xd4\xaf\x77\x69\xa7\x81\x6a\x16\x69\x14\x07\x9a\xa4\xa6\x96\x98\xd8\xa4\xc5\x96\x82\x88\x8d\x7c\xc6\x57\xc0\x69\xd2\x18\x91\xd2\xe8\x4e\x78\x1d\xf1\x55\x29\x43\xc0\x85\x12\xc5\xe2\x9b\x9e\x14\x76\xdb\x95\xe5\x79\x21\xa5\x1e\x58\x6a\x1d\xda\x71\xa0\xe8\x17\x3b\xf4\x66\xea\x2a\xc2\x23\x57\x9a\x9a\x45\xf2\xe8\x02\xcb\xf1\xab\x35\x0f\x7d\x5a\x85\x5e\xb8\x03\x46\x5e\xf0\x03\x61\x74\xd3\x1e\xae\x06\x93\xd0\x43\x8f\x84\xd4\x42\x16\x58\xdb\x57\x05\x88\x42\x28\xf0\x2a\x87\xb0\xbe\x13\x92\xbc\x89\xea\xd3\x0d\x2c\xf9\x30\xb8\xa7\xd9\x63\xe0\x18\x11\x29\x09\x65\xd4\x81\x0c\xc7\x10\x88\x8e\x22\x42\xe9\xba\x69\x51\xd1\xa1\x5b\x0d\x5d\xb2\x1d\xb1\xe5\x5a\xbb\xdc\x95\xb2\xc5\x53\x85\x18\x50\x6e\x63\xbb\xc2\x6c\xad\xbb\xf9\xe7\xb0\x04\xd2\x6e\xb3\x78\xa5\x7e\x88\x3d\x66\x0c\x3a\x9f\x87\xd4\x17\xce\x65\x1f\x67\xf1\x5b\x19\x0b\xec\xdd\xd4\x76\x75\xc5\x50\x55\xd4\x72\xd8\xdc\x72\x21\x05\x2f\xa2\xcd\x3a\x4b\x19\xf2\x78\x6d\xef\xa4\x07\xcf\x77\x5b\xce\x96\x28\xdb\xe4\xe8\x46\xb4\x1f\x02\xde\xd7\x8b\x9d\x2b\x7d\x9e\x84\x4b\x29\xeb\x39\x0e\x8b\x9e\xc0\x63\x14\x95\x8c\xae\x2f\x0b\xba\x4e\x17\xa9\x6c\x59\xf8\x0d\x2a\x33\xbd\x1c\xc7\x2b\x54\x64\xe9\x55\x50\x8b\x55\x91\xea\xaa\xbd\x69\x4a\xd4\xef\x74\x31\xed\x6a\x69\x22\xb2\x42\x10\x3d\x30\x8b\x38\xfb\x49\xa7\xc0\xd9\x57\x91\xc1\x91\x85\x35\x02\xaf\x85\x1a\xb9\x11\x64\x81\xab\x44\x95\xe3\x28\xc8\xc1\xf4\x60\x2e\xf3\x74\xd6\x1a\x8a\x2d\xd4\x5a\xf3\xd7\x9e\x84\x90\x24\x59\x24\xf9\xe6\xc8\xca\x69\xd4\xa4\x69\x5c\x3d\xcf\xa2\xc9\xc5\x25\x7c\x01\xd9\x12\x5a\xb8\x80\x1e\x9f\x9f\x00\x10\xbf\xfc\x13\xc3\xc0\xf5\x12\xdb\x98\xfc\x12\xa3\x45\x9d\x51\x41\xca\x23\x41\x7d\x83\x65\x56\xc9\x22\x91\x9d\x36\x8b\xa7\x6a\x14\xe8\x3a\x4b\x37\xb3\xb5\x7e\x29\x3c\x1c\x92\x68\x4e\xbc\x88\xa9\x00\x5c\x47\x14\x53\x0a\x59\xa3\xa1\xd0\x54\x81\xed\xf6\x49\x28\xf9\xb1\x2e\x4a\x3c\x1d\x2b\x8d\xe7\x69\xad\x37\x3d\xae\x99\x80\x2e\x0a\x01\x5c\xd1\x0c\xcf\x31\x2a\xca\x58\x4b\x3b\x44\x0a\x35\x4f\x88\x08\x5e\x1e\x3b\x6d\xf3\x2a\x2b\xb1\x8b\x4b\x5d\xc4\x55\x8c\x69\x50\xe6\xb9\xba\x66\x8f\x39\x4a\x4c\x63\x7d\xf7\x8b\x4a\xa4\xb2\x68\x07\x0b\xbe\x4a\x7b\x27\xae\x73\x0f\xe6\xaa\x59\x5b\x45\x3f\x64\xc2\x56\xc0\x99\xba\xcc\x6a\x24\x72\x03\xf8\x7d\x72\x30\x24\xaf\x53\xbd\xc9\x2b\x55\x6f\x52\xab\xde\x8e\xc0\xd2\x72\x5a\x66\xdb\xed\xb7\x9c\x34\x4b\x5f\xe4\xc1\x20\x94\xfa\x43\x20\xca\x78\xe7\xdb\xed\x5f\x13\x53\x0f\x40\x9d\x28\xce\xbd\xe1\x73\xef\x82\xf9\x0a\x0d\x47\xe5\x3b\x6d\xd8\x19\x95\xda\xc8\x5d\x74\x12\x21\x72\x5b\x4e\x01\xa4\x09\x92\x7f\x99\xb5\xce\x9b\x82\x15\xaf\xae\x54\xa4\xbb\xbc\x6d\xa2\xf2\x68\x4b\x79\xaa\x68\xcb\x6d\x83\x41\x3f\x64\x7c\x6e\x52\x21\x4b\xf4\xdc\x06\x83\x97\xfa\x6c\x6f\xb7\x6a\x5d\xac\x6f\xed\x75\x19\x0c\x50\x1d\x7b\x5e\x40\x13\x54\x6b\x6e\x91\x6a\xfe\xcf\x35\x4b\x98\x2b\x0b\x80\x16\x0f\xe6\x00\xce\x3b\x32\xce\x84\xaf\xf2\xa9\xf7\x89\x47\xf3\x79\xb7\x7c\xc4\x17\x73\xb7\x00\x14\xcc\xd3\xbc\x44\x01\xc7\xe0\xcc\xb5\xe3\xd7\xc2\x4f\xe1\xad\xf0\x08\x3f\x52\x91\x86\x39\x50\xe2\x4f\x07\x32\xb4\x8d\x76\x70\x97\xab\x97\x31\xf8\x60\x41\xc6\x95\xa3\x17\x80\x64\xbb\x65\x8a\xd1\x9c\xd3\x0c\x89\xee\x94\x13\xd2\x8f\x52\xa7\xf6\x39\x96\x89\x98\x9f\x7e\xae\x31\x41\x6e\xf0\x76\xfb\x56\x06\xa7\x77\xa2\xc8\x60\xf0\xed\x37\x35\x46\x6c\xb7\x2f\x47\xad\xd0\xe7\xcb\xef\x13\x4c\x38\x81\xd2\x2a\x90\x96\xdf\x3b\x14\x1f\x73\x6f\xb7\x8b\xe7\x4b\x8d\x87\xf8\x15\x9d\x10\x6f\xb7\xdf\xfc\x25\xb1\x68\x83\x3d\x3f\xce\x30\xfb\x02\xa2\xef\x40\xf4\x2d\x5a\x61\x4c\x9f\xc4\xc8\x10\x8e\x62\x0e\xf8\x86\xca\x7b\x3f\xed\x30\xaf\x89\x84\x15\x46\xa0\x8f\xd2\xe8\xdb\x7f\xb5\x07\x53\xbc\x1f\x0e\x06\xc5\xfe\x3e\xfc\xf3\xd0\x29\x7e\x57\xfb\xde\x0f\x06\xc5\xde\x1e\x2c\xde\x0d\x07\x83\xb0\x48\x86\x00\x96\xb7\xc5\x54\xeb\x00\x55\xa5\xc3\xad\xec\x49\xd6\x99\x36\xea\x31\x37\x33\x72\xb8\x89\x21\x64\xce\x14\x50\xe9\xdd\xa8\x33\x46\x08\x5a\xa3\xdc\xf3\xd2\x3f\xdc\xfa\x39\x6f\x02\x72\x41\xb1\x0b\xf8\x4e\x98\x4a\xd3\x6e\x53\xe9\x32\x6a\x9a\xa1\x1a\xc6\xd2\x45\xc7\x49\xea\xfe\x9a\xcb\x5a\xcf\x7d\xe6\xda\xc9\x84\xe3\xb1\x68\xcb\x32\x70\xf1\x26\x6a\x7e\xe6\xfd\x6e\x87\x5d\xf7\x85\x27\x6d\xd1\xe9\xf0\x21\x8f\x4d\x23\x05\x83\x67\x00\xb5\x31\xab\xd1\x7f\xab\x33\xcb\x54\xdb\xee\xd6\x6b\xaa\x5d\xbc\xce\x54\x9b\x7a\xa6\x53\xc1\x45\x15\x02\xd7\x6b\x4d\x59\x50\x57\x34\x4b\x65\xa6\x84\xe8\xbe\x8c\xd4\x2f\xc7\x03\xf1\x3e\x9d\x7d\xca\x0a\xba\x8e\xfb\x43\x27\x3d\x82\x38\x0a\x22\x4f\xc2\x92\x3e\x08\x13\x57\x6a\x01\x7b\x92\x1c\x78\x12\x22\xc8\x36\xac\x04\x09\xbc\x29\xcb\xfe\x95\xdb\xa6\x59\x6b\x80\x6d\x27\x44\x55\xe1\xfa\x39\x5a\x85\xb6\x93\xa3\x2a\x16\x99\x2d\x4e\xcf\x55\xea\x20\x6c\x57\x5d\x8d\xaf\x4f\xff\x63\x1c\x07\x05\x2a\xf1\x7f\xdb\x1d\xab\x9d\x57\x29\xa4\x94\x65\x57\xa5\x90\xb2\xc0\xcc\x81\xd0\x80\xda\xa8\xdb\x06\x15\xe1\x76\x1c\xe3\x35\xa8\xe0\xdd\x9b\x75\x17\xa8\xdb\xae\x00\xee\x68\xb9\xd3\x0c\x2d\xea\x9b\xae\x98\xc7\x57\x17\x67\x67\x1f\x8e\xae\xee\x3e\x8e\x8f\xae\x6f\xae\x64\xd6\x87\x2c\xcd\xf7\xa5\x43\xcc\x7d\x5a\xec\xaf\x50\x5a\x6e\x0a\x14\xc0\x0f\x47\xc7\x3f\x72\x4d\x4d\x83\xe8\x5d\x0f\x20\xd7\xc1\x74\x29\x5d\x23\xb2\x23\x2b\xa0\x30\x4e\x1f\x9d\x5d\x7c\x1f\x07\x72\x44\xfb\x19\x4e\x73\xba\xdb\x0b\x53\x4e\x4d\x27\xa1\xea\x4a\xe5\x65\xa0\xbe\x3b\xfd\xf7\xf1\xc9\xdd\xf1\xc5\xf9\x64\x7c\x3e\x89\x83\x68\x8e\xbf\xa0\x6c\x9f\xd1\x35\xec\xa9\xbf\xa5\xe1\x16\xf6\x22\x5c\xee\x8b\x12\xd8\x8b\x4a\x86\x67\x9f\x1e\x39\x58\x00\xaf\x27\xa7\xc7\x3f\xfe\x62\x35\x61\x57\x2a\x9b\x95\x1c\xea\x55\x6d\x95\x96\xa3\x2d\x84\x3d\xfc\x59\x47\xd1\x97\x26\x20\xd0\x06\x5e\xb9\x4a\x96\xae\xce\x05\x01\xbe\x8e\x56\x7e\x01\xbd\x21\x8d\xa0\x5a\x7e\x00\xec\x1c\x09\x1f\x68\xf6\x78\xf1\x19\x15\xf3\x9c\x3e\x38\x3e\xaa\x78\x41\x68\x81\x3e\xa8\x56\x84\x0b\x77\x5d\x49\x0b\xbc\xc0\x24\xcd\xf9\xd7\x97\x69\x26\x42\x30\xb4\x1b\x9a\x41\x96\x9f\x71\xc6\x96\xc9\x50\x98\x80\x37\x3e\xd7\xc7\x4d\xcb\x04\xdc\x0a\x4a\x94\x03\xee\x70\x77\x64\xa0\x82\x9b\x86\xbf\xa3\x1b\x37\xbe\xcb\xe1\xd1\xe9\x01\x3c\x7d\x55\x8c\xcf\x52\xa6\x1d\xac\xc3\xe6\x9b\x1e\xbf\x43\x73\x4f\xe8\x78\x27\xb6\x82\xf0\x2a\x8f\x37\x99\x49\x13\x08\xdc\xed\xdb\x6e\x71\x97\xe6\xd0\xd8\x66\xbd\x25\x22\x0d\xd6\xb5\xde\x17\x3b\x66\xaa\x5d\x98\x66\xbf\x6e\x4a\x76\x22\x30\x4c\x04\x3f\x18\xe5\x83\x2b\x1a\x8e\xf7\x0e\x3f\xe9\x56\x5b\xe3\x72\x96\xae\x55\x60\x97\x55\x7c\x25\x08\xa8\x2e\xf6\x99\xee\xcc\x35\xad\x4a\xba\x37\x8b\xec\xa3\x0d\x3d\xd8\x41\x24\x32\x30\xc1\x4b\x43\xfb\x50\xa8\x06\x5b\x74\xd2\x8d\x2c\x20\x0d\x0f\x21\xf5\x41\x4d\x83\x61\x23\x7b\xa3\x9d\x8e\xdb\xfa\x98\x6b\x1f\x1d\x47\x65\x28\x2f\x65\xd5\x32\x2c\xe9\x83\xae\xf7\xc4\x4e\x11\x09\x61\xe5\x93\xe4\xda\x12\xdc\x34\x5c\xfc\x5a\xb8\xcd\x7c\x17\xd3\xb0\x0b\xe3\x1b\x08\xdf\xc4\xcb\xe7\xbd\xfc\x9a\x88\x38\x18\xf4\xfd\x98\x68\xc5\xed\x29\x7a\x33\xd2\x52\xfe\xd7\x1f\xb2\x51\xb1\xeb\x98\xbd\x1a\x0d\x2d\xe9\x77\x3e\x0f\xf3\x48\x89\x02\x1e\x0c\xf5\x79\x01\x7a\x4d\xf2\x0d\x3c\xf6\xa0\xa6\x00\x6a\xe1\x26\x80\xc5\x0b\x1d\xd7\xbc\x47\xe1\x8e\x63\xc9\x47\xce\xef\x04\xe6\xf8\x5d\xdb\xbe\x1d\x9a\xec\xa5\x35\xb8\xd0\x55\x36\x5f\x91\x51\x4e\x72\xd7\x3a\x96\x07\xea\xd5\x74\x19\x56\x83\x15\xc9\x05\xd8\xe1\xf0\xe6\xb9\xca\x50\xac\xce\x2a\xd9\xc5\xd8\x9c\xa2\x26\x6b\xb3\x2b\x3d\x27\xd6\xaa\x6e\xb0\x30\x79\x17\xb2\x51\xe9\xf6\x6f\x3a\x6e\x44\x5c\xc2\xc9\xe1\x5f\xed\x6a\xb7\xcb\x9f\x6e\xe3\xd0\x88\x0e\xa2\x20\x8c\x26\xbf\xe1\x88\xb9\xd7\x64\xb5\x21\xa5\x99\xf2\xb0\xae\x31\xe9\xca\x93\x24\x11\xbf\xc7\x67\xe3\x8f\xe3\xf3\xc9\xdd\xf9\xc5\xc9\x78\xbb\x75\x98\x47\x94\xae\xd7\x88\x64\xc7\x4b\x9c\xfb\x33\xea\xb8\xce\x9e\x02\x2f\xf3\xf4\x31\x09\xee\x73\x3a\xfb\x14\x34\x60\x24\x82\x36\xcd\x58\xca\x61\xa3\xd5\xa0\xd8\xd1\x09\x5d\x27\x43\x88\x07\x83\xaf\x71\x18\xb6\xdd\x7f\xb5\xed\x9a\x6b\x0d\x66\x6d\xc8\x9c\x16\x33\xf4\x9d\xb4\x36\x28\x82\xe7\xb2\xfd\x73\x0f\xdf\xb7\xd3\x84\x83\x27\xd2\x6c\x9b\xb4\xef\x32\x89\x37\xb2\xc8\x65\x6a\xf5\x05\x73\x35\xc2\x87\x6d\x16\xe9\xa1\x2d\x74\x17\xe5\xa0\x0a\xa3\xed\x49\x76\x5e\xce\x75\x91\x56\xc9\x9a\xd5\x2f\x68\x1f\x09\xfd\x45\x92\x24\x44\xb1\xda\xed\xb6\xf6\x26\x76\x8a\x5d\x37\xe3\x65\xca\x19\xb2\xe6\xce\x3a\x8e\x84\xb5\x56\xad\x92\xe3\x77\xf9\xc3\xce\xdc\x2d\x86\xc9\x39\x5b\xae\x35\x58\x1f\xc1\x0e\xf3\xa8\xa1\xf5\x39\xb7\x91\xc2\xec\x84\x8c\xdd\xdd\x9b\x15\x59\xca\xb8\xa0\xd2\xb4\xda\x88\x7c\x1d\x0c\xa7\xd1\x9f\x99\xa4\xc5\xed\x5e\x32\xc9\x43\x27\x28\x33\x8f\xa4\xf2\xeb\x4f\xfe\x62\x53\x41\x91\x03\x26\xb6\x3e\x16\x83\x92\x5f\xcb\xb1\x18\x66\xb3\x73\x18\x1d\xe7\x9e\x50\x82\x9a\xc7\xde\x63\xba\x56\x67\xbe\x8e\x53\xe9\x8e\xbc\xeb\x12\xc4\x5a\x62\xae\xcb\xf4\x95\xa4\x1b\xdd\x15\x88\xf7\x2f\x28\x3d\x07\x16\xae\x05\xaa\xd4\x16\xa5\xbb\xc2\x50\xb4\x6f\xbb\x5c\x1b\xd9\x87\x1e\x4e\x9b\xa3\x68\x4e\x67\xb9\x77\xd4\xac\x54\xa7\x0c\xf7\x71\x45\x60\xd8\x45\xbb\xf1\x26\xbf\x78\x96\x29\x1c\xca\xff\xe3\x20\x18\xd9\xa9\xaf\x3c\x67\xc3\x0c\xee\xe9\x59\x69\x0f\xd7\x6d\x99\x91\x77\xbd\x40\x93\xe1\xcf\x41\x73\x9a\x32\x03\xf0\x79\xba\x42\xc9\x32\xd2\xb6\x08\x4e\xd9\xdb\x0b\xe5\xa6\x52\x68\xd5\x0a\x96\x34\xa1\x8d\xfd\x7f\x91\x9e\x62\xaf\xa9\x5f\x0d\x38\xec\xd2\x0e\x0e\x62\xad\x52\xb4\xbd\x4e\x07\x83\x30\x28\x59\xca\xf0\x4c\xa4\xc2\x6d\x2d\xef\x61\x9b\x27\xc4\xa4\xa6\x1c\xb0\x68\xf1\x37\x33\x5d\xdf\x02\x34\x39\x5c\x5f\x67\x22\x93\xee\xc7\x3a\x6b\x8e\xcc\x44\x66\x45\xb1\x59\x52\x9d\x8f\x9d\xb0\x1d\x69\xf4\xab\x46\x62\x90\x06\x3a\xd5\x78\xd4\x85\xf6\xae\x37\xb9\xb4\xe0\xbb\x5c\xd4\x3d\x5b\xa1\xc8\xb1\xcc\x42\x50\x7d\x5d\x2e\x8f\x65\xfd\xbc\xc0\x4b\xe6\xde\xc5\x4a\xc5\x13\x02\x54\xe7\x45\x50\x23\xe2\x47\xd5\x96\x1d\xfd\x84\xb2\x29\xca\xc8\xd7\x6b\xde\x77\xdd\x0c\x46\x33\x11\x27\x25\xa1\x46\xfd\x0e\x91\x78\x30\x60\x46\xa7\x72\x49\xf0\x5a\x1a\x75\xce\xd0\x5c\x77\xef\xca\xc4\x22\xee\x0a\x74\x89\xda\x83\x41\xff\x99\x86\xaf\xf8\xb8\x76\xb4\xac\xe8\xa3\x4b\x6c\xdb\x14\xb2\x7b\xd0\x41\x8b\x6f\xb4\xbb\x0f\x02\xd1\x8d\x6b\x1d\x69\x2f\xbf\x2b\xc3\x76\xc4\xa2\x8d\xba\xb4\x0e\x16\xe5\x68\xce\xf6\x58\x24\xbc\x67\xdf\xa9\x27\xb8\x30\x21\x48\xce\xd7\xaf\x72\x18\x53\xe0\xb5\x53\x1e\x1a\x06\xbf\x63\xbc\xc6\x3a\xe0\x1f\x11\x3f\x55\xb3\xc8\x31\x8b\x36\x1d\xd3\xc5\xeb\x42\xfa\x2e\x4f\x5c\xad\x7a\x96\x0f\xca\x04\x1b\x32\xef\xa7\xaa\x50\x2e\xc2\x9c\x48\x60\x9d\xe5\xdb\xad\x82\xa5\xf7\x0b\xb8\x4e\x8b\x12\x7d\x97\xd3\x94\x85\x05\xd8\x63\x1d\x58\xc1\x09\xd8\x2c\x72\x0d\xb2\x2f\x1e\xfc\x2a\x2d\x16\x98\xb4\xc7\x2e\xcb\x7d\x43\x77\x6a\xcc\xc8\xdd\x52\x67\xe0\xfb\xbb\x07\xee\x1a\x8b\xff\x37\x0d\xbc\x7b\xc5\x55\x66\x2d\xf7\x10\x78\xb0\x81\x4b\x12\xc6\x17\xc1\x8f\x12\xba\xda\x8b\x17\xe4\x59\xbc\xc0\x60\x6f\x07\xc1\xa8\x29\x86\xf7\x68\x3c\x8b\xf3\x56\x1e\x36\x71\x17\xec\x1b\x24\x18\xf9\x82\xc3\xb0\x8a\x62\xf2\x0d\x1f\x03\xdb\x90\xd2\x6c\xce\x8b\xcf\x7b\x01\xec\x05\x7b\xcf\x21\x8b\x7f\xb8\x0d\x8c\x78\x76\xb4\x2e\x46\x34\x06\xeb\x36\x56\xe9\x88\x8b\xdd\xfb\xe8\xef\xd4\xf5\x54\xf1\xac\x13\xdb\xbd\x4e\xca\x98\xe2\x12\xc3\x1d\x94\xda\x27\x41\x8e\x98\x23\x34\xb6\x6f\xbb\xe0\x0e\x63\x05\xd0\xcf\x4a\x75\xd1\xff\x48\xe4\x1b\xd9\xd7\x8c\x57\x0c\xd0\xa4\x78\x70\xda\x55\x12\x8c\x6a\x17\xa2\x67\x62\xcd\xe0\x0b\x1e\x61\x28\xdb\x8f\x30\x68\x0b\x5d\xe1\x58\x99\x70\xc3\x3d\x15\x3c\x1f\x80\x56\x3f\x19\xa4\xe2\xc9\x0a\xcf\x33\x0e\xea\xba\xb1\x7c\x9d\x8f\x5b\xf9\x4a\x1f\x37\x0e\x1f\x12\x25\x3d\x15\xe2\xe2\x47\x24\x73\x5e\xd2\x07\x5e\xfc\xbf\x36\xea\x6c\xd6\xe9\x9d\xa0\x3d\x9d\xe4\xc2\x3e\x17\x42\x56\x28\x67\xa7\x42\x38\x3b\x8d\x2c\xc7\x95\xe6\xb6\xd7\xe1\x63\x6e\x52\x2b\xd2\x95\xd4\x6a\x14\x1c\x05\xda\x61\xdb\x04\xbd\x05\x47\x57\xe3\x56\xb1\xf0\xb0\xf2\xc5\xc2\xa5\x72\x28\xf2\x3a\x45\x5c\x72\xb9\x7e\x10\xfe\x2b\xab\x54\x7d\xa0\xfc\xc4\x1c\x8a\x8d\xdb\x09\xc8\xb1\x65\xcf\x01\xa3\xcd\xae\x57\x33\x64\xb8\x82\xed\x6d\xd1\x06\xf7\x7a\x5b\x6c\x5e\x1b\x18\xd7\x6e\xb7\x82\x9b\x2a\x04\x6e\xd6\xfb\xaf\x09\x8c\x63\x94\xe6\x0c\xaf\xcb\xaf\x09\x8c\x53\xdf\xca\x27\x2f\xee\xcb\xc8\xfc\xb6\x9f\xbe\xb0\xe3\xe1\xc2\xff\xdc\xfe\xed\x6f\x25\xb8\x2f\xf7\x15\xe8\xdf\xfe\x76\xbd\x17\xc0\x60\x11\x08\x9f\xcc\x94\xe0\x95\xf0\x60\xb1\x9c\x35\x18\x5a\xad\xb9\x9a\x13\xeb\x53\x0f\x19\x66\x39\x6a\xa5\xa0\xb2\x03\x9c\x94\x35\xa4\xfe\x24\x43\x79\xfa\x58\x87\x44\x49\x4a\x04\x02\xb8\x64\xab\xdc\x76\x0c\x51\xe7\xc2\xf7\x46\x46\xed\x92\x6c\x2a\xad\x1e\xfd\x41\x57\x20\x80\xca\x81\x13\x15\xed\x01\xd7\x6d\xcf\x53\xce\x72\x66\x9f\x2e\xdb\x7d\xa4\x22\x9b\x8a\xf4\x9e\x38\xba\x99\x5c\xc4\x41\xba\x61\x54\x04\x8f\x89\xc8\xb1\xc6\x2b\x1c\x8d\x18\x32\xe7\xbd\x0e\xe1\x0c\x51\x2f\x71\x7f\x58\xaf\xed\x9b\x77\x19\xfe\xdc\x13\xbc\xab\xde\xd5\x5e\x41\x73\x54\xff\x7c\x6f\xc3\xa4\x45\x41\x1f\x82\xf7\xef\xde\x66\xf8\xf3\x7b\xcf\xc7\xfb\x42\xfb\x30\x00\xe2\xdf\x37\xf5\xbe\x88\x0c\xd3\x3d\xe9\xe6\xa6\xf7\x53\xef\xd2\x50\xee\x8a\x48\x06\xa9\xb6\xa3\x7f\x60\x2f\xbf\x98\xb5\x09\x7d\xab\x17\xb8\x7f\xe0\x5b\xc8\x79\x8e\xd7\x32\x64\xd0\x0e\x48\xbc\xb8\x99\xc4\x01\xdd\x30\x19\x99\x67\x07\x66\xe2\x56\x60\x26\x76\x02\x33\x71\x23\x30\x13\xc3\xd3\xf3\xeb\xf1\xd5\x64\x7c\x12\x07\x98\x94\xa8\x60\x48\x3c\x47\xe2\x86\x6b\xe2\x96\x1f\x90\x29\x13\x43\x11\x85\x7c\x3c\x5f\xf7\x24\x8a\x88\x06\xec\xf4\x81\xb9\x4b\x9e\x26\x17\x17\x67\x93\xd3\xcb\x38\xa8\xcf\xa8\x2a\xba\x3b\x3d\x3f\x17\x5e\x25\xee\xce\xc1\xa3\xab\x2b\xde\x44\x24\x77\xba\x82\x8b\xe4\xe9\x87\x8b\x9f\x38\xa4\x7a\xa1\xc6\x79\xdf\xcd\x9d\x2e\xfc\x78\x74\x7e\x73\x74\x16\x07\xab\x94\x6c\xd2\x3c\xa8\xe0\xaa\xf3\x71\x0e\x54\xdf\xe4\x8e\xa5\xbf\x7d\xed\x54\xc0\x54\x9a\x6d\xfd\x5b\xf4\x2c\x9e\x03\xa8\x95\x6f\x99\xb0\x7d\x22\x31\x2b\xd1\xe1\x32\xed\x00\xc5\x86\x83\xcb\x33\xe1\x8a\x0c\x3b\x97\x7f\x25\x6a\x45\x1c\xae\x7c\x8f\x68\xac\x22\x19\x33\xe0\x7b\x82\xa2\x9e\x5d\x05\x57\xda\xe5\x76\x27\xe0\x01\x07\x94\x5c\x56\x97\xed\x02\x6f\x14\xd4\x1f\x77\x64\x48\xd6\x80\xa0\x4e\xa6\xa0\xf2\x4c\x38\x21\x42\x5c\xae\xf8\x71\xfc\x8b\xb4\xe3\xba\x66\x44\x93\x36\xcb\x7e\x87\xab\xd1\x40\xf3\x9b\x3a\xac\xef\x44\xbd\x55\x5e\x07\xf6\x75\x76\x20\xd2\x8d\xe2\xc6\x66\x47\x33\x69\xe8\xf4\x97\x73\x70\x5c\xfe\x8c\xd9\xf2\xc8\xae\x0c\xc1\x21\x8e\xee\xc4\x89\x0a\xc5\x06\x63\x10\xe3\xe8\x4e\x1c\x24\x5d\x60\xbc\x78\x95\x2d\x6e\x81\xd8\x04\xaf\x4d\xb8\xaa\x65\xb4\x9b\xab\x7c\x46\x8e\x01\x53\xcc\xcf\x6a\x50\x4a\x56\xfa\x06\xcf\x74\xcc\xd4\xbb\x94\x2b\xdf\xe5\xb8\x9b\x84\xde\x3e\x0c\xbe\x97\x13\x9c\xbb\x70\xdf\xe6\x19\xab\xac\x73\xb7\xd3\x02\x1f\xff\x34\x3e\x9f\xf8\xe1\xeb\x18\x24\x25\xff\xc9\x10\x00\xd7\x63\xb2\x3e\x3c\xc6\xd2\xc9\x70\xfb\x22\xa1\xc6\x59\x3b\xc9\x4c\xfb\xd1\x1c\xeb\xb8\xb7\x5e\x68\xd0\x07\xfe\xb7\x87\x20\xba\xe4\xa1\x2e\x69\xf9\x0e\x68\x9a\xc0\xb7\x6c\x77\x06\x3c\x79\xab\x94\x98\x17\x6c\xdc\x07\x6c\xd4\xdd\x53\xd0\x7e\xd1\x3a\xb8\xcc\x51\x5a\xa2\xde\xa6\x44\x3d\xde\x43\x8f\x92\x9e\x92\x4c\x7b\xaa\x8d\x32\x68\xba\x7b\xb5\x77\x51\x3c\x3c\x6d\x7c\xee\x45\xbd\x3c\x09\xc7\x94\x30\x81\xc2\xb5\xa7\x8e\xa6\x01\x4f\xcd\xa1\xd6\x1e\x39\xe6\x9e\xd9\x04\xa3\xd8\x90\x11\x7d\x20\xa8\x38\xe9\x30\x12\x3b\x8b\x2b\x53\xe7\x76\x48\xe9\xe6\x1a\x40\x49\xfa\xbe\x93\x07\x73\xa9\xbf\xdc\x9c\x9e\xb4\xa7\x7d\x7e\xf4\x71\x0c\x46\x69\xe3\xf6\x0e\x67\x01\xd4\x6f\xd3\xec\xb8\xdf\xcb\x50\x39\x2b\xf0\x3d\xca\xee\x1f\x6b\xf8\x52\xb0\x05\x66\x79\xf9\xa8\x6b\x12\x23\x44\xa9\xcc\x92\xe6\x82\x63\xae\x9c\x1c\xf8\x14\x96\x49\x57\xb0\x9d\xce\xb0\xa3\x85\x94\x43\x6f\xa9\x4a\xbd\x21\xf2\xab\xb8\xcb\x18\x7b\xe1\xa1\x95\x12\xf0\x88\xb1\x74\xb6\x14\x8b\xb6\x54\xa4\x27\xcd\xb2\xba\x54\x05\x66\xe8\xcc\x7a\xfd\x03\xfd\xd8\x87\x6a\xd4\x08\x55\x87\x8e\x61\x41\x07\x3d\x36\xa1\xc0\x48\x2c\x43\x66\x08\x92\x97\x81\x30\xf9\x3e\xe3\xd7\xa3\x11\xa7\x25\xdb\xad\x5c\x71\x73\xa7\xd6\x26\x55\x1a\x73\x3b\x0e\x86\x16\xd7\xbc\x01\xe8\x0e\x39\x4d\xa1\x15\x88\x38\xf3\x44\x1d\xea\xff\xed\x45\x91\x45\x95\x8a\x47\xbc\x47\xcb\xf4\x33\xa6\x85\x03\xd2\x92\x52\x2b\x28\xa4\xac\xf8\x49\xf5\x1c\xdf\x45\x42\xfc\xaa\x2a\x48\xc9\xb1\x30\x34\xc5\x6e\xd0\xb1\xf6\x8e\x35\x4d\xf4\x93\x04\xd5\xb8\x30\x18\x98\x37\x94\xa5\x3a\x67\xe0\x8e\xc5\x9b\xa3\xe2\x49\x12\x4a\xe4\x0d\xbb\xd3\xf4\xf3\xdf\x09\x8b\xa2\x8b\xf4\xf2\x56\xef\x37\xc7\x94\x75\x87\xdc\x8f\x64\x8e\x07\x27\x41\x5c\xfb\x2c\xb2\xe8\x6e\x8e\xbf\xd4\xf7\x61\xd6\xbb\x99\x16\x2f\x19\xb1\x36\x67\xe1\x82\x47\x1b\x7f\x3a\xa8\xea\x39\x80\x24\x49\x92\x4d\x74\x71\x33\x11\x9d\xda\xbc\xfe\x45\xd7\x7f\x82\x29\x5a\x42\x84\x73\xf3\x27\x2a\xbd\x77\x7e\x8b\x8e\x3b\x3f\x1a\xdd\x59\x90\x27\x37\x57\x47\xfc\x0f\x10\x2f\x42\x29\x5f\xec\x70\xf1\x54\x86\xa1\x16\xa1\x2d\x9e\x63\x2f\xc2\x95\xb3\xe5\x58\x54\xaf\x6b\x9f\x2f\x10\x5f\xad\xc1\x00\x3b\x5e\x5e\xf6\x2f\xc7\x50\x89\x85\xdb\x11\x17\x7c\xc8\x04\xaf\xe5\xd2\xf0\xa2\xdd\xce\x58\x36\xe1\x06\xc2\x43\xa9\x9d\x39\xd2\x3f\xfc\x93\xf1\xb9\xc9\x22\x40\x6a\xb1\x81\xf8\x64\x06\x75\xb1\xdb\x45\x69\x0a\x00\xfd\x29\x36\xb6\xdb\x50\xd8\x98\xec\x2b\xe5\xdf\xed\xb8\xec\x0a\xc1\xf4\x88\x4a\xb7\x0b\x69\x34\x9c\xd6\xae\x2a\xcd\x7a\xa1\xd2\xed\xa8\x17\x0a\xa0\xa8\xff\x7a\x1c\xc7\x5f\x79\xa1\xed\x53\x01\x01\xc7\xee\x76\xfa\x88\xaf\x49\x0d\xb1\x72\x45\x24\x8f\x31\xce\x79\xf9\x44\x9c\x17\x26\x9f\x16\x80\x2b\x0f\x73\x6d\xbe\xcd\xef\xd5\x23\x0c\x09\x0d\x6a\x8b\xd8\x7e\xb0\xc7\x44\x9b\x0e\xb4\x67\x3c\x46\x26\xd5\x7f\x18\x0f\x2e\x9d\x25\x5a\x59\x77\xea\x88\x0d\x86\xd7\x42\x78\x35\x72\x4d\x67\x4e\x85\xe6\x50\x47\x5a\x20\x52\x45\x5a\x2e\x62\x32\x38\xe4\x2e\x72\xac\x09\x6a\xb3\xac\x45\x82\xac\x71\x06\x38\x3a\x88\x58\x3c\x75\x1c\xd4\xb8\xdc\xe6\xbb\x9f\x30\x52\x53\x5c\xb2\x55\xde\x7e\xf5\x82\x08\x9f\x79\xed\x35\xba\xdd\x12\x95\x48\x11\x1c\x62\x91\x82\xaf\x7e\x71\x0a\x97\x21\x03\xdb\x2d\x8b\xd0\x6a\xcd\x1e\x43\x2d\x57\x84\x04\xc4\x2c\x62\xe8\x0b\x0b\x65\xf2\x40\xf1\xfe\x15\x88\xd9\x2d\x3e\x0c\x78\x9f\x41\x1c\xf0\xb2\x40\xdc\x15\xe8\xbd\x62\xbe\xf7\xd9\x1d\x19\xc7\xf3\x9e\x83\x66\xe4\xfb\xc2\x0a\x16\x18\x83\xbf\x78\xa7\xf1\x39\x09\x52\x7c\x73\xd8\x2a\xa9\x25\x47\xbf\xc8\x28\x80\x00\x64\x7c\xe4\xae\xb4\xe8\x0b\x93\x59\xde\x32\x37\x41\xf1\x54\x7c\x67\x9b\x44\x76\x39\xde\xe9\x3e\x95\x6e\x5e\xae\x73\xcc\xc2\xa0\x17\x80\x68\x4e\x8b\xb1\x7b\x3b\x2d\x2d\xd8\x26\xa0\x9e\x00\x87\x2f\xf3\x51\x79\x48\xb9\xcc\xc9\x62\xe4\x01\x6d\x34\xf4\x7b\x16\xaa\x2c\x2c\x48\x3f\x8d\xd8\xc3\xf3\x90\xf4\x93\x64\x11\x49\x93\x95\x46\x32\xce\xe0\x15\xbd\x3b\xf4\x75\x6a\xd9\xe8\x7c\xd5\xda\x01\xb5\x7c\x59\x43\xd2\xa4\xd7\xd9\xd0\xc5\xcd\x64\xd4\x5c\x09\xfc\xd2\x19\x2b\x93\x83\x7e\x79\xaf\x7c\xf1\x77\x52\xaa\xe1\xdf\x55\x4e\xe7\x1e\x4b\x00\x69\x1a\x02\x3c\x4f\x52\x6a\xc7\xd3\x3a\x64\xa5\x31\x0c\x1b\x8f\xbd\xf9\x6f\xe6\x78\x01\x9f\x8c\x09\x59\x99\x16\x2d\x9b\x7d\x60\x5c\x5a\xb9\x14\x28\x09\x8f\x40\x55\xfd\xd3\x83\xa6\xd6\x99\x7a\xcd\x21\x0d\x77\x7c\xa1\x60\xb6\x5b\x7d\xfb\xc0\x59\x91\x89\xdf\xf2\xeb\xa0\xbe\x5e\xe0\x8b\xfa\x08\x76\xea\xb6\xaa\xa5\x20\x90\x6c\x4a\xe2\xc2\x4e\xaa\xda\x52\xdb\x46\x21\x49\xa4\x73\xb0\xd7\x34\x87\x01\x30\x89\x49\xfe\x08\xd3\x9f\xcc\x6a\xc2\x64\x14\x94\x2b\x8f\x18\x4b\xba\xc9\x9f\x71\xa8\x44\x98\xb8\x16\x55\x86\x52\x28\x7c\xd6\x84\xc7\xb9\x84\x2d\x5c\x68\xf1\xf5\xd0\x2d\x96\x85\x71\xe8\xd8\xe7\x88\x65\x9c\xf3\x81\x43\xa2\x71\x5d\xdc\x70\x70\x19\xd3\xfe\x2d\x8c\x49\x87\x75\x23\xde\x57\x25\x1b\xe2\x75\x52\x8b\xd7\xc4\x3c\xcc\xe0\x69\x16\xc4\xba\x5a\x22\x80\x38\xd4\xff\x6f\x21\x00\xdd\xb0\x9d\x18\x70\xa0\xc2\x19\x3c\xa6\xe0\xed\xf6\xe5\x1b\x79\x71\x33\x79\x6e\x1f\x39\x81\xfb\x9a\x7d\x14\x7a\xa4\x76\xaf\x6d\x6d\x23\x2f\xb6\xbd\x6f\xf9\x36\x7a\x66\xe3\x5c\xb0\xa8\x84\x3a\xac\x87\x75\x98\xab\xb3\x72\xf5\x03\xc3\xee\x82\xb2\xa9\xb2\xc1\xf5\x87\x4a\x0e\x91\x77\x10\x3b\xa3\x8c\x9a\xaf\x80\x85\xaf\xcb\x5e\xd6\x4e\x5e\x06\xf4\xf2\x86\x44\xfe\x95\x3c\x89\x88\x7d\xf5\x0b\xf2\x85\xd0\x3f\x2a\xcf\x2b\x64\x44\x0a\x38\xe2\x7b\xf1\x57\xa2\xfe\x8f\x18\xbd\x16\x24\x39\xf4\x3d\x5e\x26\x96\x9d\xc9\xc7\x46\xcc\xdf\x89\xf9\xcb\xf9\xf8\x2b\xd3\xab\xad\x3c\xb8\xdf\x66\x4a\x4f\x95\x31\xdb\x4a\x44\x30\x09\x92\x90\xd9\x4f\x55\xd1\xd5\xe3\x2d\x9a\xf6\x1d\x8b\xde\x2d\x9a\x72\x0e\x74\x8b\xa6\x8d\xd2\x5a\xe0\x14\xc3\x73\xd4\xef\x17\x6b\x07\x90\x24\x4c\x65\xd1\x16\xd7\xc0\x01\x88\x56\x29\x9b\x2d\xc3\xd4\xbc\x25\x40\x38\x86\x5b\xef\xee\x38\xea\x00\x89\x7e\xa5\x98\x84\x86\x4d\xed\xb0\x40\x79\x32\xe4\x37\x4d\x06\x5d\xe6\x4e\x9f\x75\x94\xd5\x36\x33\x50\x0b\x0b\x46\x01\xed\x90\xe7\x9b\xd6\x12\x92\x78\xad\xc3\x62\xee\x82\x34\xb9\xdc\xfb\xcb\xbe\xe9\x34\x50\x89\x35\x9b\x26\x02\xa1\x2d\xfb\x6d\xce\x46\x3d\x97\x04\x41\x99\xaa\x05\x8d\xef\xf8\x80\x80\xdf\xfc\x16\x21\x69\xbb\x7f\xe9\x8b\x64\x00\xb1\x27\x73\xd9\x60\xc0\x44\xc2\x1f\xb2\xdd\xf6\xdf\xaa\x0b\x2e\x37\xab\xb8\x88\x6c\x36\xac\x43\x3d\x34\x88\x3d\x9e\x5f\xe6\xc6\xba\x23\xbf\xd9\x1f\x91\xe0\xec\xef\xf1\xf8\xdd\xcc\x00\x9e\x1f\x7d\x1c\x77\x41\xb1\xba\x39\xc5\x90\xbb\x06\x61\x2d\x95\xf9\x46\x68\x11\x5d\x4d\x67\x35\x98\xbe\xf8\xeb\x02\xc5\xaf\xc9\x04\x94\xb7\x5f\xf5\x53\x8e\x4c\xab\x97\xb9\x47\xad\x5e\xfb\x26\x5e\xbb\xdd\x0a\xae\xaa\x10\xc0\x3b\x4f\x32\x9a\x35\x5d\x2b\x8b\x99\xf4\x5a\x32\xbf\xeb\x84\x34\x65\x87\xd7\x92\x02\xb5\xbc\x96\xdc\x7c\xfb\x73\xc3\xdd\xac\x9b\x03\xed\x9a\x63\x54\x17\xe5\x24\xa1\x18\x4b\x1c\x04\x1d\x8e\x38\x7a\x60\x2f\x77\xc4\x59\x7e\xdb\xf8\x76\x7f\x89\xd2\x4c\x3a\xe2\x2c\xbf\x7d\xef\x69\x7c\x5f\x18\x16\x5d\x3f\x9d\x0a\xc0\xdc\x3f\x2d\xbe\xeb\xf0\xc9\x0c\xbc\xdb\x05\xab\x12\x09\xcf\x77\x65\x65\x99\x9c\x4e\xce\xc6\x71\x10\x35\x06\x0a\xeb\x1c\x28\xce\x08\x85\x07\x8f\xed\xa7\x43\x5a\x7e\x3a\xc4\xf1\xd3\x21\x0d\x3f\x1d\xe2\xf5\xd3\x21\x0d\x3f\x1d\xe2\xf1\xd3\x21\x5e\x3f\x1d\xd2\xe9\xa7\x43\x3a\xfd\x74\x88\xf3\xa6\x1f\xb6\x3c\x61\x32\xeb\xa8\xc9\x1c\x94\xea\xe6\xaf\x58\x08\x53\x70\x09\xe4\x1b\x72\x15\x0d\x33\xa8\xae\x64\xe7\x49\xd6\xf6\x40\x99\x3f\x6b\xc7\x6c\x98\xe6\xf4\xdb\x74\x0b\xeb\xb2\x93\xef\xf8\xef\x61\xd2\xd4\x3b\x28\x4d\x9a\xf3\x3f\xcc\xa4\x39\xff\x03\x4c\x9a\xb3\x48\x60\xa8\xcf\x94\xf9\xcc\x77\xda\xfb\x1f\xb6\x17\xb6\x69\x07\x5d\xd6\x76\xd0\xa5\xb6\x83\xce\xed\x4f\xba\x16\x69\x87\xb1\x42\x9d\xce\x40\xa4\x79\xdc\x6d\x3f\x54\xa0\x87\x9e\xb2\xe7\x6c\x88\x0a\x4c\x8e\xf7\x77\x96\x1a\xcb\xaf\x90\x1a\xdb\x2f\x47\xfc\x56\xf9\x46\x53\x5f\xbf\x7c\x63\x65\x66\x55\x32\x8e\xbc\x2d\xda\x25\xe3\x64\xdd\x32\x4e\xcd\x93\xfe\x9e\x32\x4e\xf6\xf7\x78\xe0\xf7\xf7\x96\x71\xf4\x52\xbd\x4c\xc6\xd9\xbc\x5c\xc6\x21\xaf\x97\x71\xb2\x2a\x9c\xb7\x84\x9c\xbf\xfb\xe3\x28\x1e\x1d\x52\x3d\x30\x58\xae\x1f\xb9\x98\xa3\xc5\x1a\x6c\x5e\x87\x38\x18\x42\x89\x20\xda\x9f\x58\x46\x0a\x8b\x77\x7f\x69\xfd\x86\x84\xd2\x91\x0d\xac\x71\xc1\x56\xd0\x9e\x67\x80\x53\xf5\xf8\xed\xd1\x64\x1c\x07\xc2\xbc\x90\x32\x61\x19\xb6\x46\x24\x03\x63\x62\x35\xc8\x46\xa5\xf3\x5a\x73\x1c\xe4\x34\xcd\x1c\x08\x3b\xa5\x5c\x9e\x3c\x9d\x5c\x5d\x5c\x8a\xfc\x04\xa7\x93\xf1\x47\xeb\xbd\x10\xcc\xd0\x4a\x3e\x3c\x22\x6a\xe5\x63\x1f\x8d\xb7\x3e\xe4\xf3\xa0\x6a\x98\x48\x3a\x59\xcb\xe7\xa5\x2f\x7f\xd1\xe9\xde\xca\xf5\xa3\x79\xae\x71\xfa\xc6\x7c\x12\xa9\x6f\xe0\xf9\xd1\x4f\x77\x67\xa7\xd7\x93\xbb\xef\xaf\x2e\x6e\x2e\x65\x76\x36\xd8\x8b\x72\x5c\xb2\xfd\x45\x41\x37\x6b\x0d\x72\xfe\xe3\xb5\xac\xdd\xcf\x31\xf9\x24\x4b\xf5\x5b\x22\xbc\x54\x0e\x58\x34\xa5\x8b\xeb\x46\x1a\xd3\xb1\x9e\x1f\xb1\xe6\xd8\x7a\x99\xa4\xb1\x06\x2a\xd9\x9d\x05\xa0\x42\x38\x84\x40\x76\xf1\xdd\x77\xd7\xe3\x49\x1c\xc8\xbd\x0f\xe0\xe5\x85\xbc\x9d\x8d\x83\x35\x95\xda\x70\x67\xa6\xb9\x96\x21\xd1\xcd\xb9\x60\x92\xca\xc9\x65\xd4\xfc\x3f\xf8\x70\x71\xf2\x8b\x32\xdd\xc9\xc0\x8f\x43\x19\xba\x1a\xbf\xf4\xd1\x62\x6d\xfb\x77\x53\x89\x4b\xe4\x54\x4c\xd5\xac\x3d\x17\xd8\xf7\xba\xe1\xea\x75\x7f\x06\xd0\x5d\x6d\x9d\xac\x4e\x65\x45\xbf\xd5\xa9\xf1\xe4\x27\x56\x81\x32\xb4\xc9\x78\xfc\x56\x1e\x20\x19\x44\x9d\x0c\x4d\xf0\xbc\xb3\x52\xe2\x86\x25\x55\xe1\x64\xbe\x04\x4d\x38\xba\x5b\x17\x74\x86\xca\x52\xe6\x2b\x13\x6d\x14\x68\x5e\xa0\x72\x59\xbb\x3c\x2a\x08\xa0\xb2\xe5\x11\x5f\xb6\x3c\xf5\x51\x67\x0a\x79\xcf\xe8\xcc\x4d\xbb\x53\x1a\xc9\xad\x3c\x9c\x45\x06\x8f\x66\x91\x44\x31\xce\x4f\x05\xd1\xd1\x4e\x67\x7a\x9d\x25\x95\x39\x24\xb1\xa7\x14\x16\x09\x4e\x92\xa4\x6e\xae\x7e\x7e\xf9\x5a\x27\xde\x09\x41\x3c\x1c\xbd\x74\x43\x9c\x85\x6f\xb4\x25\x4b\xc5\x53\x0e\xed\x17\x87\x35\xd2\x01\x2e\xae\x58\x19\x3e\x4c\xac\x15\xdd\x99\x55\x1a\xcf\x43\xaa\x82\xac\xa8\xca\x28\xad\x9f\x17\x26\x9d\x91\xdf\xe2\x8d\x18\x11\xfe\xb7\xdd\xa6\x91\x7c\x68\x5c\x99\x6a\x6f\xc5\xa3\x72\x78\x1a\x82\x88\xd1\xf5\x5e\x01\xa9\x79\x4c\x41\x38\xab\x9a\x77\xaf\x7d\xe2\x50\x05\xa2\x92\x16\xcc\x8e\xf9\xb4\xee\x00\x6f\x87\xd3\x7d\x74\x3b\x9c\x56\x9e\xbb\x5a\xe9\x2a\xa6\x96\x59\xbe\x99\x8d\xc4\x6c\x98\x59\x6b\x5d\x7a\x30\x55\xd9\x48\x5e\x9f\x04\xac\x66\x0b\xa0\xf3\x68\xcc\xe7\x61\x10\x35\x60\x5d\xf2\xd3\x3a\x6e\xe3\x76\x45\x3b\x53\x98\x21\x2e\x56\x99\x46\x2b\xdb\x6f\x59\x21\x56\xdb\x43\x79\xf7\x59\xd7\x19\xbf\x3a\x6c\xeb\x5c\xdc\x33\xf7\x87\x5e\xc3\xba\xb8\x18\xd1\x69\x89\x54\x3a\x14\x64\x25\x2a\x92\x92\x35\xce\x02\x30\x92\x0f\xf6\xd5\xae\xb3\xf2\x4e\xac\x05\x28\xde\xee\xd3\xe5\x49\xf0\xa7\x60\xaf\xd0\xa8\xe4\x37\x78\x53\x9d\x36\xcc\x3e\x85\x5d\x2a\x4b\x63\xed\x93\x44\x51\x08\x1f\xf1\x58\xa7\x0b\xf4\xcb\x85\xe5\x5c\xd9\xa8\x37\xb9\xb6\xdc\xde\xd5\xd2\xbe\x68\x00\x4e\x92\x8b\xed\xf6\x63\xca\x96\xd1\x2a\xfd\x12\x36\xa2\xd0\x2d\x20\xd8\x99\x09\xc3\x86\x32\x91\xc4\x72\xf8\xaf\x19\x52\xbd\x26\x76\x0a\x07\xd9\x82\x77\x19\xba\x02\x85\x25\x81\x10\x03\x51\x54\xbf\x2b\xe3\x87\x4b\x3e\x5d\xb6\x27\x91\x1d\xa2\x4e\xea\x48\x7c\x4f\x78\xec\xa1\x7d\x03\x6f\x2f\x81\xfd\x16\xb3\xbd\x5e\xfd\x24\xd1\xb9\xdf\x2c\x8e\xf5\x3e\x71\x2f\x26\xf5\x31\xbb\x75\x7e\x99\xac\xec\xd3\x51\xfb\xe4\xf5\x93\x04\x6b\xb7\x2f\x2d\x87\x86\x56\x70\x47\xfb\x8b\xc1\x80\xbd\x73\xce\xf9\xed\x70\xaa\x5b\xa8\x4b\xde\x0f\x81\xb3\x85\xed\xd3\x6e\x85\x81\x88\xeb\xc5\x10\x8c\xf4\x0d\x4e\x99\x38\xcd\x99\xa7\x2c\xf6\xf7\x47\xc0\x3b\x05\x77\xf6\x25\x1f\xcf\x7b\xb7\x0d\x51\xe8\xd5\x0d\x1b\x60\x7b\x07\xd3\xed\xb6\x39\x43\x5e\x0a\x5a\xcb\xd4\xec\x55\xe5\x3e\xd0\xf5\x9e\x4b\x18\x67\x15\x8c\xfc\xa6\x66\x6f\x85\x16\x19\xb2\xaa\x3d\x81\x60\x00\x46\x24\x21\x2e\x2f\xad\x99\x10\xda\xd3\xb9\x99\x15\x55\x92\x9a\xec\x14\xbe\xd9\xe3\x55\xcb\x02\xcd\x4d\xd9\x9b\xaa\x7e\x32\x53\x1b\x07\x60\x00\xc0\x08\xd7\xd7\xfd\xb9\x2b\xc0\x81\xc3\x10\x1b\x8f\x96\x5a\xb8\x53\x39\x8f\x2d\x69\x4f\xe5\xea\xaf\xed\x5b\x79\x24\x55\x01\x00\xb1\xa7\x10\xc4\xa1\xaf\x18\x6a\xef\xd7\x32\xd4\xa2\xa9\xd6\x1c\x80\x08\x79\x0e\x5d\x89\xb5\x21\x9a\x76\x74\xff\xa2\x26\x55\x03\xc6\x81\xd4\xea\xc8\xd7\x6c\x27\xbf\xd5\x3e\xaf\x69\xa4\xd5\x3c\x4f\xc6\x41\x99\xf4\x86\xef\x7e\xe3\xd5\x7e\x57\x82\xd2\xa2\xc9\x52\xf7\xea\xd8\x77\xcc\x58\x2a\x48\x7e\x9b\x75\x07\xb7\xad\x3b\xb6\xb4\xe0\x7b\x79\x47\xdd\x5f\xd5\x71\x6d\xc4\xff\xea\x8e\xdb\x96\x88\x53\x7b\x45\x7a\x02\xfc\x4a\xeb\x0d\xb6\xad\x37\xe4\x0f\xb7\xde\x60\x61\xe4\x20\x4e\x1e\x02\x2b\x89\x5f\x1a\x39\xba\x3a\xf4\x79\x20\x34\x9e\xf4\x59\x46\x5a\xbf\x56\xf6\x3f\x45\x00\x09\x27\x80\xf5\x5e\xdd\x92\x69\x77\xe8\x3d\x86\xfa\xc1\x5a\x19\x8c\xf0\x87\x86\xde\x93\xee\xd0\xfb\x95\xc7\xd2\x19\xcd\xb9\xfc\x74\x0f\x49\xf3\x49\x01\x96\xde\xfb\x1e\x14\x10\xc5\xee\x73\x02\xa6\xc8\x7e\x4c\x40\x14\x76\xa6\xda\x67\xe9\xbd\x6d\x15\xc1\x96\x55\xe4\x25\x76\x0f\xe8\x7b\xbe\xb5\xf3\xee\x86\xd6\xad\x3b\x66\x88\x17\x18\x42\x5a\xc6\x13\x59\x70\x77\x73\x16\x07\xef\x7b\x39\xee\xbd\xef\x99\xaa\x1d\xe9\xf9\xf9\x62\x4c\x61\xcf\x2d\x5c\xe3\x3c\x6f\x97\xf2\xde\x45\x22\xff\x67\x6d\x20\x35\x88\x1a\x94\x7a\x35\xf6\x7d\xaf\xf9\xd2\xab\xb1\x16\xa5\x5e\x63\x08\xab\x99\xa2\xb1\x7f\x54\x2a\xa6\xad\xad\x72\xa7\xcf\x84\x12\xf6\x1b\x29\xce\x7e\x73\xc2\xdc\x5d\x39\xe8\xb0\xa6\xb8\x9e\x64\xa0\x16\x90\xf5\x22\x90\xd4\x3b\x60\x0a\xf3\x76\x96\x47\xcd\x56\x69\x93\x2d\xdd\x0e\xa7\x70\xb9\x3b\x13\x89\xf5\x72\x20\x9e\x87\xb9\xec\x67\x96\x04\x37\x67\x41\x92\x24\xb9\x98\xa1\xb0\x18\xd1\xa8\xc6\x21\xfd\xf7\x28\x6d\x50\x9d\x5c\xbf\x61\x00\x00\x4c\x93\xf4\x36\xad\x05\x47\x65\x0c\xd1\xd1\x2e\x44\x3e\xa5\xb5\xf3\xd9\x55\x00\x33\x0b\xde\x97\x6b\x3f\xad\xa4\xca\xae\xc2\x03\x35\xcb\xdc\x78\x72\x3e\xea\xba\x0c\xc0\x7e\xe6\x8d\x21\x19\x0c\xfa\x9b\x8e\x14\xe8\x4b\xf1\x08\x11\x0a\x97\xd2\x90\xe0\x15\xe2\xb4\x3a\x9d\xeb\x4b\xc3\x36\x6f\xb4\xe7\x7e\x32\x6e\x67\x10\xb6\xa7\x5e\x36\xa6\xde\x82\x4e\x2b\x15\x0d\x68\xa5\x74\xf7\xe7\x2a\x2d\x41\x35\x52\x5e\xbf\xf5\xa0\x0b\x58\x58\x98\x0c\xe7\x20\x9e\xcb\x1c\xe2\xe9\x57\x98\x0f\x38\xa1\xf0\x19\x03\xc4\xa3\x5d\x1e\x61\x16\x12\x58\x28\x63\x0c\xcc\xa5\xc9\x6b\x99\x84\xa9\x46\x3b\x52\xa3\x5d\xfd\x96\x93\x85\x80\x20\x96\x69\xaf\xb4\x88\x45\x8d\x30\xc5\x31\x7e\x96\x88\xac\x99\x9d\x71\x33\xe2\x25\xda\xa5\x73\xd0\xa4\x17\xd0\xc6\xc3\x9e\xf2\xe8\x8e\x99\x06\x8e\xe9\x6a\x9d\x23\xbe\xe3\x70\x09\x67\xb0\x00\xd5\x68\x39\x18\xcc\x0e\x45\x73\xde\x60\x9b\xcd\xae\x60\x9b\x4d\x08\xa0\x1e\x8c\x2d\x8f\x61\x7d\x43\x99\xfa\x3a\x6f\x2c\x23\x4c\x85\xd0\x43\xc4\x53\x08\xcd\x76\xd4\xb2\x08\x84\xcc\x85\xb0\x5e\x6f\xb9\x59\x56\x2f\x3d\x16\x8f\x65\xe5\x7c\x70\x79\x47\xa3\x50\xb0\x07\xb1\x5b\xee\xe5\x68\x41\x65\x7e\x1f\xe2\x8b\xff\x95\x22\xa9\x78\x9b\xf7\x00\x54\xfa\x0d\xe5\x3a\xaf\x6b\xab\xf5\xe6\xd5\xab\x6e\xdd\x1b\x5d\x6c\xb5\x3e\x04\xb0\x38\x0c\xeb\xe4\xa9\xea\x99\x5f\xab\x27\x99\x51\x20\x6e\x39\x85\x69\x74\x70\x79\x00\x3f\x5a\xf6\xe2\xd9\x64\xda\x96\x01\x14\xa9\x5e\x26\xce\x83\xc8\xf5\x2a\x8b\x85\xd5\xbb\xde\xdc\x81\x96\xf2\x53\xaf\xc7\xf3\x2f\x1d\x57\xe9\x60\x90\x86\xa0\x82\x6c\x87\x10\xff\x82\x0c\x64\x46\x88\x87\x65\x82\x2d\xef\x30\x7e\xc6\xdd\x2c\x62\xe6\x21\x3a\x17\xca\x9f\x3b\x8c\xec\xc8\x1d\x46\x5e\x26\x9c\x13\x9d\x3b\x8c\xd4\xc2\x39\xfb\x0d\xc2\x39\x27\xe5\xdd\xb9\xbf\x48\x33\xf7\x17\x7d\xcd\xcb\x64\xed\x67\x4b\x1b\xaf\x90\x09\x29\x4f\xa7\xb4\xe2\xeb\x96\xb4\x3f\x31\x75\x8e\x64\x9d\xd6\xc5\xcf\x8a\xd6\xa2\x61\xe6\x19\x4d\xe5\xbc\x20\xf7\x7c\x6e\x2b\xb4\x23\xb7\xd5\x9b\xb2\xf7\xff\xa7\x9f\xd3\xeb\x59\x81\xd7\x4c\xe7\xb7\x2a\x7b\xb2\xc7\x48\xfd\xdf\x5b\x6d\x4a\xd6\xbb\x47\x3d\x4c\x66\xf9\x26\x43\x59\xef\x1e\xcd\x69\x81\x7a\xfe\x66\x22\x93\xfd\x4a\x4c\x43\x06\x96\x59\x51\x4d\x22\xa5\xa6\xfc\x15\x49\xbc\x64\xb7\xc3\xe9\xbb\x6f\x06\x03\x76\x7b\x30\x7d\xf7\xd7\xed\x56\xc4\xda\x0b\xcb\x92\x78\xec\xf3\xf6\x60\xca\xeb\xbe\x99\xbe\x3b\xd8\x6e\x79\xf9\xfb\xe4\xcf\xaf\x9f\x53\xca\x7a\x39\x4a\x4b\xa6\x27\xf5\xf9\x20\xfa\x6b\x74\xd0\xbb\xdf\xf0\xf2\xb2\xec\xb1\x65\x4a\x7a\x9f\x05\x9e\x05\xa0\x12\x29\xc5\x6f\x18\xce\x93\x12\xb2\xe8\x28\x47\x05\x4b\x52\xc8\xa2\x0f\xe2\x35\xca\x24\x87\x2c\x3a\x4e\x0b\xe1\xb8\x94\x2c\xf9\x0f\x9a\xe7\xe9\xba\x44\xc9\x0c\xb2\xe8\x44\x49\xc3\xc9\x06\xb2\x48\xe6\x5d\xcf\x20\x8b\x2e\xe5\xb5\x7c\x72\x07\x59\x74\xad\x15\xe2\x64\x01\x59\x34\x49\xef\x93\x15\xff\x5f\xfa\xaf\x25\x73\x8e\xdd\x4f\x15\xfc\x47\x28\x3d\x7c\xc1\xe8\x1f\xde\xbe\xfd\x53\xaf\xa4\x9b\x62\x86\x3e\xa6\xeb\x35\x26\x8b\x9b\xab\xb3\xe4\x5e\xcf\x39\x5a\x61\x12\xfd\x5a\x46\xab\x74\xfd\x7f\x02\x00\x00\xff\xff\x83\xb8\xb6\x8d\x84\xc5\x00\x00") func cmdInternalPagesAssetsJsBootstrap400Beta2MinJsBytes() ([]byte, error) { return bindataRead( _cmdInternalPagesAssetsJsBootstrap400Beta2MinJs, "cmd/internal/pages/assets/js/bootstrap-4.0.0-beta.2.min.js", ) } func cmdInternalPagesAssetsJsBootstrap400Beta2MinJs() (*asset, error) { bytes, err := cmdInternalPagesAssetsJsBootstrap400Beta2MinJsBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "cmd/internal/pages/assets/js/bootstrap-4.0.0-beta.2.min.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x18, 0x86, 0xbc, 0x56, 0x1d, 0xec, 0x7c, 0x44, 0xa7, 0x54, 0x1d, 0x82, 0x37, 0x7a, 0xd8, 0x1a, 0x40, 0xff, 0x32, 0x49, 0x6f, 0x32, 0xad, 0x25, 0x98, 0x84, 0xf0, 0x79, 0xc, 0x44, 0xd6, 0xa5}} return a, nil } var _cmdInternalPagesAssetsJsContainersJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\x69\x73\x1b\xb9\x11\xe8\xe7\xa7\x5f\xd1\xeb\x6c\x76\xc8\x88\x1c\x52\xde\xe3\xd5\x52\xa6\xab\x64\xd9\xde\x28\xf1\x55\x92\x9c\x54\x4a\x56\xa9\xa0\x19\x90\x84\x3d\x1c\x4c\x00\x8c\x28\xae\x57\xff\xfd\x15\xae\x01\x30\x07\x49\x69\xbd\x9b\xe4\x25\xfe\x60\x91\x33\x8d\x46\xa3\xd1\xe8\x0b\x0d\x70\x34\x82\x63\x5a\xac\x19\x99\x2f\x04\x3c\x1e\x1f\x7c\x07\x3f\x51\x3a\xcf\x30\x9c\xe4\x49\x0c\x47\x59\x06\xa7\xf2\x15\x87\x53\xcc\x31\xbb\xc1\x69\xbc\x37\x1a\xed\x8d\x46\xf0\x8a\x24\x38\xe7\x38\x85\x32\x4f\x31\x03\xb1\xc0\x70\x54\xa0\x64\x81\xed\x9b\x01\xfc\x0d\x33\x4e\x68\x0e\x8f\xe3\x31\xf4\x24\xc0\x23\xf3\xea\x51\xff\x50\xa2\x58\xd3\x12\x96\x68\x0d\x39\x15\x50\x72\x0c\x62\x41\x38\xcc\x48\x86\x01\xdf\x26\xb8\x10\x40\x72\x48\xe8\xb2\xc8\x08\xca\x13\x0c\x2b\x22\x16\xaa\x1f\x83\x45\x52\x02\xff\x30\x38\xe8\xb5\x40\x24\x07\x04\x09\x2d\xd6\x40\x67\x3e\x20\x20\x61\x88\x96\xff\x16\x42\x14\x93\xd1\x68\xb5\x5a\xc5\x48\x11\x1c\x53\x36\x1f\x65\x1a\x94\x8f\x5e\x9d\x1c\xbf\x78\x73\xf6\x62\xf8\x38\x1e\x9b\x46\xef\xf3\x0c\x73\x0e\x0c\xff\xb3\x24\x0c\xa7\x70\xbd\x06\x54\x14\x19\x49\xd0\x75\x86\x21\x43\x2b\xa0\x0c\xd0\x9c\x61\x9c\x82\xa0\x92\xe8\x15\x23\x82\xe4\xf3\x01\x70\x3a\x13\x2b\xc4\xb0\x44\x93\x12\x2e\x18\xb9\x2e\x45\xc0\x33\x4b\x22\xe1\x01\x00\xcd\x01\xe5\xf0\xe8\xe8\x0c\x4e\xce\x1e\xc1\xb3\xa3\xb3\x93\xb3\x81\x44\xf2\xf7\x93\xf3\x3f\xbf\x7d\x7f\x0e\x7f\x3f\x3a\x3d\x3d\x7a\x73\x7e\xf2\xe2\x0c\xde\x9e\xc2\xf1\xdb\x37\xcf\x4f\xce\x4f\xde\xbe\x39\x83\xb7\x2f\xe1\xe8\xcd\x3f\xe0\xaf\x27\x6f\x9e\x0f\x00\x13\xb1\xc0\x0c\xf0\x6d\xc1\xe4\x08\x28\x03\x22\xb9\xa9\x27\x11\xce\x30\x0e\x48\x98\x51\x4d\x12\x2f\x70\x42\x66\x24\x81\x0c\xe5\xf3\x12\xcd\x31\xcc\xe9\x0d\x66\x39\xc9\xe7\x50\x60\xb6\x24\x5c\xce\x2a\x07\x94\xa7\x12\x4d\x46\x96\x44\x20\xa1\x1e\x35\xc6\x15\xef\xed\xcd\x95\x3c\xc5\xc9\x02\x31\xc1\xe3\x8c\xa2\xb4\x17\x25\x25\x63\x38\x17\xd1\x00\x3e\x17\x28\xf9\x84\xe6\x98\x4f\xe0\x22\x4a\x28\xc3\x0a\x2e\x1a\x40\x34\x47\xe5\x1c\xcb\x0f\x29\x9e\xa1\x32\x53\xcf\x66\x94\x2d\x91\xfa\x54\x12\xf9\xbf\x90\x53\x10\x5d\xde\xf5\x0f\xf7\xf6\x66\x65\x9e\x48\x2a\x60\x51\x2e\x51\x4e\x7e\xc6\xbd\xbc\x5c\x0e\x80\x93\x9f\xf1\x00\xca\x9c\x08\xde\x87\xcf\x7b\x00\x37\x88\xa9\xaf\x87\x7b\xa0\x86\xdc\x93\x5f\x60\xaa\x41\xe2\x82\x16\xbd\xfe\xa1\xf9\x92\xe1\x7c\x2e\x16\xf0\xcd\x37\x90\x97\x4b\x78\x3a\x55\xc8\xf4\xcb\xb0\x81\xc6\x0c\x0a\x6c\x64\xc0\xf6\x00\xee\xf6\x00\x18\x16\x25\xcb\xe1\x42\x11\x23\x9b\x5c\x1e\xee\xdd\xed\x49\xc6\xbd\xa4\x59\x46\x57\x92\xab\x92\x61\x27\x2f\x8e\x21\x47\x4b\xf9\x35\xa1\xf9\x0d\xce\xe5\x58\x9a\x83\x3a\x79\x71\x2c\xc7\xe5\x86\xc2\xb0\xa4\x25\x1c\xf3\xc1\xf8\xf1\x77\x03\xb8\x88\xce\xc9\x33\xc9\xa5\x9f\xf4\x9f\xd7\xfa\xcf\x5f\xf5\x9f\x67\xd1\x65\xff\xd0\xd1\xc7\xb0\xb8\x18\x5f\xc6\x82\xbe\x24\xb7\x38\xed\x3d\xee\xc3\x3e\x44\x10\xc1\xbe\x7a\x73\xa0\x88\x6e\xd0\xfc\x1a\x0b\x46\x92\x16\xb2\x9b\x74\x6b\xd0\x5d\x48\x1f\x8f\x15\xe9\x9a\x72\x4d\xb8\xa6\x5b\x93\xbd\x16\x98\xdf\x9f\x74\x49\xfb\x73\x86\x56\x80\x40\xc9\x4c\xec\x28\x4c\x19\x5a\x9d\xcb\x67\x3d\x35\x85\x1c\x33\x82\xf9\x39\x11\x19\xe6\x03\x10\xf2\xef\xf9\xba\x90\x9f\x53\x24\xd0\x00\x70\x86\x97\x38\x17\x27\xe9\x40\xce\xf6\x3b\x29\xba\x72\x9d\x33\x71\x92\xa7\xf8\xd6\x0d\x4e\x42\x2b\xb4\x30\x85\x1c\xaf\xc0\x2c\x83\x1b\xc2\x4b\x94\x91\x9f\xd5\x82\x89\x9f\x5b\xa0\x5e\xbf\x12\x47\xd9\x98\xc0\x14\xc6\x87\x40\xe0\x49\x40\x8f\x11\xc8\x43\x20\xfb\xfb\x56\xe4\xaa\x7e\x62\x94\xa6\xc7\x34\x2b\x97\x79\xcf\x51\x7d\x41\x2e\x07\x01\x8a\x0b\xa2\x79\x27\x45\x33\x68\x7a\x4a\x57\xbc\x27\x9f\xa8\xd7\x64\x06\xbd\xaf\x7a\xd5\x58\x95\x52\x23\x79\x4a\x57\x66\x1d\x57\x12\x1f\x3c\xbd\xa8\x1a\x5c\xc2\x54\xbd\x56\x8b\xa2\x6b\xf4\x7a\xe4\x29\x4d\x4a\xd9\x28\x9e\x63\xf1\x42\xb7\x7f\xb6\x3e\x49\x5d\xe7\x7d\x43\xb0\x61\x6c\xc2\xf9\x71\x86\x38\x7f\x83\x96\x98\xc3\xd4\xd0\x11\x2d\x30\x4a\x31\x3b\xa5\xab\x68\x02\x51\x34\xd0\x0f\xd5\x5c\x9b\x67\xea\xf3\x90\xd1\x95\x7d\x49\xd3\xf4\xbc\xf5\xbd\xec\xed\xd0\xf4\x46\x0b\xe1\x3a\x41\x99\xc0\x2c\x47\x52\xb7\x9f\xd2\xd5\x99\x58\x67\x78\x02\x82\x95\x58\x63\x2c\xd0\x1c\x4f\x20\xc2\xb9\xd2\x4a\xee\xd9\x19\xf9\x19\x4f\x9c\xb4\x18\x54\x19\x5d\xfd\x59\x2c\x33\x1f\x81\x14\x23\x3d\x85\x13\x27\x52\xee\xd5\x11\x4f\x70\x9e\x92\x7c\x3e\x81\x19\xca\xb8\x69\x14\xf0\x63\x12\x7e\xb5\x23\xe9\x9a\xa5\x58\x0a\x7f\xaf\x92\x83\x81\x1a\x6e\xbf\xb6\x60\x32\x92\x63\x50\x4d\x6b\xab\xe6\x15\xc9\xf1\xb1\x7c\xde\x0b\x17\x4d\x63\xa1\x48\xb5\xe7\x56\xc6\x92\xe4\x30\x85\x93\x7c\x46\x72\x22\xd6\x96\xd1\x4b\x74\x0b\x53\x18\xfa\x8f\xdb\x96\x83\xc4\xdd\xb6\x0c\x94\x1f\x93\xdf\x60\x26\x94\x66\x9a\x11\xc6\x05\x24\x8a\x97\xd2\x28\x23\x78\x8e\x04\x8e\x15\xa8\x94\x6d\x89\xe6\x82\x5c\xc2\x57\x53\xc8\xcb\x2c\xb3\x58\xf4\x9a\xb8\x20\x97\x17\xe3\x4b\xb3\x6e\x65\xbb\x9e\x7b\xaa\x64\xd1\x48\xa3\xea\xf5\x25\xc9\x53\x39\xa4\x81\x1c\x81\xee\xa0\xa2\xfb\x23\x4c\xe1\xe0\x10\x3e\x1a\xba\x2f\xc8\x65\x45\xfa\x47\x47\xba\x1e\xff\x0d\xca\x60\x5a\x75\xff\xf1\xf2\xd0\xbc\x93\xd4\xca\x77\x4f\x64\x27\xae\x09\x18\x36\xde\xa0\xcc\x42\xde\xd5\x5a\x3c\x95\x14\x05\x2d\x14\x8b\x1b\x2d\xee\xec\xea\x92\xfe\x05\x86\x94\xe6\x91\x80\x15\xca\x85\x64\x1c\x5f\xd0\x15\xa0\x7c\x2d\x9b\x95\x98\x83\x72\x85\xc4\x02\xe5\x30\x06\x4e\x21\x41\x85\xe2\xb7\x24\x46\x41\x00\x92\x13\x80\x44\xac\xf1\x1d\xe9\xe9\xe0\x68\x89\x41\x90\x25\x1e\x68\x84\x07\xe3\x3f\x5a\x1f\x6d\xce\x50\xb1\x80\x6b\x9c\xd1\x55\x0d\x13\x99\xc1\x0a\x43\x82\xf2\xd8\x09\xce\xdf\x95\x20\xc3\x54\x81\x0d\xa1\x27\x87\x34\xd4\x9c\x19\xc1\xc1\xd8\xaa\x2e\x07\xf9\x04\xc6\x96\x05\x7e\xf3\xf1\xa1\x37\xe8\xa3\x34\x55\x5d\xa7\x58\xc9\x9e\x14\x6f\x3a\x03\x8c\x92\x85\x95\x20\x94\x6b\x88\x1c\x27\x98\x73\xc4\xd6\x5a\x0e\x7f\x85\xaa\x6f\x53\xdb\x51\x8a\x04\x96\x5c\x8a\x6a\x3a\xdb\x88\x5d\xb0\x1e\x0e\x1e\x6e\x1e\xa2\xbc\x5c\x5e\x63\x56\xef\x65\x17\xcb\xa0\x19\x76\xcc\x30\x12\x58\x71\x45\xea\x01\xc5\x9a\x70\xb4\xbf\x97\x09\x71\x2a\xe8\x3e\x66\x64\x34\x82\xf3\xb7\xcf\xdf\xf6\x6e\x96\x88\x2d\x69\xd6\x9f\xc0\x2b\x4a\x3f\x01\xc9\x05\x95\x8a\x2e\x9f\x5b\x07\xe7\x86\xe0\x95\xa1\x4f\x2e\x86\x39\x16\x80\x80\x2f\x29\x95\x7e\xb5\x46\x84\x72\xb2\xac\xc6\xdc\xb0\x18\x49\xc9\x6e\x94\x25\x9e\x40\x64\x75\xa7\xb1\x0c\x0b\x2c\x03\xab\x09\x7c\x3b\x1e\xeb\x07\x19\x9e\xe3\x3c\x9d\xc0\xe7\x82\x72\x25\x85\x13\x88\x72\x9a\xe3\xe8\x6e\x60\xd4\x4a\x52\xf2\x73\xc4\xe6\x58\x4c\x20\x4a\x90\xc0\x73\xca\xd6\x06\xdb\xcd\xd1\x2d\xe1\x93\x6a\xb1\x2b\x0f\x60\xa2\x14\xef\xc0\x2a\x19\x82\x57\x5a\xfe\x27\xa1\x16\x99\xb8\x95\x31\x08\x15\x43\x8d\x2e\xf3\xd2\x23\xef\x9a\x0a\x41\x97\x91\x53\x23\x87\x9a\x29\x27\x7a\x6d\xaf\x16\x34\xc3\x4a\x98\x8c\xa4\xc1\x02\x71\xa7\x10\xd4\x32\x1f\x80\x60\x6b\xc9\xdc\x04\xe7\x02\x33\x20\x2a\xec\x93\x30\xc6\xe4\x54\x2b\x1a\xa6\x53\x5f\xa3\x49\x3e\xc7\x6a\xd8\xb1\x1b\x5a\xac\x75\xdc\x41\x7c\x00\x7f\x92\xc0\x87\x9b\x40\x95\x02\x1d\xc7\x3f\x3a\x50\x25\x1d\x0f\x33\x96\x3f\x61\xa1\x87\x66\x82\x06\xa3\xde\x88\x1c\x94\xd4\xc6\x24\x87\x1c\xe5\x94\xe3\x84\xe6\x29\xf7\x2c\xe9\x1c\x8b\x13\x03\xd4\x33\x71\xd1\x00\x0a\x86\x6f\x08\x2d\xbd\x90\x25\x29\x99\x6f\x91\x0c\x64\xdf\x9a\x4f\xd9\xc0\x7f\x5f\x21\xb0\x6b\x76\xc9\x61\xf8\x14\x72\x1e\x3b\xc7\x59\x22\x91\xcb\xe5\x9c\x2c\x71\xaf\x0f\x43\x85\xc4\x3d\xe8\xc3\x9f\x94\x3b\x3e\x1e\x8f\xed\x20\x8f\x17\x38\xf9\xc4\xe5\x84\x78\x81\x22\x4e\x81\x0b\x24\x38\x90\x3c\xc9\xca\x14\xd7\xde\x31\xcc\x69\xc9\x12\xdf\xe5\x5e\x20\x7e\x6a\x9e\xf6\x54\xd3\x41\x05\xa5\x07\x6c\x08\x54\xef\x62\xfd\xbf\x61\xeb\x53\x18\xcb\x78\xcc\x7b\x73\x31\xbe\xbc\xb0\xad\x2f\x9b\x84\xa2\x2c\x93\x91\x89\x40\x24\xc7\x4c\xd2\x08\x05\xa3\x37\x24\xc5\x29\x64\x84\x8b\x07\x11\xfd\x92\xb2\xa3\x2c\xeb\x55\x68\x4f\xf2\x19\x6d\x8c\x41\x4a\x6d\x08\x61\xc7\x30\x9d\x4e\x9d\x55\x32\x43\x55\x0e\x9d\x55\xbf\x6d\x8e\x4f\x2b\xaa\x40\xd5\x2b\x85\xeb\xb3\x36\x6c\xa2\x42\x81\x8a\x44\xe7\x17\xd4\x09\xb0\x0e\x41\xf5\x46\xfa\xa7\x35\x97\x90\x63\x21\x05\x5c\x85\xe8\x3c\x96\x12\x87\x80\x70\x95\xac\x61\x84\xe3\x54\xbe\x44\x39\x20\xc6\x90\x4a\xc6\xa8\x0f\xdc\x64\x70\x56\x54\x62\x32\xeb\x8a\x4f\xe4\x17\x04\x5c\x30\xa9\x74\x33\x74\x8d\x33\x65\x58\x90\x74\x98\xb1\x0c\x2f\xb5\x37\x60\xb3\x13\xaa\xcf\x9a\x23\xfa\x93\xa2\xa3\xe7\x79\x9c\x9a\x32\x3d\x48\x43\x65\x99\xf3\x05\x99\x89\xde\x45\xf4\x4a\x76\x22\x83\xc9\xbf\x49\xcc\x2a\x98\x6c\xd8\xb5\x82\x16\x65\x26\xbf\x28\xc7\x40\x8e\xcf\xc4\x8d\xce\xe4\xc3\xb4\xdd\x26\xa9\xc1\x9e\x53\x67\xf0\x0d\x31\xf7\xb2\x9e\xc6\x92\xa8\xac\x8a\x35\x26\xd6\x62\x1c\x58\x8b\xc1\x70\xfa\x92\xd1\xe5\x04\x7e\x74\x0f\xce\xa9\x07\xb0\xc6\x32\xcc\xd0\x30\xff\xf7\x7b\xff\x99\x04\xb3\xad\x96\x24\xa7\xec\x9c\x24\x9f\xf8\x04\x0c\x50\x65\xd5\x26\xf0\x39\x2d\x99\xf9\xf8\xa3\x8c\xcd\x31\xe2\x2a\x04\x89\x64\x5c\x80\x58\x74\xe7\x87\x4b\x4a\x69\x56\x86\xbb\xd3\x6c\xab\x09\xdb\xd5\x64\x6b\x3b\x50\x29\xdf\x81\xe5\x8b\xaf\x7a\xb5\xeb\x88\x92\x85\x8c\x55\x48\x3e\xa3\xa1\x82\x7d\xad\xdf\xc8\x75\xd0\x63\x94\x8a\xe7\x84\x0d\x20\x41\x59\x76\x8d\x92\x4f\x5a\x4a\xbe\x96\x54\xfc\xe5\xec\xed\x1b\x0b\x00\xfb\x10\xa1\x82\x8c\x6e\x0e\xe2\xf1\xc8\xa0\x8e\x06\x60\xd1\x6a\x8f\x08\x3e\x57\x68\x8c\x8b\x04\x77\x01\x5d\x05\x6f\x21\xe7\x1d\xa3\xd2\x8f\xac\x91\x63\x57\xab\x8c\xdc\x76\xa7\xee\x71\x3c\x1e\x15\x3c\x82\xfd\x10\x41\xdf\x4c\x41\x9c\xd2\x1c\xf7\x76\x20\xda\xc2\xcf\x10\xc9\x1c\xfc\xc7\x7f\x2e\x6e\xd9\x00\x04\xbe\x15\x67\x02\x89\x92\x0f\x00\x33\x46\x59\x80\xe3\xe2\xb2\x31\x6c\x65\xbf\x2d\x3d\xc6\x3c\xd4\xf2\x8b\x38\x75\x10\x21\x7b\x64\x4f\x7c\x47\xc6\x8c\x46\x70\x8a\xff\x59\x62\x2e\xe0\x87\x31\x97\xba\xc6\x75\xbb\x20\x5c\x50\xb6\x56\x2b\x2d\xa7\xd2\xe7\x28\xa4\x97\x5c\x65\x9f\x74\xb3\x29\x48\xbe\xc6\x5a\x01\x91\xd9\xba\x57\x05\x94\xef\x0b\xe9\x90\xc3\x12\x91\x5c\x9b\x1a\xd3\x13\x4e\x9f\xad\xdf\x9f\xc0\x6a\x41\x32\x0c\xa5\x04\x92\xaa\xeb\x51\x5e\x2e\xaf\x14\xd8\x23\x58\x60\x66\x82\xcd\xa8\x7a\x1a\x4d\xe0\x07\xb3\xe0\xf4\x43\x4d\x4e\x34\x81\xb1\x5c\x41\x5a\x3d\x7c\x1d\xaf\x16\x38\xef\x59\xf7\xec\xeb\xb8\xa0\x5c\xb4\x4a\xa4\xb3\x69\x8d\xb9\x1f\xd8\xb1\xf5\x07\x5b\x11\x1d\x8c\x78\x79\xbd\x13\xae\x0e\x89\x72\x6d\x4f\x31\x2f\x06\x10\xa0\x93\x8f\xfc\x08\xb4\x12\x99\x10\xe4\x62\x7c\xd9\xd2\xd0\x45\xdb\xe0\x49\xd7\x73\xab\x32\x75\xe0\x28\x85\xea\xf8\xdd\x7b\x28\x39\x6a\x98\x85\xe3\xa2\x3c\xa7\x02\x65\xef\xe5\x3b\xdf\x3a\x2c\x9d\x3a\x18\x68\xe1\x74\x26\xdb\x78\x16\x05\x4e\xe2\x05\xe2\x57\x49\x51\x4a\x7f\xe3\xab\x16\x97\x25\x4a\x8a\x32\xea\x87\x76\x3c\xc8\x54\x29\x27\x5c\xaa\xef\x8b\xe8\x5c\x47\x75\x91\xa2\x27\xba\x3c\x0c\xcd\xc8\xc5\x65\x67\x78\xd7\xf0\x80\x02\x93\xef\x1c\x43\xdf\x21\x22\x26\x79\xe0\xf9\x85\xc1\x6b\x18\xc2\x81\x07\x62\x5d\xd4\x37\x92\xd4\x9a\x37\x1a\xcb\x70\x94\x0b\xb4\x2c\xb4\x4f\xea\xbe\x6b\x79\xd5\x18\xac\x2d\xaf\x86\x02\xd5\xa3\xb8\x28\xf9\x22\xc4\xd4\x6f\x83\x50\x20\x49\x51\xc6\x7a\x22\x85\xe4\x93\xf5\x48\x6b\x8f\x65\xa8\xef\x68\x36\xd8\x54\x3c\xae\x30\x59\xbc\x2e\x98\x0d\x52\x55\xa2\x2b\x49\x15\x1d\x53\x86\x79\xb4\x4d\xd0\x32\x8a\xd2\xa6\x9c\xbd\xa2\x28\xdd\x45\xc2\x3a\xc4\xe2\xe8\x06\x33\x34\xc7\xbf\x87\x60\x7c\xc9\x49\xb3\x73\x26\x79\x72\x85\xf4\x18\x54\x1e\x66\x3c\xfe\x72\xd3\x72\x5a\xe6\x2a\xa1\x0a\x62\xc1\x30\x4a\x37\xcf\x50\x81\xd9\x30\xa1\x0c\x6f\xd2\x09\xef\x30\x93\x53\xfd\xaf\xd0\x0a\x26\xd9\x84\xb4\x0c\x28\x8a\x4d\x9a\x89\x55\xae\x65\x5d\x3c\x9a\x22\x60\x22\x02\x8f\xde\x58\x1a\x14\x89\x84\x07\x52\xa0\x51\x69\xfe\x2b\xf1\x56\xbb\x22\xa4\x9a\x82\xff\x4f\x54\x90\x8a\xb4\x02\xf5\x51\x60\x26\xe7\xe8\x4a\x7d\x83\xe9\x54\x6d\x4c\xce\x48\x8e\x53\xdf\x1a\xb9\xc9\xa9\x12\xba\x0f\x5e\x18\x41\xce\x77\xac\x73\xbe\x1d\x13\x14\xa4\x7e\x43\xcc\x15\x69\xb0\x71\x44\x17\x1f\x2f\x9b\xba\xb1\x0e\xd1\x87\x91\x87\xae\xa1\x30\xef\x7e\x5f\xb5\xa9\x67\xe2\x9a\x61\xf4\x29\xa5\xab\xbc\xb9\x2a\xd5\x72\x7c\x66\xdf\x77\xae\xcb\x20\xa6\xed\x08\xb4\x37\xaf\xd3\x00\xf4\x61\x56\xfc\x3d\x57\xd9\xd3\xe8\xaf\x98\xe5\xf8\x3e\xe6\xbc\x46\xe6\xf6\x35\xd5\xd2\xa0\x6d\x6d\xb5\x82\xfd\x07\x98\xf9\x92\x63\xd6\x94\x64\xf9\xb4\xd5\xc8\x77\x2c\x96\x1a\x52\xbe\xe6\x02\x2f\x9b\x68\xf5\xf3\xdf\xc9\x7b\x38\xd5\xb9\x13\x1d\x0f\x1b\x11\x52\x11\xbf\x14\x91\x19\xa3\xcb\x20\x3f\xe2\xfb\xbe\x26\x99\x54\x72\x93\x84\x96\xd8\x0a\xc4\x39\xd6\x8d\x5f\xaa\xfd\x2c\x9b\x9a\x51\x19\xc6\x94\xdc\x90\xb4\x44\x99\x46\x5e\x50\x22\x59\x14\x46\x54\x1e\x7e\x35\x90\xe7\x48\xa0\x5e\x4b\xaf\xba\x87\x6e\x5f\x65\x07\x51\xb7\xfb\xd6\x75\xe4\x6d\x82\xee\x1b\xa8\x46\x83\x0b\x72\x19\xe7\x32\x94\x6d\xd1\xb0\x66\x57\xad\xb5\x4d\xb8\xac\x1a\x1b\x6d\xc6\x58\x75\xb6\xf4\xf6\xde\x7c\xeb\xb5\x01\xde\x2c\x34\xd3\x48\x45\xc0\x39\x66\x2a\xc7\x03\xbc\x40\x8c\x63\x33\xd3\x3a\xff\x65\x17\x08\x20\x21\x27\x0f\xdf\xc2\xcf\x98\x51\x27\x1d\x6a\x02\x01\x09\x87\x4f\x43\x91\xfd\x83\x81\x9c\xfb\x6b\x0c\xa5\x94\x06\xc4\xf5\xb6\xa6\xd9\x7b\x62\x74\x15\x7b\x74\xfb\x8b\x35\x58\x97\xd5\xe8\x9a\x33\x34\xa3\xec\x05\x4a\x16\x2e\xb8\xf3\xad\x65\xb8\xf8\xd4\xae\xa9\x1f\x9d\x85\x40\x17\x64\xff\xe0\xd2\xec\x67\xbe\xcc\xe5\x02\xd5\x8a\xa5\x02\xec\x58\x71\x8d\xe4\xa3\x2f\x27\x13\xf3\x77\x50\xad\xd9\x89\x5e\x88\xaa\xc9\x46\x9f\xd0\x1f\xeb\x16\xdf\xd0\x5f\x2b\x0d\x1f\xb1\xc1\x33\x67\x82\xbe\x6a\x26\x88\x5b\x16\xd8\x56\x73\x93\xd8\xe5\xa9\xb5\xf4\xae\x2b\xd7\xb0\xd5\x85\xe5\x15\xc7\x3d\x9b\xf2\x60\x13\xe0\x68\xad\x2b\xdb\xdd\x03\xb5\xc3\x3d\x2b\x28\xa1\x4a\xad\x06\x1c\x5b\xe5\xea\x9e\x3c\xc4\xdb\x68\x4c\xf7\x12\x2f\x29\x5b\xb7\xce\xf8\x6b\xf5\xea\xb7\x9f\x74\x4d\xc2\xbf\x64\xde\xcd\xb4\xc9\x59\xd3\x54\xe8\x19\x82\x11\xd0\x1c\xbf\xc6\x73\x74\xbd\x16\xf8\xcb\xcc\x8d\xc5\x66\xe7\x27\x9c\x20\x95\x04\x57\x33\x44\x65\xa4\x98\x65\xd5\x66\x44\xeb\xd4\xbc\xd5\x40\x9b\xa3\xb4\x16\x6f\x70\xb3\xef\xd4\xed\x80\x55\xde\x92\x44\x60\x88\xd5\xf6\xcd\x22\x35\x3e\xaa\xad\x1e\xd8\xee\x76\x6e\xe8\xec\xe9\x14\x1e\xfb\x2b\x73\x83\x1f\xb7\x91\xe4\xc7\x9e\x83\xc7\xd0\xca\x12\xb8\xfb\x1a\xfd\x52\xfe\xa1\x5f\x7f\x43\x61\x49\xb2\x8c\xa8\x70\x47\x97\x4e\xa0\x4f\x7a\x23\xa5\xc0\x2c\xc1\xb9\x40\x73\xac\x77\xc7\x2b\x96\x56\x56\xe6\x35\x12\x8b\x98\xd1\x32\x4f\x7b\xbd\x5e\x35\xa2\xc0\x65\x83\x51\x7b\x64\x65\xf6\x2b\x8d\xba\x52\xd3\x63\xf1\x3f\x55\x2f\x2a\x63\xe6\x4d\xe5\xc1\x78\xec\xc7\x43\x66\xaf\x48\x19\xa6\x8b\xe8\xf8\xdd\xfb\x68\x50\x41\x5f\x86\x75\x68\x7a\x35\xed\x2a\x12\x1a\xda\xab\x56\x3a\x43\xa2\x54\x3e\x82\xa0\xc1\xe6\x05\x27\x3f\x9b\xd4\xb1\xec\x44\x15\xd7\x36\x05\x43\x62\x35\xab\x59\x41\xb8\x21\xeb\x06\x4f\x03\x0e\x69\xc8\xab\x04\x15\x28\x21\x62\xed\xf8\x60\xb1\x6f\x00\x0e\xa2\xe3\x70\xc8\xfe\x54\xb5\xa8\x17\x85\x3c\x9c\x93\x90\xbb\x5a\xf9\x46\x03\x1f\x6d\x8d\xc7\x79\xb9\xfc\xc9\x2e\x45\xd3\xd8\xf8\x75\x7b\x2e\xec\x9f\x91\x0c\x5b\xdf\xfe\x73\xe8\x2a\xfa\xfb\xa7\x01\x64\x9b\x33\x1a\x38\xb6\x21\x78\x15\x73\x19\xaf\xb8\xca\x2a\x5b\x36\xcc\x32\x4a\x59\x4f\xed\xa6\x18\x06\xa8\x71\xc7\x63\x29\xad\xea\x69\xc5\xfd\xc3\xc0\x49\x93\x23\xb3\x05\x07\x28\xbd\x21\x9c\xb2\x78\xc6\x15\xee\xb8\x72\xa6\x14\x82\x14\xdf\x10\xb5\xc3\xed\xfc\x42\xb3\x41\xe1\xa9\x57\x53\x3a\xa1\xcb\xf9\x29\x4b\x31\xb3\x3e\xa1\x06\xb8\x70\x1c\xdd\x97\xbd\xc7\xca\xb5\xbc\x54\x0e\xfe\xcb\x33\xf8\x43\x04\xfb\xd0\xab\x9e\xc3\x3e\x1c\xf4\x07\xde\x70\x2f\xeb\xd5\x6f\xaf\x94\x04\xa9\xd2\x28\x55\x53\x24\x83\x19\xc7\x36\x4b\x55\x4a\x78\x91\xa1\xb5\xae\x8f\xff\x3e\xb6\x8d\xa3\x97\x0e\x32\xc5\x02\x91\x8c\x47\xc0\xb1\xb6\x01\x5c\x90\x2c\x53\xd5\x62\x7a\x07\x8d\xe9\xfd\x48\x35\xb7\xd2\x78\xb8\x5e\xb8\x5b\x2e\x4b\x74\x7b\x55\xe9\x6e\x7f\xa8\xdf\xbb\x15\x12\xc8\x91\x2e\x92\xbb\xf2\xb7\x8b\x1d\xb3\x9c\xd0\xf1\x8c\x24\xb8\x37\x1e\xf8\xc0\xbe\xbb\x6a\x0c\x67\xe7\x3e\xb4\x32\x87\x6a\x4b\xd7\xd9\x5c\xa5\x7c\x1e\x7f\xa7\x04\xe5\xf1\x77\x87\xf6\xf5\x4f\xa4\xfe\x3a\xb0\xd3\x6d\xfe\xcb\xbd\x6d\xe4\x56\x3d\xb5\x35\x69\xb2\x83\x43\xd3\xb9\xfb\x31\x80\xe8\xcf\x54\xdc\x23\x94\xfc\x62\x59\x93\x2f\x9d\xfb\xee\x76\xa8\xb6\x35\x59\x51\xf6\x89\xe4\xf3\x2b\x8e\x45\x6b\xc3\xce\x84\xc4\x9e\x09\x30\xcd\x8e\xb7\x9e\x2d\xa5\x6a\x07\xc0\xb7\x98\x14\x67\xb5\xae\x76\xd4\xfc\x1d\x82\xe2\x9b\x1e\xf8\xe6\x9b\x3d\x9b\x86\xd9\x02\xf9\x24\xe8\xbd\x92\x9d\x1a\x49\x3b\x98\x3a\xcb\x86\xf7\x76\xef\x55\xf9\x16\x8c\xce\xd5\x31\x97\x6b\xc4\xe2\x2f\xe5\x08\x2e\xa8\xd0\x6b\xac\xa6\xe8\x3b\xa6\xd2\x53\xfa\xc1\x50\x2d\x3a\xa5\x49\xb7\x21\x6c\xd8\x8f\x56\x54\x09\xcd\xd2\x0a\x93\x8f\x77\xe8\x88\x96\xb0\x5f\xf7\xa2\x3f\x58\xd6\x0c\x17\x54\x0c\xed\xd2\x8d\x57\x24\x15\x8b\x9e\x1b\xe1\x3e\x44\x7f\x8c\xfa\x8d\x36\xb2\xa3\x7a\x23\xaf\xf3\xb0\x95\x86\x1b\x0a\x7c\x2b\xa2\x6a\xc3\x58\x7e\xf3\x53\xdb\xfe\x59\x96\xfa\xb8\xf5\xe1\x8d\x91\xda\xa8\xf0\xe1\x02\x1e\xc0\xbe\x87\x2d\x82\x9e\x04\xf6\x59\x20\x69\xea\x47\xda\x35\xdd\x35\x7f\x57\x0f\x5e\xbc\x55\xa6\x6d\xa1\x5f\xd0\x37\x43\xfe\x79\x34\x57\xd0\x90\xa3\x25\x0e\x33\x6f\x6f\xb0\x90\x02\x72\x62\x5b\xa9\x92\xfe\x5e\x85\x44\x6f\xb1\x57\x5f\x8d\x09\x6a\x53\x82\x0e\xa6\xab\xf6\xcb\x41\xd8\xcc\x19\x4c\xa7\x10\x74\xd5\xa8\xfa\x22\xad\x49\x97\xe1\xc1\x86\xf8\x3a\xd7\x23\x02\x71\x3b\x62\xb7\xa0\x58\x56\x0b\xdd\xcc\x98\xd5\x51\x9d\x07\x6e\xb0\xd9\x4e\xba\x36\xd9\xcc\xfb\x4d\x1b\x6d\x72\xf6\xdc\x64\xa9\x39\xb4\x6a\x81\x04\xb3\x01\x53\x35\xe0\x80\x8e\x5a\xc9\x61\xc5\xe6\x7a\xc3\xce\x19\xae\x04\xb4\xee\xdc\x19\xca\xe3\x0a\xd5\xa0\x56\xcc\xd8\x84\x70\xc9\xe8\x60\x9a\x35\x0d\x5e\x81\x7b\x42\x73\x4e\x33\x1c\x67\x74\xee\xfa\x8f\xde\x9b\xdd\x53\x0a\x33\x92\xa7\x6e\x08\x8f\xa2\x01\xd4\xe4\x30\x7a\x24\x1d\xc8\xa8\xaa\x1a\x09\xf6\xfe\x0c\x59\x41\x36\x68\xab\xc1\x37\x02\x22\x3f\x9f\xda\xcf\xff\x9e\xd5\x0f\x27\xf9\x19\x4e\xee\x15\xf9\x9a\x9d\x6e\x5b\x21\xfb\x25\x9d\x8b\x70\x6b\xa3\x29\x10\x17\xa1\x10\x5c\xc6\xe2\xf6\x4a\x31\x17\x86\x4e\x33\x2a\x72\xef\xd1\xd6\xdf\x30\x0c\xb8\xf2\x65\x48\x64\xbf\x82\x44\xb6\x23\x89\x5f\x60\x1f\x47\x69\x2d\x28\x30\x03\x5d\xaa\xbd\x31\xd7\x68\xd5\x94\xaa\x89\xe3\xad\x5a\xf0\x85\x7a\xf5\x3f\x35\xf8\xdf\xad\x06\xb5\x02\xfc\x9f\xea\xfb\x6d\x54\x9f\x5e\x7e\x0f\xd4\x7d\xba\xf1\x6f\xaf\xfc\x1e\x4e\x24\xdb\x95\xc8\x2f\xa0\xfe\xb4\xba\x6a\xd5\x7f\x5e\xb6\xc9\x4b\xf1\xe8\x68\x45\x9f\x0e\xac\xf9\x81\x2f\x49\x86\xcf\x14\x94\xce\x50\x6c\x2a\x8a\x6b\x0a\x73\x8b\x0a\xb2\xe2\xab\x76\x5e\xda\x53\x7f\x2d\x0b\x12\x67\x30\x95\xc1\xc9\x93\x94\xdc\x3c\x8d\x3a\x0f\x5a\x6f\x4f\x10\x6e\x4f\x0f\x7e\x81\xe4\xa0\x4d\x8e\x19\x6e\x3f\x7f\xfb\xda\xc9\x9e\xb7\xce\x1e\x90\x37\xd4\x62\xcc\x63\x1b\xd9\x99\x92\x7b\x13\xd2\x79\x64\xbb\x90\x4e\x37\x90\xf1\x9b\x05\x0e\x63\xb9\xda\xe9\x7e\x37\xc2\xb6\x30\xce\x07\x72\xb9\x68\x17\xca\xf9\x81\x9c\x23\xa4\x1f\x19\x19\xbe\xab\xe5\xbe\x4e\x96\x68\x8e\x79\x8f\xa8\x3f\xce\x82\xea\xef\x32\xf2\xc9\xcb\x2c\x83\x5f\x7e\x01\xfd\xc4\x1d\xbe\xa9\x9f\xbd\xb1\x4b\x24\x38\xf7\x05\x53\xf8\x5c\x9d\x6a\xf0\x54\xfa\x29\x56\xc7\xdf\x74\xe2\x3a\x3a\x47\x73\xe5\xdb\x9e\x3c\x57\xc7\x49\x08\x13\x25\xca\xe0\x8c\xfc\xac\xd4\xbe\x3a\xe8\x21\xc9\x0d\x4b\x27\xdc\xe9\x7c\x85\x51\x17\x9e\x4b\xf8\xb6\x4f\xd5\x51\x4d\xfb\xa9\x42\x53\x1d\x10\xb7\xbb\x0f\x3b\xe5\xd2\x02\x66\x34\xa4\xbb\x45\x7f\x2b\x8a\xd1\xbc\xfe\x88\x49\x3e\xc0\xd4\xe0\x93\x01\xa7\x7c\x72\x25\x21\xa5\xf1\xe6\x45\x46\x44\x2f\x9a\x44\x95\x9d\x2c\x28\x57\x4f\x13\xdc\x1b\x1e\x0c\xe0\x60\x43\xdd\x5c\x0b\xce\xee\x72\x0e\xd5\x53\x17\x25\x1f\x9b\x94\x18\xff\x46\xb5\x72\xae\xcd\x81\x5f\xe9\xa0\x3a\xd4\x35\x29\x0a\xec\x22\x84\x96\x5a\xc8\x95\x3e\x78\x9b\x47\xa1\x8d\xd0\x43\xfe\x48\x49\xae\x7a\x6f\xb5\x23\xaa\x27\x0d\x32\x80\x0e\x18\x37\x2e\x92\xc6\xbc\xbc\xe6\x82\xf5\xc6\x03\x78\xfc\x5d\x3b\x78\x35\x8a\xcf\x37\x13\x8f\x27\x37\x5a\x36\xaf\xf4\x75\x28\xb3\x49\x90\x5c\x69\x07\xeb\xdb\xb2\x0e\x25\x58\xfe\xe1\x42\x07\x9f\xa8\xb3\x4c\xa9\x39\x29\xd8\x4a\x50\x48\x87\x69\xa0\x48\x48\x63\x41\x5f\xd1\x04\x65\xf8\x4c\xc9\x7b\xaf\xea\x71\x8b\x21\xd3\xc7\xaa\x44\xe7\x1d\x1d\x51\x4a\x93\x4f\x98\x0d\x75\xb7\xd1\x00\xbe\x1d\xfb\x77\x74\x1c\x36\x74\x89\x39\x90\x23\xd5\x09\x3f\xa5\x54\x0c\xa0\x3a\x7d\x52\xb8\xb3\x3a\x4e\xc9\x78\x0f\xdb\xf4\x8a\xc9\x9f\x69\x94\x43\x41\x8b\xa8\xaf\x15\x67\xf4\x86\x42\xf5\x02\x66\xb4\xd4\xf6\xb5\xa9\x8b\x42\xad\xb3\xa7\x3d\x58\x53\x75\xf8\x4e\x6b\x9b\x77\xe6\xef\x99\x40\x4c\x80\x75\x35\x8f\xdf\xbd\x87\x3f\xaa\x4b\x53\x5e\xbc\xd6\x1f\x4e\xcf\xce\xec\x8d\x17\x75\x05\xa5\x8f\xf4\x44\xa6\xc8\x9a\xe4\x73\x87\x86\x2e\x97\x28\x4f\x55\x3f\x67\xa7\xd1\x1e\x40\x87\xfa\xd2\x88\x37\xe8\xab\xcd\xda\xcc\xfb\xa4\x31\xb5\xb5\xda\xa0\x17\x7d\xc2\x7c\x85\xf8\x9d\x75\x13\xf4\x7c\x76\x14\x44\x9b\x14\xb0\x9d\x02\x37\x32\x03\x61\xba\xdb\xb1\x5e\xda\x68\xd8\xa6\x6c\xec\xa2\x66\xc3\x35\xe3\xe1\x90\x8b\x46\x15\x44\xee\x00\x57\x90\x74\x27\x30\xc4\x70\x2e\xae\x76\x84\xe6\x52\xbe\xae\xa4\xd3\xde\xbe\xbc\xad\x2e\x9e\x40\xbd\x1b\xbd\xd9\x7f\x95\x14\x65\x55\xa6\xb2\x09\xc8\xbb\xc1\x47\x2b\xd5\x07\xf6\xb7\xc4\xcb\xed\xfd\x2d\xf1\x72\xc7\xfe\x9a\x1d\x31\xce\x1b\x2a\xb4\x09\xd2\xbf\x2f\xfd\x81\x8a\x76\x03\xd8\xd0\x4b\xa0\xad\x37\x8c\xa1\x39\xa3\xa2\x6c\xaf\xa9\xad\x0f\x43\xab\x85\xee\xd9\xaf\xc1\x27\xcb\xdd\x04\x90\x33\xaf\x4a\x23\x5c\xa2\x26\x1c\x98\x33\x5a\x16\x30\xad\xf3\x48\x3f\xbf\x2a\x90\x2e\x01\xb0\xbe\x32\xd7\x61\x09\x43\x2b\xdb\x32\x23\xf9\x27\x40\x1c\x88\x00\x19\x5e\xf1\x6a\xdf\xd8\x9d\x31\x8b\x1b\xfd\xbd\x92\x8d\xa6\x10\x3d\x41\xb0\x60\x78\x36\x7d\xa4\x2e\x91\x72\x67\xe6\x5c\xdb\x91\x3a\x28\xa7\xbb\xda\x87\xe8\xd1\xd3\x28\xd8\x93\xd0\x6f\x3c\x6b\xfd\xed\x58\x7b\xc4\x4f\x46\xe8\x69\x54\x2f\x96\x74\x82\xa6\xdb\x29\xe1\x72\x14\xdd\xdd\xa7\x62\x7f\xab\x69\x0c\xed\xd2\x00\x1e\x7f\xdf\x30\x8d\x7e\xae\xab\x11\xe9\xe5\x34\x0d\x02\x3d\xa5\x1e\xea\x91\xde\x0e\xd9\xae\x8e\xe0\xc5\xf8\xdd\xe6\xac\x0c\x2c\x51\x01\x74\x06\x3a\x86\x51\xdb\x2b\x20\x68\x23\x28\xda\x16\x08\x39\xa4\xf7\x0e\x35\x3b\x02\xc8\x1d\x23\xd0\xdf\x2e\xd2\xc4\x59\x8c\x8a\x02\xe7\xa9\x73\xf8\x1c\x85\x9e\x24\x02\xa8\x8b\x5f\x32\xc4\x79\x2f\x62\x74\x05\x09\xcd\x86\x7c\x39\x3c\x78\xdc\x00\xd3\xe8\x24\x96\xc5\x77\x4f\x2b\x8f\xa5\xaa\x0a\x21\xaa\x1a\x44\x4a\xf1\x44\x85\x75\x5e\x70\xd9\xef\xfb\xc7\x04\x6a\xf1\xa5\x57\xdc\xe5\x28\xf4\x88\xaa\x36\x1a\xaf\xbd\xb6\xf2\xcb\x30\x45\xf9\xdc\x59\xe7\x07\x8d\xd8\x8c\xf6\xc7\x0d\x83\xed\x24\x48\x3e\xd4\x60\xb5\x11\x85\xc3\xf5\xa2\xe3\x40\x4c\x9a\x54\x7c\xdb\x1c\x8a\xd7\xd8\xe2\xbc\x57\x54\x5f\xdd\x0d\x00\x10\xd5\xa8\x8c\x26\xf5\x99\xb0\x46\x25\xf2\x7a\x8d\x26\xfe\x00\x2a\x08\x95\x27\x8e\x26\x40\xf4\x93\x3b\x2b\xce\xd2\xb3\x8d\x54\xe9\x90\x3d\xa2\x1f\xe3\x65\x21\xd6\xbd\x8a\x57\x38\x73\xfb\xae\x3b\x24\x80\xac\xc2\x79\x71\x5b\xe0\x44\xf0\xe0\x54\x44\x92\x51\x5e\x32\xcc\xd5\xed\x30\x28\xcb\x62\x38\x9a\x09\x6c\x8e\xcc\xe1\x5b\x9c\x94\x4a\x03\x49\x35\xf5\x97\x33\x60\x65\x2e\xcd\x14\x10\x2e\xf1\xcd\xc9\x0d\xce\x95\xb2\x67\x34\x83\x6b\x94\x7c\x82\x6b\x3c\xa3\x4c\x1f\x4b\x27\x79\x49\xf2\xb9\xba\x05\xf3\x5c\x5d\x3a\x6a\xb5\x99\x5e\xbc\x1c\x10\x5f\xe7\xc9\x82\xd1\x9c\x96\x3c\x5b\xfb\xda\x0e\x17\x2f\x54\xcf\xb8\x27\x3f\xf3\xea\x14\xfa\x1b\xaa\x5e\x72\x39\x30\x5a\xc4\x55\x1e\x1d\x17\x5b\x53\x0f\x2e\x51\x8f\x14\x0e\x55\x33\xa9\xc7\x87\x81\x08\x9b\xae\x57\xaf\xa6\xba\x97\x58\xdf\x65\xa1\xe4\x49\x3e\xe8\x55\xb7\x4b\x9c\x25\x0b\x9c\x96\x19\x36\xf7\x55\xdd\x0a\xf5\x5e\xe2\xe0\xfa\x62\x17\x5a\x8a\xa0\xc0\xbf\x65\x4c\x87\x70\x37\x80\x71\xed\x1e\xb8\x2c\x73\xb7\xf2\x70\x30\x7c\x2f\x5a\xaa\xe8\x15\x40\xaf\xbb\x06\xa9\x76\xd4\xdb\xe5\x00\x55\xe7\xae\xe8\x76\x4b\x81\xed\x2f\xbf\xb4\x95\x8a\x34\x6b\x2d\x35\xbf\x94\xc5\x6c\x39\xd7\xd0\x28\x35\x8e\x94\x99\x1b\xda\xdb\x47\x37\x94\x52\x1d\x7a\x1e\x97\x9d\xc4\xe3\x77\xef\xe3\xad\xa4\xef\x4e\x59\x78\x82\x3d\x4a\x8a\x72\xa8\xd2\x63\x43\x4d\xa4\xbd\x2b\x75\x47\x22\xdd\xc5\x57\xec\x63\x8e\xe6\x28\xeb\x4f\xe0\x14\x0f\xf5\x7d\x85\xea\x54\xc4\x2b\x8a\x52\x40\x6a\x91\xa9\xab\x5c\xb9\x40\xea\xc2\xc1\x46\xa9\xb6\x41\xb6\x69\x04\xa3\x11\xfc\x1f\xff\x74\xf4\x23\x49\x7d\x46\x51\xaa\xc9\x7e\xb4\x03\xd9\xa3\x51\x45\xf9\x4e\xbc\x0a\x4e\xf6\x7a\x0a\x5f\x31\xce\x1e\x0d\x7e\x28\xef\x76\xa2\xa0\x76\x8a\xb1\x4e\x83\xee\xba\x3a\x05\x79\x5f\x22\xac\x94\xe9\x32\x97\x2d\x82\x76\xdf\x55\xe0\xd7\x12\x9a\xfa\xbe\x87\xb1\xca\x52\x69\x76\x04\xb7\x90\x69\xf7\xd3\x76\xa6\x33\xa8\x2e\xb1\x3b\xa0\x43\xb5\x3d\xfc\x5b\x4c\x6a\xb8\x8d\x5b\xf5\xa7\x37\x64\x1e\xca\x1a\x57\xf8\xba\x85\x3b\x4d\xf7\xb2\x83\xe2\xed\xf6\xb6\x46\x55\x5d\x71\x95\x5c\xd0\xa5\xb9\xd1\x97\x6f\x51\x61\x0a\xf6\x6a\xa9\x61\x77\x9b\xb9\x39\x16\xba\x0b\xd3\x83\xbf\x34\xea\x1e\x4f\x95\x7b\xab\xbf\x08\x6f\x26\xf1\x30\x54\x1d\x1a\x9a\x5c\xb6\xce\xfd\x53\x2b\xb4\x8b\x04\xbd\x42\xd5\xdb\xa1\xc1\x51\xcd\x6d\xcd\x78\xf9\x5d\x1c\x7a\x28\xee\x5a\x67\xda\x3f\xc7\x53\x5d\x3d\xd3\x38\xc6\x03\x53\x19\x68\x89\xf0\x1c\x12\xaf\x57\xdd\x86\x66\xb3\xda\xaa\xef\x38\x68\x19\x6c\xd8\xcf\xa0\xf7\x80\xe3\x69\xdb\x26\xd5\x04\x2a\xba\xba\xfb\x98\x96\xd6\x03\xfe\x83\xd5\xb7\x7e\x0f\x43\x03\x37\x4c\x24\x60\xd4\x8f\x6f\x50\xd6\xf3\x38\xb8\xe9\x04\xde\x5e\x38\x4f\x6d\xd8\x03\x55\x15\xc0\xab\xe2\xed\x67\xeb\xe3\xa2\x6c\x3d\xf1\xea\x51\xdf\x6f\x9c\x68\xbc\xdb\xbb\x27\xff\xea\x85\xd1\x0f\x66\xa1\xd1\xc0\x0f\xe1\xe2\x86\x53\x6d\x21\x23\xbb\xfa\xd8\xca\x4b\xdd\xc3\x43\xd8\x69\x58\xda\xe2\x73\x86\x07\xa7\x51\xae\xfb\xaa\x9f\x8e\xe6\x2a\x59\xa1\x6f\xe1\x3f\x7e\xf7\x7e\xa0\xab\x30\x91\x80\x25\xe5\x02\x22\xcd\x15\xc0\xb9\x60\x24\x4c\x53\x6c\x14\x02\xd5\x4c\x4f\x4a\x73\x39\xc9\x0e\xdd\xd4\xa1\x01\x5c\xfb\xcb\x0a\xc5\xe6\xe2\x13\x1e\x4b\xaf\xf4\x29\x5c\x07\x0f\x1a\x15\x97\xba\xc6\x06\xe0\x0e\x70\xc6\x71\x1b\x8a\x27\xdb\x50\x84\x18\x6a\x2f\x13\xba\x2c\x10\xc3\xcf\xd6\x52\x47\x6a\x6a\x3d\xde\xfb\xf7\xa6\xb7\x8c\xd4\x1e\x73\x50\xdb\xd6\x4b\x92\x77\x2a\x17\xcb\xb2\xaa\xc6\x57\x31\x29\xe8\xfb\x21\x33\xaa\x05\xb2\x7d\x52\xd5\xa5\x81\x5d\xf3\xda\x2d\x90\x5f\x66\x6a\x4d\xa1\x7d\x30\xbb\xa1\x83\xb5\xe3\x04\x1b\x44\x4f\x76\x40\xf4\x9f\x39\xcd\x12\xc2\x50\x47\x04\x65\x70\x8d\xb8\xfe\x3d\x0b\xd3\x07\xa3\x59\x86\x59\xbd\x52\x3a\x1c\x0e\x2f\xaf\x8f\x94\xb9\x7b\xe6\x55\xc6\x95\xd7\x47\xba\xa8\xf9\xa9\x7a\xa3\xaf\x06\x08\x0f\xb9\x2a\x8e\x79\x7c\x77\x6d\x9e\x74\xb6\x19\xfa\x8d\x82\x37\xe3\x43\xef\x5c\xb9\x15\x62\x9b\x91\x94\xc1\xaf\x9d\x40\xfb\x3d\x38\x75\xac\xb3\x89\x9d\xb7\x30\x98\x1b\x9f\x78\xc0\x7a\xaf\x1c\xa6\x28\xcf\xca\xa5\xbf\xb3\xaf\x85\xc4\x7b\xe8\x37\x34\xb9\xcb\xc6\xf9\x7d\xf9\xb8\x2a\x8b\xd3\x28\xf7\x75\xea\xb3\xfd\x1c\xa8\xeb\xc4\x82\xed\x72\x66\x38\x38\xaa\x9f\x14\xe5\xc4\xf6\x35\x6a\x23\xd2\x48\x96\xd7\xdf\xc4\xeb\x77\x4b\x93\xc6\x74\xa8\x3b\x5c\xe9\x0c\xc8\x72\x89\x53\x82\x44\x38\x0b\x7c\x60\xee\x77\x95\x31\xac\x76\xdc\xaa\x59\xf3\xe6\xe6\xde\xbe\x97\x3b\xff\x5d\x73\x91\x03\xbd\xf6\xcb\x2f\x66\xd9\x6c\x00\x0a\xee\x84\x75\x2d\xbe\x6a\xe9\xcf\xfd\x96\xc8\x65\x50\xdf\xe4\x83\x56\x3f\x8a\xa0\x32\x76\x9b\xfa\x6d\xca\x4a\x43\x10\xa1\x89\xfa\x22\x98\x1d\xb9\x9c\x2e\x6b\x97\x63\xa8\x87\x87\xee\x46\xc3\x2e\x7f\x57\x0f\xe2\x01\x34\xd5\x7d\xde\x4e\xba\xbe\x6a\xbf\xf7\x29\x80\xac\x96\x70\xe3\xd0\x7d\xfb\x02\x3d\x6c\x41\xa2\x15\x66\xe3\x0e\x93\x9a\x3e\xde\xa0\x90\xc3\x7a\x04\x5e\xd5\xd2\xf6\x5a\xce\x6e\x48\xd7\xd0\xc6\xa0\x1c\x67\xfa\xb0\x64\xed\xbc\x8d\xc9\xc8\xda\xaf\x5e\xae\x9b\x17\x28\x77\xa9\xfd\xaa\x56\x77\x02\x51\xbf\x0d\xfc\xba\x82\x0d\x29\x51\x43\xdb\x5a\xd1\x0b\xb5\xc3\x27\x36\x43\x59\xed\x2d\xe5\x78\x65\xd5\xa4\x64\xce\x8c\x61\xbe\xd0\x77\x7f\x56\x46\x45\xdf\x95\xcb\x0d\xb8\x2e\x86\xae\x86\x0d\x29\xa3\x45\xed\x36\x29\xb5\x1d\x65\xf9\x57\x41\xda\xf4\x76\xd7\x61\xc8\x8d\x67\x1d\xab\x22\xeb\xce\x05\xed\x6f\x1c\xd5\xd6\x71\xdb\xd9\xb3\xd6\xe2\xe6\x8d\xc8\xdb\x9b\xec\x90\x57\xee\x98\xa4\x4a\x43\xec\x32\x89\x51\x74\xe8\xdf\x5d\x97\x65\xde\x59\x24\x7b\xd4\xd0\xcd\x44\xb8\x65\xa6\x36\x0b\xea\xd3\xd0\x5d\x82\x79\xcf\x91\x37\xf6\xcc\x02\x79\xeb\x38\xf9\xd7\x8a\xd0\x9e\x98\xaa\xef\xcf\xc8\x55\x90\x91\xfa\x06\x93\x5d\x29\x42\xb0\x5e\xc4\x68\xa6\x4a\x66\x0a\x86\x39\xce\xf5\x2f\x61\x75\xc0\x3b\x9c\xa8\x1d\xe5\x06\xf4\x4b\x9c\x97\x44\xe0\xe5\xae\xed\x04\xba\xd6\x9b\x38\x03\x18\x1e\x6c\x6d\x93\x64\x24\x91\xeb\xc5\x2e\x9d\x58\x36\x56\x97\xfc\xd4\xaa\xe3\xfb\x5b\x51\xb5\xe9\x8b\x6a\x8b\xda\x53\x6e\xbb\xcf\xcd\xb8\xba\x07\xca\x1a\x7f\xa5\x2a\xb4\xcf\xa5\xae\x16\x6e\xdf\x8d\x08\x55\x4a\xe5\x5b\x79\x59\xb1\x96\x22\x5a\xef\xad\x24\xba\xba\x8e\xd8\x0c\xfb\xd7\xe5\xaa\x9a\xb7\xe6\x76\x7a\x17\xfa\x9f\x54\x4e\x8d\x0d\x41\xc2\xb8\x38\x2d\xf3\x30\xc1\xd5\x05\x05\x53\x7b\xb5\xbb\x07\x7c\xaf\x8c\xa3\xfd\xd7\xba\xd3\xdf\x90\x86\xc8\x21\xd0\x79\x84\x5d\xb2\xa3\xfa\xdf\xdd\x6e\x14\xd6\x32\xc6\x01\x79\x56\xb8\xa2\x86\x8d\xac\x27\xf2\x1e\xd2\x73\x7b\xe2\x33\x20\x20\xcc\x30\xee\x94\x52\xec\xa0\xe4\x2e\xcc\x8c\xdd\x77\x57\xcd\x4f\xbd\xf8\xee\x05\x4a\xd3\xa3\x2c\x53\x57\xe0\x37\x9c\xdc\x46\xf6\x54\xfd\xf2\x86\x7b\xb8\xbd\x86\x5a\x47\x2a\xb2\xc1\x59\xa1\xce\x94\xb4\x70\x32\xe4\x62\x60\x0b\x82\x45\x03\x24\x6f\x52\x64\x0f\x3f\xdb\x30\x6b\xea\x83\x5c\x04\xed\x2f\xbd\x0a\x63\xff\xda\xd4\x8a\xbc\xf6\x4b\x40\xf4\x7b\x63\x40\x1c\x70\x68\x21\x2c\x98\xe2\xe3\xdf\xd4\x4f\x37\x55\x7d\x5f\x38\x0c\xd5\xad\x21\x6a\x35\x2a\x60\x98\x9a\x1f\x54\x30\x2f\xec\xd0\xf5\x2f\x1f\x54\x43\xb6\x88\xeb\xca\x40\x83\x4d\xa5\x55\x0e\xe5\x4f\x1a\xdb\xeb\x52\x08\x9a\x0f\xa5\xcd\x75\x34\xf4\xe3\x05\x49\xb1\x9f\x23\xbc\x73\xaa\xc0\x9a\x68\x6f\xd0\xfb\x10\x5d\xa9\x5e\x78\x47\xd1\x44\x63\xc9\x6f\x32\x92\xf7\x37\x93\xf7\x36\x94\x0f\x37\x95\xbe\xe1\x53\x0c\xf7\xcd\x9e\x63\xc9\x40\x4f\xce\x56\xd3\x67\x8d\x9f\x81\xf6\x38\x2e\x67\xce\x89\x40\x38\x71\x81\x68\x78\xbf\xc2\xa1\xff\x59\xca\x7a\x4d\x72\x0e\x1b\xaa\xc2\xff\x3d\x2f\x7f\xcd\xcf\xb1\xd0\x1a\x49\x1f\xca\xf3\x64\xc3\x1d\x37\xf7\x56\x48\xc3\x24\x3a\x89\x7c\x87\x08\xab\x96\xcd\xfe\x3e\xf1\x83\xb2\x2d\xcd\xec\xaf\xaa\x4d\x21\xe8\xdf\x9d\x44\xef\x38\x85\xee\x07\x46\x3e\x2b\x2c\x1b\xaa\xb0\xc8\xc9\xb1\x94\xe1\x5f\x1d\x1d\xa9\xbe\xb6\x47\x46\x66\xb2\x75\xc5\x82\x3b\x0e\xd9\xe4\x77\xb5\x61\x63\xa0\xa6\xd2\x2f\x33\xec\xdb\xc6\x71\x7d\x63\x52\x30\x6e\x73\x53\x92\x9f\xb7\xda\x3a\x01\xea\x38\xd9\x85\xba\x98\x51\xe1\xa8\xc2\x84\x96\xe0\x2b\x48\x5c\x29\x56\xe2\xb4\x2e\x89\xc6\x48\x6c\x1a\xf5\x1b\x7b\x81\x67\x73\xe4\x76\x9e\xa3\xe8\xd0\x9f\xf6\x9d\x47\x51\x93\x8e\xa6\xf5\xf5\xaa\x10\x3b\x2e\x8a\xbb\xbf\xa9\xf2\x5a\x29\xcf\xb3\x35\xc6\xe8\x68\xd7\xa8\x23\x0c\x2c\xac\x67\x91\xda\xd6\x20\xba\x0d\x06\xd7\x29\x39\x35\xb8\xc0\x86\x79\x97\x67\xed\xb0\xea\x6b\x98\x1e\x66\x26\xf5\xee\xd6\xcd\x39\xbe\xf5\x0b\x01\x01\x14\x13\x20\xc9\x10\xe7\xd3\x0f\x91\x0d\x1f\x3f\x44\x4f\xe1\x89\xb6\x62\xd5\xbb\x6b\x91\xc3\xb5\xc8\x87\xf6\x67\x80\x6b\x97\x7f\xd8\xa6\x43\x41\xe7\xf3\x0c\x7f\x88\x40\xac\x0b\x2c\xdb\x29\x34\x1f\x22\x20\x69\xf5\xad\x66\x1a\x2d\x91\x96\xc0\xfd\x80\xc2\x0f\x91\xaa\x71\x34\x88\x03\x2a\x01\x31\x82\x86\x0b\xc4\x0b\x5a\x94\xc5\xf4\x43\x24\x4d\xfa\x87\xa8\x4e\x9b\x82\xc2\xb7\x05\xca\x53\x2c\x89\x50\xda\xfd\x43\xe4\x2a\x80\x5d\xc7\xa0\xd5\x8f\x26\xb6\x6e\x91\x7d\xa4\x35\xbd\xf6\x21\x7a\xfa\x64\xa4\x14\x17\x68\x04\x96\x6d\x09\x62\x38\x78\x3b\xd2\x2c\xe8\xe8\xbc\xcc\xb6\x77\x6d\xdc\x82\x0f\x51\x63\xde\x86\xd2\xe4\x7e\x88\x40\x5a\xe0\xe9\x87\x48\x7f\x6b\xe5\x86\x42\x91\xe1\xf4\x7a\xdd\x35\x29\x52\x79\x2b\x39\x18\x95\x99\xfc\x5f\x2d\x96\x56\x9a\xa5\x04\x55\x44\xbb\x1f\x1a\x94\xca\xbf\x0b\x65\x80\xcc\x0f\xf3\x0d\xe2\x7e\xed\x16\xda\x30\x13\xa0\x9b\x1b\x65\xdf\x52\x0a\xe9\x97\x40\xd6\x54\x68\xa8\x99\xbe\xc4\x8f\xfe\xa0\xa2\x30\xfa\x65\xf4\x6f\xf3\xeb\x3f\x61\x21\xe0\x4e\xca\xf8\xbf\x24\xea\xf8\x6d\xb4\xab\x7e\xf3\x3e\xd7\x27\x20\x43\x38\xf5\xf3\xe4\xbe\x1a\x6e\x5e\x4c\xd0\x12\xa8\xdc\x2f\xac\xe9\x4c\x4f\xe8\xb1\x1d\xd3\xcc\xe8\x2a\xdf\xe5\xdd\xa9\x41\xd3\x17\xde\x35\x70\x3d\xdc\x0b\x9d\xe2\xc6\xa1\x2d\x50\x6e\xb5\xe7\xd1\x98\xe4\x7f\x97\x93\x13\xb2\x46\x73\x25\x64\xd3\x45\x80\xee\xb2\x11\xdb\x99\xfb\xbb\x73\x87\xc2\xe7\x87\xf1\x59\xa7\xee\xad\xf1\x71\xdc\xd8\x3b\x0e\x8d\x05\x9d\xc8\x18\x88\x5c\xab\x92\x61\xdb\x51\x18\x68\xe8\xdf\xd1\xb3\xdd\x5c\x54\xf0\x97\x7e\xbc\x11\x9e\x49\x51\x4d\x5a\x02\x0d\x3d\xf3\x15\x6c\xe5\xb5\x3c\x0e\x7b\x0c\x91\x8d\x5b\x11\x75\x5e\x04\xee\x80\x76\xba\xbb\xa0\x45\xed\x0f\xfc\xf5\x11\x28\x76\x5b\x73\xae\x0a\x50\x52\x58\x2d\xb0\x4b\x20\xc2\x8c\xe4\x84\x2f\x30\x57\x3f\xf5\xa3\xca\xc4\x43\x27\xf3\x1d\x9a\x7b\x9b\x04\xba\xa3\x05\xe2\xc7\x45\xa9\xfe\xbe\x36\x35\x0c\x95\x8e\xf7\xcf\x37\x8d\x46\xf0\x5c\xfd\xbe\xf2\x0c\x8b\x64\xa1\xe5\x52\xff\xce\xb1\xfe\xd9\xe5\x05\xba\xc1\xea\xe7\x96\xdd\x0f\x50\xba\x1d\x8a\x63\xf7\x6b\x16\xaf\x83\x92\x81\x8e\xa4\x7f\x78\x90\xbd\xb6\xec\x3a\xb7\x00\xbc\xc4\xa1\x4d\x54\x74\x24\x3d\x61\x6a\x07\xd9\x06\x14\x6a\xd5\x69\xa8\x65\x0f\xdb\x36\x27\xba\x14\x41\x17\x19\xb5\xc8\xa0\x5a\x18\x3b\xf8\xc4\x07\xe3\x60\x37\xca\x1c\x8a\x0a\x2e\x1a\x45\x42\x4f\xb7\xaa\xc6\x37\x01\x12\xe0\x1b\xcc\xd6\xf0\xc3\x58\x6d\x59\xed\xf8\x4b\x7e\x95\x39\x6d\x1c\x25\x86\xfb\x1c\x3e\x76\xfb\xed\xdc\xbb\xa7\xa5\x51\x52\xf6\x05\x88\xba\x37\x59\x55\xd1\xe3\x00\x7e\x18\xeb\x73\xe0\xee\x4c\x83\xff\xab\x8c\x03\xb9\xca\x94\x3f\xe4\x25\xef\x35\x4f\x0f\x2c\x4b\x5b\x7f\xab\xd1\x15\x78\xba\xb7\xdd\x21\x90\x9f\xdf\xaf\xe5\xf3\xbb\xb9\x57\x0f\x82\xe5\x68\xaa\x43\xed\xda\xbf\xf9\x7f\x01\x00\x00\xff\xff\x09\xd4\x28\x41\x2d\x87\x00\x00") func cmdInternalPagesAssetsJsContainersJsBytes() ([]byte, error) { return bindataRead( _cmdInternalPagesAssetsJsContainersJs, "cmd/internal/pages/assets/js/containers.js", ) } func cmdInternalPagesAssetsJsContainersJs() (*asset, error) { bytes, err := cmdInternalPagesAssetsJsContainersJsBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "cmd/internal/pages/assets/js/containers.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa9, 0x8b, 0x82, 0xb8, 0xe0, 0x68, 0x92, 0x21, 0x9, 0xc6, 0xea, 0xfa, 0x2d, 0x53, 0xd5, 0xf3, 0x57, 0x2, 0xe9, 0xae, 0x9b, 0x54, 0x52, 0xc9, 0xa4, 0xf3, 0x48, 0x7b, 0x72, 0x98, 0xd5, 0x8c}} return a, nil } var _cmdInternalPagesAssetsJsJquery351MinJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\xfd\x69\x97\xdb\x36\x12\x30\x0a\x7f\x7f\x7f\x45\x8b\xe3\x61\x00\x0b\x52\x4b\x76\x92\x7b\x43\x35\xa2\xe3\xb4\xed\xc4\x33\x59\xdd\xce\x24\x19\x8a\xce\x61\x8b\x50\x8b\x31\x05\x2a\x24\xd8\x4b\x44\xce\x6f\x7f\x0f\x0a\x0b\x41\x8a\xea\x64\xe6\x79\x6e\x72\xdc\xe2\x02\x62\x2d\x54\x15\x6a\x3d\x7f\x3a\x3a\xfb\xed\x87\x8a\x15\x0f\x67\xb7\xcf\xa7\x9f\x4c\xe7\x67\xf5\x19\x5a\xe3\xb3\x7f\x5c\x9d\xbd\xce\x2b\x9e\xc4\x22\xcd\xf9\x59\xcc\x93\xb3\x5c\x6c\x59\x71\xb6\xce\xb9\x28\xd2\xeb\x4a\xe4\x45\x79\x56\x9f\xfd\xf6\xbb\xfc\x74\x9a\x17\x37\xe7\x59\xba\x66\xbc\x64\x67\x4f\xcf\xff\x7f\xa3\x4d\xc5\xd7\xf2\x43\xc4\x88\xc0\x07\xaf\x2a\xd9\x59\x29\x8a\x74\x2d\xbc\x85\x97\x5f\xff\xc6\xd6\xc2\xa3\x54\x3c\xec\x59\xbe\x39\xdb\xe5\x49\x95\x31\xdf\x3f\xf1\x62\xca\xee\xf7\x79\x21\xca\x65\xf7\x96\xb2\x69\x92\xaf\xab\x1d\xe3\x62\x29\x10\x23\xa3\x19\x0e\xda\x56\xf1\x21\xdd\xa0\x51\x5b\x04\x8b\x6d\x91\xdf\x9d\x71\x76\x77\xf6\xaa\x28\xf2\x02\x79\x7a\xcc\x05\xfb\xbd\x4a\x0b\x56\x9e\xc5\x67\x77\x29\x4f\xf2\xbb\xb3\xbb\x54\x6c\xcf\xe2\x33\xf3\xa5\x87\x17\x05\x13\x55\xc1\xcf\x04\x62\xb8\x09\xe0\x2f\xf2\x2a\x9e\xb0\x4d\xca\x59\xe2\x8d\x4c\x77\xd5\xf7\x4b\xf5\x13\x88\x6d\x5a\x12\xdb\xa1\x4b\xc2\x7a\xd3\x70\x1b\x17\x67\x82\x86\x11\x29\xe8\x77\x30\xee\xe9\x0d\x13\xdf\x17\xb9\xc8\x65\x75\xdf\x6d\x48\x49\xc5\xb4\x94\x73\x4a\x6e\xa8\x98\x6e\xb2\x58\x2c\xdd\xf1\x99\x4e\xc1\x9b\xe9\x3a\xce\x32\xe8\xde\x60\x91\x75\xce\xd7\xb1\x98\xc6\xfb\x7d\xf6\x80\xc2\x88\x30\xdc\x90\x8a\x8a\xe9\xbe\x2a\xb7\x24\xa5\x62\x9a\xf2\x84\xdd\x7f\xb7\x21\x9c\x1e\x1a\x92\x53\x3e\x15\xf9\x95\x28\x52\x7e\x43\x6e\x29\x9f\x6e\xe3\xf2\xbb\x3b\xfe\x7d\x91\xef\x59\x21\x1e\x48\x4c\x6f\xdb\xf7\x19\x8d\x55\xe3\x6a\x10\x98\x3c\xc8\x2a\x76\xf4\xb8\x1f\x9e\x79\xd4\x2e\xb0\x5c\x74\x5e\xed\xae\x59\xd1\xce\x22\x9b\xf2\x3c\x61\xef\x1e\xf6\xac\x21\xf7\x03\xd5\x9c\xf1\x2a\xcb\x46\x94\xf9\x3e\xa3\x94\xb2\xa9\x9a\xee\x86\xbc\xa2\x97\x76\xb5\xc9\x9a\x1e\x64\x75\xc1\x68\x46\xca\x62\x2d\x7f\x78\xce\xd7\x4c\x5d\x7c\x03\x70\x14\x8c\x66\xcd\xc2\x54\x7f\x76\x2d\x01\x95\x70\x7c\x90\xcb\x52\x90\x94\xe4\x14\x71\xca\xeb\xfa\x15\x9e\xae\x0b\x16\x0b\xf6\x2a\x63\xb2\x6a\xe4\x95\xeb\x22\xdd\x4b\xb0\x48\x37\x28\x9f\x0a\x76\x2f\xa8\x04\xf2\x4d\x5e\xa0\xe2\x2c\xe5\x67\x6b\x8c\x52\x2a\xc2\x22\xaa\x6b\x58\xd3\x17\x42\xed\x17\xe6\xfb\xdd\x7b\x54\x60\xec\xfb\xf9\xb4\xec\x3c\x23\x29\x5e\xf0\xe9\x96\xc5\x89\x5c\x2f\xc6\x93\xcb\x6d\x9a\x25\x28\xc7\xd3\x7d\x5c\x30\x2e\xbe\xcd\x13\x36\x2d\xd8\x2e\xbf\x65\xe6\x4d\x63\x87\x71\xd7\x9b\x27\x4a\xd9\x92\x8d\x3d\x2f\x38\xda\x5b\xac\xae\x87\x16\x64\xc9\xc3\xdc\x00\x53\x54\xd7\xe6\xb3\xc0\xbc\x6f\xe4\xfc\x6c\xa8\x07\x98\xc2\x23\x57\xb4\xbb\xd1\x4d\xd3\xec\xee\xec\x6a\xba\xe1\xd3\x94\xa7\x02\xde\x38\x53\xbd\x97\x7d\x54\xd0\x3f\x1a\x49\x08\xc8\x18\xbf\x11\x5b\x2f\xe5\x12\x1e\xd8\x54\xdd\x12\x4e\xe5\x60\xf4\xde\x1b\xed\x10\xc3\xbe\x3f\xba\x87\x1f\xe4\xc5\x45\x11\x3f\x78\x94\xca\x15\x9a\x51\x4a\x45\x5d\x1b\x40\xb2\x63\x11\xbe\x3f\xbb\x10\xbe\x2f\x26\x73\xb9\x2c\x0c\x37\xb2\x4b\xf4\x6a\xba\x37\x9b\x8c\x1e\x14\xf6\x0a\x36\x64\x9d\xf3\x52\x14\xd5\x5a\xe4\x45\x70\x45\x54\x17\x82\x19\x11\xf9\x0b\xd9\x52\xbb\xab\xec\x10\x4b\x35\x4b\x72\x97\xe3\x86\xdc\x30\x31\xb4\xf3\xcc\x12\xb8\x85\x03\x76\x31\x5b\xca\xab\x90\x8d\xe5\x8f\x1e\x6f\x14\xa8\x67\x51\x43\xe4\xae\xbc\x12\xf1\xfa\x43\xa7\x4a\x35\x63\x57\xd3\x1d\x2b\x6e\x18\x54\x35\x75\x3a\x8d\x30\x61\x2d\xa2\x9a\xee\x0b\x76\xab\x36\x24\x05\x3c\x24\x1a\xc2\xe2\xf5\x76\xa8\x8f\x57\x53\xf9\x06\x2a\x04\xbc\xb0\x8b\xf7\x6d\x31\xde\x22\x11\xd9\xa0\xed\x19\xba\x9a\xee\xe2\x3d\xea\xe2\xb8\x0e\x04\x68\x20\x22\x42\x56\x8a\x71\x43\x00\x95\x0d\x4c\x64\xaf\xe2\x52\x63\x29\xa8\x3a\x2e\x6e\x60\x3f\x97\xb2\x82\x4d\x5a\x94\xe2\x54\x05\xec\x77\x34\xc3\x0d\xc9\xe2\x47\x8b\x4c\xe6\xb8\x21\xec\x96\xf1\x3f\xef\xc7\xd5\xf4\xa6\x60\x8f\x8c\x10\x89\xf1\x1c\xff\xfd\x19\x0c\x2d\x4f\x92\xff\xf3\x0a\xcf\x84\xae\x8d\xfd\x3e\xb0\xee\x0e\xa4\x10\x4e\xc7\x6c\x8c\x00\x8c\x82\x59\xbb\xe8\xdd\xe6\x66\x17\x94\xfb\x3e\xbf\x10\xcb\x10\x00\x8b\x47\x51\x10\x46\xb2\x7a\x7e\xba\xb3\x16\x6a\xea\xfa\x18\xc0\x14\x60\x06\x15\x29\xf3\x42\x04\x62\x2a\x7f\x48\xb9\x87\x65\x15\x53\x75\xd1\x90\xab\x29\xbb\x17\x8c\x27\x14\xf6\xbf\xbe\x76\xda\x93\xc3\x01\x54\x4b\x00\xcb\x92\x98\xda\x45\x0e\x67\x51\x5d\x1f\x1a\x52\xd2\x39\xa9\xda\xc7\x66\xd8\x19\x1d\xcd\x17\x12\xcb\x7a\xd7\x79\x9e\xb1\xd8\x41\x5b\xb1\xef\xa3\x8c\xc6\x9d\xca\x4a\x5d\xd9\x78\x8c\xc9\x11\xf6\x8b\xeb\x7a\x87\x62\x5c\xd7\x28\xa6\x87\x06\x93\x92\x52\x5a\xf9\x3e\x8a\xd5\x76\x29\x27\x13\xbc\x28\x2f\xaa\x85\xfc\x3a\xdd\x20\x45\x72\x10\xeb\x54\x8f\x01\xe5\x0b\x85\x5b\x0a\xca\x42\x11\x11\xef\xd7\x5f\x01\xbb\xfc\xfa\xab\x37\xa2\x54\xf8\x7e\x3c\xa2\xb4\x90\xbd\xf3\x7d\xf9\x73\x35\x4d\xcb\xef\xb3\x38\xe5\x6a\x9a\x51\x21\xbb\x90\x52\x40\x32\xd3\xb4\x84\x5f\x49\x16\xf0\x12\x71\x1a\xcb\x1a\x73\x9a\xfa\xfe\xa8\x5b\x80\xe3\x65\x18\x05\x69\x5d\xf7\xab\xe3\x78\xc9\x83\x43\x43\x52\x3a\x9a\x13\xf9\x39\x35\xcb\x81\x32\x92\x93\x02\xe3\xe0\x36\x4f\x93\xb3\x99\xee\x15\x14\x29\xb0\x85\xa1\xb8\x5d\x3f\x74\x60\xf7\xfb\x98\x27\x79\xa0\x39\x25\x6f\x8c\x36\xe3\x6f\x62\xb1\x9d\x16\xf2\xf1\x0e\x61\x3c\x2d\xd8\x3e\x8b\xd7\x0c\x9d\xaf\x5e\x9e\xdf\x10\xcf\xc3\x24\x2d\xdf\xb2\x38\x79\x90\x84\x96\x49\x3e\xab\x03\xca\x7d\x1e\x4c\xa2\x1b\x9e\xe7\x7b\x17\x1e\x1b\xd2\x19\xd2\xf1\x56\x20\xdc\xd0\x04\x34\x92\x44\x2c\x54\x6b\x7b\xa6\xca\x47\x72\xde\x2d\x05\x93\xb4\x62\x84\x04\x95\x4d\xe1\x21\x82\x87\x38\xbd\xd5\xb8\x99\x78\x0e\xb4\x7b\x58\x12\x6b\xe7\x01\xf6\x7d\xcd\xe7\x70\x4c\x29\xcd\xb0\xec\xe7\xab\xdd\x5e\x3c\x9c\xea\xe7\xc2\x85\x0e\xd5\xe1\xb9\xe9\xf9\xac\x21\x37\x59\x7e\x1d\x67\xaf\x6e\xe3\x2c\x70\xb1\x81\x64\x41\x24\x2f\x72\x50\xfc\x8a\x24\x5f\x53\xb8\x6c\x08\xc7\x47\x48\x5c\x62\x0f\xd9\x18\x27\x05\x9d\x49\x7e\x44\xd2\x56\x7c\x90\x2d\x73\x6a\x28\xe9\xa2\xb8\xe0\x8b\x42\x01\xf2\x68\x2e\x89\xa5\x9e\x9e\xb0\x88\x48\x41\xe4\x0f\xc6\xd7\x05\x8b\x3f\x34\x2c\x2b\xd9\x99\x65\x64\xd8\x9f\x7f\x61\x00\x87\x49\xba\xf1\x81\xf5\x88\x65\xdb\x3f\x49\xa0\xc3\x68\xd1\xe7\xe0\xd0\x5e\xb3\x8d\xb2\xdb\x4b\x43\xdb\x38\xf1\x4a\x60\x2e\x5d\xbe\x24\x64\x51\xc0\x70\x50\xe9\x45\x20\x0c\x63\xc2\x1b\x92\xf2\xe3\x36\x09\xef\x11\x60\xb1\x9c\xcc\x83\xd4\xac\x33\x83\x99\x84\xa6\x7a\x5d\x95\x23\x57\xdd\x1d\x0b\x83\x75\x0a\x3a\x23\xe9\xf1\x5c\xb2\x30\x1d\x8f\x23\x60\xf3\xec\x1c\xe8\x32\x34\x25\xac\x21\x12\xd9\x1f\xf5\xca\x34\x50\x48\xbe\x3f\xa5\x33\x92\xdb\x9a\x49\x4c\x47\x7c\x91\x5e\xe4\x8b\x74\x3c\xc6\x23\x81\x58\x98\x46\x24\xc5\x23\x4a\x63\xdf\x2f\x00\xb3\xc3\x33\xbb\x59\x8b\x1e\xad\x3e\x62\x60\x67\x24\xa6\x61\x64\xc1\x02\xd6\xb5\x1d\x49\x7e\x51\x2c\xf2\xf1\x18\x6b\xdc\x96\x52\xd9\x64\x1e\x91\x9c\x70\x0c\xd0\x0e\x2d\xa6\x78\x61\x81\x22\x57\x40\xf1\xa7\x1f\xe8\xfe\xdd\xa0\x58\x72\x46\x55\x9a\x04\x73\x52\x56\x7b\x79\x6a\x0b\x1e\x1a\x4c\x06\xf8\xce\xab\x87\xdd\x75\x9e\x01\x82\xdc\xf0\x50\xdd\x4d\x53\xc1\x8a\x58\xe4\x85\x9c\xe6\xfe\x23\x4c\x34\xdf\xe2\x7d\xa1\x88\xc1\xd9\xb7\xc0\xfe\x9d\xa9\x63\xc9\xd9\x6b\xc3\x6d\x02\x78\x9c\xbd\x8c\x05\x3b\x7b\xcb\x6e\x5e\xdd\xef\x35\xa2\x50\x28\x48\x37\xec\x01\xf9\x12\xc8\x3b\xf3\x70\x8f\x38\xf3\xd0\x62\x18\x6f\x2c\xc6\x5e\xe4\x45\x54\x4c\x45\xfe\x75\x7e\xc7\x8a\xcb\xb8\x64\x08\x37\x18\x0e\x73\x0e\x99\xe3\x86\xce\x25\xe4\x9a\xe4\x24\x25\x5b\xb2\x21\x37\xe4\x8e\x54\x24\x23\xef\xc8\x25\x89\xc9\x2b\x72\x4b\x4a\xb2\x26\x0f\xe4\x8a\x7a\x65\xfa\xc7\x1f\x19\xf3\xc6\xf3\xa7\x12\x39\xca\xce\x92\x3d\xe5\xed\x71\xe6\x03\x9d\x01\x20\xee\x68\xc5\x10\x26\xf7\xea\xe7\x85\xfa\xf9\x56\xfd\xbc\x1c\x66\xc5\xe5\x21\x49\x00\x79\x1c\xcd\x30\x99\x35\xe4\x37\x7a\x68\xfa\x27\x3a\x38\x87\xfe\x2e\x0f\x84\xf9\x9e\x7c\x6d\x0e\x86\x5f\x99\x8b\xef\xec\x49\xf4\x7b\x7a\x6a\xc7\xc8\x0e\x5a\xd8\xe2\x17\xc5\x82\x2b\x8c\xc3\x42\x1e\xc9\x2e\x60\xb3\x23\x35\x78\x4c\xe6\x0d\x79\x4b\xbd\xf5\x96\xad\x3f\xb0\xa4\x2e\x59\xc6\xd6\x82\x25\x75\x5c\x3e\xf0\x75\x1d\x57\x22\xdf\xe4\xeb\xaa\x84\xab\x7d\x16\x3f\xd4\x20\x77\xc8\xb3\xb2\x4e\xd8\x86\x15\x75\x92\x96\xf1\x75\xc6\x92\x7a\x9b\x26\x09\xe3\x75\x5a\xee\xe2\x7d\x9d\xe5\xf9\xbe\xde\x55\x99\x48\xf7\x19\xab\xf3\x3d\xe3\x75\xc1\xe2\x24\xe7\xd9\x43\xad\x4f\xfa\x49\x5d\xae\xf3\x3d\x4b\x3c\xf2\x0d\xf5\xc2\xd5\xea\xfe\xd9\x6c\xb5\x12\xab\x55\xb1\x5a\xf1\xd5\x6a\x13\x79\xe4\x0d\xf5\xd0\x32\x58\xad\x56\xab\x70\xb5\x4a\xe2\xc9\xe6\xc5\xe4\x75\x74\x98\x93\x4f\x1b\x6f\xfc\xcd\xd8\x5b\xd6\xf0\xea\x7d\xfb\x49\x1d\xae\x56\x77\x93\xa8\x0e\xdf\xaf\x66\x93\xd5\xea\xfe\xff\xd9\x44\x78\xec\x91\x9f\xa8\xb7\x5a\x85\xf0\xcd\x53\xe4\x8d\xdf\x8c\x3d\x8c\x96\x81\xbe\x0f\x9f\xbe\x7f\x52\x8f\xfe\x13\x2d\x29\xd6\x4f\x96\xc1\x47\x48\xb7\x3b\x95\x55\xad\x56\xab\x8f\x22\xfc\x14\x7f\x54\xaf\xbc\xfe\x8b\x95\x27\xdf\xac\xbc\x5a\xd7\x8b\x6b\x5d\xcb\x6a\x15\x79\xe4\x35\xf5\x82\xb6\xc1\xd5\x0a\x21\xf4\xdf\x57\x8d\xeb\xfe\x1b\x84\xc3\xd5\x2a\x8a\x6a\x6f\xfc\xd3\xd8\xc3\x4f\x71\x3d\x7d\x8a\x57\x2b\xd9\x34\xf9\x82\x4a\xc0\x55\x1b\x0c\x7d\x33\xf6\xc6\x1e\xf1\x6e\x3c\x4c\x9e\xb8\xcf\xbd\xf7\xd0\xc7\x31\x54\xfc\x5e\x57\x1a\x61\xd3\x0a\x7e\xaa\xc6\x30\x7e\xa2\x3f\xfe\x75\xe0\xe3\xa7\x44\xfd\x78\x98\xfc\x31\xf4\x1a\x85\x9f\x8f\xff\x23\xbb\xf8\xcd\xd8\xc3\xb6\xe8\x8f\xbd\xee\xd5\x9f\x7b\x98\xfc\xec\x3e\x7c\x8d\xc9\xbf\xfa\xf5\xbd\x19\x7b\x4f\x3c\x4c\xbe\xa4\x87\x37\x2f\x83\xce\xbb\xbf\xe9\xd9\xf5\x30\xb9\xfc\xfa\xc5\xd5\x55\xf7\xed\x6a\x35\x6d\xdf\xbf\x7b\xf1\x65\xf7\xad\x7a\x55\x87\x4f\x23\xf9\xfa\xc5\xbb\x77\x6f\x83\x5e\xbb\x3f\x61\xf2\xfd\xd5\xab\x1f\x5f\x7e\xd7\x7f\xf1\x1a\x93\xcb\xaf\xde\x7c\xdd\xeb\x4c\x80\x00\xbc\xe1\x78\x54\xcb\x03\x50\xcd\xc5\x56\xfe\x9b\xc8\x1b\x3c\x41\xeb\x6d\x9a\x25\x75\xbe\x99\x48\x64\xab\x21\x42\xcf\x96\x3c\x0b\xd5\x79\x92\xd4\x08\x85\xe3\x49\x54\x63\xb4\x5a\x25\x4f\x31\xaf\x5b\xa0\xd4\x2f\xf4\xfd\x6a\x95\x8c\x71\x8d\x2d\xb4\xc1\xea\x7b\xa9\x87\x89\x64\xca\x7b\x23\x95\xc0\xfe\x76\xec\xe1\x27\xba\x08\x67\x2c\x29\x2f\x73\x2e\xd8\xbd\xe8\x8f\x4d\x56\xa7\xd6\x2e\x68\x7b\xc5\x7e\xaf\x6f\x44\x9d\xa9\x11\xb5\x03\xec\x8e\x01\x2d\x83\xc9\x6a\x95\xe0\x25\x74\xdd\xe9\x18\x5a\xd2\xf0\xfd\x24\xaa\x9f\xe8\x2e\x36\xe4\x17\x7a\xfe\xd5\xbb\x6f\xbe\x7e\x72\x9e\x92\x1f\xe8\xb9\xec\x60\xca\xf7\x95\xd0\xd8\xa7\x96\xfd\x8a\x0b\x16\xd7\xd7\x95\x10\x39\xc7\xb2\xdc\x3f\xe8\xf9\xfb\xed\x2a\x91\x97\xff\xa4\xe7\xef\xc3\xf7\x87\x68\xbc\x3a\xac\xca\xa7\xab\x90\xc7\x22\xbd\x65\x67\xab\xbb\x73\xf2\x6f\x55\xdb\xdf\x50\x28\x11\xc1\x18\xd7\x68\x75\x37\xc6\xf5\x6a\x6a\x1e\xe0\x27\xe7\x84\x31\x7a\x1e\x8e\xff\x13\x9d\x13\xc1\x3a\xb0\xf6\x27\xa8\x06\xb9\xb8\x06\xeb\xcd\xc1\x19\x1d\xe2\xb3\xbc\xd9\xbd\x37\x66\x0a\x5b\xa3\x39\x9e\x7c\xfa\xc9\x27\xcf\x3f\xb5\x47\xc4\xba\x46\xfc\x62\xb6\x54\x34\x72\xba\x29\xf2\xdd\xe5\x36\x2e\x2e\xf3\x84\x21\x3e\x86\xa2\x38\x18\x7c\xf9\xf9\xe7\xf3\x59\xfd\xc9\x27\xcf\x3e\xfb\x94\xcc\x67\xcf\x9e\xfb\xbc\xfe\xe4\xd3\xe7\xcf\x66\xf2\xb8\x5a\x30\x7a\x8e\x42\x89\xf8\xee\xe7\x1b\xc0\x7d\xf5\xfb\xc9\x72\x95\xe0\xfa\xfd\xe4\x89\x46\x89\xfa\xcd\x64\x55\xbd\x7e\xfd\xfa\xb5\x9c\x91\xf3\x1b\x92\xf6\x47\x60\x7a\xb9\xf4\x56\x33\x8f\x52\xca\x96\xde\xaa\xda\x6c\x36\x89\x17\x98\x11\xcd\xc8\x64\x8e\xc7\xde\x6a\x25\x07\xb9\xd6\xdd\x7b\x21\x90\xa1\x3c\x93\x39\xb6\xa2\x49\x34\xff\x14\x8f\xbd\x33\x2f\x50\xc5\x1b\x92\x33\xf7\x20\xfa\x4e\x9e\x68\x63\x46\xaf\x19\x3a\x96\x8a\x8c\x66\x20\x5b\x34\x44\xc6\xf7\xbd\x4d\xca\xb2\xa4\x64\x02\x3a\x06\x22\xca\x6f\xe3\x1d\xeb\x31\x02\xe4\x90\xa4\x45\xe0\xb5\x82\x3a\x8f\x70\x09\xeb\x5e\xc6\x6e\x18\x4f\xbc\x06\x2f\x44\xf1\x70\xf8\xca\xc8\x38\xe8\x77\x8a\x29\xdd\x4f\x61\x8f\xca\x2f\x4a\x4c\xba\x77\x22\x74\xef\x8d\xb4\xa8\x15\x92\xae\x63\xb1\xde\xca\x9e\x7f\x45\x0f\x50\x6d\x60\x78\xd7\x65\x77\x7a\xbf\xd6\xad\x32\xa2\x5b\x15\xb8\x23\x2f\x6e\x81\x88\x39\xcc\xef\xe2\x6e\x9b\x66\x4c\x92\x71\xcd\xef\x8e\xc7\x11\x5e\x58\x5e\x57\xd2\xf1\xa6\x95\x3f\x96\x4c\x31\xd8\xa4\x50\x75\xc1\x09\x9f\x94\xc0\xf7\xac\xc9\x06\xa4\xb6\xd3\xfc\x8e\xb3\xe2\xa5\xe1\x6d\xf6\x94\x2d\x5b\x99\x6f\xf0\x99\xe4\x57\x41\xf2\x1a\x46\xf6\x1c\x60\x85\xc3\xa2\xae\x47\xa2\xae\xe7\x23\x4a\xf7\xbe\xff\x99\xfa\x99\xc3\x6d\xcb\x60\xc8\x53\x8b\x3c\xdd\xbe\x43\x0c\x13\x46\x59\x5d\x5f\x92\x57\x18\x34\x02\x73\xfd\x25\xaa\xe8\xbf\xa7\xec\x9e\xad\xe5\x24\x48\x36\x25\xa5\x55\x38\x8f\xa0\xcc\x67\x54\xd6\x06\xfa\x03\x14\x53\x36\xbd\x61\x42\xcb\x7e\xbf\x78\x78\x93\xa0\x14\xe3\x4e\x53\xf1\x34\x4d\x28\xa5\xa9\x7d\xa8\xf8\xe0\x58\x1e\x4f\x80\x75\x4e\x37\x68\x03\xa2\x85\xcd\x40\x55\xbe\x2f\x17\x24\x06\xfe\xf9\xf1\x7a\x64\x87\xaa\xf0\x59\x64\xde\x1b\x20\xe2\xc4\xed\x62\xf9\xc5\xc3\xbb\xf8\x46\x82\xa6\x1c\x19\x81\x1e\xc2\xe0\x9e\x47\xd8\xf7\x93\x6e\xc9\xcb\x2c\x2e\x4b\x59\x56\xae\xca\xf0\x9b\x3f\x6d\xcd\x96\x94\xa3\x21\xbc\x49\x37\x28\x99\xfe\x5e\xc6\xbe\x3f\xfa\x36\x14\x72\xff\x45\xf2\x10\x7e\x5b\xd7\xa3\xdb\xa9\x60\xa5\x90\xfd\xf2\x7d\x04\x0b\xd1\x0a\x98\x47\xa7\x77\x95\x5a\xb9\x35\x15\x12\x7e\x88\x3c\x8e\xca\x05\xfc\xd1\x54\x56\xd7\x7f\xd8\x7a\xf1\x01\x6d\x28\x63\xe6\xde\xf7\x1f\x18\x62\x8e\xdc\x1c\xd7\x35\x93\xc7\x77\x26\xa7\x02\xd8\xc0\xba\x46\xa8\x54\x8b\xdc\xca\xe0\xbd\x34\xf1\x30\x5e\x96\xb4\xb4\x12\x8e\x82\x91\x94\x61\x89\x87\xfa\x05\x49\x49\xaf\x30\x26\x39\x45\x19\xdd\xca\x4e\x18\x26\x58\x6d\x9c\x7c\x32\xc1\x59\x98\x47\x14\x95\x4b\xef\x6f\xde\xb8\x0c\xbc\x00\x5a\xf6\x00\x39\x8d\xef\x19\x92\xaf\xf1\x62\x4d\xb3\xe9\x6f\x79\xca\x91\x47\x3c\xdc\x48\x34\x71\x34\xf5\x9b\x29\x88\xab\xaf\x80\x5a\xe5\xc5\x8b\x2c\x43\x6b\x98\x74\x8b\x03\xbe\x45\x82\x8c\x66\xb8\xd9\xa4\x3c\xce\xb2\x87\x43\x49\x29\xbd\x92\xab\xab\x14\x06\xbd\x21\x36\x4d\x63\xcf\x6a\xc2\x0e\xf5\x09\xf1\x9e\xcc\x3d\xac\xb7\x71\xbb\xb7\xe5\x29\xe3\x60\x4e\xaf\x86\xa4\xd8\xb7\x72\xe3\xb7\xe7\x6e\x7d\x5e\x85\xf5\xc7\x9f\x5f\x4f\xd7\xf1\x7a\xcb\xbe\x86\x79\xf1\xfd\x84\x65\x4c\xb0\x33\x16\x16\xd3\x72\x9b\x6e\x04\xc2\x11\x61\x1a\x56\x28\x77\xb0\x89\xc4\x3b\xed\x41\x26\xbc\x8a\xe8\x68\x46\x58\xfb\x7e\xcd\x5a\x01\xe9\x65\x5f\x4d\x63\x11\xb6\xc2\xb9\x1a\xaf\x8f\xe4\xbe\x68\xe7\xcb\x08\x66\xec\x84\x09\x07\x5a\x7c\x5f\x9c\xd2\xb9\x08\x4c\x04\x95\x07\x61\xa7\xb7\x1b\xd6\xc5\xa1\xfa\x48\x59\x7b\x98\x14\x94\x77\xa1\xa2\x98\x4c\xf0\xf5\x34\x16\xa2\xf8\x2a\xe6\x49\xc6\x42\x1e\x16\x51\x44\x45\x5b\xdb\xbe\x53\x9b\xf0\x7d\x26\x6b\xf1\xfd\xb9\xa5\x3f\x12\x5d\xaa\x7b\xe1\xdc\xb3\x69\x99\x57\xc5\x9a\xbd\xe1\x09\xbb\x9f\x08\xf7\x4e\xe2\x82\xc2\x6c\xe8\x02\xf0\x2c\x56\xdd\xe1\x94\x4f\x25\xa1\xba\x4a\xaf\xb3\x94\xdf\x80\xc8\xd3\x39\xb4\x4d\xe6\x56\xc6\xb1\x9c\x07\x93\x79\xdb\xcb\x44\x4e\xe7\xa1\x07\x0b\x8e\xca\x0f\xd8\xab\xc7\x48\xa6\xec\x30\xa8\x62\x28\x15\xce\x5c\x6e\x99\xa3\x7a\x38\x96\x86\x9f\xaa\x4d\x77\x13\xb5\xed\x8a\xba\xf6\x14\x37\x07\x77\x6e\x7b\x2e\xa4\xdd\xfc\xc9\x38\x36\x79\xb1\x03\x05\xd5\x92\x75\x00\x64\x34\xef\xf0\x09\x4b\x2f\x8b\xaf\x59\xa6\x4a\x3a\xd7\xce\x37\x9d\x0a\xec\x87\xb2\x6f\xc1\xd1\x6d\x5a\xbe\x74\x1e\xd4\xb5\xfb\x64\x44\xe9\x48\xf8\x7e\x2c\xb7\xc0\xd0\xd7\x4e\xeb\x72\xcc\xee\x3b\x67\xdc\xb7\x0c\xc5\x76\xdc\x99\xc3\x09\xe5\xf6\x69\x4e\xc7\x39\x71\x5f\x75\xa4\x8e\x31\xa8\x93\x0d\xbf\x90\x63\x92\xd2\xa2\x0b\xea\xe9\x64\x82\x59\xc8\x69\x11\xa6\x91\x24\x05\x20\x10\x18\x21\x21\x7f\xe4\x35\xc6\x8d\xfc\xdf\x76\xe9\xa1\xb3\xe9\x7d\x7f\x48\xd3\x3e\x4c\xf1\x7c\x9f\x35\x9b\xbc\x40\xec\x2c\xe5\x67\x09\x2d\xd9\x54\x4b\x9d\x28\x88\xc4\x4b\x39\x7d\x3f\x7f\xf3\x35\x1d\x84\xa7\x78\xc7\xca\x7d\xbc\x66\x3f\xbe\x7d\x43\x38\x45\x3d\x2e\x45\xd2\x0d\x2b\x8e\xd1\x0d\x1b\x61\xee\x2f\x9a\xdc\xd4\x35\xf7\x7d\x6e\x21\xb3\xae\x3d\x79\xd6\x90\xc7\x8e\x77\xd0\x17\x26\x4c\x6d\xc7\x3d\x90\xa8\x16\xf8\xa0\x7e\xab\xc1\xde\x8a\xfb\x46\xf4\xd2\xf7\x25\x73\x52\x38\xdb\xbd\xe8\xf7\x0a\x38\x0d\x74\x49\x8b\xa3\xfe\x92\x57\x74\x94\xa2\x4b\x4c\xf6\x50\x13\xe2\xf4\x72\x9a\xb0\x4d\x5c\x65\xe2\x5f\x29\xbb\xc3\xb2\xf3\x22\xdf\x8f\xa8\x44\x33\x88\x4f\xe3\x24\x79\x75\xcb\xb8\xf8\x3a\x2d\x05\xe3\xac\x58\x1e\x3f\x42\x5e\xc5\xb3\x3c\x4e\x3c\x92\x33\x32\x9a\xe3\x80\x4b\x9c\x16\xaf\xb7\x50\x4a\x56\xe8\xdc\x22\x2f\xe7\x6d\x71\x8c\x89\x26\xc1\x74\x3d\xc4\x81\x9f\xc5\x1d\xf5\x37\xc3\x9d\xdb\x23\x6c\x9f\xa4\xb7\x1e\xc6\x64\x18\x58\xfa\x54\xd3\xf7\x47\xc7\x0f\x91\xa6\xcb\x67\x86\x70\x9c\x41\x9d\x1a\x98\x1b\xd9\xdd\xd8\x90\xcf\xf2\x44\x9f\xd9\x74\x6d\xd8\x21\xea\xa5\x1e\x19\xf5\x19\x0b\xfb\xda\xc3\x50\xe3\x10\x18\x9f\xac\x7b\x68\x02\x2e\xf3\x9d\x9a\x00\x39\xfa\xd1\x09\x4e\xd0\x7b\xda\x1d\xc7\x30\x03\x47\xff\xa9\x00\xf9\xf2\x14\x2b\xa8\xbe\x94\x9c\xeb\x5f\x5d\xb2\x34\xa1\x57\x64\xd4\xab\x50\x6d\x8e\xa1\xa7\xe8\xaa\xdf\x4d\xd9\xd8\x12\x5d\x4f\x37\x69\x26\x58\x31\x7d\xf3\x72\x70\xf3\x1a\xce\x45\x30\xc2\x5b\x2d\xf8\xe0\x1c\x1e\xf3\x79\x0a\x23\x12\xd9\x06\x4f\xba\x2d\x48\x44\x97\x6e\x06\x6d\x7d\x44\x8f\x97\xf7\xfd\x57\x96\x56\xf7\xd9\xfc\xb6\x4b\x7c\x19\xf2\x28\x08\xa3\xa6\xc1\xc1\xa3\xa3\xe2\x7f\x69\x54\x6a\xfc\x27\x11\xa4\x1d\xa8\xa2\x55\xc7\xcf\xd4\x04\x58\xe9\x80\xe4\x77\x6e\xe3\xac\xd2\xc4\xf1\xff\xde\x94\x28\x55\xef\xe0\xc4\xa4\x1b\x49\x6a\xe4\x21\x85\xd3\xfc\x44\x07\x01\x33\x99\x8e\x99\x13\x49\x98\x47\x8b\xb4\x53\xa5\x01\x22\x86\x9d\x73\x6b\x4e\x53\x75\x64\xfd\xdf\x9a\xd0\xfc\x31\xac\x98\x99\x8f\x77\x2f\xbe\xa4\xc3\x3b\x77\x39\x24\xcf\xf8\xb3\xa9\x72\x3e\x1f\x7e\x8c\x18\x0e\xe0\x48\xb5\x14\xc7\x48\x8b\x19\x8d\xee\xe0\x49\x9e\x38\x8a\xa6\x93\x95\xcb\x35\xf0\x9e\x02\x93\x86\x0f\x86\x1f\xcc\x41\xbf\x85\x25\x7b\xc3\x3b\xe4\x06\xf8\x7a\xee\x28\xa1\x0c\x9b\x60\xe1\x05\x24\xa2\xfd\x19\x72\x8e\x9a\xff\x35\x30\x75\x3f\x7f\x85\xad\x95\xcb\x89\x83\x28\xc3\x0d\x29\xe5\xc0\x6f\xe5\x1f\x75\x1c\x6d\x91\x5b\x7f\x0a\xe1\x34\xda\xc3\x67\x4a\x81\x7b\x8c\xce\x38\x67\x85\x24\xea\xd4\xbb\x88\xcf\xd2\x84\x7e\xe4\x8d\xaf\xc6\xde\x47\x9f\x5f\x9c\xc7\x9f\x5f\x28\x21\x62\xfb\x78\xb2\x2a\x56\xab\x8f\xce\x76\x65\x9c\x65\xf9\xdd\x3a\xde\x8b\xaa\x60\xf4\xa3\x8f\x3e\xbf\xc8\xf7\x5a\x58\xa2\x74\x1e\xf0\xec\x5c\x3d\xfc\xfc\xe2\x5c\x3d\xfe\xdc\x23\x43\x34\x2a\xec\x56\xf7\x9e\x7e\xf4\x51\x64\x91\xbb\xef\xdf\xaa\xf5\xf1\xc2\xa7\xef\x9f\x44\xb4\x55\x2c\x7c\x54\xaf\xbc\x15\xc8\xa3\x07\x2b\x35\x3d\x69\xab\xaa\x6b\x53\x55\xab\xc2\x58\x06\xb0\x43\x6a\x25\xd4\x3d\x55\x57\x9a\xfc\x87\xaa\xf1\x0f\xd5\xf6\x1f\xea\x61\x82\x06\x8e\x6b\x8a\x63\xc7\xb8\x77\xc0\x96\x7c\x99\x07\x96\x05\x5d\xfa\x27\x4e\xb4\x2e\xcb\x77\xe6\x64\x60\x20\x50\x27\x5c\xfd\xe5\x19\x0a\xb4\x9e\x6a\xa0\xda\xf6\xd5\xe0\x97\xf1\xdf\x60\x32\xc6\x4f\x07\x3e\x9d\xfe\x6d\x3a\x0e\xc7\xff\x89\x4e\x7c\xba\x5a\xad\x36\x1e\x26\x76\x4d\x1d\x1d\x95\xe4\x1e\x7a\x30\xcb\x7a\xe0\xb9\x2d\xd8\x86\x7e\xf4\xd1\x99\xe5\xfc\x3f\x32\x57\x5d\x78\x1d\x7c\xaf\x80\xf1\xdc\x81\xc6\xc5\x89\x63\xb6\x5e\xb7\x85\xe8\x2d\x9c\xdc\xc7\x1e\xf1\x94\x76\x6e\x60\xf9\x86\xd7\xf9\xe5\x29\xa8\x82\x75\x4d\x86\x40\xbd\x5d\xcd\x56\xa5\xe6\x61\xf2\x0c\x24\x4a\x03\x2b\xc9\x38\x0c\x72\xa0\x26\xfb\x8a\x78\x81\x99\x0b\x0f\x93\x23\x34\x60\x67\x6c\x34\x3b\xdd\x4c\x5b\xc1\x5f\x6d\x67\xa8\x9a\xa7\x24\xb8\x77\x40\x80\x4c\x9f\x06\x72\xed\xb1\xc4\x6a\xbb\x58\xac\xb7\xac\x34\xe5\x0d\x86\x5b\xd3\xd8\xbc\xaa\xeb\x78\x7a\xc7\xae\x3f\xa4\xe2\x9b\x6e\x59\xf9\x62\x97\xff\x31\xf0\x34\x1f\x2a\x59\xf6\x1e\x4a\x94\xd9\x83\xbe\x44\xce\xca\x3a\xe7\x1c\xf0\x08\x94\xa7\x6b\x63\x03\x08\x3a\xb8\xf6\x2e\x2c\x47\x72\x8b\xc2\xc8\x4a\x3d\xb2\x11\xf5\xc8\x6b\x09\xd5\xb7\xf4\xd6\x4e\x98\xa3\x23\xb9\xd5\xb2\xb1\x5a\xf2\xb9\x25\x2d\x87\xca\x94\x6e\x19\x61\xe6\x23\x9e\xae\xf3\x9d\x3c\x72\x9b\x53\xd5\xf7\x79\x99\xca\x6e\x63\xf2\x20\x0f\xd5\x4e\x31\x2e\xe2\x94\x97\x78\x39\x24\x13\xff\xac\x23\x77\x59\xb2\xfe\xe9\x2a\x60\xa4\xa0\xa2\x2b\x32\x5a\x38\x3a\xf8\xa2\xae\x47\x68\x54\x28\xd9\x75\x7b\x82\x93\x4f\xb9\x6d\x7a\xd9\x5e\xa2\x02\x07\xec\x54\xd7\x7d\x7f\xfe\xa9\x7f\xf2\x2d\x18\x90\xf5\xf9\x81\x74\x83\x84\x96\xf6\x08\xea\x76\x52\x72\x46\xc2\xe1\x7a\x46\xb3\x85\x95\x8a\x91\x97\x54\x2c\x8f\xea\x61\xae\x3e\x3f\x93\xbb\x60\xb6\x50\x93\x34\x3a\xd9\xa7\xc9\x48\x9c\x7a\x65\x99\xe3\xba\x46\x73\x79\x2c\x1d\x3a\x7c\x53\x8a\x44\xff\xa9\xc0\xcb\xd3\x73\x20\x70\x30\xc7\x75\x3d\x4a\xc0\x4e\xf1\x25\x93\xc7\x50\x96\x28\xab\xae\xe1\x2f\x40\x8e\xc2\x97\x8c\xd2\xcb\xba\xee\x75\x01\x64\xce\x0f\x68\x4f\x18\x5e\x4e\xe6\x81\x80\x32\xe2\x44\x19\x81\x97\xf3\xa0\x5a\x7e\x8f\x2a\xc2\xf0\x44\xfe\x08\x1c\xcc\x82\x8f\x7d\x2e\xbf\x9d\x0f\x2d\xcd\xc9\x29\xb5\xf6\x47\xed\x82\x01\x2f\xe7\xdc\xc6\x34\x64\x91\x64\x78\x04\xd8\xfa\x8c\xd2\xba\x1e\xe5\xb8\x05\xbd\x4b\xd3\xe3\xe5\x3c\x48\xe5\x75\x3e\xd4\xbd\x05\x28\x41\x28\xb5\x5f\x6a\x01\xe4\x82\x53\xb6\x68\xa5\x84\x0e\xdc\xc4\xd3\x8a\x2b\xf9\x2d\x97\xa5\xc4\x70\xa9\xd2\x2d\xa5\x4a\xc4\x61\x11\x51\x4a\xcb\xb0\x88\x70\x31\x1e\x5b\x56\x72\xb9\x57\xef\x08\xbc\x09\x54\xb1\xbd\xec\x71\xa9\x2f\xe7\xc1\xac\xc1\xe4\xb2\x21\x25\x33\x38\x6e\x58\x87\x58\xca\xce\xf3\x2a\xcb\xd4\x1f\x81\xdd\x4f\x2c\xc6\x3c\x5a\x06\xd0\x18\x1d\x61\x56\xdf\x7f\xd5\xd3\x66\x94\x75\x3d\x2a\x5d\x6d\x46\x4f\xbf\x81\x45\xf1\xa0\xf1\x86\x45\x7b\x02\x18\x6d\x5e\xd7\x03\xa8\x52\xc2\x9b\xc1\x27\x5a\x9f\xd5\x3e\xb0\xb8\xc2\x6a\x86\x8e\xe5\xfd\xfa\xcd\xec\x02\x14\x70\x97\x6a\xd4\x21\x8b\xec\x79\x5a\x0e\xdf\xa0\x96\xc1\x29\x1b\xda\x74\x20\x27\x82\x39\x79\x50\x46\xfc\xb2\x96\x58\x88\xfe\xcc\x3d\xfa\xad\x46\x0d\x1d\x69\x77\xcf\x80\x2a\x52\xa2\xed\xdf\xd4\x54\xb9\x25\x49\xaf\x24\x5e\x2a\x3b\xb7\xd1\x2b\x73\xee\x31\xd0\xd3\xda\xb5\x2e\x8b\xc0\x15\xd5\xd4\xf5\xe8\xd5\xb2\x77\xf0\x17\x38\x00\x53\xb8\xa3\xc3\x20\xac\x66\x31\x2d\xf7\x6c\x9d\x6e\x52\x96\x2c\x0b\x75\x2a\x0c\x40\xd6\x2f\x87\xcf\xca\x75\xbc\x67\x03\x7e\x29\x88\x8d\x3d\x0f\xf7\x14\x46\xea\x93\xa2\xe8\x00\xdb\xb1\x21\xac\x77\xf5\xc0\x45\x7c\x7f\x06\x25\xc9\x59\xc5\x0b\xb6\xce\x6f\x78\xfa\x07\x4b\xce\xd8\xfd\xbe\x60\x65\x99\xe6\x3c\x38\xf3\xc6\xba\xca\x8a\xa7\xbf\x57\xec\x2a\x2f\x06\x65\x89\xca\xab\x48\xe2\x0d\xd8\xd6\x19\x1d\x25\xd3\x84\x09\xb6\x16\x2f\xab\x7d\x96\xae\x63\xc1\x4a\x52\x51\x8d\x1b\xaf\x84\xe4\x40\x40\x73\xa0\x74\xec\x92\x15\x91\x2f\xd0\x4b\x4c\x32\x73\x24\x14\x54\x99\x3c\x62\xa0\x15\x61\x2a\xf7\x41\x41\xb9\x31\xfa\xc3\x8e\x62\x83\x69\x63\x70\xc4\xe5\x66\x9e\x5b\xe8\xac\x40\x63\x42\x58\x43\x72\x5a\xc2\xe4\xbf\x63\xf7\xc3\x03\xf0\x3c\x8b\xf8\x0c\xf4\x03\x82\x52\x4a\x5c\x4a\x69\x5a\xd7\x9f\xa9\x9f\x39\xdc\xaa\x83\xe4\x91\xd9\x28\xb8\xe7\x80\xc5\x09\xb7\xe8\xb5\xf3\x10\xac\x74\x19\x65\x53\xb0\x2e\x01\x16\x6f\xc1\x16\xf2\x81\xab\x0f\xe1\x63\x9a\xcb\x63\xa5\xd1\xe7\x3e\x57\x4d\x7f\xec\xea\x6b\x55\x4f\xff\x25\xa1\x45\x95\x6b\xe7\x0d\x04\x10\x50\x87\x68\x45\x41\x0d\x41\xd7\x4a\x2e\xac\xb0\x4c\x49\x0f\x8e\x96\x2c\xf8\x64\x46\x14\xa7\xfd\x7d\xc9\xaa\x24\x0f\x32\x46\x00\x2d\x05\x5f\x92\x76\x7b\x04\x87\x86\xc8\x33\xb7\xfc\x2d\x58\x06\xf6\x28\xc1\xc1\xfb\xdc\x0b\x8e\x0d\x11\x94\xfb\xc4\x68\xd6\x10\xef\x6c\xe0\x7d\x43\xbc\xb1\x7d\x5c\xb0\xdb\x34\xaf\x4a\x3d\xfc\xce\xb7\xff\x39\x55\xa8\x69\xc8\xbe\x60\xaf\x41\xa4\x15\x1c\xc0\xae\x69\x48\x02\x17\xce\x23\x2a\xff\xf4\xc4\x5b\x84\x85\xcf\x23\x8a\xe4\xdf\xba\x66\xe1\xc7\xf0\xf7\x93\xa8\xae\xdd\x3d\xa5\x8b\xca\x43\x24\x00\xe1\x33\xa5\x4f\x78\x1e\x51\x4f\x6e\x8d\xf0\x79\x04\xfa\x46\xd2\x5a\x8b\x7c\x8c\x1b\x6d\x32\xf5\x68\x5f\x3a\x38\x86\x78\x5c\x6c\x55\x03\xf3\xc8\xd6\xf4\x1c\x2f\x75\xef\xcc\x8e\x46\x2c\x9c\x45\xb2\xe3\x1f\x47\x74\x8c\xe4\xcf\x52\x76\x59\x5e\x7e\x1a\xd5\xf5\x1c\x07\xcf\x9e\x22\x8f\xdd\x32\xae\x2a\x7b\x0e\xfe\x54\x49\x62\xee\xb0\xfc\xf6\x13\xf5\xed\xff\x13\x8d\x59\xf8\xff\x1e\x15\x08\xe4\x8f\xef\xf7\x5b\x6c\x8c\x7d\xd8\xd0\xd6\x19\xc9\xe6\x7d\x5f\xce\x8e\x81\xb5\x2f\xa7\x30\x07\x8a\x3c\x41\x1d\x4b\xb9\x13\x03\x18\xd0\x52\x96\xa4\xdd\x29\x0f\xb8\xef\xff\xac\x8a\x73\x49\xde\x04\xdd\x22\x2e\x09\x8d\xba\xe1\xc6\x5f\x10\x79\xd8\x23\x46\xb5\x39\x11\x78\x62\xae\x31\x2c\xcc\x4c\xd6\x3b\x6b\xe7\x50\x1e\xda\x65\x63\xdc\x79\xe2\xae\xd6\x73\x8c\x1b\x09\xd0\x0a\x84\xde\xbd\xf8\x72\xc0\x11\xa6\x2f\x17\x1d\x54\x00\x6a\x71\xd6\xf2\xc8\xcf\x65\x34\x1b\xf4\x90\x6c\xf5\x89\x12\x0d\x0e\xeb\x16\xb5\x9c\x58\xd9\xfb\x1d\xf7\x6b\x17\x32\x60\x0f\x5c\x5b\x2b\xd1\xb1\xf2\x42\xef\xad\x59\x22\x1b\x7b\xca\x7a\xad\x7e\x82\x41\xf8\xb8\x43\x8c\x0c\x7a\x6e\xc2\x1a\x0c\xe0\xb5\xb5\x6b\xba\x61\x6f\xea\xfa\xcf\x85\xc1\x7d\x41\xb0\x56\x4a\x78\x18\xf6\x5a\x83\x1b\xd2\xdd\xbb\x20\xbd\x7d\x44\x17\xab\x59\x02\xc9\x6f\xe1\x45\xcf\xec\x5e\x1e\xeb\xe4\xd9\x27\x90\x07\x1f\x24\xc6\x12\xaf\x7b\xea\xd1\x52\xd2\x91\x34\x30\x25\x96\x62\x04\xb7\xef\xf5\x6d\xea\xfb\xe0\xd7\x67\x21\x2d\xc5\x81\xf7\xb4\x7d\x39\x99\x5f\x74\xdf\x3d\x69\xdf\x69\x63\x65\x34\x49\x0d\x34\xaa\xa6\xfe\xa3\x8b\x4c\xe6\x17\x48\x22\x8c\xd6\xe4\xe1\x0b\x89\x13\xc1\x1e\x03\x77\x2a\xad\xd5\x17\x00\xf4\x80\xf1\x85\x85\x55\x53\xf7\x78\x0e\xb5\x8f\xbd\x89\x07\xd0\xdb\xc3\x36\x5b\x22\xd9\x95\x1b\x72\xab\xa6\xeb\x81\x02\x72\x19\x51\xba\x75\xa0\x9e\xec\xa8\x97\xc5\xa5\x70\x9f\x4f\x3e\xc6\xe4\x9e\x7a\xda\x6a\x13\xc0\xd9\xcc\xae\x24\x78\x37\x6a\x7e\x6e\x07\x5c\x82\x47\x23\xf7\xb4\xd0\x9c\x76\x10\x30\x96\x59\xf4\x61\x44\xe9\x6e\xe9\x39\x14\xcf\x1b\x20\x02\xeb\xee\x29\x64\x43\xef\x4f\x6f\x16\xb2\xa7\x23\xee\xfb\xa3\x7b\x92\xd0\xd1\x5c\x92\xee\x35\x50\xe8\x07\xc3\x4e\x64\xf8\x10\xdb\x83\x45\x4c\xe3\x30\x03\x11\xfd\xfd\x32\x3e\xbd\xfd\x36\x81\x1c\x79\xdc\xe7\x87\x47\xf3\x45\x45\x33\xea\xe5\x3c\x03\x97\xd0\xad\xef\x8f\x2a\xdf\xef\x0c\xa7\xb1\xdb\x3f\xdd\xa0\x8a\x86\xbb\xe5\xda\xa1\xf8\xc1\x7a\x2a\xa7\x1f\xae\x23\xb2\xf3\xfd\x3d\x3e\x24\x14\x95\x14\x15\x14\xa5\x14\xe5\x14\xc5\x74\x8d\xc3\xab\xa8\xae\x51\x1c\x5e\x45\xf4\xd0\x60\x1c\xc6\x9a\x0d\x7b\xf3\x52\x3e\xcf\xdd\x7b\x55\x60\x1b\xd5\x75\x18\x61\x89\x07\x29\xfd\xe0\xfb\x45\x38\x8f\x24\x7f\x19\x3e\x8b\x48\x4c\x4b\xdf\x5f\x3b\x96\x7d\x61\x19\xd9\xe9\x18\x8f\x4b\xdf\x8f\x7d\x5f\x4e\x4b\x5d\xa3\x84\x96\x74\x86\xeb\xba\x9a\xee\xf3\x3d\x02\x7b\xb5\xee\x4c\xf8\xfe\x78\x9c\xf8\x7e\xac\x64\xf8\x69\xb8\x8d\x68\xf8\x81\x94\x24\x89\x16\xca\xb1\xc7\x72\x2e\x7b\xdf\x87\xea\xdc\x91\xb1\xff\x4b\x23\x23\x60\x0d\x91\xe0\xbf\x3e\x8a\xff\x72\xbd\xf5\x30\x61\x10\xaa\xf7\xf1\xff\xd0\x73\x39\x35\x49\x84\x89\x9a\xad\x8e\x1f\x13\x4a\x26\xf4\x56\x36\x7d\x53\xd7\xc9\xdf\x6f\x28\x9d\xf9\xfe\xec\x82\x26\xe7\x37\x4d\x33\x40\x74\x49\x6e\xc8\x6e\x4c\xaf\xa7\x7b\x60\xd4\xca\x90\x45\x75\x7d\x3d\x2d\x99\x50\xbc\x50\x19\xf6\x46\xe6\xb2\x10\x5e\xc5\xb5\x8d\x02\x4b\xce\x54\x05\x8a\xcb\xb7\x1e\x79\xe1\x55\xb4\x8c\x51\x8e\x83\xf9\x45\x6c\xec\x3a\x91\xa0\x21\x23\x8c\x78\x1e\xc9\x23\xe2\xb6\xd5\x73\xec\x40\x7d\x53\xba\xe5\x23\x86\x1c\xec\x51\xf3\x8d\xef\x11\x23\x45\x98\x46\xd8\x1a\x6f\xc0\x5d\x83\x87\xe8\xa9\xac\x4c\x12\xf7\x06\x07\xb1\xe4\x0b\xd5\xcc\x04\x07\x9e\x8b\x20\x3b\x56\xb5\x68\x2d\x55\x18\x91\x92\x6e\x10\xeb\x5b\xa2\xd9\xc9\x28\xe5\x64\xf4\x46\xd0\xb1\x35\xa5\xa5\x39\xf6\x17\x24\x84\x25\x66\xdd\xd1\xc4\x93\x09\x46\x29\xcd\xc3\x38\x52\x2c\x4a\xac\x86\x13\x47\x34\xc5\xdd\xc1\x74\xfc\xc8\x0a\xe0\x65\x48\x89\x0a\x2d\x55\x20\x29\x26\xf0\x10\x6e\x47\xa9\x82\xe9\xa6\xc1\x64\x1b\x97\x9d\x31\x3e\x66\x57\x64\x0e\xec\xcc\x9e\xd3\x1b\x4c\xcc\x31\xfd\x44\x2d\x82\x8a\x3e\x43\x7c\x5c\xb1\x24\x71\x9d\x73\x4e\x5d\xcb\x03\x4c\x4b\xdd\x04\xf4\x35\x8b\xf9\x4d\xa7\x99\x76\xc4\xff\xd2\xec\x1f\x70\x05\xa7\x20\x16\xbe\x3f\xf3\xc6\x1c\x13\x4e\xf9\xa3\x9c\x19\x39\xd6\xaf\x25\x39\x48\x25\xa9\x3c\x9e\x43\x4d\x7d\xc6\xe4\x7e\x97\x05\xf2\x85\xec\x40\xff\x9d\x7a\x8e\x8d\x33\x76\xdf\x27\x0b\x3b\xb1\x01\xec\xa0\x39\x50\xe9\x46\x81\x02\x9c\xfa\x1c\x41\x55\xdf\xb4\x0e\xb7\x62\xd0\x06\x13\x11\x17\x7d\x1f\x7f\xc5\xfe\xf0\x69\x96\xaf\x63\x25\x94\x6d\xaf\xe5\x3e\xdc\x76\x14\xeb\xc6\x22\x1f\xda\x48\x93\x86\x14\x79\x3e\x18\x33\x80\x49\x9c\xd7\x10\xf0\x7e\x3a\xf5\xfe\x72\x1a\xaf\xe5\x59\xaf\xb5\xf9\x19\x5d\xca\x26\x5f\x83\xcb\x54\xdd\x5e\x23\xc9\x5c\x8e\x46\x48\x19\xbd\xc9\x59\xdc\x16\x6c\x53\xd7\xff\x61\x53\x11\x5f\x83\x55\x20\xb8\x84\x83\x0e\x22\xb8\x61\x68\x34\xc7\xc4\xe8\x24\xe0\x7e\x86\x89\x56\x70\x0d\x32\xe3\x8f\xda\xe1\x39\x66\x78\xb2\x17\x6c\x6a\xbc\xbd\x6a\x4f\x29\x98\x9c\x57\x46\x05\xd9\x10\x73\x35\xcc\xa8\xbb\xd6\x77\x1d\x53\x3a\xf3\x19\x0c\x8a\x68\x03\xfe\xb6\x56\xb6\xdb\x8b\x87\x4e\x95\x7f\xe9\xe4\x9f\x4a\x7c\x64\x40\xe2\xe2\xd3\x21\x4f\x5e\xd5\x87\x81\xde\x8e\x2c\x4d\x98\x42\xeb\xa0\x98\xde\xb2\x38\x61\xc5\xd0\xd8\xfe\xa1\xcf\x67\x76\x4e\x71\x43\x60\x02\x87\x0a\xff\x30\x50\x58\xd9\x39\xfe\x1f\x2e\x93\x63\x2d\x69\x80\xc6\x35\xa0\x6c\x08\x38\xef\x1c\x6f\xe6\xbf\x6e\xf0\xe9\xc9\x1a\xda\xfa\x7d\x1f\xa9\xe3\x02\x12\x47\x76\xd8\xc0\xfa\x82\xe7\xb6\xf9\xa6\xbf\xcd\x4d\x58\x88\x5b\x07\x89\x99\x49\x0a\x67\x11\xe0\xb8\xde\x6b\x47\xe8\x19\x8a\xc9\x5c\x96\x61\xbf\xf7\x4b\xb4\xb8\x3f\xe4\x17\xb3\x25\x1f\x8b\x80\x43\xc9\x5b\xc6\x8f\x6b\x73\xdc\x20\x17\xfc\x42\x2c\xf8\x98\x3e\xc3\xac\x6f\x2b\xc1\x1a\x0c\xa1\x22\x1e\xf9\x7c\xfe\x27\x9f\x67\x47\x43\xe9\xba\x15\x9b\xbe\x8a\x0b\xbe\x14\x01\x5f\xcc\x2e\xe8\x64\x52\x2c\x4c\x65\x45\xa7\xb2\x9b\xbf\x58\x19\x5f\x8c\xc7\xc5\x85\x18\xae\xa5\x69\xb0\x85\x72\x2e\xb6\xd4\x81\xf9\xdf\xc9\xa1\x88\x93\x34\x0f\x46\x33\x85\x43\xae\xf3\x7b\x79\xbd\x49\x21\xfa\x0e\xd9\xc7\x65\x79\x97\x17\x89\xbc\x4e\x77\xf1\x0d\x84\xe4\xc1\x2e\x23\x45\x13\x30\x50\x31\x46\x9d\x87\xb2\xba\xde\xa5\x42\x96\x2f\x58\xc9\xc4\x71\xf9\xad\x2a\x6f\x6c\x49\x77\x0c\xe1\x43\x6b\x5a\x7a\xcf\xcc\xbe\x57\xfb\x62\x46\x3a\xbe\x2e\x9e\xb7\x10\x17\x7c\x21\xc6\x63\x5c\x8c\x21\x9e\x83\x12\xfe\xb6\xb6\x2e\xb6\xa6\x6b\x86\x4a\x62\xf9\xa7\x0a\x4c\x80\x0b\x92\x69\xe4\x41\xd6\x34\xab\xeb\x8a\x6c\x60\x43\x39\x42\x36\x4a\xe9\x9a\xec\xa9\xa3\xf4\xd0\xe8\x67\xd9\x5f\x05\xed\x75\x43\x59\x58\x45\x86\xdf\x67\x8e\xd6\x70\x63\xc4\x8e\xa5\xfe\xa2\xa5\x56\x8f\x1d\xf8\x24\xef\xbb\x8f\x94\xe9\xf7\x51\x1b\x03\x8d\xf8\xbe\xa9\xdf\x6a\x07\x5d\xe1\xe6\x63\xfd\x03\x7d\x12\xca\x29\x53\x2c\x3a\xb3\x2c\x3a\xeb\xb1\xe8\xac\xcb\xa2\x93\xcc\xf7\xb3\x47\x10\x08\x56\x8d\xd6\x35\x5b\x18\xb7\x18\x54\xd0\x34\x5c\xab\xa3\x95\x7b\x22\xa1\x8e\x5b\x50\x1c\x3e\x93\x2c\xeb\xb3\x48\x79\xc4\x84\xeb\x88\xc6\x58\x3e\x3b\x1e\x60\x4b\xf7\xed\x7a\xdf\x31\xd4\xca\x40\xe6\x17\xe9\x90\x87\x95\x9d\x6a\x9a\x1e\x1b\xfb\x83\x62\x2e\x2c\xa2\x5e\x63\x0e\x1d\x09\x52\x89\xaf\x6c\x8b\xef\x18\xb2\x61\x52\x5a\x98\x85\x25\x94\x6c\xf2\x8c\x54\x2d\xe8\x66\x54\xf9\xe4\x0b\x1b\xb3\x04\xe6\xbd\x04\x1e\x57\x1e\xc3\x39\xca\xa1\x1e\x79\x54\x52\x7b\x38\x87\x79\x56\xfe\xdd\xa8\xc4\x6e\x08\x10\xdb\x85\x4b\x86\x12\xb2\x25\x37\xe4\x96\x3c\x90\x96\xf4\xdc\xfa\xfe\xe8\x36\xbc\x8a\x7c\x1f\xdd\xd2\x4b\x86\x6e\x31\x26\x0f\xbe\x3f\x7a\x50\xcf\x1e\xe4\xb3\x07\x88\xcf\xf0\x18\xab\x4e\x62\x65\xa3\x55\xc9\x3f\x19\xb5\xf1\x16\xd6\x54\x42\xcf\x49\x9c\x34\x83\x70\x65\x36\x18\x43\x0a\xc1\x18\x40\xdb\x27\xc2\x22\x72\x45\x50\x0d\xda\xd6\xb5\xf7\xd4\x23\xad\xfd\x1a\x58\x5f\x72\x38\x19\x6c\xe8\x28\xa9\xeb\x11\xf3\xfd\xed\x72\x1d\xbc\x63\x68\x2d\x8f\xcb\xd0\x43\xb2\xa7\x37\xcb\x07\x09\xb2\xcb\x24\xc8\xea\xfa\x16\xa2\xad\x88\x60\x23\x21\xe7\xc6\xf7\x6f\xd0\x86\xec\x55\xc9\x5b\x7c\x48\xe9\x3b\x86\xf6\xa4\xc2\xe4\x16\xa5\x24\x8c\xd4\x8b\xbc\x0f\x03\xb9\x3c\x78\xc4\x34\x0d\x73\x58\x94\x7d\x58\x85\x79\x24\xcf\x1e\x1b\x7d\x15\x63\xdc\x48\x66\x43\x89\x49\xea\x3a\x31\xf2\x12\x38\x17\xe5\x74\x3f\x58\xdf\x5e\xd5\x97\xaa\x75\xdc\x84\xb9\xac\x68\xf1\x00\x14\x95\xec\xe1\x58\x45\x0a\xdc\xfc\xc9\xe7\xf2\xb4\x90\xd2\x87\xe5\xf7\xe0\x8a\x16\x94\xba\x93\x2c\x4c\xd5\xe9\x28\x55\xdd\x53\x3b\x7f\x0f\x03\x96\xa4\x78\xb9\x37\x8a\x9e\x8c\x98\xfa\x71\xb0\xc7\xe4\x61\xa9\x7b\x20\xc8\x9e\x14\x38\xb0\xfe\x8e\x64\xdf\x31\xf5\x7f\xd5\xc1\xc7\x29\xd1\x66\xf0\xd6\x9b\x80\x5e\x4f\x8d\x56\x23\x04\x41\xb2\xe4\x07\x22\x12\xd3\x5c\x9e\xb0\xed\x2b\xef\xcc\x93\x5b\x22\x5f\xce\x03\xb9\x2d\x06\x1d\x3a\x81\x6d\x4e\x1b\x12\x13\xc9\xd1\x66\xc3\x85\x26\xf3\x8b\xef\x51\x0a\x51\xb0\x54\xb9\x35\x0d\x87\x77\xf8\x28\x97\x3b\xab\xae\xc5\x88\xd2\x3b\xb9\xad\x50\x4a\x05\x6e\x01\xad\xd2\xc5\x83\xcc\x6c\x78\x03\x97\xa9\x3a\x31\x16\x4d\xb4\x28\x2f\x0a\x13\x60\x48\x74\x87\x5a\xea\xa1\xe2\x35\x0d\xaf\x19\xba\x63\x68\x8d\x89\xc0\x51\x8b\xf1\xe4\x07\x4a\x50\xee\x14\x37\x8e\x62\xa0\x65\x93\x4f\xb5\x22\x1b\xe3\xf0\x2a\x32\x61\x61\xc6\xe3\xd2\x8d\xcf\xd0\x69\x97\x9b\x76\x3b\xc1\x5d\x2e\x19\x9a\x5f\x94\xbe\xaf\xba\x01\x97\x92\x92\x5a\x01\x66\x39\x99\x63\x1d\x62\x10\x1d\x94\xba\xd4\x3b\x53\x4a\x8c\x72\xf2\x4c\x55\xb9\xf4\x9e\x7a\x81\xe7\x35\x4e\xd0\x20\xe3\x67\x26\x48\x79\xc1\x7d\xff\x55\x5b\x65\x29\x27\x8c\xf0\x8b\x42\x3d\xa5\xe6\xb9\x7d\x0a\x84\x1c\x37\x6b\xed\x65\x66\x35\x8c\xd0\x43\x73\xb3\x63\x4e\xa4\x37\x33\x5b\x65\xcb\xa0\x74\x04\x27\x20\xa9\xdf\x31\xb2\xa5\xa5\xa4\x37\x1f\x18\x4f\xff\x18\xf4\xb0\x26\x5d\xd1\xe9\xbd\x11\xfb\xa7\x1b\x94\x59\xcb\xd4\xe5\x2c\xc8\xac\x36\x75\x11\x53\x66\x70\xdd\xf5\xd4\xea\xc8\x8c\x44\x42\xad\x0b\xc4\x56\x91\xa8\x1a\x15\xf4\x57\xe5\x99\x1a\x4b\xc6\x17\x41\x98\x26\x1a\xeb\xda\x24\x7d\x33\x3b\xad\xae\x63\x6b\x3f\x25\x91\x84\x9c\x1c\x3a\x9a\x13\x54\xd0\x3f\x6c\x0d\xe0\xe7\x61\xfd\xec\x88\x46\x14\x7a\x95\x38\x81\x20\x89\x50\xa9\xb3\x2a\x67\x60\x5e\xd8\x36\x6a\x95\x3a\xca\x04\x5a\x76\x1e\xcb\x7e\x7e\x19\xe6\x91\xd3\x55\x89\xc7\xd4\x00\xe4\x15\x2a\xa0\xfb\x7f\xda\x78\x4e\x34\x90\x06\xc5\x89\x46\xc1\xa8\x85\xeb\x08\x45\x76\x86\x8d\x30\x2c\x88\x97\xad\x7a\x0c\x07\xf7\x88\x91\x12\xdb\xb9\x6f\xc8\x86\x96\xca\x48\x28\xcd\x86\xd7\x53\x12\xb7\x1d\xb9\x97\xeb\xaa\x30\x6d\x28\x31\xcc\x0b\x67\x5d\x47\x31\x3e\x28\x75\xce\x16\x41\xd8\xa1\x96\x02\x69\x93\x17\x85\x4d\x5f\x31\x10\x8c\xc1\x6e\x5b\xa6\xc6\x7d\x37\xc8\xcd\xd5\x02\xc5\xf4\x05\x62\x04\xdd\xd2\x9c\xec\xe8\xec\x02\x3d\xd0\xd4\x48\x7e\xc8\x3d\x9d\x5d\xdc\xb6\xcc\x68\x9f\x70\x4a\x2e\x40\x73\x00\x12\xf4\xe8\x8c\x64\xd4\x9b\x81\x54\xde\xf7\xc3\x88\x6c\x64\xbf\xf7\xf4\x8e\x24\x92\x80\xde\xfb\x7e\x6b\xad\x8e\x24\x15\x4c\x31\xd9\xd2\x0f\x63\xaa\xce\x5a\xfb\xe5\x3c\xe8\xc4\xf2\xaa\xeb\xe9\x9c\xdc\xd0\xc4\x0c\x4c\xc2\x64\xea\xfb\xe8\x8e\x6a\x5b\xa7\xba\x4e\xf1\x22\x1b\x81\xe6\x41\x47\x00\xca\x69\x12\x66\x11\x5e\x64\xe3\x31\x10\xab\x7b\xdf\xcf\xf1\x21\xa6\x33\x22\xea\x3a\xef\x1b\x47\x5d\xd6\x35\x7a\x27\xf9\x0e\x4e\x47\xaf\x8c\xb9\x40\x49\x6f\xc3\x58\x9b\xe7\x97\x28\x97\x1f\x5e\xca\xcd\x7f\x28\x0c\x9b\xa2\x05\xd8\xb2\x2f\x1f\xe8\x16\x37\x3b\xdf\x47\x28\xa7\xa3\x52\x36\xe6\xfb\xd5\x64\x42\x98\xef\xaf\x4d\x71\x20\xa2\xd5\x98\x66\x64\xe7\xfb\xb2\xbb\x15\xf4\xc8\x36\xf7\xa0\x9a\x2b\xd1\x9a\x6c\x14\xdf\x6c\x89\xee\xec\xa2\xd2\xa2\xeb\x6c\x32\xc1\x6b\x10\x5a\x6f\x94\xe8\x5a\xfe\xd0\xdf\x95\x79\x4a\x81\xf1\x62\x23\x69\xe0\x06\x37\x86\xb0\x15\x64\x83\x49\xea\xfb\x92\x9f\x98\x5d\x6c\xac\x71\xe2\xfc\xa2\x1a\x3f\xd8\xbb\x8e\xdd\x06\x2a\x2c\xa2\xd2\x63\x23\x77\x74\x8f\xc9\xba\x21\xbb\xa5\x64\x1a\x71\x50\x60\x30\x87\xd6\xc6\x4a\xac\xb1\x1c\x1a\xb9\x69\x0d\x07\x8e\x00\xe5\xc8\xf1\x9e\x0e\x07\x5e\x65\x64\x4d\x47\x85\xef\x6f\x11\xa3\x99\x6d\xa6\xae\x95\x43\x80\xf1\xc0\x97\x7c\xfd\xda\x6c\x45\x39\x4b\xcf\x2e\x50\x4e\xd7\x92\xcd\x5e\x3b\xaa\x5d\xdc\x5a\xb9\x7a\x6f\x5e\x4a\xdc\x8f\x62\x9a\x87\xb3\x08\xeb\x33\xfe\x67\x3d\x37\xd5\x57\x12\x40\x2d\xe5\xc9\x41\x09\x0f\x94\x47\xf9\xdd\x0b\x8a\xac\xf7\x09\xb2\xf6\xac\x2e\x9e\xd2\xa2\x4f\x81\x8d\x22\xc2\xf1\xca\xcf\x40\x61\xd7\x31\x72\x24\x2d\x15\xc9\x0d\x42\x52\xa7\x3b\x33\xb8\x26\xa5\x5f\x4e\xdd\x08\x25\x5a\xc2\x82\x97\xb3\x20\x3f\x96\x89\xcb\x7e\xca\x21\xa6\x11\x71\x06\x52\xd2\xb8\x43\x41\x25\xa9\xae\xa8\x1a\x8a\xe6\xc7\x0b\x5a\x3d\x3a\x22\xe3\xbe\x9e\x1b\x86\x47\xb9\xb1\x8b\xae\x1b\xbb\xd0\x6e\xf1\xb9\x61\xc1\x52\x32\xc7\x64\x84\x98\x95\xdf\x03\x95\xcc\xdb\x60\x05\xad\x1b\x79\x81\x09\x37\x7a\x21\x0d\x54\x28\xab\xeb\x0d\x62\x64\x8d\x31\x2a\xc0\xbe\x8a\x70\x32\x12\x75\x6d\x7a\x73\xaa\x17\x84\x37\xc4\x35\x23\xa2\x57\xc6\xef\xd9\xc3\xc6\x88\x48\x9b\xe5\x82\xab\xd5\x15\x39\x36\x45\xa2\xa3\x51\x46\xde\x21\x4c\xba\xb6\x9a\x27\x9c\xcc\xe6\x8f\x18\xbe\x3e\xe2\x04\x3e\x60\x31\x6f\x8f\xe0\x43\x86\xf3\x7f\x53\x56\xf2\x1e\xf1\xfe\xa6\x64\x55\xad\x98\xb0\x27\xa4\x92\xe5\x25\xc5\xac\xeb\x8d\x16\x59\xd5\x20\x64\xdd\xb2\xf4\x66\x2b\xea\xbb\x34\x11\x5b\x8f\xf4\xf9\x48\x45\xd4\x86\xfd\xd2\x04\xf1\x8c\xd2\xb7\x27\xef\x5a\xce\x83\x67\xb8\xe7\x8b\x78\x64\x8b\x3d\x38\x2e\x10\xcc\x9d\x83\x57\x89\x33\x92\xae\x11\x3e\xec\x07\xe5\x6d\xe1\xfd\xc9\xa0\x55\x51\x3b\x6a\xfd\xe5\xe0\x20\x7d\xff\xcf\xa5\x82\xed\x44\x18\x8f\x54\xb0\xa3\x3a\xb5\x64\x3a\xae\x6e\xaf\x4f\xad\x2d\xbd\xee\xd6\xdb\xa3\x0e\x01\xf7\xbe\x70\xe7\x5e\x09\x8a\x43\x11\x2d\x7b\x53\xfd\x3f\x59\x08\x62\x52\xb2\x06\x5d\xe2\xc5\x15\x6c\x79\x9a\x40\x3c\xcd\x7d\x41\x93\xd6\xce\x4b\x3f\x0a\xbd\xc0\x53\xf1\x39\xf7\x85\x65\x49\xaf\x5c\xcb\x3e\x73\x43\x13\xe7\x29\xb9\x52\x21\xa7\x13\x63\x3f\x47\xae\x94\x5b\xf3\xcb\x7c\x4d\x13\x75\x49\xae\x5a\x5b\xcf\xc4\x5e\xca\x76\xc1\x78\xd1\xda\xbf\x26\xfa\x01\x98\x68\x6e\xe9\xf0\x51\x07\x54\x73\xd6\xba\x92\x2f\x5a\xed\x49\x28\x24\x42\xfb\x6c\xd4\xd1\x9a\x1c\xc9\x82\x00\x0a\x52\xdf\xbf\x02\x0f\xaa\x52\x32\xf1\xfa\x74\xa1\x63\x1a\x5a\x3a\x58\x34\xe4\xdd\xc9\xf8\x72\x61\x34\x20\x9d\xef\x07\x43\x60\x2a\xe8\x2a\x37\x35\x3b\xc6\x76\x1f\xcc\x54\x03\xe6\xed\x20\xfa\x56\x5e\xf8\xa2\x1b\x3a\xef\x2f\x5a\x05\xf5\x82\x00\xc9\xfe\x7e\x4b\xcf\xdf\x5f\xa0\x30\x9e\xfc\x11\x85\xef\x57\xe7\xab\xd9\xe7\x01\x04\x9a\x13\xab\x62\xc5\x57\x9b\xe8\x29\x0e\xbb\xf7\xab\xf3\xe5\xe7\x68\x19\x5c\xac\xce\x57\xf3\xcf\x6b\xfc\xe4\x3c\x6d\x7b\xf5\x12\xe9\x88\x3a\xe6\x60\x83\x38\x5e\xea\x70\xc2\x6c\x30\x96\xf0\x68\xd4\x89\xbf\x3c\xa2\xb4\x68\x70\xe0\x08\x42\x06\xbe\xee\x9c\x94\xb9\xfe\xe4\x28\x00\x0f\x7f\xec\xd3\xc9\xfc\x22\x6d\xe3\x73\xea\x2a\xae\xf4\x91\x41\x3e\x23\x05\x04\xe1\x86\xfb\x13\xe0\x26\xc2\x59\x1b\x27\xd4\xf7\x11\xa3\x5e\xc0\x73\x81\xc0\x68\x0a\x7b\x98\xa8\x80\x17\x96\xc3\xea\xf8\xc3\x2f\xd5\xb6\xeb\x1b\x70\xa3\x82\x30\xbc\x0c\x8b\x28\x08\xa3\xa0\x5b\x04\x31\x62\x02\x33\x0f\xcd\x45\x17\xc0\x20\x3c\xb3\x13\xd7\x18\x1d\xc0\xf8\x72\xd8\x9b\xdf\x8d\xd8\x9c\xc2\xdd\xc2\x31\x51\x6d\x8d\xb3\xec\xa1\xb1\x17\x2e\x5a\x6e\x17\x3d\x73\x8e\x66\x03\x82\xca\xd2\xd9\x42\x5c\x14\x20\xa8\x4e\x37\xa8\xdd\xec\x28\x0d\x45\x44\x20\xca\x78\x2b\xcd\xc4\x4a\x7e\xce\x69\xaf\x81\x30\xc2\xc4\xad\x49\xcd\x0b\x62\x04\x2a\x69\x05\x69\xf3\x8b\x62\xe9\xa2\x25\xc4\x71\xc0\xad\x95\xde\x90\xd1\x5a\xb7\x9d\x97\x3a\xb4\x38\xb0\x93\xa3\x39\x86\x98\xbf\x83\x3a\xad\x47\x3f\x84\x58\x63\xe9\x90\x46\x74\x34\xd2\x25\x8f\xcd\xe4\x7c\xff\x83\xe5\xe2\xe4\x84\x06\xb6\x17\xad\xbe\x1d\x90\xdf\x6f\xe4\x77\x15\xc1\x6d\x55\x3e\x45\x17\xe1\xea\x6e\xf5\x53\x34\xfe\x1c\x87\xef\x3f\x8f\x9e\xd6\x7f\x73\x82\xb8\x2d\x90\x8d\x6b\x3f\x0c\xc0\x24\x05\xf2\xd2\x59\x56\xcb\x50\xff\x36\xd0\x47\xcd\xf1\x16\xd4\xbb\x50\x32\x93\x59\xe4\xfb\xde\xe7\xea\xba\x8d\x6b\x16\xf9\xfe\xf3\x0b\x2b\x1b\x5b\x86\x4a\xc8\x03\xd6\x08\x51\xf0\xbb\x3a\x86\x43\x90\xe3\x51\x11\xca\xc2\xc6\xdc\x59\x32\x71\x62\xaa\xe2\xdc\x2f\x21\x48\x05\xd6\x0b\x8d\x83\xa3\x18\xdf\xc2\xbe\x83\x58\x31\x26\x22\x96\xa0\xe2\x2c\xe5\xa5\x88\xf9\x1a\x82\xb5\x2e\xe5\x26\x0d\x24\xe5\x69\x83\xd1\x93\x2b\xc9\x1a\x96\x4c\xb2\x1b\xf0\x25\xd1\xb1\x8b\xf5\xce\x3c\xf6\xde\x09\x5e\xc1\xaa\x92\x6f\xd5\x12\x69\xe3\xa8\x7e\x48\x6b\x81\xdb\xcc\x0a\x02\xef\xa0\xad\xb0\x88\xf0\x52\x5f\x20\x01\xce\x22\x30\x14\xb0\x43\x2c\x40\x12\xdc\x09\x8b\x6e\x98\xdc\x94\xbe\xea\xbb\xa0\x17\xe1\xb3\x48\x59\xb5\xca\xea\x66\x11\x4d\x89\xb3\x71\xe9\x1c\x13\xa7\x02\x27\x37\xc5\xd2\x7e\xc0\xba\x1f\xa8\xed\x17\xec\x24\xc8\xb5\x54\x73\x5a\xb0\x38\x79\x58\xea\x5f\x80\x44\x74\x25\x71\xa3\x8d\x9a\x8c\x54\x3d\xb8\xc1\x8e\xd4\x4a\xc2\x1a\xf9\x8d\x5e\xa1\x57\x0a\x4c\xbf\x56\x40\xaa\x78\xf0\xb2\xde\x17\xec\x16\x2d\x83\x1f\xb9\x48\xb3\x1a\x5c\x99\xcf\xc9\x57\xf4\x00\x36\x65\x05\xe3\xa0\x77\x53\xe6\x1f\x25\x64\xbe\x60\xf7\xa0\x3b\x93\x9f\x75\xb3\x5f\x7c\xa7\x88\x47\x9f\xb4\xcf\x47\x43\x06\x11\x67\xac\xe9\xe0\xc0\x6d\x5c\x0e\x25\x2a\x30\x03\x72\xc5\x25\xee\x46\x1f\xc6\x6d\x10\x36\x97\xce\x16\xec\x82\x2f\xd8\x11\x7e\x53\xb9\x0c\x42\x16\xb9\xf8\xad\x21\xeb\x2c\x2f\x99\x1b\xf8\xbf\x1b\x18\x5b\xa3\xdf\x56\xac\x0c\x12\x9e\x63\x4c\xac\x78\x14\xd8\xbe\x16\x6d\x00\xf0\x59\x45\x43\x8b\x48\xc3\x22\x5a\x70\xdf\x97\x74\x52\x2c\x7a\x2e\x4f\x72\xb7\xb7\x36\x03\xf3\xb9\xef\xa3\x78\x39\x99\x5f\xc4\xca\x10\x45\x22\xd0\xbe\x5f\xfd\x09\xba\x05\x61\xae\xf1\x21\xb7\xaa\xe0\xae\x10\xac\x8b\x2f\xe7\x17\xe6\x98\xda\xc5\xd7\x39\x0e\x72\x30\x25\x48\xd8\xfd\xa0\x4d\xc5\x72\x20\xdc\xb6\xa6\xe3\x72\x42\x88\x86\x74\x6c\x43\x68\x03\x5a\x36\x38\x45\x22\xac\x40\x23\x13\xc0\x5d\xfa\xc2\x8d\x79\xa4\x17\xbc\x28\xe5\xa9\x5b\x82\xdf\x8b\x2c\x43\x06\x07\x07\x93\x79\x43\x62\x37\x85\x42\x27\x1a\x64\x3f\x8b\x82\x33\xb2\x4e\x32\x8c\x1b\x26\x10\x26\x00\x76\x18\x4b\x62\x11\x27\xc9\x17\xfd\x24\x1a\x6e\xa5\x71\x92\x20\x93\xa0\xa3\x97\xfe\x20\xe8\xdd\x1b\x60\x65\x18\xcc\xa6\x74\xe8\xe9\xc3\x80\xe5\x87\x31\xb8\x38\x76\x02\x35\x8e\x5d\x2e\x4e\xd4\x6e\x45\x7a\x3f\x0f\xf5\x74\x8b\x18\x71\x35\xc8\xd8\x96\x86\x5d\x7f\xca\x5e\xad\xff\x19\x84\x3c\xe7\x7d\xcb\x0d\x5d\x58\xee\xfe\x8e\xb5\x2c\x6e\x14\x8e\x38\x55\xb6\x6f\x1a\xac\xeb\x7e\x91\x65\x27\x87\x30\x50\xfd\x63\xc5\x4f\xb4\xf0\xe7\x63\x76\xdb\x81\x41\xcb\x9a\xfe\xc2\x54\xf5\x8d\x9d\xe5\xa7\xa5\xba\x19\x5c\x97\x77\xa8\x13\x58\xb0\xae\x0f\x0d\x76\x4e\xcb\xa0\x43\xb2\x78\x78\xf0\x7b\xf7\x70\x2d\x0b\x1b\x44\x7d\xe2\xb8\x3b\xa2\xca\x81\x8f\x71\x1b\x46\xca\xf7\x0b\x74\xf4\x50\xf9\xc4\x76\x1e\x05\x48\x9e\x6b\x3c\xc1\x76\xfb\x2c\x16\xcc\x03\xdd\x5e\x5b\x5d\x5d\x33\x6c\x49\x39\x44\xf3\x72\xc2\x8f\x82\x43\x86\xe9\x11\x08\xa1\x21\x42\x7b\x11\x0d\x46\x9f\x75\xb2\xc2\xa4\x6d\x3e\x1a\x0f\xe6\xdf\x03\xbf\x67\x6d\xdc\xfe\x89\x72\x24\x91\xc8\xc5\xf7\x8f\xd0\x8f\x00\xad\x85\x3d\x38\x80\xfe\x8c\xcc\x2f\x1c\x24\xee\xfb\xe8\x2b\xc8\xb0\xd4\xe3\x4c\xc9\xd7\x9a\x99\x80\x80\x2e\x05\xbb\x65\x05\x88\x17\x48\x0f\x8d\x70\x6c\x38\xbf\xef\xe9\x79\xf8\xbe\x73\x16\x1b\x9f\xdf\xb4\x94\xf1\xad\x8b\x28\x5b\xcd\xe5\x37\xad\x17\x9f\xf3\xf4\x4d\x4f\x06\x0b\x81\x07\x99\xef\xef\x10\x78\xf0\x16\xf9\x2e\x2d\x19\x36\xb8\x15\x22\x8a\x71\x06\x4c\x57\x9c\x66\x92\x2c\xd8\xb2\x62\xcb\x78\x5b\x50\xa9\x12\x4d\xfe\x2e\xc5\x55\x90\x90\x19\xe9\x6b\x81\x9d\x88\x86\xfc\xa8\x14\x6e\x9a\xab\xe9\x65\x9c\x65\xd7\xf1\xfa\x83\xe3\xfc\x59\x98\x20\xf5\x7c\x51\xd0\xa3\x35\x28\x96\x88\xd1\x42\x25\x04\xd3\xf8\x4e\x3b\xd0\xa2\xef\x41\xe6\x7a\x14\x27\x5f\x44\x54\x92\x63\xd9\xd5\x36\x89\x48\x43\x0a\x35\xcf\x29\x11\x47\x4a\xff\xc9\x9c\xac\x69\x8f\x01\x88\x69\x5c\xd7\xc5\x34\xe7\x6b\x46\x72\x9a\xd2\xd1\x6c\x51\x19\xf6\x41\x7e\x81\x0f\x82\x56\x46\x82\xab\x85\x11\xe3\x71\x76\x61\x20\x03\x83\x11\x7a\x19\x66\x46\x1b\x2a\x79\x55\x22\xb4\xe5\xfd\xb4\x14\xf9\xfe\x3b\xfe\x3a\xce\x4a\x06\x41\xf1\x2d\x57\x20\xe8\x68\x8e\x9b\x62\xba\x63\xbb\xbc\x78\x00\x6d\xcf\x68\x8e\x75\x26\x15\xdf\x47\x25\x15\xcb\x30\x0a\x3c\x0f\x74\x4a\x87\x78\x30\xe5\x4f\x29\xa1\xda\xf7\x47\x69\xa7\xee\xc9\x9c\x54\x46\x53\xd9\xda\xc1\x9e\xc1\x0e\x37\x53\xdb\x9b\xcd\x1d\x12\x78\x59\x68\xd8\xf6\xfd\xcd\x74\x1b\x97\x10\xeb\xb4\x34\x15\xa9\xd4\x20\x56\xe8\x6e\x99\x19\x7a\x07\x81\x4f\x39\x12\xb8\xc1\x0d\x6a\x33\x28\x11\xdd\xb1\xb5\xd9\x0e\x0d\x51\x11\x2d\x07\xc6\xa1\x7b\x65\x3f\x26\x03\x9b\x5d\xcf\xfd\x64\x7e\x01\x7b\x55\x27\xe2\x40\x82\x80\xf6\x16\x97\xd6\x09\x94\xcc\x31\xe1\x17\x34\xf3\xfd\x6c\x32\x69\x4c\xdb\x7d\xae\xd1\x32\x23\x93\xf9\x45\x5b\x1b\x23\x25\x0e\x66\x76\x71\x8f\xcc\x38\x3b\x33\x2f\x41\xcb\x54\xaf\x65\x81\x03\x25\x63\x5a\x29\x13\x1a\x41\x3d\xaf\x5b\x7a\x60\x49\x47\x65\x43\xb2\xdc\xe5\x22\xfa\x15\x89\xba\x4e\xeb\x1a\xa9\xfa\x4c\xf3\xf2\x93\xc1\xea\x46\x31\x58\x2c\xb2\x9f\x52\xd1\x4f\xe4\x62\xaa\x05\xd8\x0b\x19\x91\xc7\x2e\x50\x6e\xa8\x6d\xbe\x34\x36\xc4\x38\x10\x51\x0b\x50\x24\xad\x6b\x67\x49\x65\xdd\x03\x7d\xdd\x4c\x4d\xa3\xfd\xc4\x5a\xce\x77\x83\xfd\xcd\x9b\xc6\x86\x1e\x73\xb3\x03\xbd\x64\x1b\x56\x14\x03\x56\xc1\x39\x0d\x43\x8f\xe7\x22\xdd\x3c\x78\x92\xb0\xe6\x37\x05\x2b\x4b\x8f\x38\x38\x08\x79\x6a\x97\x79\xf8\xc4\xd3\x67\x11\x09\xbd\x82\x95\x79\x76\xcb\x3c\xe2\x49\x34\xd9\xab\x40\xe2\x87\xb3\xe1\x5a\xba\xaf\x66\xc4\x54\x94\x78\xaa\x56\x88\x37\x4c\x3c\x89\x73\xff\xd7\x4a\xe7\x44\xd7\x23\x2b\x8d\x48\x4a\xbd\x3d\xe3\x09\x30\x0e\x31\x3d\x94\x22\x16\x43\x8b\x90\x36\x24\xce\xee\xe2\x87\x72\x30\x9d\x1c\xd0\x82\x76\x5d\x14\x4d\x38\x5a\x27\x0f\x10\xbd\x37\xe8\x74\x01\x54\x43\x5b\x7f\x48\xce\x27\xdd\x77\x7a\x01\x58\xb8\xcd\x60\xb5\xb0\x7b\xdd\x2c\x25\x72\x49\x83\x46\x01\xf9\xd0\xd6\xa7\x3b\x94\x86\x22\xfc\x38\x02\xdb\x23\x75\xb5\x28\x43\x89\x64\x23\xd4\x6b\x91\x41\x1a\xb2\xe1\xa4\x6e\x0b\xa0\x77\x0e\x65\xb4\x97\x70\x4c\x50\x90\x83\x8a\xa9\x82\x26\x4d\x2e\x8b\xa9\x5e\x4f\x3d\x45\xf2\x1e\x32\x4f\x06\x45\x28\x71\xfd\xd8\x93\x60\xee\x45\xaa\x31\x0e\x89\x83\xda\x26\x1b\xdc\x48\xa4\xae\x84\xf5\x6d\x6b\x0d\x91\x73\xd7\xce\x96\x43\xc5\x2b\x3a\x6b\xd9\x81\x0c\x69\xc5\xea\xb1\x53\x87\x0d\xff\x27\x9b\x2d\xda\x79\x26\x6c\x20\xfd\x19\x1c\x32\x51\x7a\x51\x29\x2d\x1e\x62\x34\x76\xd4\x73\x98\x52\x9a\xb7\x9d\x73\x72\x97\xca\x63\x83\x0e\x19\xf0\x6e\xab\xcc\xf6\xcf\x4a\x96\x6d\x26\x30\x27\x15\x28\x79\xf1\x42\x40\x6e\xa5\xbf\x9a\xf2\x51\xc5\xc4\xdd\x32\x4e\x80\xea\x94\x4b\x93\xed\x89\x64\xa8\x22\x39\x79\x4b\x4a\xac\x2f\xbf\x21\x25\xc6\x01\xaa\xc6\x63\xf2\x78\x21\xfb\x34\xd7\x8b\x27\xd7\x04\xcb\x6f\xe3\x11\xa5\x6f\x81\xbf\xd3\x1c\x4a\x41\x25\x8f\x42\x50\x59\xd7\xb9\x59\x5a\x28\xad\xa6\xa2\x69\x88\xa0\xe5\xb2\x03\xc9\xc0\x56\x21\x87\xe9\x69\x61\x78\xca\xee\xd7\x0c\x7c\x0b\xbe\xca\xf3\x0f\xf2\x60\x3d\xfc\x46\x42\xf3\xb4\x94\xbc\xe0\xbb\x22\x5e\x33\x4c\xaa\x0b\x9a\x8e\xe1\xa8\x3e\xa2\xf4\x9b\x81\x0e\xe6\x1a\xce\x00\x89\xea\xae\x2d\xd2\xa5\x40\x38\x40\x4e\x2b\x37\x4c\x00\x8b\xa9\x9a\x47\x6e\x23\xf4\x44\x31\x89\xbd\x2f\xa7\x25\x13\xef\xd2\x1d\xcb\x2b\x90\x79\xd9\xc8\xdc\x43\xdb\x93\xe1\x43\x1e\xce\xa2\xf0\x79\x04\x87\xd8\x0c\xcd\x08\x23\x3b\x54\xe0\x65\x11\xbc\x25\xac\x33\xe5\x24\x0f\xe7\x47\x25\x05\x5e\x8a\xe0\x2d\xbc\x7c\x76\xf4\x12\x92\xc8\x7d\x83\x71\x77\x7f\xe8\xcb\x47\x8e\x27\x4b\x4b\x1c\xc0\x8a\x30\x6e\x1a\x52\xd2\x43\xb3\xe8\xf2\x14\xc3\x08\x45\x84\xcf\x22\x52\x50\x11\x7e\x12\x2d\x62\x85\x48\x28\x84\x9b\x25\x05\x60\x8f\x24\x71\xf1\x4a\x4a\x8b\x86\xe4\xe1\xf3\x09\x8b\xc2\x67\x91\x89\xc7\x65\x9e\x3c\x77\x9f\xcc\xa0\x84\x24\xc7\xc4\x4c\x99\xbc\xc1\x44\x55\x2a\xe4\x03\x49\xfb\x30\x29\x01\x7b\x44\x74\x00\x37\x1f\xe3\x15\xc9\x62\x6a\xf1\x5e\x30\x4c\x50\xbb\x1f\x51\x6e\x09\x70\x83\x49\x6c\x27\xb6\xc4\x44\x79\x70\xcb\xbd\x54\xca\x8d\x53\x36\xe4\x6e\xcb\x8e\xbd\x38\xf8\x71\x42\x44\x41\x39\x29\xa8\x66\xbb\x24\x56\xd3\x69\x46\x9d\xbe\xe4\x0e\xcc\x21\x4c\x62\xfa\x67\x6e\x69\x92\x8b\x57\xe7\x37\x79\x35\xbf\xe8\x37\xba\x3c\x6a\x23\x60\x64\x32\xe1\xbd\xcd\x0b\x47\x45\xb9\x3f\x36\x88\x5f\x50\xb9\xad\xe4\xd9\x28\xd7\x44\x0e\xa2\xe4\xeb\xd2\x76\x5f\x91\x11\xc7\xc4\xd2\x51\xc0\x80\x40\x48\x11\xae\x6b\xa0\x37\x11\xd0\x9a\x48\x9d\x8d\xac\xc6\x38\x57\x54\xcf\x1c\x05\xc4\x64\x82\xdf\x28\x3d\x88\x6c\xc6\xd6\x6e\x85\x97\x0e\x5e\x35\x47\xc0\x9f\xe8\xf9\x7b\xf4\xea\x36\xce\xea\x37\x5c\xb0\x82\xc7\x59\xfd\x36\xe6\x37\xac\x7e\x2b\x67\x8e\xf1\x35\xab\x55\x7c\x96\x1a\x6c\xdb\x7f\x7c\xfb\x06\x03\x0e\x7e\x72\xbe\x38\x85\x5e\x7a\xa7\xe3\x4b\x90\xb2\xe7\x19\xf3\x7d\x7b\x39\xbd\x8b\x0b\xee\xfb\xcc\xf7\x7f\xb2\xbe\x3c\xf1\x4e\x62\xe3\x6e\x11\x93\xa9\xda\xb6\x74\x66\x5b\x02\x57\xd1\xe9\x8e\x95\x65\x7c\xc3\x08\x53\xa8\x06\xe2\xf4\x5c\x29\x41\xf3\x2b\x53\xb2\x13\x64\xa5\x83\x6b\x5c\xb4\xaa\xcf\xb3\xb8\x81\x69\x79\xdd\x81\x9d\x96\x06\x7e\x81\xf0\xe1\x95\x8e\x86\xdf\x8b\x06\xfd\xf2\xbb\x6f\xb4\xbf\xe1\xd7\x79\x9c\xb0\xc4\x23\x5f\x48\xd4\x36\x58\x56\x05\x82\xfe\x02\x9b\xbe\x22\x95\x9f\x57\xdd\x0c\xe5\x7d\x7e\xad\x56\x9a\xe1\x50\x33\x41\x51\x07\x23\xf6\x87\x8c\x18\xb6\x87\x8d\x96\x6d\xb5\xf9\x29\xe7\x04\x8a\xff\x14\xa7\x22\xd0\xd7\x9d\x3d\x87\x94\x61\xc0\x72\x32\xd1\x15\x43\xc9\xab\xa9\xae\x00\xd7\x35\xb2\x37\x74\x34\xc3\x23\xc8\x2a\x31\xbb\xe8\x94\xaf\xeb\xd7\x9d\x5d\xf1\x8a\x84\x57\x91\x16\x21\x42\x21\x18\x12\x55\x23\x23\xde\x3a\xdf\xed\x33\x26\xc0\xf0\xe3\x95\x2a\x70\x25\xb7\x40\x5d\xc3\x6c\xe9\x03\x9e\xfb\xc6\xf7\x47\xaf\xfa\x91\xe8\xa6\x49\x7e\xb5\x2e\xf2\x2c\x5b\x76\x16\x5a\xb7\x88\x03\xf4\x6a\x20\x8e\xf7\x89\x95\x3b\x2e\x68\x96\x4d\x6d\x9d\x27\x03\x76\x8a\x92\x41\x52\x38\x6b\xd0\x4d\x81\x52\x48\x4a\xd2\x72\x27\xf4\x0e\x71\x25\x67\x2f\xcf\x52\x7e\x26\x8f\xfc\x84\xe3\x27\x50\x61\x49\x78\x58\x46\x64\x34\x83\x4a\x17\xc6\x8b\xbd\x93\xc4\x14\x3e\xd8\xa9\x54\xaa\x31\x64\xb9\xcb\x40\xe2\x8e\x2c\x8b\x52\x98\x6c\x0d\x38\x40\x19\x15\xe4\x58\x75\xa7\x41\x2c\x73\xa4\xde\x1c\xe2\x2c\x6a\xf5\x93\x75\xac\x10\x88\xc9\x0e\x71\x12\x2f\x8b\xa0\x30\x69\x31\xcb\x88\x94\xc4\xbc\x72\x9c\x29\xd2\x25\x0b\x32\xcb\x4f\xe1\xa0\x5a\xaa\xf8\x2b\x84\xe3\x20\x6f\xc8\xaf\xf4\xfc\xfd\x64\x57\x4e\xce\xc9\x1f\xf4\x7c\xa2\xcc\x05\xb0\x2b\x7d\xfa\xb1\x2b\x0a\x9f\x8a\xfc\xc7\xfd\xde\x1a\x1a\xd8\x62\x3f\x77\xac\x7e\x8c\x3d\xd9\xaf\xc4\xdb\x95\x13\x27\x7c\xce\x1f\xe4\x47\x65\x9d\xf0\xaf\xa1\xed\xd5\xf7\xe0\xf9\xac\x77\x3f\x1a\x3b\x8a\xf0\xb6\x8b\x5f\x02\xe2\x48\xcb\xa9\x4e\x17\xab\xcc\x2c\xe4\xd5\xf8\xcb\x69\x95\x26\xe3\x71\x03\xbf\x74\x4e\xbe\x74\x33\x6f\x43\xac\xa3\x21\xd1\x79\xe8\xd6\xd6\x0b\xa7\x72\x68\xc8\xbf\x54\x06\x70\x37\x14\x63\xf7\x0b\x2a\x02\x2d\xb4\x57\x81\x50\x5a\x5f\x78\xe2\x96\x23\xda\x0c\x59\x90\x75\xce\x37\xe9\x4d\x55\x80\xbc\x00\x14\xe6\x98\x88\x86\x94\x4c\x9c\xf2\xa4\x52\xea\x24\x18\x81\x89\x9f\x7c\x24\xc2\xc4\x69\xf8\x33\x12\x38\xa2\x7c\xd1\xcd\xaa\xaa\xde\x14\xb8\x9b\x3c\x34\xed\xe7\x10\x77\xd6\x5d\x41\x3b\x78\x5c\x74\x1a\x0e\x7a\x23\xf7\xfd\xde\x03\xd5\x83\x86\xc4\xeb\x35\x2b\xcb\x53\x02\xf0\xb6\xfa\xba\x3e\x21\x8d\xb5\x45\xf8\xd2\xea\x5a\x64\x0f\x03\xa5\x7a\x29\xd5\x2d\xe1\x98\xb4\x2a\xcf\x25\x0f\x04\x3e\x96\x31\x75\x54\x73\xfd\xc5\xee\x6c\x6d\x38\x19\xd9\x5b\x81\x0f\x9c\x22\xd1\x4b\x95\x2c\x19\x59\x90\x39\xff\x2c\xfb\x42\xe5\x78\x71\xca\xcf\x8a\x65\x28\xa2\x40\x74\xe4\x95\xf8\xd8\x66\x5b\x27\xa2\x91\xe7\x46\x1e\x45\x0d\x72\x67\x42\x22\x77\x27\xbf\xaf\xca\xd5\xff\x18\xd8\x69\x6e\xd0\x26\xb7\xe9\xbc\x95\xc7\x98\x6d\x5c\xbe\x8c\x45\xfc\xd7\x61\xbe\x1d\xbb\xef\x8f\xfa\xfd\x11\x92\xbd\x92\x9f\xff\x02\xae\x0b\x5f\x92\x1f\xf4\xef\x3f\xb4\x21\xc3\x41\x59\x31\x3c\x5d\x35\xf5\x2a\x34\xd7\x11\x7e\x72\x4e\xfe\x49\xcf\xc3\x17\x93\x7f\x47\x2e\xa6\xf9\xf7\x80\x11\x43\xbb\xea\x47\xbe\xf1\xe9\x06\x15\xd4\x4b\x62\x11\x4f\xdc\x38\x3a\xff\x24\xde\xe4\x89\xef\xf5\x5d\xff\xfb\x20\x05\xc9\x89\x3b\xb6\x7b\x05\xc6\xea\x58\xc7\xa9\x27\x8a\x0a\x28\x20\x4a\x29\x87\xa4\xcd\x71\x56\x32\x49\xf8\x52\x79\xa8\x95\x68\x5c\xbe\x4d\x55\x08\xab\x94\x52\x3a\x4e\xc7\x9e\xb7\x1c\xa7\x81\xf6\xa0\x4e\xf1\xf2\x1f\x57\xdf\x7d\xab\xec\x11\x50\x8a\x83\xd4\x39\x2a\x36\x3f\x38\xe0\xaa\x3c\x9a\xcc\x49\xaf\xb5\x16\xbb\x72\x95\xdb\x47\x8b\x66\x5d\xb0\xf5\x4b\xc4\x70\x5d\xff\xe2\xdc\x35\x24\xe9\x7e\xd3\xd9\x6f\x3f\x4c\xd5\x7e\x34\x7d\xd0\x5b\xe4\x65\xff\x13\x7c\xf8\x41\x73\x4e\x3a\xf8\xe2\xaf\x8f\xd5\xfa\x4b\xbf\xd6\x5f\x4f\x56\xfb\x4b\xa7\x5a\x60\x46\x1c\x75\x7e\xb7\x11\x4e\xac\x51\x93\x0e\xe2\xaf\xb4\xbb\x24\xa6\xb9\xef\xe7\x8e\x19\x6a\x17\x62\x94\xdd\x48\x47\x61\x93\xd2\x1f\x00\x71\xe4\xca\x86\x2b\x77\xd4\xdf\xa3\x5f\xd4\x1b\xe2\xe9\x49\x94\x90\x51\x7a\x00\x14\x34\xee\x6e\x5c\xc9\xe1\xc7\x70\x1a\x90\x0d\xa1\x02\xd2\xa4\x2b\xd6\xb9\x0d\x4b\xa6\x20\x53\x99\x5b\xff\x8c\x8c\xda\xe9\x13\x8c\xc9\xbf\x95\x2b\x24\xa4\xb0\x5e\xfc\x02\xb0\xd0\x6f\xd6\x8d\xa8\x99\xea\x8b\x23\x61\x8a\xc6\x84\x70\xa6\x75\x78\x68\x05\x5d\x4a\xf4\x84\x1b\x1c\x3c\xe9\x27\xfc\x37\xfe\xf2\xe9\x06\xe5\x0e\x62\xb5\xf6\x42\x76\xd3\x23\x61\xe6\x4b\xb2\x14\x4b\x11\xb8\x6f\xfe\xdd\x7b\xba\xf8\xd3\xce\x10\x06\xb1\xbd\xb4\xd9\xd0\xf1\xc1\x4e\xbd\x91\x23\x1f\x86\xc7\xae\xee\xfc\xb8\x25\x0d\x52\xca\x36\x00\x37\x46\x4f\xae\x81\xea\xf7\x8a\x55\x6c\x98\x9c\x2a\x07\x0c\x53\x39\x45\x42\x6e\xf9\x7b\x0f\x8f\x3d\xf8\xc8\x23\x05\xfd\xc5\x12\x1c\xc2\x7d\x1f\xa2\x28\x1f\x25\xc4\x97\xa5\x9c\x1d\xe0\x5a\xd6\x70\x8c\x03\x9b\xb8\x00\x93\x42\x52\x83\x86\x24\xec\xb8\x53\x12\xdc\x74\xfb\x0b\xa3\xd1\x84\x52\xaa\xf1\x36\x8d\x17\x49\x29\xb7\x7e\x4d\x92\xe7\xf9\x15\x8a\xc9\xa3\x5f\xa9\x62\xbd\x7a\x29\xb7\xb2\x6f\xaa\x70\x97\xfb\x4d\x31\x99\x80\xc7\x08\x92\x6d\x51\x6d\xb5\x6a\x22\xe5\xba\xdf\x62\xa2\x29\x4a\x0e\xba\x2b\x62\x75\x82\xce\xec\x5f\x4d\xf5\x60\x34\xa2\xc8\x31\x26\xa3\xc2\xf7\x61\x87\x82\xc6\x04\xa4\x0f\x48\x62\x85\xb6\x9f\xc3\x79\xda\xf5\xb4\x43\x09\x6f\x61\x91\x8b\x5a\x00\x0e\x88\xce\x4e\x33\x27\x07\xa5\x8f\x39\x2d\x2a\xef\x8b\x6e\x1c\xdc\x13\x0a\xbb\xc4\x3c\x52\x49\xa0\xfa\xb8\xa8\xb7\x42\x16\x68\x18\x7d\x66\x74\xcb\x47\x19\x22\x41\x74\x27\x79\x7c\x39\xb3\x84\xc9\x79\xee\xc3\xfa\x05\x5b\x9a\x75\x35\xe8\x4c\x98\x78\xb2\x96\xc9\x09\x06\x01\x5d\xb5\xee\x7e\xad\xbc\x88\xba\x10\xa0\x9e\x63\xd2\x2e\xae\xbb\xa4\x23\x63\xe5\xd7\xae\x9b\xfe\x40\xee\xd0\x63\xb8\x7c\x7c\xeb\xf5\x2a\x51\xdb\x7c\x9d\xb1\xb8\xf8\xe1\xd1\x7a\x34\xc0\x28\x68\x27\x61\x34\x28\xe3\x73\x99\xb5\x39\x49\xbb\xd2\x24\x45\x0c\x48\xdc\xb1\xae\x2a\x5d\x01\xda\x64\x52\xd4\x75\xda\x39\x02\xe7\x24\x94\xec\xd0\x62\xc8\xfc\x0a\x09\xca\x08\xd3\xd4\x58\xa7\xee\x84\xbd\xe8\x04\x6f\xe2\x1a\x1b\xe4\x61\x1c\x11\xd6\x81\x56\x95\xc5\x05\x20\x52\x22\xfe\xf1\x98\xe8\x3b\x00\xc2\xd2\x89\x23\xa5\x9c\x11\xb5\x1c\x48\x58\x41\x90\x4a\xd0\x3b\x89\x96\x92\x7f\x4a\x9e\xae\xa6\x35\x5e\x25\x63\xb4\x0c\x42\xf6\x2a\x82\x17\xab\x64\x5c\xe3\x73\x9d\x54\xaf\x9f\xc6\xf7\xbd\xc9\x96\x8c\x69\x8d\x91\x37\x66\x6c\xec\x61\x38\xd5\xfd\x3d\x7a\xea\x24\x41\xa6\xa1\xf7\x2e\xdf\x7b\xc4\x7b\x9b\xde\x6c\x85\x47\xbc\x2f\x72\x21\xf2\x9d\x47\xbc\xaf\xd9\x46\x78\x11\x29\x18\x3d\x3a\xd5\x77\xd3\xe5\x3a\x9a\x5a\x6b\x1c\xd7\x4f\xac\x2a\xf9\x90\x5c\x9e\xb4\xf2\xdd\x3e\x2f\x59\x02\x26\x7f\x05\x30\x5e\x6f\xf3\x5c\x87\xd0\x41\xff\x43\xb5\x3a\x18\x93\xa9\x04\xe5\x2a\xa7\x66\xb7\x9c\x9e\xd2\x78\x38\xc9\xaf\xc7\x73\xae\x98\x3c\x46\x55\x72\xb5\x52\x3c\x64\x90\xa6\x0e\x92\xbd\xd7\xda\xff\xa4\xf3\xd4\xf7\x53\x06\xa7\x3f\xfb\xf5\xd5\x74\x0d\x88\xc8\xd3\x25\x3c\xec\x9c\x4c\x4b\x36\xe0\x12\x47\x9f\xcd\x48\x49\x8b\xe3\xc8\xa0\x67\xc5\x74\x5d\x15\xc8\x0d\xce\xee\xce\x86\x26\x2b\xa0\xfe\xaf\xa8\x04\xa0\x0c\x14\x5b\x10\xd5\x15\x41\x81\x6f\xab\xdd\x35\x2b\x42\x11\x2d\x3d\x2f\xf0\xf6\xf7\x1e\x86\x90\x89\x2d\x97\xd3\x2b\x56\xd7\xb2\xd0\x88\xd2\xcc\xf7\xc7\x15\xf6\x7d\xc1\x94\x19\xaf\x6d\x4e\xf9\xbe\xae\x7d\x7f\x1d\x3e\x8f\x64\x41\x7c\xa8\xce\xe9\x33\x92\xd1\xac\xae\xe5\x33\xb2\xa6\xe3\xaa\xae\xe7\xce\x06\xb9\x52\x73\x06\xbd\x5d\x8f\x33\x4c\xd0\x7c\x92\xe3\xa7\x68\x3e\x41\xb9\xec\xf7\x79\x55\xd7\xd3\x4f\x30\xbe\xa0\x33\xf0\x2c\x9e\x61\xb2\x3e\xa7\xf9\x62\xfd\x94\x3e\x23\x47\x1f\x6b\x37\xc0\xc6\x31\xc8\x5f\xd3\xf1\xba\xae\x65\xb3\x33\x49\x05\xc3\x79\xb4\x5c\x8f\x91\xfc\x1d\xcf\xf1\x53\x1e\x3e\x8b\x82\x31\x07\x71\xbe\xdc\x84\xd3\x8a\xa7\x82\x66\xa4\x98\x96\x22\x2e\x04\x5d\x93\x62\xca\x78\x42\x53\x8c\x49\x0a\xc2\x88\x8a\xd1\x83\xb3\x6a\x19\xeb\x79\x7e\xf4\x1c\xae\x43\x39\xe8\x19\xd9\xb4\x91\xdd\xd6\x17\x9b\xc5\x7a\x3c\xc6\x48\x9e\x27\xd7\x91\x06\x25\xe3\xf8\xec\x02\x10\x11\x4b\x64\x61\x47\x8e\x25\x0b\xd7\x91\xc6\x27\x85\x03\x44\x75\x0d\xcc\x90\x7c\x5b\xd7\xa8\x57\x09\x85\x54\x6b\x00\x9f\x45\x1f\x3e\x63\x06\x96\x47\xaa\x5e\x54\xd1\x98\xe6\x46\x8b\x14\xcb\xf3\x4c\x81\x7b\x9b\xa9\xa4\xa9\x75\x2c\x21\xa8\xa2\x15\x44\xed\xa8\x6b\x94\xd3\x78\x7a\x9d\x27\x0f\x9d\xdc\x23\x71\xcf\xbd\xad\xc4\x98\x54\x7a\x13\xe4\x4e\xff\x49\x7e\x2a\x6f\x69\x8e\x89\x9d\x80\x0a\xd2\x20\x7b\xd7\x59\xbe\xfe\xe0\x61\x02\x4d\xd3\x0a\x63\x8c\x03\x55\x66\xe4\x4c\x92\x7a\x42\x14\xc3\xec\xcc\x95\x12\x77\xc9\xc5\x5a\xd3\x99\x5d\x0a\xa5\x11\x92\x1f\x42\x18\x89\x75\xd4\x9b\x42\xf9\xe6\x94\x39\x71\xb9\xcd\xef\x06\xf6\x60\xa6\xe9\x1b\x70\xa8\xdb\x34\x19\x52\xb0\xeb\x32\xb8\x21\x22\xbf\xb9\xc9\x86\x68\x9f\x77\x9d\xe7\x19\x8b\x5d\xfd\xe7\x52\x9b\x7f\xca\x86\x91\xb6\x24\x97\x0d\x98\xeb\x3e\xc1\x8d\x75\x2b\xcb\x2b\xf5\x6b\x3e\x34\xb7\xea\xdb\xc6\x52\x95\x35\x23\x1b\x46\xf6\x4c\x9d\xcb\x4d\x20\xa4\x1a\x42\x23\x41\x8a\xf9\x84\xd1\xf3\xae\xb3\x50\xcf\x57\xe8\x3c\x25\x5b\xf9\xf9\x93\xfa\xfd\x2e\x4f\xaa\x8c\x3d\xa9\x57\xe7\x68\x19\xfc\x16\xdf\xc6\x35\x5b\xef\x62\x5c\xae\x8b\x74\x2f\xce\xd3\xc5\x5a\x92\x0e\x05\x25\x06\xc8\x5e\x17\xf1\x0d\x80\x4b\x37\x85\xe2\xab\x13\x29\x14\xd1\xa6\xad\xe2\xcf\xb2\x33\xe9\x24\x3f\x30\x14\x0f\x93\x4d\x3f\x3d\xb2\x49\x8d\x44\xbc\x36\x49\xd2\x51\x21\x9d\xfa\x47\x48\x7c\xd9\xcd\x12\xb4\x61\x98\x3c\xa8\xa0\x71\x97\x59\xce\x19\x5d\xb3\xe9\x5a\x5e\x00\xd9\x19\xcd\x70\xef\xce\x06\x71\x35\x81\xe6\x64\x85\xae\x13\xa4\x49\xf0\xff\xf9\xfd\xc5\xb9\xbd\xf6\xc8\xc3\x94\xe7\xd0\xc0\xa5\xfa\x8c\x8e\x46\x47\x2d\xb5\x75\xbb\x1e\x8a\xfd\x06\x6c\x12\x2f\x7d\x21\xeb\x56\x97\xaa\x4e\x5b\x0b\x40\xc6\x0d\xa3\x07\xb1\x65\x71\x12\x84\x73\xe2\x5d\x80\x03\xed\xe7\x1e\xf1\x2e\xce\xf5\x65\x44\xd6\x79\x16\x84\xcf\xec\xcb\x8b\x75\x9e\xdd\x14\x79\xb5\x57\xc5\xec\x9d\xf3\x85\x28\x3a\x1f\x08\x89\x45\x74\xa5\x70\xe9\x16\x4d\x82\xf0\x79\xbf\xe8\x85\x28\x74\xf1\xe2\xf3\x81\x6f\x7e\xd5\xc3\x0f\xc2\x19\xf1\x3c\xe2\x79\x91\x83\xbc\x6f\xdd\xa4\xc5\x56\x9c\x72\x3a\x43\xe1\x71\x0a\xbc\x53\xb9\xcc\x21\x94\x0f\x0e\xfe\x5a\x7e\xcf\xe5\x40\x2a\x25\x53\x43\x18\x91\x9e\xc0\x53\x39\xfd\x2d\xad\x05\x2c\x03\xf1\x3c\xef\x66\xa4\xed\x45\x79\x73\xc2\xd4\xd8\x60\x2a\x0a\x37\xb2\x90\x47\xc4\xbb\xc9\xf2\xeb\x38\x7b\x75\x1b\x67\x1e\xb8\x51\x2b\x1a\x23\xfa\xef\x30\x6e\x6e\xd8\x14\xe6\x98\xca\x8b\x4d\x9e\x0b\x79\x61\xd6\x15\xae\x63\x05\x3f\x37\x60\xa4\x11\x27\x04\x2e\xe0\x36\xb1\xd0\x55\xd7\xe8\x86\xc9\x6b\xfb\x99\x86\x3a\x00\x2c\x9d\xe9\x6b\x57\x65\x22\xdd\x67\x8c\x7e\x64\xae\x3e\x52\x2b\x6d\x72\x7c\x45\x0a\x61\xed\x24\x3e\xaa\xfd\xbf\x2d\x57\x77\xe3\xc5\x79\xbb\xba\xf7\xa7\x42\x52\x39\x09\xfe\xc5\x49\xe4\xa3\xc2\x11\x25\x74\x46\xb6\xed\xdc\x25\x17\xdb\x45\xa2\xdc\x3c\x20\x64\x55\x22\x89\xdf\x0c\xd2\xd0\xf4\x75\x44\x39\xc6\x66\x89\xf6\x24\x77\x62\x3a\xe5\x51\x90\xb7\xaa\xa1\x9d\x71\x9f\xc7\xf8\x00\xb6\xa4\x9b\x6e\xe2\xb1\x13\x58\xaf\xa4\x28\xd1\xec\x57\x8e\xeb\x3a\x54\xa0\x8d\x8f\x93\x03\x54\xf4\x46\x12\xca\xba\xbe\x61\x53\xb3\x17\x48\xec\x20\x81\x4a\x72\x42\x57\xd3\xad\xd8\x65\xdf\x17\x4c\x9b\x30\xe7\x78\x5c\x49\x9e\x68\x4d\xab\x70\x66\xe2\x3c\xaf\x27\x13\x1c\xd3\xd8\x41\x0a\xed\x00\x63\xd7\x08\x9b\xa0\x98\x6e\x5c\x73\x71\x37\xb2\x2b\xf5\x3c\x1d\x98\x49\x9b\x04\xea\x11\xbe\x63\xf7\x9a\x3d\x97\x04\xba\xf7\x85\x5c\x07\x9b\x21\x73\x1f\x26\x3a\x04\x47\x01\xb1\xa0\x5a\xf3\xcb\x9c\x14\x18\xa7\x36\xbe\x94\x33\xcd\x19\x4d\x65\xcd\x24\xa6\xb7\x0c\x75\xa7\x58\xf2\x18\x8a\x1e\x79\xa0\x8a\x7b\x60\x28\xc6\xf2\xe4\xbe\x76\xda\x8c\xc3\xb5\x6c\x73\x6b\x56\xcb\x84\x9a\xf4\xb0\x75\xdf\xcd\xad\x10\x6e\x03\x8c\xe2\xb5\x24\x81\x1f\xd8\xc3\x39\xb9\xd3\xb4\x74\x97\x57\x25\xab\xf7\x79\xca\x05\x2b\xea\xb5\xf2\xe6\xdd\x31\x5e\xd5\x49\x11\xdf\xd4\x49\x91\xef\x71\xbd\xce\xd2\xf5\x87\x73\xf2\x0e\xbe\x09\xdf\x4f\xa3\xa7\x58\x1e\xef\xa6\x68\x3a\xc6\x35\x76\xc0\xfb\x92\xb9\x69\x02\xec\xe3\x57\xce\x63\x27\xf3\xf9\x15\xeb\xfa\x0a\x53\x4a\x7b\x16\x4a\xfa\xcd\xab\x6e\xac\x56\x47\x12\xdd\x20\x4c\x29\xf2\x20\xd2\xab\xca\x4e\xde\x56\xff\x81\xb9\x0a\x55\x85\x51\x63\x52\x76\x35\xa7\x56\xd7\x74\x30\xda\xd3\x63\x7f\x5d\x10\x81\x16\x75\xcd\x09\xb7\x07\x6b\x81\xa1\xfa\x12\xaa\x17\x61\x19\x91\xdc\xe1\xc6\xd2\x8d\x76\x8b\x29\x54\xa4\x17\x4a\xd3\x25\x4a\xc1\xd6\xc4\x56\x11\xe8\x17\xbe\x7f\xac\xfa\xe2\xb2\x74\x41\x0a\x5b\x56\xdf\x3a\x3d\xd0\xa1\xc2\x53\x9c\xd2\x57\xcc\xc2\xd4\xa8\xcd\xa5\xe2\x86\xba\xcf\xe1\x9c\x92\x12\x94\x0e\x9e\x54\x11\x9e\xe6\x9b\x0d\x62\x3a\x51\xdf\xb1\x95\x61\x83\xa7\x37\x55\x9a\xd0\x18\x7e\x20\x04\x1e\xdc\x5f\xc1\xcf\x78\x0c\x29\x28\x8e\xa5\x2a\xec\x96\x71\xa1\x8c\x84\x94\x94\x27\x25\x05\xc8\x74\xdb\x45\x7a\x21\x67\x11\x96\x27\x5f\x22\x8d\xfe\x49\x4a\x46\x73\x10\x7d\xda\xef\xe5\xb3\x83\x4d\x30\x1e\x8c\xe6\x64\x0b\xd9\x5b\x8a\x13\x9e\xc3\x9a\x58\x80\x15\x0e\x9c\x00\xe7\x3e\x9b\xa6\xe5\xbb\x22\xbd\xb9\x61\x85\x76\xb0\x4a\x95\x6b\xa6\x89\xf6\x81\x91\x69\x11\x22\x13\xc4\x59\x98\x46\xca\x29\x25\x61\x19\xbb\x91\xf8\x40\x79\xc8\x83\x14\xf1\xfb\x22\xdf\xc7\x37\xb1\x1a\xab\x9d\xff\x62\xc0\x80\xe8\x97\x56\x84\x9c\x2a\x3d\x7a\x6e\x7a\x46\x74\x3f\x10\x26\xc5\x88\x52\x2b\x99\xd1\xaf\x71\x5d\x8b\x65\xe7\x73\x48\x10\x4e\x0f\x0d\x14\x77\x62\x5f\xc8\x1e\xbd\xd9\xed\x58\x92\xc6\x82\x75\xba\x46\x18\x38\x61\x31\x2e\x5e\x2a\x4c\x8b\x30\xd1\x79\x7a\x15\xce\x6b\x83\x9d\xa0\x4e\x53\x5a\xb9\x6b\xe6\x44\xa8\xa9\x43\x56\x20\x5d\x84\xb3\x88\x5c\x4d\xc1\xb6\xa1\xd5\x4a\x63\x52\xd8\x38\xcd\xc6\x1b\x93\x3c\xd6\x3f\xc9\xe3\x3b\x82\x43\x23\x26\x4d\xc1\x8f\xb5\x0b\x00\x97\x0c\x37\xfa\x19\x3d\x28\x16\x20\x38\xf4\xfc\xde\x04\x61\x03\xa1\x9e\x14\x65\x25\x7b\xa2\x83\x31\x9a\x69\x06\xd0\xf8\x17\x12\x18\x1f\xf8\x54\x43\x14\x9c\x7a\x51\x4e\x39\x36\x4f\x48\x4a\x73\x1b\x7b\x02\x44\xce\xa7\x7c\xe4\x65\xbf\x09\x37\x9b\x84\xf7\x36\x89\x3c\x9d\xde\xaa\xfe\x97\xf2\x80\xda\xde\x51\xad\x6e\x57\x64\x07\x70\x07\x06\x92\x75\xab\xfb\xa0\x0c\x33\xcc\xdd\xc0\x26\x1e\xe2\xea\xae\xda\x29\xd4\xab\xc7\x92\x91\x89\x19\xbc\x34\xaf\xe4\x81\x12\xe2\x39\x98\x00\x83\x8e\x5d\x9a\xce\x8b\x8c\x49\x46\x11\xa3\x48\x51\x17\x57\x25\x2c\x09\x7c\x57\xb7\x94\x4d\x26\x38\xa1\x37\x14\x95\xf4\x9d\xe6\x06\x58\x98\x45\x3a\xc6\xd0\x3c\x22\x5b\x8a\xca\xf0\x99\x4e\x4b\xa4\x03\xdd\x4c\x4d\xa4\x1b\x4c\x12\xdf\x47\x1b\xda\xdf\x89\x09\xec\x44\x92\x50\x94\x2e\x37\x9d\xfd\x18\x6c\xa6\xd7\x29\x4f\x40\xa5\x5a\xd7\x09\x39\xf9\xed\x9a\xb6\xba\x14\x08\x9b\x96\x90\xbc\x48\x6f\xa0\x8e\x1b\xa5\x6d\x2c\x2c\x56\xe1\x44\xae\x59\xa0\x56\x90\x98\xb5\x0f\x52\xe2\x06\xbd\x08\x00\x12\x4e\x44\xc4\x30\x7a\x54\xd2\x62\xad\xad\x8e\xe2\x33\xf5\x40\xc1\x40\xd0\x9e\x56\x8a\x5d\x43\xfa\x92\x86\x51\x8b\x6d\x2e\xf3\x8a\x0b\x3a\x23\x1b\xb9\x2b\xab\xbd\xef\x8f\xe6\x23\x4a\xf5\x9d\x76\x23\x25\x05\xd9\x92\x58\xe2\x89\x23\x3b\x23\xdf\x3f\x7e\x86\x12\x12\x63\x4c\x36\xf2\x85\x9c\x67\xf9\x6b\x6a\x5a\x63\xb2\x36\x10\x6f\x20\xb8\xfb\x80\xaa\xe9\xc0\x98\xa4\x6d\xdc\xca\x7d\xb7\xbf\xe3\x31\x99\x91\x35\x0e\x34\x27\xb5\x6e\xd1\xb8\xda\xb0\x72\x90\xa3\x19\x6e\x06\xad\x1a\xfe\xda\xce\x6d\x95\xc4\xbe\xaf\xd1\x05\xec\xe3\x5b\x10\xc6\xd8\x0d\x86\x0f\x19\x45\x5a\x19\xf6\x57\x80\x36\xdd\xa0\x1e\xdc\x8a\xff\x0a\x6e\xf1\xe1\x24\xe8\xc1\xe2\x52\x54\x3c\x0e\xba\x90\x0f\x84\x94\xb4\x84\xa4\x5c\xbd\xb4\x47\xab\xd5\x14\x7b\x63\x03\x41\xab\xd5\x14\x2d\x83\xe9\xd3\xd5\x6a\x5a\x63\x0f\x8f\x3d\x24\xaf\x9e\x60\x4f\x72\x93\x83\x91\x4a\xd7\x10\xa8\x94\x8c\x52\xdf\xbf\x19\x51\xba\x9e\x1a\xd8\xaf\x6b\x70\x2e\x90\x0b\x0b\xcf\xd5\xca\x97\xbe\x6f\xb2\x33\xae\xa7\x16\x82\x71\x5d\x17\xbe\x5f\x40\xb9\xd2\x66\x76\x44\xde\xd3\xa7\xe0\x99\x58\xd7\xa3\xf6\xb9\x84\x6a\x0b\x24\x39\x99\x4b\xe8\x6a\xbf\xe9\x41\xcd\x64\x42\x36\x5a\xc8\xe6\xfb\xe6\xca\x68\xe9\xd6\x18\x2f\x62\xdf\x1f\xed\x5b\x42\x25\x79\xf1\xb8\x48\xf2\x3b\x6e\x77\x85\x79\x60\xbe\xda\x12\x07\x77\x5e\xb9\xf6\x93\x88\x91\xa4\x7d\x69\x74\x83\xb0\x13\x1b\x6b\x67\x94\x9c\xa5\xfc\xac\xc2\x66\x41\xad\xc6\x2d\x19\x4b\xa8\x00\x40\x1d\xcd\xf0\xa2\x6f\x52\x52\x01\x4c\xda\xd2\x9e\x6a\xe4\x4c\x81\xa4\x27\xc1\xde\xa0\xdb\x61\xc6\xc5\xc8\x69\x41\x29\xa2\x0e\x10\x7d\xcd\x9b\x92\x57\xaa\x6e\x6d\xd2\x7b\xc9\xb5\x65\x14\x39\x7c\x83\x67\x5a\xab\xeb\x21\xb2\x12\x56\x2a\xbc\x1a\x40\xdb\xfa\x08\x64\xed\xdb\x43\x03\x32\x49\x08\xd0\x50\x11\x41\xe7\x0b\x71\xa4\xf1\x86\xa8\x27\x65\x28\xa2\xd6\xb2\x5a\xa7\x50\xad\x5a\x48\x87\xb4\x0f\x4a\xcf\x35\x5a\x4b\x66\xe4\xa5\x9e\x82\xba\x86\xb5\xeb\x3c\x73\xdc\xe3\x2b\x38\x7e\x9a\xfe\x69\x44\x54\xba\x05\x48\xa6\xe2\xaf\xe8\xa0\x0b\x29\x8d\x43\x21\x8f\x44\xbe\x3f\xaa\xa6\x69\xe9\xf0\x19\x57\x22\xdf\xef\x59\x82\x30\x3e\x54\xd3\x75\x55\x14\x8c\x0b\xdd\xb1\x74\xca\x32\xb6\x23\xbc\xad\x27\xa7\xa9\x6d\x2e\xe4\x4e\x85\x43\x1c\x4c\x5b\x73\x35\x2d\xec\x4e\xd1\x60\x99\x4f\xdd\x27\x6e\x01\x73\x66\x73\xf7\x16\xaa\x74\xb3\xdf\x5d\xff\x46\x73\x52\x4d\x25\x51\xa2\x39\xfc\xb4\x56\x61\xa8\xa0\xe8\x88\x53\xcd\xed\x7e\xd6\x2c\xab\xaa\xa8\xae\x73\x33\x12\xac\xe9\xbb\x1e\x6e\x09\x59\x2d\xe4\xd9\x00\x55\xd3\x82\x95\x55\x26\x28\xc8\xdd\xab\x63\x76\xb1\x3a\x66\x78\xb1\x3d\x58\xae\xa7\xfb\xbc\x14\x66\xf9\x20\x8c\xa4\x73\xdf\x59\x4e\x62\x5a\x02\x4b\x2e\x35\xbf\xc3\x8a\x52\xd2\x89\x6e\x2d\xba\xc8\x02\x62\xc4\xab\x64\x22\x00\x69\xbe\x9f\xb9\x76\x30\xc8\x83\xe3\xaa\x9b\x1d\x61\x7e\x41\xd9\x54\x65\x60\xd0\xb6\xa8\xd9\x88\xaa\x78\x42\x19\xcd\x3a\x3e\xe8\xc0\xb2\xea\x00\x5c\x6e\xb5\xa6\xd6\x51\x9b\xd3\x61\x24\x57\x23\xb3\xa9\xcc\xb1\x8e\x42\xab\x42\x63\x1c\x1a\xa2\x32\x19\x54\x20\xd8\xb2\xfc\x6d\x1c\xa6\x72\x05\x21\xc8\xa9\xc5\x87\x26\x29\x6e\x1c\xa6\x11\x2d\x3a\x6c\x04\xf8\x72\x22\x15\x51\x45\x1b\xe7\xa0\x0c\xeb\x08\x4c\xfa\xb9\x4e\x55\x9b\x59\xaa\x86\x49\x0c\xd9\x45\x73\x9b\x6c\x20\x6f\x23\x68\xea\x08\xb2\x12\x0a\x82\xac\x5d\x87\xbc\xb1\x4b\x9a\xa9\xcd\x5a\x5d\x88\x3f\xfd\xca\x38\x54\x56\x92\xcd\x2f\x81\x17\x97\x70\xd2\xe1\xc7\xf1\x61\xd8\x98\xf4\xe8\xec\x40\x04\x39\x30\x5e\xed\x98\xb1\x23\xed\xdb\x95\x82\x7d\x27\x84\x85\x71\x3d\x59\xb4\x91\x94\xdc\x00\x29\x8f\x33\xa8\xd4\x9e\x8c\x86\xde\x75\xf4\x93\x8f\x7e\x7e\xfc\x26\x14\x51\xdf\xae\xf5\xd4\xf8\xf4\x99\xf7\x4f\x86\x74\x57\xa4\xc2\x5c\xab\x13\x97\xca\x08\xd1\x90\x4d\x3a\x1c\x6b\x24\xb4\xe6\xc1\xd1\x92\x05\x92\x50\xe8\x99\x04\xb3\x39\x8d\x11\x82\x43\x96\xc7\x49\x70\xe0\xf9\x17\xd5\xb5\xb6\xca\x25\x00\xc2\xc1\x01\x18\xc8\x01\x1b\x4a\xd9\xe1\xba\xb6\x82\x83\xbd\x46\x52\xc2\x84\xd0\x14\x53\xa8\xc0\xf7\x5f\x20\x41\x8c\x3e\xc3\xf7\x5f\x40\xb4\x45\xb5\x3d\xe4\x19\x8d\x8c\xe6\x0d\xd1\x07\x8e\xff\x6f\x5a\xc1\x44\x8e\xc6\x8a\xd1\x07\xac\x41\x0d\x7e\xf8\x2f\x1b\xd1\x54\xd4\xb6\x53\xd7\xf0\x3e\x06\xca\x7d\xcd\x36\x79\xc1\x2a\xae\x26\xd6\xc5\x72\xdd\x1e\x18\x44\xcd\x34\xb6\xf3\x7d\xd6\x85\x21\x30\x82\xed\x3c\x99\xaa\x7e\x82\x3e\xc4\x7e\x87\x9b\xa6\x51\x6e\x28\x96\x75\x39\x32\xba\x67\x43\x8e\x21\xb2\xc1\x21\x7f\x11\x65\xd4\xa8\x81\xe5\x38\x73\xf7\x08\x20\xb6\x13\xa5\x4a\x15\x6d\xc3\xc2\xba\xb0\x46\x04\x38\x9f\xea\xd3\xe4\xc0\x26\x32\x61\x9d\xc0\x58\x5d\x15\x53\x0f\xd2\x52\xd3\x96\xef\x15\xa5\x61\x09\xb5\x41\x2b\xed\xa3\xba\x6e\x0d\xfb\x8e\x5e\x6a\xd2\xc5\xdc\x79\x5b\x5e\xb2\xe0\x95\x69\x52\x91\x76\x03\x06\xbe\xff\x5c\x51\x03\xb8\x73\xec\x8f\xcd\x93\x96\x02\x04\xe6\x99\xaa\xa8\xcb\x2a\xb0\xee\xbd\x2a\x02\x81\x6b\x59\x62\x8b\x74\xee\xb5\xfe\x53\x4d\x01\x11\xea\xbc\x08\x67\x50\x63\xdf\xa4\xde\xa7\x3b\x76\x25\xe2\xdd\x9e\xaa\x19\x35\xb7\x75\xfd\x32\x16\x6c\xca\xf3\x3b\xa4\x65\x45\xed\xde\xa7\x72\x0f\x1c\xe1\x50\x7a\x70\x82\x91\x05\xfa\x35\x39\x9e\x71\x39\x55\x43\x1c\x92\x7a\xfe\x08\xa3\xa3\x0a\x5c\xa5\xbb\x0a\x86\x19\x8c\xe6\xa4\xcb\x30\xf4\xfd\xa5\x19\x3d\x06\x8d\xc5\x29\x38\xb8\x64\x44\xd2\x70\xfd\xda\xb6\x02\x79\xaa\x7a\x6c\x49\x43\x7a\x5c\xc9\x7f\xd3\xf0\xf1\xb8\x1e\x6b\xfa\x88\xfd\x51\x6d\x0f\xcd\xd2\x7f\xd3\x89\x47\x66\xf9\xcf\x7a\x73\x42\xd6\xa7\x94\xf0\x47\xbd\xb5\xe1\x47\x0e\x71\x26\xfe\xc9\x1e\x24\xad\xb9\x06\xb2\x00\x41\xcd\xd6\x72\xbb\x67\x96\x40\x6d\x63\x7e\xc3\x92\x77\x79\x05\x21\xe5\xe5\x13\x51\x64\xfa\xab\x84\x89\x38\xcd\xe4\x15\x2c\xc6\xf7\xdb\xb8\x84\x8f\x76\x4c\xc4\xba\xc8\x3e\xbe\x61\x3f\x9b\x8b\x5f\xe4\x05\x58\x64\xea\xb7\xb7\x29\xbb\x93\xbf\xde\x7a\x1b\x17\x9e\x22\x88\x89\x69\xb7\xb8\xd4\xd7\x1f\x54\xe1\x0f\xec\xc1\x3c\xd1\x89\xb9\xec\x95\xea\x58\x96\x32\x2e\x7e\x6e\x2f\xa1\xb9\x7c\xb3\x29\x99\x7a\xaa\x2e\xe1\xa9\x56\x71\xbc\x49\x9c\x1b\x38\x84\xcb\x0e\xae\x0b\xc6\xf8\xcf\xed\x25\x7c\xa1\xf0\x80\x33\x0f\x22\xd7\x0a\x08\x75\x63\x9f\xdf\x6d\xd3\xa1\xf3\x9c\xe5\x39\x17\xbd\x90\xbb\x50\xde\xf7\xaf\x4d\x5c\x68\x45\x94\x96\x36\x44\x91\x9e\x88\x65\x7b\x19\xb0\xa9\x9d\x0b\xfb\xbd\xeb\xdb\x70\xd7\xab\x6b\xee\x8b\xe5\x3c\x78\xe6\x8b\xe5\xf3\xe0\x63\x5f\x2c\x9f\x05\xb3\x40\x7f\xa8\xa0\xc1\x08\x56\x25\xa0\xb4\xd1\xb8\x54\xc6\x3c\xa5\x4e\x49\xb9\x47\xae\xb3\xaa\xd0\xb7\x79\x25\xbc\xa6\xe7\x78\xdc\x3f\x85\xb0\x88\xf6\x99\x0b\xcb\xb6\xbc\x30\xc6\x95\xe4\xea\x14\x8b\x70\x5c\x56\x11\xfa\x8e\xcc\x44\xb8\xd1\xc3\x40\x7b\x25\x31\x47\x11\x78\x70\x9d\xdf\xb2\xc2\x23\x70\x99\xb1\xf8\x96\x99\xc7\x95\xf0\xcc\xa2\xeb\xe2\xfa\x4e\x7d\xa0\x6f\xf4\x27\xe6\x55\x7f\xc4\xe9\xf0\x88\x3b\xdd\x4b\x89\x11\xe9\x04\xa9\x66\x93\x07\x53\x8c\xf7\xe8\x04\x28\xc3\xed\xe1\xcf\x0d\xde\xca\x29\xd5\x2c\x53\x3f\x88\x1f\x87\xec\x10\x6a\xc5\x69\x61\x0f\x80\x44\xd0\xc2\x8a\xed\x06\xb5\x39\x44\x7f\x93\x62\x22\x9a\x23\x83\xe1\x4e\xfa\x3b\x63\xfc\xa7\x3b\xf4\xc1\x2e\xa2\x7a\xde\x90\x9c\x1f\x8b\xf0\x4e\x15\x27\x73\xf9\xc1\x66\x73\xca\x27\x0c\xcc\xd8\x8f\x51\xbd\x7c\x62\xa7\xc6\xb0\x22\x9d\xf9\x22\x57\x88\xf5\xe4\x0d\x4a\xa3\x55\xb4\xe7\xeb\x65\x3b\x43\x63\x6f\xea\x8d\x9d\x57\x81\x33\x79\x85\x3d\x94\x11\x3b\x8b\x0a\xaf\x0e\xea\x0d\x75\xee\x9d\xf4\x2c\xe5\x67\x0c\x2b\x54\xbf\xd9\xc8\x73\x19\x61\x61\x3a\x18\x42\x13\x04\x03\xc2\xf7\xdb\x38\x12\xad\xe1\x35\x64\xfb\x10\x44\x58\x35\x23\xb0\x39\x0a\x0c\x5e\xe9\x30\x82\x27\xf5\x6c\x1d\xf7\x01\xc2\x95\x2d\xb4\x36\xa0\xfa\x96\xd1\xf3\x0b\xa5\x51\xae\x2f\xc0\x90\xac\xbe\xc8\x52\xfe\xe1\x3c\x25\x2f\x19\x3d\xd7\xb6\x3e\xab\xf2\x29\x5a\x06\xe1\x7b\x1a\xd5\x74\x55\x3e\x35\x26\x40\x53\x7c\x9e\x92\xdf\x18\x3d\x7f\xbf\x2a\x9f\x5e\x8c\xd0\x32\x58\x85\x97\x2f\x5f\xbc\x7b\xb1\x0a\xeb\xc9\x04\xd7\xf2\x41\xb4\x8a\xe4\xf5\xe7\xab\xf2\xe9\x13\xd7\x29\xea\xf7\xae\x8e\x57\x45\x51\x93\xa4\x06\x78\x7a\x74\x1c\xce\x4f\xb8\x21\xe0\x3c\x51\xc8\x72\x10\xc8\xd7\x84\x82\x43\x1e\x18\x7b\x78\x38\x9c\x45\x75\xed\x84\x0e\xfb\x9a\x75\x7c\x38\x01\xc4\x91\x42\xaa\xa7\xb2\x22\x8e\xbd\x73\x6f\xac\x59\x53\xa7\xa6\xaf\x9c\x9a\xc0\x97\xea\x5c\xd9\xd9\xb6\x1a\x76\x9b\xb8\xe7\x13\xbc\x64\x2e\x87\x6b\xdd\x64\x02\xc3\x83\x1f\xb5\xea\xb6\xf4\x1d\x1b\x94\x7b\x2c\xb4\x04\x42\x74\x43\x80\x77\x65\xdf\xa8\x34\xda\x32\x6c\x65\xde\x16\x18\xad\x10\x52\x1c\x09\x21\x49\xa9\x83\x70\xce\x48\x41\xcb\x30\x8d\xfa\x56\x38\x1d\xc5\x2d\x49\x89\x2c\x13\xf2\x08\x2f\x7e\xe8\xb6\x9f\xd3\xd6\x0f\x0b\x93\x98\xba\x21\xcb\x72\x4c\xb4\xeb\x0c\x81\xbc\x57\x76\xc4\xdf\x33\x64\x35\xf2\x05\xbd\x41\x3a\xb6\x99\xc4\x04\x56\xe0\x0f\xc6\xa9\xd6\x4f\x64\x4f\x37\x93\x39\x49\x28\x28\x1c\xb7\x74\x87\x12\x10\xf7\x6f\xeb\x7a\x7e\xb1\x19\x70\xb6\x94\xa7\x03\xd7\xe4\xcd\xf7\x5f\x6a\xea\x98\xb4\x27\x99\xde\x2e\x72\x72\xd1\xb2\xdf\x11\xc3\x8b\xad\xef\x83\x86\x93\x26\x6e\xc0\x4e\x22\xc0\x28\x05\x61\x8c\xc9\xf7\x0c\x69\x87\x2e\xdc\x40\x87\x36\x60\x7d\x8f\x18\xbd\x67\xa8\x20\x3c\x9c\x45\x3d\x4b\xd5\xd1\x9c\x70\x92\xe3\x4e\x90\x43\x75\x8c\x69\x0d\x55\x5a\x19\x37\xa3\xf2\x74\x50\xd7\xb9\x16\x2c\x95\x14\xc5\x3a\x3a\xa0\x92\x2d\x5b\x03\x91\xaf\x99\xcd\x1d\x62\xcd\x47\x2b\xca\xc8\x7a\x44\xe9\x1e\x94\x22\x57\xca\x12\x0f\x55\x64\x34\x83\xac\x5c\xa5\x3c\x89\x28\x43\x99\x98\xdc\xca\x17\xb6\x3a\x8c\x8d\x83\x0c\x0f\xd7\x11\xa9\xc8\x1a\x46\xa7\x80\x26\xa3\x71\x18\xb7\x01\x95\x7b\x03\x54\xbd\x8b\xc9\x57\x0c\x13\x65\xcb\x5a\xea\xce\xc4\xb2\x2a\x63\xa9\x52\xb9\x96\x2a\x23\xeb\x0c\x53\x75\xed\xba\x64\x0f\x2d\xc1\xcb\x48\xa5\x84\x93\x65\xb1\xf6\x7d\x4f\x99\x70\x7a\x23\x90\x5e\xb6\x9b\xb2\x9b\xe7\xe1\x6a\xfa\x2b\xbb\x8d\xb3\x1f\x8b\x0c\x64\xaf\x3c\xff\x06\xbe\x92\xf5\x9a\x17\xaa\x42\x72\xe0\x39\x5f\xb3\x40\x96\xe1\x6b\x56\xd7\x55\x0f\x5b\xc0\x63\x0f\x37\x24\xc3\xc1\xb5\x6c\xb1\x35\x04\xb2\x7e\x9b\xbf\x31\x48\xfa\x50\x91\xac\x95\x8d\x3a\x06\x70\x6f\xd9\x51\x22\x3e\x92\x52\xb1\x74\x22\x34\x32\x1c\x30\x92\xd3\xd9\x42\xe7\x06\x2a\x54\xaa\xbb\x45\x3e\x1e\x63\x5e\xd7\xf3\x91\x1b\xa6\x1d\xd8\x81\x8c\xc5\x1c\xb6\xe3\x2d\xb8\x7f\x92\xa2\x93\xda\x17\x71\xb0\xf6\x2f\x54\xda\x11\x59\xc4\x59\xe4\x4e\xd9\x8e\x7d\x73\x81\x3b\x66\xc5\xd6\x8b\xd3\x35\xc6\x1a\x94\x4b\x41\x10\xe1\x23\x76\xa0\x93\x3b\xd3\x6e\xf0\x9e\x69\x28\xd9\xd0\xd4\xf8\x81\x8f\x50\xdf\x96\x54\x8d\xdd\x75\x03\x98\x77\x1f\x28\x57\x63\x95\xc0\x01\x31\xac\xd0\x20\x98\x55\xad\xb1\x8e\x5e\x8c\x72\x79\xeb\x6c\x14\x9b\xf8\x90\xe6\x61\x11\x11\x09\xa2\x85\xb1\x6b\x24\x6d\xb6\x0d\x94\xd1\xea\x54\xc2\x0d\xdf\x37\x72\xa5\x52\xb3\xdd\x95\x21\x99\xb4\x34\x57\x81\xae\x4b\x39\x29\x78\xc6\x64\x16\xee\x41\xe4\xef\xda\xc2\xd2\xb2\x73\x0b\xf3\x21\x20\x18\x32\x56\xb2\xe5\xbc\xae\x61\x18\x04\xec\xf2\xdc\x01\xe6\xfd\x81\x7d\xc7\x10\x8c\x2c\x86\x50\xde\xa0\xd8\x02\x6a\xb3\xb6\xcb\x3b\xbb\xd0\x93\xe4\xc0\x85\xc5\x3f\x0f\x12\x33\x8c\x36\xbe\xdf\x45\x36\x90\x5d\xc9\x02\xde\x51\x32\x68\x47\x91\xd5\xd7\x2c\x01\x68\xb7\x5a\x0c\x4e\x99\x85\x6e\x30\xc2\xe0\x58\x07\x4a\xe7\xe1\x2f\xad\xd3\x37\x3c\x32\xe4\xad\x0d\x00\x60\x9e\xa4\x61\x11\x2d\x7b\x0c\x90\xe4\x40\x83\xae\xc6\x0f\x8c\xb4\x8c\xc6\x6f\xe1\x36\xa0\x39\xad\x86\x87\x3f\x38\x41\x00\x90\x7b\x6b\x98\xb1\x63\x56\x39\x81\x34\x3b\x43\x9b\xe1\xad\xe5\xc3\x1c\x77\xd0\x47\x0b\xe2\x81\xb4\xd0\xba\xcc\x80\x03\x6c\x3f\xee\x00\x5b\xaa\x9c\x26\xca\x7e\x5e\x1b\xdd\x43\xc2\x6c\x7c\xc4\x2f\xce\xb5\xee\xa3\xbf\x9f\x7a\xcf\x3e\xeb\x3f\xaa\x6b\x25\xe4\x73\xcd\x20\x3b\x1e\xb1\x47\x9a\xca\x86\x28\xa3\xc6\x81\x23\xde\xf7\xac\x77\x2a\xe9\x0c\xef\x7f\xef\xe2\xef\x76\x3e\x3b\x06\x95\xaa\x9f\xfb\x82\xfd\x4f\xdd\x31\xdc\x58\xb7\xa9\xf9\xc0\xb3\xcf\xfa\x8f\x0c\x5f\xd1\xf6\x6b\x21\xa6\x29\x2f\x59\x21\xbe\x00\x79\x32\x44\x51\x73\xc3\x18\xcb\x8e\x2a\x51\xf3\x7f\xdd\x4f\x68\xd9\x25\x01\xbd\x07\x47\x0d\x2b\xfb\xac\x86\xc4\x1b\x31\x78\x10\xff\xbf\xdf\x5c\x27\xf7\x8c\x6c\xfa\x28\x1a\xa9\x0d\x61\x0f\xaa\x5d\x4d\x0b\x95\x18\x2d\x14\x11\x06\x95\x73\x3f\x69\x0d\xea\x11\x43\x06\x59\x32\xe4\x39\xb7\x63\xb2\xdb\x3d\x8e\x0d\x90\x2b\xc7\x16\x55\x4b\x63\x7c\x9f\xe9\xc0\x37\x94\x8a\x25\x0b\xb4\xd0\x57\xf2\x39\x83\x4e\x6e\xc0\x66\x19\x66\x11\x06\x28\x09\xe7\x5f\xdc\xd5\xad\x82\x04\xce\x36\x4a\x87\xd8\xcd\x83\xd2\x09\x11\xc0\x54\x50\x09\xe7\x94\x60\xc3\xdc\x58\x63\xea\xc1\xd0\x2a\xcc\xf7\x47\xdf\x3a\x69\xc9\x46\x37\x2c\xb4\xc6\xdb\xec\x31\xe3\xed\x08\x1f\x18\xed\x9b\x66\x4b\xa0\x2e\x1e\x60\xe5\xec\x21\x02\x54\xcb\x7a\x30\x5c\x2b\xa5\x4f\x2f\x98\x50\x0b\xe6\xf4\x9b\xca\x4a\xe9\xcc\xb5\xf5\x15\x1a\xc2\x0c\x62\x53\x1b\x1c\xb4\x5e\xa7\x31\x90\xe6\xcf\xba\xc1\x62\x8d\xab\x76\x68\x03\x85\x3c\x0e\xe9\xed\xc2\xb8\x51\xe9\x9d\x88\xbd\x4a\x1e\x73\x31\x1b\x18\x19\xa4\x92\x51\x99\x3c\x74\x5f\x34\x4a\xd2\x59\x66\x1a\xc2\x3b\x11\xf1\xd5\xa8\xde\xe5\x81\xa7\xae\x3c\x83\xb6\xe4\x23\x7d\xe9\x11\x77\x6b\x05\x9e\xc2\x17\xe6\xe9\x0b\xd8\xcd\x1e\x6c\x6a\xcf\x4c\xc0\x8b\x2c\x0b\x3c\x67\x32\xba\xa2\xad\x58\x07\x25\x67\x11\x3d\x41\xd2\x69\x18\x91\x82\x42\x58\xa7\xd4\x26\xc8\x9b\xcc\x81\xaa\xe7\x17\x34\x05\x42\x2e\x68\x0e\x71\x45\x5a\xe7\x6f\xb5\x21\x24\x8b\x77\x85\x0a\x49\xf0\xc3\x38\x42\x02\x93\xca\xc6\xea\x14\x2a\xed\x40\x67\x6f\x0e\x86\x19\xff\xa6\xef\x2a\x6c\xdc\x83\x97\xa3\xfd\x3d\x56\x3e\xc2\x63\xe3\x22\xfc\xa6\x6b\x24\x69\x04\xb2\x9d\xf3\x8a\xe5\xb5\x52\x76\xe7\xa4\x18\x10\xd3\x7c\xcf\x38\x2b\x20\x5c\xd2\x25\x56\x1d\xbc\xcc\x77\xfb\x4a\xb0\xe4\x4a\x39\x77\xe2\x86\xfc\xc4\x4e\x65\xaf\x21\x39\xd5\xc6\x33\xa9\x8a\x56\x94\x87\x69\x64\x3c\x71\xc3\x34\x22\xed\x25\x15\x61\x1a\xb5\x45\x0b\x6a\xec\x97\x30\x11\xd8\x29\x26\x6b\x68\x73\xe8\x93\xd7\x9d\xa9\xe0\x4c\x9b\x85\xd5\x1e\x86\xd1\x3b\x81\xe6\xd8\x20\x17\x6e\x3a\xa3\xab\x54\x99\x75\xde\x00\x7f\xec\xfb\xc8\x83\x83\x55\x4c\xb9\x1c\xb8\x51\x67\x03\x43\x0a\xf1\xb3\xb9\x44\xc3\x75\x0d\x0c\x3b\x98\xa5\x3a\x2e\xaf\x18\x93\xd1\xc3\x74\x9f\xde\xb3\xec\x8b\xfc\x1e\x26\xab\x44\xd8\xf7\xbf\xd1\xc8\x26\xc6\xbe\xff\xda\x28\x63\x55\x6c\x91\x72\x0a\xe9\xfd\x20\xf6\xe2\x2e\xe5\x3f\xc1\x4d\x2e\x6f\xe2\x7b\x75\xd3\x3e\x77\x9e\x9a\xef\x68\x4c\x64\x4f\xef\x74\x49\xf5\xac\x70\xbf\x49\x89\xf3\x55\x8e\x9d\x00\x4b\xf1\x32\x1e\x7b\x5e\xe0\xe4\x6b\x7f\xd2\x11\x57\x1d\x3a\xf1\xa4\x94\x92\xb4\xcd\xb4\x67\x73\x66\x50\x81\x4f\x04\xe7\xd5\xb6\x65\xa6\x60\xd3\x34\x23\x97\xd2\x99\x56\x99\xaa\x3b\xc3\x87\x4a\x7b\x79\xae\xcb\xf2\x1d\xbb\x17\xd4\xdb\xeb\xbc\x8c\x41\x7c\x0d\xd1\x69\xd9\x22\x63\x1b\x11\x4c\xe6\xf2\xbf\xfd\xfd\x02\xc6\x1b\x7c\x3a\xdb\xdf\x2f\x76\x71\x71\x93\xf2\x89\xc8\xf7\x81\x7c\xb3\x8f\x93\x24\xe5\x37\xc1\x6c\x71\x9d\x17\x09\x2b\x82\x99\x47\xb2\x93\xd5\x9b\xf4\x9b\x0b\xed\x5f\x1a\x80\x4f\xeb\xe2\x3a\xbf\x9f\x94\xe9\x1f\xb2\x1e\x55\xcb\xe4\x3a\xbf\x5f\xe4\xb7\xac\xd8\x64\xf9\x5d\x50\x42\x90\x3c\xdd\x72\x10\x57\x22\x37\x8d\xb9\x3d\x70\xfb\xf9\xf7\x05\xf4\xef\xef\x12\x2f\x75\x38\xb4\xaa\xcb\xb0\x65\x5a\x2c\x44\x2f\x8f\x77\x5f\x86\x17\x9c\x7a\xf3\xbf\x6b\x63\x9c\x7c\x4f\x4a\x3a\x7f\x26\x09\x21\xc4\xd7\x97\x7d\xf9\x9a\x6d\x04\xb6\xc3\x2d\xd2\x9b\xad\xa0\xde\xa7\xb3\xbf\x7b\x24\xa7\xcf\x3f\xd5\x45\xe1\xb1\x3c\x3f\xd9\x27\xd0\xcb\xf6\x3b\x33\x3b\xd4\x33\xb3\xef\x91\xd4\x34\x95\x4d\x95\x76\x09\xe0\xea\xfc\x39\x96\x03\x72\xcf\xd1\x15\xd6\xd1\xfa\x1c\xe1\x97\x70\xe8\xbf\xca\x1d\x9c\x57\x3c\x41\x10\x65\xe9\x75\x96\xc7\x90\x2e\xa7\x39\xf2\xd9\x3e\x76\x26\x05\x97\x2b\x92\x9d\x78\xb1\xc8\xac\x03\xb7\x19\xca\x75\xbc\xfe\x70\x03\xad\x5d\x66\xe9\x9e\x7a\x3a\x71\x85\x5c\x4e\x09\x16\x5d\x47\xcd\xe1\x4f\x3c\xf2\x00\xa4\xad\x80\xb3\x39\x2c\x45\xb7\x1e\x30\x99\x1a\xfa\xb6\x8d\x62\xf3\x40\x0e\xd7\xf9\xfd\x15\x40\xd4\x5b\x96\xa5\x27\x02\xcc\x33\x84\x49\xd1\x90\x2e\x1e\x39\x51\x2e\xd7\xe5\x4c\x06\xd3\x13\xc5\xb8\x64\x05\x54\x83\xdf\x58\x10\x39\x51\xb6\x6c\x88\x82\x6c\xd5\xd7\x53\x3d\x4c\xdb\x2a\xdf\x15\x2f\xd3\x1d\xe3\x65\x9a\xf3\xf2\x48\x05\xac\xb4\x1f\x5d\x2d\x60\x0c\x12\xbe\xa3\xe5\xd3\xa2\x71\x22\x06\x5e\x15\x1e\x26\xfc\x14\x28\xb0\xff\x12\x71\x78\x10\xbb\x59\x7e\xa1\x72\xac\x52\x0f\x1e\xf2\xde\xc3\xcf\xe4\xc3\xde\x4e\xed\x1d\xad\x44\xf7\x96\xcb\x0d\x35\xb0\x69\x05\x26\x31\x7d\x7e\x01\xa0\xfe\x86\x0b\x54\xe8\x36\x8e\xf6\x0d\xc3\x98\xc4\x4d\x83\x71\x83\x14\x0e\xf8\x95\xd1\xd0\xfb\x89\x5d\x7f\x48\x85\x47\xbc\x6f\xf2\x3f\x3c\xe2\xed\x4a\x2f\x22\x7f\x0c\x4c\x20\xcc\x86\x1a\x04\xf9\xb1\x1b\x16\xe1\x67\xe6\xa4\xd6\x92\x13\x25\x49\x5b\x19\xb2\xa8\xae\x7f\x64\x21\xeb\xc4\x49\x64\x92\x1a\xff\xc1\x96\x2c\x80\x57\x43\xbc\x04\xe4\x16\x76\x83\x49\x8e\x59\xeb\xf9\xc2\xe9\xaf\xec\x38\x58\x9e\x0a\x53\xfe\x2b\x0b\x79\x34\x16\x18\x5a\xb0\x86\x6a\x0d\x50\x53\xa6\xa3\x4b\x82\xa7\x1d\xcf\x39\xab\x01\x22\xd0\x72\x34\x59\x87\x2c\x8e\xf0\x74\x8c\xcf\xc9\x97\xf2\xf5\x64\x72\x4e\x7e\x61\xf4\x60\x17\xda\x41\x52\xb7\x69\x99\x5e\xa7\x59\x2a\x1e\x02\x6f\x9b\x26\x09\xe3\x1e\x31\x88\x5d\x47\x2b\x68\xc8\x0f\x8c\x1e\x32\x26\x04\x2b\xae\xf6\xf1\x5a\x22\x6a\x6f\xe6\x91\x4d\xce\xc5\x4f\xb0\x32\x81\xf7\xf1\x6c\xe6\x39\x13\xf8\x0f\xd6\xcb\x33\x69\xec\xe4\x2d\xef\x56\x2c\x01\xab\xed\xe2\x7b\x34\x23\x45\xf8\x2c\x9a\x20\x5e\xd7\x33\x8c\xc7\xa8\x80\x30\x1f\x10\xd3\x23\x10\x2d\x46\xfc\xe7\x90\x93\x1e\xf5\x54\xc6\x5f\x88\xd7\x38\x0f\x66\x44\x45\x41\x9d\xa9\x24\x80\x94\xa2\x62\xe9\x29\x3a\xe3\x05\x06\x03\x79\x56\xb6\x3f\x03\x7e\x6a\x11\x5f\x7c\xbc\x88\xc7\xf4\x19\xf6\x14\x49\x30\x01\x2b\xaa\xb1\x8d\x79\xc2\xc7\x9c\x85\x31\xc4\x46\x4d\x31\x26\xc5\x12\xd9\xda\x4c\xe1\x49\x1b\x20\x45\x93\x33\xaf\xfb\x91\xa9\x7d\x74\xfc\x81\xee\xa2\x2a\x3f\xf6\x7e\x52\x59\x8c\xd5\x77\x10\x02\xfe\xf1\xba\xdb\xa7\x10\x0b\xd2\x2d\xfe\x48\xcd\x41\xf9\xd7\xca\x99\x35\x1b\x15\xbe\x3f\xbb\x00\x0f\xc1\x6a\x4c\x9d\xe5\x83\xcb\x35\x4b\x33\xc4\x42\x4f\x91\x3a\x6f\x2c\x8e\xa1\x5e\x58\xa8\x8f\x26\xf9\xa4\x9a\x94\x93\xe9\x27\x18\xcb\x55\x27\x55\xbb\xce\xff\xee\xc1\x0e\x30\x9b\x24\xa5\x68\xf4\x30\x3d\xa2\x08\x48\x72\x99\xd8\xf7\xbd\x96\xe7\xe8\x84\xaa\xb1\x1f\x78\x64\x34\x27\x05\x26\x39\x4d\x49\x4c\x35\xb3\x5b\x60\x52\xd2\xbf\xd6\x63\x09\x50\x2d\x6b\xda\xcb\x28\x1d\x2f\x62\xea\x49\x9e\xc6\x33\xc9\x0f\x87\xfb\xea\xfb\x69\x5d\x8f\x1e\xa6\x43\xb4\x00\x61\xe5\x1c\x0f\xd8\xbb\xae\x55\x75\x94\xd2\xb8\xae\x47\x0e\xd5\x97\x6c\xb1\x97\xf2\x2c\x3d\x11\x93\x47\x0d\x13\xb2\x0c\x48\xc4\x0a\xb6\x2e\x6f\xd9\x5a\x94\x08\xbb\xc1\x01\xff\xf2\x7c\xa1\x9c\x96\x4a\x65\x0d\x8e\xa1\x10\x31\x05\xfc\xcd\x3a\x7d\x92\x6b\x38\x36\x1b\xb4\xae\x51\x3a\xb4\xeb\x48\x4e\x0a\x12\xe3\xb1\xdc\xd9\xed\x72\x9b\xf0\x90\xca\x9f\xc7\x31\x1f\x64\x8e\xad\x1a\xa4\x00\x75\xca\x39\xda\x86\x75\x59\xaa\x00\x6b\x87\x5c\xe2\x26\xf1\x10\x1c\x8e\x63\xbb\x82\x70\x5c\x9f\xe4\x61\xed\x3d\x5d\xd8\x0a\x7a\x20\xc4\x0c\x5f\x7a\x73\x2f\xe0\x60\x4d\x69\x83\x07\x05\x87\x98\xa7\x3b\x30\x90\x7a\x23\x58\x01\x17\x60\x5d\xae\x4c\x92\xb2\x6a\xd7\xde\x6e\xd2\x2c\xfb\x4e\x77\x43\xde\x66\xec\xfe\xcb\x22\xbf\x33\xd7\x57\xdb\x22\xe5\x1f\xe0\xae\xc5\x9d\xa3\x19\xb9\x29\xd2\xe4\x45\xc1\x62\x73\x7d\x09\xb5\x76\xef\x5e\xf1\xa4\xfb\xe0\x4a\xc4\x85\xfd\xfa\xad\x6a\x44\x5f\x3a\x65\xdf\xe6\x77\xb6\xa0\x04\x9a\xaf\x6c\xa3\x79\xdb\x4f\xc5\x88\xc3\xc5\x7e\x1b\x2b\x8b\xa9\xbb\x34\xc9\xef\xe0\xea\x8f\x37\x90\xcc\x50\x5e\xe5\xf9\x4e\x99\x07\x6b\x92\x18\x1c\x1a\x02\x14\x74\xc0\xb2\x43\x99\x68\x3c\xef\xe9\x63\xfe\xdf\xde\xbd\xe6\x46\x9c\xa0\x51\xa4\x84\xc8\xb2\xa4\xa2\x5f\xda\xe3\x1f\x18\xf2\xab\x73\x68\xba\x41\x15\x9c\xb7\x7f\x66\x10\x92\x27\x56\xc0\x0b\x30\x00\x71\x9e\x9c\xdb\xd2\x09\x3f\xd1\x6e\x56\xdf\xf7\x6e\x98\xf0\x52\xb8\x6c\xd5\x0c\x29\x8d\xb5\x47\xa9\xda\x42\xcb\x34\xc8\x42\x11\x2d\x5a\x91\x18\x45\xb9\x75\xbb\xc6\xb0\x8d\x0c\x5d\xe3\x18\x72\xb3\xcc\x41\x21\x40\x75\x2c\xac\x54\x62\x1b\x8f\x03\x10\x49\x86\x0c\xc4\x84\xdc\xf7\xb9\xc2\xff\xe6\xcd\x88\xd2\xbc\xae\xe5\x98\xf8\x98\xa6\xb2\x9a\xa3\x28\x57\x65\x1b\xe5\x0a\x1f\xb3\xd6\x75\x0d\xc7\x70\x49\x3e\xc1\x44\xc2\xc6\xe5\x6c\x59\x6b\x89\x51\x90\x1c\x0d\xf5\x52\xbe\x65\x45\x2a\xb7\xa3\x9c\x88\xb2\x37\x11\x14\xf4\x2d\xb1\xf6\xae\x86\xc4\x1b\x75\x8d\xaa\x65\x26\x9f\xb4\xf6\xea\x84\x63\x98\x1c\xca\x21\x67\xc8\xfa\x28\xde\x71\x27\x0c\x98\x5e\x51\x43\xfa\xdb\x65\x75\xd7\x11\x3d\xbe\x90\xb8\xb3\x6a\xee\x62\xcd\x20\x61\x9d\xed\xbe\x8a\xfd\x68\x11\x3c\x84\x60\x2a\x76\x71\xa6\xe3\x42\x0a\x89\xcc\x7e\x60\x2a\x42\x2a\x64\x5e\x55\xd1\xa5\x78\x5d\xf3\x25\xca\x5d\xb4\x96\x62\x02\x61\xe9\x79\x5d\xa7\xe5\x6b\x89\x81\x18\xca\xf1\x32\xaf\xeb\x59\x90\xe2\x20\x75\x44\x71\xa1\xa7\x58\x54\x8f\x68\x7e\xa4\x93\xb0\xad\xc2\x07\x67\x2c\x55\x44\x8f\x30\x94\x4e\xdf\x6f\xd3\x08\xff\x4b\x4f\xd1\x71\xc8\x35\x13\x0f\x6e\x18\xb3\xc3\xab\x2f\xe4\x8a\xa7\xfc\xa6\x2d\x82\xb0\x3a\xaf\x2e\x81\xb6\x56\x72\xf5\x7e\x92\x57\xbf\x74\x02\x5b\xea\xe5\xb1\x65\x1a\xfc\x78\x5c\x6e\x45\x98\x73\x3a\x7a\x98\x76\xce\x40\x92\x92\xb5\x1c\xa6\x9c\x76\x7b\x3c\x26\x31\x45\xf9\x7f\x43\xb1\x53\x49\xa1\xf9\xf2\x9f\xba\x4f\x24\x96\x7c\x8b\x8d\x1d\x1c\x43\xd4\x4d\x54\x4e\xe8\x20\x0b\x52\x1d\x13\xf4\xca\x61\x41\xdc\xa5\x0e\xab\x08\x4f\x74\x2b\x86\x74\xa9\xf6\x81\x47\x21\x25\x08\xa0\x5a\x36\x56\x0e\x40\xc5\x93\x73\xd9\x55\x30\xd7\x57\x92\xb8\x2a\x02\xeb\x2c\x33\xac\x0a\x63\xf2\x0f\x86\x66\x44\x90\xd2\xa8\x07\x0d\x44\x38\x82\x08\xfa\x84\xa1\x96\x3d\x68\x4f\x9f\x64\x80\x9c\x69\x4e\xc3\x19\x85\xa2\x6c\x6d\x6d\x2d\xb4\x0c\x82\x84\x3c\xe5\x4d\x00\x0e\x0e\xed\x37\xc1\xac\x19\x80\x89\xc7\x2b\x69\xb0\x26\xea\x8e\xb9\xa5\x92\xf3\x78\x1e\x31\xa2\x1d\xcf\x23\x5a\xe0\xa3\x99\x4b\xa7\x1d\xe0\xe7\x9d\x2d\x92\x8e\xf3\x88\x1e\x94\x56\x75\x58\x71\x4c\x67\x2a\x59\xe2\x40\x2e\x45\xb6\x64\xc6\xe9\xf6\xcc\xc3\x81\x3c\xae\x89\x8b\x8f\x41\x19\xc4\xc3\x54\x32\xb8\x22\x92\xf5\xab\xa8\x80\x45\x28\x26\xcf\xe0\xd7\xc9\x84\xdf\x34\x2e\xb3\x9e\x9a\x60\x82\x6d\xe7\x24\x36\xa4\xff\x80\x9c\x17\x1d\x35\x6f\x1f\x11\x9e\x56\xe1\x1c\x8b\x81\x49\xac\x8e\x2d\xfd\x98\xeb\x6a\xd4\x2d\x1f\x6c\xf3\x3b\xc7\x17\xe9\x22\x1e\x8f\x71\x1e\x8a\x30\x8e\x22\x0b\x6b\x02\xce\x05\x92\x86\xd9\x34\x2c\x4d\x3f\xde\x31\x5f\xba\xd1\x07\x21\x89\xa4\x09\x83\xd8\x80\x11\xe6\x71\xcc\x62\x50\x3d\x20\x74\x35\x7d\x77\xc7\x18\xa7\x4c\xe0\x53\xbe\x04\x4c\x10\x89\x2d\x07\x1c\xb6\xe5\x3a\x2b\xc5\x4c\xc6\x76\xc6\xeb\x63\x5f\xe4\x7b\xca\x8d\xc5\x62\x99\xf2\x1b\x9a\x4a\xec\xaf\xae\xdb\xb8\x3f\xca\x66\x12\x22\x2d\x95\x54\x18\x0b\xf6\xb8\x10\x46\x8f\x7a\x47\x8d\x27\x86\x31\x70\x67\x3c\xa1\x85\xba\x84\xd0\x88\x79\x8f\xb0\xf2\x96\xb0\x36\x64\x5d\x15\xc7\x36\xf9\x8a\x0b\xdd\x6b\xaa\x64\xba\x6b\x41\x85\x69\x9c\xab\x42\x69\x69\x9d\xba\xfb\x8d\xed\x7e\xfb\xbe\x21\x45\x75\x9c\x72\x08\x4c\x7d\x1f\x6f\xcc\x9d\x80\x69\x52\x29\x56\x54\x67\x53\xce\x4b\x2a\xb1\x8d\x9a\xb3\xd0\x99\xcb\xc8\xa8\x53\xfb\x1f\x3e\x65\x64\x46\xe6\xc3\xef\xb4\x5d\x80\xaa\xd5\xa8\x63\xf3\x3b\x8a\xcc\xac\x4e\xda\xd9\xc7\x4f\xc5\xb8\xbd\xeb\xd6\x57\x0a\xb6\xd7\xaa\x38\xf7\x51\x6b\x28\xa7\x5c\x4c\x4d\xfd\x26\x87\xb9\xef\x73\xb9\xc3\x96\xdc\x46\x19\x39\x35\xa9\xf6\xbd\xca\x3d\xd3\x60\x38\x29\x38\x80\xe9\x9e\x22\x08\x72\x2b\xa1\x07\xeb\x16\xd6\xa3\xc7\x26\x6a\xb8\x09\x8b\x03\x2c\xab\xec\xa8\xa3\xbe\x37\x26\xf8\xf2\x71\xc8\xd4\x3a\x99\x08\x3e\xba\xb0\x22\x04\xfa\xdd\xb2\x5b\x34\x40\x96\x36\xa8\x29\x50\xcf\x89\x07\x71\x75\xd5\xe1\x6f\x04\x39\x28\x24\x42\xee\x7b\x11\x5e\x4d\x37\xf7\x30\x91\xb6\xf6\xa3\x27\x88\xe1\x60\xb0\xe3\x23\x07\x95\x3d\xd6\xef\x9f\x99\xca\x15\xb8\xc7\xfd\xbe\x03\xff\x7e\x17\x58\x04\xd2\x19\x00\xbc\x1b\x33\xd8\x6e\x40\xe8\x34\x6f\xf0\x2e\xdf\x77\xc0\x5b\x3f\x06\xa2\x77\xe8\x8f\xaf\xd7\x69\xb9\xc7\xe0\x41\xc7\x66\x6d\xa8\x53\xc6\x81\x05\x90\xc8\x41\x9e\x77\xe2\x53\x16\x68\xe5\x9d\xa4\x4a\xc7\xef\xa6\x9f\x4c\x14\x33\x91\x97\x88\x3d\x85\xcb\xef\xdf\xe0\xf3\x67\x8e\x17\xa1\x07\xdf\x7a\xb2\xa9\xcd\x3d\x3d\x3a\xa7\x12\xbb\x18\xf4\xa0\xb2\x46\x08\x41\xb8\x20\x85\x20\xa9\x20\xb9\x50\xe1\xb4\x54\xd0\xcc\xba\xdc\xe6\x77\xf5\x36\x4d\x18\x7e\x72\x4e\x62\x41\xcf\xdb\x10\xcb\x4f\x9c\x70\x59\xa5\x40\xf8\x00\xfe\x80\x60\xe7\xfd\x6a\xaa\x64\x75\xbe\x7f\x39\x2d\xd8\xef\x15\x2b\xc5\x0b\x73\x48\x7d\x5d\xc4\x3b\xb6\x3c\xf1\x1c\x95\x02\x07\x9d\x4c\x45\xa5\xee\x2f\x38\x32\xdc\xc6\x19\x56\xb7\x22\x5d\x7f\x40\xd8\x09\xbf\x54\x89\x96\x1d\x38\x99\xd3\xca\x98\xa3\x37\x98\x08\x41\x5b\x8f\xb4\xb6\x9a\x4c\x74\xe3\x5c\xcf\x48\x4a\x0f\x8a\x79\x0e\x98\x52\x85\x0a\x25\xca\x5b\x14\x17\x1f\x2f\x8a\x31\x7d\x36\x11\x38\x0d\x0d\x3d\x1e\x23\x4e\x39\x0b\x8b\x08\x47\x34\x0d\x1d\x69\x58\x44\xdd\xe4\xef\x28\x9d\xea\xf3\x2d\x4d\xb5\xa6\x4f\x12\xcf\xb6\x1f\x6b\x31\x64\x65\x89\x36\x62\x2a\x24\x79\x63\xff\x7f\xde\xbe\xff\xb9\x71\x1b\xd9\xf3\x5f\xb1\x70\x73\x2c\x60\x04\xcb\xf2\x24\x75\xf5\x8e\x1a\x3c\x56\x76\x32\xb3\xc9\x56\x26\x93\x8d\x9d\xec\x6c\x69\xb8\x29\x5a\x82\x6c\x26\x14\xa9\x05\x21\xd9\x5e\x53\xff\xfb\x15\xba\x01\x10\xa0\xe8\x49\xf6\xbd\xbb\xfb\x61\xc6\x22\x08\x82\x20\xbe\x34\x1a\x8d\xee\xcf\x47\xe1\x1e\x64\x99\xb3\xd9\xaa\xa9\x57\x85\x8e\x6e\x91\x97\x24\x37\xaa\xef\x9c\x17\xa2\x74\xeb\x71\xf3\xba\x70\x3e\x6a\xe8\x90\x69\x7d\x63\xb9\xe6\xd2\x9b\x1c\x55\x5f\x85\x8d\xa6\x0d\x0f\x1a\xa3\xb0\xcd\xb1\x31\x03\xca\x3a\x4c\x04\x48\xdf\x21\x1a\xf8\x0c\xa9\x4d\xc3\xb6\x77\xe0\x14\x30\x2b\x8e\x66\xfb\x1c\x1f\x47\x16\x6e\x6f\x71\xb9\xf0\x7e\x33\x42\xeb\xae\x33\x1d\xcb\x75\x68\xcf\xab\x50\x94\x9b\x0e\x9e\x56\x7e\x4d\x38\x97\x8c\xd7\xe2\xf2\x9c\xea\x8b\x3e\x11\x8c\x77\x58\xed\x0a\x9b\xa7\x1d\x7a\x17\xba\xf4\xa5\xca\x67\x6a\x5f\xd3\xba\x47\x06\x0f\xb8\x13\x69\xc3\x97\x15\xaf\xb9\xd9\x90\xd5\xaf\x2f\x93\xa4\xcc\x74\x4a\xcb\xae\x3b\xcd\x74\xc9\xe7\x39\xe3\xed\x10\xe8\xbc\xca\x19\x9f\x5c\xb2\x23\xaf\x44\xeb\xe1\xc6\x31\x0c\xbd\xe1\x3b\xb0\x56\x84\x6e\xe7\x66\xeb\xb2\xd3\x41\xda\x64\xce\x9f\xac\x03\xe2\x5b\x10\x20\xa9\xc9\x85\xbf\x4e\x94\x91\x23\xd7\x8c\xbb\x50\x3d\xbb\x2f\x2e\x65\x9b\x4a\x9f\xf8\x01\xd7\xbb\x54\x73\xdf\x98\xa9\x6f\x6e\xd7\x7c\xa9\xf6\x2d\xc9\xb1\x95\xd2\x65\xce\x2d\xa4\xa0\xb9\x1e\xa5\x0d\xb0\x2a\x18\x6d\x78\x65\x96\x55\x8c\x9a\xc1\x9f\xb3\xe8\x0b\xe0\xc4\xc2\xde\xc0\x0f\xf0\x6d\xef\x7b\xcb\x32\x35\xf0\x1a\x23\x15\x47\x82\xd3\x8c\xaa\x2d\xb3\x41\xf7\xa6\xa0\xab\x16\x61\xf8\xfb\x02\x7d\x69\x27\xf3\x85\x7e\x5d\x83\xbe\xed\xbb\x5e\x63\xd7\x5f\xf6\xfe\xc2\x19\xfd\xe3\x1d\xcb\x65\xce\x58\xda\x86\x94\xa0\x2e\xd9\x2d\xfb\x7c\x25\x2a\x58\x08\xb0\x16\x93\xcf\x60\x45\x40\x86\x1a\x6d\x9a\xe5\x86\x96\x42\x2f\x95\xf8\x48\x6b\x96\xf3\x46\x00\xa0\x68\xac\x81\x37\x68\xea\x69\x96\x97\x2e\x83\x68\x96\xa6\xa2\xb5\xa5\x44\x33\xd2\x48\x34\xdc\x73\x11\xd5\xf9\xd0\x9a\xa1\xc0\x7c\x81\xfb\x19\xb0\x60\x30\x5f\x87\x46\x14\xd6\x7d\x94\x36\xac\x2f\x43\xe5\xbc\x61\x58\xc9\xae\xa3\xf6\xa5\x75\xce\xb5\xf9\x55\x5a\x27\x5d\x6d\x5e\x5c\x1e\xe9\x6a\xb4\xf3\x99\x9f\x81\x70\x16\x12\x49\x15\x33\x17\x41\x38\x55\xbc\xe1\xee\x71\x2f\xa3\xb6\xb4\x86\xd0\x50\x06\x1b\x9f\x90\x6a\xa1\xc2\xb5\xde\xbe\x0e\x6e\x30\xc8\x2a\xf0\x09\x40\x29\x02\xde\x8f\xba\x67\x22\xdd\x16\x3b\xba\xe2\x2b\xcd\x2b\xc6\xb7\xd4\x55\x15\x54\xc7\x24\x09\x2f\xb1\x4a\x8d\xc9\x57\xf5\x8c\xc4\x36\x87\xbb\xb6\xc4\xc4\x36\xd5\xfc\x76\xd5\x71\x84\x7e\x96\xaa\xd8\xa6\x9a\xdf\x5e\x5e\xda\x34\xbc\xf2\x2b\xdd\x36\x04\xab\xdb\x73\x27\x33\x8a\xba\xdc\xa6\x15\x47\x82\x88\xf0\x93\x8f\x8c\xf1\xea\x78\x35\xf3\x4b\x6b\x1f\xcf\xb2\xd1\xfc\xc9\xad\x12\xe9\x13\x79\x49\xd2\xe5\xd8\x0c\xc6\x7d\x4a\x3f\xcd\x31\x46\xde\x89\x45\x49\x6b\xab\x53\xf1\xde\xe2\xc0\x61\x8e\xe6\x47\x6e\x8b\x1f\x48\x06\xc0\xba\xb0\x94\x0e\xb8\x3c\xa5\x52\x48\x8f\x65\xb5\x08\x10\xde\x41\x5a\xcb\xa1\x98\xae\x05\x8c\xba\x70\x95\xab\x73\x11\x5f\x02\x10\x50\x9c\xe4\x69\x54\x34\x7a\xcd\xda\x01\x16\x7f\xf6\x33\xbe\xfd\x7c\xe3\x8e\xef\x4a\x38\x4b\x75\x46\x34\x73\xc5\x77\x08\x2d\xb2\x36\x3b\xe3\x3b\x67\xfd\xe5\xb7\x91\xf1\xb8\x80\x2d\xf1\xc1\x43\x01\x92\xcd\x83\xd1\xa7\x08\x7e\x2e\xf8\x7f\xd7\xd8\x65\x5d\x67\x61\x36\x61\x62\xc6\xfc\x31\x40\x80\xc3\x66\xfb\x1a\x52\xd7\x49\x42\x0b\x7f\x21\xe6\xbc\x35\x33\xd4\xd3\xba\xf0\xf0\x22\x5c\x62\xfb\x67\xba\xae\xa5\x0c\x88\x67\x5d\xca\x74\xca\x77\x23\x4b\xf6\x58\x5a\xff\xd0\xf9\x39\xef\xf9\x70\xa0\x8e\xb6\xcb\xba\xae\x88\x79\x66\x2c\x77\xa2\x13\x66\x39\x6f\x3c\xa6\x1c\x2c\xfd\xce\xb7\x08\x6e\x99\x3d\x30\x41\xe5\x13\x6c\x73\xbc\x14\x42\xd0\xdb\x8c\x18\x25\x94\xa4\x04\x1b\x10\x9e\xc3\xdf\x13\x61\xb6\xe3\x93\x43\x00\xb3\x70\x30\x12\x6d\xd5\xd4\xba\xac\xf7\x72\x71\x2b\x26\xf3\xe3\xda\xc8\xa2\x43\x92\x98\x5b\x66\xf3\xee\x8c\x0b\x8a\x1d\xcb\x0d\xa5\x7b\x31\xc2\xa9\xc6\x60\x37\x12\xa7\xae\x59\xef\xbb\xbf\x19\x32\xa1\x25\x09\xad\x67\xce\xa5\x48\x2c\xef\xfc\x6f\xde\xff\xfc\x18\xfc\xfe\x7b\xce\x6d\xaf\x57\x50\x37\x07\x89\x0f\xac\x01\xfd\xa8\xe9\x8d\xab\x3d\x5e\x3f\x5d\x8d\xf0\x5d\xc0\x73\xd9\x4a\x54\x29\xad\x10\xbb\x1a\x08\x30\x87\xd4\x19\x5d\x57\xf1\xb1\xc7\x39\x3e\xc4\x18\xe3\x34\x38\xc3\x5b\x75\x9d\xbd\x3a\xc7\x03\x77\x93\x86\x7b\xb2\x89\xa8\x46\x19\x38\x36\x55\x53\x00\x0c\x09\x9c\x85\xec\x50\x24\x06\xa3\xe8\xae\x07\xff\x3f\x32\xdb\x06\x15\xd0\x49\xf8\x3b\xbc\x12\xbe\xdc\x55\x46\x48\xba\x62\x8c\xf7\xcf\xc5\x35\x32\x02\xdd\xb7\x6a\x92\xd0\xbe\x89\x85\xf7\x1a\x18\x1b\xcd\x41\xbe\xfe\x79\x08\xce\xeb\xfb\x2b\xbc\x73\x19\xde\xf9\x7b\x78\xe7\x55\x7e\x04\xfe\x85\xc9\x25\x5f\x33\xf3\xd1\x87\xcc\xbd\xb9\xac\xcf\x0e\x49\x42\x6f\xc5\xc1\xee\x8a\x58\x7a\x08\xf9\xa9\x9c\x54\xe0\x4f\xce\xb1\xc1\x34\x4a\x93\x24\xd4\x3d\x20\x26\xb7\x8c\xdf\x26\x49\xd0\xa9\xa7\x6d\xea\x87\xe5\x6d\xd7\xd9\x8e\xe4\x21\x80\x9b\x93\x3d\x7c\x1d\xd0\x82\x28\x6e\x26\x06\xc3\xba\xaf\x34\xbd\xcd\xcc\x04\x49\xe7\x5c\xf1\x1d\xe3\x50\xdc\xc1\x7c\x8c\x99\x3d\x7b\x6b\x41\xb9\x85\xf0\x35\x59\xaf\x7d\x8a\xfd\x2b\xe6\x8c\x1d\xf3\x5e\xca\x0e\xd9\xb4\xb2\x78\xe7\xe0\x24\xb3\x64\x69\x7c\x03\x54\x3e\x69\x5d\x89\xdb\x9d\x94\xeb\x71\xff\x54\x21\x93\xe4\x34\x8e\x39\x8b\xb5\xe8\xf4\xc9\xad\xbb\x69\xdd\x75\x93\x3a\x49\x74\xd7\x6d\xc1\x57\x5c\xf6\x7a\xae\x74\x9a\x34\xde\xd7\x49\x32\xd9\x82\x5b\xa7\x0e\x28\xcb\x37\x0f\xb3\x66\xb3\xc9\x94\xd7\x89\xc5\x3c\xed\x4f\xc9\xec\xfb\xfb\xbb\xc0\x78\xe2\x2e\x4c\x4b\xe2\xbe\xdb\x7c\x4f\x1b\x16\x12\x24\x2f\xfb\xe4\x3c\x1d\xcf\xe2\x55\x7c\x77\x62\xa7\x50\x08\x27\x09\xa0\x78\x29\xbf\x9e\xd8\x5f\xc0\x7c\xc5\xb8\x9a\x35\xd5\x5a\x28\xaf\x84\xf0\xfe\x67\xb8\x4a\x6c\x29\x64\x64\x49\x02\x7f\x7b\x43\x98\x29\xc1\xbe\x67\xc0\x31\x65\xd3\xd9\x91\xab\x63\x6c\x6d\xde\x14\x6b\x79\xdd\x3c\x1f\x54\x0f\x5a\x86\x75\xbc\x2f\x24\x03\xe1\xe1\x0f\xbe\xf9\xdc\x71\x69\x98\xa1\x66\xb6\x94\xa0\xcd\x48\xea\xcf\xd1\xf5\x11\x11\x72\xd9\x91\xdb\x7b\x27\xe0\xb9\xf6\x90\x4f\x9c\xca\x76\xe0\x69\x83\x16\xb5\xe7\x88\x21\x1d\xba\x33\xae\x6e\x2c\x0e\x61\x38\xa2\xcc\xa3\x6c\x61\x76\x7e\x21\x50\xe1\xa6\xac\xcb\xf6\x8e\xa0\x63\x83\xd1\x34\xe9\x64\xce\xfc\xd0\x29\x66\x78\x5f\x14\xdc\x2c\x55\x48\x78\x08\xad\x16\xf0\x06\x16\xd6\xa8\x89\x4d\x6b\xef\xf3\x82\x0d\xf7\x3d\x25\x97\xbd\x7b\xd1\x98\x67\xb8\xc9\xee\xfc\x75\xf1\x8a\x6b\xda\xf8\xda\x9c\xa0\x82\x97\x10\x00\x6d\x14\x33\xb3\xd8\x7a\xbe\x2d\x6b\x17\xc5\xea\x94\x3d\x33\xd8\x78\xe8\x3e\x36\xd8\x64\x6e\x43\x4c\x26\x70\x52\x1c\x11\x72\x71\x33\x8c\x41\x99\x6d\x23\x58\x6b\x1b\x1a\xa8\x80\xc5\xd1\xfc\x0f\x55\x4e\x92\x82\x2a\x88\x92\xf1\x40\x96\x70\x34\xaa\x46\x32\xea\xde\x0b\xdb\x3d\x84\x76\x9a\xda\x83\x3b\x9e\x9f\x2f\x58\x6d\x1e\x31\x7a\xeb\xc4\xe1\x50\xf8\x9a\xc2\x2d\xa8\x2b\x6a\x13\x14\x12\xcc\xa8\xc2\xce\x6c\x18\x97\x46\xb4\xd7\x0e\x06\x54\xf3\x4b\xc6\x16\x13\x99\x24\x8d\xd1\x26\xa2\x09\x51\x32\xc4\x3c\x33\x3d\xde\x77\x5b\xd1\xe3\xc6\x4f\xd0\x69\x12\x02\x1f\x71\x76\x3e\xdf\xa4\x5c\x87\x4d\xc5\x6b\xa1\x97\x85\x63\xca\xcb\xb9\x0a\x2e\xb1\x95\x73\x08\x57\xb4\xcd\xdc\x88\x3a\xab\xfb\x0d\x31\x34\x8a\x1b\x8a\x93\x39\x8f\x88\xeb\x0a\xe8\x5b\x65\x26\x3e\x36\x2b\xfe\x0d\x62\xc6\x27\xc0\xc2\xe6\xcd\x49\xd2\xb4\x69\xb9\x94\xd8\xa6\x36\x5a\x2c\x49\x20\x05\x25\x0f\x7e\x26\x24\xf4\x4d\x69\x4a\x29\x5d\x33\x4a\x68\x46\x53\x2f\x29\xe6\x0b\xf9\xba\x59\x48\x38\x06\x93\xb9\xe9\x13\x99\xdb\xca\x46\x17\x81\x4c\xf2\x5e\xe9\xf6\xd6\x91\x45\x67\xde\x56\x8b\xe4\xa8\x27\x72\xd4\x20\xa3\x93\xef\x40\x40\x6c\xea\xa5\xca\x17\xf6\xef\x73\x94\xe0\xd6\x0e\xdd\x75\x63\xcc\x41\xe5\xb8\xeb\x3c\xce\x6a\x27\xbd\x2a\x4d\x15\xb6\x24\x32\xb3\x06\x67\x92\x6d\x55\xae\xe5\xd7\xcd\x7d\x9d\x56\xda\xea\xb6\x8c\x43\xe2\x4f\x3b\x48\x82\xfa\xdb\xa4\x6b\xe4\x34\x32\xc9\xf6\x33\x19\x37\xf2\xf6\xdb\xba\x77\x34\xc2\x32\x8e\x90\xfe\x61\xaf\x83\x1b\x50\x12\xde\xb0\x05\xf5\xf7\x6c\x71\xc7\xe3\xa0\xa1\x4e\xa3\x6a\xa2\xa6\x89\xbe\x52\x45\x9f\x87\xa3\x51\x2c\xf3\xde\x74\x7b\x22\x6b\x39\xda\x71\x5c\x66\x1c\xab\xa1\x89\x76\xa1\x5f\xd7\x21\x56\x2b\x95\x02\xc2\x37\xa8\x8d\xe3\x98\x40\xbf\xf4\x13\xf4\xfc\x9c\x5f\xb2\x45\xed\xf7\x24\xd6\xe8\xdd\xec\x28\xd8\x7e\xad\x1d\x38\xd8\x62\x8b\xf8\x04\x03\xeb\xe1\x74\x11\x67\x33\x2f\x14\xe0\x75\x45\x16\x69\x71\xf9\x45\x70\x3b\xfc\xb2\x1a\x60\x50\xb4\x99\x6b\xad\xa6\xcc\x3d\x08\x06\x89\x28\x1b\x7a\xd7\xf3\x60\x99\x17\x4f\x6d\xd5\xdc\xa7\xff\x6b\x3e\xe7\x9b\xa2\xd5\xe9\xab\xf9\xbc\x37\xf0\x7f\x39\x9f\xdb\xa5\x76\x2d\x8d\x32\xec\xcb\x52\xbc\x3f\x43\x50\xa0\x35\x00\xc2\x7b\xaf\x5e\xe4\x5d\xa7\x7a\x2a\x45\x1e\x48\x78\xc9\xc7\x0c\x01\x91\x25\xdd\x0c\x83\x85\x3e\xa9\xfe\x1b\x74\xf8\x71\xb9\x6a\x0c\xfc\x54\x23\x8e\xdf\x16\x9d\x90\x97\x23\xf7\x10\xac\x86\xfc\x0e\x2d\x15\x9e\xd2\x41\xd4\x3f\x22\x20\x0a\xe2\x38\xb4\x88\x63\x87\xfa\x50\x0b\x70\x38\x52\x1a\xc9\x01\x90\x17\x07\xa1\xed\xe5\x5a\x94\xda\x02\xe3\xc8\x35\xa7\x9f\xa9\x25\xc3\xa7\x05\xd1\xa4\x7f\x19\x92\x5b\xf1\xc7\x19\xfc\xf8\xd9\x65\x10\xfd\xdb\xe0\x40\x65\xa7\xf9\x5a\x0b\x8b\xa8\x5e\x68\xad\xbe\x81\x80\xed\x45\xa4\x1e\x99\xf4\xcf\x9e\xc6\x5f\xc1\xa3\xcf\x1e\x77\xf3\x1e\x95\xe5\xdf\xe0\x07\xed\x1f\x7a\x8e\x9e\xf7\xa4\x5e\xb1\x27\x40\xbf\xdd\x35\x0b\xf7\x17\x13\xe0\xe4\xf8\x0f\xfc\xf3\xca\xfc\x61\x27\x38\xfe\x22\xe2\x79\xf2\x70\x14\xd9\x15\x98\x44\xdd\x11\x3f\xb5\xfc\x1e\x11\x02\x42\xd7\x51\x23\x9d\xa1\x0d\xf1\xd8\x79\x10\xc5\x09\x27\xe6\x01\x72\xbd\x11\xcc\x4e\x1f\xc8\x76\x8e\x12\x99\xc5\x64\xf4\x20\xc6\x45\x9d\x41\x5a\xd4\x26\x40\x64\x5f\xf6\x9e\x67\x65\xe8\x82\xa7\x44\xe9\x3d\xcf\x34\x63\x99\x4a\xe9\x80\xbf\x4c\xf3\x7a\x4a\x08\x33\x9f\x53\xf6\x1e\x61\xa5\xdb\x2d\x63\x11\x8e\xbf\xd8\x14\x60\xf7\xff\x30\x59\xcb\x7a\x0d\x1f\x6a\x6f\x5a\x0e\x79\xd0\x6f\xdd\xe7\xa7\x08\xf8\xff\x34\xf4\x7b\x42\x87\xdf\x70\x58\x26\x89\x1d\xac\x48\x39\x0b\xae\xbb\x6e\x64\xdb\xc9\x2d\xed\x88\xed\xb9\x37\x46\xf8\xdc\x2c\xcd\xb2\xcd\x2b\x6a\x44\xda\x7a\x66\xf0\x0d\x4f\xce\x20\x06\xd1\xdb\xf8\xca\x0d\x2d\x4f\xc8\xe3\x6d\x4c\x81\x28\x97\x6a\x3a\xcd\xd9\x29\xd6\x10\xae\x22\xbb\x93\x63\xd8\x70\xf5\x01\x95\x5a\x67\x83\x9e\xac\x59\x3a\xf8\xa6\x1a\xad\x94\x1e\x45\xf0\x74\xe4\x20\x99\xab\xad\xf3\xc5\xa7\xfb\xe9\xc5\x2d\x1b\x91\x8c\x85\x58\x6b\xeb\x04\xe8\xbb\x6d\x01\x49\x9f\x09\xa5\x1c\x0c\x5d\xef\xce\x03\x63\x7c\xad\x97\x4d\xce\xe1\x7f\x24\xc8\x81\x01\x53\xd8\x52\xb2\x06\x46\x8a\xbd\x5f\x32\xae\x5c\x2c\xe9\x9d\x3d\xaf\x85\xbe\xed\x50\xb2\x75\x0e\x9b\xa3\xb3\x50\xd1\x2f\x2e\x4a\x7e\x6b\x33\x16\x9d\xb9\x63\x92\x02\xaa\xb6\x20\x9c\x8b\xca\x90\x61\x20\x67\x36\x22\xf3\x8c\x04\xa7\xa4\x8f\x3a\x02\xa8\x0a\x27\xb5\x75\x38\x09\x79\xff\xaa\xa2\x05\x0c\x77\x12\xb8\x55\x6f\xc3\x12\xe2\x03\x0d\xc9\x32\x99\x8e\x05\x7a\xc7\x15\x8b\x89\x22\x77\x11\x56\xf3\xa8\x30\xc5\xf3\xff\xcf\x0b\xd3\x18\xf2\xf9\x77\x84\x69\x10\x13\xb9\xc4\xe2\xdf\x95\x0f\x70\xa6\x25\xf3\xa1\x50\x3d\xa9\xdf\x7f\x4d\xa8\x9e\x3d\x23\x23\xcd\x62\xe3\x2a\x60\x86\xa5\x86\x6d\x40\xe0\xac\x93\x47\x02\xf0\x8f\x0b\x38\x09\x5e\xb4\x7f\x50\x98\x49\xc0\x94\xf6\x6f\x4d\x9f\x74\x71\x83\xce\xd9\xe3\x1e\x2c\x03\xa1\x47\x74\x71\x03\xce\xc1\x01\xbc\x41\xe6\xc3\xac\x34\xbf\x9c\xb3\xf4\x4e\x3b\x78\x48\x07\x65\xc3\xba\xee\xf6\x34\x11\xa0\xf6\x94\xdc\x64\xf3\xf4\xfc\xd2\xc8\x2b\xdb\x3a\xe9\x13\xd9\x34\x8a\xa4\xe4\x4e\x6f\xab\x77\x8d\x22\xdc\x8e\xcf\x14\xff\x9a\x87\x89\xe9\xba\x48\x69\x80\x45\x26\xf0\x0d\x71\xba\xc4\x33\x9f\x25\xc3\xd8\xfa\x30\x1c\x3b\x82\x98\x08\xf1\x25\x5c\x89\xd0\x5a\x1c\xb5\xc1\xa1\xd7\xc9\x48\xd9\x3a\x49\xa8\x1e\x3c\xfc\x47\xdf\x32\xd8\x2b\xd9\x9e\x22\x9c\x28\x59\xac\x3f\xd4\xd5\x23\xe1\x64\x5b\x3c\x7c\x07\x13\xc4\x34\x93\xac\x2a\x1b\x5e\x65\xaf\x7e\xb0\xce\x0d\x9c\xa8\xe6\xfe\x6a\x57\xd4\x26\xbd\xa9\xec\xaf\x7d\x2b\xdf\x17\x3b\xc2\xc9\x46\x15\x5b\xf9\x27\xeb\xb3\xea\xc2\x2d\xde\xae\x11\x2c\x3c\xdc\x8f\x19\xf5\xc4\x0f\x62\xc0\x67\x89\x56\x7a\xd8\x60\x0e\x3d\x1a\x8b\xf5\xfa\x8d\xe9\xb7\xc0\xf4\xe3\x76\x14\x71\xe0\x29\x9c\x07\x6f\x69\x0f\x01\x3d\x32\xa5\x8d\xe2\x6f\x79\x5b\x5d\xb9\x54\x47\xa8\x69\x8f\x76\x23\xce\x2c\x52\x1a\x95\x62\x0b\x47\x05\x4e\x90\xb8\xe5\x0c\x84\xc2\xde\x32\xe9\x95\xe2\x51\x63\x38\x21\x80\x20\x06\xe7\x05\xe4\x8c\x4c\x0f\x9a\x96\x6c\x6a\x04\xec\x53\x11\x90\xe2\xc9\x65\x61\x1e\x57\xbd\xbf\xfc\x19\x99\x36\x90\x0f\xd0\x19\xd4\x54\xe0\xd5\xa2\x34\x73\xb1\x15\x07\x4d\x15\xb2\x9e\xb7\x23\xf2\x97\xb7\x1e\xcc\x0b\x31\x43\x6c\xa4\xe2\xff\x8b\xc6\x0b\x8a\xfe\x9d\xf6\x9b\x9c\x48\xe2\x68\x3b\x69\xe4\x82\xab\x3f\x21\xff\x9f\x5a\x1c\x2f\xcf\x2f\x5f\x8f\x35\x3d\x53\x42\x79\xa4\x34\x9f\xcc\xff\x1b\xfd\x80\xfb\xed\x41\x3f\x94\x4e\xd1\xf0\x11\x1d\x25\x2f\x02\x5f\x62\xd1\x74\x5d\xbc\x6a\x96\x3e\x52\xe8\xc4\x34\xa1\x93\xa4\xc8\x34\x9a\x1a\xfd\xb8\x2e\xad\x61\x22\xec\xab\x92\xa5\x5b\x5a\xb2\xec\xf3\xbd\x1b\x54\x98\x96\xa3\xbd\x0b\x68\xe0\xec\xf8\x0c\x65\x72\x18\x49\x0c\x3e\x1a\x4f\x76\xef\xef\x0c\xcd\xa6\x83\x4b\x66\xbb\x45\x0a\x85\x54\x28\xf5\xec\xae\x68\xf1\xad\x92\x65\x75\x54\x71\xc9\xd2\xba\xff\x34\x69\xd9\x6f\xfc\xba\x56\x82\x3b\x3f\xb6\x0a\x86\xb3\x98\x61\xe4\xc7\x62\x92\x04\x74\x71\xe4\x97\x5f\xfc\x42\xf0\xcb\x2f\x84\x3b\xac\xd2\x36\xd2\x71\x4e\x92\x7c\xf7\x4a\x6b\xe0\x2d\x33\x42\xd2\xd0\x44\x1c\x97\x0b\xea\x10\x43\x58\x1d\xfb\x59\xcf\x10\x00\xce\x17\x5a\x98\x81\x26\xcd\x40\x5b\x44\xa3\x5d\xd9\xd1\x3e\x1c\xe3\xe7\x97\xaf\xa9\x1d\xe7\x30\x0d\x70\xac\xfb\xd1\xec\xa7\xf1\xc4\x45\x2a\x4c\x2e\x9d\x3a\xf9\xa0\xc5\xc5\x27\x75\x71\x1b\x6f\x55\x0f\x45\x00\xfc\xe3\x15\x17\xc9\x4b\xee\x41\x7e\xbc\xad\x7b\x30\xa1\x33\x5a\x8a\xad\x99\x8a\xe3\x83\x0a\x3d\x59\x4f\xf0\xa7\x92\xc4\x9d\x87\x6b\x51\x66\x75\x34\xca\xdc\x38\x3c\x14\x15\x65\x2c\xad\x59\xa6\x05\x21\xfe\x24\xa6\x1f\xf6\x99\x9e\x9a\x1b\x43\x87\x75\x00\xb7\x44\xb7\x0f\x3d\x06\x45\x66\x8d\x7c\xa6\xff\xe4\x94\x90\x23\x63\x1c\xf6\x67\x87\xa2\x0a\x3c\x9f\x2d\xb7\xd0\x30\x79\x1c\x60\x0f\xfc\x6b\xac\xc2\xa5\x02\x85\x4b\xf5\xe3\x4e\x73\x02\x3b\x2c\x08\x85\x82\xa2\x70\xc3\xa5\xcd\x20\x61\xa9\xce\x06\x75\x18\xab\xc0\xe7\xde\x7e\x7b\xfa\x76\x33\xb7\x1c\x4d\x84\x7d\xf7\x98\xea\x4d\xa5\xb0\xb6\x0d\x96\x49\x2f\xfb\x1e\xb4\x91\xc8\x69\xd8\x58\x8e\x64\x2f\x52\x7c\x5d\xed\xd2\x27\xb4\xdd\xfc\x41\x55\xd0\xd6\x27\x84\x1a\x98\x80\xbb\xf1\x41\x53\x0b\x10\x27\x21\xb6\x0b\x75\x9a\x67\x4a\xb5\xf8\x7d\x8e\x00\xb9\x05\x4d\x3b\x56\x97\x8c\x54\x85\x84\x73\x7b\xd8\x6c\x41\x74\x5b\x51\x80\x9d\x20\x05\xe2\x9e\x22\x6b\xa6\x97\xa9\xb7\x7d\x63\xc4\x43\xf3\x7a\x9e\xed\xd3\x22\x6b\xc0\x19\x74\xef\x7c\x99\x28\xee\x66\x3d\x2b\x8e\x51\x1f\x15\xb0\x18\x27\xc9\xa4\xf6\x2c\x3b\x49\x42\x27\x75\xa8\x9d\xb9\x1b\x5d\x37\xf9\x8a\x86\x77\x38\x71\x5c\xce\x84\x39\x68\xc1\x2b\x5a\xdb\x19\xc0\x7b\x27\xb7\x85\xb5\x57\x6a\xbf\xc4\xb4\xa7\x21\x52\x81\xbb\x59\xd4\x30\x66\x46\xfc\x26\xdd\x24\x09\x1d\x47\x51\xe6\x14\xe7\xe7\x8c\x82\xe7\x68\x11\x7c\x9a\x88\x28\x82\xfb\xc1\x68\x0b\x86\xe1\xa5\x18\x6f\xc0\x37\xa1\x16\x93\x79\xb4\xed\x1d\x74\x86\x38\xbf\x64\xbc\x39\x1e\x23\xcd\xd4\x9a\xdc\x7a\x3b\xdf\x40\x63\x8c\xe6\x5f\x7e\x6a\x25\x80\x06\x3b\x09\x5a\xf1\x7b\x57\x07\x73\x19\x7f\x07\x95\xae\x75\xb5\x19\x64\xde\xb2\x08\x1b\x81\xf8\x8d\x80\x9b\xf3\xac\x18\x39\xc1\x6b\xb6\x03\x3b\x23\x4d\x4d\x52\x6b\x55\x39\x32\xd8\x70\x58\xb0\x7a\x41\x9a\xda\xe1\xd6\x97\xf5\xd9\x1b\x90\xcb\x37\x76\xf7\x6e\x6f\xc0\x9f\xce\xc1\xd9\xdf\x54\x7b\xc5\x5e\x5c\xf0\xfb\xb8\x22\x63\x74\x0f\x0b\x3f\x33\x2d\xd6\x24\x7f\x3a\x25\xb8\x19\x89\x90\xec\xf9\x0b\xc5\xb2\xee\xba\xb7\x39\x5f\x8b\x83\x63\xa8\xb3\x70\xd0\x16\x3f\x3a\x95\xfc\x2e\xb8\xe7\xc1\xc9\x21\x43\x4f\x1b\xd6\x13\x0f\xa6\x4b\x20\x5a\x6b\xc4\x46\x14\x02\x00\x9c\xde\x72\xb3\x05\xae\x07\x71\xb9\xe1\xf5\xe4\xc6\xee\xf9\xd6\xd3\x13\x66\x50\x33\xd4\xce\x2f\x5f\xaf\x7b\xf5\x6d\x06\xbe\x28\x6b\x41\xef\xc4\x3a\x78\x31\x9b\xa1\x07\x02\xe3\x77\x96\xfc\x90\xf1\xbd\x08\x9e\x4b\x51\xd7\x36\x7d\x35\x5d\x73\x2a\xc5\x67\x28\x8b\xd6\xfc\xd4\x17\x21\x49\x24\x63\x3d\x5b\xaf\x50\xd9\xab\xf4\x0b\x1e\xb4\x82\x08\x98\x34\xb9\x0c\x58\xd5\x44\x90\x29\xfb\x2f\x32\x28\xa2\xc9\xc8\x91\xf0\xd8\x23\x0f\xee\x68\x61\x10\x71\x1f\xb9\x5e\xcc\xf2\xec\xa1\x01\x97\x32\x4f\x23\x61\xc0\xc1\x97\xe4\x94\x60\xcf\x72\x42\x22\x5b\xa2\x6d\x7d\xcf\x84\x67\xaf\x7b\x70\x34\x2b\xba\x26\x2a\x49\x26\xab\x99\x63\x73\x4a\x92\xc9\x03\x00\xa6\x22\x30\xf4\x2a\xa2\x95\xec\xba\x35\x77\xfd\xdc\x4e\xd7\x66\x65\x6c\x44\x13\x48\x46\xb6\x68\x16\x83\x94\x9d\xe3\x0b\xe7\x85\x68\x16\x05\x04\x0c\xc7\x60\x69\x5d\xf7\x96\x25\x89\xcd\x57\x84\xd0\x69\x5d\x57\xd8\xa2\xfe\x56\xd6\xeb\xe6\xbe\xeb\xde\xb0\x63\x19\xd2\xe9\xed\x96\xa5\x65\xd1\x93\xcf\xd1\xf2\x6d\x44\xe3\x68\x09\x2e\x5f\x97\x59\x9b\xae\x3c\x37\xa6\xf9\x1e\xea\x29\x0e\x9b\xdf\xe5\x37\xc4\x62\x72\xc7\xe6\xd4\x38\x00\x74\xf0\x33\xa8\x6c\xd3\x36\x46\xdb\xa6\x95\xd8\x27\x49\xb3\xdc\xe7\xfd\x9d\x24\xf9\x19\x9d\x83\xfd\x08\x88\x1e\xf1\xbc\x43\x8e\xd9\x69\x48\x4b\xd3\x3b\x43\xe3\xd7\xac\x4d\x4f\xcb\x11\xae\x1b\xca\xba\x6e\xe5\xfd\x52\x2c\x61\x60\x9f\x60\x5f\xba\x9b\xed\xf0\xf0\x8d\x75\xdd\xe4\x67\x5a\xb3\xae\xdb\x27\xc9\x96\xd6\xcb\x35\x34\xa8\x19\x06\x49\x42\x69\x21\x6a\xfc\x0c\x6a\xfe\xc2\xa8\xec\xa9\x57\xfd\x1c\x17\x6b\xfe\x5c\x0f\x24\xc9\x66\x8c\x2e\xf6\x5e\x33\x6e\xde\x05\x44\xd2\xcf\x3f\x39\x46\x37\x85\x0f\x9f\xd6\xc1\xce\xa8\xc2\xd5\xb5\x00\xa4\x4e\xcf\x0c\xd8\x5a\xae\x9b\x71\xbb\x5f\xef\x94\x1b\x48\x11\x5e\xf3\x27\x2b\x43\x23\x6a\xa2\xf9\x91\x2d\x86\xfc\xd5\x0a\xb1\x22\x35\x3b\x41\xf3\x1d\x93\xe8\xbf\x77\x2e\x14\x97\x6d\x2a\xaa\x1d\xa6\xaa\x4d\xfc\xe6\x84\xa7\x3c\x76\x18\x36\x9b\x00\x00\x78\xf6\x0e\x53\xa7\x65\xd6\x80\x22\x1c\xae\x76\x18\x49\xf9\xef\x51\xb6\x04\x9e\x3d\xf1\xa1\xad\x95\x4f\xb6\xdd\xa8\xf2\xc2\x8e\xc7\x3c\xa3\xb8\x0e\x46\xc2\x4c\x8d\x31\xbe\x84\xbc\x47\xb1\x08\x81\xb4\x75\x74\x09\xae\x1a\xde\xab\x4f\xb1\x85\x36\xd3\xe5\x64\x24\xd6\xbc\x04\x07\x80\x30\x2f\xa7\x1a\x20\x4a\x2e\x01\x3b\x19\xe9\x5f\xff\xaf\xd5\xe3\xfc\x72\xa1\xb3\xe8\x6d\x9a\xa5\x74\x9c\x58\xad\xaf\x9c\x77\x1c\x54\x0c\xe2\xe4\x40\x0b\xb9\xd6\xe2\xcd\xac\x6a\x56\x18\x11\xf2\x46\x8b\x27\x20\x97\x0e\x02\xa9\xf8\x5b\xb3\x81\xcc\x2e\x16\x57\x33\xb0\xdc\x7e\x7c\xff\xdd\xa9\x93\x12\x58\x7e\x64\xd7\x9d\xb8\x22\x79\x10\x29\x33\xb2\x01\x89\x55\x0b\x98\x1e\x6f\x66\x5f\x7f\x78\xff\x83\x29\x50\x31\x2c\xf8\x9d\x6a\xb6\x57\xf0\x38\x28\x20\xf2\x41\x5f\x3c\x6c\x2b\xc2\x7a\x98\x55\x7f\xc8\xdf\x5b\x60\x27\x10\xe6\x6a\x4f\x7a\xdb\x3f\x3d\x5e\x17\xb7\x66\xbb\x44\x09\x14\xa9\xa4\x52\x8d\x0a\xfc\x98\xaf\x66\x90\x42\xc9\xb7\xf5\xa1\xa8\xca\xf5\xd9\xc7\xf7\xdf\xa5\x66\x2b\xce\xb8\xc6\xc8\xb9\x2b\xf3\xb5\xcb\x4f\xf9\x8b\x0b\xfe\x1b\xec\x9c\xb3\x4f\xf5\xc5\x2d\xff\xca\x6a\x6b\xed\xfe\x66\x5b\x6a\x7b\x0a\xd3\x95\xdb\xe2\x56\x76\x4a\xb6\x52\x77\x9b\xb2\x92\x70\x2c\xf3\xfd\x67\xcf\x6f\x7e\x93\x8f\xb7\xb2\x66\xe1\x59\xcd\xd7\x9a\xd6\x5c\xf6\xf4\xd2\xfa\x34\x28\x5b\x32\x66\x27\xd5\xf0\x54\x5f\x75\xdd\x95\x5d\x50\x6b\x96\x95\xb0\x2e\xa7\xa6\xc4\x29\x59\x92\xe9\x29\x2b\x8c\x76\xc6\x7e\x6d\x36\x86\x46\xbb\xc8\x09\xd7\x88\x71\x63\x5d\xb3\xca\x0d\x55\x5d\xe7\x9e\x9c\x08\x71\x6f\xde\x6f\x8a\x96\x43\xe7\x2d\xc9\xfc\xab\x34\x94\x24\x97\x3a\x77\x80\x39\xbb\x42\x15\x5b\x31\x7e\x96\xb8\xcc\x79\x39\x76\x4b\x6c\xa9\x66\x99\xa6\x2c\xd5\x0b\xb5\x74\x58\xae\xb9\x90\xf5\xaa\x59\xcb\x9f\x7e\xfc\xf6\x4d\xb3\xdd\x35\x35\x32\x4a\x4e\x89\x20\xd3\x91\x3b\xa8\xf7\xd4\x66\x0b\x5b\xb3\x23\x88\x30\xdc\xd4\xba\x83\x6c\x32\xd6\xc2\x66\x6e\xff\xfa\xcf\xbd\x54\x8f\x49\x02\x5e\xe2\x3f\x54\x45\x59\x5b\xff\xc2\xd1\x0e\x60\x4f\x25\x6e\xec\x8d\x62\xc7\xfb\x2d\xbe\x6f\xc9\x20\xf0\x07\x3b\x19\x22\x6a\x78\xd9\x83\x92\x59\x95\x2f\x21\x6c\xe0\x6a\xd9\x4a\x55\x16\xd5\x38\xc0\x9f\x6d\x5a\x6a\x6d\x56\x36\x23\x7e\x07\x03\x0c\x8d\x30\x69\xa4\x00\x3d\x82\x13\x8d\x12\xc9\x1e\xe0\xa3\x81\x4b\xda\x69\x45\x82\x28\xaa\x50\x8f\x94\x68\x0f\x3c\x32\xe7\xf3\x39\x2e\xe0\xcc\xc8\x8b\x22\xca\x4d\x73\x99\x36\xb6\x66\x9f\xb2\xa5\x24\x75\x7b\x65\xa3\xd7\x7f\xef\xfc\xff\x42\xfb\x8b\xd1\x28\xbe\xd2\x3d\x2e\x34\xde\x5d\x39\x1a\x86\xc9\xce\x63\x46\xb3\x23\x8b\x3f\x2e\x8c\x64\x0b\x4d\x4d\x31\xec\x21\x7a\x11\x0c\x8c\x4b\x35\xcb\xd0\xb0\x54\x8f\x18\x96\x9e\xcc\x87\xa4\x1a\xbb\xdf\x12\xa4\x7a\x73\xca\x6f\x9a\x93\x4f\xea\x53\x4d\xcc\xea\x98\x8e\x64\xad\xc7\xb3\x22\xe4\xb0\x93\xcf\xbf\x6a\x71\xf1\x3f\x5f\xcd\x2f\x6e\xf9\x3f\xb5\xb8\xf8\x1f\xb3\x97\x2f\x2e\xf8\x77\x5a\x5c\xd0\x65\x96\xe4\xec\x17\xb1\xfc\x47\x92\xbf\xbc\xe0\xdf\x80\xcc\x99\xbd\xcc\x58\xba\x3c\xfb\xa4\xf3\x97\x74\xf9\x0f\x53\x62\xfe\x92\xbd\xb8\xb8\xdd\xf2\x0f\x56\x26\xfd\xf9\xed\x75\xf7\xcd\xdb\xaf\xbe\x36\x7b\xcb\x1f\x4c\xda\xa7\x8b\x4f\x17\x17\xfc\x47\x2d\x9e\x8e\xfc\x3d\xfc\xff\xad\x16\xe4\xe5\x05\x71\x41\xa8\xe4\x25\x61\xfc\x6f\x23\x4e\x35\x45\x88\xe5\xfb\x4e\xd3\xc6\x8f\xae\xb8\xdd\x4f\x97\x04\x30\xd7\x49\x2e\x85\x29\x7b\x11\xc7\x08\x45\x66\xae\xe8\x74\xd8\x1f\x58\x0c\xfc\x0b\xc8\x14\xd0\x74\x96\xf3\x3c\xa3\xb5\xa8\x3d\xdc\x4a\xd7\x91\x97\x84\xd3\xc6\x45\xb2\xe1\xd1\x77\x1f\x3c\xc4\xd2\xe1\x3d\x67\x69\xe9\xcf\xb4\xff\xa4\x81\x64\xa8\xe1\x05\x8e\x9f\xd6\x34\xd0\x5e\x68\x21\xc4\x7b\xdd\x7f\x7d\xe5\xd6\x41\x0f\xa4\xd9\x2e\x65\x8e\x0e\x99\x20\x33\xf4\xd2\x72\x9a\x8f\x6a\x5a\x14\xdf\xf0\x9c\x37\x6f\x0d\x58\x4d\xed\xb2\xce\xb3\x7d\x36\xa1\x4a\xd4\xcc\xda\xe5\x52\x5a\x02\x01\xb7\xd9\x89\xf4\xde\xf7\x35\xe3\x95\xf9\x6f\x72\xc9\x8e\x8c\x2b\xcf\x9c\x1c\x66\x5e\xce\x73\xa3\xb4\x63\x5c\x71\x92\x54\xd0\xcd\x01\xd4\xb0\x1e\xda\x95\xae\x66\xc5\xaf\xc5\xc3\x95\xd4\xba\xac\x6f\xdb\xd9\xa6\x2a\xb4\x8d\x37\xf5\x6c\xec\x35\x02\x4a\xf7\xd4\x7f\xcb\x3a\x37\xea\x7f\x69\x6a\x2e\x53\xd5\x75\x54\x89\xa7\x23\x63\xa6\xd5\x81\x64\xda\x4b\xc1\x80\x7b\x74\x32\x37\x4b\x21\xe3\xf2\xf8\x37\x0d\xe7\xbd\xe2\x1a\xff\x86\xfe\x4c\x2b\x5d\x1e\x64\x3a\xe7\x55\xd1\xea\xf7\xcd\xba\xdc\x94\x72\x0d\xc1\xb3\xba\x80\x20\xda\xb0\xae\xe9\xd3\x5e\x55\xa9\x2b\x04\x54\x71\xf2\xe7\xb7\xd7\x84\x97\xed\x77\xcd\xaa\xa8\x52\xf4\xa1\xb8\x69\xf6\xba\x2b\x76\x3b\xf3\xef\xbc\xd5\x8d\x32\x2b\xfb\x6c\x7a\x0e\xef\x6c\xcb\xa6\x86\x05\xde\xac\xf5\xdd\x7d\xb9\x06\xfa\xd4\x17\x17\x28\x71\xae\x6d\x3c\xfe\xaa\xa9\x18\x47\x9a\x20\x20\x72\x54\x8d\xd1\xcf\x80\x8b\x64\x32\xe7\x45\xfb\x58\xaf\x2c\xcb\xb2\x96\xb5\x06\x1e\x3e\x62\x76\x52\x25\x6a\x5f\x17\x0f\xe7\xf7\xf7\xf7\xe7\x9b\x46\x6d\xcf\xf7\xaa\xc2\x75\x6d\xbd\x38\x5b\xdd\x19\x55\x46\x8b\x9f\xae\xdf\x9d\xff\x07\xe1\x46\xeb\xdb\x69\x1b\xeb\xf7\xad\x46\x66\x0e\x54\x97\x76\x66\xc1\x22\x88\xea\x8f\x29\xe6\x27\xe1\x0f\xe6\x3a\x7a\xd3\xb6\xe2\x67\x5e\xc3\xe2\xbf\xb6\x00\xd1\x19\x64\x30\x29\x36\xc7\xaf\xc5\xa1\xb0\x0c\x2b\x47\x57\xf7\x36\x7d\x32\x65\x5e\x7c\xba\x79\xd8\x56\x9f\x6e\x2e\xf0\x95\x17\x9f\x6e\xcc\xdf\x0b\x2c\xef\xe2\xd3\x8d\xf9\xfb\xe9\xe6\xe2\xc8\x95\x6c\x77\x4d\xdd\xca\x77\xa5\xac\xd6\xf6\x61\xe2\x12\x3f\xbe\xff\x8e\xd8\xaf\x70\x49\xd7\xf2\x41\xbb\x6a\xb9\xb4\xbf\x5c\x7d\xf8\x1e\x6b\x70\x90\x4a\xdb\x68\x47\xa8\x22\x49\x51\x6d\x44\xa5\xf1\x0c\xbe\x19\x78\x3c\xe1\xd2\x94\x42\x52\xf3\x34\xaa\x99\x36\xd9\x7c\x78\xda\xab\xb4\x47\x1e\x0c\x69\x1c\x32\xae\xab\x1e\xb4\xd9\xad\xf9\x41\xb5\x7f\xc6\x2b\x45\x67\x2f\x34\x85\x89\x13\xcf\x15\xb3\x3f\x4e\x5f\x68\x1a\xa7\x02\xa9\x8a\x49\xe8\x79\x8b\xde\x69\xfa\xa3\x66\x90\x78\xad\x8a\xba\xdd\x35\x4a\x9b\xc4\xf7\x36\x71\xf0\xda\x31\xdb\x94\x95\xab\xce\xe3\x5f\x0b\x0d\xb3\xd3\x4c\x63\xb0\xf4\xf1\x9a\xaf\xb9\xe2\x77\xfc\x16\xa4\xda\xa1\x9f\xd6\xfb\x9d\x0d\x85\x78\x14\x87\x99\xfd\xec\xae\x3b\xf0\x6d\x7f\x99\x24\xc0\x7e\xe4\x60\x3d\x1e\xad\xb2\xc4\xb2\x2b\xfa\xc8\x52\x67\x7c\x7c\x88\x60\x03\xf8\x8d\xb8\x9a\xbd\x29\xaa\xea\xa6\x58\xfd\xd6\x52\xd2\xd4\x2b\x79\xb6\x95\xdb\x46\x3d\x12\xc6\xef\xc5\x61\xd6\xea\x42\xef\xdb\x37\x40\x70\x0f\x90\x44\x4f\x47\x6e\xc5\x2c\x41\xf2\x57\xb9\x26\xfc\x5a\x3c\x29\x59\xac\x1f\xaf\xb4\xd9\x7d\x03\xd9\xfa\x8f\x76\x5c\x7c\x23\x8b\xf5\x18\x99\x37\xf0\xb0\x39\xd8\xcc\xa7\x5a\x3c\x1d\xad\xd1\x47\x8b\x6f\x34\xc6\xb8\xee\x18\xab\x97\xfa\x84\x47\x02\x28\xef\x05\x7d\xf6\x56\x04\xd2\xa0\x97\xaf\x72\x76\xd4\xa2\x5e\xca\x91\xac\xc7\x48\xc3\xd0\xa8\x61\x68\xab\xf4\xf1\x33\xa3\xf5\xdd\x4a\xfd\x55\x55\xc5\x5f\x33\x86\x27\x7d\x97\xed\x52\xef\x46\xf2\x23\x42\x6d\x9c\x7c\x7b\x30\x1e\xf1\x95\xc8\xd6\xd6\x0e\x2b\x97\x8f\x24\x75\x9d\xe4\x85\x59\xb7\x2c\xf3\xf3\x91\x37\x07\xa9\x54\xb9\x96\xef\xcb\x2d\x32\x88\x3e\x6b\x14\xbf\x83\xd8\xb6\xad\xcd\x27\xa4\x2b\xa1\xef\xdd\xf1\x0e\x82\x80\xf8\x3b\x76\xed\x22\xf9\xe4\xf2\xda\x8e\x88\x93\x38\x11\xc9\xee\x97\x3a\x17\x4b\xf3\x3f\x6c\x33\xf2\x98\x31\xa5\xb8\x31\xf3\x65\xc4\xbd\xa6\xeb\xf6\x2e\xe7\x2a\x49\x56\x33\xc8\x08\x10\x8f\x74\xee\x58\xae\x8f\xb0\x4b\x78\xf0\x28\x0e\xd7\x8c\x1f\x66\x7b\x55\x09\x4a\x65\xd7\xc1\xcf\xae\xb3\x6b\x08\x9b\x12\xc2\xbc\xee\xf6\x83\xe6\x81\xfc\x9f\x92\x8b\x0b\x62\x9e\x05\xfb\x9a\x9e\x6d\xa5\xbe\x6b\xd6\x5d\xa7\x2d\x13\xdc\xc1\xa7\x60\x16\x7e\xe8\xd7\x64\x41\xfb\x0b\x50\x5e\xd8\xf3\xda\x10\x21\x2e\xd0\xf4\x30\x5b\xa9\xa6\x6d\xbf\x6e\xb6\x45\x59\xb3\x27\x35\xae\xa8\x99\x8d\xb7\xc2\xe5\x14\x3e\x86\xdb\x0b\xfc\xc3\xa3\x42\xc4\xdf\x06\xdf\x33\x35\x2b\x71\xd3\xea\x89\x50\x83\x1b\x0a\xd2\xfb\x0d\x7a\x5c\x8e\x91\x9a\xe5\xc6\x7e\x55\x92\x1c\x66\xc1\x8a\xd8\x73\x23\x7a\x3d\xc7\xe5\xb3\x0f\x08\xb7\xcb\xc1\x4b\xd3\xa6\xaa\x58\x03\xa8\x5f\x51\x31\xc6\xff\x64\xc4\x25\x3f\x70\xcd\xaf\x19\xf7\x5e\x26\xd7\x9e\xb0\x82\xde\x3a\xf3\xb6\x79\x35\x2e\xcb\x2c\x49\xe6\xc2\x08\x3d\x50\x20\xa6\x53\xd0\x3b\x22\x93\x16\x01\x79\xa8\x0b\xa5\xfb\x6e\xc4\x3f\x31\xae\x1f\x3f\x80\xf3\x82\xa5\xef\x99\x7c\xb0\x1b\x13\xcc\xca\xb8\x6d\x66\x3f\x4a\xfe\x09\x67\xab\xd1\x43\xd9\x33\xed\x02\x88\x98\x56\xe8\xa2\x96\x80\x04\x82\xfe\x08\xe3\x77\x55\x06\x38\x1a\xb1\x8d\x88\x7f\x7a\x26\x40\xcd\xc9\x94\x80\xee\x6b\x6b\x88\xea\xf2\xc6\xf9\xde\xf0\xa0\x17\x82\x6a\xf5\x96\x1d\x11\x77\x97\x79\xd5\x66\x2a\xe8\x5b\xdb\x00\x1b\x96\x91\x84\xa4\x24\x23\x6c\x6a\x3b\xce\x3a\x55\xda\xfc\x68\xa5\x3e\xcc\x56\xc5\xea\xce\xac\x58\x1b\xb1\xf1\xb5\xfb\x4e\x73\xf2\xe2\x92\x30\xde\x8c\x17\x48\x7e\x11\x64\xfa\x46\xcf\x6e\xf7\xe5\x7a\x3a\x9d\x36\x6e\x92\x6e\xf0\x67\xb9\x71\xba\x20\xc0\x48\x84\xca\xe1\x72\x93\x27\xc9\xf5\x6c\x28\x39\x29\xf9\x76\x73\xee\xf2\x9c\x5f\x95\xf5\x4a\x12\x7e\xf2\x24\x18\x8a\x75\x71\xfb\xb9\x42\xbe\x6f\x6a\x79\xfe\xde\xcc\x03\xd2\xe7\x66\x8c\x07\xa3\xbf\xef\x7a\x6b\x50\x1f\x74\xb2\x0e\x2f\xd9\xf8\x9b\x6c\x01\xe7\xd7\xe0\xc9\x1d\x15\xc0\xf8\xd8\x03\x5f\x81\xb6\x48\x42\x39\xb3\x9c\xe7\xa6\x3a\x56\x8f\x5c\xc6\x77\xf2\xec\xd9\x3b\x53\xb3\x49\x80\x6a\x87\xc9\x99\x59\xc6\xa6\xdf\xea\x29\x59\x9c\xfd\x53\xcc\x67\xf3\x4b\x92\x12\xc2\xd2\xbe\x18\x84\x2e\x3a\xcc\xee\x70\x69\x63\x23\xd5\x2c\xfb\xdb\xc0\x4c\x0c\x52\x03\x89\x83\xae\x64\xbd\x76\x20\x54\x61\x1a\x9e\x46\x3e\xf2\x6b\x7e\x60\x5d\x77\xe7\xcf\x7f\xaf\xad\x7c\x87\x42\xf6\x82\xc0\x15\xe1\x37\xc0\x18\x7b\xe8\x21\x3b\xf8\x35\xc6\x5b\x1f\x66\xed\x1e\xec\xa8\x26\x05\x60\x3c\x0e\x68\x23\x64\x7c\x25\xfe\x64\xb4\x2f\x2b\x63\x40\x95\xb8\x9e\xf5\x6a\x88\xb8\xe4\xb7\x49\xb2\x1d\x88\x0e\x60\x40\x5a\x5e\xf3\x43\x1e\x49\xa5\xc3\x0c\xf4\xff\x24\x99\xbf\x3e\x40\x24\x52\xb3\xd7\x70\x80\xf9\x1c\xb2\x95\xfb\x0e\x62\x33\x1b\x55\xc1\x3f\xc9\x50\xa2\xdf\x89\xc9\x25\x5f\xcd\x5a\xb3\x29\x2a\x78\x15\x58\x4a\x61\x55\xd5\x77\xaa\xb9\x3f\x93\x8b\x8a\x9e\x5f\x1a\x7d\x13\x7d\xa8\xe0\x8a\x7c\xdf\x9c\x79\x25\x33\xdc\xc8\x57\xcf\x9e\x15\x0b\xbd\xb8\xeb\x3a\x0a\x71\x86\xeb\x24\x19\xc4\x08\xad\x4d\x73\xd9\xd3\x93\x9d\x50\x46\x64\xf1\xa8\xb1\xe6\xaf\x65\xf6\x65\x6a\x36\xf9\xaf\xe6\xf3\xd7\x40\x5e\xf6\xfa\x8b\xf9\xbc\xeb\xbe\x98\x7f\x29\x84\x90\x10\x93\xd0\x3e\xef\x6b\x6f\xa9\x81\xdc\x06\x84\xef\x85\xec\xc7\xa1\xd5\xec\xc8\x4b\x22\x84\xd8\x9b\xcd\xed\xde\x1f\x04\x7b\x0c\x09\x05\x88\xaa\xd2\x6b\x29\x66\xc6\x9d\xe8\x91\x83\x29\xc6\x60\x18\xa9\x9e\xbb\xb8\x35\x0a\x8b\x19\xa4\x49\x02\xf4\xc4\x20\xa3\x14\x63\x4f\x7b\xbf\xff\x2e\xd9\xe2\x46\xc9\xe2\x37\xb3\xf6\x99\xba\x94\xf5\x59\xcd\x1a\xa8\x16\xa8\x34\x3d\x2b\x37\x62\xf0\x4e\xf6\xc8\x16\x3d\xeb\xb7\x36\xcb\xd2\x68\x8f\x00\x27\x9b\xb3\xa7\x46\x94\xb6\xc4\x02\x38\x8d\x4a\x76\x04\x50\x8d\xc2\xbc\xc1\xfb\x91\x37\x13\xfc\xf4\x24\xe9\xab\xd2\x30\x5e\x2f\x9b\xfc\x48\x0f\xfc\x1a\x40\x8b\x27\x25\xf8\x92\xf5\x7e\x11\x8e\x3c\x33\x14\x10\xb8\x7c\x04\xb5\xc1\x1d\x93\xcd\x99\x87\x91\x62\x47\xc6\x87\x7d\x36\x36\x74\x9e\x8e\xc0\xab\xda\xdb\x2a\x70\xd5\x81\xc6\x5d\x2d\x2f\x73\x24\x45\x05\x2d\x2f\x78\x2f\xab\x96\xc5\x50\x6d\x8d\x5a\xa9\xc8\x17\x8d\x58\xb9\x9e\x76\x5e\x9f\xa6\x87\xe0\xcc\x2e\xd8\x72\x2e\x2d\x73\xe6\x48\x3a\xe8\xbb\x93\x7d\x92\xa8\x24\xc1\x2a\xbe\x83\xfd\x18\xee\xa6\x82\x04\xaa\x79\xff\x09\xe0\x57\xd0\xf0\xe0\xf5\xe6\xb5\x38\x00\x1b\xd3\xdb\xde\x94\x8e\x42\x73\x9f\x24\x7b\xf0\xfa\x87\x1e\xa7\x85\xa8\x96\x7b\xe8\xe3\x26\xef\xba\x6a\x49\x5e\xc2\xcf\x80\x24\xbb\x02\xc7\xa3\x56\x94\x01\xb4\x2c\x5b\x5e\xe6\x18\x2d\x10\x14\x00\xb2\xd9\x97\x01\x57\x8c\x3d\x01\x8e\x74\x91\x99\x6c\x65\x9e\x02\x90\x40\x05\xa3\x96\x36\xc2\xe4\xe1\x2b\x3f\x48\x5a\xd3\x01\xc1\x98\x85\xcc\x85\x79\x7d\x91\x24\x72\x49\x40\x8c\xb4\x24\x67\x5a\x14\x54\x3b\x24\x28\x38\xc9\x31\xd7\xbd\xd0\xb1\x46\xd1\x16\xf6\x68\xd1\x01\x0c\x87\x3f\x69\x91\xc9\xd4\x48\x1e\xec\xc2\x16\x20\xe9\x54\xb3\x35\x23\x7d\x4a\xce\x74\x63\xda\xe0\x78\x3c\xc6\xe5\x58\xf1\x4c\xb8\x69\xfa\x54\x1f\xcd\x60\x6e\xf9\x35\x2f\x19\x2f\x33\x3a\x58\xf5\xe9\x5e\x5c\x8f\x4d\xea\xef\x8a\x56\xfb\x85\x1e\x61\x55\x4e\x96\x79\xb1\x67\xfc\xb9\xe7\xcd\x82\xee\x1e\xb3\x8b\xbb\xd8\x33\xc6\x5f\xa1\xf0\xea\x3a\xf2\xcd\xdb\xaf\xbe\x26\xb0\x46\x19\xfd\x28\x03\xac\x13\x47\x44\x90\x5a\x19\x87\xa9\x7a\xeb\xea\x91\xd2\x4a\x00\x12\x95\x96\xc0\x2a\x06\xea\x52\x29\xcc\xf0\x68\xed\x22\x64\x54\xb5\x42\x54\x7c\x22\x93\xa4\xea\x3a\x5a\x09\xe2\x9a\x14\x7c\xc6\xa5\x98\x33\x06\x4b\x3f\xec\x9a\x84\xf4\x3f\x81\x6a\x87\xea\xae\xab\xcc\x86\x85\x97\xd9\x43\x04\x73\xf6\xc8\x97\x0d\xaf\xf8\x75\xce\xd2\x87\x10\xe7\xec\xd1\x2c\x5e\x15\x2f\xf2\xbe\x50\xb3\x7d\xa3\xf7\xb0\x5d\x47\x01\x1f\x2d\x7b\x65\x86\x0b\x9f\xed\xa6\x14\xae\xde\x62\x1d\xcd\x3a\xc8\xcb\xac\x49\x4d\x71\x37\x80\x1e\x14\xbc\x24\x07\x08\x14\x3a\x58\x41\xdf\xd8\x15\xda\xaf\xa2\xe7\xe7\x4e\x61\x87\xf3\xbb\x31\x75\xbd\x01\x3f\x3a\xb7\xd9\xbe\x86\x4d\xf5\x5f\xae\x3e\x7c\xff\x4c\x70\xd9\xd9\x95\x0b\x72\xe1\x35\x27\x60\x20\xc2\x8d\xf8\x15\x88\xb8\xf1\xfd\xb4\x7b\xc6\xb6\x81\xee\x79\x87\x23\xe7\xb6\x5b\xa9\x09\x27\xbb\xa6\xd5\x71\x60\x7a\xc9\x9e\xae\x96\xe5\x30\x98\x2c\xc0\xce\xd8\x3a\xd2\x39\xd5\x75\x35\xaf\x01\xcc\xdb\x19\x72\xd0\x4c\xd3\x43\x86\x81\x7d\x4a\xa2\x31\xb3\xe4\x4e\x26\xa5\xca\xce\x11\x6e\xe7\x4c\x5a\x1f\xf9\xe9\x41\x16\xb8\x30\x61\x9d\x23\x03\xd4\x88\x17\x6f\xbf\xf9\xf6\xda\x9b\x67\xd5\x02\x0f\x31\x60\xf8\x8c\x44\x34\x78\xa7\x04\x6a\xa9\xf0\x8f\x42\x18\x13\x21\x08\x61\xed\x58\xce\x9f\x0b\x3e\xb7\x5f\x1c\x7e\x28\x5a\x6d\xfd\xc7\xfa\x95\x0b\x76\x12\x81\x85\xf5\xd2\xdb\x60\x2f\x63\x6b\x61\xb8\x8a\x85\x06\x96\xe3\x91\xf7\x52\x7e\x00\x7b\xdb\xb3\xbe\x53\x1f\x00\x3f\x38\xa9\xbb\x57\xc5\xee\xab\xaa\x7a\x1e\xce\xd7\xba\x52\x98\xa1\x8e\x27\x57\xa6\x51\xbc\xff\xb3\xd1\x56\x18\xd7\xe2\xca\xc2\x26\x9f\x70\xf3\xb3\x99\xfc\x27\x9d\xb3\x80\xae\xd2\x65\x8b\xc3\x82\x22\x46\x5b\x57\x32\xd7\xe3\xe7\x7c\x00\x9f\x68\xfd\xf1\x91\xe2\xd7\xda\x0b\x90\xe9\xd7\xd4\xf0\x24\xb5\xa7\x5e\xf7\xfc\xa6\xda\x32\x88\x82\x05\xc6\x34\xc4\xb7\x75\x84\x14\x57\x07\xc3\xbb\xfe\xbd\x30\x04\xff\x3c\x8d\xdc\xc3\xd9\xe7\xe3\x0e\x7c\x94\x81\x0e\xd4\x43\xca\x16\x0e\xb5\x3c\xd3\x33\xdb\x43\x14\xc2\x47\x6d\xcd\x91\x6d\xc0\xdc\x39\x89\x95\xc1\x43\xe8\xc5\x1f\x0a\x8c\xf1\x45\x67\x51\x58\x0c\x4b\x91\x60\x77\x5f\xc7\x6f\x18\xc4\x1f\x62\x07\x52\xc9\x66\x75\xa3\x29\xb9\x69\xd6\x8f\xe4\x94\x14\xbb\x0f\xc2\xf1\x0c\xa9\xee\xf0\xb3\xac\xd6\xa6\xfb\x5b\x33\xa9\x1c\x30\xa5\x0d\x81\xdd\xb5\x72\xbf\x6e\x5a\x07\x38\x75\x5a\x85\xc9\x20\x23\x10\x73\x59\x02\xd1\xf1\x5b\x63\x85\x4c\xa8\x0c\xc9\x06\x8d\x1e\x8b\x97\xc8\xfb\xf2\x19\xf2\x08\x78\x4d\x74\xaa\xf4\x70\xa7\x42\xe5\x12\x8c\x56\x3d\x3d\xcf\x9b\xd9\xc7\xf7\xdf\x7d\xa3\xf5\xce\xee\x1d\x43\xfa\x5d\x24\x63\xd3\xe2\x69\x0e\xb8\x0a\x97\xaf\x5e\x7d\x91\xbe\x9a\x7f\x79\xe4\xff\xd2\xc3\xa3\xab\x87\x3b\x45\xd9\xe2\x71\xb6\x6a\x54\x2b\x26\x93\x7f\xe9\x24\x21\xf7\xa5\xbe\x7b\xa3\xe4\x5a\xd6\xba\x2c\xaa\x96\x94\xf5\xd9\xbf\x34\x7f\x84\x07\xc5\xbf\x34\x64\xb3\x95\xf5\xbb\xa6\xbe\x87\xac\xdb\x46\xc3\x0b\xa3\xcf\x62\xc9\x5d\x67\x0a\x9e\x94\x91\x75\xce\x29\x36\x11\xcf\x77\xe4\x16\x51\xda\xea\x99\x4d\x07\x50\xbd\xd2\x12\xed\x84\x25\x58\xed\x4a\xdc\x45\x9a\xab\x56\x82\x6b\x29\x2f\x67\xbb\xa2\x6d\xef\x1b\xb5\x66\x1c\x9e\x46\xc5\xb6\xc7\xfb\x0c\x13\x15\x80\x79\xf6\x09\xcb\x3a\x5f\x04\x19\xdd\xce\x08\xb0\xa2\x06\xb6\xdf\xb1\x34\xda\x3f\x62\x5e\x1e\x7c\x6a\xd7\xc9\x25\xf9\x78\x6e\x7b\x4a\xae\xcf\x81\xd6\x37\x07\x64\xd1\x91\x74\x41\xe2\xae\x25\x8c\x4b\xa6\x4e\xed\x04\xe8\x41\xc1\x16\xcd\x98\x7b\x76\x30\x72\x1a\xd0\x73\x0b\xa1\x66\x4d\x5d\x35\xc5\x1a\x7e\x80\xde\x04\xbf\x60\x67\x0d\xbf\xec\x7e\x1a\x7e\xc3\x66\x15\x94\xb1\xd5\x5d\x51\xdf\x22\xcd\x36\xb7\x06\x04\x50\xdf\x94\xb3\x2d\xa4\x56\x09\x83\xd4\x11\xc0\x30\xd4\x9b\x32\x4d\xe7\xdc\xe6\x64\xa9\xa6\x2e\x9d\xab\x40\x45\x33\x37\x7e\xd1\x4b\x97\x94\x77\xdd\x68\x36\x3c\xb5\x42\xfa\x0f\xbf\x87\xb1\xc6\x41\xb8\xc3\x46\x9c\xaf\x82\x9c\xf2\x41\x67\x4f\x37\x65\x5d\xa8\xc7\xb4\x4f\x3e\xa6\x4f\x70\xbe\x15\x67\x3c\x72\x08\x22\x39\x3d\x95\xa0\x0c\x02\x34\x7c\xab\x36\x94\xf1\x62\xd0\xb6\xae\x45\x1b\xea\xbe\x9c\x07\xc1\x31\xb6\xed\xb3\xbe\x17\x8a\x74\xb4\xed\x83\xce\x34\xaa\xb3\x0a\x4c\x09\x49\xf2\x9c\xcd\xa4\x49\x92\x02\xd0\x29\x79\x63\xde\x8f\x3d\xe7\x8c\xdf\x60\x25\x29\x23\x2b\x1c\x1e\x88\x23\x6a\x54\x6c\x3c\x69\x9c\xf1\xe4\x78\x72\xb0\x00\xaf\x69\xa8\xe3\x54\x79\x5e\x85\x92\xe1\x84\x08\xd5\x22\x80\xa2\x2f\x77\x5a\xe0\x09\x7d\x74\x06\xe7\x4f\x77\x31\x8b\x3d\xc6\xed\xcf\x60\xf9\x59\x74\x4c\xfb\x4c\xba\x5c\x6d\x47\xd3\x1f\xce\xfb\x3b\xd1\x69\xae\x7d\xdb\xc5\xa7\x1b\x9a\xa5\xa6\xd4\xce\x64\x64\x98\x0c\x47\xb8\x7f\x40\x93\x92\xa1\xae\x1c\xe8\x4d\x8c\xcb\xd1\xc6\xf2\x1a\x5c\xa4\x39\x79\x02\x79\x6f\x22\xb6\xbf\x4c\x73\xf1\xd3\x46\x45\x18\x17\xa3\x1b\xf6\x8d\xd9\x0b\xe9\xd3\x77\xf4\x46\x25\x70\x0c\x8b\xa5\x56\x6d\xbb\xe6\x2b\xad\x55\xfb\x19\x79\xad\xc4\x15\x25\xaf\x31\xef\x7f\x12\x86\x41\x4e\xd1\xc3\xc8\x2a\x0f\xce\x54\x4f\xf6\x04\x3f\x75\x19\xde\xe0\x35\x6f\xd5\x2a\xad\x8d\x60\x3f\xb2\x59\x53\x53\x62\x26\xd5\x99\xdd\xde\xc5\x8e\xb0\xca\x79\x6f\x32\x5e\xa2\x5c\x32\x2a\x1f\x0d\xc4\x10\x6e\x3b\xbf\x9c\x7f\x09\x0b\x20\x5e\x9a\x06\x79\x0b\xea\x77\x84\xc1\xa3\x8c\x62\x38\x32\xae\xcb\x24\x29\x69\xef\x1a\xfa\x93\xe6\x1f\xb5\x58\xe6\xfc\x67\x2d\x2e\xa8\x60\x9f\x32\x9a\x89\xa4\x7b\xc1\xba\x4f\x19\xfa\x83\x06\xe3\xd6\x6c\xa2\x76\x29\x59\xd9\xa3\x5e\x3c\xbc\xdf\xb9\x93\xdf\x53\xcf\xd7\x8f\x1a\x9d\xc7\x61\x4b\x87\xe1\x17\x53\xf2\x4b\x60\xdd\x8f\x94\x67\x74\xa6\x91\xa3\x83\xc8\xbc\x08\x0e\xf9\x77\xe4\x79\xb6\x1b\x5e\x88\x09\x92\x53\x40\xce\x24\xa1\x3f\x7b\x84\x81\xbd\xaa\x58\x46\xf6\xaa\x22\x23\x18\x15\xd6\x7a\x0f\x87\x32\xf2\xbf\x7b\x28\xd3\xbf\xd3\x1e\x9d\x10\xf3\x17\xa3\xa0\x8b\xae\x23\xf8\x15\xd0\x9b\x91\xa7\x8e\xc7\x7f\xb2\xd5\x77\xcd\x2a\xb6\x74\x90\xc2\xb2\x41\x02\x35\x2a\x6f\x94\xc2\x8b\x4c\x2e\x8b\x5c\x98\xff\xfc\xc9\xcb\xcf\x78\xf2\x32\x55\x2c\x1d\xb4\x13\xb4\x4f\x70\xc0\xe3\xda\xcb\x9d\xc9\xd8\x9c\xe0\x8a\xa9\x60\x7e\x06\x76\x43\x1c\xee\xe8\x82\x11\xd9\x0d\x9d\xcd\xb2\xf7\xc8\x55\x53\x72\x76\x5f\xb4\x67\x75\xa3\xcf\xcc\x28\x32\x2d\xc6\x9b\xe5\x3c\x3f\xf2\xb8\x35\x04\x6e\xd8\x79\x29\xde\x2c\x55\xce\xdf\x44\xe0\x6e\xec\xa9\x11\x3e\x5e\xf5\xc8\xeb\x11\x84\xd8\x9e\xb7\x2d\xbb\xa2\x6f\x5c\x68\xfb\x0f\x66\xa2\x2a\x96\x42\x71\x25\x97\x4b\x95\xc3\xc7\xc7\xed\xad\x07\x4d\x69\x46\xf1\xbe\xbd\xa3\x8a\x01\xbc\xeb\x96\x96\xcc\xcc\x21\x44\x6b\x6f\x44\xd9\x93\x53\x38\x39\x04\x8e\xf2\x78\x40\xfb\xcd\x35\xc0\x7d\x40\x5d\x05\xa5\x3f\x69\xf1\x76\x56\x6e\x77\xb8\xe1\x82\x91\x34\x92\x91\x9a\x51\x67\xf6\x09\x66\xec\xd5\x52\x99\x7b\x82\xbc\x36\x83\xed\x3f\x5f\x5f\xe0\x9f\xf0\x82\xf0\x57\x42\x88\x9f\x74\xb0\x57\xf0\x47\x7d\xd6\xfb\x05\x8a\x18\xdf\x86\x9f\xfa\xee\x65\xcb\x3c\xa5\xa3\x01\xe9\x14\x4d\x16\x46\x48\xeb\xae\xa3\x63\x5f\x99\x51\xaa\x04\xfd\xc3\xdf\xc9\x86\x27\xd9\x37\x45\x2b\x4d\x32\x1c\x5d\xbf\xf5\x6e\xeb\xd6\xb3\x6b\x44\xd0\x31\x96\x6a\xf1\x16\x28\xe3\xea\x24\x59\xe6\x9c\x96\xe2\x7b\xf4\xfd\x90\x8c\x65\x4b\x3d\x78\x43\xb9\xbc\xcc\x59\x9e\xd2\x52\x3c\x20\x30\xaf\xe6\x0d\xf4\x6c\xe3\x09\xef\xae\x68\xc3\x7a\x61\x7c\x35\xdb\x4a\x75\x2b\xe9\x32\x37\xfa\x6f\xbf\x1d\x63\x28\x42\x41\xf6\x58\x73\x01\x68\x4c\x9f\x13\x50\xb0\x73\x6c\x85\x0c\x31\x0a\xdc\x2e\xf4\xfc\xf2\x35\x12\xc2\x1d\xcc\x0c\x44\xeb\xb9\xd9\x78\x9b\x7d\x3a\x5e\xcd\xb9\xb9\x06\xef\x69\x1a\x19\x8f\x52\x3d\x82\xa9\xab\x91\x93\xf5\x87\x0f\x57\xd7\x84\xf1\xf9\xeb\xa2\xff\xbe\x53\xc3\x4b\xd9\x75\x43\xdb\x0b\xfa\x95\x59\x8b\x2c\x1b\x20\x17\xcb\x68\x16\xf2\x62\x66\x72\x53\x95\x99\x25\x73\x5d\x1e\xfe\xd3\x43\xc2\xd1\x60\x04\x9a\x0e\x81\x80\x61\x33\x0b\xcd\xca\xe5\xa6\x6e\x9d\x24\xf1\xda\x5b\x9c\x6c\x90\xeb\x10\xa7\xb1\xe9\xba\xc0\xcc\x0f\xba\xb3\xe6\x32\x07\xd0\x72\x6b\xa8\x18\xec\x6e\x2d\xc6\x61\xd0\x3b\x91\xd5\x4f\xc9\x1d\xf5\x00\x9c\x63\x3b\x79\xe1\x88\x8c\x8e\x6e\x6b\x6b\x5e\x81\xbb\x60\x08\x41\xf9\x00\x3f\x9f\x07\x0b\xf2\xe7\x24\x3d\xe7\xb2\xa5\x2f\x24\x10\xa5\x47\xc1\xa3\xe0\xe9\xb8\x20\x46\x45\x2e\x57\xc0\x66\xdf\x53\xff\x79\xb2\x43\x41\x94\xac\x0a\x5d\x1e\x00\x54\x52\xac\x6c\x1d\x28\x62\xe3\xda\xa2\xc1\x58\xca\xf7\x7d\x42\x05\xc4\x7d\x9c\x46\x0c\x8a\x55\xd7\x91\x4d\xf9\x00\x50\x6f\x00\x09\x7e\x7e\xf9\x9a\x36\xd3\x7d\xb8\xe4\xed\x75\x43\x58\x46\x0b\x41\x95\x58\xf9\x4a\x50\xc6\x66\xba\xd9\xf1\x52\x28\xe0\xea\x03\x03\x76\xc0\x19\xd8\xb0\xae\x9b\xf3\x32\x4c\xda\x23\x25\xf3\xd6\x85\xf2\x6b\x17\x6a\x5a\x47\x40\xbd\x66\x5a\x59\x88\x64\x3d\x03\x44\x53\xba\x31\x7f\xf1\xea\xbc\x35\xff\x4f\x8b\x3e\x8b\x79\x3b\xe4\x31\x3f\xec\xf5\x79\x0b\x7f\xa6\x25\xe3\x64\xdf\x1a\xd9\x56\xd6\x67\x3a\xd3\x33\xb8\x70\xef\xdd\xb0\x94\x9e\xa0\x0f\x6c\xc2\x77\x4e\x05\x70\xb8\xf1\x91\x5c\xd1\x6b\x5d\xbe\x15\xb4\xf6\x86\x21\x5f\x54\x60\x3d\x6c\x06\x63\x03\xa3\x9b\x9f\x03\x51\xf1\x8b\x17\x82\x7f\x8c\x99\xc5\xc0\x6c\x89\xa5\xce\xfc\xd8\x73\x88\x04\x10\x9a\xe0\xf1\x60\x86\x48\x0f\x2a\x53\xcf\x19\x6b\x32\x07\x2d\x30\xc6\xc9\xc8\x6b\xb3\xb5\x0b\x6d\x96\x61\x0c\x26\x7f\xd2\xcd\x2e\x95\xd0\x6a\xf5\x6c\x57\xdc\xca\xbf\x63\xa5\x38\xb0\xfe\x4b\x6c\x27\xbc\xf3\x11\xef\x1c\x59\x0a\x0f\xcd\x31\xcb\xfc\xe8\x80\x08\xb8\x67\x94\x0f\xf5\xd6\x8d\x37\x77\x86\x50\x24\xee\xeb\x78\x29\xe2\xc2\x8c\xba\xd5\x0f\x6e\x9c\x07\x2a\x9c\x73\x4c\x3f\xff\xad\x78\x84\x6b\x19\x00\xfd\xfc\x3a\x69\x00\x6e\x9a\x0b\x6f\xff\x00\x46\x3e\xb3\xb7\x70\x51\x5d\x76\xb9\x71\xf6\x57\xb0\x08\x0b\x51\xc3\xba\xde\x75\xf8\x7b\x90\x17\xe0\x26\xfc\xe4\x1f\x91\x13\x60\xb2\x0d\x80\xa4\x64\x92\x48\xa4\x8b\x39\x61\x34\xa0\x25\x88\x14\x5f\x7b\x86\x03\x7a\xc0\xcc\x7e\xdd\xec\x3c\x27\x3b\xe3\xa5\x1d\xcd\x83\x4c\xdf\xc9\x8d\xee\x73\xb9\x13\x18\x68\x6e\x9c\x94\x25\xfc\xef\xdb\x18\x39\xb5\xae\x9b\x1d\x96\x0a\x1d\x62\x27\x26\xbe\x61\x98\x15\x58\x45\x31\xc4\xf0\xc8\xc3\xf6\xfc\xb7\xa2\x5a\x82\xce\xc2\xa7\xfb\xa6\xff\x03\xad\x1a\x3d\xe8\x6c\xe0\x5d\xa7\xe4\x31\x46\xfb\xf5\xfc\x72\x29\x09\xc6\x32\xe1\x9e\x8f\x0e\xd3\xed\xe8\x0f\xc3\x1f\xb5\x0b\xfd\x6a\x44\x94\xc5\x68\xa9\x88\x60\x1c\xc1\x10\xfe\x21\x92\x4f\x70\x68\xa4\x92\x65\x4a\xc8\xf4\x7f\x0f\xc7\x80\xd9\x4b\x04\x73\x94\x8d\xd0\x56\xab\x4c\x2d\xcb\x1c\x20\xe0\x16\x46\x32\xb8\xcf\xa0\x4d\xa6\xc2\xc9\x9a\xd6\xbc\xc9\xea\x54\x85\x53\x9b\x59\x98\xb9\xa3\x91\x39\x7c\x94\xd8\x33\x00\x75\xde\x11\xbb\x0a\x45\x27\x66\x75\xc4\xd0\x5a\xe7\x48\x55\xbb\x2b\x1f\x64\xf5\x83\x63\xf7\x3d\x81\x85\xd0\x1e\x3a\x03\x19\x99\x6b\xc6\xdf\x7b\xf6\xe7\x0c\x86\x7d\xbf\x50\x2d\xeb\x1c\x68\x64\x8d\x0e\x13\x74\xa4\x65\x2c\xf7\x0c\xcb\x30\xc0\x53\x4b\x1c\x13\xf4\x5a\xc1\x5b\x08\x51\x85\x87\x3c\xeb\x2c\xa8\xe5\x64\x5a\x38\xeb\x4a\xda\x72\x42\x52\xd2\xec\x35\x24\x07\xcf\x2b\x24\xa1\xdd\xd4\xcb\x26\x1f\x8d\x85\x1b\xb6\x9b\xe9\xb7\x00\xa9\x3a\x08\xb2\x34\xab\x6d\xd7\x51\x38\xf5\x97\x5d\x37\xc1\x25\xc2\x51\xd8\xa5\x8e\x60\xd8\x1f\x6a\x7c\x76\xe0\xd8\x3c\x30\x78\xe6\x80\x6c\xef\xd7\x7c\xfc\x0a\x96\xc9\xa5\xff\xce\x3c\x95\x5e\x58\x0d\xa5\xd6\x92\xac\x40\x74\x42\xb6\x78\x0c\x66\x38\x04\xe3\xfc\xdc\x73\xc2\x49\x10\x86\xb0\x83\x6c\xaa\xca\x3c\xcf\x55\x74\xe5\x32\x38\xea\x65\xcc\x10\x5f\xf5\x2f\x67\x2e\x64\x46\x20\x13\xad\xa5\x9e\xe5\x25\x4b\x23\x5a\x5a\x5e\xb2\x23\x6f\x79\x9d\x39\xe8\x1b\x7b\xe2\x17\x0c\xd7\xde\x41\x94\xf7\xa7\xcf\x7c\x70\x74\x1d\x1e\x82\x47\xc7\xe3\xbc\xf7\x12\x1b\x46\x03\x7d\x66\x9e\xa3\xfc\x02\x12\x84\xd3\xd8\xf0\x9b\x72\x60\x9e\x1a\x62\x78\xe3\x6c\x82\xc8\x72\xf3\x39\x7c\x5f\x9f\x3c\x32\x78\x60\xb3\xf1\x4f\xb0\x23\x77\x00\x0e\xbf\xc3\xfb\x10\x90\x34\x98\x77\x3c\xf3\x94\x7f\xc6\x2c\x4b\x27\xd0\x52\xc1\xeb\xc9\xcb\x97\xc4\x9e\xfb\x99\x04\xcd\xc1\x29\xfa\x25\x81\x4f\xb8\x6b\x0e\x9f\x8d\x86\xdf\x36\xfb\x56\xca\x5a\x4b\x65\x66\x3c\x5c\x55\xb2\x38\x48\xaa\xbb\x4e\x86\xe2\x87\xdc\x54\x7b\x75\x06\x21\xe9\x67\x36\x4e\xfd\xcc\x05\xa8\x9f\x29\xd9\x96\xff\x92\x67\x38\xea\xce\x56\x55\xb9\xfa\xed\x6c\x7d\x53\xe1\x0f\x28\x74\xdd\xdc\xd7\xf8\x6b\xbf\xc3\xbf\x66\x63\x88\xbf\x4c\x15\xed\xaf\xbd\x3e\xeb\x6b\x74\xd6\x57\xe7\x0c\xad\xdd\x67\x18\x24\x7c\x86\xc1\xc5\x67\xbf\xc9\x47\x28\xf7\x37\xf9\xb8\x53\xb2\x6d\xcd\x8f\xfd\xee\xcc\x86\x61\x6c\x65\xbd\x27\x81\x53\xd0\x89\xc8\xdc\xd4\xc0\xa3\x35\xd6\x36\xf3\x13\x9c\xd4\xcc\x75\x5d\x8d\xfd\x0d\x68\xc9\x18\xb5\x69\x5d\x2c\x6a\x1f\x8b\xf8\x67\x2d\x2e\xfe\xb1\xfc\xd4\x7e\xda\xbf\x7b\xfb\xee\xdd\xa7\x87\xaf\xe6\xf9\xb4\x1b\x5c\xbf\x00\xa0\xb1\x9d\x6a\x1e\x1e\xc7\x23\x7f\xd1\xec\x7a\x62\x68\x43\x03\x02\x44\x0f\x63\x0c\x4b\x6d\xf6\x03\x01\x8b\xa5\x68\x51\x39\xef\xf7\x95\xaf\x98\xd9\xce\x9f\xaa\x01\xd2\xed\x06\x6d\xf0\xbc\x72\xa1\x1a\xc3\x12\x00\xb3\x10\xcc\x8d\x42\x86\x7f\xba\xee\xca\x1a\x21\x79\x69\xb4\xf5\xbb\xa6\x5a\xff\x28\x8b\xf5\x63\x8c\xc5\x03\xe0\xc4\xc5\xfa\xf1\x6f\x45\xa9\xa7\xd3\xd4\x5e\x01\x4d\x08\x78\x5d\x80\x83\x9d\x88\xc2\x49\x9d\xc9\xe5\x2f\x57\x1f\xbe\x17\x41\x48\xd2\x95\x8f\x72\x15\x5f\xc1\xb3\xef\xec\x8b\xc4\x16\x2e\x11\xbc\x44\x3c\xf0\xab\xd9\xaa\xd8\xca\xea\x4d\xd1\x4a\xf1\x91\x5f\xa1\xf1\xfb\x1e\x9e\xbf\xf7\xd0\xfa\xf0\xc8\xf7\xfb\xad\x54\xe5\x6a\x84\x4f\x04\x9f\xa2\xd2\x2d\x06\xc1\x4e\x47\xe8\xd0\xd1\x5b\x18\xad\x73\x52\xb6\xdf\x17\xdf\x53\x19\x92\xd7\x4b\x04\xbe\xd7\xaa\xdc\x3e\x8f\x93\x04\x08\x62\x54\x46\xc1\x12\x7f\x06\x37\xf8\x23\x27\xee\xa9\x7e\x00\x20\xb2\x78\x92\xe0\xdf\x59\xb1\x5d\xbb\xdf\x94\x60\xa0\x11\xe1\xcb\x7c\x84\x29\xfe\xca\x8e\xce\xbf\x6b\xf1\x66\xf6\xeb\x5f\x4d\x4e\xfe\x57\xf3\xfb\x45\xcf\xf3\x53\x37\x6f\x9a\x7a\x53\x95\xab\x51\x5c\xa7\x37\xb3\x17\x46\xfb\x4b\x12\x6a\x7e\xfd\x55\x03\x55\x8a\x2b\xcb\xdf\xb1\x97\x7f\xd7\x8c\x5f\x1d\xf9\x28\x16\x7a\x98\xcf\x14\x75\x65\xb2\xb2\xc5\xff\x09\x00\x00\xff\xff\x49\x22\x74\xca\x83\x5d\x01\x00") func cmdInternalPagesAssetsJsJquery351MinJsBytes() ([]byte, error) { return bindataRead( _cmdInternalPagesAssetsJsJquery351MinJs, "cmd/internal/pages/assets/js/jquery-3.5.1.min.js", ) } func cmdInternalPagesAssetsJsJquery351MinJs() (*asset, error) { bytes, err := cmdInternalPagesAssetsJsJquery351MinJsBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "cmd/internal/pages/assets/js/jquery-3.5.1.min.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x61, 0x50, 0xa3, 0x5c, 0xf, 0x48, 0x6c, 0x46, 0xca, 0xdf, 0xe, 0x23, 0xe, 0x2a, 0xa1, 0x59, 0xc7, 0xc2, 0x3e, 0xcf, 0xbb, 0x56, 0x11, 0xb6, 0x4e, 0xe3, 0xf2, 0x5f, 0xcb, 0xff, 0x34, 0x1f}} return a, nil } var _cmdInternalPagesAssetsJsLoaderJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\xbd\x79\x97\xda\xb6\xf7\x38\xfc\xff\xbc\x0a\x70\x5b\x2a\x05\x8d\x81\x99\x49\xda\xd8\x51\xf8\x4d\xb3\xb7\xd9\x3e\x59\xba\x11\x9a\x23\xc9\x32\x38\x18\x4c\x6d\x33\x4b\xc0\xef\xfd\x39\xda\x6c\x19\x4c\x32\xd3\xc9\xf7\x39\x27\x61\x6c\x59\xba\xda\xae\xee\xa6\xab\x2b\x10\xae\x16\x2c\x8f\x92\x05\x80\xeb\xde\xad\x83\x83\xd6\x83\x64\x79\x99\x46\x93\x69\xde\x7a\x37\xe5\xad\x07\x71\x92\xad\x52\xde\x7a\x1e\xd1\x94\xa4\x97\xad\xd3\x55\x3e\x4d\xd2\xcc\x3d\x68\xbd\x7d\xfd\xf0\xcf\xc3\xe7\x11\xe3\x8b\x8c\x1f\x3e\x0b\xf8\x22\x8f\xc2\x88\xa7\x5e\xeb\x74\x49\xd8\x94\x1f\x1e\xb9\xfd\x83\x5b\xbd\x83\x1f\x57\x19\x6f\x65\x79\x1a\xb1\xfc\x47\xff\x8c\xa4\xad\xb9\x6f\x6a\x6c\x11\x02\x08\x5c\x8b\x44\x8a\xfb\x7e\xca\xf3\x55\xba\x68\x59\xed\xd1\x29\xf4\x1e\x71\x63\xbe\x98\xe4\xd3\xe1\x3a\x48\x16\xdc\x6b\x0f\xd0\x19\x89\x57\xdc\x23\x23\xda\xed\x8e\x0b\x4f\x27\xf7\x8b\xa2\x28\x81\x2f\x2a\xd8\xce\x6a\x11\xf0\x30\x5a\xf0\xc0\x69\xe3\xfc\x72\xc9\x93\xb0\xf5\xf6\x72\x4e\x93\xb8\xd3\x51\x7f\xdd\x28\xe7\x29\xc9\x93\xb4\xd3\x21\xa3\xad\xa4\xb1\x69\x19\x1d\x52\x97\x91\x38\x06\x04\x7a\xeb\x05\xbf\xc8\x3d\xd9\x01\xab\x4e\x2a\x3b\x14\x85\xa0\x0d\x48\x2b\x5a\x64\x39\x59\x30\x51\xd9\x69\x9a\x92\x4b\x08\xd7\x04\x8b\x56\xf9\x61\x92\x02\xd9\x32\xc4\xf0\x68\xec\xb7\x01\xc5\xc4\x15\x00\x01\x84\xae\xe8\x8a\x0f\x99\xbb\x5c\x65\x53\x40\x5d\xd9\x51\xe8\x13\xcc\x0a\xdd\x0c\x52\xd5\xc7\x08\x20\x88\x22\x06\xd7\xb5\xea\xde\xe6\x69\xb4\x98\x74\x3a\x80\x60\xf5\x08\x08\xac\x6a\x0d\xb0\x19\x4e\xc4\x71\xdf\xe7\xf7\x02\x9f\x77\xbb\x6a\xac\x42\x4c\x46\x7c\xec\x47\x21\xd0\x5d\x65\x28\x44\x1c\x11\x08\x55\xe5\xeb\x97\x1e\x47\xef\xbc\xb0\x28\xca\xf7\xc3\x01\x7a\xe7\x9d\x25\x51\xd0\xea\x17\xc5\x81\xac\x80\x60\xc7\x34\xd1\xc1\x66\xc0\x5f\xd1\x4f\x9c\xe5\xae\x9a\x88\xd7\x69\xb2\xe4\x69\x1e\xf1\x6c\xd8\x94\x7e\xe9\x95\x58\xa0\xfb\x17\x85\x80\x60\x2c\xc7\xd1\x5d\xa6\x49\x9e\x08\xa8\x9b\x0d\xc1\x58\x97\x2f\x13\xa1\x19\x26\x9f\x8c\xe8\x18\x33\x35\x82\x7e\x39\x78\x15\xfa\x71\x39\x5b\x04\x8f\x9c\x44\xc2\xa8\xda\x3a\x89\x13\x4a\xe2\x77\xd3\x28\xeb\x74\xaa\x67\x44\xd0\x4e\xce\xf3\x68\x11\x24\xe7\x9d\x8e\xfa\xbb\xfb\x3d\xe3\x71\xd8\xe9\x88\xdf\xdd\x6f\x0a\xb2\xa9\x61\x5c\xa1\x05\xee\xfb\x15\xce\xfb\xdd\x2e\x55\x93\xc3\xb0\xe8\x91\x98\x1c\xd6\xe9\x30\xf7\x05\xc9\xa7\x18\x8b\x5f\xd3\x65\x56\xe4\xd3\x34\x39\x6f\x3d\x4a\xd3\x24\x05\xce\x03\xb2\x58\x24\x79\x2b\x8c\x16\x81\xae\xab\xa5\x9b\x00\xfd\x42\xce\x36\xc1\x9c\x80\x7c\x1a\x65\xd0\x3f\x28\x87\xe5\x5f\x31\xe6\x72\xc4\x29\x24\x9e\xae\x39\x24\x3e\xc1\xc4\xcd\x96\x71\x94\x03\xc7\x75\x6c\x74\xea\xfb\x41\xd9\xda\xc3\x81\x1f\x18\x64\xe2\x98\x8c\x02\xd9\xde\x36\xe0\xad\x68\xd1\x62\x10\xd2\x94\x93\x59\x8b\xf8\x0c\xb3\x11\x1f\x17\x04\x93\x51\x55\x74\xec\x07\x98\x8d\xc8\xd8\xa7\x98\x82\x00\xfa\xb4\x8d\x83\x4e\x67\xb1\x8a\xe3\x36\xa6\x9d\x4e\x40\x00\x43\x04\xad\x59\xb2\x08\xa3\xc9\x2a\x25\x34\x16\x8b\x1e\x9d\xa7\x51\x6e\x9e\x15\x5d\xa0\x05\x2c\x8a\x7f\x81\xb3\x85\x2f\xae\x18\x8a\x67\x8b\x80\x5f\x38\xa8\x42\xb0\x92\xce\x90\x21\xa9\xf0\x4e\x62\x9d\x19\x57\x35\x48\x12\x13\xdd\x97\x45\x01\xfd\x3d\xb0\x6f\x00\xf6\x9d\x00\x5b\x4d\x42\x6a\x21\xbe\x18\x00\x8c\x09\x54\x93\xbb\xe0\xe7\xad\x77\x97\x4b\xae\x27\x59\x10\xe9\x1f\x05\x98\x1f\x5b\xb2\xef\xad\x30\x49\x35\x01\xb0\x1a\xe7\x74\x59\xd7\x69\xcd\x57\x59\xde\x12\x28\x41\x79\x4b\x00\x6d\x25\x69\xab\x22\x8d\x50\x2e\x7b\x9b\x8e\xbc\xe1\x93\x47\x17\xcb\xe6\x7a\x1f\x47\x69\x96\xb7\x48\x3a\x59\xcd\xf9\x22\x6f\xe5\xc9\x55\x2a\x25\xad\x94\x4f\x56\xb1\xc0\x8d\x8b\x65\xca\xb3\x4c\x50\x08\x58\xae\xcd\xae\xe3\x88\x59\xdb\x01\xc4\x17\x41\xf6\x47\x94\x4f\xaf\x38\xbc\x0a\x2b\x53\x33\xb8\x4e\x59\x1c\xfa\x8a\x4e\x61\x8c\x59\xa7\x03\x18\x0e\x34\xea\x41\x9f\xc9\x85\xe4\xce\xc9\x05\xe8\x23\xf5\x18\x2d\x00\xdb\xf4\x51\x99\xa7\x42\x79\x8e\xa9\x59\x9c\xfd\x7b\xbc\xd3\xe9\xdf\x63\x3e\x8c\x42\x10\x8c\x0e\x0f\xd9\xb8\x8d\xe9\xe8\xf0\x90\x8f\xf5\xaa\x6c\x0f\x4c\xff\xfa\xf7\x31\x97\xb3\xdc\xd4\xc7\x2c\x27\x69\x7e\x93\x5e\x5a\x00\x20\xe2\x65\xd7\x50\x58\x35\xf6\x5a\x9d\x9c\xe0\xbe\x3f\xb9\x17\x76\x3a\xec\x1e\xd7\xbd\x63\xdd\xae\xec\xdd\xa4\xdb\xdd\xed\xdd\xe4\x3e\x0e\xf5\xd2\xd8\xe9\x5c\xca\x97\x9c\xe4\x57\xe8\x98\x21\x74\xba\x5b\x02\x49\x91\xa3\x4b\x4b\xfc\xec\xdf\xa7\x9b\xcd\xe0\xf8\xe4\x68\xf0\xd3\x4f\x47\x3f\xdd\xbd\x47\x2d\xec\x7c\x43\x16\x13\x83\x9e\xcf\x16\x67\x24\x8e\x82\x16\x4b\x56\x8b\x5c\xad\x0c\x07\xfa\x74\x83\xfb\x16\xe1\x72\x1c\x9f\xca\xae\xd1\xce\xa0\xd3\x01\x41\x17\x33\x88\xe8\xfd\xfb\xf7\xf1\x00\xb2\x2e\x66\xa6\x6b\xc1\xde\x59\xcb\xd3\x68\xfe\x9c\x87\x5b\x5d\xab\xe4\x81\x4a\x88\x11\xfd\x11\xe3\x10\x13\xc6\x41\xef\x9f\xd1\x87\xec\xc3\x05\xe9\x8f\xbb\x3d\xe4\x38\xb0\x64\xed\x9b\x0d\xdd\x33\x84\xa2\xa6\xb7\x62\x8a\x9b\x47\x71\xb3\xd9\xdb\x36\xdd\xf6\xd7\x69\x32\x8f\x32\xbe\xb7\xa5\x13\xb8\x96\x6d\x14\xdc\x47\x3e\x30\xac\x56\x8b\x7a\x23\x42\x52\x11\xc3\x36\xc5\xf2\x7d\x02\xa0\x9f\xa7\x97\xeb\x09\x98\xba\x29\xcf\x92\xf8\x8c\x23\xf1\x24\xf8\x0b\x2c\x18\xc9\xd9\x14\xcc\xe0\xda\x24\x81\x99\x2d\x27\x31\xa0\x2b\x23\x58\x4c\x71\xf5\x21\x10\xcd\x30\x08\x65\x93\x22\x3a\x9c\x78\x62\x8e\x69\x25\xaf\x4e\xe1\x7a\x0a\x26\xb0\x80\x85\x10\x0e\x2a\xb6\xcf\xac\x31\xa0\xb8\xcc\x3e\xb1\x68\xa9\xaa\xbb\x6c\x43\xad\x67\xba\xf3\xb6\x5c\x3c\x75\xa7\x40\xd4\xa3\xb2\x2b\xc9\x6c\x02\x0b\x5f\xd1\x82\x90\xb8\x19\xcf\xdf\x45\x73\x9e\xac\xf2\x5a\xed\xac\x56\x3b\x07\x13\xd4\x87\x45\x2d\xc7\x14\x5b\xd5\x08\xc4\xd4\x83\xdd\xe9\xe8\xba\xf4\xca\x55\xeb\x62\xa2\x1b\x6e\xcd\x88\x41\xe6\x29\xee\xfb\xd3\x7b\x93\x4a\x66\x98\xaa\x22\x33\x7c\x30\x19\x4d\xc7\xbe\xf8\x91\x63\x2d\x27\x6d\x06\xcc\x14\xc5\x7a\x10\x26\x20\x86\x45\x51\xd8\x93\x52\x6b\xe8\xa4\xd6\x95\xdd\x21\x52\xab\x70\xe2\x17\xb0\xf0\x69\x73\x39\x0b\xdb\x44\x6d\xeb\x6d\x79\x7f\x09\xd7\xb3\xcd\x06\xcc\x70\xbb\x8f\x62\x25\x7d\x4e\xd1\x12\xc2\xa2\xa8\x26\x07\xcd\x70\x49\x71\xd6\x1a\xed\xbc\x89\x24\x16\xee\x2f\x10\x29\x5c\x33\x09\x53\x58\xd4\x1b\xf3\xcb\x36\x36\x4c\xb0\xc2\x05\xa8\xf2\x83\x2d\x1e\x77\xda\xd2\x8b\xa6\xc5\x94\x28\xa5\x6b\x14\xdc\x2e\xca\x85\x50\xe7\x40\xe8\xf3\x38\xe3\x2d\x01\xac\x86\xaf\x0a\xe4\x53\x30\x51\x19\xd6\xc4\xcb\xce\x23\x31\xe2\x46\xf8\x83\x6b\x46\x32\xde\x32\x52\xa1\xa7\x3a\xa9\x84\x9d\x89\x5f\xca\x49\x32\x4f\x29\x4d\x7b\x53\xdc\xee\x97\x1f\x03\x1e\x92\x55\x9c\x8b\xc4\x41\x31\x1d\xca\x1a\x4f\xc1\x04\x7a\xf2\x29\x12\x38\x5a\xf8\x07\xf6\x08\x9c\xd6\x46\x40\x55\x69\x56\x79\x7a\xb9\x9e\xe2\x89\x9b\x4f\xf9\xa2\x5a\xbf\x7a\x60\x66\x86\x49\x17\x0d\x92\xbd\xae\xf9\x31\x98\xa2\x5a\xdd\xb5\xb1\x9f\xee\x22\xd0\x27\x70\x84\xb6\xb3\x45\x4d\xd9\x06\x3b\xd9\x3e\x59\xd9\xd0\x54\xce\x65\xbf\xad\x56\x87\xe1\x08\x75\x21\x38\xe3\x79\x1e\x73\xe0\x74\x27\x5d\x07\xb5\x9c\xee\xb4\xeb\x40\xaf\x9c\x5e\x12\xa7\x9c\x04\x97\x3a\x57\x20\x64\xd5\x2c\x27\x39\x77\xba\x1a\xa4\xaf\x49\xe3\xc4\x90\xc6\xa9\x7a\x98\x83\xad\x86\xcd\x6d\x7c\xd7\xf4\xa6\x5d\xd2\x9b\x3a\x6f\xad\x2f\xf1\x6e\x77\x02\x43\x97\x2a\xd4\x25\xa3\xc9\x18\xfa\xf6\x6a\x54\xd4\x26\xc4\x02\x45\x59\xad\xca\xa7\x0d\x73\x5a\x92\xe8\x83\x89\xfb\xa4\x91\x42\xd7\x40\x3c\xde\x1a\x4e\x45\x39\xea\x74\xde\xac\xc8\x59\x09\x6c\xb6\x45\xee\x63\xb8\x36\x49\x92\x9a\xd4\xaa\x10\x68\xb5\x55\x4b\x49\x0e\x66\xe0\x14\x3d\x31\x04\xa1\x01\xc1\x4e\x87\x65\xc1\x95\xa0\xda\xe9\xe5\x3a\x06\xa7\xe2\xd9\x54\x7d\x46\xe0\x7a\x29\x7e\x8b\xc2\x7b\x22\xe9\x45\x8c\x96\xe8\x02\x6f\xb1\x0c\x59\x4d\x8c\x4f\xfd\x25\x7e\x52\xe8\xf1\x7d\x02\x66\x60\x82\x62\x88\x66\x8a\xdc\x18\xa6\x7f\x51\x6f\xbf\xac\xa7\x36\xd2\x36\x63\x17\xbd\x03\x6a\x21\xed\xe0\xea\x93\xfd\xdd\x86\x6b\x4d\x14\x62\x97\x6a\x7a\x30\xf0\x26\x20\x76\x19\x54\x8b\x5c\xad\xff\x23\x6f\x6a\xa7\x99\x65\x5f\xc3\xf3\xf7\x0b\x7e\xb1\xe4\x2c\xe7\x81\x42\x5d\xaf\xe5\x74\x0f\x04\x58\x5f\xd1\xcf\x58\x31\x37\x9b\xff\x0d\x05\xba\xcd\xf4\x8a\xd5\x6c\x6d\x26\x1b\xaf\x67\x18\x07\xf2\x59\x4c\x68\x53\xcf\xb7\xf9\x31\x9a\xc1\xf5\x4c\x71\x64\x51\x8e\x30\x7e\xd5\x52\x66\x5d\xc4\x58\xe4\x44\x4b\x1c\x6b\x73\x88\xdf\x5e\x2a\x83\x48\x95\x04\x03\xb0\xd4\x56\x11\x81\xda\x68\xa6\xeb\x23\x71\xdc\xb0\x10\x24\xbc\x19\x9e\x1a\x78\xba\x11\x33\x09\x75\x18\x80\xd1\x18\x6e\xcb\x15\x31\x5a\x5a\x93\x74\x21\x51\x6e\x9b\x57\x09\x7c\x3b\x1d\xad\xc8\x18\x9f\x11\xff\xc9\xe1\xa1\xdf\xc7\xf8\x49\xa7\x13\x83\x53\xcd\xae\x4e\xf1\x68\x8c\x9e\x08\xd5\x38\x69\x9d\xaa\xa1\x55\xe8\x01\xd1\x93\x6e\x17\x05\x60\x56\xf5\xe1\x02\x9c\x96\x2a\x30\x44\xcb\x5a\x7b\xcf\xa7\x51\xcc\x41\x5b\xb5\x57\xf6\xd4\x18\xa3\xb4\x58\xa7\xcd\x1f\x51\x76\x3d\xdd\x93\x0a\x1d\x68\xd8\x6f\x63\x2c\xe4\xe9\x9e\x78\x1d\xf4\x98\x47\x45\x42\xa7\xc3\xda\x18\xb3\x3d\x7a\x6e\xb4\x60\xf1\x2a\xe0\x57\xad\x4f\x49\xda\x12\xf7\x82\x46\x1b\x55\x60\x6c\x54\x01\x84\x5a\xa2\x0a\x2a\x85\x85\x6d\x36\x4a\x62\xef\xdf\x57\x2a\x5b\xa9\xc1\xb0\x2e\x47\x7d\x08\x7d\xa1\x9e\xb0\xca\x7e\x15\x8c\x98\x34\x39\x84\x58\x76\xad\x1c\x1e\x10\x22\x6a\xac\x58\xed\x7e\x61\xb4\x97\x7d\x1a\xcb\x35\x7b\xa9\x3e\x1c\x0e\xda\xd8\xd2\xc8\x4a\x18\xd0\x8d\x16\x01\xbf\x78\x15\x8a\xcc\x9b\x4d\x1f\x1a\x7d\x62\x7b\x6c\x59\xb2\xbc\x14\x1a\x5c\xb4\xd8\x2b\xa6\x33\xb8\x66\xf8\xe5\x6a\x4e\x79\x0a\x58\x89\xcf\xcf\x16\x61\xb4\x88\xf2\x4b\x31\xab\x9b\xcd\xa1\xfd\x3a\x64\x1e\xdb\xf4\x8b\xa6\xa6\x33\x14\x20\x6e\x06\x4e\x52\x81\x72\xdc\x45\x45\x7e\xa0\xcc\x30\x1c\x97\x6a\x33\x1f\x86\x1e\x05\x5c\xe8\xcb\xfd\xfb\x6c\x58\x4e\x46\xd8\x65\xa8\x0f\xbd\x4a\xa7\x44\xa1\x28\xde\xbf\x1f\xd8\x79\x82\x5a\x9e\x40\xe4\xe1\xb8\x7f\x9f\xdb\x79\x78\x2d\x0f\x17\x79\xa2\x10\xb0\x7b\x01\x94\xe2\x71\x20\x94\x51\xc9\xa0\x45\x7b\xa5\xe0\x21\xd5\x52\xd9\xfc\x51\xd0\xed\x8e\x3d\x10\xf0\x98\xe7\xbc\x55\x7e\x43\x41\xb7\xab\xc5\x34\x01\x83\x63\x1b\x7c\x37\x38\x64\x10\xb1\x2e\xe6\x87\x81\xcf\xef\x07\x3e\x3c\x3c\xe4\x75\xf8\x42\xa9\x57\xf0\xf9\xd8\xb3\x81\x8b\x0f\xbe\xc5\x06\x4a\x35\x51\x1a\x90\xf7\x4e\x21\x97\x92\x81\x28\xb0\x2d\x31\x36\xd8\x59\x14\xac\x56\x94\x49\x1b\x0a\x69\xb1\x64\x91\xe5\xe9\x8a\xe5\x49\x5a\x59\x4e\xa4\x50\x00\x9c\x4f\x19\x4b\xe6\xcb\x8f\x99\x2c\xf2\xd1\xe9\x02\xbe\xd9\x38\x0e\xec\x3a\x1f\x9d\x6e\xd0\xed\x22\x0e\x6d\x15\x4c\x8c\xad\xd1\x80\xb8\x1f\x68\x63\x94\x13\xf0\x8c\xa5\xd1\x52\x72\xe0\xab\xd8\xda\xc2\x2f\x2a\x60\x79\xa2\x96\x16\xde\x35\xeb\xab\xaa\x95\x5c\x13\x54\xf6\x7f\x5a\x1b\xc4\xd2\x0a\x5f\x1f\xcd\x7a\x85\x04\xab\xcc\xbb\x85\x2c\x5b\x3b\x56\xab\xad\xf5\x6c\x91\xff\xac\x9e\xde\x47\xf5\xc7\x07\x31\x99\x2f\x79\x50\x66\x1b\xdc\xa9\x3e\x9a\xe7\x67\x8b\xfc\xf8\xa8\x4a\x36\xcf\x8f\xe3\x84\xd4\x5f\xee\x9c\xc8\x17\xc7\x98\x4c\x5b\x0e\x44\x0c\xf7\x7d\x76\xaf\x32\xc7\x18\xaa\x15\xe0\x90\x8c\xe8\x88\x8d\xc7\xbe\x2d\xfd\x18\xf1\x27\xe8\x74\xaa\xe4\x72\x03\x23\xa8\x46\x79\x44\xc6\xd2\x3a\x6a\x25\x5d\xcd\x4e\xba\x3b\x29\x53\x02\x88\x36\x09\x0b\x2a\x55\xed\x39\x28\x32\xa9\x86\x97\x64\x97\x0b\xf6\xac\x71\x62\x2c\x32\xb3\x35\x27\xf5\x42\xb0\x66\xed\x9c\x6a\x4b\xbc\xde\x55\x29\xfc\xdd\x4d\x98\x3d\x08\x54\xf8\xbb\xbb\x22\x11\x51\x16\xec\x3d\x7b\x22\x5d\xec\x38\x8a\xd3\x30\xdc\x47\x81\xae\xb4\x2e\xb6\xb3\xd2\xa0\x6d\x4c\xd9\xac\xdb\x35\x7a\xa7\xb6\x31\x03\x8e\xc8\x88\x8f\x21\xd2\x7b\x52\x45\x11\x48\xae\xbd\xdb\x52\xb3\x3d\xa5\x47\xdd\x6c\x96\x94\xe6\x25\xcd\xec\x8b\xc2\x0f\xae\xd2\xef\xa0\x2a\xd9\x64\xe4\xe6\x8b\x3c\x8d\xae\xc2\xb9\xca\xd4\x48\xaf\xfd\x26\x9e\x36\xa2\x88\x8d\x8b\xbd\x1c\x2b\x8c\xe2\xf8\x4a\x3c\x12\x05\x66\x24\x2d\x46\x23\x98\xfb\x0e\x63\xef\x23\xde\x65\x50\x92\x7d\x25\xad\x06\x9b\x4d\x70\x9f\xc3\x40\x50\x29\xc3\xfa\x02\xe8\xf7\xef\x07\x52\x7c\xa8\x15\x0c\xb4\x05\xb3\xe2\x91\x82\xdf\xfa\xec\x5e\x20\x97\x9b\xe2\x09\x63\x4c\xb7\xc9\x76\x53\xd7\xe2\x2b\x9a\x2c\x69\xc5\x1f\xe9\x70\xe0\xd1\x92\xe6\x30\x21\x04\xaa\xfd\x11\x9b\xbb\x5a\x1b\x24\x8a\x6b\x8d\x7d\x55\x77\x94\xc9\xbf\x80\xc3\x4e\xa7\x7f\x8f\x0e\x01\xdf\xde\xf1\x92\x8d\x52\x9a\x18\x47\x54\x88\x8b\x6a\xa3\xd0\x25\xcb\x65\x7c\x09\x18\xe2\x10\x7a\x7a\xef\x90\x97\xab\x97\xed\x9d\xbd\x98\xe4\x2f\xc8\xf2\x8a\x42\x4e\x65\x38\x1d\x8d\xf5\xd6\xa1\xdd\x2d\x6b\x13\xb1\xdc\x3c\xd4\x5c\x13\x71\xa4\x76\x99\xea\xfd\x0c\xe1\x30\xb0\x9b\x2f\x24\x02\x4f\xa5\x80\xb0\x6c\x7d\x50\x6f\x7d\x98\x26\xf3\x2b\x63\x1c\xd3\x06\x15\x21\x05\xd9\x86\x43\x43\xed\x8c\x0d\x6f\x34\x46\xe1\xf5\xb6\x89\xe9\xee\x36\x71\x14\x82\x06\xe5\x35\x14\x08\x12\xaa\x01\xa1\x75\xf3\x7a\x1b\x88\xa1\xaa\x6f\xfc\x72\xd5\x7d\xa6\x0a\x04\x28\x54\x7a\x02\x9a\x74\xbb\x10\x16\xa5\x10\x53\x59\xf5\x91\x36\xd4\xfb\x22\xc7\x76\x69\x3a\x9a\x8c\xd1\xa4\x52\x6a\xf9\x1e\x5c\x9f\xf1\xcb\x9b\x11\x8c\x4a\xb1\x50\xb4\xa2\xac\x23\x09\xaf\xb4\x86\x74\x72\x35\xc5\xc0\x6c\x2d\x65\x7b\x69\x8f\x1c\x98\x6f\x45\xe7\x5a\x4c\x35\x5c\xcc\xcd\x27\xb2\x67\x2e\xb5\x36\x91\xf1\xfc\xb5\x69\xc5\xab\x10\x7e\x22\xb8\xf1\x83\x32\xfc\x49\x5b\x0a\xf1\xf5\x4e\x6a\x4c\xf0\xfa\x4f\xaf\xdd\x2f\xd0\x9c\xe0\x75\x21\x4d\x2b\x73\xe2\x7e\xfc\x28\xbb\xf5\xf1\x23\x8e\x89\x3f\x23\x78\x4e\xdc\x3f\x8d\x99\x4f\x9b\x38\x08\x5c\x17\x33\x82\xdb\x83\xe2\x13\xc1\x33\x32\xb4\x77\xc8\xe1\xda\x06\x41\x45\xeb\xad\x04\xa1\xd3\x35\x0a\x97\xa4\xeb\x18\xc1\x92\x5f\xe4\x7c\x91\x45\x34\xe6\xd6\x7e\x5c\xe1\x49\xd3\x93\x68\xf7\x82\xe0\x4f\x44\xcc\x6a\xb5\x1d\xbe\x6f\x23\x22\x14\xc2\x42\xc9\x8c\x73\xd5\x3e\xfd\x79\x7b\xb3\xde\x9d\x92\xec\xd5\xf9\xc2\x6c\xfb\x6b\xf7\x0a\x44\x61\x21\x26\xfc\x0f\x4e\x66\x3b\xe4\xc9\x12\xa4\x67\xa5\xfc\x0a\xa6\x5d\xc5\x07\x52\xb2\x08\x92\x39\x80\xdd\x01\x2c\x65\x4f\x20\x79\xc9\x0c\xae\x67\x78\x01\x66\xd5\x12\x8c\xfd\x36\x88\xf1\x6c\x6b\x01\xc6\x38\xd6\x4b\x4e\xc2\xce\x78\x0e\xe2\x51\x7f\x8c\xe2\xd1\x60\xbc\xbd\x87\x61\x6f\x5c\xcc\x14\xf1\x8b\x0d\xae\xcc\xf4\x30\x56\xdb\xfe\x38\x36\x9b\xd9\x78\xb6\xd9\xd4\x24\x3d\x6b\x0b\x84\x0b\x48\x51\x08\xda\x39\x98\x89\xa5\xab\xa1\x2a\xbb\x5f\x40\x44\x22\xd2\x22\x48\x5c\xd8\x0d\x0a\xab\x26\xa8\x61\x1e\xcd\xc6\x7e\xdc\xe9\x80\xf2\x0d\xdb\xb6\xf6\x28\x04\x4b\x5b\x40\x62\x46\x9e\x5e\xfa\xa5\xd2\xfc\xa8\xc4\x0a\xb0\x84\x9d\x8e\xf8\x35\xc8\x11\x83\xa5\xde\x7a\xa9\x4b\x4e\x6d\xb2\xd9\xb4\xcb\xe5\x40\xe2\x6a\x9f\x50\xa0\xba\x32\x2c\x5a\x9f\xc1\xba\x80\x28\xde\x49\x39\x58\xca\x0e\x13\x30\x1a\xcd\xd0\xd1\x18\x8d\x62\x74\x3c\x1e\xcb\x79\x3c\x6a\xe3\xa5\x3b\xe1\x39\x98\xc1\xcd\xe6\xd8\xbc\xc4\xb0\xaa\x68\xe9\x2a\x25\x4d\xcc\xf5\x52\x4d\x20\x3a\x31\x0d\x6f\x2f\x05\xce\x81\x19\xec\x74\x4e\x70\x59\x58\xaf\xb1\x0b\x83\xa8\x42\x9a\x03\xb0\xd2\x30\x14\xc5\x76\xbe\xd7\x1a\xd6\x34\x0a\x02\xbe\xf8\xe8\x74\x6b\x38\xe7\x0b\x9a\x91\x72\xfe\x59\xac\xa1\x10\x38\xcb\x94\x9f\xf1\x45\xae\x07\x31\x59\x64\x2a\x59\x74\x52\x0b\xa0\x53\xdc\xaf\x99\x0a\x33\x6e\x49\x8f\x33\x14\xab\x11\x15\xb8\x55\x37\x6a\x9b\xdd\x4d\xbd\x40\x5a\x33\x7e\xe9\x40\x5f\x76\xd8\xc2\x9c\x5a\x11\x2b\x6b\x2b\x24\x51\xec\xb5\x9c\xee\x0c\xfa\xb3\xd1\x64\x3c\x52\x8b\x68\x8c\xe3\x9a\x54\x54\xdf\xc7\xa9\xb5\xac\x12\x45\xe5\x40\xaa\xfa\x86\x36\x2c\x23\xe4\xd6\xf7\x00\x48\xf6\x65\x20\x07\x13\xf5\x20\xb8\x96\xb6\x99\xd7\x21\xa8\x89\xfd\x5a\x4b\xb6\x61\x0c\xb5\xd2\x5e\x6b\x60\x7b\xb0\x63\x4b\xfb\x12\xad\x31\x06\xc5\x75\x59\x6a\xea\x66\xda\x4e\x87\xa7\xee\x94\x93\x00\x4f\x6d\xea\x20\x0d\x9b\x6a\x39\x4e\x5d\xe2\x57\xfa\x55\x7d\xbd\xc4\x7a\xdf\x2f\x96\x20\xda\x32\xaf\xa4\x41\x99\xaf\xd3\x45\x0d\x6d\xac\xbe\xfb\x06\x25\x63\x6d\x0f\x45\x5b\x1e\x71\x33\x81\xcc\x7e\xac\xf6\x0c\xbe\xa8\x7d\x40\x9b\x78\x59\x8d\x9d\x75\x3a\x25\x05\xab\x68\x57\x5c\x27\x58\xf1\x30\xd4\xcb\x68\x18\xe3\x50\x2f\x47\x0f\xc4\xd8\x71\xba\xad\x6e\x77\x82\x42\xb9\xee\x04\x0a\x43\x2f\xc6\xce\xf2\xa3\xd3\x9d\x49\x94\x5f\xe2\xa9\x4b\x47\xb1\x94\x96\x96\x62\xa2\xa6\x2e\x15\xb9\x44\x67\xd5\x26\xe6\xd2\x08\x94\x53\x23\x50\x5e\xe0\xe5\x68\x2a\x4b\xcc\x04\xed\xec\x74\x2e\x84\xc0\xd2\xc6\x58\xfe\xdd\x6c\x66\x58\x3f\x1a\x2f\xb5\x28\xf0\x62\x14\x47\x59\xee\x2d\x91\x34\xbd\x79\x53\x14\x7b\x17\xa5\xd7\x9a\xfd\xfd\x40\x65\x38\x1c\xa0\xb8\x1c\x1b\x8b\x18\x4f\xcb\x6d\x71\xc1\xad\x15\xb7\xa1\x40\xef\x1d\x64\xd1\x67\x21\x07\x47\xa1\xdc\x8c\xc6\x42\xb4\x2c\xb9\xcb\xcc\x6f\x83\xca\x90\x6b\xb8\xcb\x0c\xcf\xb6\xb9\xcb\x4c\x70\x97\x99\xe2\x2e\x8d\xe4\xb4\x41\xf9\x17\x44\x96\xec\xea\x7c\x8d\x79\xbf\x48\x8c\xa7\x75\xd2\x7b\xe1\x9d\x14\x10\xcd\x34\xf1\x5d\x80\xd1\x68\x8a\x9c\xcc\x19\x8f\x95\x3e\xe6\x64\x4e\x1b\xcf\xe4\x74\x4f\xe1\x66\x33\x10\x2f\x62\x0c\x36\x1b\x95\xa8\xca\x8b\xb7\xcc\xbc\x21\x27\x77\x60\x5b\x30\xbc\x23\x93\xbb\x6a\x85\xc6\x38\xd3\x7c\x50\x33\xfd\x0b\x04\x91\xa3\xb6\xd9\x68\x83\xff\xa8\x3f\x6e\xe3\xe9\x66\x23\x9b\x61\xd2\x06\x96\x2b\x8a\x55\xda\x30\x33\x0d\xe1\xa4\x2a\xd0\x1f\xbb\x17\x9b\xcd\x81\x93\xd7\x80\x6c\x36\x6d\x53\x56\xed\x0d\xb4\x07\x42\x4c\xbb\x02\x5f\x50\x7b\x72\x9a\xbe\xfa\x7c\x1f\x39\x97\x4b\x6c\x8a\x85\x96\x38\x1d\xf6\xbd\xa9\xee\x7c\xa0\x44\xd2\x29\xf4\x63\x57\x60\xe4\x66\x03\xd4\x83\xde\xcd\x1c\xc5\x6e\x14\x8c\xf1\x68\x2c\x33\x0c\x63\x57\x4b\x27\x78\xe6\x89\x8c\xda\x7a\xa1\x10\x13\x65\x66\x2f\x27\x43\x82\x5a\x98\xe4\x19\xbf\xf4\xa6\x86\x40\x14\x48\xc1\x57\x9a\x42\xec\xc6\x10\x99\x42\x8a\x98\xc5\x6e\x5c\xa6\x54\x2f\x62\xe2\xba\x5d\x58\xe7\x10\xfc\x0b\xa4\x59\xae\x88\xaa\x77\x25\xd1\x8c\x3b\x9d\xa9\x6c\xc0\x10\xa8\xbf\xd2\x42\xc6\x38\x98\x2a\x2b\x39\x1a\x40\xa4\x3f\x18\x23\x81\x65\x73\x75\xe9\x68\x2a\x06\x44\x64\x31\x0d\x16\x8f\x92\x16\x9a\x07\x49\x98\x63\x31\x08\xae\x22\x9b\x92\x1c\x56\xfd\x38\x3c\x44\x07\xed\x3e\x94\x2c\xc0\xee\x02\x8b\x39\x49\x71\xcd\xab\x61\x6b\xe5\x97\xe3\xb2\x45\x02\xea\x70\x6a\x7c\xae\xd4\x36\xdb\xed\x72\x34\xdc\xb8\x5e\xa0\xc6\x5d\xcb\x02\xc0\x1a\x3f\x37\x86\x62\xdc\xe4\x1c\xd6\xcb\xea\xb5\xd3\x60\x27\x62\x5b\xda\x4e\x09\x78\x34\x15\xc4\x12\x69\x70\xe3\x02\xd6\x21\x0a\x65\xf0\x3a\xe0\x5a\x12\xdc\x36\x14\xa5\x9d\x5d\x13\x8e\xea\xdf\x16\xa4\x30\x49\x1f\x11\x7b\xf3\x75\x6b\xcf\x50\xce\x83\x45\x42\xfc\x36\xb0\xb6\x0b\x35\xe1\x5d\x9a\xb5\x8e\x0e\xa6\x4a\xcd\x98\xa1\xe5\x68\x30\x46\x4b\x41\x7e\xa5\x75\xa2\x56\xeb\xae\x21\xae\x61\xd0\x7d\xa3\xc9\x97\xea\xb5\xd4\x7c\xa5\x54\x48\x58\x92\x5d\xc5\x97\x0f\xae\xa9\xb1\x55\xd1\x72\x99\x48\x08\x71\x32\x01\x54\x89\x98\xd9\xbf\x69\x0e\xe8\x2d\x7a\x38\x80\x46\xbd\x56\x95\x64\xd1\xe2\xfa\x95\x44\x21\x90\xc6\x2a\x43\xc7\xa8\xb6\x86\x96\xb5\x2a\xd8\x34\x03\x14\xd6\xeb\xef\x0e\x2a\x5b\x42\xff\x3e\x1d\x1e\x32\xaf\x34\x2e\x99\xd2\x83\xab\xd8\x93\x76\x1a\xe4\x1e\xdd\xbe\x4f\x3b\x9d\x43\xf7\xe8\xf6\x3d\x5a\xcd\x2e\xc3\x14\x05\x78\x80\x38\xa6\x28\xc4\x7d\x34\xc1\x03\x3f\x6c\x63\xee\x43\x76\x0b\x53\x34\xb9\x85\x0f\xc5\x47\x10\x62\x0e\xbb\x93\x5b\xac\xd7\xed\x06\xd5\x6c\x6c\x8f\xe6\xa0\x4b\xeb\xc3\x97\x93\xed\xe1\xab\xef\x2c\xa8\x9d\x83\xaa\x67\x3b\x87\x14\x1a\xb7\xe3\x00\x05\x0c\x1e\x52\x70\xc8\x20\xec\x1d\xd9\x15\x32\xba\xcf\x81\x6f\x6b\x74\x76\xa7\xc8\x1e\x2f\x6b\xba\x96\xc9\xb9\x3d\x5d\x68\xd0\x3b\xfe\xf2\x0c\xb1\xf8\xf3\xf1\xd1\x75\x67\xe8\xfe\xfd\xfb\xfd\x1d\xb4\x39\x3e\x32\x56\x74\x5f\xa4\x03\xda\x39\x39\xba\x7b\x72\xb7\x3f\xf8\xe9\x4e\x1f\x76\x3a\x80\xde\xbb\x87\x07\x77\x10\xeb\xe2\xc1\x1d\x58\x65\xf9\xe9\xe7\xc1\xdd\x7e\xff\xe7\x32\xcb\xcf\x22\xc7\xcf\x55\x86\xfe\xd1\x9d\xdb\xc7\x83\x9f\x4f\xca\x0c\x27\x22\xc3\x49\x99\xe1\xf8\xe8\x68\x70\x74\x74\xfb\xe4\xa7\x23\x93\xe1\x48\x64\x38\x2a\x33\x1c\x0d\x4e\x7e\x3a\xf9\xf9\xf8\xce\xc9\xcf\xb0\xd3\xa9\xec\xf6\x2d\x56\x9b\x89\x9d\xd5\xb9\x77\xe6\xf9\xc5\x75\xe6\xbd\x6b\xcf\x7b\x39\xea\xfc\x62\x39\x1f\xfc\xdf\xad\x0b\x6b\x4d\x88\x15\x50\xae\x08\xd6\xbc\x16\xf8\xc5\x12\x50\x78\x38\xb0\x07\x24\x4c\x93\xd5\xb6\x07\x7b\x7d\x48\x6a\x36\xb1\x76\x69\x14\xb3\xf7\xbe\x60\xc3\x38\x95\xa3\xaf\xc7\x54\x48\x4b\x76\x19\x30\x80\x4d\xc3\x4b\x47\xfd\x71\xe5\x82\x2b\xde\x6a\x03\x3a\xbd\x5c\x26\x57\x5e\x4a\x47\xf7\x4b\x6b\xa2\xd9\xd6\x31\x99\xb7\xd2\x87\xe5\x5a\x2a\xbf\x8c\xfa\x63\xe8\xf5\x15\xaa\xa3\x00\x71\xbd\xbf\xc0\xe5\x66\xde\x76\x79\xb9\xcb\xc0\xab\x3d\x09\x8e\x1a\x00\x32\x2d\x4e\x0f\x1e\x0d\xfa\xfd\x7b\x7c\xb3\x19\x3c\x3a\x1c\xf4\xfb\xf7\xd5\xc6\x70\xbb\x3c\xc2\x62\xaa\x0a\xf6\x57\xa5\x0d\xee\x1a\x65\x6a\x55\xf4\xb8\x1f\x74\x71\x78\x2b\xac\x4d\xbd\xa4\xe4\x01\xbc\xc5\x8b\xaf\xc2\x6e\x06\x8b\x14\x50\xbf\x01\x68\x6d\x82\xa2\xf9\xea\x6a\x3b\x43\x75\x94\xb7\x57\x95\xda\x6c\xa0\x9d\x3b\xb7\x6f\x1f\xdf\x46\x1c\x33\xf5\x54\xee\x7e\xdd\xe2\x5d\x00\xe8\xfd\xfb\xf7\x07\x77\xd4\x17\x78\x8b\x77\x83\x5b\x80\xd9\x49\xf7\xee\x0d\xee\x08\xf2\x05\x37\x7d\x1b\xdd\x05\x39\xef\x5f\xc7\x34\x5d\xb1\x64\xd8\x93\xcf\xcf\x5f\x0e\xb6\x21\x5e\x8d\xae\xee\x07\x58\xe3\x15\x59\x34\x59\xfc\x57\xf9\xa1\xaf\xbc\x5f\xa2\xec\x25\x79\x09\x28\x1c\x52\xaf\x7f\x8f\x0e\x07\x9e\x5a\xf2\x07\x55\x15\x57\x66\x7f\x57\x26\x82\xea\x78\xc5\x90\x79\xfb\xb9\xe0\x2e\xd7\xbd\xa9\xd0\x22\x08\xda\xe1\xd1\x2d\x8b\x11\x0a\x4c\x02\x83\x43\x06\x7b\x60\xd0\x65\x8d\x2c\xb1\x6c\x4e\xba\x5a\xb0\xff\xd2\x1e\x33\xbc\x9b\x8d\xe5\x70\x43\xeb\xfe\x37\x74\xb3\xd9\xdf\xec\x30\x4e\x92\x14\xd4\x5a\xdd\xdc\x4e\x55\xad\xfb\xe8\xf5\xdb\x67\xcf\x5f\xbd\xb4\xda\x5a\xc7\x26\x21\x0c\x1c\xa1\xc3\xdb\x47\x50\xcf\xb2\x2e\xf7\xe2\xf4\xcf\x8f\x6f\x4f\x1f\x3f\xfa\xf8\xec\xe5\xbb\x47\x4f\x1e\xbd\x69\x02\x70\xb7\xdf\xff\x69\x70\xf7\xae\x60\xac\x27\xfd\xbb\x77\x07\xb5\x8a\x5f\x3c\x7b\xf9\x35\x00\x87\x5f\x04\x10\x65\x8f\xc5\x88\xf0\x6b\x2c\x10\x67\x21\x8b\x5a\x9c\x86\x4a\xa5\xdc\x8c\x7a\xa7\x63\x86\x59\x39\xad\x1d\xda\xaf\xc5\x56\xed\xcf\x16\x39\x9f\xf0\xfd\xce\x0a\x0d\xeb\x73\xab\xe5\x72\x19\x61\x6c\x4f\x1c\x95\x2a\xe4\x56\x4d\x2f\xc9\xcb\xff\xd0\xc9\xca\xdb\x83\x76\x3a\xa6\x87\x45\x7d\x16\xa3\xec\x2d\x09\xf9\x4d\x7a\xa2\xcb\xca\xc1\xb3\xb0\xee\x1e\xde\x83\x27\xf5\xbe\x2d\x49\x9a\x71\xc9\xb9\xf7\x6d\xfd\x54\x39\x76\x0b\x3e\x5b\x7c\xb9\xd8\xb3\x45\xae\xb7\xdf\x92\x2f\x9d\x1f\x25\x99\xa0\x8b\xc3\xda\x9b\x57\xdf\x0b\xab\x64\xa4\xc1\x17\xd9\x66\x80\x6d\xc6\x26\x16\xb4\x72\x32\x93\x5b\xc2\xad\x68\xd1\x0a\x60\x0e\x02\xc4\x85\x98\x49\x46\x7c\x8c\x83\x11\x1f\x5b\x2e\x31\x7e\xe5\x7e\xa9\xda\xb1\xaf\x7f\x09\xa9\x3b\x6b\x5e\xd9\x43\xa3\x3c\x0f\x35\x1a\xa3\x40\x0a\x03\xd2\xf5\x8d\xc2\x1c\x50\x14\x08\xe9\x56\x59\x71\x46\x01\xa2\xa3\x60\x3c\x86\xdb\xa2\xae\xae\x30\x4c\x93\xf9\xa3\x6b\x57\xba\x2e\xd4\xd9\xcd\x2d\x4d\x58\xb5\xa0\xd9\x5b\xcd\xe9\xd2\x6a\x4f\x51\x16\x50\x3b\x8a\x14\xef\xee\x97\xef\x6c\x89\x07\xe5\x66\xb8\xdf\x0e\x94\xda\x5e\x25\xc1\x75\x80\x03\x7d\x96\x37\x0a\xf5\x9e\x16\x08\x60\x1b\xe3\xa0\xb9\x2d\xa6\x7a\x79\x22\xd2\x1a\x81\x56\x36\x4d\x56\x71\xd0\xba\x8c\x78\x1c\xe8\x13\xb1\x99\x03\x7d\x36\x0a\x46\xfd\xb1\x98\xe5\xc1\xb8\xd8\x1a\xc7\x37\x3c\x8c\x39\xdb\x2f\x6f\xae\x8b\xfa\x0c\x4f\x78\x6e\x6d\x6b\xaa\x9e\x5f\x63\xa7\x7a\x34\xae\xd7\xeb\x26\xe7\x8b\xdf\xae\xb4\x45\x5f\xc3\x18\xdc\xd8\x9a\x97\x64\xce\xc5\xaa\xf7\x69\xf3\x77\xdd\x5a\x7b\x66\xf4\x39\x71\xdb\xd3\x63\xc7\xdb\x10\xcb\xe5\xe1\x66\x2b\x9a\xa9\x5d\xd7\x3e\x1a\x9c\x08\xc9\x83\x41\x85\xa4\x72\xf5\x94\x08\xea\xb2\x64\xc1\x48\x0e\x4a\x85\xbc\xb1\x2d\x0f\xb5\x33\x62\x92\x5e\xad\xef\xd5\xd2\x5f\x17\x28\xc0\x5b\xc3\x27\xf4\xe3\x86\xae\x88\x89\xe7\xe3\x71\xf3\x68\x54\x2d\x10\x4b\xae\xd6\x85\xad\x39\xaf\x6f\xfe\xef\xa3\x05\x0b\x52\xeb\xee\x55\x7d\x18\xae\x4a\x09\x04\x19\xd8\xa1\x02\xfa\x98\x8b\x4b\xe2\xf8\xad\x3a\xe1\xb2\x77\x9b\x2b\x28\x7d\xd6\xb2\x9c\xe4\xab\xcc\x73\xc2\x55\x1c\x46\xb1\x2c\xa3\x2c\xc8\x41\x6d\x13\x7c\xb7\x80\x3a\x30\x20\xf2\xa7\x9c\x64\xc9\x42\x14\x68\xea\x52\xcd\x21\xcc\x0f\xb0\xe5\xfb\x11\x54\xcd\x0b\xcb\xf1\xe0\xe6\x58\x02\x08\xa1\x3a\x70\x21\x94\x87\xa2\xf2\x6d\x71\xa5\xcf\x4b\xc9\x35\x4d\xaf\x6b\x47\xb4\x49\x1c\x5f\x5e\x87\x75\x56\xa7\x3b\x1a\x54\x5a\x53\x83\x69\x17\x05\x10\x6e\x65\xae\xb9\x97\xa0\xff\x0a\x43\xd1\x37\xe6\x17\xb0\xf4\xae\x31\xa8\x2d\x3d\xa7\xbe\x2e\xc3\x3f\xd6\xdf\xad\xd1\x90\x25\x77\x65\x7a\xe5\x13\x6e\xa4\x55\xe3\xc8\x25\x12\xe5\xc0\xca\x3d\xbc\x2f\x31\x68\x96\x72\x92\xf3\x61\xed\xcd\xdb\xbb\xa9\x5a\x58\xbb\xbb\x98\xd8\xfe\xcc\xb4\x40\xff\x92\xc6\xd3\x83\xc4\x7e\x91\x6e\x18\xca\x39\xc2\x0c\x49\xe9\x22\x0d\x18\x1a\x8d\x6d\x49\xb5\xa8\x7b\x4c\xd7\xdc\x1f\x8a\x28\x04\x4d\x1e\x60\x1a\x6a\xa7\xb3\x03\x5e\x8d\x74\xb5\x1d\xb4\x93\x41\x8f\xfd\x6e\xfa\x9e\x41\x97\x6e\xf7\x28\x80\x3e\xaf\x6a\xab\x53\x15\xc0\x90\x85\xd0\xf6\x42\xdf\x03\xb2\xf2\xdc\xef\x74\x00\xc7\x0c\xfa\x1c\x2f\x09\xe0\x76\x10\x8d\x9d\x08\x1a\x06\xec\x3e\xa4\x31\x48\x71\xc0\x51\x00\x37\x1b\x5e\x14\xa0\x86\x93\x65\x47\x9b\xf4\x8c\x7f\x49\x1d\x81\xeb\x81\x3f\xae\xec\xd9\x97\xa7\x97\xeb\xc6\xd0\x21\x3a\x83\x76\xec\xfb\x3a\x4d\xaf\x74\x43\x3e\xe4\xae\xed\x33\x8d\x31\x06\x41\x2d\x65\xb3\x69\x0f\x60\xa7\xc3\x5d\xbe\x58\xcd\xb9\x95\xa9\x7a\xd7\x59\x80\xa3\xce\x9c\x47\x0a\xac\xda\xb2\xc3\x46\x82\x11\x20\x8c\x37\xb6\x02\x60\xde\x64\x71\x4f\xed\x08\x89\xec\x13\x9e\x8b\xcc\x99\x7e\xcd\x78\x2e\x75\x0e\xb5\x2d\x19\xda\xdb\x92\xdb\xa3\x1a\xf3\xfc\x7a\xa3\x6a\xbc\x8e\xc4\x63\x79\x50\x46\x6e\x14\x1b\x7b\x8b\xda\x86\xa3\x23\x36\xd6\x0d\x08\xb6\x1a\x70\x60\xb5\x60\xdf\x90\xef\x63\x8c\x5f\x99\xa9\x7a\xf7\x26\x57\xe2\xb5\x15\x48\x2b\xb3\xed\x9c\x96\x92\x4a\x63\xf0\x89\x6f\x78\xec\xd7\xba\x20\x0b\xc9\x63\x29\x65\xe4\x15\x9f\xe0\xe6\xb6\xc9\x00\x41\xf5\x96\x5f\x19\xc7\xa5\xe5\x12\xef\x33\x5d\x8a\x79\xd0\x58\x9e\x12\x85\xc8\x51\x08\x2a\xe3\xa1\xa8\x6a\x28\x7f\xb5\x37\xa8\xc0\x2b\xb5\xc1\x56\x1f\xcc\x29\xb9\xe6\xe1\x31\x26\x45\x8f\xed\x09\xb7\xdd\xc5\xf6\xc2\xdb\xcf\x37\xec\xe2\xc3\x86\xb4\x5d\x29\xb9\xdd\xdf\xea\xc8\xae\xc3\xd5\xd7\x9b\xb1\xed\x26\xb1\x03\x63\xb8\x5b\xef\xa0\xa8\x89\x0a\xfb\x4a\x56\xf6\xb8\x76\x93\x47\x5d\xa5\xdf\x5b\xb4\xfe\x8a\xb8\x51\x1d\xdb\x32\x53\x6f\xe8\xff\x50\x7a\xde\x0c\x81\xfc\xa3\x26\xfe\x78\x47\x07\x1e\x72\x4f\x48\x8d\xa8\xdd\x87\x5e\x58\xd2\x9e\x4e\xa7\x6a\xe7\xe3\x34\xf9\x2c\x24\x2c\x38\x04\x02\xcf\x70\x80\xd4\x86\xb9\xd7\x34\xdb\xbb\xd9\xb6\x26\xe6\x2a\xa2\xf1\x90\x78\x0b\xcb\xab\x55\xe2\x9b\x45\x7c\x16\xaa\x9f\xa8\xf4\xc9\xa8\xd1\x1e\xe5\xa8\xaa\x0f\x0e\x6d\x8f\xa2\x25\x70\xb0\x2a\xee\x04\x3f\x6f\xbd\x20\x4b\xb5\x8a\xd7\x0c\x0b\x99\xac\xd2\x44\xfd\x36\x08\x30\xdb\xda\x42\x56\x25\x83\x00\x68\x2a\xae\x03\x42\x48\x0f\x00\xe3\x18\x10\x7d\xe6\xff\xff\x3b\xf1\xb0\x26\x27\x9e\xa0\x72\xe2\x31\xfb\x0d\xed\x40\x3a\x6d\x31\xe5\xba\x13\x68\xd7\x9d\x40\xf6\x89\xc1\x36\x0e\x1a\xd2\x15\x34\xf9\xed\xc8\x7c\xab\x3b\xf0\x70\x1c\x58\xbb\xef\x21\xe6\x96\x03\x4f\xa8\xdd\x6f\x42\xcb\x81\x87\x55\xaf\x03\xf1\x5a\x41\xb3\xca\x1a\x74\xde\x29\x2f\x0f\x38\x9e\xb4\x71\x58\xf7\xe6\xb1\x21\x56\x9f\x86\xed\x81\xc7\x6d\xaf\x1e\x8d\x3b\x93\x7d\xfe\x3c\xb6\xaf\x21\x09\x02\x5c\x37\x75\x2b\xcb\x76\xdf\x63\xbe\x99\x6e\x2e\x64\x4c\x66\xbb\x82\x58\x88\xb0\xdf\x9b\x72\xdb\x57\x46\x42\xd7\x25\xb5\xef\xea\xd7\x80\xb2\xad\xe3\xe9\x8d\xae\x2b\x44\xa5\x6f\xfb\xaa\xec\xf5\xc9\x64\x5b\x87\xf3\x34\xba\xd4\x4b\xec\x77\x38\xd1\x85\x4a\x64\xa8\x97\xdb\xeb\x10\xa2\x8b\xa9\xef\xdb\xa5\xa4\x33\xca\x2e\x18\x3b\xcf\xae\xab\xc6\xc1\x97\x0b\xec\x7a\x94\x6c\x1d\x4f\x32\xf3\xab\xf3\x81\x06\x6d\xb4\x3a\xa0\x81\x42\xb4\x73\x32\xbb\xe9\x48\x31\x4b\x02\xfe\x3a\x89\x16\xf9\xe9\x7f\x8e\x84\x64\x83\x10\x2b\x9c\x19\x33\x86\xb5\x31\xb1\xd9\xa8\x9d\xfa\x7b\x98\x76\x3a\xf4\x5e\x00\xd7\x32\xea\x91\x3e\xc5\xe6\xb2\x29\x49\x1f\x24\x01\x3f\xcd\xf5\x26\xc6\xed\xdb\x47\x77\xef\xdc\xe7\x9b\xcd\xed\x3b\xc7\x83\xbb\xf7\xf8\x66\x43\xbb\x03\x21\x6c\x56\xbb\x90\x74\xab\x5c\xb7\xda\xb1\xbd\x7d\xe7\xf8\x48\xc6\x64\xba\xfd\xd3\xf1\xc9\xf1\x3d\x3a\xe4\xde\xa0\x7f\x74\x72\x0b\xf0\x43\x09\x18\x76\x69\xf7\xee\xd1\xe0\x4e\xb1\x15\x42\x49\xa8\xf9\x0f\x4c\x6f\xae\x69\xda\x71\x1c\x7d\xa8\x6a\xc7\xb4\x6b\x9d\xac\xda\xd9\xba\x0c\xc6\x3a\x80\x14\xdf\x6c\x06\x83\xc1\xc9\x60\x30\x10\x9d\xe5\xed\x9a\x49\x9f\xc3\x3d\x01\xa5\x22\xe5\x72\xfd\x51\x4c\xc1\xc7\xa5\x68\x75\xcb\xe9\x72\xe8\xcb\x4d\xc6\xfb\x98\x0f\x59\x17\xdb\x7d\xd3\xc3\x05\x38\xf4\x00\x3f\xc4\x22\x9b\x74\x85\x68\xcc\x73\xff\xfe\xfd\x41\xbf\x33\xe8\x1f\x1d\x6f\xd4\xa8\xed\xcd\xa9\x33\x89\x51\x87\xbb\xe7\xbb\x76\x70\x6e\x2e\xc8\xdd\xe9\x95\x8e\xe8\xa9\x88\x7f\xbb\xe1\xdf\x3a\x9d\x36\x75\xd5\xa9\x8f\x66\x3b\xab\xca\xd6\x5a\x92\x2c\x93\xa1\x53\x9a\x42\xc1\x99\x76\x00\xa8\xe2\xc1\x4d\xc9\x19\x37\x31\x09\x73\x32\x71\xcb\x03\x99\x72\xd8\x25\x40\x40\x51\x43\x6b\x86\x4a\xa1\xf5\x9c\x89\x5c\x00\x72\x6d\x70\xdc\x1e\xa0\x70\xf7\x1c\xa7\x72\xce\x5a\x17\x68\x2a\x16\x0a\xc9\x72\x19\xfa\xcf\x16\x92\xd7\xb6\x4b\x34\x32\x41\x44\x7d\x75\x4a\x81\xb9\xfc\x82\x33\x10\x28\xd6\x39\x2b\x97\x03\x6e\xf7\xd1\x9e\x82\x56\x35\x18\xe3\x69\xa7\x03\xac\x94\x2e\x1e\x40\x7f\x62\xbc\x37\xfd\x89\x64\x48\xd8\x0a\xa0\x56\x14\x7e\x78\x95\xf3\x9f\x61\x49\x6a\xc2\x7a\xd0\xc0\xcc\x1c\x7c\xd5\x07\x12\xdb\x18\x93\x61\x19\x01\xd4\x73\x5a\x4e\xb9\xbd\x78\x8f\x76\x3a\x64\x48\x74\x64\x36\xb5\x05\xc9\x78\x14\x03\xda\x2b\x4f\xbe\xc2\x9a\x31\x97\x42\x6f\x4f\x78\xbe\x25\x09\x1e\x5d\x39\xf6\x61\x2d\x6c\x9d\xa2\x6a\x4b\x12\xa8\xc8\x66\x25\x55\x09\xba\x19\x01\x0c\xd1\xc3\x32\x2e\xdd\xbe\x38\x0d\x65\xd9\x6f\x58\xfb\x76\xdd\xdd\x60\x5f\xed\x79\x1a\xcd\xdf\x44\x93\xe9\xb5\xe3\xbf\x95\xe1\xdf\xbe\x6f\x8a\xff\xb6\x37\xd4\xdc\xde\x61\xde\x13\xfe\x4d\xb6\x4d\x03\xfc\x83\x93\xd9\xd5\x45\x63\xe3\xce\x7c\x23\xf1\xf8\xbf\x9c\x0e\x62\x3b\x67\x81\x82\x9d\x14\x6e\x0e\x07\x31\x45\xd3\xdb\xbc\x94\x6b\xd5\x53\x60\x9d\x06\xe2\x96\x44\xc5\x55\xfb\x4a\xb5\xcc\x94\xeb\x74\x4c\xb9\x26\xcb\xca\x55\x05\xc4\x9a\x50\xd8\xee\xc3\xfd\xf2\xdf\xf5\x85\xae\x06\x89\xb1\x5e\xa8\xec\x64\xfd\x54\x8b\x18\xd2\x95\x24\x93\x9b\x8d\x8c\x42\x9b\x13\xdc\xfb\x67\xf4\xe1\xbc\xdb\xfb\x78\x38\xee\x8e\xf0\x78\xdd\x47\x47\xc5\xf7\x3d\x74\xae\x02\x4d\x55\xc6\x91\x0b\x52\x61\x18\x20\x98\xb8\xff\xae\x78\x7a\xf9\x96\x0b\x8d\x4e\x06\x4a\xae\x27\x00\x47\x99\x47\x46\x8b\x64\xc1\xf8\xd8\x81\x72\xdb\x14\x13\x57\xbe\x6f\x36\xc4\x9d\xf0\xfc\x34\xcf\xd3\x88\xae\x72\x0e\x1c\x99\x2c\x73\xe5\xc4\xcd\x79\x96\x03\x02\x85\x66\xee\x54\xbb\x0b\x67\x2a\x2a\x40\x63\xd8\x59\x8a\x57\x3a\x9e\x02\xb1\x37\x76\x05\x0f\xc3\x74\x44\x46\x6c\x3c\x46\xea\xf8\x78\xe9\x7a\x21\xbb\x57\x0e\x4e\x59\xcb\x79\xed\x20\xdf\xa5\x15\x93\xda\xe8\x69\x5b\x27\xf9\xda\x98\x0e\xa9\x47\x86\xf5\xc3\xcc\x04\x0e\x1d\x22\x43\x3e\x78\xd4\x73\x44\x5d\x56\x4f\x2e\xab\xa1\xb4\x2d\x20\xb2\xb2\x2a\xd7\xe7\xaf\xd7\x2d\x3d\x1d\xd4\x21\x42\x52\x3f\x92\x43\x8b\x8a\x11\x9c\x96\x71\xa1\x0d\xe2\x4a\x69\x55\x1f\xb3\x26\x2e\x8d\x16\x01\xb2\x0e\xd8\x96\x05\x7f\x21\x56\xdc\xd9\x36\xa9\x1d\x21\x53\xa7\xef\x76\x84\x2e\x43\x54\xb7\x4f\xe7\x66\x71\xc4\xb8\x3e\xd0\x69\x8a\xa0\xa3\x5d\x57\x3f\x23\xb0\x5d\xa5\xbc\x39\x40\x5e\xe5\x5a\x2d\xb2\x69\x14\xea\x6d\x10\xc0\x51\x50\x9d\x5e\xd5\x69\x54\xee\x5c\xec\xd6\xba\x93\xcd\x3e\x70\x5c\x4d\x89\x19\x8f\x06\x5b\xb8\x18\xc5\x4e\xe7\x70\xd0\x6e\xda\x5d\x11\x1f\xad\x13\xa8\x65\x04\x20\x67\x41\xf2\xe8\x8c\xb7\x84\x1c\xe9\xc0\xe1\x67\x7c\x4a\xbc\xcf\xf8\x97\x72\xeb\xe3\xb3\x6e\x8f\x64\x4e\x56\x93\xaa\xc9\xfd\xc5\x30\xf9\xda\xba\x50\xb4\x73\xe5\x93\x51\x7f\x1c\x2d\x5a\x6c\xb3\xb1\x36\x33\x4a\x5b\x9b\x92\x69\xde\xca\x85\xba\xd9\xd8\x6f\xc0\x11\x10\x9c\xae\x28\x6f\x53\x7a\xb3\xba\x64\xa8\x05\xe2\xca\xd1\x06\x10\xfa\x90\x94\xc7\x33\xac\xe8\x07\x6c\x14\x8c\x3b\x1d\xf1\xdb\xde\x8d\xcc\x3d\x0a\xc6\x43\x86\xc5\x47\x4f\xfd\xc1\xeb\xc2\x93\x7f\xad\xd5\xf8\x40\x5b\x64\x6b\xfb\x3b\x56\x44\x19\x5b\x17\xf4\x2d\xeb\x89\x3e\x20\x4b\x6a\x0a\x57\x19\x2a\x07\x5b\xe1\x41\x1e\x10\x9b\x73\x5a\xf1\xc0\x1f\xea\xcd\x33\x89\xee\x2e\x23\xcb\x7c\x95\xf2\xb7\x39\x61\xb3\x77\x29\x61\x1c\xee\x49\x57\xc2\xc4\x43\x58\x1d\xf7\xa6\x58\xaf\x18\x37\x13\xb9\x7c\xda\xe9\xa8\xb0\x7e\xf2\x15\x53\x58\x10\x93\x32\xe7\x59\x46\x26\xdc\x8a\xd3\x5e\x3c\x00\x0f\x91\x2c\x0f\xfd\x87\x56\x6f\x16\x64\xce\xb1\xf3\x60\x95\xe5\xc9\x5c\x7e\x76\xaa\x96\x3f\x52\x83\xa6\xf9\x37\xc1\x18\x3f\x24\x9d\x0e\xdd\x6c\x1c\xc7\x44\x2e\x7c\x44\x8a\x47\x16\xb4\x57\xb8\xdd\xf7\xed\x84\x17\x5f\x88\xd0\x53\xd6\xf3\xb8\x36\x74\xb6\x74\xfe\x48\xf0\x03\x7b\xc0\x31\x96\x49\x54\x3c\x08\x41\x93\x78\x8e\xa8\xe7\x23\x17\x4d\xf7\x1e\x88\x9c\x16\x7d\x7c\x6c\xc1\x15\x13\xf9\x08\x3c\x24\x88\x40\x79\xf4\xfc\x11\x11\x32\xfc\x43\x79\x5c\x5e\xbc\x3f\xc5\xeb\xd0\x5b\x17\x85\x7f\xf0\xd4\x0d\xdd\x67\x78\x3d\x25\xde\xda\x99\x64\x39\xc9\x23\xe6\xb2\x64\xee\x78\xeb\x38\x21\x01\x4f\xbd\xc7\xc0\x99\xe6\xf9\x32\xf3\x7a\xbd\xf3\xf3\x73\xd7\xca\xd3\x13\xfa\x6c\x9e\xf5\x7e\x58\x9f\xf1\x34\x8b\x92\x45\xd1\x53\x65\xdc\x4f\x99\xd0\x2c\x38\x5d\x4d\xae\x50\x5c\xe6\xb3\x81\x7c\xca\x7a\x9f\x32\xb2\x8c\x3e\xca\x2f\x1f\x7f\x58\x2f\x09\x9b\x91\x09\x2f\x3e\xce\x93\x60\x15\x73\x0b\xfc\xc7\x68\xf0\xf3\xe2\xbf\xd4\x21\xca\xd5\x6a\x11\x09\xbb\x55\x7d\xfc\xf8\xc3\x3a\x26\x8b\xc9\x4a\xa4\xa9\x7a\x59\x32\x5f\x46\x31\x0f\xae\x37\x30\x65\x9f\x4c\xf1\x7d\xdd\x2a\xbf\x5f\xb1\x67\xcd\x7d\xaa\x41\xb9\x5a\xb7\xb2\xec\x7a\xb5\xb1\x4c\xbc\x66\x2b\x1a\x44\x69\xd1\xfb\x61\x1d\x46\x31\x17\xeb\xab\x70\x20\x3a\x60\x59\x76\xf4\xdf\xc1\x0d\x8a\xf2\xf1\x68\x1b\x74\x3e\x8d\xd2\xe0\xe3\x92\xa4\xf9\xe5\xf5\x2a\xb0\x0a\xee\x6d\xb7\x95\xe7\x9a\xcd\x6f\x82\x7e\xc5\x6e\x7c\x9c\xf0\x6b\x4e\xf4\x15\xba\x52\xa0\x6a\x35\x2f\xbe\xbe\x98\x17\x37\x5a\xcb\x8b\x1b\x2e\xe5\x83\x2b\xac\xe5\xfd\x75\xfc\x1f\x2e\xe5\xa6\x61\xf9\xc6\x2b\xb9\xa9\x8a\xff\xb3\x85\xdc\x54\xd9\x97\xd6\xf1\x17\x97\xf1\xd7\x80\xdd\x74\x15\x37\xc1\xbf\xca\x22\x3e\xb8\xd2\x2a\xbe\x2a\xf4\x6f\xb1\x88\xff\x63\x4f\x8a\x02\xfd\xe5\x8d\x1c\x1d\xaa\xd6\x19\xa3\x85\x60\xd2\xe6\xd5\x1b\x8d\xd1\x24\x25\xcb\x69\xc4\xb2\x5a\xae\x55\xe4\x8d\x1c\xf3\x45\xbe\x7f\xa4\x24\xe3\xf5\xc4\x30\x26\xd9\x54\xe6\x5c\x45\xe2\xf5\xdc\x3c\x4d\x78\x62\x1e\x65\xd4\x67\x92\xf3\x20\x8f\xe6\x3c\x8e\x16\x02\x84\x4e\x8b\x92\x85\xec\x52\x95\xcb\xa4\xa8\xc2\xc8\x61\xc9\x22\x4f\xa5\xc3\xa6\xc3\x92\x94\xab\xdc\xc8\x91\x9b\xa4\xa2\x54\xca\x89\xca\xef\xd0\x34\x39\xcf\x78\xaa\x73\x50\x92\x7a\x23\x27\x3c\x77\x90\x13\x5c\xca\x06\x3b\xc8\x39\xe7\x34\x4c\x16\xb9\xa2\x48\xce\x58\x64\x6a\x2c\x7c\x60\xbf\x9a\x6e\xd0\x15\xa5\x31\xcf\x4a\xa8\xc7\xce\x18\x31\x12\xf3\x45\x60\xaa\x1a\x23\x59\x80\x07\x51\x9e\xa4\x9e\xb3\x8a\x5a\x65\x93\x5b\xd1\x9c\x4c\xf4\xe3\xce\x78\xb4\x26\x64\x35\xe1\xad\x09\x4f\x54\x86\x79\x52\x0e\x43\x2b\x49\x27\xea\x41\xf5\xb8\x16\xc2\xb0\xaa\x4c\xcd\x8c\xa3\xa7\xe8\x9b\x57\x2b\xa1\xd6\xeb\x8e\x52\xb6\x33\x18\xf1\x2a\xcb\xab\x41\xb3\xa7\x4b\x7d\x4f\xe2\xd5\x7c\xd1\x38\xe0\x66\x96\xcd\x58\x9b\x77\x83\x71\xba\x63\xf2\x8b\x86\x5a\x22\x1a\x59\xe4\xf9\xf6\x54\x8b\xe4\xd5\x84\x5b\xc8\x68\xca\x4c\x78\xa2\x12\xe6\x64\x29\x4a\x29\xfc\x75\x90\xfe\x70\xa0\xbe\xec\xd6\x3b\xe5\x24\x57\x45\xce\xf8\x84\x18\xa4\x9d\xf2\x38\x4e\xce\x93\x34\x0e\x0c\x06\x54\x03\x6e\x2a\x97\x29\x16\x9e\x56\x39\x1c\xf5\xad\xc2\xc2\x9d\x4f\x62\x9a\xf6\x7d\x5b\x46\x7b\x3f\x65\x4b\x92\xce\xe4\x4a\xab\x7d\xd3\x6b\xef\x2b\x8b\xc2\xaa\xb3\x3e\x49\xaa\xfb\x6a\x9c\x2c\x5c\xb1\x46\x71\x8c\x0c\xde\x98\xce\x27\x67\x3c\x15\xf8\xa6\x08\x57\xb5\xa8\x0d\x6a\x8c\x51\xd5\x8d\x7a\x6d\x19\x59\xcc\xf8\xa5\x85\x60\xe2\xc7\x55\xa9\xce\x18\x65\x8c\xe4\x39\xbf\xc2\x1a\xd7\x19\x9b\xeb\x58\x2d\xe8\x2a\xcd\x0c\xfa\x1c\x28\x3c\xcd\xf2\x94\x93\xb9\x84\x57\xc3\x6f\x15\xb0\x53\x77\xac\x5a\x17\x35\x34\xb1\x48\x9c\x2c\x28\xbb\x5b\x61\x65\x9e\x72\xae\x86\x51\x02\x29\x51\xa9\x4e\x54\xcf\x93\x34\x10\x39\x75\xb6\x02\x3d\x25\xde\x3a\x38\xf6\x0c\x2b\xf1\xe4\x70\x68\x66\xe2\x39\x67\xb7\x1d\x64\xc8\xbd\xf8\x24\xf8\x77\x61\x8f\x56\xad\xe0\x47\x9d\x68\x95\x3f\xd9\x2a\xaf\x72\x28\x30\xb5\xe1\x34\x80\xbc\xad\x51\xb6\x8a\xeb\x0f\xb2\x70\x81\x9e\x88\x86\xab\xde\x57\x65\x75\x42\x56\xab\x55\xa5\x1d\xe6\x11\x9b\xf1\x34\x3b\x64\xc9\x9c\x46\x0b\x1e\x68\x38\xf3\x3a\xc7\x2a\x41\x09\x44\xb2\xc1\xe4\x49\x12\xe7\xd1\xd2\x65\x59\xe6\x14\x0d\x3c\xa5\x2c\xb8\xcd\x7f\xd0\x41\x05\x64\xeb\x9b\x01\x66\xd3\x76\xab\x05\x55\xaa\xdd\x10\x2b\xb9\xa1\xbc\xc6\x9b\x26\x20\x0a\x91\x9a\x21\xc9\x6f\x25\xb8\x92\x64\x5a\xa3\x61\x78\xa5\x55\x5c\xa7\x99\x62\x5b\xf4\xa1\x2a\x6c\x13\x8a\xaa\x78\x3d\xbb\x01\x52\xad\xf2\xb2\xb8\x49\xb2\x0b\x9b\x34\x53\x4c\x2f\xa0\xb2\x8c\x62\x69\xf6\xf4\x89\x04\x95\x1b\x95\xb9\x56\x79\x14\xdb\x99\xc2\x24\x9d\x93\x3a\xcc\xed\xf1\xfc\x52\x11\xb4\x5d\xfd\xc1\x56\xfd\xb5\x51\x16\xa2\xcd\x5e\xb0\xe2\xbd\xca\xf8\xb5\x46\x88\x77\x1b\x76\x51\xf8\x4f\xdd\xd0\xfd\x1d\xaf\xbf\xf7\xd6\x0e\x9b\xa6\xc9\x9c\x1f\x86\x29\x99\x73\xc7\x33\xf2\x5d\xe6\xad\x9d\x81\xdb\x77\xfb\x8e\xb7\x5e\x2d\x84\x10\x9f\xf2\x2c\xe3\x81\xe7\x3c\x78\xfc\x6c\x91\xe5\x24\x8e\xc5\x0a\x41\xcd\x5f\xe6\xd1\x42\xd3\x02\x01\x63\xf0\x0d\x60\x1c\xdd\x08\x46\x81\x48\x1c\x91\x8c\x67\xde\x7a\xe0\x69\x78\x12\xae\x63\xde\x8a\x02\x65\xe7\xa1\xb2\xaf\xd7\x06\xe1\xa8\xa1\xf9\x65\xce\x8f\x59\xca\x76\xaa\x2f\xbf\xea\xe6\x1f\x35\x34\xfe\x3a\x10\xac\xc6\x1f\x79\x12\x5a\x51\x20\x87\x5f\xe4\x87\x92\x08\xd5\x5a\x7b\xec\x0e\x1a\xa6\xcc\xe4\x3d\x94\xea\xa5\xac\xee\xa0\xe9\xbb\x6e\xf0\x71\xe3\xbc\x37\x00\xd9\x0b\xc3\x6a\xf2\xb1\xa7\x1b\x25\xe1\x3a\x9e\x86\x2e\xde\x06\x8e\xf9\x26\x46\x5f\x1a\xa0\x09\x5b\xc5\xc9\x2a\xdb\x42\xc3\x9f\xdd\xe3\xdd\x11\xb4\xf3\xef\x8e\xe0\xf6\x57\x89\x46\x77\x1b\xba\xf5\x5f\xe0\xfc\xdc\x84\x13\xff\x09\x4e\x03\x66\x5c\x13\xce\x36\x6a\xdf\x95\x83\x3b\x70\x7f\x96\xa8\x2d\x46\x4e\xf6\xdc\x31\xdf\x8a\x02\x1d\x68\x56\xb9\xb3\xd8\x07\xbb\xcd\xd1\x59\x3f\x36\x4f\xba\xcd\x73\xf5\x5a\xdf\x9d\xa9\x6b\x83\x38\xb9\x39\x88\xdb\x37\x07\xb1\x8b\x2a\xd7\x06\xb1\x8b\x25\xd7\x05\x71\xf4\xd3\xcd\x41\xfc\x7c\x05\x10\x07\x5f\x81\x71\xf7\xe6\xcd\xb8\x39\x62\x1c\xdd\x1c\x31\x8e\x6e\x8e\x18\x47\x77\x6e\x0e\xe2\x1b\x20\xc6\xcd\x97\xea\x55\x26\xe4\x2b\x78\x71\xf3\x09\xb9\xf9\x7c\xdc\x7c\x3a\x6e\x8e\xdc\x83\x9b\x37\x62\x70\xf3\x95\xfe\x0d\x28\xd6\x37\xa0\x15\x37\xc7\xed\xc1\x37\xa0\x36\x37\x80\xd0\x20\x2c\xde\xad\x4b\x8b\x77\x45\xa6\x4f\xd2\xf1\x65\x15\xed\xc8\x2a\x0d\x33\xa9\xf2\x1e\xae\xa2\x9d\x8a\xab\x2f\xb6\xbc\xfb\x73\x13\x46\xfd\x07\x20\xbb\xab\xeb\x3f\x00\xd9\x5d\xe4\x75\x20\x07\x57\x81\xf2\x35\x20\x57\x6a\xc9\x2e\xc5\xba\x3e\x90\x6f\x32\x24\xbb\xe8\x75\x7d\x20\xdf\x64\x82\x77\x17\xdb\xf5\x81\xdc\x10\x5d\x0f\x54\x4b\x76\x89\xcf\xf5\x5b\xb2\x4b\x7d\xae\x0f\x63\x97\x76\x5c\x17\xc6\x9d\x06\x42\x7a\x5d\x18\x3f\x7d\x03\x18\xb7\x1b\xa8\xd8\xf5\xc7\xe3\x5b\xf4\xe5\x6b\x58\x76\x05\x0a\x70\xbb\x41\xdc\xf8\x0f\xf8\xfe\x0d\x3a\xf3\x2d\x06\xf5\xe6\x30\x7e\xba\xe1\x78\x6c\x33\x29\xc9\x76\xe4\x40\x4b\x26\x75\x5b\xeb\x7d\x77\xe4\xdb\x1d\xad\x13\xfe\x24\xdf\x7e\xd2\xdf\x8c\x86\xa8\x0b\x4a\x25\x5b\xd3\xea\xa2\x40\xf3\x24\xc9\x93\x24\xde\x56\xc5\x8f\x1b\x10\xca\x64\xdd\xc5\x05\xf3\xe5\xf0\x72\x15\x1d\x56\x1f\xca\x51\x68\x32\xae\xd4\xa0\x5d\x07\xd8\xa0\x61\x5a\xfe\x33\xb0\x93\xaf\xf5\xf3\x3a\xc0\x8e\xbf\x65\x37\x9b\xcc\x49\x37\xe8\xe6\xb7\x6a\xd9\x81\xec\xe7\x37\x6c\xda\x51\xc3\x0a\xb9\x41\x3f\xbf\x69\xcb\x76\xa5\x99\x1b\x00\xdb\x95\x48\x6e\xb0\x04\xbe\xd1\x74\x6e\x93\x97\x81\x36\x98\x0e\x1c\xfb\xed\x48\xbe\x89\x1e\xa8\xe9\x97\xaf\xc7\xfa\xe3\x89\x7c\x3b\x31\x05\x4d\xc9\x81\x00\xbe\x2d\x36\x1f\x09\x46\x95\xee\x8e\x2a\x5d\x45\x71\xd0\xbb\x5c\x45\x6a\xbb\xa7\x7a\xda\xe9\xcc\xde\x9c\x87\x15\xd5\x3d\x6a\x34\x00\x7e\xeb\x3a\x9a\xb8\xd4\xb7\xae\xa3\x49\x44\xf9\xd6\x75\x34\x89\x30\x5f\xae\xe3\xe0\xba\x95\x1c\x37\xb2\x93\xb2\xa4\xf8\xbf\xbf\xf1\xe2\xff\xd6\xc0\x1f\xa5\xff\xb7\x43\xbf\x6d\x89\x57\xb6\xd6\x23\xc9\x65\x8f\x34\x97\x3d\x92\x5c\x56\x0d\x9f\x6c\x95\x7c\x53\x6d\x53\xad\xec\xeb\x14\x81\xf0\xba\xdd\x5b\x79\xee\x3a\x25\x74\x69\x3e\x3f\xd6\x06\xf3\x63\xc7\xbc\x15\x05\x2a\xbd\x76\xb7\x38\xf4\x9d\xc6\x2d\x00\xeb\xd6\xf4\xad\x6e\xd7\xbe\x18\x01\xb8\x81\x5c\x5e\x19\xc2\x81\x92\x7f\xbf\x41\x23\x76\x19\xc0\x55\x21\x6c\xd3\xaf\x9f\xf4\xa6\x43\x25\x11\x0d\xcc\xbb\x56\xeb\x55\x7d\x2a\x65\xb0\x95\xc7\xc8\x4d\x06\xc6\x4f\xba\x8c\x4a\x29\x6d\x01\x5b\x13\xd1\xc4\xc0\x54\xc6\x3d\xf2\x5d\x4d\x40\x3c\xda\xab\x20\x5e\xa5\x74\xd3\xba\xba\x4e\xe9\x7d\x82\xf6\x57\x4b\xef\x13\x03\xae\x5e\x79\x93\xe4\x75\x9d\xd2\xff\xb9\xe9\x7b\xc4\x84\xeb\x94\xbe\xc9\x84\x9f\xec\xb5\x91\x5c\xa5\xf4\xed\x1b\x8d\xda\xed\x1b\x8d\xda\x7e\x45\x75\x9f\x76\x78\x45\x7d\xfb\x2a\x95\xdf\xb9\x51\xd3\xef\xdc\x68\xc2\xef\xdc\x68\xc2\xef\xdc\x68\xc2\xf7\x5b\x18\xae\x56\xfa\xbf\x8e\xda\x2e\x65\x1d\xd4\x64\xc1\x3b\xf2\xcd\x12\x05\x0f\x2c\x59\xf0\xa4\xa6\xa2\x1e\xd5\x08\xf2\x49\x8d\xd4\x4a\x31\x31\x48\x3e\x25\x57\xd0\x3f\x45\xb6\x9e\xf8\x71\x2f\x84\xf4\xea\xda\x5f\x77\xba\xb3\x95\x79\x3f\xcd\xb9\x39\xd4\x26\x32\x7a\x73\xa8\x4d\x2b\xfd\x5b\x8c\xc0\x37\x6f\xeb\x3e\x56\x70\xf3\xc6\x36\x71\xd6\x9b\x43\x6d\xa2\x43\xdf\x62\xba\xfe\x2f\x90\xa0\x69\xf5\x57\x19\xaf\x0e\xf2\x4b\x54\xf4\x1b\x4c\x7f\x13\x47\xfc\x16\x9d\xff\x52\x63\xaf\xdf\xf9\x26\x9b\xe0\x4d\xe0\x1d\xfd\x9f\x20\x52\x93\x6e\x7f\x33\xa8\xdb\xa4\xfc\x8e\x26\xe5\x95\xaa\x6e\x13\xf6\xe3\x6d\xc2\x6e\xd1\xf5\xe3\x1a\x5d\x1f\x28\xa2\x5f\x4a\xda\x35\xc2\x7e\xe4\x14\x85\x76\x40\xfb\x03\xaf\x49\xe8\xb5\xfb\x88\xcc\xe5\xef\x67\xf9\x9b\xaa\x5f\xea\x39\x24\x75\x10\x9d\x88\x57\xba\x10\xbf\x8c\xc8\xdf\x4c\xfe\xce\x17\x9e\xf3\x79\xea\xa0\x40\x26\x06\xf2\x6e\x43\x1e\xcb\xdf\x85\xfa\xfd\x38\xa1\xf2\x21\x53\xbf\x1f\x4f\x06\x77\xe5\x53\x2e\x7f\x57\xe2\x37\x94\x85\xc3\x48\xfd\xca\xd2\x61\xaa\x7e\x3f\xaa\xda\x26\x32\x71\xa6\x9e\x65\x99\x29\xf7\x9c\xe8\xdc\x41\x53\x59\x6a\x2a\xb3\x4f\xd5\x97\x4b\xf1\x1b\x05\xe2\xd7\x89\x16\x8e\xe7\x44\x81\x83\x22\x59\x7f\x24\x6b\x8d\xce\xc5\xef\x27\x09\xed\x53\xe4\x39\x97\x91\x83\x3e\x9d\x79\xed\x01\xfa\x74\xee\x39\x9f\xce\x1c\x34\x93\x43\x31\x93\x5d\x98\x25\xe2\x37\x56\xbf\xb2\x7c\x7c\x26\x7e\xe7\xb2\x4d\x73\x99\x67\x9e\x78\x4e\x9a\x38\x68\x2e\xdb\x31\x97\x75\x2d\xa8\xe7\x2c\x12\x07\xa9\x0b\x1f\x17\x32\xf7\x42\x42\x59\xca\xe7\x65\xee\x39\xcb\xfc\x23\x4d\x1d\x24\xff\xa8\xb4\x8f\x4b\x59\x45\x2a\x33\xa6\xb2\x43\x99\xec\x62\x36\x93\xbf\xb2\x68\x26\x33\x67\xb2\x19\xd9\xb9\xfa\x9d\x7a\x4e\x76\xee\xa0\x5c\xf6\x2a\x97\x75\xe6\x53\xf9\x1b\x7b\x4e\x18\xc5\x0e\xca\x65\xa9\x95\x84\x73\xb0\x92\x2f\x67\x12\xf4\x65\x24\xfa\xfe\x79\x2a\xa6\xf2\x23\x5b\x38\x48\xfe\x11\x5f\x3e\x4f\x3f\x4e\x67\xfa\x21\x97\x15\x7d\xce\xe6\x9e\x33\xcf\x1c\xf4\x79\x55\xc6\x67\x79\x42\x76\xef\x46\x57\xd1\x9a\x6a\x37\x23\x23\x06\xd7\x7b\xf2\x95\x97\x0d\x23\x06\x0b\x6f\xbb\x50\x15\x94\xdc\x1c\x74\x46\x1c\x3b\x2a\x1a\x8a\x15\xad\x9f\x0c\xcb\x53\xd8\x0e\xf4\x88\xba\x8b\xe7\x5e\xe0\x87\xdd\x2e\x0c\x5b\xd1\xa2\xc5\x3b\x9d\x32\x88\x2e\x1f\x85\x63\x14\x22\x02\x0b\xf4\x74\xb7\xf9\x73\xb2\xdc\xba\xd4\x59\x1f\x88\x6d\xc8\x58\xb5\x5d\x1d\xbe\xde\xea\x80\x1d\x2d\xa9\x6c\xbe\x3e\xa2\x0f\x18\xbc\x46\x4f\x58\xad\x27\x20\x18\x85\x63\x73\xbb\xbb\x0e\x7e\x53\x76\xaa\x8a\xde\x52\xa0\x67\xbb\xdd\xcb\x92\x39\xbf\x5a\xff\x44\xce\x86\x0e\x1e\x5c\xa1\x87\x5f\xef\x96\x8a\xff\xcd\x64\xe0\xef\x28\x04\x2a\xce\x7f\x39\x47\x26\xa0\x8f\xba\xb3\x9e\x58\x71\x50\xcb\x70\x20\xd5\x69\xe8\x5f\xed\xd3\xd0\xdb\x9d\x50\xe1\xcd\xf5\x61\xfe\xd1\xb8\x31\xda\xc2\x6f\x56\xbc\x87\x32\x8a\x85\x8c\xdd\x55\xeb\x9f\x9a\x36\x0a\x75\xd4\x2b\x2a\xc3\x5c\xc9\x73\xf3\x64\x14\x8c\xab\x80\x70\x65\xec\xf8\x2a\x56\xc0\x73\x72\x93\x2b\x11\x10\xc7\x97\x44\x07\x40\xd2\xb1\x2d\x30\xe6\x9b\x4d\x15\x8c\x82\x77\x3a\xd5\x0d\x16\x7a\xc4\xcb\xb8\x39\x6b\x8e\xab\x20\x01\x7d\x7d\x57\x66\x60\xa5\x98\xaf\x98\x77\xc3\xda\xc5\xf8\xe6\x3a\x7b\x32\xe2\xdd\xc9\x18\x07\xa3\xc9\x58\x5d\x7d\x4f\x74\x28\x79\x58\x28\x2a\xf0\x82\x54\xd3\xf1\x6c\xe7\x10\xfc\xcb\xed\x43\xf0\xaf\x48\xf1\x6c\xfb\x10\xfc\xb3\x2b\x1d\x82\xb7\x42\x39\x58\x18\xf0\x7a\xef\x79\xf8\x67\xbb\xe7\xe1\x9f\x99\xf3\xf0\xaf\x76\xcf\xc3\xbf\x4b\x57\x59\xce\x83\x37\x3c\x4b\x56\x29\xe3\xef\xd3\xd8\xb1\x66\xf1\x7f\x7a\x16\xd5\x0c\xca\x43\xf8\x32\xec\xcd\x1b\x1d\x38\x85\xed\xb9\x1e\x7a\x17\x6a\x4b\x79\xa5\x7b\x2d\xa7\xcb\xa0\x4f\x30\x2b\x43\x12\xbd\x25\x55\x60\x20\x19\x5e\x54\x54\x70\xa5\xeb\xda\x29\xe2\xf5\xfa\x7f\x7c\x9c\xac\x16\x41\x6b\x4e\xd2\x19\x4f\x51\xcb\xf9\xb1\xcb\xbb\x3f\x3a\x48\xac\x34\x55\x7d\x4b\xad\x52\xf9\x89\xc9\x4f\x74\x95\xb7\x16\x49\x4b\x35\x3b\x26\x94\xc7\xad\x39\x59\x2e\xa3\xc5\xa4\x15\x4a\x60\x91\xbc\xaa\x2b\xf3\x5a\x3f\x76\x7f\x7d\xfb\xea\xa5\xab\x20\x44\xe1\xa5\xbc\x34\x27\xc0\x74\xc4\xcb\x95\x10\xd4\x02\x13\x0c\x1f\x13\x19\xfa\x76\xc1\x92\x80\xbf\x7f\xf3\xec\x41\x32\x5f\x26\x0b\xbe\xc8\x81\x9e\xd0\x00\x5a\x41\xe4\xdf\xc9\x88\x2c\x62\xa0\xdf\x12\xdc\xfb\x61\x0d\x3e\x9c\x77\x61\xd1\x9b\xa0\x37\x04\xf7\xfe\x01\x40\x9d\x91\x84\xc3\x0f\xbd\x0f\xbd\x51\xff\xf0\x2e\x39\xfc\xec\x7a\xa3\x0f\xe3\xc3\x71\xf7\x43\x6f\xf3\xa1\x37\xfa\xa7\xf7\xe1\xc3\x78\x33\xfa\xc7\xeb\x7d\xf8\xf0\x83\x4c\x34\xcf\xb7\x46\xc3\xef\xc6\x1b\x42\x93\x55\xee\xd1\x98\x2c\x66\xdf\xc1\x5e\x84\xde\x4b\xb8\xa3\x7f\x86\xdf\x8d\x6f\x41\xf0\x61\x38\xfa\x47\x3c\x0c\xc1\x77\xa3\x0f\xd9\x87\xb7\xe2\xb1\x67\x45\xf8\xfa\xbd\x8c\xcf\x42\xb0\xc6\x0a\x9f\xe0\xf7\x44\x85\x2a\x93\xe8\x68\x61\x2a\xf4\x29\x26\xa3\xe3\xb1\x5c\x02\x56\x07\x47\x83\x71\xf7\x0f\x02\x9c\xa1\x83\xc8\xe8\x48\x7e\x46\x0c\xca\xa4\xef\x9c\x8a\xe4\xaa\x71\x78\x25\x03\x2f\x94\x2d\x90\x03\x24\x90\xa3\x8c\xfa\xf1\xa2\xa4\x61\x32\xc0\x8e\x0e\x44\xe2\xe6\x0a\xf9\xde\x5d\x2e\x79\x26\xc3\x48\x75\x3a\x4c\x87\x83\x7f\x9d\xc4\x11\xbb\x54\xe1\x5d\x65\x6c\x41\x2b\x15\x38\x93\x24\x99\x7c\x37\xcd\xe7\xb1\x83\xd6\xea\xcb\xd3\x77\x2f\x9e\x7b\x0f\x08\x52\x6f\x2a\x5e\xc9\xf6\xfb\xfb\x37\x22\x4b\x01\xab\xe8\xb0\x2b\xb9\xfe\x92\x98\x77\x3a\xe5\xa3\x2b\x97\x1b\x08\x4c\xdc\x0d\x58\xbc\x20\x98\x2a\xda\x22\x9f\x08\x06\x54\xf4\x68\x48\xdd\x2d\xe8\x80\x40\xaf\x16\xa0\xfe\x19\x78\x29\x63\x54\x54\xb3\xf3\x87\x1d\x3d\x47\x05\x1f\x62\xd5\xbd\x4f\xf2\xfe\xe4\x6d\xf6\x54\x45\x90\x1e\x92\x6e\x03\x8e\x32\xe8\x39\x4e\x15\x8e\x45\xac\x03\x06\xcb\xfb\x4f\xbe\xb2\x32\x19\x0a\xa0\x09\xaf\x23\xf8\x85\x6f\xa2\xec\x98\x98\x45\x1c\x0e\xb9\x27\x56\x8e\xa9\x40\x31\x7d\x6e\xf8\x42\x68\xf8\xc2\x04\x0b\x36\xef\xab\xc0\x43\x93\x4e\x07\xd0\xcd\x06\x50\x4c\x20\xa2\x5d\x0c\xa8\xce\x7f\xdf\x10\xf4\xa1\xd3\x71\x3c\xc7\x81\x4d\x3d\x0a\x60\xd7\xc1\x4e\xd3\x17\x8d\xb6\x13\x08\xab\x80\x3d\x54\xe2\xe0\xcb\x32\xf8\xc7\x9f\x04\x37\x46\x3a\x1b\x36\x45\x45\x93\x5f\x40\x4d\x36\x32\x1f\x7b\xff\x98\x10\x6c\xb7\x80\x5e\x69\x43\x58\x26\x7d\xdf\x53\x0b\x8a\xc0\xd1\x60\x6c\x21\xff\x5f\xa4\x26\xb8\x90\x7b\x74\x78\x38\xf0\xc8\x7d\x3a\x1c\x78\x5a\x2e\xfd\xd5\x27\x9e\x1c\xb2\xbf\x09\x5e\xb9\x0b\x72\x16\x4d\x48\x9e\xa4\x62\xf6\xff\xd6\x0b\xe5\x7b\x82\xff\x26\xee\x2a\xe3\xe9\xe9\x84\x2f\x72\xf1\xe9\x7b\x02\xd7\xbf\xe2\xef\x89\x4f\x53\x4e\x66\x2d\x52\x14\xbf\x62\x3b\x12\xd6\x6f\x55\xcb\x0f\x07\x6d\xfc\x6b\x19\x4e\x88\xd8\xec\x88\xd0\x2d\x6e\x2f\xc9\x26\xac\xcb\x36\x44\x30\x76\x66\x82\xab\x50\x8a\x1d\x8b\x4d\xb5\xea\x68\xd4\x8a\x32\x2b\x6e\x73\x6b\xa9\x93\x9f\x65\x8f\xca\x78\xf7\xad\x3c\x79\x9e\x30\x12\x73\x35\x2d\x2d\x43\x7d\x5a\x32\x06\xdc\xab\xd0\x3e\xc1\x5b\xb5\x94\x6d\xb7\x14\x05\x88\xe3\x81\xcf\x77\x65\x13\x21\xa8\xad\x6d\xb9\x44\xa3\x2b\x53\x37\x34\x11\x19\x76\x7a\xc4\xb6\x71\x98\x52\x1b\x89\x19\xa6\x54\xc8\xa9\x57\x5a\x36\x01\x62\xea\xca\x27\x0d\x59\x08\x1b\x65\xcb\x03\xdd\x72\xe2\x66\x29\xc3\xaf\x09\xa0\xd0\x17\x2b\xc1\x4d\xce\x17\x3c\x7d\x98\x30\xd9\x4a\xc1\xea\x6b\x09\xae\x3e\x48\xf8\x7b\xc4\xcf\x61\xa7\x43\xdb\x78\x35\xa4\xf8\x82\x00\xea\x06\x3a\x0b\xf4\x34\xcd\xc0\xe7\xa4\xd3\x01\xe7\x44\x7c\x5e\x55\x9f\x21\xa2\xf8\x9c\x40\x9f\x0a\xe0\x59\x43\x2c\x35\x44\x6d\x64\xe0\xb4\x12\x2e\x43\x6a\x08\xd7\x15\x39\xfa\x60\x00\x87\x74\x34\x18\x8c\x3d\xf9\x8b\x09\x18\x0c\xa0\x42\xf0\x09\xc5\xbf\x01\xe7\xd5\x92\xa7\xc4\x81\x68\x2a\xdf\xde\xa5\x51\xc0\x17\xb9\x03\x37\x9b\xdf\x80\xf3\xe2\xed\xb3\x47\x0e\x44\x91\xfc\xf4\x28\x98\x70\x07\xa2\x4f\xf2\xe5\x09\x67\xb3\xc4\x81\x9d\x4e\x1b\x28\x34\x16\xc8\x73\xce\xd3\x07\x24\xe3\x76\x8c\xac\x73\x4e\x67\x51\x2e\x33\x96\x20\x64\xa9\x3d\x75\xd5\x32\xa2\x19\xc5\xd7\x86\x8e\x62\xea\x1f\xe8\x95\x3b\xa7\xd8\x71\xd0\x82\xe2\xad\x18\x65\x04\xff\x2a\xd6\xea\x27\x13\x50\xae\x97\x9e\x79\x60\xf4\xcf\x07\xe8\x8f\xbb\x10\x7c\x80\x1b\x1f\x96\x74\x43\x5e\x0f\x58\x66\x14\x75\x7c\xe8\x81\xd1\x87\xe0\x83\x3b\xee\xd6\x73\x4d\xcb\x5c\x1f\x28\x18\x7a\xa2\x43\x9b\xf4\x0c\x8e\xbc\xd6\xf8\x4b\xc0\x67\x65\xb1\x3f\x38\xfd\x2d\xca\x3f\xf4\xc0\x87\xb7\x5b\xa0\x27\x65\x1e\x30\xf4\x7e\x57\xb6\x74\x38\x6a\x7d\xe8\x8d\x87\xf5\xcc\x05\x80\xfe\x82\x76\x3a\x60\x4e\xf1\x82\x0e\x17\x74\x34\x18\x0b\xfa\xad\xdb\x27\x7b\x9f\x50\xb4\xa4\xb8\xc2\x47\x3f\xa1\x78\x49\x87\xcb\x0a\x81\x5f\x24\x81\x09\x89\xea\x6b\x06\xd8\xc6\x09\xed\x74\x12\x7a\xbf\xba\x19\x0e\xcc\x29\x84\xeb\x98\x9a\x90\x57\x09\x85\x15\xd5\x8b\x29\x9e\x2b\x92\xff\x2f\xc5\x31\x45\xa1\xbc\x7c\xbd\xe2\xb0\xa9\x15\x51\x93\x53\x3b\xb8\xa4\x59\xfd\x04\xf7\x11\xc5\x7f\x12\xc3\x4d\xfe\xa5\x10\x5a\x71\xd2\x10\x13\xdf\x9c\xc1\xc0\xa9\xa5\x06\xd5\x8d\xad\x86\x6e\x20\x13\x5c\x59\xdd\x19\xd5\xc7\x98\x74\x3a\xfc\x5e\xa0\x08\x92\x22\x34\x42\xea\x94\xd2\xd3\x04\x33\xfd\xe8\x07\xc9\x3a\xc4\x3d\xf0\x21\x10\xe2\xdc\xc3\x5b\x10\xb8\xb7\xcc\x40\x87\x70\xb3\x19\x39\x0e\x32\xff\xc6\xfe\x64\x4f\xce\xc9\x4e\x4e\x75\xfd\x65\x38\xea\x8f\xcb\x80\x6c\x7d\x8c\x27\xd5\x3b\x94\x83\xe8\x13\xfc\x17\x51\x39\x07\xe6\xcb\xb0\xef\x99\x1b\xf6\x80\x48\x46\x83\x3e\x44\xb2\x70\x63\x96\x89\xce\x02\x37\x1b\x03\xea\xc8\xe4\x53\xc5\xca\x57\x95\x45\x7c\x47\x22\x15\xfa\x21\x0e\x47\xc7\xa2\x5b\x93\xd1\xf1\xb8\x38\x9f\x46\x31\x17\x10\x48\x19\xe1\xb4\x7f\x0f\x0b\x21\xad\x22\x53\x99\xa1\xa7\x14\x50\x54\x8f\xc7\xcd\x3a\x9d\x4a\xd3\x34\xf2\x92\x90\x22\x5f\x75\x3a\x80\x61\xe6\xbe\x10\x22\xae\x93\xe5\x97\x31\x77\x30\x0e\x84\xa6\x2f\x9e\x5d\x96\x65\xef\xf8\x45\x8e\x99\xe7\xb0\x98\x64\x99\xfe\x28\x9f\x5f\x92\x39\x17\x1f\xc2\x24\xd5\xc9\x42\xd4\x7c\x9c\xa4\x98\x79\x39\xdd\x22\x87\x20\x80\xc3\x2d\x5a\x9b\xd3\x51\x30\x46\x0c\x7a\x7d\x2c\x74\x59\x13\xdc\xf7\x95\xd4\x90\x23\x72\xe8\xa0\x3e\x94\x57\x7e\x6e\x7d\x0c\x48\xae\x3e\x6e\x03\x14\xdc\xc6\x13\x8a\x3c\x66\x05\x2c\x64\xc0\xce\x9c\xe2\x35\xe3\x71\xbc\x24\x41\x10\x2d\x26\x9e\x23\x5e\x5e\xab\x17\x07\x89\x97\x6c\x49\x58\xf9\xe5\xad\x7a\x71\x10\x4b\xc4\x87\x85\xe7\xb0\x44\x24\x2e\x1c\x24\x8f\xf6\xd2\x24\x0d\x78\xea\x39\xf2\xe5\x17\xf9\xe2\xa0\x29\x8f\x26\xd3\xdc\x73\xd4\x5f\x07\xcd\xc9\x85\x9a\x53\xcf\x99\x93\x8b\xe7\xf2\xd1\x41\x92\xb1\x78\x86\xbf\xa4\x49\xcc\x3d\x47\xfc\x8a\xe7\x73\x55\x57\x9a\x9c\xab\xba\xa4\x43\x8a\x54\x6a\x1d\xb4\xca\x64\xc8\x01\x67\x95\xf1\x17\x64\x29\x6f\x0e\x8b\x26\x0b\xcf\x39\x3b\x8d\xe5\x3d\x89\xe7\x51\x20\x6a\x92\x7f\x1c\x0b\x1b\x56\x16\xd3\x2a\x09\x0d\xa9\xa2\xe3\xf9\x0e\x59\x2e\xe3\x88\xc9\x93\xf2\xbd\x0b\x31\x75\xdd\x8b\x79\x2c\x04\x6a\x2a\x64\xfc\x9c\x2f\x72\xa1\x71\xe8\xd0\xa3\x35\x06\x50\xea\x78\x46\xb4\x7f\x14\x73\x01\xbf\x2e\x43\x9d\x51\xcb\x8c\xc0\x30\x51\xa6\x83\x09\xa6\xc6\x86\xd0\xf7\x4d\x98\xdc\x55\x1c\x17\x67\x76\x90\xd6\x09\xcf\x71\x3d\xde\x6d\xff\x9e\x2a\xa5\xe1\xd1\xc3\x43\x5f\x11\x29\x05\xc3\x80\x22\x32\x94\xae\xaf\xfe\x28\xc0\xca\xdc\xa1\xf2\xb1\xea\x42\x04\x3b\x1a\xdf\x79\x29\x8a\x4c\x84\x14\x32\xe8\xf7\xef\x13\x57\x50\x71\xe2\xd2\x6e\x17\xa9\x9b\x13\x31\x71\x09\x22\x2e\xc1\x35\xe1\xe0\x42\x8e\xf3\x4a\x60\xe2\xbb\x68\xce\x93\x55\xbe\x7b\xdd\x18\xf1\x0b\xd4\x57\x52\xe2\x25\xb5\x68\xf0\x67\x5a\xf2\xc3\x95\xfb\x42\xe9\x51\x0f\xa6\x64\xb1\xe0\xb1\x5f\x8b\x39\x59\x9a\xe0\x3a\x9d\xda\xc5\x5a\x26\xfd\x3c\x5a\x04\xc9\x79\xa7\xa3\xfe\xba\xcb\x24\xcb\x35\xb8\x32\x8d\x04\xc1\xa3\x33\xbe\xc8\x9f\x47\x59\xce\x17\x3c\x55\x2c\xfb\x75\xca\xb3\x5c\xca\x11\x80\x6c\x33\x69\x8e\x57\x14\x38\xcf\x1e\xbf\x39\x7d\xf1\xc8\x81\x3e\xd7\x24\x21\x88\xb2\x65\x4c\x2e\xb1\x40\x65\x2e\x88\xb4\x11\xcb\xf4\x83\xc6\x05\x97\x2c\x97\x7c\x11\x3c\x98\x46\x71\x00\x38\xd4\x36\x2b\x6e\x50\xeb\x0f\xd9\x2a\x9f\xe3\xb0\x62\x83\xdc\x4d\x96\x7c\x01\x44\x55\x2c\x4e\x04\xa2\x29\x31\x09\x3b\x42\x96\x7a\x36\x9f\xf3\x20\x22\x39\x77\xba\x92\xc3\xa4\x64\x11\x24\x73\x00\xd1\x14\x3b\x61\x24\x96\x13\xc6\xa1\x1b\x27\x0a\xa3\x15\x2e\xb1\x24\x1e\x3a\xb7\x1c\xaf\x21\xbd\xeb\xf4\x7a\x4e\xd7\xfa\x30\x4d\xb2\xdc\xe7\xf8\x73\x35\x7d\x33\x89\x78\xc0\xb9\xe5\x60\x3c\xdd\x6c\x66\x6e\x92\x46\x93\x68\x81\xf1\x14\x76\x3a\x33\x57\xd0\x21\x8c\x27\x2a\x5a\xf3\x32\x49\xf3\x81\x9b\x2c\xb4\x36\x0c\x60\x81\x44\x3a\xf4\xc3\x9d\x91\x07\x8e\xce\xe4\xa0\x03\x8e\xda\x03\x7d\xa5\x84\x84\x20\x78\x74\xf9\x76\x84\xd7\xd6\x4c\xda\xf1\xd8\x43\x7b\x8a\xc1\x04\x4d\xa1\xbc\x15\x60\xfb\xde\x35\x0b\x6d\xda\xb6\xbc\xa7\x5e\xb5\xc0\xb7\xae\xee\x92\x27\x48\xdf\xf6\xc8\x7c\xba\xdd\xa3\xad\xe5\x58\x86\x45\x57\xb1\xab\xe1\x9a\xe9\xa7\xf2\x7a\x84\xe7\x3e\x73\x9f\x2b\x43\x86\x18\x8e\x62\x27\x5c\x2d\x87\xeb\x40\x2d\xac\xf5\x73\x8f\x17\x7e\x80\xd5\xab\xae\xfb\xa8\xd6\xc7\x7e\x43\xe4\x59\xbe\xb5\xee\xb8\x58\x64\xd6\xd2\x3c\xa5\xe6\xf6\x0e\x8a\x6b\x94\x86\xa4\xad\x07\xaa\xc7\x67\xb4\xe1\x82\x41\xf1\xe1\x17\x5a\xd4\xc2\x7b\x13\x37\xe5\x19\xcf\x01\x2c\xa0\x7f\xba\x37\x74\xb5\x65\x5b\x7c\x40\x05\x11\x03\xd0\x67\x32\x8c\xb5\xb4\x2f\xa9\xb6\x0c\xd5\x1f\xd5\x75\xe6\xe9\x96\x31\x43\x15\x99\x1d\x47\xb5\x22\x10\x8f\x28\xd2\x66\x21\xe2\x0a\xa5\x86\x96\xe4\x88\xb8\x8a\xda\x89\x97\xcd\x46\x90\x2c\x99\x0f\x1a\xb2\x25\x5f\x1a\xa2\x35\xff\x52\x0e\x8f\xcc\xd6\x30\x50\xbf\xd8\x1d\xcd\x6c\x92\x5c\xb3\x0f\x9b\x96\x6b\xc2\x5e\x51\x5e\xbf\x06\x40\x0e\xe0\xce\xc5\x2a\xfb\xea\xb6\x42\xa5\x6a\xe2\xfc\x84\x6e\x36\x4f\x29\x80\xfe\x33\xba\xd9\x80\x27\x14\x40\xf4\x8c\xe2\x76\x1f\xfa\x8f\xa8\x8c\x46\x2e\x72\xc9\xc9\x7d\x42\xab\xd2\xa2\x84\x40\xd8\x95\xab\xef\x87\xec\x74\xca\x47\x73\x55\x64\x45\x84\xb7\xef\x90\xd4\xf6\x3b\xff\x49\x4d\x85\x21\xea\x5a\xc9\x5f\x29\x2c\x14\x77\x79\xb2\xa3\xe1\x50\xfc\x2b\xf5\xdb\x97\x40\x22\x68\x49\xba\xe0\x66\xb3\x72\xff\xd0\xc4\xda\x3c\x55\x43\x64\xab\x51\x4d\xdf\x6b\xb0\x30\xae\xc3\x1e\x82\x4b\x31\x2e\x97\x14\x0b\xb6\x02\xd1\x25\x05\x14\x42\xaf\x9e\x49\x5e\x95\x25\xda\x27\x46\x6e\x80\x1e\xa9\x55\x70\x6a\x8d\xd7\xaf\xd4\x56\x01\x7c\x82\x05\x0e\xfa\xca\xc2\x28\x30\x4d\xed\x26\xb9\xd4\x98\x07\x29\x5c\x5f\x88\x9a\x8a\x73\x0a\x1e\x50\x44\x60\x21\x41\x5b\xf3\xf7\x1b\xd5\x76\xce\x36\xa9\x07\xa9\xd7\x2f\x6d\xe2\x7e\x3f\x49\x92\xc9\xc7\x77\x53\xbe\x20\x34\xe6\x15\xe4\x2a\x72\x7c\x05\xee\xb9\x80\xa6\x31\x45\x4b\x10\x9f\xf4\x2d\x0d\x46\xc2\xb0\xd1\x89\xa9\x45\x23\x9f\xa7\x2a\x29\xc2\xed\x81\xa0\x95\xa4\x8d\xcf\xa1\x89\x96\xaf\xb2\xfb\xa4\x66\xe1\xb1\x83\xc4\xbf\x00\x14\x1d\x21\xb6\x75\xf7\xa8\x48\x3d\x96\x97\xa7\xea\x56\xcb\x34\x19\xc7\x58\x26\x57\xcb\xed\x79\xc3\x72\x63\xb5\xa6\x4e\xec\x05\x60\x5a\xdc\x1e\x14\xcf\xbf\xbe\x8a\xae\x06\x48\x6d\xf4\x7c\x85\xf2\x3d\xff\x02\xe5\x2b\x3b\xf3\x92\x1a\xfb\xac\xda\xeb\x7a\x61\xa8\x5d\xe0\x4e\x30\xf1\x03\x49\x0d\x02\x97\x61\x56\x6d\x65\x1e\x3c\xb7\x2d\x8d\x53\xbe\xc0\xdb\x3b\xc5\xa5\x65\x45\x0d\xe0\xa5\x8a\x63\x2f\xe3\x77\x5f\xca\x4b\xe3\xd5\x33\x83\x85\x6f\xc3\xaa\x63\x0f\x6e\xf7\x6b\x5f\x19\x59\x30\x1e\x63\xbb\x4b\x4a\x03\x54\x63\x64\xf3\xbf\x97\x42\x2e\x7e\x5c\x1b\x98\xd7\xba\x2d\xd4\x30\x74\x1b\x15\x5f\x6b\xca\xa4\xe0\x11\x97\x40\x81\x55\x2e\x33\x3c\x80\xb8\x4c\xda\xeb\x5d\x6a\xef\x82\xf7\x11\x97\x13\x83\x42\xf5\x67\x82\x99\x4b\xfd\x49\xa7\x03\x26\xee\x74\xb3\x01\x41\xb7\x8b\x26\x2e\x91\x5a\x32\xe0\x78\x02\x51\x1b\xf0\x4e\x67\x70\x2f\x80\x10\x0a\x85\x50\x71\x5c\xbe\xd9\x80\x10\x4f\xe4\x15\xa7\xa2\x7a\x26\xd8\xc2\x40\x28\x62\xaf\x29\x60\x88\x42\x0f\x84\x43\x10\xe0\x10\x69\x2e\x8b\x99\x3b\x91\xf7\xa8\x4c\x70\x00\x4d\xa2\xfa\xa3\x20\x7a\xff\xa3\x80\x41\xf4\x46\x14\xe7\xe8\x18\x51\x08\x61\x41\xf4\x0a\xd2\x96\x7d\x40\xe4\x07\xcb\x54\xff\xb6\x94\x9d\xa9\xbc\xd8\x4c\xb2\xa7\x63\xf9\x77\xb3\x79\x27\xd6\xbe\x4f\xdc\xc9\x90\xb8\xaa\xdd\x98\x7a\x44\x62\x07\x11\xaa\x40\xb5\x3c\x5e\x69\x8c\xaa\xae\x8f\x7a\x49\x55\xe8\xf6\xf2\x47\xde\x3a\x21\x27\xea\xb9\x75\x8f\x14\x9a\xc0\x35\x17\xb0\x2a\xc3\xf5\x54\x91\x2b\x75\xf9\x0c\x35\xa6\xc8\x29\xf4\x43\x30\x33\xeb\x34\x86\xeb\x09\x88\x61\x51\x78\xa1\xcf\x05\xdb\xdd\x53\x9c\x59\xc5\xcb\x8d\x9a\x59\xa7\x33\xb5\xb7\xc6\x5e\x0e\x27\x60\x0a\xbd\x46\xf0\x93\x42\xb6\x5b\x6a\x40\x72\xac\xb8\x7d\xcf\x72\x61\xa3\xea\x69\x0d\x4b\x4b\x1a\xa7\xe9\xc9\x91\x20\xae\x35\xd4\xfe\xe5\x8b\xf9\x8f\x65\xfe\x6a\xa2\x5e\x58\x5b\x2a\x1a\x5d\xd7\x04\x63\xcc\xa4\x34\x71\x8c\xd4\x95\x41\xd6\x75\x44\x9a\x19\xb6\x98\x0c\xa9\xd6\xd2\x3c\xb1\x95\x27\xad\x28\xcf\x78\x1c\x3a\x50\x4c\x2d\xc1\x03\x63\xa8\x0f\x30\x43\x1c\x13\xf7\x14\x85\x98\xb8\xbf\x08\xdc\xaf\xed\x20\x3e\x87\xeb\xb7\x14\x04\xe8\x25\x05\x7c\xb3\x39\x47\xe1\x66\xa3\x82\xf3\x43\x23\xe9\xb7\xfb\x0a\xcf\xa2\x10\xfc\x46\x41\x00\x61\xa0\x58\x2d\x97\x7e\x11\x48\x64\x50\xc1\xe1\xa3\x10\x7c\x26\x22\x83\x99\xa9\x29\x56\x59\x45\xa5\x97\x60\x0a\xe1\xfa\xbd\xa8\x6a\x8a\x54\x51\x5f\x16\x2d\xad\x63\x6a\x92\x66\x42\x92\xd6\xee\x11\xb3\xad\x2c\x13\x41\x30\x8b\x89\x14\xa8\x3e\x61\xa6\x14\x3f\x64\x56\x03\x92\x88\x8d\x8e\xdb\x98\x6e\x36\xb5\xdb\x8f\x5f\x6e\x36\xbf\x8b\x59\x66\x10\x16\xd6\x2a\x79\x5f\xa2\x37\xe2\x56\x4c\x7e\x81\x31\x6b\xb1\xe8\xa7\xb8\xdd\x47\x81\x6a\x0c\x47\x33\x68\xf9\x36\x4c\x6a\x79\x98\x9d\x47\x75\x5c\xb3\x53\x6a\xba\x32\x41\x21\xb4\x7a\x28\x90\xb2\x82\x26\x1b\xbe\x26\x6e\x24\x7b\x16\x09\x90\x42\xc0\x72\xe7\x62\x16\xaa\x6c\xff\xb3\xcc\x07\x5a\xea\xa4\x5a\xea\x14\xa3\x40\xb1\x12\x2e\xeb\x32\xa6\x24\x01\x40\x2c\xec\x2d\x99\xd3\x46\xda\x39\x6e\xb2\x35\xfa\x04\xff\x4f\x91\x5a\xe8\xc3\x37\x9a\xe8\x12\xa4\x70\x5a\xfd\xf9\xa4\x05\xe8\x48\xb2\xb2\x6a\x68\xdf\x58\x94\x23\x0a\xc1\xb1\xc4\x68\x2a\x9a\xdb\xa6\xee\x14\xaa\x1b\x69\x3b\x1d\xe2\x4e\x7d\x21\x2c\x33\x48\x24\x37\x14\x88\x42\x5d\x02\xa9\x5b\x4e\xea\x1f\xd4\x5c\x79\x2c\x91\x50\x0d\xea\x74\x48\xdd\x89\xb6\xe6\xbb\x0c\x7a\x65\x26\x3d\xc4\x1c\xae\xff\xd4\x43\x2f\x81\x70\x29\x0a\xbd\xa0\x82\x4a\x56\xfb\x99\x25\xbf\x3c\xc2\x98\x4a\x62\xa8\x05\x29\x26\x8d\x56\xae\xdc\x8a\xa0\x76\x62\x55\xf8\xf7\x92\xc2\x0a\x0c\xd8\x62\x50\xc4\x9d\x76\x3a\xb5\x06\x50\x21\x8c\xc8\x1d\x3e\x8a\x2f\x2c\xc9\x4e\x70\xb7\xf5\x43\x95\x51\x0d\x2f\x2c\x1e\x80\x97\xe8\x21\xf4\x5f\xee\xdc\x8e\xa0\xb8\xa6\xe3\xf7\x6e\x1d\xb4\x5e\x27\xa9\x00\x90\xb5\x92\x50\xfa\x70\xc8\x1b\x37\x5a\x24\xe5\xad\x30\x4d\xe6\xad\x17\x09\x9b\x46\xbf\x45\x39\x6a\xa5\x9c\xf1\xe8\x8c\x07\x2d\x7a\x79\xd0\x7a\x37\xe5\xad\x07\x71\x92\xad\x52\xde\x3a\x5d\xe5\xd3\x24\xcd\x5a\x42\x39\x4d\x5b\xf9\x94\xb7\x5e\x3c\x7b\xd7\x8a\x23\xc6\x17\x19\x77\x5b\xa7\x71\xdc\x4a\xf2\x29\x4f\x15\xe4\x28\x6b\x3d\x48\x96\x97\x69\x34\x99\xe6\x07\xad\xa3\x7e\xff\xf6\xe1\x51\xbf\x7f\xb7\x09\xa2\x2a\x2b\x2f\x67\xca\x5a\x6f\x78\xc6\xd3\x33\x1e\xb8\x07\xb7\x7a\x15\x7a\xbc\xb2\x94\x95\x29\x1e\x8d\x15\x12\x3d\x36\x6a\xcb\x53\xb1\x82\x2b\x39\xa9\x14\x9d\xc4\xa2\x52\x92\x95\x2d\x5b\x9e\xaa\xcf\xef\xb1\x96\x3b\x4d\xae\xc8\x88\xa2\xd4\x92\xb9\xe6\xb8\x5f\xbc\xfa\xaa\x24\xa2\xc5\x10\x55\x99\x4d\x49\x5e\x75\x3a\x2a\x51\x17\x04\xb0\x24\x7d\xc6\x14\x56\x09\xae\x2e\xf5\xf5\xa5\xd2\xfa\x8d\x0c\xa9\x29\x47\xa0\x07\xa8\x3b\x3f\x3c\x44\xfd\xfb\x98\xba\x73\xe5\xa3\xa5\x40\xea\x9b\x57\x1f\x2b\xa5\xf4\x71\x85\x1d\xee\x53\x25\xef\x78\xba\xdf\x6d\x63\xad\x13\x2b\x5c\x72\x8a\xd7\x6a\xb9\xa2\xff\xe9\xbf\x6f\x14\x56\xb5\x07\x92\x92\x14\xfe\xab\x3d\x9c\xaa\x9c\x0d\x39\x7c\x6f\xcc\x52\xaf\x59\xd5\xde\x94\xce\x19\x62\x2a\xfa\x42\x2c\xc7\x4c\x8a\x0c\x6d\xea\xff\x25\x68\x93\xed\xd4\x63\xae\xea\x77\x8d\x9e\xe1\x9e\x5a\x17\xec\xfd\xad\x65\x90\x53\x49\xd1\xcb\x52\xdf\x5b\x64\x83\xb8\x53\xe5\x0e\x35\x92\x09\x63\xa8\x94\x6c\x59\x51\x65\x2f\x7c\xf5\x35\xf9\x55\xf2\x40\xc1\x70\xb6\x85\x94\x09\x9a\xc2\x75\x80\x27\x3e\xc7\xd3\x02\xfa\xdf\x6b\xfa\x16\x54\x82\xf6\x04\xae\x27\xf6\xe4\xbf\x1e\x86\xe5\x1c\x79\x1c\x4c\x2c\xc7\x9a\x50\xb1\x44\xed\x6e\x59\x1b\xe6\x5d\x49\xb8\xda\xd1\x66\xd6\x7e\xfe\x33\x02\x88\x3b\xad\x6a\xaf\x36\xe2\x2f\x01\x1d\x0d\xc6\x82\x82\x54\xe3\xfb\x17\x2d\x07\x38\x12\x64\x4a\x10\x53\x01\xad\x72\xb8\x8b\x10\xc3\x94\x8d\xe8\xd8\x17\xc2\xc4\x4a\xdd\x95\x6a\xcc\x32\xcc\x25\x10\x99\x1b\xcf\x45\x26\x31\xba\x11\xee\x17\xa5\x89\x55\xe2\xa6\xce\x21\x54\x4b\x9f\x4a\xd1\xb9\x12\x99\x99\xc0\x14\x31\x49\x66\xc3\xa6\x4d\xdc\x4f\xbe\x11\x14\xc5\x07\x7d\x9b\x0e\x0a\x31\x1f\xf5\xc7\x68\x82\xf9\x68\x30\xf6\x39\xe6\xa3\x23\xb9\xe3\x23\x04\x92\xc9\x70\xe2\x85\x96\xc0\xa0\x79\xbf\xbc\x51\xeb\x29\xa2\x46\xbe\x6b\xab\xfb\x06\x05\xb2\x11\x29\x31\x4f\xb1\xa0\x11\x35\x81\x4f\xdd\x2a\x23\xc5\x01\x8a\xa7\xd2\xf2\xf6\x1b\x95\x57\x86\xda\x17\x49\x19\xfb\x9b\x65\x7b\xa8\x5d\xc4\x58\xa6\xc3\x40\xf0\x61\x21\x68\x94\x97\x32\xcf\xe0\x9a\xe2\x19\x92\x28\xdf\x47\x72\xbc\x37\x1b\xc0\x70\xbb\x0f\x0b\x29\x94\x53\x3f\x90\x6d\xfb\x0c\x88\xfb\x0b\x22\xa8\xdd\x87\x28\xa8\xde\x06\xb0\x7e\xe9\xe3\xab\x21\xf8\x5e\x70\xae\x29\x0a\x20\xa2\xee\x7b\x01\xc8\xa3\x0a\x95\x44\x1a\xf4\x95\x1c\x78\x20\x6f\xff\x61\x80\x42\x24\x26\xcb\x25\x63\x29\xf6\x44\x58\xf0\xca\x6a\xf5\x04\xac\xb4\x4c\x89\x02\xaf\x7c\xb1\x08\x7d\xb1\x6c\xdb\x7d\x54\xe3\xfe\xd6\x7d\x41\x7f\x0b\x15\xd8\xe2\x40\x82\xff\xfc\x4d\x05\x03\xfa\xdb\x56\x71\x8d\xc5\xd1\x79\xc8\x43\x9e\xa6\x3c\x68\x4d\x49\xd6\x22\x71\xca\x49\x70\xd9\x0a\xa3\x94\x07\x4e\xbd\x84\xe2\x59\xa7\x2a\xc7\x03\x12\xc7\x3c\xd8\xbe\xd8\xe7\xf5\x6e\xd5\xaf\x45\xcd\xaf\xbf\x58\xf1\x39\xc9\x5a\x6a\x19\x8a\x3a\x5f\xef\x5e\x22\xa4\xbf\x6d\xd7\xc6\x98\x25\x91\xd7\x8c\x94\x9f\x15\x75\x65\x8a\xba\xa2\xbe\xb1\x0a\x62\x52\x30\x66\x33\x0b\x5b\x4c\xaa\x56\x8f\x02\x29\x98\x98\x20\x6f\x9a\xd6\x2b\xc5\x9e\x32\xe3\xda\xc3\x19\x0a\x99\x60\x75\x95\x0c\xc9\x1a\x2e\x83\x32\xab\x47\xaf\x1d\x41\x9c\x18\xe0\xd2\x11\xae\x5c\x68\xdf\x53\xc0\x11\x43\xcc\x78\xb2\x95\xaa\x4b\xa1\x08\x6d\xfd\x22\x7d\x81\x15\xbe\x5a\xb2\x61\x79\xa3\xee\x73\x02\x42\x86\xd4\x3e\x7a\x75\x15\x2e\xf3\x09\x0e\x4b\xeb\x00\x67\x98\x01\x9b\xe6\x4c\x99\x6d\x4c\xa5\x9b\xcd\xba\x90\x97\xe7\x9a\xcd\x82\xcd\xa6\xdc\x36\x50\xf5\x6d\x7b\xec\x21\xb5\x7d\xf1\xf6\xc1\x9b\x67\xaf\xdf\x39\x82\x30\xac\x5f\x7b\x1c\xbd\xd5\xdb\xea\x05\x9a\x28\xc4\x05\x11\x43\x21\x44\x53\x25\x01\xce\xb0\xda\x6b\x67\x6e\xae\xe6\x6b\x58\x3e\x79\xb7\x1f\x1d\xfb\xfd\x7b\x33\xb9\xe8\xf4\xa6\x4a\xf3\xa6\xcf\x27\x31\x8a\xed\xbe\x1a\x89\x58\x56\x33\x63\x60\x80\x1c\x9d\xb7\x25\xa3\xc9\xf3\xa0\x15\x26\x69\x2b\x4e\x48\x10\x2d\x26\x2d\x15\x94\xb4\xe5\x74\x03\xe8\xff\x0f\x4c\xc4\x5a\x9a\x08\x5e\x1a\xc3\x02\xcd\x20\x0a\xdd\xb7\x82\xce\x70\x37\x59\x88\x12\x58\x3c\x48\x6c\xcf\x72\x92\x73\x36\x25\x8b\xba\x89\x9e\xbb\xf2\xeb\x5b\xf1\xb5\xd3\x71\xe4\x19\xfc\xc0\x69\xe3\xad\x74\x96\xcc\x97\x02\xb5\xb6\xbe\x6c\x36\x40\x76\x82\xb9\x31\xd9\x6c\xda\x03\x34\x15\x6c\x7e\x22\x78\xfc\xa4\x5c\xe0\xb0\x90\xcd\x91\x7e\x80\x78\xb7\xfb\x52\x61\xb6\x07\xa0\x8f\x1c\xb9\x4c\x5a\x72\x33\x7b\xb7\xe3\x07\xbb\x3d\xf7\x43\xcc\x5c\x62\x36\x78\x33\x89\x05\x8c\x82\x10\xad\xf5\x16\x29\xbf\xc8\x7b\x9f\xc8\x19\x51\x40\x1c\x19\xa5\x3b\xe3\xb9\xe7\xbc\x7f\xf7\xf8\xf0\x67\xa7\x80\x7e\x26\x10\x38\x84\x7e\x20\xfe\x12\xe8\xc7\x82\xb4\x6d\x6f\x4e\x95\xf7\xc6\x96\xf8\x17\xb3\x52\xff\xd1\x5f\x01\xc5\x80\x54\x68\x07\xdd\x09\x37\x7b\x5d\xd9\x2f\x97\xef\xc8\xe4\x25\x99\x73\xe0\x3c\x7d\x74\xfa\x50\xba\xd1\xf4\xdb\xd8\x38\x40\x0c\xe9\xa8\x3f\xf6\xc8\xf6\x16\x59\x55\x5b\xc4\x40\x29\x0b\x6a\xa9\xef\xb5\x21\xaf\xea\x4d\x68\x30\x06\x99\x85\xee\x9e\xab\xfa\x3a\x9d\x4f\x4c\xd1\x5c\x99\xed\xad\xad\xe9\xc9\x2f\x52\x2e\xd1\x38\x2d\xbd\x37\x6b\x9c\x59\xac\x74\x8d\x50\xe7\xf2\x51\x4d\xa6\x7a\xde\x41\xaf\x73\x9f\x96\xdb\x89\xcd\x98\x2f\xd5\xac\x25\x49\xf9\x22\x7f\x99\x04\xbc\xfe\xe6\xa6\x7c\x9e\x9c\x71\x35\xe8\x04\xca\x2d\xd1\x6a\xc1\xcf\x6a\x0b\xde\xf9\x35\x53\x61\x23\x5a\xb2\x45\x2d\x20\x15\x83\xef\x9c\x2e\xe9\x3a\xd0\x91\xd7\xc0\xb1\x2e\x76\xbc\x96\xd3\xa5\xd0\xb7\x95\x1a\x73\xdb\xbb\x28\x80\x49\xf1\x00\xcc\x98\x20\xf3\x4f\xdd\xd0\x4d\x0c\x7d\x9c\x33\x3c\x65\x28\x61\x78\xc1\x2a\x12\xb9\xb4\x05\xa4\xdf\x85\x80\xa4\x5c\xac\x11\x71\x7f\x43\xc4\xe5\x44\x60\x9f\xc5\x01\x17\xe5\xf0\x32\xcc\x24\x66\x12\x5c\x3a\x15\x6b\xa2\x34\x17\x79\xd6\x86\x80\x1c\x3f\x3a\x41\x15\x32\x7b\x6b\x92\x5d\x2e\x98\xd7\x1e\xa0\x40\xb0\x1b\x4f\x48\xa7\xd0\x76\x8b\xd5\xc2\x01\xb0\x37\xbc\xbe\xa7\x40\x48\x98\x92\x58\x99\xf3\x1c\xb0\x90\xbd\x73\x1f\x90\x9a\x6e\xb1\x60\x98\xa8\x33\x62\x89\xfb\xb8\xfe\x69\x6e\x7d\xfa\x1b\x2f\x99\x7e\x94\x88\x90\x30\x75\x1d\x5c\xe2\xae\xea\x85\x08\x7e\x2a\xba\xb7\x64\xd0\x37\x16\xa4\x3a\xf5\xdf\xde\x3c\x51\xa3\x40\xf1\x75\x06\x00\x49\xbe\xd5\x9e\xd2\xcd\x26\xa5\x00\x0e\x9f\x88\x2a\x2b\x77\x7a\xb8\x66\x4a\x50\x9f\x33\x10\x20\x0a\x61\x01\x3d\x9d\xa2\x59\x5c\x39\x82\xa6\x35\x02\x33\x9e\x12\xc0\x6a\x50\xbe\x32\xca\xfa\x73\xf3\x60\x0b\xc2\xa7\x06\xe8\x9c\xec\x31\x61\xaf\xf5\xe1\x00\x82\x7e\xf3\x28\xe2\xc4\x63\xfa\xb4\xde\x99\x41\xc1\xb7\xe2\x41\xa6\xb8\x49\x7d\x98\x75\xdd\x6f\x47\x64\xdc\xe9\x88\x5f\x57\x11\x6f\x93\x7d\xf9\xb5\xec\x13\x62\xb2\x12\xd2\x70\x0a\xa3\xb1\xcf\x04\xae\x9b\x2e\xb9\x54\x8b\x7d\xb3\xa9\xf8\x04\xc6\xa5\x37\x89\xc5\x2f\x86\x04\x40\x6f\x8f\xa3\xc1\x10\x94\x05\x76\x77\xc2\x1f\xbe\x7a\xf1\x40\x39\x04\x3c\x57\x1c\x4a\x0b\xb2\x7b\x60\x01\xc9\xc8\x74\xa6\xaa\xc6\x3c\x27\x6c\x2a\x33\x0e\x77\x93\x80\xa3\x28\x9c\x83\x08\xf4\x2a\xe9\x7c\xdb\x79\x42\xd3\xc1\x61\xed\x0d\x13\xaf\xfe\x6e\x6b\x4c\xb5\x2f\x40\x48\x4d\x00\x16\x05\x34\x83\x7f\x46\xf0\x5b\xb5\x92\xce\xdc\x5f\x6a\x13\x21\xe6\xde\xe4\x7a\x58\x9f\x4d\x31\x81\x9b\x0d\x10\x7f\xb0\xba\xad\x2d\x10\xcb\x02\xfa\x16\x22\x08\x1d\x41\x97\x7e\x44\xb6\xf4\x6a\x55\x70\x42\x3c\x8a\xaa\xd2\x2a\xf7\xaf\x58\x47\x62\x2d\xc3\xb0\xb2\x55\x2a\x68\x73\x79\x5c\x75\xb5\x64\xc9\x5c\xba\x3f\xe9\x13\xab\x39\xcf\x72\xf9\x7e\x32\xf0\x9c\x65\xca\x0f\x4f\x6e\x3b\xe8\xe4\xc8\x7a\x3e\xb6\x9e\x4f\xac\xe7\x3b\x9e\x73\xa2\x0e\xad\x9e\xa8\x48\x30\x27\x77\xdc\x23\x07\x9d\xfc\xec\x39\x27\x3f\x8b\x74\x5d\xb7\x78\x75\x90\xa9\xd8\x73\x4e\xee\x3a\x48\xd7\x2a\x5f\x2c\x93\xc0\xbf\xcc\x32\x1d\xd0\xd2\x51\x82\x94\x26\x1d\x86\xfb\xfa\xc8\xc4\x8e\xe7\x73\x14\x82\xc1\x3d\x65\xf9\x66\x3f\x1c\xd5\x8f\xf8\xbc\x5f\xf0\x33\xbe\x68\xa9\xb3\x57\xad\x24\x6c\x95\xa5\xad\x3b\x92\xd5\x79\x31\xe6\x07\x5d\x7c\xa4\x4c\x35\x72\x53\xbf\xf4\xa4\x0e\xac\x63\x69\xa3\xa0\x2b\x34\x68\x63\xc7\x56\x9b\x42\xb6\x2a\xf6\x2f\x93\x46\x49\x86\x89\xfb\x00\x98\xb3\x68\xa5\xb8\x1c\x74\xbb\x55\x0d\x4c\x42\x96\x7b\x6b\xe2\x11\x6a\xcb\xa4\x28\xae\x4e\xf2\x54\x59\x03\x44\x44\x8e\x62\x8e\xff\xb5\xf4\x08\x7f\xee\x3e\xac\x11\x01\xa6\x8d\xac\x95\x97\xe7\x68\x8c\x28\xee\xfb\xf4\x9e\x3e\x9f\xa5\xdb\x41\xbb\x5d\xa8\x0f\x89\xa9\x21\xd7\xba\xc7\x88\x8e\xc7\xb6\x13\xd5\xdc\x7d\xd0\x58\x41\xfd\xd0\x97\x3a\xc4\x07\x6a\x1b\x12\x29\x2b\xed\x0a\x4c\xee\x17\x95\xc7\xdd\xaa\xab\xa9\xfb\xf2\x6a\x6a\x7a\xaf\xfa\xea\x97\xe7\xeb\x64\x5b\xfc\x77\x80\xb8\x14\x05\xd2\x85\xc9\x25\x23\xd6\xed\x8e\x71\x00\x45\xf3\x8b\xaa\x10\x66\x45\x53\x3d\x4a\x03\x5a\x17\xca\x0d\x1e\xd3\x9d\xaa\x4c\x2d\xe8\x9d\xbc\x11\x59\x5a\xb7\x4d\x1d\x88\x8f\x82\x31\x16\x7a\x76\xb7\xeb\xd7\xaa\x2a\xe6\x75\x07\x36\xfb\xa4\xc3\x3b\x3d\x9a\x88\x40\xed\x08\x32\x22\x63\x8f\x8a\x71\xdc\xf5\xb0\xb0\x32\x6f\x36\x5a\x71\xec\x76\xb5\x55\x5c\xcd\x0d\x81\x46\x83\x14\x4b\x5f\xc2\xd1\xa7\x72\xb7\x60\x55\x07\x17\x65\xf6\x3d\x98\x67\x9d\x71\x41\xa1\xde\x4d\xe6\xb9\x90\x91\x89\xf1\x68\x0f\x11\x2f\xb7\x42\xab\xc9\x7c\x57\xeb\xe5\x95\x9c\xe3\x95\xcd\x4f\x54\x98\x31\xdc\xfb\x07\x0c\x3d\x30\xfa\xc7\xeb\x0d\xbf\x73\xc7\x5d\xe8\xc1\x21\x18\x7a\x1f\x7a\x1f\x7a\x2a\xfd\xc3\x87\x9e\x3c\xd8\xf5\xff\xe0\xb0\x7a\x1b\x42\x30\xf4\x3c\x30\xea\x1f\xde\x1d\x77\xa1\x28\x81\x47\xea\xd3\xe6\x7b\x28\x33\x0e\xbf\x1b\x77\x15\x24\xf1\x26\x00\xc8\xb7\xef\xcc\x51\x15\x08\x87\xdf\xf7\x2a\x22\x93\xb3\x72\x47\xb7\x7e\x61\x7a\xc7\x22\x06\x0d\x97\xa5\x1b\x94\x1c\xb1\x71\xe5\x1d\x8f\x1d\xa8\xb7\x7a\xd5\x51\x54\x1c\x18\x6f\x67\x99\x2f\x5b\x51\x75\x88\x09\xf4\xe5\x96\xc3\x76\x6a\xd0\x1d\x68\x2a\xa2\x0a\xf8\x42\xf1\xe1\xc3\x80\xef\x1c\xf7\xe1\xe5\xd9\xc3\xde\x87\x6e\x6f\x82\x9c\x96\x03\xa1\xe7\x38\xb0\xb0\x77\xab\x57\xb6\x4d\x42\x1b\x60\xb5\xcd\xdb\x9c\xeb\x9c\xef\x3a\x4b\xd0\xf2\xa3\x74\x9b\x50\x1a\x51\x8d\x9c\xad\xd8\x10\xe8\x0c\xc4\x8d\xd0\x19\xd3\x16\x5d\x77\x02\xf5\xc6\x0d\x26\xee\x27\x64\xbc\x85\x5c\x82\xce\xcb\x2c\x73\x9d\x45\xed\x2b\x5d\xe8\xf4\x4b\x26\x77\xd1\xf5\xb7\x29\x26\xee\x14\x7a\xca\xe9\xa9\xf4\x5f\x75\xe7\xd2\x4c\x96\x31\x31\xa1\x65\xfb\xca\xda\xe9\x68\xa0\xfc\xc9\x85\x34\xa1\x5b\xf1\x99\x01\xaa\x0f\xe9\x41\xd3\x1c\x99\x76\x5c\x65\x3d\x2f\xcb\x9f\x8c\xcb\xb6\xc9\x4c\xb7\xab\x4c\x17\x65\xa6\x3b\x5b\x95\x4c\x55\xde\x9f\x54\x25\xd0\xb3\x5a\x66\xbc\x51\xf8\x79\xeb\xbd\xda\xa8\x51\xdf\x20\x2c\x0e\x56\xb6\xe5\xc7\xd8\x30\x76\x0f\x4d\x48\x4a\xad\xa6\x4c\x9d\x5d\x91\x14\xe0\x94\x01\x8a\x7e\x61\xb2\x11\x8e\x57\x5e\x60\xae\x3a\x28\xfd\x0f\x36\x1b\xe9\x21\xe9\x60\x4c\x0d\x49\x77\x7a\x3d\x07\x22\xa0\xc1\x7d\x82\xcd\xd0\xfe\x9f\x03\x91\x4e\xdf\x7f\xca\x8c\x41\x58\xe1\xdf\x0f\x47\xb7\x81\x3a\xcd\x19\x9e\x1e\x3e\x1e\xaf\x8f\x0a\x28\x10\xf2\x87\xef\x07\x0e\x84\x48\xb7\x6a\x8e\x4a\x8d\xd4\x34\xc7\x73\x50\x05\x4e\x36\x5a\xa3\x9f\x62\x70\x42\xfb\xed\x39\x6d\xcc\x5c\xa1\xe1\x9f\xe6\xa0\x5f\xb5\xd8\xe9\x55\xad\x3c\x65\x80\x21\xa7\xe7\x60\x3b\xe7\xf0\x01\xf3\x1e\xca\x1e\x41\xdf\xc0\x65\xf6\xe1\xce\x0a\xd4\xd0\x11\xca\x9b\xc9\x34\xb5\xbe\x7c\xe7\x20\x09\xfc\x11\x83\xd6\xc5\xf8\x9f\x92\x68\x01\xc4\x42\xf3\xeb\x73\xa8\x55\xa0\x9a\x6c\x57\xf9\x99\xac\x34\x8f\x44\x0c\xb7\xdb\xc4\x9d\xf8\x6c\x78\x26\x86\x5d\x2c\x19\x4f\xa5\x7d\xf2\xd9\x90\xaa\x95\xa3\x53\x88\x4c\x91\x0b\xc8\x63\xda\x4c\x45\xdc\xb9\x6f\x98\xa1\x3c\x16\xc9\xe0\xb9\x02\x34\xd7\x92\x82\x1c\x49\x51\x5c\x11\x35\x39\x88\x41\x35\x34\xb0\xdc\x80\xea\x74\xda\x7a\xc0\x03\xec\xf4\x9c\x6e\x50\x5d\xc2\xce\x31\x75\x69\xdd\x07\xbf\xe7\x40\xff\x70\xd0\xc6\x32\x92\x81\xfc\xac\xe8\x16\xe8\x23\xde\x1d\xc0\x6e\x00\x0b\x8e\x03\xe9\x90\xea\xba\xfa\xa8\xbb\xfc\x2b\xa0\x3b\x65\xd3\x24\x88\x8a\x60\xba\x3d\x07\x6e\x36\x5b\x89\x3d\xd7\x81\x70\x1d\xe0\x3e\xc6\x7c\xbb\x11\xa8\x2f\xe8\x26\x37\x44\xba\x67\x11\xe9\x50\xac\x16\x75\x02\x9e\xd7\x25\x87\x29\xe6\xa3\x49\xb7\x3b\xf6\x65\x8b\xa6\xc3\xa0\xd3\x99\x48\xd8\xda\xe4\x19\xea\x19\x77\xa0\xa7\x1a\x3f\x1d\x02\x30\xb8\x17\x96\xc7\xed\x07\xd2\xd1\x58\xe7\x3e\x70\x9c\xb6\x3c\x4c\x02\x65\xc9\x64\x29\xf8\xea\x5e\x88\xd0\x03\xfa\x65\x2a\xd8\x6f\xbb\x0f\x8b\x00\x87\x1a\x8d\x7a\x8e\xa6\xf7\x01\xe6\x85\x98\x6c\x8a\x03\x8f\x61\x51\x01\x26\x35\x8c\xf5\xd9\xf0\x42\xcc\xb3\x21\x94\x1a\x45\xa6\xca\x86\xaf\x29\x66\xb5\xfd\x6e\xf9\xe4\xb3\x6a\x63\x6d\x82\xd9\x50\x50\x2b\x24\x77\x02\x7c\xb5\xd7\xa1\x77\x3d\xaa\x05\xed\x7d\xdf\x43\xa2\xe1\x95\xe1\xe3\xbc\xe2\x91\x14\xae\x29\x7e\x29\x25\x67\xa1\x00\x45\x21\x88\xb2\x97\xe4\xa5\xdc\x08\xe9\xdf\xa7\x75\x41\xfb\x17\x12\xb4\x96\x49\x9a\x1b\x51\x5b\x9a\x6e\x88\x3b\x37\xa7\x86\x89\x66\x3f\x55\x4d\x17\x65\x6b\x6b\x5b\x19\xef\x87\x40\x6e\x80\xa0\xc7\xb2\xfb\x88\x08\x22\xea\x09\x32\x07\x28\x96\xf4\xeb\x89\x60\x1e\xa4\xa4\xb6\x54\x65\xb1\xac\x4d\x9f\x59\xfd\xf8\xe9\x90\x56\x7c\x15\x90\x1a\x39\x93\xe4\xeb\xe8\xf6\xd1\x6d\x31\x7b\x0d\xcc\x57\x68\x95\xd6\xf9\xd2\x53\x56\x37\x05\x34\xc5\xd1\x00\x04\x97\xe4\x54\xb0\x32\x53\x1d\x45\x4f\x19\x44\x4c\x1f\xb9\xb8\x22\x4d\x25\xd0\xab\x8f\xda\x53\x66\x64\x17\xb1\xcc\x1f\x24\x01\x97\x4b\x5d\xa3\x83\xf3\x83\xd3\x05\xe4\xfe\xfd\x93\xce\xe0\xb6\x65\x2f\x1f\xdc\x81\x5d\x40\x76\xd2\xa4\x1f\xc1\x2f\x0c\xf7\x46\xdf\x7d\xe8\x7d\x18\xfe\xbf\x71\x6f\x82\x1e\xaa\xd7\xa1\x27\x5e\x1e\xe8\x17\xf1\xfc\x44\x3f\xcb\x5c\x8f\x18\xee\x7d\xd7\x9b\x54\xa8\xf7\xbe\xa6\xbe\xed\x38\x28\x32\x4c\xea\xfb\xf0\xed\x36\xb5\x26\xec\x77\xe5\xb5\xa2\x1c\x9c\xd5\x9e\xd3\xbf\x4c\x3a\xa2\xf4\xc5\x44\x77\x3a\xb9\xc2\x85\x4a\x41\xd7\xbb\xc7\x41\x00\x1a\x26\x8d\x36\x49\x4c\xd2\x8d\x53\x28\x50\xef\x6b\xfa\xd3\xae\x87\xf7\xef\x5a\xc5\xc9\x2d\x07\x53\x82\xff\x30\x5e\x15\x35\x06\x2c\xc5\x67\x02\x7d\xb6\xd9\xe8\x04\xe5\x0e\xce\xf0\x68\x0c\x7d\x6d\xbb\x2a\x7d\xc3\xbb\x78\x60\x2b\x4e\xd6\xca\x7d\xc6\x4c\xdd\x04\xfa\x14\xff\xa1\x3c\xca\x85\xf2\x23\x24\x27\xaa\xd4\x1f\xed\xc7\x42\x5c\x7a\x28\xf5\x1c\x51\x37\x85\xe6\xc4\x99\x12\xbe\x94\xbe\x24\x0b\x54\x5b\xae\x42\xc5\x21\x2e\x3b\x3c\x44\x95\x22\x73\xff\xe8\x96\x1c\x59\xa9\xa6\xd9\x04\xe0\xd7\xc6\xa6\x94\xfa\x8d\x69\x51\x71\xb0\x4f\x15\xa9\x8d\x1f\x31\x99\x2a\x6b\x94\xdc\x93\x7f\x52\xb3\xd9\x71\x31\x99\x26\x48\x06\x0a\xb4\x02\x52\xff\xb3\xad\x8a\xfe\xbe\xa3\xea\xea\x0a\x1f\x02\x68\x04\x29\xa5\x82\x8b\xc9\x30\x31\x61\x6c\x6d\xc8\x94\xe4\x32\x3e\x0c\x6a\x38\xd3\x6f\x26\x50\xa8\xde\x55\xfc\x98\xba\xd6\x4d\xaa\xa6\x28\x19\x60\x34\x6e\x0e\x61\x40\xe0\xaf\x46\x32\x86\x52\xda\xfd\x95\x00\x8a\x2c\x3c\x2a\x51\x0c\x6a\x4b\xc0\xda\xee\xd3\x97\x14\x14\x0d\x8b\xc8\x43\xd8\x15\x63\x38\x68\xd2\x3a\xbf\x86\xde\xb5\x46\x2a\xbc\x3d\xac\x63\xbb\x51\xb0\xfd\x1a\xca\xcb\xad\xff\x3d\x78\xde\xa4\x31\xdb\x2e\xe3\x42\xe9\x50\x75\x3c\xb4\x7c\x32\xfa\x65\x27\x87\x46\x31\x10\x9c\x58\xa9\xd3\x4d\x72\xb4\x11\x77\xca\x60\x11\xea\x4d\xc6\x80\xd1\x8e\x38\x9a\x4c\x3a\xdb\x16\x92\x1a\xba\x88\xf1\xa5\x0d\x0a\x20\x55\xb1\x7e\xbe\x18\x22\xc5\x0f\x4c\x47\x02\xb8\x75\xd4\x3e\x68\x0a\x17\xe1\x4b\x01\x20\x18\x85\xe3\x4e\x07\x4c\xba\xf8\xcb\x31\x1f\x44\x3e\x28\x1d\x33\x95\x55\xbc\x3a\x37\x63\xc8\xac\x96\x36\x3a\x4e\xcd\x18\x73\xc9\xea\x32\xea\x7b\x9f\xba\xca\x83\x59\x9f\x37\x29\xa9\xae\xf4\xb3\x41\x54\xe9\x6c\x4d\x07\x4b\x14\x41\x58\x97\xca\x9a\x64\xf3\x32\xd4\x05\xa6\xfb\x0e\x12\x56\xa5\x1f\x6b\xea\x42\xa5\x97\x87\x28\x26\xe8\x0c\xb2\x88\xdb\x3e\x8a\xa1\x56\x6a\x50\xaf\xc2\x0f\x94\x94\xfa\x4c\x23\x6d\x00\x91\x79\xe4\x10\xf5\x4b\xeb\x87\x41\x65\x5d\x8b\x85\xb8\x7f\x94\xb9\x7f\x23\xa0\xd4\x4a\x69\x17\x97\xc7\x9a\x61\x21\x5d\x58\x95\x47\xb3\x34\xb6\xae\xca\x28\x1b\xd8\x71\xd0\x5f\xe2\xe7\x37\x86\xfe\x46\xcf\x35\xf8\x17\xd6\xc6\xd3\x4b\x06\xe0\xfa\x2f\x2c\x72\xfa\xcf\x19\xfe\x1b\xff\xa6\xd7\xdc\x99\x8a\xe0\x12\x73\x69\xf8\x15\xa2\x31\xf8\xa5\x9e\x84\x5e\x31\x88\xaa\xb4\x8c\xe7\xaf\x16\xcf\x13\x12\x3c\x20\x71\x4c\x09\x9b\x39\xe8\xa9\xfb\x46\x3b\xd7\x92\xca\x70\xdf\xbc\x73\xa9\xf7\x50\xa1\x4f\x70\x65\xb2\xd7\x76\x5a\x15\xbb\x65\xb3\x21\x23\xb3\xe0\x0e\x07\x63\xb9\x05\x6a\xc5\x4e\xc8\x52\x26\x4b\x6b\x15\x87\x18\x72\x27\x74\x97\x17\x0c\x8b\xd9\x57\x4a\x7b\xef\x9f\xf3\xf3\xf3\x0f\xee\x24\xcb\x49\x1e\xb1\x0f\x2e\x5b\xf4\xe0\xd0\xd1\xaf\x2e\x5b\x38\x5e\xf5\x92\xcc\x1d\xff\x35\xab\x3b\x7c\xbd\xd6\x12\x8e\x92\xee\xea\xa2\x71\x55\xa9\x20\x45\xf2\xe4\xa0\x1c\x09\x79\xbc\x79\x8b\xde\x2a\x8f\xd6\xff\x49\x67\x17\xb3\x63\x02\xa0\xf2\x89\xa1\x62\x42\x0d\x14\xb2\xca\x13\x35\x07\xfb\x08\x77\x9e\x5e\x4a\xfd\x4a\xca\xea\x66\x17\x53\xc6\x57\x92\xa7\xc1\xa5\xc1\x22\x09\x56\x31\xcf\xe4\x92\x27\xb8\xef\x93\xca\xf2\x46\x2a\x0a\xc2\x46\x64\xec\xbf\x62\x20\x90\x1e\x26\x28\x70\x75\xe4\x5e\x14\xc0\xa2\xa8\x5c\x4e\x6b\x92\xf5\xa9\x6e\x5e\x2b\x24\x51\xcc\x83\xd6\x79\x94\x4f\xbd\x96\xd3\xe5\xd0\xb7\x7d\x90\xdf\x58\x4b\x9c\x20\x86\x84\xd6\x68\x26\x44\x1b\xdd\x0f\x7b\x50\xba\x15\x89\xb9\x2a\x25\xa4\xea\xa3\xd4\x04\x7c\x82\xa9\x1f\x24\x52\xfe\xc7\x18\xcb\xbd\x05\x41\xda\xb7\x02\x67\x85\xd1\x22\xca\x79\x2b\x4e\x92\x65\x2b\x5a\xb4\x74\x37\x4c\x30\x2a\xbd\x73\x0b\x58\x55\x5e\x56\xcb\xa0\x3e\xeb\xce\xa0\xcf\x30\x08\x86\x66\x13\xe2\x50\x85\xc1\x31\xbb\xf1\x26\xa0\x71\xb9\xe7\x20\xdd\x6a\x3d\x86\xa8\xdc\x6c\xb3\x8e\x27\x58\x9d\x16\x55\x3d\x73\xa7\x64\xf4\x82\xe9\xcd\x94\x14\x31\x2c\x87\xc5\x10\xa2\x6a\x23\x14\x50\x54\x56\xc2\x5c\x4a\x0a\x8d\x18\x5b\x56\x99\x00\x57\xcb\x54\x5d\x93\xaf\x21\xbb\x3a\x4c\xc4\xdb\x25\x67\x51\x18\xb1\x72\x11\xef\xcb\xbf\x5c\xd1\x38\x62\xcf\xf7\xe5\x3a\x6b\x04\x27\x39\x57\xb0\xab\x68\x99\x96\xb7\x9c\x2e\x81\x82\xac\xd8\x92\x14\xc7\x01\x60\x25\x62\x71\xe8\x97\x41\x96\xb8\x92\xc1\x85\xf2\x2a\x3a\x6b\xec\x95\x5f\x6e\xf2\xdb\x1d\xb2\x73\x95\xf6\xef\x12\x2b\xa1\xcb\x37\xee\x4e\x4e\xe0\x3a\x54\x2e\x90\xc6\xf1\xb2\x28\xdd\x90\x6a\x9e\x8a\xef\xe4\x64\x37\xac\x4f\xa9\x52\x8d\xc8\x18\xfa\xf5\xb0\x4d\x44\x39\x6a\x58\xd1\xf5\x00\xd1\x68\xf2\x97\x25\xad\x35\x71\x1c\x75\xe4\xb5\xce\x6b\xa8\x3a\x3b\xcf\x48\x0e\x98\x36\x4a\xf4\x46\x1f\x32\x34\xee\x7e\xc8\x6e\xf5\xec\xe8\x68\x16\xc3\x7b\x6f\xf4\x35\x19\xf4\xa2\xda\xfa\xb0\x34\xc0\x43\xa1\xa2\x7c\x74\xe0\x56\x75\x0d\x14\xcd\x87\x04\x53\xa4\x50\xfd\x0f\x21\xd5\x8b\x25\xaa\x4c\xa7\xed\x01\xf4\x95\x7f\xbe\x5e\xf4\x1f\x47\xff\x7c\x1c\x77\xbf\xef\xc1\x61\x5d\xdf\x34\xe9\x62\xb5\x23\x82\x65\xfb\xa0\x47\xb0\xc3\x17\x8e\xb5\xf3\x63\x29\x67\xb5\x1e\x48\x1a\xf8\x67\xa7\xf3\x67\x5b\xd5\x6c\x02\x86\x9d\x93\x74\x01\x9c\xd6\x69\x9e\xf3\xf9\x32\x57\x11\x8e\xa4\x17\x50\x49\x1b\x7e\x94\xfe\x1d\x3f\xb6\x92\xb0\xf5\x44\xe2\x4e\xeb\x81\xc4\x1d\x15\xd5\x2e\x9f\xf2\xd6\x32\xe5\x67\x51\xb2\xca\xe2\xcb\x96\xda\xdf\x14\x65\xc0\x9f\xa2\xd0\x79\x14\xc7\x2d\xca\x5b\xab\x8c\xab\x43\x27\x9c\x04\xae\x54\x90\xf1\x9f\x65\xab\xff\x54\x6d\xb4\x64\x95\xdd\xa6\xff\xd5\xe9\xfc\x75\xe5\xa6\xd7\xda\xa9\x1c\xba\xc8\x62\xb2\x22\x13\x6e\x7a\xf3\xb5\xc6\xff\xf5\x95\xc6\xff\x05\x7d\x31\xf0\x7a\x1a\x09\x76\xaa\x39\xf8\x6b\xbb\x37\x7f\x5a\xc4\x6e\x5d\x20\x56\x85\x77\x22\x50\x88\xa6\x6a\x1f\xa1\x44\x41\xcb\xc5\xd7\x08\x5d\xf8\x4f\xc1\x0d\x7d\xea\x06\xc9\x9c\x44\x0b\xfc\x82\xf9\xea\x6c\x81\x58\xa1\x92\x55\x96\x6f\x82\x11\xfc\x5e\xb2\x79\x86\xa9\x6b\xba\xee\x33\xfc\x07\x03\xef\x99\xb4\xe5\x56\xc9\x58\xc9\xd9\xbf\xa9\x8d\x58\xea\x2a\x2f\xe5\xf7\x69\xfc\x96\xe7\x62\x50\xb3\xd2\xbb\xe8\xfd\x9b\xe7\x6f\x39\x49\xd9\xf4\x35\x49\xc9\x3c\x93\xdc\x95\x60\x20\xf9\x7d\xfd\x13\xc8\x93\x65\x75\x86\x3f\x93\x5f\x20\xd4\xbc\x5f\x4e\xca\xa1\xc6\x2e\x41\x94\x48\x15\xd3\xce\x4c\x6d\xb4\x08\x13\xe0\x3c\x56\x8c\x33\x4f\x5a\x13\x9e\xb7\xea\x05\xd5\x29\x87\x3c\x59\x8a\xba\x1d\xc1\x87\x7f\x63\x58\xb2\x95\x82\xba\x4b\xc2\x66\x64\xc2\x33\xfc\x4e\x0c\x8d\x79\x2b\x67\x48\x08\x73\x3b\x6c\x43\x7f\x7b\x2e\x46\x5a\x3a\xef\x44\x8d\x2e\x1d\x4f\x15\x1b\xd2\x5b\x69\x24\xcb\xa2\xc9\x02\xac\x0b\x44\xd0\x3a\x23\x21\x97\x31\x82\xda\x7d\xe9\x8e\xf2\xcb\x36\xb1\x15\x19\x24\x27\x41\x02\x3a\xf4\x0f\x14\xb0\x5a\x35\x15\xa5\x19\x8d\xb5\x4a\xb3\xb3\x71\xde\xed\x32\x8d\x38\x56\x30\x53\x5f\x64\x76\xce\xa2\x6c\x45\xe2\xe8\x33\x31\xce\xce\x22\x5f\xa7\xc3\xba\x5d\x6d\x92\x2e\xfd\x0b\x9a\x65\x26\x91\x7d\xb3\xa9\x62\x9e\xda\xe9\x30\x28\x75\x07\xf1\x86\x0c\x50\xb9\x57\xfb\x99\xa8\x54\x79\x3a\x52\x3e\x95\xeb\x81\xc9\x80\x9b\x0d\xe3\x11\xeb\xb1\x10\x7f\xa1\xff\xd4\x7d\xb3\x7d\x0a\xa3\xfd\x77\x9d\x87\xbe\x58\x65\x79\x4b\x60\x7a\x6b\x17\x50\x8b\xf2\x30\x49\xf9\xd6\x97\x26\x7e\x56\x9a\x17\xff\xd6\x3e\xfb\xd0\xfb\xbb\x69\xb6\x9a\xe5\x76\x5f\x86\xb0\xf9\x9b\xe1\xc7\xc0\x51\xd1\x32\x7b\xbd\x39\x59\x66\xae\x2a\x4d\x96\xd2\xcd\x6d\x2e\xd3\x7a\x64\x19\xf5\x3e\x65\xc3\x4f\x19\x59\x46\x6f\x78\x10\xa5\x9c\xe5\x38\x4f\x57\xdc\x81\xe8\xfb\x1d\x10\x87\x64\x19\x1d\x66\x59\xec\x9a\x86\x68\x30\x0d\xe5\x3b\x61\x14\x73\x5c\x56\xe9\x40\x4b\x69\x24\x41\xe9\x03\x57\xa3\x94\xcf\xb5\x6f\xe7\x0b\xb2\xcc\x5a\xa7\xaf\x9f\x49\x89\x54\xd2\x40\x09\xbf\xa5\x7d\xfb\xa2\xac\x15\xf0\x65\xca\x19\xc9\xb9\x20\x77\x7e\xe5\x49\xc7\xdc\x19\xbf\xdc\x6c\x98\xcb\xe2\xa8\x72\xf2\x65\x6e\x1c\xd1\x94\xa4\x11\xcf\x90\xb5\xb9\x62\x79\x0c\xcc\x04\xdd\x8b\x71\xdf\x8f\xef\x99\xd3\x02\x7e\x6c\xa4\xeb\x25\x9e\x8e\xe2\xb1\x3f\x1b\x2d\x47\xfd\xf1\x18\x2f\x47\x83\xb1\x11\x24\x66\x05\x60\xae\x3c\x83\xf4\x71\x29\x09\xcb\xb0\xfe\x6a\xed\x03\xbb\x73\xb2\x04\x76\xdd\x1a\xc4\xd4\xe4\xc1\x0e\x2c\xa0\x37\x1a\x43\x14\xe2\x9d\xd5\xbb\x9e\xf1\x4b\x8f\xa0\x8c\x78\x41\x21\x74\xca\x09\x76\x8e\xe4\xea\x19\x7e\xcf\xbc\xbf\x99\xff\x77\xb3\x08\xa4\x9d\x15\x24\x09\x56\xf1\x3f\x4b\x2a\x6c\x89\xac\x13\xb4\x2e\x50\xa8\x05\xd5\x99\xfe\x3b\x35\xe7\xc1\x68\x60\xa3\xc1\xf9\xf9\xb9\x6b\x69\x59\xbd\x68\xb1\x5c\xe5\xf2\x2e\xbb\xde\xa7\xac\x17\xe5\xc4\x4a\xf9\x78\xec\x7e\xca\x6a\x33\xcf\xca\x99\xff\x2c\x94\x62\xd1\x22\x43\xfc\x86\xa0\x2e\x63\x55\x5f\xe0\xb0\x7a\xf6\x46\xd5\xf3\x18\xba\xd1\x82\xc5\xab\x80\x67\xc0\xa9\x6a\x75\xe0\xb0\xce\x81\x7f\x34\x78\xe5\x70\xad\xbe\x3a\x57\xc2\xac\x0f\x8b\xd7\x31\x27\x99\xf2\x39\x6e\xfd\xd8\x05\x34\xe8\x3a\x2d\x85\xe3\xf1\xa5\xe4\xb3\x7b\x86\xbd\xb4\x2a\x7c\x71\xd8\x69\x20\xc6\x7d\x6d\x34\x04\xae\xff\x06\xb0\x80\xd0\xab\xc7\x4b\x6d\xea\x82\x3a\xfa\x96\x4f\xc9\xa2\x65\xf7\x5e\x74\x62\xb5\xc8\x56\xcb\x65\x92\x8a\x5e\xfc\xb8\x0d\xcb\x36\x05\x08\x99\xc9\x40\x94\xa7\x16\xa2\xc5\x59\x32\xd3\xba\x60\xb2\xca\x5b\x99\x94\xbb\x2f\x45\xd5\x66\xd8\x1d\x85\x16\x41\x0d\x2d\xc8\x27\x72\xb1\x4d\x60\x44\x5a\x2f\x8e\x68\xd6\xfb\x61\xad\xb4\xd8\xa2\xf7\x83\x51\x8e\xc4\xa3\x20\x11\x45\x0d\x3f\x78\x60\xb9\xf3\x6a\x6d\x91\x48\x26\x41\xae\xa9\x29\x4a\xa1\xca\xa4\x49\x6d\x06\x30\x05\x46\x8a\x43\xb6\xc2\xd8\x20\x9a\x86\x41\x3d\x50\x81\x98\xb5\xdf\xdd\xef\x85\x92\x2d\x8f\x23\xac\x29\xe6\x42\xd5\x0b\x5c\x7d\x8d\x03\x94\x71\x68\xcc\x75\x39\x23\x3a\x6e\xd2\xb0\xde\x2f\x66\x8b\xe4\xbc\x6c\x2a\x12\xca\x6c\xd7\x41\x62\x12\xa4\xd0\xe7\xea\x5d\x78\x8e\xf5\x78\x79\x04\x19\x8d\x4c\x86\xd1\x46\x32\x62\x51\xe0\x56\x57\x4b\x14\x3e\xc5\xaf\x09\xd0\x3e\xb9\xc0\x78\x90\x06\x01\xfa\xcd\xe3\x05\x84\xb5\xdd\xbf\x46\x62\xab\xed\x0b\xff\x61\x45\x38\x5d\x40\xac\x05\xa1\x04\x1e\xd9\x25\xb1\x36\xf6\x91\xa4\xd0\x58\x28\xbf\xb8\x36\x02\xc1\x91\xd5\x7a\x98\x18\x0d\x5a\x10\x24\xb9\xe5\xf7\xa5\xa0\x59\x3a\x02\xf6\x0b\xd9\xab\x96\xf3\x63\x97\x74\x7f\x94\x6b\x62\x91\xe4\x2d\x7b\x55\xf8\x5b\x9e\xe4\xff\xb3\x1d\xb9\xeb\xb6\xdf\xa6\xc3\x59\x04\x12\x50\x6d\x96\x37\xea\x8e\xda\xaa\x53\x85\x0a\x39\xd3\x61\x21\x9b\xdc\x49\xb7\x76\x3d\xdf\x5d\x2e\xb9\xc0\x0b\xa3\xdb\x44\x59\xcb\xe9\x9a\xac\x0a\x53\x28\xb0\x82\x87\xd4\x0a\x1b\x79\xa0\x44\xac\x6d\x0b\x0f\x83\x7e\x61\xb9\xfc\xbf\x62\x37\x13\xec\xb2\xf3\x48\x46\x5e\x19\xf5\xc7\x70\xcd\x04\x7e\x38\x42\x2a\x70\x3c\x12\xe8\xf8\xfb\xea\x84\x31\x91\xe6\x31\x15\x26\x51\x65\x2b\xa9\x99\xc7\xbe\x96\xb5\x2e\x38\x7a\x4a\x28\xd3\x65\x9e\xd6\x0b\xe8\x50\xaf\x5e\xd8\x00\xb3\x28\x0e\xea\xd6\x50\x9e\xba\x62\x29\x08\x51\x7e\x95\x72\x47\x46\xd6\x7a\xc1\x86\xf5\xc5\x52\xd7\xd7\xca\x4b\x2c\x5b\xd9\x34\x59\xc5\x41\x2b\x59\xc4\x97\x42\x0f\xd3\xfa\x59\xb2\x60\xdc\x75\xa0\xf7\x92\x01\x85\xd4\x2b\x37\x25\xf8\x25\xd3\xcf\x17\x04\xbf\x31\xcf\x97\x42\x51\xd6\xcf\x9f\x09\x7e\x67\x9e\x7f\x15\x4a\x92\x7e\x7e\x46\xf0\x1f\xe6\xf9\x94\xe0\xd7\xe6\xf9\xdf\x26\x3f\xed\xe7\xac\xf0\x0b\x68\x9d\x58\xf3\xff\xbf\x00\x00\x00\xff\xff\x02\x42\xb6\x13\x61\xfe\x00\x00") func cmdInternalPagesAssetsJsLoaderJsBytes() ([]byte, error) { return bindataRead( _cmdInternalPagesAssetsJsLoaderJs, "cmd/internal/pages/assets/js/loader.js", ) } func cmdInternalPagesAssetsJsLoaderJs() (*asset, error) { bytes, err := cmdInternalPagesAssetsJsLoaderJsBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "cmd/internal/pages/assets/js/loader.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3a, 0xb4, 0xfb, 0x83, 0x63, 0xfe, 0xa4, 0xd4, 0xad, 0x17, 0x76, 0xa7, 0x11, 0x50, 0x35, 0x18, 0xf5, 0x8e, 0xf2, 0x13, 0xb0, 0x3d, 0xc5, 0x45, 0x1b, 0xd7, 0xb7, 0xe5, 0xfe, 0x7d, 0x64, 0x34}} return a, nil } var _cmdInternalPagesAssetsJsPopperMinJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x7c\x6b\x97\xdb\xb6\xb5\xe8\xf7\xfe\x0a\xea\x9c\x96\x00\x2c\x88\x23\xa5\x37\xf7\xdc\x4b\x19\xd1\x72\x9c\x71\xe3\xd4\xf6\xb8\xf6\xb8\x4e\x4a\x73\xc5\x1c\x11\x1a\x21\xa6\x08\x16\x80\xe6\x51\x49\xff\xfd\x2c\xbc\x48\x50\xe2\x8c\xd3\x7e\xf0\x88\xc4\x63\x63\xef\x8d\xfd\x06\xe8\xb3\x27\x7f\x88\x9e\xf3\xe6\x5e\xb0\xeb\xb5\x8a\xe0\x73\x14\xbd\xa0\x25\x15\x6c\xc9\xa3\x7f\xb0\x1b\x5e\xf1\xe8\x9b\xe9\xec\x7f\xfe\x10\xfd\xc0\xa4\x12\xec\x6a\xab\x68\x19\x6d\xeb\x92\x8a\x48\xad\x69\xf4\xfa\xe5\x65\xf4\x8a\x2d\x69\x2d\x69\x04\x2b\xf7\xa0\xa8\xd8\xc8\xa8\x10\x34\x2a\x54\xb4\x56\xaa\x49\xcf\xce\x78\x43\x6b\xc9\xb7\x62\x49\x13\x2e\xae\xcf\xdc\x50\x79\xf6\xfa\xe5\x25\x4a\xfe\x10\x3d\x39\x83\xab\x6d\xbd\x54\x8c\xd7\x90\x62\x85\x76\x80\x5f\xfd\x46\x97\x0a\x10\xa2\xee\x1b\xca\x57\x11\xbd\x6b\xb8\x50\x32\x8e\x81\x5e\x7d\xc5\x6a\x5a\x82\x91\xef\xdc\xf0\x72\x5b\xd1\x85\xfd\x49\xdc\x50\xa2\x20\x4a\x81\x07\xdb\x41\xb2\xb3\xe3\xd8\xfe\x26\xc5\xa6\x5c\xd8\x47\xa8\x50\x4a\x93\xb7\xbc\x69\xa8\xd0\x93\x0f\x08\xaa\x35\x93\xb8\xc5\x0c\xed\xc0\x56\xd2\x48\x33\x62\xa9\xc0\xdc\xb7\x47\x14\x52\xb4\x13\x54\x6d\x45\x1d\xd1\x38\x06\x99\x45\x3e\x7a\xe1\x06\xe4\x80\x10\xb2\x3b\x24\x8a\xbf\x57\x82\xd5\xd7\xc9\xb2\xa8\x2a\x48\xd1\xa1\x85\xa0\x2c\xd5\x6c\x05\x67\x23\x42\x68\x52\xf3\x92\x5e\xde\x37\x14\x59\xa8\x59\x3e\xbf\x29\x44\xc4\xc9\x35\x55\xcf\xf9\xa6\xd1\xbb\xf0\x5e\xdd\x57\x14\x52\x5c\x6f\xab\x0a\xcd\xdd\xea\x6a\xc1\x33\x95\xa7\xbc\x83\xcc\x3b\xdc\xc0\x8f\x97\xaf\x5f\x69\x54\x2c\xfc\x37\xc5\x86\x2e\x68\x4a\x93\xa6\x10\xb4\x56\x6f\x78\x49\xf7\x7b\x9a\xac\xb9\x54\xdd\xf4\x5a\x4f\x67\x2b\x38\xf2\xa8\x44\x25\x5f\x6e\x37\xb4\x56\xc9\x15\x2f\xef\xe7\xf2\x96\xa9\xe5\x1a\x76\x10\xd1\x6e\x59\x48\x6a\x97\x4a\xcd\xe3\xf7\x17\x3f\xfc\x02\x52\xcf\x9e\x84\xdf\xd6\x54\xfc\xd0\x03\x62\x86\xfd\xb7\x07\x1c\x8c\x35\xbd\x07\x4d\x3a\x23\x0a\x52\x84\x05\x61\x09\xbf\xa1\x62\x55\xf1\x5b\xdc\x04\x2f\x3f\x63\x19\xbc\xfd\xe2\xf9\x71\x06\x8b\xad\xe2\x7b\xb9\x14\xbc\xaa\xd0\x59\xa2\xa8\x54\x50\x8c\xe5\xb8\x41\x0b\x9a\xd6\x50\x73\x27\xd8\x06\xa1\xa9\xb5\x9c\xa6\x71\x4c\x13\xbe\x5a\x49\xaa\xde\x1a\xfe\x60\x46\x78\x1c\xf3\x96\x50\xbf\x04\x8b\x63\x4b\xe2\x88\x10\xfd\x6c\x28\xd7\xcf\x8b\x89\xde\xcb\x0c\x5c\xfe\x00\x30\xb8\x7c\xf6\xfd\xab\x73\x90\x27\xac\x2e\xe9\xdd\xc5\x0a\x76\x70\x50\x1c\x03\xa9\x0a\xc5\x96\x7a\x6b\x14\xe4\x18\x34\x5c\x32\x23\xb3\x68\x21\x20\x47\x29\x4f\xe9\xe2\x98\x71\x9e\x5b\xe7\x15\xd5\x3f\x69\xf9\x40\x47\x47\x5c\xe3\x89\x53\x81\x00\x38\x2a\x5a\x0a\x54\x1c\xc3\x56\x4e\xd4\x7e\x2f\x20\x4d\x56\x4c\x48\x0f\xee\xf9\x9a\x55\x25\xd2\x32\x14\xb0\x4d\x06\xf2\xaf\xc5\xd1\x88\x58\x27\x55\x0b\x9a\x4a\x18\x36\x04\x53\xcb\x56\xf0\x47\x74\xbf\x1f\x75\x92\xbf\xdf\x8f\x94\xfe\x77\xac\x0a\xd1\x43\x84\x3a\x0d\xa1\xc9\x92\x6f\xf4\x52\x9e\x53\x6f\x1d\x33\xa1\x42\xb1\x5e\x3c\xf9\xe1\xe2\xf9\x87\xd7\xe7\x6f\x2e\x7f\x7d\x7b\xf1\xfe\xe5\xe5\xcb\x8b\x37\xbf\xbe\xb8\x78\xf5\xea\xe2\xe3\xcb\x37\x7f\xd1\x7b\xbc\xa0\xa9\xc2\x35\xe1\x0b\x95\x52\x5c\x90\x76\xb9\xa5\xa0\x85\xa2\xef\x8a\xfa\x9a\x42\x34\x2f\x12\x49\xd5\x7b\x55\x08\x05\x19\x9e\x22\x6c\xde\xcf\xeb\x12\xd6\x78\x8a\x0c\x2a\x15\x29\x34\x2a\x1b\x5e\x3f\xab\x97\x54\x2a\x2e\x9e\xf3\x5a\x15\xac\xa6\x62\xce\x56\x90\x8e\x08\xa9\xe2\x58\xe9\x9f\xfd\x9e\x25\x4b\xdb\x29\x61\x8d\x3c\xa5\x0d\xac\xd0\xa2\x4a\x05\xac\x2c\xc4\x15\xd1\x8c\xf6\x72\xb7\x32\x9a\xba\x28\xa1\x7d\xc0\x0a\xa5\x9a\x99\x12\x2a\x64\x1a\x02\x26\x17\xdd\xce\xcf\x9e\x16\xe2\xda\x10\x24\x93\x8a\xd6\xd7\x6a\x1d\xc7\x37\x9c\x95\xd1\x74\x44\x48\xdb\x95\xcd\xf2\x45\xf8\x92\x02\xc5\x1b\x80\x39\x31\xbf\x5a\x32\x16\xc0\xea\xd4\x25\x6f\x40\xea\x9e\x5f\xd1\x95\x02\x98\x85\xd2\xc5\x56\xd0\x8a\x16\x21\x84\xed\xf7\xad\x64\x31\x8b\x4f\x4d\xbe\x22\xd6\x58\x9c\x8c\xb0\x6b\xb1\xfa\xda\x0d\xd9\xef\x6b\xcf\x12\x91\xf1\xfc\xe0\x8d\x87\x7e\x6e\x39\x50\x59\x31\xb3\x22\xf2\xcd\xef\xe3\xc1\x37\x79\x1c\x87\x6f\x98\x91\x02\x2a\x6c\x58\x80\x70\x6d\x5f\x2a\x4d\xb3\xb6\x4b\x7c\x31\x99\xa5\xb3\x79\x6b\xba\x14\x6f\xc6\x84\x3d\x11\x58\x5b\x31\xa5\xf8\xc6\xbf\xe9\x19\x63\x52\x9b\x67\xe3\x74\xdd\x4b\x87\xec\x2a\x44\x16\xdc\x39\x7e\x1b\xee\xa6\x40\x33\x1c\x33\x62\x5f\x09\xe1\x0b\xf0\x4e\x03\x01\x29\xf8\xde\x2c\x03\x3c\x0a\x4d\x21\x24\x7d\x51\xf1\x42\x41\x9a\x81\x2b\x2e\x4a\x2a\xc0\x98\x8f\xc1\x47\x56\xaa\x35\xc8\xf1\x6c\x8a\xc6\xc3\x83\x58\x6f\x50\x87\xd8\x46\x23\x86\x39\x66\xad\xb6\xff\x04\x55\x06\xac\x95\x04\x63\x9a\x63\x95\x39\x59\x30\x6f\x3c\x03\xcb\x8a\x69\x93\xee\xde\x82\x91\xbc\x37\x92\x51\x88\x16\xbd\x01\x63\x96\x81\x4d\x21\xae\x59\x0d\xc6\x10\xfc\x48\x0d\x91\xda\xb0\x2c\x80\x95\x39\xc3\x00\xf4\xd8\x38\xc7\x90\xd4\x71\x08\xe5\x69\x48\xcc\x1a\x5a\x16\x53\xd2\xf3\x68\x58\x91\x87\x2c\x0c\xe6\x44\xe3\x19\xc7\x27\x5e\x58\x79\xad\xdc\xad\x0d\x02\xe9\xa6\x45\x05\x1b\x96\x21\x7c\xab\x19\xaa\xdb\x2d\x67\x5d\xf3\xa1\xc3\x67\x19\x18\x51\x49\xe1\xee\x80\x29\xde\x19\x01\x49\x9d\xd0\xd0\xc4\x00\xc1\x56\x9e\x52\x2b\x63\x34\xb1\x4b\x1e\x02\xd2\xae\x3b\x37\xb6\x3b\x68\x1d\xd4\x68\x23\x25\xee\x77\xda\x3e\x5e\x53\xf5\x3d\xdf\xd6\x25\xab\xaf\x9f\x9b\xdd\x79\x47\x97\x0a\x5a\x13\xa3\x45\x9c\x86\x22\x4e\xbd\x88\xcf\xb9\x13\x69\xcc\xbd\x08\x63\xde\x89\x36\xe6\xad\x30\x1f\x96\x85\x09\x09\xd0\xee\x40\x2b\x49\xa3\xaf\xad\x29\xc8\x4e\x03\x4c\x2d\x5c\xac\x78\x93\x9a\xb5\x1c\xcb\x1c\xe0\x89\xeb\x76\x0c\xf6\x4b\x4f\xcc\xd0\x03\x6e\xc8\x50\x74\xb3\x86\x28\xdd\x1d\xb0\x24\x8d\x65\x9d\x8e\x6f\xac\x44\x7e\xb4\xaf\xc2\x01\x17\x16\x78\x49\x1a\xc7\xce\x6e\xe4\x8f\xee\x5d\xf8\x15\x85\x41\xae\x22\x3e\x3c\x30\xa0\x26\x12\x6f\xda\x16\x3b\x65\x52\x6a\xd6\x57\xfb\xfd\xc6\x6e\xc6\xb5\x09\x61\xe6\xd5\x84\xac\xe0\x35\x06\x77\x00\xe1\x8d\x7b\xbe\xd7\x26\xc4\xa2\x38\x21\x15\x16\x0e\x89\x09\xd9\x78\x73\xb6\x84\x22\xd8\xe0\x2d\xa4\x98\x5b\xa8\xcc\xc8\x24\x16\x1d\xfd\x5d\x68\x81\x1b\xa2\x45\x01\x4b\x72\x0d\x39\xc2\x25\xd1\xd1\x1c\x2e\x74\x90\x81\xf0\x8a\x04\xca\x5f\x24\x56\xf7\x2f\x79\x63\xc8\xd1\x7a\x8f\x37\x43\x23\xb4\xda\x75\x43\xd6\x64\x09\x77\x7a\xc7\x1a\xcd\x94\x89\x34\x7f\x57\xd8\xec\x67\x63\x78\x3a\x91\xf6\x67\xe3\xb6\xd3\xed\x84\xdf\xc7\xa6\x15\x5f\xcd\xac\x75\x62\x55\xf9\x92\x37\x64\x8a\xfd\x9b\x5e\x92\x4c\xf1\x88\xc5\xb1\xb0\x44\x6f\xfb\x98\xb5\x93\x0c\x4e\x57\x43\x9d\x1a\x86\xee\x9d\xaf\x0d\x8a\x64\x35\xd9\xe2\xb5\xdf\x51\xf7\x66\xf0\x24\x9b\xc9\x15\x5e\x3b\xb1\x70\x2f\x1d\x52\xdb\x3e\x52\x57\x6e\x7b\x20\x5b\xf0\xce\x83\x97\x28\xe5\x84\x90\x32\x08\x0c\xcb\x30\xdc\x83\x6b\x52\xc1\x35\xe6\x08\xe1\x75\xb7\xa7\x57\x61\x78\xf6\xb8\x53\xe4\x64\x6b\x5c\x04\x66\xe4\x27\xa8\x42\x89\xc6\xb7\xac\x2e\xf9\x6d\xc2\xea\x9a\x0a\x27\xe3\x53\xad\xc9\xdd\x38\x2b\x9c\xbd\x81\x5e\xc4\xa7\x5a\x8e\x0a\xa8\x10\x6e\x7a\xde\x4d\x12\xb3\xc7\xc2\x2a\xdb\x98\x07\x0c\xb7\x3b\xed\x94\xb3\xed\x31\xdc\xb6\xfb\xcd\xfc\x4e\xd7\x87\x79\x2b\xcb\x32\x90\xe5\x5b\x4f\x37\x7b\x28\x2c\x3d\x8e\x1d\x16\xa3\x59\x0a\x56\xec\x8e\x96\x36\x62\xa6\x61\xc4\xbc\xdf\xdf\x1e\x47\xf5\xf7\xc6\x6d\x31\xec\x84\xa7\xb1\xd4\x4c\x2d\xee\x53\x6d\x1e\x6c\x14\x6a\xa2\x95\x1b\x46\x6f\x75\xfa\xa8\x41\x0b\xd4\x90\x2b\x28\xd1\x5c\xdb\x31\x33\xb7\x98\x3b\xaf\x65\x73\x02\x33\x68\x01\x0b\xa2\x33\x09\x85\x10\x6e\x11\x2e\x5a\x52\xe2\x18\x16\x5f\xdb\x51\x84\x52\x60\x37\xc4\x42\xfc\xea\x84\xb4\x20\xc2\x45\x99\x5b\x58\x60\x69\x71\xf7\x1c\x0a\x17\x1f\xdd\x42\x89\x2c\xe1\x2b\xb2\x86\x5a\xab\x57\x4e\xe7\xf0\x92\xac\xac\x36\xce\x1b\x6b\xdc\x2b\xa3\x1c\x55\xb0\xbf\x8d\xd3\x11\xb2\x19\x9b\x4e\xdc\x38\xeb\x5f\x59\x75\xa9\xc2\x1d\x6f\xac\xda\x90\xe5\xd8\xf6\x5a\xfb\xdf\x90\xca\x5b\x31\x3f\x99\xe1\xc6\x7b\x93\xc6\xab\x1a\x6b\xd7\x32\xcf\xdd\xf6\x9d\x87\x8a\x61\x8d\x87\x76\x29\x96\x86\x36\xf1\x7d\x12\xe4\xbc\x37\x3e\x4e\xc1\xb5\x9d\x29\xc8\xb7\xbf\x2f\xe6\xfb\x36\x8c\x7b\xbf\xcd\xd3\xa9\xe6\xeb\x64\x66\xbc\x8a\x4f\xdd\x80\x4e\x29\x41\x1b\xa5\xd3\xb9\x15\xaa\x7b\xa8\x17\x14\xb8\x6e\xf5\x65\x37\x68\xf1\x94\xe1\x71\x63\xdd\x96\xf5\xef\xed\x40\xcb\x0a\x65\x7f\x4f\x4c\xa4\x77\xfc\xc3\x70\x5b\xee\x29\xf7\x70\xb0\x02\xee\x46\x2b\xbb\x5f\x4d\xcf\x8b\xb6\xa0\x0f\xb8\x24\x17\xa6\x68\x91\x7c\xa1\xf7\x12\x4a\x94\x6c\x8a\x26\xa8\xc9\xf4\x42\x93\x2f\xf4\x3e\xa5\x07\x2c\x33\x9a\xe3\x5d\x21\x68\x91\x9e\x43\xfd\x82\x0e\xe8\x80\x12\xc9\x85\x3a\xaa\xe6\xf8\x4d\x4a\xf4\xe0\x09\x35\x3f\x07\xed\x89\xca\x64\xc5\x2a\x45\x45\x6f\xa5\xfe\x5e\xb3\xd3\xbd\xfe\x8e\xf0\xd0\xe8\xc5\x31\xeb\x5a\x7e\x74\xee\x04\x57\x64\xfa\xb4\x70\x7b\xbd\x28\xb2\x69\xae\x29\x4b\x4b\xf7\x80\x57\x84\x26\xb2\xa9\x98\x82\x60\x02\x50\x36\xcb\x3d\xf4\x6a\x0c\x57\x0b\x30\x01\xe3\x55\x0a\x40\x60\x45\x2e\xac\x50\x79\x5b\x55\x42\xfd\xe2\x27\x6d\xf5\xe6\x07\x83\x5f\x75\x74\x9c\x96\x6c\x10\xe6\xa1\x8b\x52\x9d\xba\xf5\x02\x72\xdf\x6e\xc3\x58\x6d\xec\x07\x3a\xb5\xde\x0d\xce\x32\x31\xaf\xb6\xfc\x6e\xff\x7b\xd1\xca\xb8\xb5\xca\xfd\x90\x65\xcc\x5b\x23\x5d\x77\xc4\xdc\x75\xc4\xd8\x48\x0d\x08\x1b\xda\x5a\xe9\xb5\x5e\xc2\x0b\xa7\xcd\x14\xb5\xf8\x03\xdb\x02\x0e\x5d\x52\x24\x68\x53\x15\x4b\x0a\xcf\xf4\x94\xbd\x99\xbe\xb7\xa3\xf6\x8a\x37\x67\xd7\x78\x40\xe0\x54\x46\xf3\x30\xb8\x7d\xef\xf7\x81\x13\x1e\xee\xe0\x34\x77\x11\xac\xe6\x7d\x47\x37\xeb\x6b\x09\x6b\x95\x49\x10\x57\x9f\x71\xc4\x58\x32\x82\x0a\x8d\xf6\x82\x62\x61\xe8\xf1\x34\x4a\xdd\x50\xd9\x44\xcc\xd0\x59\xea\x06\x0b\x11\x68\x13\x6e\x42\xfb\x42\x37\xda\xe7\xd4\x77\xb6\x6c\xcd\x9a\x9c\xa8\xac\xc9\xc7\x2a\x2b\xf3\xb3\x6f\x26\xcc\xfc\xe0\x3a\x93\x39\xd1\x51\x83\x5c\xa8\x4c\xe6\x13\x96\x15\x79\xaa\xb2\x3b\x28\x51\x8e\x83\xbd\xb8\xec\x29\xd4\x33\x21\x8a\xfb\xa4\x11\x5c\x71\x75\xdf\xd0\x64\xc5\xea\x72\x61\x7f\x6c\x31\xd3\x69\x97\xd2\xec\xe9\x80\xfc\xe0\x59\xc8\x56\x70\x08\xc4\x4b\xcd\x82\xd6\xbe\x75\x4d\x43\xf6\x80\x66\x2a\xd7\x41\xe7\xc1\x27\x10\x1a\xc3\xc7\xc7\xb5\x80\x3d\xab\x43\xcd\x79\x0e\x5d\x86\x69\xeb\x03\xd6\x46\x1b\xaf\xaf\x4d\xa7\xac\xd8\x92\xc2\x29\xfe\x41\x47\x27\x75\xb1\xa1\x00\x33\xd4\x42\xac\x93\x15\x17\xe7\xc5\x72\xdd\x21\xaa\xd0\x4e\x65\x5d\x11\x38\x8f\xe3\x25\xaf\x25\xaf\x68\x72\x5b\x88\x1a\x82\xcf\x1b\x5e\xb2\x15\xa3\x22\xf1\x63\x3e\x47\x4c\x46\x25\x6d\x04\x5d\x16\x8a\x96\x38\xda\x4a\x1a\x05\xc3\xea\xcf\x23\xe0\x69\xed\x81\xde\xef\x55\xb2\xaa\xe7\x2a\xa1\x75\x71\x55\xd1\x32\x8e\x29\x64\x3a\xdc\xe3\x4e\xc7\x64\xd2\xd8\xda\xf2\xf2\xa4\x09\xe1\xae\x45\xd0\x15\x15\xb4\x5e\xd2\xde\xb8\xb6\x55\x5b\x0f\x06\x39\x56\x08\x1d\x10\x0e\xbc\xde\x1b\x68\xeb\x68\x6a\xcd\x64\x22\x55\xa1\x68\xc2\xe4\x0f\x54\x2a\xc1\xef\x69\xe9\x93\xdd\x1d\xab\xa5\x2a\xea\x25\x4d\x4d\x6d\x5b\x6a\x93\x24\x75\x92\x54\x08\xc1\x6f\xdf\x77\xaf\xca\x95\xfb\xcd\xdb\xaa\x62\x4d\x43\xcb\x74\x34\xc3\x0e\xa1\x74\x77\x38\xcc\xe9\x00\xd2\x17\xb0\x43\x00\x9b\x47\x4b\xa2\x7d\x0e\xc8\xa0\x89\x31\x06\xda\xd7\x92\x1b\x3b\x89\x37\x9a\x12\xd9\x75\xe0\x81\x15\x1e\x01\x8a\x7b\x50\xfc\x9e\xc9\x44\xa3\x9f\x5c\xe9\x04\xb4\x10\x8c\x4a\x1f\x47\x3f\x36\xba\x29\x4a\x9d\xad\x6a\x34\xb9\x60\xd7\xac\x2e\xaa\xb7\x2d\xba\x74\x10\x43\xb7\xbb\xef\x61\x88\xe0\x10\x01\xc1\x74\x74\x32\x3f\xf1\xb1\x2c\x01\xc5\x95\xe4\xd5\x56\x51\x80\x29\x79\x6e\xa1\xb6\x58\x62\x8a\x70\x6f\xa7\x9f\x9b\xfa\x64\xb9\xe8\x11\xc5\xeb\x0f\x4d\x59\x28\xed\x74\x52\x38\x34\x9c\x8c\xa6\xf8\x68\x86\xed\x31\x21\x74\x27\x5c\x5f\x7a\x76\x87\x26\x92\x6f\xe8\x89\xd3\xd6\x61\x99\x56\x4a\xe3\xb3\x9d\x16\x04\x65\x72\x6d\xde\x7a\x75\x8a\x8f\x7a\xe2\x8a\x0b\x68\x9d\x4b\x36\x9a\x61\xb0\x91\x00\x83\x8f\xf4\xea\x0b\xd3\x36\xf9\x35\xff\x17\xc0\xe0\x02\xe4\x26\xe4\x5b\xae\x0b\xf1\x4c\xc1\x29\x4a\x14\xff\xa0\x79\xf5\xbc\x90\x14\xa2\x31\x75\x76\x61\xa6\xed\xfe\x74\x5e\x3f\x55\xce\xef\x4f\x66\xf3\x7a\x3c\xf6\x2e\x5b\x65\x75\x8e\x05\x61\x0b\x00\xc6\x6c\xcc\x53\x5b\x9e\x1c\x38\x4e\xea\x15\x84\x12\xa3\x22\x99\xc8\xbd\x41\x14\x87\xa0\xd4\xdd\x11\xf3\x16\x76\x2e\x6b\x50\x03\x35\xab\xbf\x1c\xef\x22\x28\x9a\xa6\xba\x37\x6a\x07\xb4\xad\x08\x44\x27\x11\x74\xc3\x6f\xe8\x33\xaf\x88\x10\xdc\x4d\x5a\xb9\x01\x28\x54\x03\x8b\xa3\x09\xed\x08\x00\x03\x3d\x9d\x4c\x0d\xf5\x2a\xde\x0c\x76\x64\x1f\x21\x50\xa2\xa8\xe5\x8a\x8b\x0d\x40\x39\x01\x7e\xd9\x92\x49\xbd\xbb\xe7\x37\xb4\x56\xaf\x98\x54\xb4\xa6\x42\x42\xd4\x17\x25\x8b\xff\x45\xed\x38\x10\xc7\xe1\x02\xdd\x69\x80\x1b\x67\x4e\x16\x42\xfa\x2d\xb4\x8e\xc1\xdf\x3f\x98\x20\x77\xa7\x5f\x2a\x29\xe9\xaa\xd8\x56\xea\xef\x8c\xde\xa6\x36\xa5\xea\x20\xfc\xd8\xd5\x2f\x6d\x56\xd0\xa6\x6b\x34\xac\x99\x88\xd3\xc3\x96\x00\x28\x9d\x37\x49\x51\x96\x3d\xd2\x8d\xcf\xda\x35\x85\x94\xec\x86\xa6\xa3\xe9\x01\x61\xb1\xdf\xff\x08\x6b\xd8\x84\xc7\x1e\x6e\x71\xcc\x92\x66\x2b\xd7\xb0\x09\x54\xe1\x59\x87\x1a\x4f\xb6\x46\x67\x4d\xc1\x8c\x30\xac\xe9\x3e\x5d\x11\x08\x2a\xd9\xbf\x28\xc0\xbd\xe1\x7d\x24\x5c\x79\xad\x0e\x4e\x0d\x7e\x84\x02\xfb\xc2\xeb\xd1\x54\x9e\x84\xa9\xad\x44\x6d\x83\x33\x97\x44\x60\x9e\x50\x8d\x84\x3c\xb7\xba\xad\x25\x3a\x70\x40\x2f\x21\xda\x05\xa2\xdf\x1b\xba\xdf\x07\xe6\x87\x3c\x83\x8f\xd8\x6d\x7c\xec\x3f\xe4\x72\x4d\xcb\x6d\x45\xad\x29\x0b\x33\xfb\xd7\x3d\xab\x64\x18\x65\x85\xe9\x01\x5e\xa9\x90\x60\x84\x55\x9f\xe2\xd3\xe8\x81\xa2\x1d\x1d\x86\xe8\x59\xd8\x87\x78\x40\xfd\x06\xa2\x4d\xc4\xf1\x32\x24\xcb\xdb\x26\xcf\x5a\x37\xee\x88\xbb\x33\x1c\x1c\xdf\xbd\x7b\x84\xbb\x71\x0c\x97\xda\xa7\x57\xcf\x6a\xb6\x29\xf4\xf0\x17\xa2\xd8\x50\x38\xc4\xbe\x80\xbd\xe4\xf5\xe0\x3e\x98\xbe\x90\xcd\x1f\x82\x33\x64\x30\x22\x84\xc6\xf1\x88\xc9\x37\xc5\x1b\x18\x9e\x1f\x20\x14\xc7\x4c\xbe\x60\x35\x33\xde\xa3\x9b\xfe\x8b\xdd\xa5\x30\xbf\x54\xe8\x94\xd9\x6d\x6a\x05\xc0\xdc\x85\xe6\x2e\xa0\xf6\x41\xb4\x2d\x4c\xe3\x36\x62\x77\x09\xc6\x40\xe8\x1e\xc7\x1f\xa0\xca\x78\xae\x4d\x2a\x23\xa0\xb9\x03\xda\xd1\x5a\xa3\xc6\x75\x00\xce\xf3\x31\x0b\x5d\xd1\x6f\xff\x26\x8e\x1a\xc2\x7c\x34\x33\x81\x29\x3d\xb1\xd4\x5c\xc7\xde\x92\xaa\xa0\x05\x1b\x74\xc2\x25\x5f\xf4\x13\xca\xe3\xb8\x39\x74\xa8\x5e\x7b\x9d\x07\xc5\x35\x19\x8d\x58\x1c\x0f\xb8\xe1\xd6\x41\xeb\x69\x3a\xde\xd6\xa3\xba\x80\x34\x31\x35\xdc\xa7\xcc\xfe\xda\xa2\xeb\xa8\x2d\x92\x80\xcf\x60\xac\xc6\xe0\x33\x98\x1f\x05\xc9\xe6\xdc\xe8\x33\x18\x83\xc8\x7b\x2e\x1d\x24\x0b\xfa\xcf\x2d\x13\xb4\x8c\xae\xee\x23\x30\x16\xbd\xde\x3a\x32\x2b\x44\x8a\x47\xb7\x5c\x7c\xc1\xd1\x15\x8d\xe4\x56\x50\xdd\xc0\xea\x65\xb5\x2d\x69\xc4\x54\x74\x45\x57\x5c\x50\x3b\x7b\x04\xd0\xe1\x34\xf9\xfc\x6b\x20\x7b\xb4\x2e\xdd\xd1\x8e\x54\x85\xd0\x19\x97\xfd\xb5\x6d\xba\x37\x0d\x8e\xd1\xfe\xf9\x1f\x9c\x7a\x86\x27\x7e\x33\x1d\x74\x14\x5d\x96\x42\x75\x0a\x5e\xf8\x58\x83\x8f\x67\x28\x59\xf2\x7a\x59\x28\xd8\x36\x4e\x31\x47\xc1\x5d\x0c\x96\x08\x7a\x43\x85\x8e\x51\x52\xd6\x21\xf6\xf7\xbe\x1b\xaa\x09\x4d\x36\xe6\xc8\xe4\x0c\xc2\x45\xfa\x69\xb2\xff\x34\x46\x8b\x4f\xe5\x93\x4f\x89\xfe\x8b\x60\xf2\x04\x9d\x21\x2c\xc8\xb8\xd6\x38\x35\xa4\xce\xbe\xc9\xcd\xc6\x89\xae\x06\xc5\x56\x50\x67\x49\x4d\x57\xa5\xfa\x13\x70\x65\x3f\xe9\x2f\x69\x34\xee\x6e\xc6\x9f\x1a\x90\x4a\xc2\xe7\x57\x82\x16\x5f\xec\xe5\x8b\x3f\xb9\xbb\x1a\x7f\x12\x20\x75\xce\x2e\x95\x84\xd9\xbb\x17\x25\x59\x42\xd9\x92\x55\x66\x2a\x3f\x9b\x4d\xa7\x4f\xc4\xc1\xd4\x4b\xd7\x9a\xfd\xcd\x7e\x0f\x6e\x4c\xf1\xb2\x41\xae\x50\xea\x86\x17\xc4\x0f\x59\xfc\x04\x1f\x3a\x59\xfb\x3d\xa5\xe9\xf4\xab\xd3\x1f\xab\x80\x17\x0e\xe5\x36\x86\x6b\x77\xe3\x5f\xc7\xbb\x91\x4d\xf1\x34\xff\x6a\x79\x80\x21\xdc\xb4\x25\xa4\x33\xf8\x69\xbc\xff\x34\x41\x67\x0f\x96\xcd\x68\xa2\x04\xdb\x40\xed\x21\x64\xb0\x4b\x97\xb0\x19\x48\x96\x27\xf6\x12\x90\xa4\x85\xd0\x52\x81\xf7\x9f\xe4\x19\x3a\x20\x34\x6f\x32\x99\xc7\xb1\xa9\x47\xea\xc7\x6e\xb3\xb1\x0e\x1e\xfb\x4a\x7b\x61\xb3\x8a\x48\xd2\xa6\x10\x3a\xd4\xd7\x6a\x7a\xbb\x66\x8a\x46\xb2\x29\x96\x14\x4a\x64\xee\x68\x1d\xa7\xba\x45\xb4\xe4\x9b\x4d\x11\x41\x8c\x22\x9d\x2b\xd2\xa2\x4c\x5c\xc2\x5b\x92\xb3\x4f\xf2\x09\xfe\x24\x9f\xec\x3f\xc9\xf1\x19\x2e\x88\x41\x45\x2e\xb2\x26\x4f\xb3\xa6\x55\x02\xd9\x6a\x46\x66\xd0\xb4\x4c\x2a\x51\x36\xcd\x73\x84\x8f\xda\x66\x79\xee\x47\x7b\x08\x72\x3c\x43\x28\xef\x24\xa8\x38\xe2\x6a\xb7\x57\xd0\x5a\xe0\x91\x48\x05\x3a\x2d\xc4\x34\x64\x34\x0b\x8b\x4f\xe5\x76\x49\x07\x2b\x93\xc0\x98\x90\x8c\xb6\x69\x83\xe1\xb2\xd9\xfe\x31\xc0\x60\x12\xec\xbb\x42\x0b\xd8\x1b\x49\x94\x5e\x67\x8a\x29\x4a\x9b\xa3\xae\xb1\xed\x9b\xe9\x3e\xea\x89\x54\xe8\x80\xb3\xfc\x41\x41\xd1\xc6\xa1\xb6\x67\xc3\x5a\x58\x8a\x81\xa0\x44\xe3\x4d\x07\x7c\x93\x66\xcb\x07\xe3\xfc\x60\x9d\xa9\x7c\x4c\xf8\x13\x08\x26\x96\x34\x36\x99\xe5\xe6\x86\x02\xb2\x70\x03\x0b\xfb\x97\xe0\xba\x01\x66\x44\xb9\x7c\x14\xd7\xbd\x34\x57\xb4\xa7\x9b\x52\x87\xc8\x3e\xbd\x95\x44\x04\xe1\x43\x49\xea\xa3\x92\x5c\xeb\xb8\x3e\xc0\x31\x43\x8b\x6c\xcc\xf0\x34\x4f\xff\x05\x19\x6e\xb0\xc4\x25\x72\x7a\x45\x08\x29\x17\xd0\x1d\x0a\xf0\x6c\x9a\xbb\x73\x86\x09\xe1\xd9\x2c\x47\xbe\xe2\xf8\xd0\xb0\xb1\x1f\xe6\xae\xa7\x98\x41\xbe\xc3\x8c\x32\x87\x7e\x6e\x90\x0b\x1b\xec\x11\xdd\xc0\x40\x07\x4d\xa7\xe9\x36\xa3\x6f\x30\x3d\xf8\x34\xf5\x57\xf2\xba\x50\xeb\x64\xc3\x6a\xfc\xb3\x7d\x5c\x55\x9c\x0b\xfc\x93\x6b\x2f\xee\xf0\xdf\xc8\x50\x52\x69\xed\xd2\xf0\xfd\x45\x6f\xcf\xf0\x3f\x48\x06\xce\xcb\x6b\x0a\x30\xb8\x14\xac\xd4\x89\x1e\x06\x2f\x98\xa0\x2b\x7e\x07\x72\xfc\x47\x32\xc5\x94\x92\xe9\x9c\xd2\xa7\xff\x70\x72\x36\xa7\x74\x4c\x66\x88\xad\xe0\xdf\xe2\x78\xfa\x94\xd4\xc5\x0d\xbb\x2e\x14\x17\xc9\x56\x52\xf1\xec\x5a\xdb\x47\x2f\xbc\xff\xc8\x28\xcd\x11\xda\xfd\x91\xcc\xac\xf5\xb7\x77\xeb\xb0\xa2\xe4\x6f\x71\xec\x2c\xe7\x5b\xc1\x37\x4c\x52\xcc\x29\x51\x74\x71\x5a\x98\xef\x74\x2a\xb8\x18\xa9\x74\x80\xaf\xd5\xa0\x0f\x24\x11\x54\xf2\xea\x86\x42\x94\xa8\x35\xad\x61\x38\xc3\x28\x86\xb6\x88\xe8\x70\x48\xff\xdd\x65\x24\x55\x97\x6c\x43\xf9\x56\x0d\xc2\xc4\x7f\xd4\x50\x31\xa3\x24\xe8\x75\xe0\x7c\x49\x91\x99\xd8\xd0\xa8\x79\xc7\xb3\xa2\x69\xfe\x4e\x85\x64\xbc\xee\x8c\xeb\xeb\xf7\x2f\xcf\xa3\xd9\x14\x20\x84\xd9\x01\xd7\x01\xcc\xf6\xee\x1a\xa4\x91\xaf\xab\xf1\x55\xa4\x10\x52\x6b\xc1\x6f\xa3\x9a\xde\x46\x97\xf7\x0d\x3d\x17\x82\x0b\x08\x9e\x17\x75\xcd\x55\xb4\x2c\xaa\x4a\x9b\xd9\xaa\x90\x32\x2a\x64\x54\xb4\x14\x02\x74\xc0\xa2\x87\x73\x78\xc7\x54\x2f\xe6\xc5\x90\x1f\x55\x3a\x4c\x9d\x83\xdb\x12\x07\x4f\x68\xbd\xdd\x50\xa1\x83\x3e\x12\xbe\xec\xf7\xa3\x19\x36\x07\xd5\x2b\x76\xbd\xb5\xfd\xa3\x29\x06\x37\x45\xb5\xa5\x40\xc7\x6c\xa6\x5a\x79\x2b\x98\x72\x7d\x08\xbb\x88\xd8\x8a\xec\x5b\xc1\x1b\x2a\xd4\x3d\xa4\x98\x9b\x53\x14\xde\x86\x6c\x5d\xc5\xb5\x77\x41\x48\xc7\x9f\x50\x75\xf5\x65\xcc\x11\x66\xa6\x4d\x27\xc2\xea\x70\x80\x08\x37\x7d\x8e\xea\x90\xd8\x87\x50\x3a\x90\xa4\x8b\x87\x70\x50\x78\x67\x50\x4f\x39\xee\x88\x4c\x47\x53\x1c\x52\xa8\xdf\x3d\x45\x26\x2b\x4e\x4d\x29\x9a\x63\x7a\xc0\x92\xfa\x53\x2f\x9d\x35\x5f\xd7\xfb\x7d\x28\x87\x6d\x65\x0a\x73\x32\x9b\xf3\x93\x18\x72\xce\xc7\x63\xe4\x07\x31\x8d\xaa\x0a\x82\x49\x9e\x63\x85\x1c\xf4\xae\xbc\xbe\x2e\xe4\xc5\x6d\xed\x69\xb0\x17\x81\x35\x2b\xe2\x18\xd2\x8c\xe9\xcc\x84\xe5\x5d\x85\xfc\x80\x4b\x4a\x32\x73\xe0\x38\xb1\xa1\x2e\xb6\xa7\x8f\xf6\x67\xa2\x43\x5e\x93\x14\xb5\xbd\x36\x41\xd2\x2d\xb6\xcf\x9e\x28\xfa\x5e\x1f\xcb\xd8\x56\x3b\xc2\x9d\x1a\x86\x2f\x5d\xab\x9f\x68\x6c\xb1\x1d\x62\x4f\x42\x6c\x8b\xed\xce\x71\x41\x49\xe9\x63\xe0\x3f\x23\x5c\x51\xb2\x7b\xf1\xea\xe5\xdb\x14\xac\x2a\xd6\x00\xfc\xfc\xd5\xc5\xf3\xbf\x7e\x7c\xf9\xfe\x3c\x05\xcb\x8a\x2f\xbf\xdc\x32\x49\x01\x7e\x7e\xf1\xe1\xcd\xe5\xf9\xbb\xb0\x93\x6f\x6b\x45\x45\x37\xe6\x80\x57\xc3\xda\xa0\x60\x10\xb0\x99\x42\xb6\xf8\xfd\xd7\xfa\x16\xe1\x4b\xba\x3b\xcc\x6b\x9b\x29\x63\x85\x86\x0a\x0e\x03\x26\x44\x67\x3e\x54\xaa\xa3\x6c\xbb\x76\xa9\x3f\x3a\x58\x30\xf6\x8d\x70\x97\x87\xdb\xd7\xe4\xca\x1c\xce\xac\x99\x44\xfd\x72\x19\xb1\x97\xbe\x54\xf2\x83\x8d\xbf\x25\x16\xbd\x5c\x7d\x17\x94\x12\xd3\xd1\x0c\xb7\x25\x5c\xfd\xd2\x2b\x30\xa4\x59\x7e\x38\x2a\x8c\xdb\xab\xcb\xbf\xfd\x73\x4b\xc5\xfd\x42\x7b\xba\x94\x87\xe5\x3e\x6d\x0b\x99\xef\x66\xba\x9b\x3d\x50\x1c\x27\xbb\x03\xee\x1d\x14\x1f\x21\x1d\x94\x36\x45\xf7\x8c\x06\x52\x69\x8a\x76\xf5\x29\xfc\x8c\xe6\x27\x8c\xe8\xf5\xee\xf7\xbb\x43\x08\x7a\x21\x7a\xdd\xe9\xce\x84\x37\xfd\x2a\x6b\xef\x68\x7b\x98\xae\x47\xcf\xbb\x75\x2e\x9d\xd2\x03\x1e\xc6\xf7\xf1\x33\x6f\x97\x72\x4f\x94\x4f\xb9\x8f\x70\x1b\x3e\xb2\x0a\xcf\x90\x54\xc2\xeb\x57\xbc\x28\x51\x1c\xfb\x47\x58\x07\x41\x57\xed\x63\xb1\xba\xab\xa0\xe1\xda\x55\x71\xfc\x7a\x56\xf8\xdc\x8d\xbb\x86\xf4\x98\xd0\x2b\x25\xcd\x1b\x57\xa7\xb5\x18\x0c\x57\x78\x07\x4a\x50\xa4\x69\x73\x2b\x6d\xdc\x33\x73\x49\x00\xd8\x65\x01\xb6\x66\xfa\x54\x91\xde\x38\x0b\xa8\xd5\xe1\x70\xc0\x76\x52\x69\xc5\xfc\xe1\x59\x6f\x87\x66\x0d\xe1\xfb\x30\x88\x97\x83\x0b\x0f\x55\xb5\x1f\x86\xf1\xae\x07\x23\xd7\xee\x0c\x76\xd7\xb3\x69\xf2\x41\xb1\x4a\x92\xf0\x84\x81\xf4\x83\xc1\xc5\x75\xc5\xaf\x8a\xca\xd5\xa9\x91\xfb\xf4\xc4\x4c\xc3\xab\x20\xf8\x96\xa4\xa4\xba\xc1\x2b\x04\xd9\xb5\x5d\x6d\x34\x8b\x7b\xbb\xa1\x9d\xde\x51\xf9\xdd\x9c\xdd\xb9\xc3\x9d\x90\x98\x03\xf6\x87\x44\xfd\xd6\x56\x42\xd3\x9d\x5c\xb3\x95\x4a\x77\x46\x80\xd3\xd9\x74\x8a\x69\xb7\xca\xaa\x1e\x88\xdd\xc2\xc4\x81\x13\xd5\xcf\x09\x4c\x8e\xd1\xbf\x7a\xc1\x74\x3e\xdd\xdd\x08\x77\x69\x86\x20\xa1\x98\x37\xa4\xee\x92\x0e\x97\x9c\xb5\xee\x4a\xbb\xbd\xde\xd1\x7d\x49\x64\xff\xa4\xbe\xd0\x0d\x47\x87\xf2\xb8\x22\x3b\xe3\xc2\xd2\xc6\x98\x9c\x12\x8b\xac\xd4\x81\x7f\x5d\xf6\x5a\xc6\x22\x2b\xf2\x49\x93\x15\x39\x0a\xcf\x3c\x9d\xed\xb4\xe6\xaa\xc1\x95\x76\xdd\xed\xf5\xf3\xc3\xc1\x9d\x94\x7a\xbe\x7d\x73\xc2\xb7\xbf\xf8\x11\xd3\x03\x6e\x84\xd9\xbf\x0b\xf7\x01\x8b\x9f\xf4\xe7\x47\x98\xdd\xdd\x11\x57\xa7\x67\x9b\xf6\xcb\x0d\x1f\x93\xfa\x13\x95\x79\xd0\xd4\xf9\x06\x53\x25\x84\x9c\x08\xc8\x91\x3f\xd9\xbe\x3f\x9d\x8d\x87\x26\x63\xe5\x4f\x4a\x31\x47\xf3\x10\x11\xc2\xe6\xce\x3d\x27\x8d\x60\x5c\x30\x75\x6f\x2a\x26\x7d\xee\x61\x2d\xcc\x82\x6d\x0a\x71\x7f\x22\x47\x9c\x34\x19\x6d\x53\x48\xfd\xfc\x94\x65\x34\x8f\xe3\x91\x4a\xa8\x5c\x16\x0d\xfd\xc8\xd4\xfa\x9d\x47\xc5\xd0\xf0\x13\xd4\xe3\xb0\x1e\x87\x74\x64\x69\xef\x51\x73\xa4\x63\xbd\x25\xd7\xa8\x0d\xad\xd3\xa5\x97\xb4\x2f\x35\x35\x69\x32\xde\x43\xe1\xbb\xaf\xa0\x50\x93\x5f\xa1\x9e\x63\x50\x98\xc0\x10\xb2\xbb\xb0\xd5\xde\xba\x42\x2d\x86\x1c\xd7\xe8\x70\x78\xe4\x1a\x43\xab\x59\xa6\xe0\x92\xf9\x20\xac\x2f\xf6\x14\x2d\x40\x4b\x25\x48\x81\xe3\x2b\x98\x37\xad\x8c\xca\x4c\xe5\xe6\x64\xf7\xf4\xdc\xd9\x64\xb9\xd8\x6f\x55\xda\xae\x21\x7a\xa5\x77\xa7\x71\x39\x76\xbb\x9e\x7e\x8b\x4f\x64\x2f\xed\xdf\x91\x3c\xe0\x2f\x94\x36\x97\xfc\x9a\xaa\x35\x15\x5e\xb2\xff\xcf\xef\x32\x23\xde\x14\x68\x19\x77\x02\xa3\xad\x47\xe0\xfc\x42\x5b\x73\x64\x67\x04\xf9\x19\x37\xde\x54\xf4\xd1\x6f\x79\x66\x6e\xeb\x35\x0b\x47\x65\x67\x4d\x4b\xdd\xd8\xb7\x1f\xcd\x83\x97\x7a\x78\x26\xf3\xa7\x02\x32\x6d\x3c\x74\x20\x7f\xc4\xd9\xac\xcc\x89\xeb\x9d\x70\x6d\x44\x30\xcf\xca\xfc\x3b\xdd\x24\x1f\x9d\x20\xb5\x0c\x6b\x4b\x62\xee\x66\x78\xce\x7d\xfb\x98\x4d\xf0\xc7\x09\xa6\x3e\xfc\x22\x54\xe2\xf0\xcc\x59\x83\x03\x18\x84\xfb\x72\x7c\xa1\xb1\xd6\x99\xa3\xfb\xb2\x8a\xad\x20\x90\xe6\xcb\xc5\xce\x83\xd5\x26\xf1\xad\xc9\x89\x99\x48\x4c\x14\xf9\x9e\x56\x74\xa9\xb8\xd0\x0c\x1e\xd5\x1d\x68\x7b\x25\xd4\x7c\xee\x75\x32\x71\xe0\x13\xa8\x7e\x49\xf3\xe3\xb3\x77\x6f\x5e\xbe\xf9\x4b\x1a\x7d\x36\x14\x78\xfc\x3e\x47\x9b\xad\x54\xd1\x15\x8d\x96\x6b\x56\x95\x11\x5f\x45\x4c\xc9\xc8\x42\x8d\xdc\xa0\x11\x40\x98\xba\x03\xd1\x87\x45\x26\x30\x50\xa6\x4e\xeb\x64\xae\x24\x4d\x20\x73\x85\x97\xa9\x9e\x86\x74\x32\x25\x10\xae\x48\x71\x5a\x8e\x5c\xe9\xc6\xe0\xe3\x15\x73\x15\x57\xf1\x57\xfc\xd6\xdf\x64\xc0\x6b\x3d\x24\x14\xbb\x6b\xdd\x70\xe5\x3f\x64\x71\xba\xb8\x25\xaf\x60\x8d\xb2\x2a\x9f\x97\xd9\x75\x3e\xd9\x3e\x95\xd9\x26\x1f\x92\xa3\x4d\x3e\x21\xba\x6f\x02\xed\x40\x84\x70\x99\x6d\xf2\xf1\xf6\x3b\x99\x5d\x3f\x30\x63\x4c\xec\x90\x89\x1e\x32\x60\x26\x96\x27\x93\xac\xcf\xb8\xb2\xf3\xca\xac\xca\xcf\xbe\x99\x6c\xcf\xbe\xc1\xb7\x44\x0d\xf8\x20\x7c\x1f\xde\x63\xbc\xed\xbe\xde\x59\x99\xaf\x8d\xf0\xf9\x51\xb7\xff\x28\x69\xd5\xfb\x28\x09\xdf\x90\xab\xc9\x10\xbd\xf7\x93\x73\xaf\x96\x37\xe4\x27\xf8\x2b\x94\x59\x95\x4f\xb6\xf8\x06\xe1\xa9\xa6\xc6\x48\x4e\x7b\xec\x1a\x90\x67\x3a\x08\x64\x3a\xc3\x69\x28\x64\x78\x83\x4d\x45\x4f\x68\xf3\x06\x6f\xac\xad\x66\x78\x8d\x01\x40\x98\x69\xbd\xc4\xd4\xdb\xbb\xec\x6e\x62\xa6\xe7\xc0\x5e\x95\xf2\xaa\xfa\x7f\xbf\xe2\xbe\xd9\x0a\x7e\x79\x40\x47\xcd\xf9\x45\xa8\x94\x6c\x05\x69\xe2\xee\x61\xc5\x71\x78\x79\x8a\x90\x81\x3b\x4a\x7d\x6d\xe6\xff\x89\x43\x1f\x08\x2b\x90\xb9\xda\xf3\x90\xf6\xd4\xe4\x0e\x32\x84\x1f\x54\xb0\x59\xbe\xdf\x03\x80\x1b\x92\xe5\xfe\x4c\x4a\x25\x57\x74\x5d\xdc\x30\x2e\xec\xe1\x54\x54\xd1\xc4\x94\x0e\x1a\x92\x31\x5c\xe7\xc1\x21\x95\xee\xea\x8a\x05\x0d\xf9\x27\x64\xe8\xb8\xfb\xb8\xa4\x60\x46\xe1\xd1\xd4\x0f\xf4\x67\x5b\x0d\xe9\x16\x9e\x77\xb7\xd3\x4f\xfc\xae\xc4\xa5\xd9\x25\x36\x22\x44\xee\xf7\x8d\x2b\x2c\x10\x42\xca\xf1\x2c\xd8\x9b\xaf\x32\xc5\xec\x42\x71\x1a\xfe\x54\x64\xe8\x82\xd8\x8a\xfc\x8c\x37\xa4\x2d\x8d\xb3\x38\x5e\xc1\xc2\xde\x0a\x47\xdf\xad\xa0\xbd\x5d\x8f\xf6\xfb\x2e\xba\x70\x43\x4c\xfb\x53\x3d\xc2\x0e\xde\xef\x7d\x49\xdc\x0d\xb0\xa6\xc4\x02\x51\xbc\xd1\x03\xba\x72\xb8\x1b\xa3\xdb\x0d\x0c\x37\x18\xaf\x49\x08\xdb\x7e\xeb\x81\xf0\x92\xf4\x90\x72\xdf\x69\x21\x7c\x4d\x02\x20\xe6\x8b\x11\x84\xb7\xa4\xbf\x38\x6f\x61\x5f\xf5\xc8\x5c\x1f\xd1\xb4\xec\x11\x70\x7d\x8c\xed\x16\xdf\x7e\xc5\xbf\x33\x6d\x6f\x46\x23\x65\x34\xe7\xef\x85\x60\xa6\x5e\x23\xe3\x18\xde\xda\xef\xae\xdd\x97\x1e\x66\x69\xdd\xe4\xce\x98\x85\x59\x7b\x74\x3c\xe8\xda\xb5\x75\xa3\xb6\x68\x0e\x37\xfb\xfd\xd5\x7e\x7f\x6f\x5d\xb9\x53\x51\x32\x9a\x62\xd3\x61\xaf\x20\x34\x59\x39\x9e\xe5\x08\xdf\xc7\x31\x14\xe4\xaf\x50\xa0\xfe\x05\x48\x36\x86\xc2\xdc\x3a\x17\x29\x00\x03\x56\xd7\x7d\x11\x78\x2c\x3e\xef\x07\xb5\xfa\xf1\x1b\x87\xc8\xdc\x26\x1c\xb4\x3a\x14\xdb\x8a\x9d\x0d\x10\x0f\xd8\xab\x88\x2f\xe4\x3d\x1a\xf4\xb5\x5f\xce\x1c\xb0\x31\x5e\xde\x08\xfe\x4f\x68\x04\x67\xff\x59\xc2\xd8\x79\xe5\x9a\x30\x4f\xa8\x20\xac\x97\x1f\x3e\xee\x95\x39\x32\x79\x23\xe9\x84\xe5\xe4\xd6\x48\x70\x49\xbb\xe7\x85\x73\x22\x32\x9e\x4f\xa0\x5c\x98\x9e\xa3\x28\x30\x4f\xa7\xfd\xbd\xbc\x83\x03\xd7\x3a\xc9\x52\x87\x42\x3a\x98\x5b\xb3\x92\x7a\xde\xfc\xbf\x47\xa3\xe0\xc7\x62\x38\x0d\x05\x60\x70\x94\x37\x1e\x47\x71\x6a\xd0\xbc\x70\x72\x39\x0c\xf5\xb4\xfe\x75\xb2\x80\xbd\x2c\x57\x6c\xe8\x01\x05\xee\x41\x7b\x27\xff\xdd\xc9\x53\xa3\xf3\xfb\xbd\xfd\xe2\xe4\x3b\x67\x17\xf4\xbb\xe2\xcd\x77\x5e\xf3\xf5\xbb\xe9\x78\xea\xec\x89\xa1\x76\x6a\xc0\x6b\xda\x3a\x3a\xec\xbb\x39\x62\x4d\xba\x5b\xc9\x19\xb8\x9b\xf0\xad\x9a\xf0\xd5\xa4\x43\x03\xe4\x04\x00\x13\x62\x1a\x68\xb3\x47\xa0\xcd\x7e\x17\xb4\xd1\x2c\x4c\xe8\x97\xf6\x3b\x0e\x73\x5b\xb3\xdd\xc1\x6f\x7f\x5f\x86\x7e\x67\x12\x97\x7b\x5c\x9f\xfa\x80\xe6\xdf\xd8\x8e\xe0\xba\x68\xb8\x13\xd7\xcd\xf6\xd9\x72\x49\x2b\x2a\x8c\x7d\x9b\xb7\x75\xef\xe6\xf8\x5a\x40\x17\x43\x1f\xcd\xf9\x1c\xd9\x7a\x60\xb4\xe1\x37\xb4\x8c\x14\x8f\x3e\x87\xf4\x7e\xee\x2e\xf7\x14\x75\x19\xdd\xb2\xaa\x8a\x6a\xae\xec\xbd\x9e\x46\xeb\x3d\x2d\x23\x56\x47\xab\xad\xda\x0a\x1a\xdd\xd8\x43\x34\xa9\x83\x71\x5b\xd6\x4a\x7e\x93\xfe\xe2\xbc\xc4\x25\x2e\xba\xab\xfd\xcd\x42\x1d\x13\x90\x36\xb8\x22\x43\x15\x0c\xbc\x22\xd7\xb0\x42\x78\x43\x76\xfe\x4e\x6b\x5a\xb7\xd7\x5b\x0f\x78\xed\x3e\x51\xf9\x19\xd6\xce\x4d\x29\xde\x98\x37\xe3\x87\xdc\x47\x2a\xfa\xdd\x3b\x20\xfb\x11\x8b\x6e\xb1\xfe\xeb\x80\x97\x24\xf0\x32\xdc\x7f\x01\xe2\x33\xc3\x6d\x50\x2d\x60\xad\x99\x70\x91\xf9\x15\xe9\x5f\x99\xd5\x7a\x51\x06\xe0\x96\x8b\x89\xff\xfa\x6e\xec\x3f\x3f\x4d\xcd\x27\xa9\x58\x76\x70\xb7\x7a\x94\xb1\x32\x63\xf7\x25\x6a\x6a\xbf\x4e\xc5\x45\x1c\x5f\xa1\x4d\x76\x95\x13\xbb\x4a\x55\x28\xfa\xe7\x12\x82\xb1\x1c\x83\xe6\x0e\x47\x60\x5c\xda\x87\x29\x02\x78\x93\x2d\x73\x32\xc5\x9b\x6c\x6b\x7e\x12\xbd\x67\xcf\xd7\x45\x7d\x4d\x49\x80\x63\xf7\x71\xe3\x6d\x1f\xd1\x59\x3a\xc3\xf7\x3d\xa4\x66\xe9\x6c\x6e\x80\x96\x4f\x6e\x2d\x58\xf9\xe4\xbe\x0f\x78\x39\x06\x1a\x8b\xad\x39\x58\x3e\x27\xbb\xff\x0a\xee\x2c\xff\x57\x1a\x58\xc9\xe0\xab\xa0\x4e\x0d\x9d\x9b\x3b\xef\xe9\x66\x7b\x73\xcf\x77\x6f\xda\x86\x36\xa0\x7f\x1f\xf6\x1f\xc5\xf4\xfd\x31\xc6\xaf\x1d\x4b\xdb\x68\x8a\xef\xba\x1d\xbe\xf7\xdb\x79\xc0\x9d\xba\x79\x7d\xff\xff\x8f\x5a\x6c\x47\xd3\x2f\x83\x6e\xd9\xe3\xfc\xdb\x60\x6f\x9f\xe0\x30\x4d\x89\xe3\xf0\xfc\xa2\x4f\x4d\x7b\xd2\xf5\x0b\xec\x4f\x1a\xa0\xda\x9e\x1d\xa4\xfd\xb3\xd6\xf0\x23\xc9\x0b\x58\x63\x85\x29\xc2\x0d\xb9\x81\x3c\xbc\xfc\xa1\x9b\x31\xff\xfa\x17\x15\x27\x43\xfc\x67\x14\xed\xa5\xb8\xfe\xb5\xc8\xde\x95\x76\xdc\x20\xfc\x0b\x54\xb8\xd3\xec\xee\x0b\x08\xf3\xa9\xcb\xc9\xbe\x59\x13\x72\x38\x1c\xf0\x8a\x1e\xd0\xfc\x0f\x67\x67\xff\x1d\xd9\xff\x65\xea\x75\xd1\x34\xac\xbe\xfe\xf0\xee\x15\x71\xd5\x85\x0d\xab\x93\xdf\x64\xb2\x29\x9a\x3f\xfc\x6f\x00\x00\x00\xff\xff\x10\xa0\xcc\x28\xf4\x4a\x00\x00") func cmdInternalPagesAssetsJsPopperMinJsBytes() ([]byte, error) { return bindataRead( _cmdInternalPagesAssetsJsPopperMinJs, "cmd/internal/pages/assets/js/popper.min.js", ) } func cmdInternalPagesAssetsJsPopperMinJs() (*asset, error) { bytes, err := cmdInternalPagesAssetsJsPopperMinJsBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "cmd/internal/pages/assets/js/popper.min.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa5, 0x2f, 0x7a, 0xa5, 0x4d, 0x7b, 0xca, 0xaf, 0xa0, 0x56, 0xee, 0xa, 0x5, 0x2, 0x62, 0xdf, 0xc5, 0x69, 0x4a, 0xe2, 0x8d, 0xee, 0x8b, 0x4c, 0xac, 0x34, 0x29, 0xaf, 0x37, 0xff, 0xd, 0x66}} return a, nil } var _cmdInternalPagesAssetsStylesBootstrap400Beta2MinCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x6b\x8f\xe3\x38\x92\x28\xfa\xfd\xfc\x0a\x6d\x16\x0a\x5d\x39\x6d\xb9\x24\xf9\x99\x4e\x54\x63\x66\x1a\xb3\x38\x03\x4c\xef\x87\x9d\xb3\xc0\x05\xfa\xd4\x05\xf4\xa0\x6d\x4d\x49\x96\xae\x24\x57\x2a\xc7\xf0\xfe\xf6\x0b\xbe\x24\x3e\x82\x94\xe4\x74\x76\xcf\x01\xce\xd6\x4e\xa7\x4c\x05\x23\x82\x8c\x60\x44\x90\x22\x83\x9f\xff\xf0\x6f\xff\xc3\xf9\x83\xf3\xe7\xa2\x68\xea\xa6\x0a\x4b\xe7\xfb\x72\xee\xcd\x3d\x37\x42\x4d\x38\x0f\x9c\x4f\xc7\xa6\x29\xeb\xdd\xe7\xcf\x07\xd4\x44\x1c\x66\x1e\x17\xf9\x23\xae\xf5\x73\x51\xbe\x56\xe9\xe1\xd8\x38\x81\xe7\xfb\x6e\xe0\xf9\x1b\xe7\x7f\x1d\x91\x80\xed\x4f\xe7\xe6\x58\x54\xb5\x11\xf8\x25\x6d\x1a\x54\xcd\x9c\xbf\x9e\xe2\x39\x06\xfa\x5b\x1a\xa3\x53\x8d\x12\xe7\x7c\x4a\x50\xe5\xfc\xf2\xd7\xff\x25\xb0\x90\x36\xc7\x73\x84\x89\x7f\x6e\x5e\xa2\xfa\x73\xc7\xcf\xe7\x28\x2b\xa2\xcf\x79\x58\x37\xa8\xfa\xfc\xb7\xbf\xfe\xfc\x97\xff\xf8\xfb\x5f\x30\x7f\x9f\x77\x55\x51\x34\x17\xd7\x8d\xb2\x33\xda\x7d\xf0\xbc\x4d\xb4\xdf\x3f\xbb\x6e\x7a\x4a\xd2\x43\xb1\xfb\xb0\x5e\xfb\xde\x3e\x78\x76\xdd\xf2\x5c\x95\x19\xda\x7d\x58\xef\x97\x41\xec\xe3\x82\xf4\xf4\x6d\xf7\x01\x6d\x17\x68\x1b\x3f\xbb\x6e\x85\x92\xdd\x87\x24\x5e\xac\x96\xab\x67\xd7\x2d\xaa\xf0\x74\x40\xbb\x0f\xfb\x64\x83\xfc\xe5\xb3\xeb\xbe\xa2\x2c\x2b\x5e\x76\x1f\xf6\xfb\xd8\xf7\x36\xcf\xae\x7b\xa8\x10\x3a\xed\x3e\x04\xdb\x70\x43\x6a\x34\x28\xcc\x76\x1f\x02\x2f\x7e\x7a\xc2\xaf\xe3\xd7\xf0\xb4\xfb\xe0\x6f\xc2\x20\xda\x3e\xbb\xee\xcb\x31\x6d\x30\x3a\xc2\xdb\xa1\x0a\x5f\x77\x1f\xb6\xeb\x2d\x7a\x5a\xb3\x9f\x6e\x12\x56\xdf\x76\x1f\x16\xcb\x45\xb8\xf4\x30\x73\x55\x9a\x87\xd5\xab\xd0\xa0\x1a\xc5\xc5\x29\x21\x65\x5d\xcd\xfa\x1c\xc7\xa8\xae\x05\x2e\xd2\xd3\xbe\x10\xc9\x86\xd5\x29\x3d\x1d\x04\xb6\x13\xdc\xae\x4a\x68\x69\x86\xc5\xb5\xfb\xb0\xdf\xee\x9f\xf6\x21\x01\x90\x18\x89\x2a\x14\x7e\x2b\x8b\xf4\xd4\xb8\x6d\xbd\x53\x4a\xea\x7c\xb7\xda\xac\xcb\x56\x2e\xcd\x93\xdd\x66\xbd\x55\x4b\xb3\xc3\xee\xe9\x29\x50\x4b\xdb\x6c\xe7\x07\x9e\x47\x8a\xf7\xc5\xa9\x71\xf7\x61\x9e\x66\xaf\x6e\x1d\x9e\x6a\xb7\x46\x55\xba\xdf\xb9\x61\x59\x66\xc8\xad\x5f\xeb\x06\xe5\xb3\x3f\x67\xe9\xe9\xdb\x2f\x61\xfc\x77\xf2\xf3\xdf\x8b\x53\x33\x7b\xf8\x3b\x3a\x14\xc8\xf9\xaf\xbf\x3e\xcc\xfe\xb3\x88\x8a\xa6\x98\x3d\xfc\x4f\x94\x7d\x47\x4d\x1a\x87\xce\x7f\xa0\x33\x7a\x98\xfd\xa9\x4a\xc3\x6c\xd6\x23\x9d\x3d\xfc\x09\x23\x75\x7e\x2e\xb2\xa2\x72\xfe\x92\x17\xff\x48\x1f\x7a\x3c\x7a\xc1\xdf\x5f\xf3\xa8\xc8\x1e\x14\x26\xf3\xe2\x54\xd4\x65\x18\xa3\xdd\xc3\xdf\xff\xfd\x97\xe2\x54\xb8\xff\x89\x0e\xe7\x2c\xac\x1e\x66\xbf\xa0\x53\x56\xcc\x7e\x29\x4e\x61\x5c\xcc\x7e\x2e\x4e\x75\x91\x85\xf5\xec\xe1\x6f\x69\x84\xaa\xb0\x49\x8b\x93\x83\xe1\x1f\x66\x0f\x3f\x17\xe7\x2a\x45\x95\xf3\x1f\xe8\xe5\x61\xd6\x21\xbc\xfe\x31\x47\x49\x1a\x3a\x65\x95\x9e\x9a\xcb\x1f\x66\xbb\x5d\xb8\xc7\x63\x68\xb7\x8b\xd0\xbe\xa8\xd0\xa5\x41\x6d\xe3\xd6\xc7\x30\x29\x5e\x76\xa7\xe2\x84\xfe\x2d\xcd\xcb\xa2\x6a\xc2\x53\xf3\x1c\x15\x2d\xfc\xe6\x1a\xce\xc2\xdd\xf7\xb4\x4e\x1b\x94\x50\x04\x09\x8a\x0b\xca\xce\x8e\x8c\xc5\x2c\x3d\xa1\x6b\x18\x45\xd5\xaf\x4d\xda\x64\xe8\x2b\x23\x7b\x89\x8b\x53\x83\x4e\xcd\xee\xc1\xf9\xf4\xe0\x84\x4d\x53\x7d\x22\xef\x1f\x9d\x87\xc7\x87\x6b\x59\xa1\x0b\x51\x6f\x97\xf6\x45\x59\x21\xf7\xa5\x0a\x4b\x81\x70\x94\x15\xf1\xb7\xff\xef\x5c\x34\x68\x86\xa1\xa3\xa2\x4a\x50\xb5\xf3\xcb\xd6\xa9\x8b\x2c\x4d\x9c\x0f\x4f\x4f\x4f\xcf\x65\x78\x40\x54\x35\xdc\xf4\x54\xa7\x09\xda\x85\xdf\x8b\x34\xb9\x36\x47\x14\x26\x97\x24\xad\xcb\x2c\x7c\xdd\x35\x61\x94\x21\x17\x17\xa1\xca\x3d\x54\xc5\xb9\xbc\xa6\xf9\x61\xd6\x54\x17\x53\xfd\x63\x30\x3b\x2e\x66\xe5\xa5\xa8\xca\x63\x78\xaa\x77\x8b\xe7\x97\x34\x29\x5e\xea\xdd\x82\xbe\x12\x2b\x92\xe6\xb2\x7a\xf3\x53\xf8\x3d\x0a\xab\x8e\x32\xee\xcc\xeb\x3c\x0a\x93\x03\xd4\x02\xcf\xf3\xae\x73\xc2\x1c\x7b\xe9\xc6\x45\x96\x85\x65\x8d\x76\xfc\x41\xe8\x10\x0a\xe9\x34\xc9\x8c\x3f\x1d\x2f\x51\x18\x7f\xc3\x0d\x3a\x25\xb8\x6a\x51\x11\x6b\xa1\xd5\x71\x29\x76\x94\xf4\x95\x85\xa2\x23\xc0\x59\x92\x24\x02\x96\x2b\xa0\x4c\x44\x63\xd2\x7f\x62\x43\xc1\x78\x8f\x8a\xf6\x7a\x6c\xf2\xec\x22\xa8\xfb\xae\x1f\x3e\xcf\x58\x51\xdc\x23\x22\xa6\xc3\x9f\xfb\xab\x67\xf7\x05\x45\xdf\xd2\xc6\xa5\x7a\x99\xfe\x13\xb9\x61\xf2\x8f\x73\xdd\xec\x7c\xcf\xfb\xf8\xec\xe6\xb5\xe5\x4d\xf1\x1d\x55\xfb\xac\x78\x71\xeb\xe6\x35\x43\xbb\x3a\xae\x8a\x2c\x8b\xc2\xaa\x47\x1a\x96\xee\x31\x3d\x1c\x89\xa9\x62\x9d\xd3\x54\xe1\xa9\x2e\xc3\x0a\x9d\x9a\xeb\x1f\x31\x96\xef\x29\x7a\xc1\x8d\xbc\xbc\xa4\x49\x73\xdc\x25\xe8\x7b\x1a\x23\x97\xfc\xb8\x86\x55\x93\xc6\x19\x9a\x85\x58\x2d\x66\x49\x1a\x66\xc5\x61\xb6\x4f\x0f\x71\x58\x62\xe5\xc7\x8f\xe7\x0a\xcd\xf6\x45\x81\xfb\x85\x2a\xd7\xec\x48\xb4\x6b\x96\x87\xe9\x69\x76\x0a\xbf\xcf\x6a\x14\x63\xe0\x4e\x1f\x88\x52\x5f\xa3\x22\x79\xbd\xe4\x61\x75\x48\x4f\x3b\xef\x59\xec\xae\x7f\x25\xbb\x45\xf8\xc2\x9d\xbf\xf3\x2b\x94\xd3\x9f\x2f\x54\x7c\x4b\xcf\x53\xc4\xb9\x7a\x66\xfa\x17\xf8\xc1\x2a\x78\x7a\x26\x92\x0b\xb3\xf4\x70\xda\x65\x68\xdf\x3c\x83\x8a\x7a\xfd\xb5\x09\xa3\xf4\x94\xa0\xf6\xcb\x83\xeb\x3f\x7c\xdd\xed\x8b\xf8\x5c\x5f\x8a\x73\x83\x91\xef\x3c\x41\x05\x8f\x95\xa8\x71\xcc\xb6\x60\x95\x7b\x66\x2c\x78\xcf\x5c\x25\x88\xb9\x8a\x32\x74\x3d\xfa\x33\x3a\x8e\x8f\xcb\xd9\x71\x35\x3b\xae\x59\x9f\xbb\x4d\x51\xee\xbc\x67\xf6\x23\x2a\x9a\xa6\xc8\x77\xf3\x55\x85\xf2\x6b\x69\x03\xc1\xdd\x40\x2d\x5d\x12\x36\xa1\x5b\x54\xe9\x21\x3d\x85\x99\x4b\xed\xde\x4c\xb0\x81\x66\x4b\x29\x2b\x3d\x04\xe1\x24\x45\xd3\xa0\xe4\x79\x10\x20\x3e\x57\x75\x51\xed\x8e\x28\x2b\x9f\xbb\x21\x48\x18\xf5\xae\x61\x92\x54\xa8\xae\x2f\x7a\x03\x98\x58\xc9\xa8\x39\x15\x55\x1e\x66\x92\x24\xd3\xd3\x11\x55\x69\x73\x4d\xb2\x59\x91\xcd\xce\xd9\x60\x7f\x14\x99\x53\x60\x58\xe7\x8c\xc1\x1d\x52\xc9\xe9\xeb\x75\x1c\x25\xcd\x45\xd4\xa0\x8d\xe7\x5d\x93\xe4\x02\xc8\x80\x13\xc1\x6a\xb3\xf3\x04\x37\xd0\x8d\x18\xc7\x73\x08\xe9\x64\x7f\xba\x08\xad\x49\x9b\x30\x4b\xe3\x6b\x34\xab\x9b\xaa\x38\x1d\x24\x72\x51\x91\x25\xa8\xba\xd6\x79\x98\x31\xfb\x44\x14\x7b\xeb\x7d\xbc\xd6\xe7\x68\x56\x9f\xcb\x4b\x59\xd4\x29\xe9\xe8\x0a\x65\x61\x93\x7e\x47\xc2\x00\xd8\xac\x3e\x4a\xbd\xe4\x3d\x7f\x47\xd8\x3c\x84\x19\xd3\xf1\x28\xac\x11\x71\x84\xf5\x39\xba\xb0\xd6\xb8\xf3\x60\x85\xf2\x2b\xc6\x8d\x7b\xcf\x9d\xe3\x5f\xe1\x85\xa9\x3f\x8b\xd1\x54\x29\x63\x87\xa1\x0f\x16\xc1\x70\x99\x14\xc8\xad\xbf\xa5\xe5\xae\x88\xfe\x81\xe2\xa6\xbe\x86\xbb\x23\x1e\x0e\x3d\xb1\xd5\x3a\x5a\x98\x55\xea\x1a\xee\x4e\x45\xf3\xe9\xd7\x63\x85\xf6\x5f\x1f\xe9\x33\x1f\x9a\x5f\x1f\x19\x16\xa6\x1a\x20\xcb\x76\x04\x74\x5c\xcf\xec\x30\x22\xc3\x6f\x25\xd5\x9b\x90\x6b\x5c\x24\x68\xf6\x2d\x4a\x70\x10\x31\xab\xc3\xbc\x94\xdc\x53\x17\x3c\xf5\x61\x94\x68\xf7\xb0\x45\xa8\xd0\xd0\x18\xe8\x2d\x4f\x78\x6e\x0a\xab\x7b\xba\x52\xaf\xa1\xa9\x72\x9a\x1f\x2e\x8a\x4a\xe5\x69\x92\x64\x88\x8f\x6c\x3e\x60\xb1\x8a\x7d\x3f\x90\x56\x93\x49\xcc\xe3\xa5\x23\x7e\x4c\x93\x04\x9d\xae\xbf\x56\x45\x86\xbe\x44\xe7\xa6\x29\x4e\x5f\x67\xe1\x2c\xac\x50\x38\xa3\x3f\x67\xe9\xa9\x3c\x37\xac\xcb\x5e\x4b\xf4\x85\x4c\x58\xbe\x3e\xce\xb2\x30\x42\xd9\xac\x46\x19\x8a\x9b\x59\x7d\xce\xf1\x34\x62\x86\x3b\x1f\x57\xbe\x10\x4f\x5c\x9c\xe3\xa3\x1b\x12\x6f\xb6\xcb\xc3\x53\x5a\x9e\x33\x22\x93\x67\xe3\x9b\xab\x3d\xb2\xb9\x32\x47\x7a\x29\xc3\x24\x49\x4f\x07\xd2\xbd\xf3\x0d\x31\x01\xbc\x88\xdb\x05\x5a\xca\x94\x99\xcd\x64\x54\x0f\xc3\xd0\xb9\x24\x8a\xa3\x15\xaf\xcd\xf1\x22\x80\x71\xdb\x46\x5a\xdb\xb9\xe4\xf4\x44\x46\x36\xb1\x33\xa0\x4f\xa0\x7d\xc7\xdb\x51\x85\x49\x7a\xae\xb1\x61\x22\xc5\x8a\xbe\xe1\x10\x8a\x99\x67\x5e\xb4\x2a\x5b\x07\xeb\x85\xc3\x07\x2e\xa9\xe1\x56\xb8\x7d\xa4\x45\x57\x51\x38\xb3\xa2\x6c\x68\x0c\xc1\xa4\xd1\x49\x01\x8c\x17\xf8\x40\xe9\x75\x96\x97\x40\x46\x5d\x24\x74\xd1\xdc\x25\x7b\x4b\xe9\xd2\x7e\x23\x76\x67\x5f\x54\x39\xd5\x3c\xa6\x34\xa8\x46\xcd\xd7\x19\xfd\x51\x9f\xa3\x3c\x6d\xbe\x72\x05\xc3\xf1\x9f\x43\xdf\x30\x0d\xbc\xf0\x66\x87\x65\x89\xc2\x2a\x3c\xc5\x68\x47\x5f\x5d\x25\xb8\xdd\xce\xcd\x8b\x7f\xb2\xce\x49\x4f\x27\x54\xcd\x44\x72\xc6\xd7\x8c\x01\xe0\x3d\x13\x90\xf6\x82\x2b\xdc\xce\x03\x06\x17\xe9\x1b\x8a\x39\x3e\xa2\xf8\x5b\x54\xb4\x5f\x67\x42\x21\x16\x7f\xf1\x15\x8e\x7e\x9f\x3b\xc4\x22\x9a\x24\x6c\x90\x84\x02\x17\x34\x69\x8e\xdc\xac\x88\xc3\x4c\x7a\x95\x17\xa7\xe6\x28\x95\x60\x40\xb0\x0f\xb3\xb4\x6e\x70\xc4\xdd\xe9\x87\x6c\x84\x2a\x44\xb4\x81\xdb\x94\xeb\x3e\x45\x59\x52\xa3\xe6\x92\xa7\x27\x1a\xe0\xee\xbc\x9e\xdf\xe7\x4e\xb9\xd8\x54\xc0\xbb\x66\xe8\x80\x4e\x89\x1c\xb8\x3e\xd3\x8a\x24\x08\xcf\xc3\xd6\x15\x7e\xaa\xa8\x64\x97\x2e\x98\x54\x5a\x00\x68\xe7\xb3\x6c\xfa\xc5\xd9\x21\x8d\x53\xae\x65\x55\x1c\x48\x54\x63\x72\xbe\xb4\xcb\x4e\xe7\x3c\x42\x15\xd6\x08\xd6\x6b\x44\xea\x6e\x5d\x62\xae\xa8\x9a\x1a\x00\x8b\x73\x23\x03\x5e\x18\x8b\xb8\x4b\x19\xf6\x1a\x85\x55\x7c\xfc\xca\x47\xbc\x5b\xec\xf7\x35\x6a\x76\x2e\x59\xa5\xd0\xc5\x24\x8c\x1b\x56\xb3\x27\x47\x0b\xdc\x18\x03\x66\x32\x6b\x26\xd8\xde\x17\x42\x3a\x41\x88\xf5\x75\xf6\x69\x86\xdc\x73\x99\x15\x61\xc2\xdb\x83\x05\xd1\x75\xb1\x79\x64\x16\xe7\x06\x9b\x08\xc8\x44\x5e\x99\x7b\xe8\x5e\x62\x45\x74\xd3\x06\xe5\xd7\x06\xe5\x65\x16\x36\x48\x9e\xfd\xfe\x4a\xfd\xd2\x57\xa9\x54\x9c\xa2\x1e\xfd\xd9\xfc\x18\xcc\xe6\xc7\xc5\x6c\x7e\x5c\xce\xe6\xc7\xd5\x6c\x7e\x5c\xcf\x8c\xd1\xbb\xae\x59\x90\x31\x64\x81\xdf\x4a\x9b\xa9\x04\xb2\xa2\x11\xfa\x47\x5f\x08\x0a\x03\x6a\xf6\x31\x4f\xc7\x40\x2c\xa7\xa5\x0b\x3c\xfd\x17\x15\x7a\xc3\xc0\x97\xb3\xe3\xf2\xa2\x6a\xfa\x15\x37\xe7\xb8\x92\xca\x03\xf6\x62\x8d\x1b\x25\xcf\xb2\xae\xf3\x0c\x85\x89\x0e\x2d\xb5\x69\xe1\x79\xd7\x39\xeb\x4d\x57\xe4\x7c\x0d\x40\xaa\xad\xef\x6b\x8a\x6d\x5b\xcd\x21\x2a\xe6\xba\x62\x0f\x2c\x27\xd6\x15\x3b\x69\x31\xae\xee\xb1\x12\x63\x30\x5f\x98\x25\x88\x61\x18\xb7\x5d\xdc\xac\x13\xd8\x6e\x4d\xa3\x3a\x44\xe1\x27\x6f\x86\xff\xcd\xfd\xc7\xeb\x9c\xcc\x05\x66\xc0\x8c\x40\x9d\xe9\x5e\xe7\x79\x58\x7d\x9b\xe1\xff\x74\xae\x63\x1e\x60\x7a\xfa\x9c\x36\xde\x6f\xd1\xe2\x3a\x27\x63\xe2\x7c\x22\x7e\x25\xe9\x02\x1c\x3a\xa3\x79\x26\x2f\x05\x97\x43\xa1\xe9\x18\x9b\x02\x4b\x06\x1d\x3c\x46\x35\x30\x1a\x30\x66\x61\xdd\xb8\xf1\x31\xcd\x92\x47\xde\x9f\x15\x1d\x25\x65\x7b\x9d\xa7\xa7\xb4\x49\xc3\x2c\xad\x73\xa1\x3f\x9e\xbc\x8f\xcf\x4a\x28\x70\x2e\x4b\x54\xc5\x61\x8d\xae\x73\x6d\x72\x06\xcc\x34\x25\x9d\xef\x2b\xb8\x74\xe1\x44\x71\x30\xb2\x20\xa4\x80\x0f\xa8\xdc\x2d\x46\x75\x6b\x8d\xff\x3b\xf0\xfc\xa5\xf3\xbf\x3d\xef\x4f\xde\xc3\x75\x9e\xe6\x07\x77\x9f\x9d\x53\x3c\xcf\x94\xbc\x95\x68\xd6\x09\x54\x73\x3c\xe7\xd1\x29\x4c\x33\x41\xc2\x44\x33\xc1\x75\x8b\x67\x70\xc1\xec\x59\x8e\x10\x19\x02\xd2\x6f\x74\x62\x19\x66\x99\x33\x0f\x6a\x07\x85\x35\x72\xd3\x13\x76\x37\xaa\x1b\x95\x18\x63\x73\x05\x58\xc2\xf4\xa5\x8b\x27\x0e\x90\x5d\x94\x46\x50\x07\xcd\x43\x6e\x59\xbe\x72\x37\xdb\x27\x4c\xf2\x9a\xf5\x9b\x97\xac\x31\x31\xa1\xcb\x2b\x94\x3b\xf3\xa5\xac\x3b\x02\x87\x51\xb2\xf4\x97\x1b\x48\x26\xf4\x43\x04\x24\x80\x6b\xf8\x93\x44\xc4\x53\xe2\x0c\x0d\x19\xf7\x0b\xdf\xa2\x64\x3c\x67\x44\x29\x34\xb6\xd8\x5a\x98\xca\x16\xe6\xea\x5b\x94\x38\x22\x05\x4f\x1c\x2d\x9e\x62\x84\x36\x9e\x47\xe6\xa1\xf2\x58\x19\x9a\x95\x82\x8c\x52\x96\x30\x36\x47\xe9\x16\x7d\x0a\x31\xd0\x51\xe2\xa2\x84\x3a\x39\x9a\x97\x15\x72\xe9\xac\x97\x4c\x02\xb1\x9a\x33\x6d\x5c\x2c\xbd\xb2\xed\xa6\xcc\xee\x2b\x9b\x1c\x5f\xe7\x78\x10\x87\x29\x0e\xd0\xf5\xb8\x92\xd9\x29\x7f\x55\x76\x51\x36\x35\x91\xa4\x44\xb2\x65\x24\xfc\x15\xd7\x90\xc8\x60\x62\xdf\x46\x3e\xf5\xe1\x2f\xf9\x08\xf5\x78\x11\xc8\xf6\x63\x71\x85\x79\xbc\x02\x95\xc8\x37\x2a\x43\xa5\x4d\x60\xa8\x44\x3e\x61\x19\x2a\x3d\xad\x0d\x95\xe8\x17\x2e\x43\x2d\xdf\xa7\x0c\xf6\x2f\x99\x9d\x7b\x87\x9e\x9b\x57\xc5\x4b\xa7\x79\x6e\x5e\xbb\xfb\x0c\xb5\x78\xb6\xc3\xcb\xf0\xef\x67\xfe\x82\x7c\xc5\xd9\xe1\xff\x3c\x2b\x3f\x25\x52\xae\x48\x9d\xd0\x22\x25\xd7\xf9\xa9\x70\x0f\xe7\xa6\x41\x55\x2d\x7b\x28\x4f\x59\x16\x14\x00\x7f\x9a\xc7\x45\x36\x13\x0b\x7e\x8d\xb3\xb0\xae\xff\xf0\x25\x2e\x32\xf7\xeb\x45\xee\x08\x4f\xee\x05\xef\x4a\x6b\x63\x50\x9f\xfd\xf1\xd8\x5f\xfe\x3b\xa0\x7f\xd9\x9f\x05\xfd\xb3\xa4\x7f\x56\xf4\xcf\x9a\xfe\xd9\xd0\x3f\x5b\xfa\xe7\x89\xfe\xc1\xbd\x48\x9f\xb2\x03\xff\xcb\x69\xe1\x27\xaf\x7f\x14\x4a\x83\xee\xb1\x7f\x5a\x74\x4f\xcb\xee\x69\xd5\x3d\xad\xbb\xa7\x4d\xf7\xb4\xed\x9e\x9e\xba\xa7\x9e\x9f\x3c\xe1\x7f\x39\x3f\xf8\xc9\xeb\x1f\x85\xd2\xa0\x7b\xec\x9f\x16\xdd\xd3\xb2\x7b\x5a\x75\x4f\xeb\xee\x69\xd3\x3d\x6d\xbb\xa7\xa7\xee\xa9\xe7\xa7\xce\xf9\x5f\xce\x0f\x7e\xf2\xfa\x47\xa1\x34\xe8\x1e\xfb\xa7\x45\xf7\xb4\xec\x9e\x56\xdd\xd3\xba\x7b\xda\x74\x4f\xdb\xee\xe9\xa9\x7b\xea\xf9\x69\x33\xfe\x97\xf3\xd3\xf6\xea\xd1\xf6\x1a\xd2\xf6\x4a\xd2\x76\x7a\xd2\x76\xaa\xd2\x76\xda\xd2\x76\x0a\xd3\x76\x3a\xd3\x76\x6a\xd3\x76\x9a\xd3\x76\xca\xd3\x52\xfd\x01\x56\xa7\xc5\xb9\x78\x7a\xea\x7c\xbd\x30\xcc\x6d\x23\x9f\xa8\xfd\xa5\x1b\xb5\x65\x85\xf6\xa8\xaa\x50\x42\x3d\x80\x47\x07\x6f\x14\xd6\x29\xf9\x7e\xdf\x81\x11\x2e\xbe\xa3\x9d\x4f\x01\x0e\x55\xf1\xb2\xf3\x95\x20\xe6\xda\x69\x7d\x87\x9f\x2c\x74\x12\xf3\x22\xff\xa2\x95\x98\xdd\xe1\x38\x68\xa0\x4b\x46\x9e\x8c\x60\x3b\x5f\x90\xff\xfb\xf8\x0c\x14\xf5\xf5\xbb\x32\x8a\x24\x90\x91\xf8\xeb\xf9\x1a\xff\xdf\x46\xc0\x22\x94\x09\x4d\xe9\x0a\x29\x9e\x85\x8c\x27\x58\x09\x08\xf0\x8f\xbe\x66\xb0\x62\x55\x96\x72\x95\xc5\x42\x6f\x80\x50\xd6\x23\xe8\x0b\x29\x9e\x95\x8c\x67\xe9\xeb\x4d\x10\xca\x7a\x3c\x7d\x21\xc5\xb3\x96\xf1\xac\x3c\x01\xc1\x4a\x5a\xd3\x59\x71\x31\x6e\x94\x2a\x80\x0c\x56\x90\x10\x56\x8a\x14\xb6\x32\x9e\x35\x20\x85\x35\x24\x85\xb5\x22\x85\x27\x19\xcf\x46\x94\xc2\x46\x92\xc2\x86\x4b\xc1\xf7\x14\x35\x02\xc4\xb0\x85\xc4\xb0\x55\xc4\xe0\x2b\xfa\xf8\x04\xc8\xe1\x09\x92\xc3\x93\x22\x07\x5f\xd5\x49\x4f\x94\x04\xb0\xbc\x76\x9d\xd3\xf8\x6a\x9f\x56\x75\xd3\x8f\x5a\x3a\x0b\x71\xfd\x67\xfe\xc0\xe1\x7c\x15\x86\x83\x74\x10\x81\x0a\x11\x30\x88\x80\x43\x2c\x54\x88\x05\x83\x58\x70\x88\xa5\x0a\xb1\x64\x10\x4b\x0e\xb1\x52\x21\x56\x0c\x62\xc5\x21\xd6\x2a\xc4\x9a\x41\xac\x39\xc4\x46\x85\xd8\x30\x88\x0d\x87\xd8\xaa\x10\x5b\x06\xb1\xe5\x10\x4f\x2a\xc4\x13\x83\x78\xea\x7a\xcc\xd3\xba\xcc\xe3\x7d\xe6\x75\x40\x7a\xbf\x76\x1d\xdb\xf7\xbd\xd6\xb5\x3e\xef\x5b\x1f\x77\x2e\x59\x2f\x74\xfd\x8b\x18\xcf\x08\x83\x85\xbd\x0f\xa4\xf7\xa2\x2d\x62\x00\x0b\x09\x80\x98\x1c\xf6\x66\x29\xbd\x11\x6d\x09\x03\x58\x49\x00\xa2\x91\x60\x00\x6b\x09\x80\xd8\x02\xf6\x66\x23\xbf\xd1\xf9\xde\x4a\x00\x6b\x9d\xef\x27\x09\x60\x23\xf0\xed\x7b\x72\x9f\xe8\x8c\xfb\x72\xaf\x09\xc3\xca\x16\xde\x63\xa7\xfe\x9e\x9e\x8e\x85\x0c\x6f\x75\x76\x38\xa8\xb9\x87\xbf\xc3\x11\xd1\x9d\x5c\x1e\x0e\xa9\xa6\x7b\x3d\x1c\x7e\xdd\xc9\xf1\xe1\xf8\xed\x4e\xbe\x0f\x07\x80\xd3\xdd\x1f\x0e\x16\xef\xe4\x01\x71\xb4\x79\x27\x27\x88\xc3\xd5\xe9\x7e\x90\xc4\xd2\x77\x72\x85\x24\x18\xbf\x93\x37\x24\xd1\xfc\x8d\x0e\xb1\xce\x47\xfb\x44\x69\x7c\x99\xdc\xa2\x34\x78\x4c\x9e\x51\x1a\x16\x26\xe7\x28\x8d\x02\x93\x7f\x94\xf4\xdb\xe4\x22\x25\xcd\x35\x79\x49\x49\x51\x4d\x8e\x52\x52\x41\x93\xaf\x94\x94\xcb\xe4\x2e\x65\x5d\x32\x7b\x4c\x59\x4f\xcc\x4e\x53\xd6\x01\x8b\xdf\xac\x73\x57\x76\x13\x9e\xf8\x6a\xc8\xab\x12\xf1\x0e\x38\x56\x22\x5d\x93\x6f\x25\x52\x1d\x70\xaf\x44\xa8\x03\x1e\x96\xc8\xd4\xe4\x64\x89\x2c\x07\xfc\x2c\x11\xe5\x80\xab\x25\x92\x34\x79\x5b\x2a\xc1\x01\x87\x4b\xc5\x67\xf0\xb9\xd6\xe5\x31\x3c\xb3\x7f\x4f\xa7\xcb\xd6\x0d\xde\xea\x74\xf3\xe4\x3e\x4e\x37\x4f\xee\xe6\x74\xf3\xe4\x16\xa7\x9b\x27\x77\x73\xba\x79\x72\x37\xa7\x9b\x27\xb7\x38\xdd\x3c\xb9\x9b\xd3\xcd\x93\xbb\x39\xdd\x3c\xb9\xc5\xe9\x92\x05\xb5\x3b\x39\x5d\xb2\x22\x77\x27\xa7\x4b\x96\xf4\x6e\x74\xba\x79\x32\xda\xe9\x4a\xe3\xcb\xe4\x74\xa5\xc1\x63\x72\xba\xd2\xb0\x30\x39\x5d\x69\x14\x98\x9c\xae\xa4\xdf\x26\xa7\x2b\x69\xae\xc9\xe9\x4a\x8a\x6a\x72\xba\x92\x0a\x9a\x9c\xae\xa4\x5c\x26\xa7\x2b\xeb\x92\xd9\xe9\xca\x7a\x62\x76\xba\xb2\x0e\x58\x9c\x6e\x9e\x18\x9d\x2e\x11\xb0\xdd\xe9\x12\xf1\x0e\x38\x5d\x22\x5d\x93\xd3\x25\x52\x1d\x70\xba\x44\xa8\x03\x4e\x97\xc8\xd4\xe4\x74\x89\x2c\x07\x9c\x2e\x11\xe5\x80\xd3\x25\x92\x34\x39\x5d\x2a\xc1\x01\xa7\x4b\xc5\x37\xde\xe9\xf6\x9f\x97\x32\x37\x3b\xbc\xa7\xd3\x65\x1f\x0f\xde\xea\x74\xb3\xc3\x7d\x9c\x6e\x76\xb8\x9b\xd3\xcd\x0e\xb7\x38\xdd\xec\x70\x37\xa7\x9b\x1d\xee\xe6\x74\xb3\xc3\x2d\x4e\x37\x3b\xdc\xcd\xe9\x66\x87\xbb\x39\xdd\xec\x70\x8b\xd3\x25\x5f\xd5\xee\xe4\x74\xc9\x67\xb9\x3b\x39\x5d\xf2\x5d\xef\x46\xa7\x9b\x1d\x46\x3b\x5d\x69\x7c\x99\x9c\xae\x34\x78\x4c\x4e\x57\x1a\x16\x26\xa7\x2b\x8d\x02\x93\xd3\x95\xf4\xdb\xe4\x74\x25\xcd\x35\x39\x5d\x49\x51\x4d\x4e\x57\x52\x41\x93\xd3\x95\x94\xcb\xe4\x74\x65\x5d\x32\x3b\x5d\x59\x4f\xcc\x4e\x57\xd6\x01\x8b\xd3\xcd\x0e\x46\xa7\x4b\x04\x6c\x77\xba\x44\xbc\x03\x4e\x97\x48\xd7\xe4\x74\x89\x54\x07\x9c\x2e\x11\xea\x80\xd3\x25\x32\x35\x39\x5d\x22\xcb\x01\xa7\x4b\x44\x39\xe0\x74\x89\x24\x4d\x4e\x97\x4a\x70\xc0\xe9\x52\xf1\x8d\x77\xba\xc2\xf6\x8c\xcc\x6d\xdf\xf5\x4b\x6a\x7b\x9f\x8f\xa9\xed\x9d\xbe\xa7\xb6\xf7\xfb\xa4\xda\xde\xf4\x55\xb5\xbd\xdf\x87\xd5\xf6\x7e\xdf\x56\xdb\x9b\x3e\xaf\xb6\xf7\xfb\xc2\xda\xde\xef\x23\x6b\x7b\xd3\x77\xd6\xf6\x8e\x9f\x5a\xdb\x3b\x7e\x6d\x6d\xdf\xf0\xc1\xb5\xcd\x46\x7b\x5d\x69\x7c\x99\xbc\xae\x34\x78\x4c\x5e\x57\x1a\x16\x26\xaf\x2b\x8d\x02\x93\xd7\x95\xf4\xdb\xe4\x75\x25\xcd\x35\x79\x5d\x49\x51\x4d\x5e\x57\x52\x41\x93\xd7\x95\x94\xcb\xe4\x75\x65\x5d\x32\x7b\x5d\x59\x4f\xcc\x5e\x57\xd6\x01\x8b\xd7\x6d\x33\xa3\xd7\x25\x02\xb6\x7b\x5d\x22\xde\x01\xaf\x4b\xa4\x6b\xf2\xba\x44\xaa\x03\x5e\x97\x08\x75\xc0\xeb\x12\x99\x9a\xbc\x2e\x91\xe5\x80\xd7\x25\xa2\x1c\xf0\xba\x44\x92\x26\xaf\x4b\x25\x38\xe0\x75\xa9\xf8\x4c\x5e\x97\xa5\x46\x30\x1f\x3a\x82\xce\x00\x58\x76\xa9\x82\x19\x14\xba\x2d\xbe\xf4\x8c\xa1\x72\xb4\xa8\x29\x4a\xf8\x34\xc1\x07\xf4\x84\x62\xb4\xef\x50\x1e\x51\x48\x52\x29\xa8\x47\x93\x08\x6b\xca\xf1\xec\xc0\x88\x25\x2a\x92\xd7\x1f\xc9\x7f\x2f\x02\x55\x23\x3c\xcf\x1d\x01\x9e\xad\x67\x79\x1e\xea\x5c\x48\xfa\x80\x7f\x08\x4d\x5e\x90\x3d\xf9\x72\x3e\x08\x20\x19\x84\x44\x74\x7a\x2e\x09\x53\x75\xda\x65\x10\x12\xd6\x97\x52\xaf\xf1\x28\xa0\x6c\xbb\x96\x35\x55\x5a\x62\x78\xdc\x5f\x4e\x53\xed\x4e\xcd\xd1\x2d\xf6\x6e\xf3\x5a\xa2\x4f\x45\x92\x3c\xea\x1d\x23\x9e\x01\xf1\x56\x8f\x1c\x13\x39\x7a\xdc\xe3\xa1\x27\x91\xed\x95\x37\x7d\x6d\x96\x76\x67\x26\xff\xfc\xa9\x6f\x59\x57\x02\xe5\xeb\x88\xb6\x49\xd8\x4b\x8b\x72\x22\xd7\x33\xf1\xf3\xe1\x69\x1f\x27\x63\xaa\x0a\xac\xd8\x80\x20\xee\x64\x12\x5d\x3a\xa1\x99\x5a\x20\x90\x10\xca\x20\x8c\x49\x92\xec\x51\x00\x32\xdd\x67\x2b\x32\xb5\x38\xde\x27\x41\xb2\x1e\x53\xd9\xd4\x66\x0d\x0c\xe2\x51\x26\xc3\x12\x26\xcd\xe4\x9f\x62\x8b\x79\x09\x88\x6b\x81\xd6\x71\x04\xb3\xcc\x32\x31\x99\x5a\x1b\xf9\xc9\x3e\x1a\x51\xd5\xd8\x56\x19\x08\xd4\x3e\x89\x44\x7a\xda\x17\x33\xe1\x59\x40\x4c\x7f\x82\x28\x10\x5a\x21\x98\x4b\x92\x58\xca\xd4\xba\x30\x4a\x12\xb4\x1a\xa8\x67\x6a\x9a\x08\x01\x31\x25\x23\x67\x19\xad\x66\xf2\x4f\x01\x77\x57\x02\x67\xd4\x41\x28\x0a\x41\x46\x79\xaa\x2c\x53\x1b\xf7\x7b\xb4\x0d\xfd\xe1\xaa\xa6\x66\x2a\x40\x06\xee\x04\x12\x34\x53\xd7\x4c\xfa\x25\x20\xe7\x05\x20\xa2\x55\x6c\x52\x54\x96\xff\xcb\xd8\x4a\x3f\xf2\xa2\xcd\x60\x4d\x53\x23\x65\x18\x90\x35\x89\x00\xc9\xe8\x33\x13\x7f\x08\x98\xd9\x6f\x10\x4b\xb2\x4f\xf6\x08\x64\x93\xe6\x33\x33\xb5\x0f\xc5\x28\xde\xc3\x56\x47\xa8\x68\x6a\x9e\x04\x02\xf1\x25\xa3\x4f\xc2\xea\xdb\x4c\x78\x96\xa4\x87\x7f\x82\x46\x66\x1d\x6f\x63\x58\x45\x49\x6a\x36\xa3\x85\x79\x8a\xa2\x08\xee\x92\xbe\x9e\x59\x6e\x3d\x04\x68\x18\x24\xe4\x61\xdc\xa4\xdf\xd1\x4c\xfa\x25\x60\xe6\x05\x00\x22\x93\xdf\x95\x98\xa1\xf5\xa7\xba\x6e\x23\x0a\x53\x9b\x65\x98\xf1\xcc\x3a\x73\x12\xd5\x90\x3e\xc3\xa1\xcd\x84\x63\x63\xac\x70\x11\x2c\xb6\x0b\xa4\xa0\x23\xba\x25\xe0\x5b\x3e\xad\xbc\x15\x74\x40\x8e\xc6\x60\x0a\x4a\x39\x30\xc3\xac\x8d\xe1\x4b\x84\x77\x64\xe5\x74\x9a\xa3\xf2\x53\x8e\xe4\xa0\xa6\x10\x48\x43\x0c\xea\x01\x30\xb7\x46\x7d\xc1\x6a\x35\xe3\xff\x13\x63\x3f\x01\xf5\x84\x30\x50\xc6\x86\xe5\xdc\x2d\x11\xf6\x0b\x34\x9b\x15\x59\x21\xa4\xc8\x2b\x54\x97\xc5\xa9\x4e\xbf\xe3\x28\xdc\x9c\x56\xa1\x3b\x17\xd7\xb2\x64\x32\x3c\x35\x41\x97\x50\x86\x9c\x96\xc3\x4e\x81\x24\x5e\x81\xb2\xcd\xe0\x22\x5c\xf9\x98\x92\x33\x1f\x7d\xf2\x19\x88\x15\x63\xd7\x03\x2d\xda\xac\x37\x70\x8b\x72\x4b\xa2\x88\xdf\xb8\x45\x79\x32\xa5\x45\x4f\x4f\x3e\xdc\xa2\xec\xf0\x2f\xd3\xa2\xec\x30\xa5\x45\xbe\xff\xf4\x04\x37\xa9\xcd\xfe\x65\x9a\xd4\x66\xe6\x26\x69\xd0\xff\x2a\x5c\x9b\x8d\xd4\xbe\xa8\x72\x37\x2e\x4e\x4d\x55\x58\xfa\xb8\x9f\x76\x93\xa5\x06\x87\xad\x38\x28\x69\xf6\x0c\x69\xf5\x8c\x96\x5d\x31\xd5\x69\x1e\x1e\x90\x9e\x45\x2c\x4b\xcb\x5d\x9f\x54\xa9\x05\x0e\xb0\xc7\x28\x59\x26\xf0\x11\x6a\xf1\x0c\xbb\x68\xc9\xc5\x83\xec\xce\xdc\x5f\xd5\xb3\x3e\x8d\xa8\xf6\x4e\xee\xa5\x1d\xe9\x77\xd4\x96\xe1\x29\xd1\x4d\xac\x7e\xb2\x58\xed\x65\x96\x76\x69\x54\xe7\x48\xbe\x67\xeb\x45\xc9\x7e\xdf\x25\x67\xf2\xc4\xcc\xa7\x9e\x83\xff\xd1\xb3\xde\xcc\x8f\xfb\xc1\x82\xda\xf8\x00\x7b\x0c\xa5\x05\x5d\x7a\x99\xf2\xdc\xb8\x65\x16\xc6\xe8\x48\xd2\xcc\x5d\xe4\x44\x55\x45\x19\xc6\x69\xf3\x4a\x8e\xe1\x8b\x08\x70\x0f\xdc\x5a\xf7\x6d\x95\xa7\x57\x49\xd2\x1a\x2b\x7f\x32\x93\x8a\x7f\xad\x50\x98\x14\xa7\xec\xf5\x2b\x14\xd6\xd2\x90\xa3\xc7\x48\x13\x4b\xc9\x78\x49\x2a\x32\xac\xfc\x3c\x93\x5b\x7e\xce\x9a\xb4\xcc\xd0\xd7\x47\x9e\x7b\x27\x0e\xb3\xf8\x53\x40\x35\xd1\xf9\xd1\x09\xca\xf6\x11\x44\x45\x34\x82\x76\xcc\xf7\x30\x3b\xa3\x31\xca\x21\xb7\x92\x24\xcc\x91\x5b\xe8\x92\x0c\x69\x4a\xfa\x4e\xf2\x55\x81\x40\xd1\x4c\x62\x62\x02\x33\xc2\x2d\x1f\xe1\x3f\x3a\xd8\xbb\xa8\xd9\xcc\x20\x10\x25\x5b\xa2\x6a\x05\x54\x92\xd8\x3d\xe9\x54\x07\x69\x8a\x00\x7a\x8a\x99\x21\x9a\x75\x0e\xd0\x0c\x06\x89\x06\x30\xd5\xf9\x76\x33\x44\x95\x66\xa0\x92\xd2\xc3\x2d\xe0\xfc\x70\xac\x58\xed\x45\x35\xb7\x8e\x24\xd9\x32\x0b\xd3\x53\x83\xda\xe6\x2d\x14\x54\x6b\x3d\xc6\x94\x51\x83\x0b\x64\x4f\x60\xbe\xa2\x6c\x1d\xcf\xc4\xab\x5c\x9c\x1d\x66\xa3\xe0\xea\x7c\x36\xa7\xc6\x82\xa4\x96\x73\xb3\xc3\x4f\x63\xea\x8d\xae\x24\x82\x85\x49\x52\x9c\xf4\x9a\xe2\xef\xa8\x39\x19\x51\x45\x8d\x52\xb9\xce\x6f\xe0\xd5\x52\x69\x80\x57\x5c\x73\x02\xaf\x83\xc9\x05\xac\x72\x50\xd9\xb4\xb3\x32\x96\x5b\x81\x2d\xe6\xc0\x1d\x35\x0b\x9b\x61\xf0\x81\x99\x4a\x06\x09\x32\x63\x1c\x35\x27\x9b\x39\xd7\x18\x9f\xe8\x0e\x4c\xf5\xb5\x1e\xb2\x22\x01\x88\xba\x75\x3e\xda\x0d\xf9\xf3\xad\x2f\x39\x22\x7d\x3c\xda\x86\x8c\x7d\x58\x8c\x1d\x39\x92\x7c\x09\x33\x70\xb6\xa5\x21\xe9\x2e\x34\xe9\x42\xe4\x6e\x91\x6e\x76\x78\x9b\x74\xfb\xfa\x6f\x97\x6e\x76\x98\x10\x64\x6c\x37\xba\x70\x09\x71\x20\xbd\x15\x7b\x4d\x3c\x88\x31\x31\x0f\xcf\x7b\x45\x40\xdf\x25\x91\x8a\x96\x47\x85\x24\x77\xe0\xf4\x58\x6e\x94\xee\xa7\x2d\x33\x8a\x96\x27\xa2\xc7\x44\x52\x61\x02\x39\x28\xc0\x76\x4b\xc9\x53\x85\xfa\x73\x1e\x44\x3a\x42\x21\x0b\xa1\x94\x4c\x5f\xda\x7b\x39\x7f\x05\xd3\x6f\x35\xc5\xb4\x58\x8d\xe6\x38\xed\x38\x0e\xa3\xba\xc8\xce\x0d\xd2\x65\xa3\x24\xa1\x91\x04\xc6\x51\x91\xcc\x6c\xb6\x7c\xb1\xb4\x03\x79\x26\x40\xad\x2e\xd0\x60\x30\xd9\xef\x75\xfe\x3d\xcc\xd2\xc4\xdd\x23\x94\xe0\x48\x42\x4a\x99\x08\xb0\xae\x1b\x74\xbe\x52\x47\xae\xf6\xe0\xe8\x9a\xa2\xc0\xfa\x0e\xf4\x06\xf9\xa6\x8d\xe7\xa6\xff\x74\x49\xfe\xe4\xdd\xea\x59\x22\xc9\x77\x5e\x79\xbd\x6a\xc8\x49\xba\x09\x33\xfe\x08\xe7\x62\x4d\x94\x45\x26\x5b\x4b\x6f\xe6\xaf\x37\xb3\xf5\xd3\x6c\xbe\x7d\x84\x3d\x51\x7c\xae\x9b\x22\x77\xb9\x6d\x20\x81\x7e\xaa\xcc\x49\x84\xe2\x97\x90\x3d\x86\x0d\x56\x3a\xa9\xf6\x0e\x86\x91\xec\x15\x29\x57\xd6\x2e\x79\xcf\xc2\xac\xb0\x44\xd7\x30\x43\xfc\xe5\x30\x5b\x06\x48\x9d\x39\x36\x0d\xb6\xcd\x61\x85\x6e\x25\x73\x58\x98\xf1\xff\x56\x34\x6f\x36\x00\xc7\x54\xca\xd0\x52\x1d\x9b\x15\xac\x43\x36\xdc\x33\x3a\xe6\xf1\x75\x4c\x64\xf4\x6e\x1d\xa4\x62\xae\xc2\xc7\x9a\x32\x63\x54\x2d\x53\xd7\x07\x3f\x6a\xa6\xc1\x40\xac\xaf\xbb\x33\x54\xbc\xc0\x2a\xca\x1d\xa1\x4c\xf7\xbf\xf5\xd7\x49\x1a\x87\x4d\x51\x99\xba\x54\xc2\xb3\x1b\x40\x62\x58\x36\x37\x28\xe3\x48\x16\x13\x54\xc7\x55\x4a\x6f\xdf\x78\x03\x93\x02\x1a\x43\x97\x91\xc4\xb9\x06\x66\xc8\xbb\x2e\x9e\x83\xb9\xe8\xeb\xef\xcc\x95\xed\x86\x65\x2c\x0b\x3c\x05\xe6\x9b\x58\x11\x2e\x75\x11\x58\xea\x12\xe4\x9a\x59\xb2\x9b\x34\x95\xf6\x0d\xd6\x2a\x3d\xdd\xc9\x23\xd2\xab\xab\x7a\x84\xff\x67\xf8\xc4\x20\xf0\x66\xab\xc5\x34\x9f\xc8\x5a\xa8\xdb\xdc\xee\x85\xd5\x64\x9a\xa0\x24\x93\xc7\x80\x14\x15\xe6\x7d\x6c\x62\xc9\xe4\x1d\x95\xd7\x63\xd8\x1b\xe3\x21\x25\x50\xab\xd6\x09\xdd\x0c\xfb\x48\x86\xea\xbf\x35\x7d\x04\xfc\xa4\x06\x6b\xf4\x95\x16\xac\x83\xa0\xe3\x7c\xa6\x85\xc2\xb4\x7a\xa3\x7c\xe7\x78\x6a\xf6\x6a\x13\x7c\x28\xab\x72\x8b\x17\x35\x56\xbd\xc0\xea\xac\x39\xa9\x8e\xef\xb7\x79\xd2\x41\x34\xa6\x4f\xd0\xb0\xd2\x8e\x66\x73\xb2\x37\x1d\x81\xc8\xd0\x75\xb2\xe7\x50\xf1\x4c\xf4\xa8\xb6\xea\x76\x83\x34\x9e\x8d\x09\x5e\x75\x0c\x9a\x29\x7e\x75\x94\x31\xd4\xe9\xdf\x60\xe5\x88\xde\x2b\x93\xdb\xe1\x65\x09\x72\xc5\x44\x55\xbc\x38\xfd\xd2\x84\x5c\xd4\x41\xd2\x99\x6d\x8c\x4e\x0d\xaa\x9e\xc9\x0f\x92\x8a\xbc\x66\x45\x12\x03\xe2\xf8\x14\x36\x7c\x5b\xf2\x7a\x89\x95\xe5\x0b\x5d\x86\xdb\x30\xc0\x99\x70\x4a\x2b\x8c\xbf\xf1\xc2\x7f\x9c\xeb\x26\xdd\xbf\xba\x3c\xd7\x38\x2b\x86\x17\x21\xa4\x56\xd1\x15\xa4\xd1\xec\x99\xce\x77\xdd\x5f\x04\x63\x98\x57\x3f\x6b\x4b\xcb\x1f\xc2\x91\x33\xc3\x82\x86\x11\xa1\xf0\xfd\xc5\x90\xe0\x5c\xac\x29\xac\x03\x5e\x7a\xa2\x66\x15\xfa\x7d\x74\x41\x3a\x81\x67\x4c\xce\x0d\x77\xb3\x69\xb1\xcb\x02\xad\xac\x71\x75\xab\x72\x10\x6d\xb6\x42\xa5\x2f\x79\xa9\xf8\x65\xe3\xfe\x3b\x75\xa4\xb5\x07\x8c\x7e\xb2\xeb\x89\xba\x09\x9b\x34\x7e\x1e\xb1\x62\x17\x80\x87\x3e\x50\xdb\x30\x61\x29\xa4\x8f\x61\xdd\x05\x35\x8a\x3a\x77\x33\x14\xd2\xed\xd7\x2b\x59\xa6\x07\x39\x50\x2f\x52\x14\x6e\xa8\xe2\x7a\x24\xdd\x7d\x43\x86\x34\x7c\x39\x18\xdf\x82\x70\xae\x51\xc5\x63\x37\x32\x49\x21\x77\x1e\x01\xa5\xb5\x5e\xa8\x15\x68\x7b\x43\xc4\x4f\x95\xb7\x6d\x62\x19\xdc\x55\xa2\x44\x38\x64\xc7\x88\xb8\x85\x64\x26\xed\x3b\x01\xde\x76\xfb\x4e\xd4\x77\x44\x10\xdc\x9b\xe2\x47\xba\xad\x0f\xbc\x59\x0e\xbf\x9f\x0b\xa0\xca\x5d\x72\x93\xf6\x8a\x60\x54\xfd\xae\x09\x8c\x8d\xff\xba\xf0\x2d\x11\xf3\xf5\xea\xda\x7f\x58\xe1\xaf\xd9\x47\x8a\xae\xf2\xe3\x9c\x6f\x9d\x1d\x06\xdd\x51\xd0\x0b\xb8\x21\xe8\x1a\xca\x4c\xf1\x2b\xa1\x7a\x74\x4e\x48\x3f\x2e\x15\xd8\x30\x57\x2e\xfa\x8e\x4e\x4d\xdd\x77\x0d\x3f\x30\x62\xdf\x25\xca\x2e\x36\x94\x23\x31\x5a\x28\x61\x91\x6f\x28\x34\xe1\x5a\x3f\x25\xea\x4e\x58\xcf\x5b\x07\x71\x2c\xe1\x12\x84\xd6\xa1\x1f\x0e\x88\x04\x91\x31\x89\x75\xf8\x24\xc9\x75\x28\x3b\x09\xbe\xa1\xd5\xe3\x65\x3d\xb2\xca\x8e\x57\xa9\x8f\xc5\xcb\x4f\x72\x2b\xaa\xa2\x4c\x8a\x17\xec\x0a\x0e\x87\x0c\x0d\xf6\x75\x10\xc7\x5a\x0b\x56\x71\xb4\x1f\xab\xf8\xbc\x17\xbb\x43\x36\x76\x8a\x6c\xcf\x91\xb2\x41\x8b\x5f\xf6\x22\xe2\x19\xa3\x2b\x9b\x60\x13\x6d\x97\x0a\xb6\x75\xbc\x59\x6d\x12\x05\x9b\xa8\x2d\x3d\x89\x61\x7d\xf1\x17\xcb\x99\xbf\x0c\x66\xfe\xca\x03\xda\xaa\xe8\x4c\x8f\xd8\xa2\x35\x13\x7a\x60\x82\xde\x8c\xad\x04\x68\x8e\xd0\x9a\x29\xba\x43\xbb\x59\xed\xfb\xf5\x1a\x6d\xd6\x56\xdd\x81\x7b\x94\x1e\x5b\x1a\xd8\x8b\x4e\x2f\xaf\x87\xd7\x50\x05\x2c\x63\x34\x27\xf0\xb7\xdb\xc5\x56\xc1\xe5\xa3\x0d\x5a\x2c\x25\x5c\x92\xde\x30\xf4\x93\x96\x34\x95\x16\xaa\x1a\xc3\x50\x5a\xf4\x65\x74\xab\xa7\x68\xcb\xa8\x2a\x90\xae\xf0\x56\x4c\xd1\x14\xda\xad\x6a\x5f\xc7\x9b\xe5\xc2\xee\x5e\x81\x5e\x4c\x4f\xfb\x62\x80\xd8\x26\x0c\x22\x4d\xb0\xa4\xb0\x47\x31\x46\x43\xfc\xc5\x76\xa9\x8d\x53\xdf\xdf\x84\xdb\xa8\x47\x24\xaa\x07\x41\x3c\x62\x4a\xbe\x98\xf9\xeb\x60\xe6\x6f\x97\x72\xb3\x14\xcd\x20\xd8\x2c\x6a\x31\xae\x9d\x13\x74\x62\x04\x3c\xa0\x10\x94\xf3\x49\xda\x40\xba\x50\x65\xdc\xdb\x78\x1b\xbb\xcf\x81\xfa\x8d\x9d\x95\xbb\x74\xa8\x7d\x70\xcf\x67\xec\x7b\x1b\x85\x20\x2d\x94\xb0\xc8\x4a\x01\xe3\x42\x5e\xb8\xf5\x3c\x05\x57\xb2\x78\x42\x9e\x27\xe1\x12\xf5\x82\xa3\x1f\xa1\x1a\xab\xd5\xcc\x7f\x5a\xcc\x36\x5a\x0b\x15\xe5\xe0\x28\x2d\xfa\x31\xba\xd5\x13\x54\x64\x5c\x15\x40\x4b\xba\x56\xc0\x8a\x02\xf7\x35\xed\x56\xa5\x05\xf1\xfa\x69\xe5\xd9\xcd\x06\xd0\x8b\xf4\xb8\xa1\x5d\x2f\xe9\xc2\xa1\x2a\x5a\xb6\x9a\xd8\x23\x19\x63\x3a\xe2\x6d\xb0\x58\x2c\x14\x54\x51\x12\xf8\x0b\x4f\x44\x25\x2a\x09\x43\x3e\x69\x45\x4f\x6e\x9d\xa2\x22\x0c\xa1\x45\x43\xc6\x36\x78\x82\x82\x8c\xaa\x01\xe8\x07\x6f\xc1\x14\x3b\x42\xfb\x53\xed\xe4\xc0\xdf\x07\x89\x5d\x3d\xf4\x0e\x24\x47\xea\x06\x8c\x88\x74\xdb\x9c\x54\x28\xe0\x18\x65\x42\x02\xb4\x46\x2a\xa6\x24\x44\x1e\x5a\x09\x98\x44\xdd\xa0\xa8\x47\xa8\xc6\x72\x3b\x0b\x96\x4f\xb3\x40\x8c\xac\x28\x36\x59\x37\x28\x42\x9b\xf1\x18\xd7\xda\x09\x9a\x31\xa6\x02\xa0\x18\x8c\xfb\x49\x66\x83\x74\xa5\x66\xa2\x93\xa7\x64\xc0\xbf\x40\xbd\x37\x7c\x40\x72\xb1\x5c\x84\x4b\x55\x0d\x69\x61\x8f\x62\x54\x44\xba\x08\x36\x81\xe6\x17\x93\xc0\x0f\x96\x3d\x22\xd9\x64\x54\xdf\x46\x68\xc5\x2a\x98\xad\xb6\xb3\xf5\x52\x6e\x94\x66\x2d\xaa\x6f\x36\x85\x18\xd7\xca\x49\x96\x62\x10\x1e\xb4\x13\x98\xf3\x49\xd1\x06\xe9\x40\x2d\x4c\xf2\x43\xdf\x6e\x25\xf4\x5e\xe3\x97\x3f\x2b\x0b\x22\x7c\x11\xc0\x7a\x08\x00\x3e\xab\x65\x5c\x37\x50\x48\x8d\x5b\x35\x19\x58\x8b\x50\x70\x8a\x8a\xa4\x92\xbb\x69\x15\x45\xc5\x2f\xeb\x97\x4a\xa2\x53\xb5\xf1\xbd\x08\x77\xcd\x04\x95\x9b\x56\x15\xd0\x3e\xad\x89\xd3\x96\x5a\x8c\x02\x9a\xba\xd4\xc2\xf9\xd0\x96\x5c\xf8\xd2\xc2\x5b\x75\x51\x5c\x8d\xd0\x88\x8d\xd1\xc6\xc1\x35\x0e\x0d\x2b\xa4\x8f\x6f\x5e\xa7\xd1\xa9\xc0\x5a\x09\xac\xdb\x8c\xef\x51\x53\x37\xdd\xa0\x99\x6f\x58\xc4\x01\x9a\x3a\x45\x3b\x2d\x02\x9b\xbe\x98\xd3\xf1\x22\x2f\xea\xf0\x85\x8c\xb7\x6a\xa7\xb8\xf6\xa1\x90\x1a\xe5\x67\x87\xd6\x53\x14\x9c\xa0\x66\xbe\x65\x25\x48\xc5\x6f\xd0\x49\x75\x65\x68\x7c\x2f\xc2\x5d\x73\x8b\x3e\xde\xba\x4c\xa4\x35\x71\x8a\x2e\x5a\x04\x34\x75\xb9\x88\xf3\x21\x2e\x1b\xf1\x85\x93\xb7\xaa\xa1\xb8\xd6\x22\xd2\x19\xb5\xb6\x34\xb4\x78\x23\x22\x84\x14\xf0\x0d\x6b\x4d\x12\x6a\x58\xf7\xe4\xb5\xa7\xf1\xfd\x06\x74\xc6\x0d\x5a\x77\xdb\x42\x94\xdc\xac\x49\x21\xa2\x59\x18\x93\x17\xa4\x38\x17\xca\xc2\x14\x5f\x8c\x79\xab\xce\x89\xeb\x37\x0a\xa9\x31\x6a\x37\xb8\x26\xa4\xe0\x84\x34\xef\x4d\xab\x59\x2a\x7e\x58\xfd\xb4\xd5\xad\xf1\xbd\x08\x77\xcd\x0d\x4a\x78\xf3\x52\x97\xd6\xc4\x29\xaa\x68\x11\xd0\xd4\x25\x2f\xce\x87\xbc\xf4\xc5\xd7\x7c\xde\xaa\x88\xe2\x32\x91\x4c\x69\x8c\x1e\x0e\xae\x3c\xc9\x28\x21\x35\x7c\xcb\x7a\x99\x82\x1d\x56\x42\x75\xfd\x6c\x7c\x07\x82\xbd\x72\x83\x0a\xde\xba\x98\xa6\x36\x6f\x8a\x02\x5a\x24\x33\x75\x51\x8d\xb3\x21\x2d\xae\xf1\x85\xa5\x37\x1b\x42\x61\x2d\x4a\x22\x24\xab\x1f\xcf\xaa\x35\x7d\x81\x4b\x42\x0a\x29\xe0\x9b\x16\xe5\x64\xec\xb0\x02\x2a\x8b\x74\xe3\x3b\x10\xea\x95\x1b\xd4\xef\xc6\x15\x3b\xa5\x69\xb0\xf2\xdd\x22\x97\xe9\x8b\x77\xfd\x40\xe8\x17\xf1\xf8\x42\xd6\x5b\x15\x50\x5c\xfb\x12\xe9\x8c\x31\x7f\x83\x8b\x69\x22\x42\xd8\xf8\xdd\xb8\xf2\x27\x21\x36\xd9\x3d\x71\x25\x70\x7c\xaf\x01\x5d\x71\x93\xcd\xbb\x65\x59\x50\x6e\xd6\x14\x7b\x67\x11\xc5\xc4\xe5\xc1\x2c\x3d\x7d\xbb\xa8\xdb\xfc\xa6\xae\x6e\x61\x24\xb2\x06\x79\xde\x6a\x1d\x2d\x9e\xd5\xad\x6b\xe7\x53\x82\x2a\xdc\xe6\x31\xd9\x47\x6c\xd4\xe4\xef\x0c\xa7\x5e\xad\xe0\x8a\x62\xa7\xf4\x7b\xc4\x08\x22\xf5\x13\xc3\x49\x57\x23\x71\x05\xa8\xcf\x3e\x40\xd2\x7f\x90\x3a\x87\x3b\xe6\x38\xe8\x69\xd4\xb9\x40\xa3\x4f\x68\x73\x97\x3c\x19\x18\x25\xd9\xe1\x69\x4c\x01\x26\xc0\xfc\x28\x80\x8b\xe7\xc6\xc8\x09\x72\xb2\xb1\xf7\xd7\xe6\xb5\x44\x5f\xa2\x73\xd3\x14\xa7\xaf\x3d\xf4\x4c\x78\x59\xa1\x1a\x35\x86\x77\xf5\x39\xca\x53\xf1\xa5\xb8\xad\x7e\xbe\x0f\x13\xd4\xed\x43\xf4\xc4\xad\x98\xac\x90\xee\xa3\xc4\xed\x0e\x2b\x0a\x4e\xc6\xd8\x45\x48\x10\x15\x17\x59\x16\x96\x35\x92\xce\xe4\xf5\xc5\x14\x5e\x3e\xc3\xd3\x54\x86\xd7\x2c\xd7\x5a\xf1\x72\x25\xe9\x17\x87\xa0\xa8\x34\x3b\x5a\x78\x76\xa5\x6f\x83\x66\xf2\xf2\xba\x34\x71\xbb\x63\x9a\x24\xe8\x24\xb6\x96\xc2\x38\xf3\x05\xdb\x34\x7a\xed\x4c\xc6\x8c\x3c\x9d\x4b\x1d\xf1\x55\x35\x2b\xbb\x5d\xb8\x6f\x50\x65\xdb\x22\xef\xf5\xdc\x88\x9b\xaf\xe7\xc1\x6a\xa5\xef\x3f\x66\xa5\x7c\x4f\xf4\xc3\x83\x98\x82\x7e\xbe\x40\x39\xdd\x97\xdb\x69\x21\xdd\xca\xdc\x95\x43\xa9\x85\xba\x84\x45\xec\x37\xa5\x0e\x56\xd1\x9b\x87\xf2\xb2\x79\xe5\x8d\x54\xf6\x8e\x77\xb0\x39\x3a\x9d\x6d\xa7\x29\x69\x85\xee\x50\xa5\xef\x79\x9e\x7c\xae\x72\x9f\x15\x61\xb3\xc3\x60\xcf\xc2\x35\x3b\x9e\x90\x8c\x89\x59\x02\xde\x85\xbb\x39\xcb\xc5\xe2\x39\x6a\xaa\xa7\x67\x39\xb6\x10\x76\x58\x13\xfc\x59\x5a\x37\x2c\xfd\x9f\x96\x29\x0f\xf6\x10\x83\xf9\xf3\xc4\xbc\xaf\xfe\x4a\x3f\xab\x49\x33\x43\x50\x95\x72\x94\x5e\xb3\x9c\x15\x60\x4d\x04\x6a\xfe\x0e\xaa\xe7\xdd\xa0\x71\xba\xba\x0e\xaa\x1e\xd4\xcc\x51\x2a\x98\xa4\xdf\xd3\x04\x55\x17\xa5\xbd\x9d\xda\xa8\x76\xc0\x7e\xb1\x43\x87\x36\x6d\x90\x25\x61\xab\xe2\x41\x7c\xea\x42\xe2\x0c\x85\xd5\x2e\x2a\x9a\xa3\xb6\xdd\xdf\xa8\x9a\xec\x5c\x18\xb4\xfb\xbf\x57\x45\x1c\x7e\x08\x39\x11\x25\x26\xf9\x2e\x77\xb9\x50\xde\x86\xb0\xf6\xb7\x7e\xa4\x85\x10\xa6\x51\xc0\x26\x41\x12\xc2\x2e\x56\x93\xc9\xb0\x9d\xe7\xc2\xf8\x19\x49\x84\x7f\x98\x94\x89\xf4\x11\x84\x4c\xe6\xa6\x8f\x32\xd2\x70\x83\xfc\x52\x0f\x71\x44\x61\x22\x8c\x27\x2a\x6e\x25\x12\x99\x0f\x24\x9b\x53\x8e\x9e\x33\x16\x75\xb1\x0a\x81\xc9\x4c\x88\x51\xf8\x90\xb4\xe4\xdb\xa1\xd9\x1f\xc9\x50\x57\x0f\xe5\x08\xc5\xa6\x33\x59\x3a\x29\x21\x28\x22\x2f\x58\x92\x29\x8d\xbe\x70\x44\xcd\x97\x8e\xa8\xd1\x5f\x46\xd4\x54\x09\x55\x02\x4c\x35\xb9\x4b\x08\x8c\xd5\xa5\xe9\x01\x84\x7e\xe8\xbd\x10\xd8\xf6\xe4\x75\xac\x06\x64\x02\x0e\x90\x59\x07\x3f\xfe\xa8\x74\x61\x5f\xa8\x49\xd8\xe9\x1f\xc1\x5a\xc2\x2b\xb3\x76\x80\x44\x81\xb7\x03\x18\x60\x36\x8c\x30\x72\x36\x2c\x96\x33\xa9\x6c\x69\x67\x34\x45\x91\x45\x61\x75\x8f\x1c\x57\xf2\x61\xb1\xba\x09\xab\x46\x3b\x2b\x46\xde\x93\x57\x12\x79\xf3\x61\x41\x45\xa0\x78\x2a\xb9\x23\xb7\x7b\xb9\xf1\x31\xcd\x12\x3a\xb9\xdc\x65\xa1\x5c\xa0\xfa\xa2\xc7\x8b\xec\xdb\x3d\x0d\xb1\x80\x53\xf5\x55\x66\xc8\x89\xc4\x9b\xa2\xa4\x6e\xb8\x63\x43\x76\xbc\xca\x4b\x8d\x72\x4f\x48\xef\x07\x49\xf5\x55\x4f\xac\x41\x8b\x1c\xe1\x66\x9a\x18\x92\xde\xa9\xfc\x30\x69\xf5\x31\x20\x0c\x30\x42\x66\xd4\x74\x0d\x88\x88\x61\xb3\x75\xbf\xda\x4d\xaa\x3d\x18\x85\x42\x5d\x7f\xb8\x8f\xf0\x18\x69\x9b\x08\x75\x45\xbc\x59\x4a\x3f\xaa\xad\x70\xeb\x32\x4b\x1b\x25\x79\xdc\x7c\xb5\x0e\xa4\xc4\xa9\x34\xcc\x63\xa5\x36\x44\x86\xa8\x4e\x9b\xb3\x1b\xaa\xf3\xa9\xfc\x48\x36\x95\xf4\xae\x2c\x18\xdd\xac\x94\x75\x02\xb6\x16\x61\xa5\x99\x1d\x46\xd2\x84\x48\x6a\x14\x3b\xaf\xdf\x99\xbe\x24\xad\x50\x4c\xfc\x6f\x5c\x64\xe7\xfc\xf4\x0c\x97\x2a\x07\x70\xa9\xad\x14\xcf\xdf\xf6\x76\x72\xca\x19\x5c\x88\x37\x67\x84\x9b\xb8\xa8\xcb\x1d\x80\x3f\x36\xba\x9b\x9f\x46\xb8\xad\x9f\x46\xb8\x2d\x15\x46\x76\x5b\x38\xe0\xc7\x5e\x4b\x3d\x07\x6d\x8a\x1e\x86\x8d\x8e\xc5\xde\xa8\x91\x88\xc5\x5e\x5c\x6c\x46\x60\xa4\x35\x55\xc8\xd9\x6c\xc4\xa0\x49\xd0\xcd\x94\x91\xd0\xdd\xcc\x33\x88\xf6\x46\x3b\x7d\x03\x2e\x83\xc1\xbe\x9f\x44\xde\xc5\x76\x03\x82\xfa\x35\x09\x9b\x90\xb5\x82\x2d\x22\xd6\x5f\x09\x66\x47\x58\x24\x24\x79\x04\xa2\xa2\xfd\x3a\x1b\x07\x8f\xd1\x17\x36\x60\xc1\x4b\x4d\xa5\x63\xa8\x4a\x49\x02\x2b\x4b\x64\x4d\x06\xdb\x42\xb6\xec\xe2\x3d\x3e\x83\x07\x97\xc5\x68\xd0\x3e\xa3\x1a\x93\xdf\xa0\x6e\x2a\xd4\xc4\x47\xc9\xc0\xf2\x32\xd1\xf2\x09\x54\x95\x44\x1a\x3a\x0f\xdd\x9c\xa2\x9f\x5f\xf9\xd2\xfc\xaa\xfb\xc5\x28\xa8\x37\x5f\x7a\x16\x7a\xdd\x74\xc6\x0c\xc1\x66\x47\x66\x00\x79\x9e\xb6\xb0\x50\x9b\x0d\x65\x34\x16\xb3\x22\xbc\x39\xa7\x84\xad\xd9\xc3\xa6\x08\xe0\x75\x72\xad\x5b\xdd\xc3\x88\x5e\x82\xd6\x0b\xb4\x6a\x17\x43\x3e\x06\x7b\x26\x7c\x6d\x4d\xca\x7e\xe9\x88\x9e\xa0\x62\xe0\x82\xa9\x91\xf7\x8a\x00\xed\x19\xce\x97\x7e\x4b\x46\x74\x9d\xcc\x84\x1c\xe9\x83\x39\xd1\x01\xc6\xa1\x44\xe0\xb7\xa4\xfa\x1e\x60\xdc\xf6\x61\x6c\x30\xd9\x37\xc1\x07\x1b\x69\x3b\x1c\xb3\xc8\xe2\xaa\xf5\xe0\x40\x1c\x33\xec\xa6\x0d\x32\x2d\xec\x50\x63\x82\xb1\x38\x46\x4e\xbc\x0d\xe8\x46\x52\x55\xc1\x04\x67\x37\xa6\xc6\xbd\xe6\x91\xc3\x3d\x7f\x91\x96\xf8\x87\x05\x2b\xaf\x1b\x8c\x30\xa8\x63\xc5\x32\x4d\x05\xc6\x57\x51\xba\x72\x92\xbc\xa6\xb1\xaa\x05\xa9\xf7\x5a\x3a\x11\xa5\xf0\xe3\x98\x3e\xbf\x88\x9f\x5e\x14\x35\xb0\x2f\xf4\x8e\x88\x7a\x7a\xd3\xe3\x81\x6b\xdc\xf0\xfd\x05\xfa\x47\x55\x08\x8e\x4c\xde\x80\xd5\x46\x08\x16\x0a\x74\xfa\x97\x7a\x8c\xd3\xbf\xb3\x85\x37\xae\x12\x8b\x1b\xd8\xd2\x3b\xf5\x0e\xe6\xe1\x22\x67\xfa\x87\x5a\x7e\x97\xc1\xd3\x2f\x6a\xab\x33\xe2\x49\x56\x58\x28\x1f\x6d\x7b\x4d\x4b\xa5\x53\x1a\xcb\xc8\x1b\xc4\x3f\xc0\x33\xa8\x16\xf6\x3a\xec\x5b\xc6\xc8\x16\x4e\x63\x6b\x1a\x43\xba\xe6\x2a\xd9\xdb\xde\xfc\x05\x29\x4f\x4f\x42\x5c\xa8\x2d\x63\xc9\x9f\xc2\xa8\x9e\xfa\x62\x5a\x62\x29\x83\x28\x30\x89\xe3\xac\xbb\x7e\x77\x51\x98\x07\x57\xde\x91\xf0\x04\xd9\xf2\xa4\x8e\x38\x73\x67\xc0\x4d\x7a\xdd\x96\x81\x55\xdd\xfe\x85\x03\x5c\x4c\x68\x36\x98\x07\x0c\xa4\x47\x95\xe2\xd6\xa6\x44\x8b\x64\x63\x6c\x0a\xff\x40\x3a\x25\x9f\x6c\xf7\xcd\x7b\x1a\x46\x20\xf1\x2b\xdf\xd5\x35\x9c\xa3\x4f\xda\x21\xc2\x37\x73\xd1\x3d\x22\xe0\xb7\x76\xfc\x9e\x6b\x22\xd1\x43\x7d\xae\xff\x4e\xe9\xf0\xa0\x2b\xec\xc5\xd2\x0a\x95\x28\xc4\xc0\xec\x49\x7c\xd7\x35\x97\x4e\x9c\x1c\x7d\xfe\x44\x3c\xe7\xca\xfb\xe8\xac\xbc\x8f\x7d\xbf\xb1\x50\xdc\x92\xec\x10\x9e\x50\x0d\xd7\x1f\x37\x94\xb4\x6d\xaf\xe7\x2a\xfb\xf4\x90\x84\x4d\xb8\x23\xbf\x3f\xd7\xdf\x0f\x3f\xb6\x79\xf6\x1c\x1f\xc3\xaa\x46\xcd\x97\x73\xb3\xdf\xce\x3e\x2e\x7e\xae\xbf\x1f\x9c\x36\xcf\x4e\xf5\x97\x1f\x8e\x4d\x53\xee\x3e\x7f\x7e\x79\x79\x99\xbf\x2c\xe6\x45\x75\xf8\x1c\x78\x9e\x87\x6b\xfe\xe0\x7c\x4f\xd1\xcb\x9f\x8b\xf6\xcb\x0f\x78\xf4\x6c\x9d\xed\x0f\x1f\x17\x7f\xf9\xb8\xf8\xb9\x0c\x9b\xa3\xb3\x4f\xb3\xec\xcb\x0f\x1f\x83\xc5\x7e\xbf\xff\xc1\x49\xbe\xfc\xf0\xcb\x7a\xbe\x5a\x2f\xe7\x9b\x55\xe6\x2e\xe6\xab\x27\x67\x31\x5f\xfb\x81\xeb\xcf\x57\x8b\x2d\xfe\xef\xea\x6f\x9e\xb3\x9c\x07\x6b\x27\x98\x3f\x6d\x96\xce\x66\x1e\xac\x9c\xad\x13\xcc\xfd\xa7\xc5\x3f\x7f\xf8\x4c\x11\x63\xaa\x1f\x17\x7f\x79\x78\x1c\xdb\x45\xd8\x2c\x35\xa8\xca\xd3\x53\xd8\xd8\x06\xaa\xf9\x70\xef\x6f\xd9\x83\x4b\x67\x29\xf6\x60\xdd\x54\xc5\x37\x24\xf7\xa1\xe7\x04\xc7\xa5\xb9\x3b\xc8\xa4\x6e\xb4\xba\x89\xba\x6a\xaa\xf9\x2f\xa6\x68\xee\xd2\x71\x97\x82\xaa\xc5\x69\x15\x67\xc8\xa9\xbe\xfc\xb0\xf8\x41\x56\x39\xb3\xca\x50\xee\x6b\xb7\x6e\x42\xdc\xac\x09\x0b\x59\xe3\xbe\xe5\x18\x29\x69\x69\x59\x95\x5d\x62\xca\xe8\x1f\xa8\xfd\xa3\x01\x1b\x8f\xfa\xa4\x5c\xf0\xa6\x7b\x8f\xba\xfb\x86\x3d\xef\xe3\xb3\xf9\xaa\x4e\x2d\x61\xa8\x3f\x67\x0b\x55\xf2\x82\x95\x7d\x05\x0a\xce\x7e\x2a\xec\x8a\xc2\x9e\xd2\x79\xdf\x11\xb6\x02\x6d\xd4\x62\xb1\xa0\xe3\x2b\x70\xbc\xbf\x91\x31\xf6\xcf\xdc\x73\xb0\x49\x5a\x1c\x97\xba\xf9\x71\x3a\x2f\xe1\x54\x74\xe7\x29\xed\x05\x83\x5f\xd8\x96\xad\xe3\x7b\xe5\xd4\xfb\x7a\xb9\x1f\x0c\xcb\x12\x85\x55\x78\x8a\x91\xe0\x06\xd5\x42\xe5\xb7\x22\x7e\x68\x0f\xb8\x76\x89\x2e\x58\x67\xf2\x55\xac\x12\x8e\xfe\x8e\x36\xbe\x9d\x8f\x2c\x80\xc3\x89\x4d\x15\xf2\x63\xf7\x88\xa9\x61\x0f\xab\x2e\x5e\x4d\xac\x07\xa5\x14\xc8\xad\x73\xeb\xc5\x80\xcf\x13\xee\x14\xed\x27\xd0\x9b\xd5\x47\x29\x2b\xbc\x25\x7e\xbf\x71\x34\x6a\xdf\x0d\xb4\x84\xf2\x17\x61\xf3\xed\x92\x06\xf7\xd3\x90\xef\x3c\x20\x94\x17\x12\xd6\xcb\xb1\xb6\x92\xbd\x5f\x3d\x65\xe1\xd1\xe1\xa1\x85\xda\x6a\x38\x2f\xa1\x81\x63\x4c\xef\x99\xdf\xd1\xa9\x6c\x45\x5e\x4d\x31\x5f\xa3\xcc\xd5\xef\x18\x9b\xf6\x37\x5e\x8f\x5e\x84\x87\x2e\x2e\xc8\xc2\xd3\xe1\x13\x3a\x3d\xca\x1b\x6f\xbb\x6d\xc1\x3f\x1f\x8b\xa2\x46\xd8\x0a\xa2\xf9\x7c\xfe\x00\xe3\xe0\x97\x1f\xc0\xe2\x20\x1f\xe0\xfb\x95\x8d\x67\xa6\x92\xe4\x99\x4b\x66\xad\x4c\x05\xee\x2d\xa7\xb7\x7e\xc6\xc0\xda\x48\xa9\xb1\x8d\xe8\x03\x9d\xc9\x7b\xa4\xeb\xc7\x3f\x57\xc5\x4b\x8d\x1e\xae\xf3\x53\xf8\xfd\x1e\xdb\xe6\xe4\xbc\xe9\xc0\x6d\xc5\xd2\xbe\x77\x42\x96\x1e\x56\xb2\xee\x77\x25\x5a\xc2\x41\xf9\x0a\x45\xf7\xdb\x96\x4f\x9b\x03\xcd\x4d\xa7\x7f\x30\x40\x13\x46\xb5\xfc\xa1\x5d\xec\xf8\x24\x49\x7a\x30\x87\x3c\x91\x0d\xd9\x72\xdb\xe8\x7a\x91\x0c\x46\x1a\x66\x4d\x66\x6e\x58\x7e\x95\xbf\xa0\x68\x8b\xec\x7c\xdc\xe8\xd4\xc4\xbe\x51\xde\xd0\x5e\x92\xdd\x28\x55\x36\xa7\xfb\x0b\x34\xd5\xd2\x79\xb7\x9e\xf6\xd2\xfb\x92\xec\x88\xee\xe9\x41\xfc\xcf\xe5\xed\xdd\x13\x2e\xdc\x4f\x12\x2a\x44\x87\x3a\xf9\x1e\xb5\xf1\x0c\x04\x33\x07\xd3\xf7\xa6\x60\xdc\x65\x9a\x65\xba\xfc\x21\xd1\x29\x90\xdd\x6e\x60\xe1\x1d\x3d\x55\xd8\xe1\x1a\xb5\xbe\x84\xa1\x71\x74\x28\xa8\xea\xd0\x57\x7d\xed\xfb\x2a\xc5\x42\xf7\x65\xa5\x38\x7e\xd7\x50\xb9\x65\x85\xf6\xa8\xaa\x50\xc2\x97\xde\x49\x69\x14\xd6\x29\xee\xa4\x1e\x8c\xd8\xde\xef\x68\xe7\x53\x80\x43\x55\xbc\xec\x7c\x88\x62\x13\x46\x7c\x07\xd8\x4f\xe4\x47\x19\x9e\xd4\xa3\x5d\x12\x0c\xd3\x08\x65\x23\xfd\x29\xfc\x1e\x85\xd5\x9b\x36\x5a\x0c\x6f\x0a\x9e\x76\xd5\x04\xdb\xdf\xa6\xed\x73\x23\x9f\x29\xdc\x08\x35\x2f\x08\x9d\x4c\x36\x2f\x0a\xab\x9f\xe6\xb8\x46\x98\x9e\x50\x35\xd3\x8b\xdc\x7d\x76\x4e\xa7\x4c\x05\x7f\x97\xe6\xf1\xb6\xb8\x51\x85\xc3\x5a\x30\x8a\x94\x43\x56\x3f\x80\x63\x56\x3f\x80\x97\x7c\x07\xce\x66\x9a\x0f\xb7\xc8\xac\x09\x26\xb4\x2f\x1b\x70\x31\x18\x70\x9a\x03\x1d\xb9\xb5\xf2\x06\x77\xca\x78\x11\x2c\xd0\xd0\x0d\xf1\x62\x25\xc3\x69\x3a\x76\x9f\x09\xdd\x1d\x2d\x91\x32\xde\x9f\x23\x4b\x13\x14\xe5\x4a\xd0\x71\xb7\x3b\xcc\x69\xb2\x30\x24\xf8\x17\x8c\x0c\xf9\x3d\x64\x67\xc6\x6f\xe4\xe1\xed\x21\x1f\x65\x2b\x6d\x6f\x86\x76\xcb\x08\x74\xfc\xd7\x70\x4c\xca\xea\xfb\x75\xc7\x20\xb0\xa1\x28\x23\x2f\x1d\xa1\x8e\x0c\xd4\x4d\xe3\xc2\x70\x0b\x0c\x9b\x52\xcd\x57\xc2\xba\xf6\x1c\x38\x91\xc7\xd6\x3a\xc4\x13\x79\x7d\x2b\xfb\xd5\x04\xfb\xfa\x32\x16\x96\x23\x5f\xa8\xd5\xcd\xea\x56\x9b\x15\xb9\x50\x8b\x71\x4e\x27\xbe\x64\x1f\x8d\x66\xf6\xc0\x97\xcc\x00\x0e\xa8\xb9\xe5\x26\x2f\x15\xf7\x45\xbf\xe8\x8a\x1d\x83\x03\x0b\xa7\x1e\x15\x51\xc9\x39\xa2\x09\x01\x2c\x44\x55\xbc\xa8\xe6\xa1\x2a\x5e\xec\x78\x8c\x23\x99\x4f\x81\x26\x55\xa7\x7d\x7a\x91\xa6\xaf\xf4\x44\x8b\x1d\x89\xc1\x04\x01\xdf\xf1\x64\x5b\x70\xab\x0a\xc8\x2e\x4e\x94\x99\x50\x60\x61\x5a\x3b\x50\x2e\x18\xf2\x7f\x4b\xf3\xb2\xa8\x9a\xf0\xd4\x48\x26\x5d\x28\x36\x19\xae\x2e\xe0\x62\x86\x6b\xa0\xe7\xb8\x05\x92\x23\x1f\x1d\x1c\x3e\xca\x8b\xad\x2d\x5d\xa8\x62\x13\x19\x3c\xe6\x80\x41\xb7\x59\x6f\x00\xdd\xcf\x13\x4b\x8f\x4b\x2f\x6f\x1e\x74\x9b\xf5\x16\x24\xfc\x9b\x0e\xba\x3c\xb9\xcf\xa0\x93\xf1\x4c\x1e\x74\xd6\xea\x63\x07\x9d\x8a\xe4\x8d\x83\x6e\xb2\x0a\xdc\x34\xe8\x04\xa6\x7f\xbf\x41\x27\x30\x31\x66\xd0\x61\xf0\xb7\x0d\xba\xa7\x27\x1f\xd0\xfd\xec\x60\xe9\x71\xe9\xe5\xcd\x83\xee\xe9\x29\x00\x09\xff\xa6\x83\x2e\x3b\xdc\x67\xd0\xc9\x78\x26\x0f\x3a\x6b\xf5\xb1\x83\x4e\x45\xf2\xc6\x41\x37\x59\x05\x6e\x1a\x74\x02\xd3\xbf\xdf\xa0\x13\x98\x18\x33\xe8\x30\xf8\xdb\x06\x9d\xef\x3f\x3d\x01\xca\xdf\x66\x96\x2e\x97\x5e\xde\x3c\xea\xfc\xc0\xf3\x40\xca\xbf\xe9\xb0\x6b\xb3\xfb\x0c\x3b\x19\xcf\xe4\x61\x67\xad\x3e\x76\xd8\xa9\x48\xde\x38\xec\x26\xeb\xc0\x4d\xc3\x4e\x60\xfa\xf7\x1b\x76\x02\x13\x63\x86\x1d\x06\x9f\x32\xec\xe4\xea\xbf\xa5\x7e\x9b\x25\x38\x79\x08\xcb\xd5\xef\x32\x6a\xde\x32\x64\xde\x3e\x5e\xee\x39\x58\xa6\xf4\xf3\x2d\xc3\xe4\xf7\x1f\x23\x53\x06\xc8\xa4\xd1\xc1\xab\x66\x74\xc3\x85\xb4\x10\x4a\x17\xef\xc5\xe4\x4d\x4f\x8f\xb6\x0a\xca\x8a\x10\x04\x21\xe6\xdb\x19\x85\x58\xd6\x0e\xbd\xe2\x6a\x54\x45\x2b\x67\x32\xa4\x89\xc3\xcd\x28\x42\xea\xe7\x28\x11\xc3\xc2\x8a\x81\x7e\x31\xe8\x3f\xa8\x8c\x61\x56\xfc\x2c\x33\x04\x5a\x1f\x8b\x17\x1b\x20\xf8\x39\x67\x94\x88\xb8\x4a\x42\xc2\x91\xbf\x77\x49\x79\xc0\x06\xd0\xd1\xd5\xc1\x37\xed\x80\x93\xf6\x28\x2d\xf0\xff\xff\x30\x62\x6b\x13\xb0\x55\x90\xf1\xed\xb0\xff\x9f\xaf\x1e\x7f\x60\xef\x68\x34\xf5\xe5\x87\xa0\x2b\xc8\xd2\x13\x8a\xc3\xf2\xcb\x0f\x84\xeb\xae\x38\x4f\x1b\x54\x65\x69\x9e\x36\x5f\x7e\xf0\x3d\xba\x2b\x6a\xe9\x6c\x8e\x41\xf0\xcb\xd2\xf1\x57\xf4\x6f\xb0\x38\x06\x01\xb0\xc5\x0e\xee\x27\xd4\x36\x53\x06\x04\x86\x77\xc2\x49\x82\x25\x35\xac\x63\x87\x81\x8c\x18\xd6\x49\x58\x7d\x03\xed\x4b\xf7\xe9\x13\x86\x52\xc8\x03\x00\x6a\x22\x59\x18\x99\xd1\x90\x04\xab\xd5\x8c\xff\x4f\xec\x3d\x73\x6d\x1b\x4b\x03\xc6\x44\x22\xb6\x19\x45\x0d\x34\x29\x12\x9e\xc0\x8a\xc7\x68\x58\x2c\x24\x15\xbb\x62\x81\x94\xcc\x8a\x0e\x67\xfc\x48\x0c\x33\x0c\x98\x12\x45\x3c\x80\x41\x91\x20\x7c\x43\x57\xfc\xab\x5a\x15\xcc\xb4\xd3\xff\xe7\x77\xb3\x2d\x72\x67\x29\xa6\x65\xd4\x10\x91\xec\x8b\x45\xc4\x90\x51\x81\x20\xf4\x61\x1d\x87\x55\xf2\xa6\x8f\xe7\x23\xbf\x6c\xf6\xb3\x64\xef\xf9\xa5\xa8\x12\x1a\x19\x46\x15\x0a\xbf\xb9\xf8\xf7\xc8\x94\x98\xdd\xae\x9d\xa1\x8c\x98\x81\x31\x25\x26\x6e\xf1\x4f\xc7\x4a\x3e\xeb\xe6\xa9\x07\xd1\x08\xd4\x9c\x7c\x70\xd5\x0e\x9b\x39\x42\x39\xcb\x83\x38\x9c\x3b\x63\xe4\x1e\x1f\x8d\x6e\x7f\x52\x4f\x27\xdb\xbf\xb3\xe5\x0d\x91\x29\x03\x27\x3c\x45\xda\x6e\x54\x24\xaf\x83\x1b\x48\xf8\xd7\x52\x5f\xaa\xda\xa4\x4d\x86\xd4\x9d\xe2\x1b\x01\xa0\x3e\x47\x12\x0c\xd9\x7c\xc3\x77\xa5\xea\x3b\x45\x09\x4e\xd4\x36\x62\x3b\x61\xa8\xc1\x7d\x61\x1d\xd4\x8f\xfd\xa3\xb4\x0b\x5d\x6e\x09\x4b\xca\xd8\x7d\x14\xe6\x3b\xc9\x03\x30\xd7\x81\xa6\xba\xa2\x26\x7a\x8b\xc7\x67\xd3\x5e\x33\x55\x63\x25\xea\x90\x52\x31\x81\x91\xfd\x88\xec\x4b\xb5\xeb\xf8\x65\xfb\xe8\x00\x45\x9e\xe3\x49\x08\x7f\x14\xf4\x67\xac\x0a\x77\x3d\xbc\x2f\x8a\xc6\xdc\x23\x63\x7b\x40\xce\x7c\x6a\x68\x3e\x25\x05\x28\x77\xb7\x09\xd2\x83\x9a\xab\x17\x49\xad\xa7\xbb\xfe\xe4\x03\xae\xf3\x35\x24\x50\x57\x4e\x69\x41\x8f\x87\x72\x50\x25\xbd\xb1\x4c\x82\xec\xe2\xb2\xd3\x90\xb0\xb1\xda\x69\x7e\x70\xb1\xee\x66\xe1\xeb\xe0\x56\xe2\x7e\x2f\x08\xdd\x22\x02\x8f\xc4\x34\x3f\x08\x69\xb1\x9e\x87\xb4\x47\xe0\xa3\x29\x4a\xa0\xa6\x6a\xcc\x74\x14\x46\xc3\x66\xa5\x46\x5b\x03\x10\x84\xec\x98\x99\x28\x60\xd3\x8c\x64\x13\x24\xe4\x4b\xbf\xe3\x39\x1a\x8e\xdb\xa1\x2e\x55\x56\x29\x7f\x55\xb6\x96\x0d\x09\x3d\x63\xfa\x42\x1a\xb0\x8c\x46\x8a\x94\xa3\xda\x2b\x25\xbb\x18\x29\xd1\xd9\x1a\xdd\xf0\x9d\x8f\xed\xc7\xc7\x67\xf1\x79\xb2\xcf\x97\xb6\x6c\x09\x1c\x76\x4a\x2c\x59\x60\xcc\x30\xe3\x98\x9e\x12\x7f\x27\x29\x31\x03\x78\xa3\x98\x28\x6b\xa3\xe5\x04\xd0\xb4\x75\x31\xec\xde\x84\xda\x3f\x4a\x7c\x33\x23\xa0\x64\x5b\x50\xeb\x98\xc2\x93\x49\x99\x3c\x6c\x48\x1d\xd9\x7e\x58\x76\xcc\x8e\xc4\xc2\xec\xc2\x44\x8e\x74\x8f\x31\x31\xcf\x85\x05\xa3\xb9\x89\x37\xe1\x00\x1b\x38\x84\xa9\x38\x65\xaf\xa0\x47\x94\x6c\x3f\x5c\x63\x1c\xff\x13\x82\xd4\x61\x3a\xc3\x42\x9c\x16\x99\x8a\x04\x47\xa6\xd2\x15\x18\x03\x72\x62\xdd\x03\xab\xd6\xde\xd9\xbd\xd1\x0a\xe2\xea\x58\x67\xbc\x53\xb3\x56\x83\xb6\x8c\x05\xde\x03\xd6\x8c\x61\xb8\xf0\xc3\x42\xf4\xb7\x1b\x17\xe7\x53\xb3\x5b\x3c\x2b\x3f\x15\xa8\x43\x58\x76\xfb\x22\xf5\x22\x90\x47\xdb\xce\x44\xfa\x61\x09\x4f\x09\x93\xb8\x3a\xe7\xd1\x1d\xcf\xa7\x74\xf1\xaa\x1e\xed\xf9\x74\x57\xe7\xd0\xfd\x0c\xd2\x39\x1d\x55\x3d\x7b\x9e\x49\x2c\xfd\xa3\x5a\xd0\x9d\xc3\xb1\x6e\x9c\xb5\x7f\x9e\x51\x92\xbb\x77\xdb\x33\x3f\x3f\x8c\xa0\x4f\xa6\x46\x1d\x17\xc6\xfb\x7c\xde\x8c\x89\xdd\xca\x23\xd7\x51\x8e\x72\xf0\x93\x38\x65\x78\x48\x4f\xa4\xda\xb0\xa0\x95\x7d\xd1\x9a\xb8\x40\xa9\x94\xe1\x01\x69\x73\x1b\x87\x16\x6b\xf3\x3f\x6f\xdc\xd9\x1c\x8b\x8d\xea\xc9\x89\x16\xbf\xa7\x66\x37\xaa\x36\xef\xab\x51\x60\x3d\x2a\x62\xef\x33\xea\x8c\x38\x34\x62\xb8\xa9\xbd\xc7\xcf\x97\x47\x45\x0a\xb2\xfe\x41\x27\x0e\x47\x9e\xce\xb9\x0a\x48\xcd\x2b\x4f\xd0\xc1\x30\x68\x62\xe6\x97\xad\x72\xe8\x2e\x58\x0d\x5d\x7d\x65\x38\xb4\x28\xf3\xc6\x97\xd3\xfa\x82\x31\x77\x63\x8d\x32\x1f\x4a\x5f\xb0\x61\x40\xf6\xbe\x08\x5d\xa3\x4e\xb5\xc7\xec\x48\x9f\xaf\x60\x8c\xb6\x61\x60\x52\xfc\xc5\x80\xde\x2f\xb8\x52\xc2\xd4\x26\x8e\x02\x80\x9a\x0e\x20\x91\xab\x73\xb0\xbb\x26\x5d\xac\x05\x23\xbc\xa5\xb7\x82\x21\x2b\x61\x64\xff\x26\x9b\x31\x68\x32\xa8\x63\x0a\x93\x83\xdd\xeb\xe0\xfe\xc2\xdd\xb5\x54\xcf\x85\x4b\x29\x3b\x37\x6a\xca\x4e\x20\x45\x27\x70\x8b\x8c\x72\xb2\x20\x0a\x6b\x44\xaf\x8d\x83\xbd\x28\x66\x96\x9e\xff\x55\x3e\xc5\x47\xcd\xc9\x61\x6d\xd1\x0d\x06\x3f\xc1\xc7\x10\x90\x45\x18\x75\xcb\xc3\x5a\x73\xa9\x6b\x2d\x63\x25\xb9\xf9\xa9\x43\x52\xa5\x79\x58\xbd\x8e\x3b\x81\x27\x55\xf9\xf5\x58\xa1\xfd\xd7\xee\x02\x10\xe0\x95\x76\x49\xe3\xe8\x7b\x6b\xd6\x41\x1c\x73\x72\xdd\x5d\xfb\x63\xee\xd6\xd7\x2a\x41\x5c\xaa\x2f\x6f\xe5\x73\x1d\x6f\x56\x9b\xa4\x23\x29\xdf\xc3\x6f\xbb\x75\x5d\xa9\x02\xf2\x28\xbd\xba\x95\x43\x1f\x6d\xd0\x62\xc9\xc9\x89\xf7\xb3\xdb\x2e\xe9\x16\xe1\x21\xde\x84\xf2\x9b\x19\xf3\x37\xe1\x36\xe2\x84\x94\x7b\xbc\x7d\xdf\x37\xde\xda\xac\x54\x81\xd8\x93\x5f\xc9\x97\x34\xf9\xfe\x58\x0e\x93\xc5\x13\xf2\x3c\x4e\x4e\xbe\xdf\xd9\x76\xab\xaf\x5c\x03\xe2\x4f\x7a\x73\x6b\x07\x46\x49\xe0\x2f\x3a\xf6\xa4\xdb\x7f\x0d\xdd\xc7\xaf\xdd\xed\x2b\x40\xcc\x89\x2f\x6e\xee\xba\x10\x79\x48\xe8\x88\x6a\xe0\x80\x6f\x77\x29\x6b\x07\x0f\x77\x5b\x57\x7e\xb3\xd6\x25\x81\x1f\x2c\xaf\xf3\x7f\x9c\xf3\xa8\x68\x2a\x21\xc9\x73\x60\x98\x34\x05\xe0\xa2\xbf\x61\x92\xb4\xb0\xcf\x43\x75\xaa\x4b\x4c\x95\x38\x30\x81\xa7\x51\x5b\xfa\xd4\x74\x09\xd7\x79\x98\xa1\xaa\x01\xbc\xc6\xa8\x4f\x3b\x7e\xef\x65\x27\x1d\xea\x23\x44\xc9\x47\x81\x7e\xf8\xb2\xf3\xa8\xfc\xa5\x76\x63\xeb\xc6\xe3\xdc\xba\x49\x5a\xe7\x69\x5d\xa7\x51\x86\x9c\x79\x9c\x15\xb5\x29\xa5\x45\xff\x59\xc0\xd0\x1c\x90\xb4\xe2\xdb\x3c\x6f\xe9\x6d\x81\x4b\xc5\x3f\xc4\x31\x5a\x69\xf1\x7b\xb4\x4d\x42\xec\xf3\x24\x54\xce\xb1\x12\x43\x15\x06\xfa\xb4\x8f\x13\x1d\x54\x6c\x7f\xc7\x41\xb0\x59\x05\x1c\x50\x73\x6c\xcb\xf5\x32\x5c\x82\x41\xf5\x06\x6d\x91\x7a\x5f\x73\x92\x24\x7b\xa4\x23\x83\x59\x8c\xf7\x49\x90\xac\x75\x60\x80\xc9\x00\x2d\xfc\xc5\xa2\x03\x95\xbd\x9a\xbf\x5a\x6d\x82\x25\x34\xe6\x97\x28\x49\x54\x16\xe3\x05\x5a\xc7\x91\x82\x0a\x66\x30\xf2\x93\x7d\xa4\x81\x42\x7d\x18\x05\xc8\xef\xd8\x13\x5d\x9a\x17\xaf\x96\x6b\xe0\x23\xe5\x87\xc4\x47\xf1\xde\x57\xe5\x8b\xd0\x0a\x45\x22\x1e\x98\xb1\x30\x4a\x12\x6c\xcc\x04\x38\x88\xab\x75\x10\xf7\x9d\xa6\xf8\xb3\xed\x6a\xbd\xf4\xa0\x4e\xdb\xef\xf7\x8b\x38\x51\xef\xe1\xde\x23\x14\x85\x0a\x2a\x98\xb7\xfd\x1e\x6d\x43\x5f\x05\x05\xd8\x5b\x2d\x16\x7b\xaf\x63\x4f\x76\x66\x9b\xc0\x8f\x41\x91\xee\xb7\xc9\x46\x13\xe9\x7e\x15\x0b\x22\xa5\x98\x0c\xcc\xf9\x91\x17\x6d\x14\x48\x80\xb7\xe5\x93\x1f\xf8\x9b\xde\x5c\x08\x9e\x6c\xeb\x6f\xfd\x6d\x00\xb1\x86\xf0\x3f\x95\xb5\x64\x9f\xec\x91\x84\x08\xe6\x0c\xc5\x28\xde\xaf\x65\x40\x80\xb1\xf5\x16\xff\xeb\x1b\xd0\xbb\x31\x3f\xf2\x51\x00\x39\xd9\x64\x9d\x6c\x93\x27\x75\x14\xac\xe3\x6d\x1c\x8a\x78\x0c\x43\xe0\x29\x8a\x22\x24\xc1\x41\x9a\xb6\xf4\x56\xde\xea\xfa\x47\xbe\x44\xf9\x0d\xbd\xee\xab\x30\x47\xb5\x53\x56\xc5\xa1\x42\x75\xed\x46\x61\xe5\xd6\x4d\x95\x96\xa8\xbe\xec\xab\x22\xbf\x40\x69\x33\x7d\x9a\x56\xa7\x29\xc0\xb7\x9e\xe3\x5d\xaf\x7f\x7c\x47\xdc\x73\x8e\x71\x78\x4d\x4c\xcc\x4d\xaa\x5e\x34\x2a\xcc\x7b\x37\xf0\x07\x7a\xfb\x82\xa6\xd8\xae\xfb\xdd\x9e\x31\xe5\x36\xa8\x31\xcb\x58\x32\x9f\xac\xff\x13\x7d\x27\x1a\xbd\x54\xda\x3d\xe0\x46\xa2\x53\xf3\x69\xb9\x4a\xd0\x61\x06\xec\x73\x5b\x3d\x3a\xc1\xea\xe3\x4c\x70\xf0\xda\xef\x95\xf7\xd1\x50\xd3\xfc\x66\xa3\xe0\x50\x7e\x3f\xea\xa7\xe7\xfb\x8c\x20\x52\x0b\xc3\x53\x9a\x87\x0d\x4a\xba\xe5\x7a\x5a\x80\xb5\x07\xd2\x44\xc7\xe7\x17\x6a\x3b\xe9\x69\x9f\x9e\xd2\x06\x3d\x4f\xae\x71\x9d\x93\xc8\x6d\xb2\x16\xd8\xae\x05\x63\x38\xd5\xbd\x46\xec\x4b\xe8\x55\xd8\x9b\xf2\x5b\xa7\xd8\xb8\xaa\xfb\x62\xdc\x90\xd4\x16\xb7\x28\xc8\x29\x89\xf4\xfb\x74\x4d\x38\x78\xdc\x6e\x78\x2b\x45\xef\x22\xf2\xf1\xd7\xe6\x1a\x30\xcb\xeb\xef\xec\x1e\x60\x73\x72\x42\x05\xcb\xf8\x35\x5a\x5b\x28\x4d\x73\x2c\x8d\x5b\x88\xd5\xf7\x05\xbd\xdf\x7e\x3b\xcb\x96\x3a\x6d\x9b\xd7\x1d\x3e\x64\x6a\x0d\x01\x55\xc2\xba\x95\x4d\x81\x15\x2e\x2e\x56\xb1\x8c\x4e\x4b\x49\x76\x82\xaa\x78\x99\xd6\xdc\xe3\xc3\x82\x80\x7a\x9f\x9d\xeb\xa3\xb6\xfb\x4c\xb9\x04\x44\xde\xd0\xa0\x4f\xea\x54\x7c\xb7\x6c\xce\x04\xf1\xdc\xb2\xd9\x12\x32\x1a\x63\xa7\x58\x6c\x36\x15\x9a\x10\xcc\xe8\x85\x65\xe3\xf0\x9b\xd1\x30\x35\x33\xbf\xa7\x37\x0c\xd8\x89\x31\x24\x03\x40\xca\x37\x12\x43\xbb\xd9\xd4\xd0\xc8\x10\xdf\x2c\x6f\x27\x36\xd7\xaf\x00\x87\x14\x93\xf2\xa0\x28\x26\xe9\x30\x0d\xf1\xf8\xb9\x27\x9b\x66\xea\x2d\xe8\x50\x98\x98\x37\xd0\xb0\xa1\x32\xca\xaf\x87\xb0\x4a\x50\x45\x34\x08\x26\xfb\x22\x53\x1f\xb0\xd9\xb3\x85\xad\x01\x39\xaa\x70\x76\x49\x72\x3e\x24\x49\xb2\xce\xd3\x51\x8f\x9c\xa0\xb3\xb9\x38\xd0\x06\x8a\xc0\xc8\x3a\x84\xdf\x8c\xc6\x2c\x41\xf6\xde\x2e\x3f\x09\xc9\x00\x90\xbc\x3c\x69\x6a\x37\x5b\x58\x30\x32\x34\x24\x39\x09\x6a\x60\xf5\x9c\xf1\x20\xc9\x8d\x75\x98\x86\x78\xd4\xca\x05\x5b\xa4\xd0\x99\xc7\xb5\x4d\x2c\xeb\x98\x0d\x08\x8c\xb2\x22\x2f\xad\x82\x12\xaa\xdb\x20\x64\x23\x69\x6a\x25\x5b\x62\x81\xf9\x18\x90\x8f\x00\x32\x60\x1e\x19\x75\xd9\x3c\xd2\xee\xd1\xb0\x8e\x5f\xc0\x21\x6b\x35\x3a\xe7\x0c\x81\x89\x6b\x10\xbf\x19\x8d\x51\x50\xfc\xbd\x55\x56\x32\x92\x01\x20\x49\x62\xb6\x76\x6f\x43\xdf\xcc\xf0\x80\xd0\x64\xa8\x81\xef\x7a\x8c\x07\x39\x4d\x3a\xed\x30\x0d\xf1\xd8\x95\x2d\xba\x88\xa5\xb3\x4f\xeb\x9b\xd8\x86\xb0\x1b\x91\x18\x65\xc6\x5e\x5b\x45\x26\xa1\xb0\xc3\x48\x02\x33\xb7\x98\x2e\xc6\x99\xb8\x19\x90\x97\x04\x64\x17\x17\xe7\x40\x12\x17\xeb\x2a\x0d\xef\xc8\xc5\x3e\xba\xae\xa7\xf3\x4e\xaa\x9b\x78\x06\x70\x9b\x50\x18\x45\x45\xdf\x5a\x25\x25\x22\xb0\x82\xc8\x03\xcb\xd4\x56\xb6\x34\x69\x60\x65\x40\x4c\x22\xcc\xc0\xa0\x62\xf4\xe5\x41\x45\x3b\x09\x90\xfe\x88\x95\x4f\xb6\xc8\x09\x29\x58\xf5\xcd\xac\x57\x2a\x66\x03\x02\xcb\x60\xaa\xbe\x0d\x0d\xa5\xae\xba\x0d\x42\x0e\x26\x4c\xad\x64\x4b\xb4\x30\x1f\x83\x83\xa8\x52\x93\x3d\x1b\xc2\x08\x46\x5d\x0e\x23\x68\xf7\xb0\xaf\x64\x34\x5f\x29\x99\x44\x4a\x1b\xa5\x56\xea\x15\xb4\xfa\x7e\x96\x6e\x62\xe0\xd1\x45\x97\xee\x56\x00\xbf\x6c\x1d\x8f\xe4\x92\xee\x6e\x19\x98\xaf\x18\x41\x3e\x7d\xa7\x3f\x94\xa9\x8f\x07\xaf\xde\x74\x48\x36\xab\x2b\xeb\x12\xf6\x89\x8f\x2d\xa3\x78\x86\xac\xa2\x9e\xe9\x96\x8d\xeb\x3c\x2f\x92\x30\x73\x8b\x12\x9d\x2e\xca\x4a\x30\x7b\xd7\xaf\xe1\xec\xd3\x16\x25\x03\x67\x8a\xf8\x94\xdf\xf7\x56\xfd\xdd\x58\x94\x79\x65\x9d\x59\xb8\x90\x83\xd0\x99\xef\xc3\x04\x39\x8c\x9f\x24\x0d\xb3\xe2\x70\x21\x2b\x9d\x94\x38\x6f\x00\x29\xda\x17\x55\xee\xcc\x17\xb5\x83\xc2\x1a\xb9\xc5\xb9\x79\x16\x20\x6f\x85\x98\x0d\x90\xd0\x5e\x53\x3c\x59\xd8\xa0\x4f\xde\xcc\x0d\x56\x1f\x1f\x9f\x2d\xef\x78\x33\x69\xfe\x72\xa9\x99\x76\xcc\x9e\x09\xad\xf7\x28\x8a\x8f\xe1\xec\xa4\xe8\xb6\x5d\x4f\xf3\x92\x57\x96\xca\x44\x22\xae\x2f\xd1\xd1\xf5\x4a\x72\x58\x93\xdd\x92\x41\xae\x75\x01\x2f\x2c\xa7\xa8\xd8\xfa\xfb\x6f\x71\x18\x58\xe1\x42\xbd\x68\xc5\x60\x06\xb2\xb4\xdc\xf5\x29\x85\x07\x0e\x00\x07\xda\xf1\x5f\xb2\xc1\x50\x55\x58\x17\x13\x48\xaa\xa2\xbc\x75\x84\x2c\xa1\xc8\xdd\xf3\x34\xfc\x64\x64\x88\xb7\xbb\x28\xaf\xb1\x46\x5d\x44\x03\x43\xdf\xb3\x83\xa8\xf7\x5c\x7c\x7f\x53\xb2\x72\x72\x8a\xcb\x78\x75\x82\xfc\x4d\xc9\xba\xa1\x14\xde\x00\x2a\x37\xdb\x51\x2c\xa3\x70\x84\x8c\x9e\x6f\x73\xc4\xff\x8a\xc3\x02\x3a\x89\xac\x5d\x3a\xde\xc9\xa0\x48\x5e\x2d\x37\xd2\x0e\x9e\x81\x26\x07\xed\x28\x2a\x76\x4a\xf6\xbd\xbe\x98\xa1\x53\x02\x27\xca\xc2\x2f\x20\x11\xc9\xe7\x6d\xbb\x15\x7e\x91\xd9\x9f\x80\xdb\x7b\xc5\x0d\xd6\x7c\xe5\x1a\xa8\x23\xde\xe2\x2c\x9d\xf5\x93\xeb\xd4\x71\x55\x64\x59\x14\x56\x6e\x8e\xc2\xfa\x6c\xbe\xa0\xe5\xe9\xe9\xe9\xa9\x6c\x99\xe9\x5a\x61\x73\xc5\x84\x45\x9e\x3b\xdf\x43\xf1\x59\x76\x14\x49\xa6\x51\xc8\x3b\xed\x79\xbd\xfe\x2c\x3c\x45\x65\xea\x5c\x00\x5d\x60\x50\x5b\x62\x4d\x5a\x27\x13\xd1\x6f\x69\x9d\x79\x53\x14\x59\x93\x96\x96\xbb\x47\x7d\x6f\xa3\xde\x39\xd9\xdd\x64\x44\xa2\x94\x7d\x98\xa7\xd9\xeb\x0e\x3b\xfa\x0c\xb9\xf5\x6b\xdd\xa0\x7c\xf6\xe7\x2c\x3d\x7d\xfb\x25\x8c\xff\x4e\x7e\xfe\x7b\x71\x6a\x66\x0f\x7f\x47\x87\x02\x39\xff\xf5\xd7\x87\xd9\x7f\x16\x51\xd1\x14\xb3\x87\xff\x89\xb2\xef\xa8\x49\xe3\xd0\xf9\x0f\x74\x46\x0f\xb3\x3f\x55\x69\x98\xcd\xea\xf0\x54\xbb\x35\xaa\xd2\xfd\xec\xe1\x4f\x18\xa9\xf3\x33\xb6\x54\xce\x5f\xf2\xe2\x1f\xe9\x43\x8f\x47\x2f\xf8\xfb\x6b\x1e\x15\xd9\x03\x0b\xa7\xd8\x91\x8b\x2a\x0f\xb3\xc1\x2b\xfd\x85\x0f\x63\x58\x91\xc4\xdf\xd4\x0e\x81\xe1\x91\x18\x7c\xf5\x05\xbd\xef\x24\x65\x19\x6a\xb0\xfb\xc0\x26\x0a\x6b\x3c\x63\x88\xa4\x95\x20\x19\x25\xa4\x12\x15\x4a\xda\xa6\x4c\x8a\xe8\xae\x68\x52\x91\x8e\x73\x6d\xd7\x38\x98\xb1\x42\x30\xe6\x4c\xe6\x8a\x15\x7f\xea\x5e\x38\xf3\xb0\xaa\x8a\x17\x40\x27\xa0\xab\x47\x57\x82\xe6\x63\xdb\x22\x23\xb1\x5c\x73\x64\xba\x83\x85\xbf\xa0\xf2\x23\xc6\xa0\xe7\x39\xaa\x5d\xf6\xe8\xe2\xd6\xff\xda\xba\x65\x16\xc6\x28\x47\xa7\xe6\xff\xfd\xd2\x14\xe5\xd7\x19\x04\xda\x60\x97\xc9\x2c\x0e\xb6\xbe\xde\x04\x84\xac\x21\x26\xbc\xbc\xb3\xfa\xcf\x2b\x53\x31\xf3\x2e\x1a\xa0\xd0\xf5\xa4\x74\xa0\x64\x51\xb6\x52\xf2\x7b\xda\x75\x9d\x64\x1c\xd2\xda\x67\x7d\x9f\x0a\x71\xfa\xa3\x38\x25\x46\x12\xee\x56\x9a\xe7\xaf\x9b\x0a\x38\xa2\xfc\xc7\x20\xb5\x75\x2d\xbb\xff\x8f\x76\x2e\x3f\x2b\x3c\x1d\xb7\xb5\x73\x45\x1a\x6a\xf7\x12\x1b\x3f\xa6\x77\xa5\x1e\xa6\x41\xc2\xe4\x3e\xa6\xca\x03\x77\x32\x3b\x98\x7a\x8b\xfa\x32\xb4\xb6\x6e\xa6\x20\xbc\x9f\xd9\x97\xc6\x1b\x90\x5b\xfb\x59\x22\x32\x5d\x8f\x3d\xde\xcf\xca\x27\xeb\xc9\xdd\x8c\x49\xc1\x9d\x8c\xdf\xdc\xa4\xc8\x04\xa5\xad\x83\x31\x00\xef\x5e\x16\xa0\xdf\x80\xda\xda\xbd\x02\x89\xae\x73\x95\x44\x41\xa3\xb4\x59\xeb\x67\x12\x0f\x03\xbd\xec\xa6\xa7\x13\xaa\x84\x68\x82\xa4\x12\xee\x62\xba\x45\xd9\x3a\x5b\x42\xab\x9b\x19\xe9\x07\x70\xc0\x79\x88\x69\x83\x57\x51\x92\xd5\x0a\xd3\xbe\x62\x6d\x9e\xb3\xd6\x23\x96\x8e\x55\x1c\x76\xfd\xdf\xc0\xe5\xff\x9c\xc0\xe5\x37\x99\x6a\x77\x3a\x36\x2d\xf6\x99\x6f\x85\x7b\xd7\xe7\x4b\x00\x11\xbb\x1b\x72\xa6\x15\x1b\xc3\x22\x99\xce\xa4\x20\xc9\x40\xc3\x34\xe6\x09\xf7\x06\x86\x47\x56\xc2\x66\x88\x3d\x1a\xe3\x31\x00\x14\xc7\x63\x4a\x02\x80\x89\x68\x3b\x93\x0b\x63\xd7\xa3\xb2\xa9\x98\x55\xc1\x4d\xa8\xc8\x4d\xb5\x95\x35\x1b\x7e\x20\xe8\x93\x3d\x1f\xf3\x8b\xb7\xb4\x6a\x24\x73\x1d\x59\x96\x64\x6a\xab\x67\x85\xda\x2a\x0b\x24\x54\x47\xa5\xb1\xb6\x7a\xbc\x6f\xc7\x6b\xdd\xc7\x19\x24\x09\x94\x3e\x11\x96\x78\x86\xad\x3f\x38\xae\xff\x38\x8a\x65\xba\xa3\x6c\x14\x9f\x3c\x18\x06\x80\x69\x30\x2c\x2d\x46\x4c\xd0\x69\x25\x20\x36\xe1\x57\x03\xe2\xe9\xb8\xa7\xe9\xb5\x21\x96\x1e\x60\xcf\x46\x63\x30\xe6\x96\x84\x44\x22\x90\x69\xda\x7e\x2b\xcb\x8c\x15\x40\x53\xc4\xa0\xfe\x36\xf5\x1e\x2d\x01\xa0\x17\x29\x47\x46\x05\x87\x26\x1e\xe3\xf5\xb9\x9b\x78\x00\xd0\x6c\xe2\x21\xc8\x66\x8a\x42\xab\x73\x0f\x23\x01\x65\xee\x71\x03\xf2\x69\x2a\x6d\x9a\xb7\x0c\x31\x68\xa3\x32\x62\x82\xa3\xd9\x9e\x69\x5a\x7d\x3b\xd7\x3c\xf9\x89\x36\xb6\xa4\x59\xd4\x6d\x7a\x3d\x5e\x0e\x50\x57\x12\x9e\x86\x14\x5b\x9e\xeb\x4d\xd6\x6c\x87\x43\xf3\x3c\x95\x63\x7a\x0e\xae\x62\x9f\x7e\xac\xbc\x8f\x60\x88\x18\x78\x5a\xae\x3b\x0f\x9c\x87\xe9\x1f\x28\xf6\x1b\xfc\x6f\x64\x7b\xd9\xdc\x16\x80\x25\x73\x5b\x79\xc5\x7b\xc2\x38\x96\x27\xb8\x06\xf4\xda\x04\x77\x32\xea\x69\x63\x18\x9e\x1a\xdb\x99\xb3\x51\x80\x66\xd0\x46\x9f\x44\x4d\xed\xb4\xe1\x7b\x1b\xc3\xd2\x5c\x1e\x70\x8c\x6f\x19\xba\x63\x3b\x5f\xef\x41\xc6\xcf\xd0\xc0\x15\x17\x0f\xc4\x61\xab\xa5\xab\x05\x92\xe5\x74\x1f\xc1\x84\x7d\x11\xda\x09\x61\x68\x66\x48\x46\x8c\xe5\x93\x5f\x84\xff\xd9\xf3\x84\x2e\x46\xa7\x09\x5d\x88\xe9\x3a\x15\x9b\x01\x25\x06\xe9\xcd\x4c\xf2\x0a\x37\x5f\x3a\xf4\x42\x52\x92\x15\xe7\x1a\x65\xfa\xf7\xbe\xfe\x1d\x5b\x8b\x31\x7d\x53\x27\x67\x80\xb4\x6d\x16\x7d\x65\xfb\x91\x19\xb2\x0c\x30\xfa\xf3\x9f\x40\xd1\xbe\x8d\x62\x4d\xf7\x38\x18\x36\x48\x8c\x7a\x0b\x6d\x9d\xe0\x15\xf9\x2b\xac\x1f\xfb\x30\x46\xee\xf7\xb4\x4e\xa3\x34\x4b\x9b\x57\xbe\x41\xc1\xf2\x8a\xd7\x2e\x51\x55\x97\x28\xa6\xd7\xf6\x7a\x74\x81\x4b\x2b\x52\xba\xd2\x3d\xa1\xb6\x99\x29\x65\x65\x85\xbe\x2b\x65\x86\xdb\xc1\xc7\xe1\x32\xf9\x21\xa8\xbe\x52\x84\xb5\x1d\x42\xa9\x14\xd1\xa9\x8c\x65\x8f\xc8\xff\xf3\x09\xde\x22\x82\xcb\xaf\x7f\xac\xcf\x65\x59\x54\x4d\xed\x7c\xfa\xa4\xe1\x60\x0b\x16\x65\x85\x6a\x54\x7d\x47\xee\x22\x79\x74\x8a\xca\xf9\x64\x03\xa0\xe9\xff\x7e\x9b\x96\x2d\x12\x6a\x4a\xc1\xe6\x75\x2f\xaf\x57\x26\x41\x08\xbd\xca\x06\xe6\xd6\xde\x99\x78\xc8\x18\xfa\x93\xbc\x7a\x97\x2e\xbd\x5f\x03\x16\x09\x61\xd3\xd6\x6d\xdd\x7b\x53\xcf\x99\xe4\x67\xef\x38\xd7\xd2\x73\xee\x6f\xdc\x75\xb7\xb4\x60\x91\x50\x36\x6d\x5d\xe7\x8a\x7d\xd7\xa1\xc7\xf1\x63\x55\x64\xaa\x91\xe0\xc5\x36\x3b\xd1\xef\x0f\xfa\x7d\xce\x4a\x33\x37\xb1\xfa\x68\xff\x40\x20\xed\x5f\x84\x9a\xdd\xed\x67\x04\x5f\xd2\xfd\xa4\x70\xcf\x18\x6b\x92\x97\xe3\x12\xd3\x74\x7b\xb3\x9e\xc5\x2f\xe8\xb0\x20\x84\x54\xc7\x3a\xa7\x7d\xd0\x0c\xbe\x26\xf7\x95\x18\x58\x1d\xbc\x3f\x3d\x10\xb6\xa5\x90\x67\x61\xb3\xa6\x78\xc6\x7b\xfa\x45\xe9\x36\x86\xde\x74\xb9\xca\xf0\x45\x2a\xce\x3e\xcd\xb2\x2f\x3f\x7c\x0c\x16\xfb\xfd\xfe\x07\xf9\x36\x96\xad\xb3\x15\x2f\x5a\x49\xbe\xfc\xf0\xcb\x6a\x1e\xac\x1c\x2f\x73\x97\x0e\xfd\xe7\xcf\x57\x2e\xfe\x5f\x40\xff\xe7\xb0\xbf\x2e\x2b\xff\x27\x70\x43\x8a\x59\x30\xff\x62\x6d\x0d\xe6\x1b\xd2\x56\x7f\xbe\xc2\xed\x74\x84\xf6\x91\x67\x5e\xbe\x74\xc9\x3f\x6b\x5b\xd3\x53\x92\xc6\x61\x53\x54\x35\x60\x48\x94\xad\x86\x64\x4a\xab\x7e\x85\x5b\x4d\xb0\x2f\x23\xcc\x06\x7c\x14\x9e\xa7\x6b\xff\xa8\x64\x67\xff\xa8\xa6\x5d\x05\x5b\xe6\x64\xa9\x6d\x2f\x9d\x27\xed\xa5\xeb\x7e\xf1\x5d\x57\xfd\xd8\x5a\xf4\x73\xfc\x4a\x2d\x20\x0c\xe1\xdf\xc4\x8c\xe0\xbe\x39\x35\x64\xf7\x18\x74\xc4\x1c\xbe\x6c\x07\xe6\x7c\x60\x5d\xc2\x15\x85\x32\x90\xc9\xb8\x4b\xcf\x21\x2f\x4d\x98\x29\xd3\x89\x20\xb4\xa7\x87\x9d\x9f\x7f\x27\xda\x3c\x70\x36\x9c\x0a\xef\x07\x6a\x58\x92\x44\x08\x26\xcd\xc5\x0a\xc2\xb3\x83\x75\xac\xe2\xc2\xfe\x1b\x72\xa7\x70\xb8\x33\x03\xe1\xfb\xb6\x2b\x56\xb4\xb9\xb0\xeb\x9c\x7a\x4a\x9e\x49\xf2\x62\xc8\x30\xd9\x5f\x10\xc9\x6b\x34\x45\xa9\x02\x37\x45\xa9\xc3\xe5\x69\x92\x64\x1a\x5e\x5a\xaa\x43\xb3\x05\x5d\x95\x0b\x52\x0a\xf0\x80\x9b\x03\x57\x11\x5e\x19\xea\x41\x0d\x60\xe5\x62\x8d\xe8\xd0\x1d\x0e\x37\x1d\xd2\x17\xc0\x43\x01\xbe\x3b\x4c\x22\x14\x51\xc7\x6d\x4a\x45\xa9\xd0\xed\x0f\x36\x9b\xd2\x50\xaa\x94\xf5\x03\xce\x52\xa1\x89\x3a\x4d\x30\xa9\x52\x67\x07\x72\x4d\xc9\x25\x35\xda\xca\xc1\x5c\xa1\xc8\x44\x97\xa6\x8d\x54\xe8\x92\x63\xa5\xa6\x94\x91\x2a\x51\xe9\x78\x29\xff\x6d\x24\x47\x92\x41\x2a\xe4\xf8\x11\x49\x53\x22\x48\x95\xa2\x7a\x54\x52\x28\x32\xd1\xa5\x29\x1e\x15\xba\xec\x90\x9f\x29\xbd\xa3\x4a\x56\x39\xec\xd7\x97\x98\x88\xd2\xc4\x8d\x0a\x51\x7a\x58\xcd\x94\xef\x44\xa5\x29\x1f\x5a\xeb\x0a\x8c\xcd\x24\xe9\x18\xb5\x66\x56\xdf\x00\x58\x9a\x8a\x51\x6f\xa4\x70\x04\x8b\xff\x36\x4a\x93\x24\x59\x54\xa5\x79\x4c\x1b\x83\xe9\x55\x20\x85\xd8\x52\x87\x17\x5e\x4a\xd5\xc8\x5a\xdb\x45\x4f\x74\x4d\xf7\x81\xeb\xa0\xae\xc7\x81\x3d\xe0\x65\x53\x94\x1d\x00\xcd\xa0\x01\x00\xd1\x45\x3d\x4f\x49\xe8\x01\x00\xb2\xaf\x10\x9e\x9a\x4c\x03\x00\x25\x2b\x8a\x1d\x20\xf5\x81\x00\x58\x67\xf7\x80\x1c\x24\x00\xb8\x60\xae\xe4\xf3\x7e\xaa\xa9\xea\x2a\x70\x0b\x23\x81\x6b\xd6\x85\x83\x53\xc3\x20\x9f\x56\x53\x8d\x02\x87\xed\x46\xb5\x92\xf2\x4e\x19\xd1\x1c\x9c\x0f\x46\x39\xf1\xa1\x3a\x10\xbb\xee\xa3\xa3\x48\x46\xad\x8e\xa0\x1e\x75\xf5\x4d\x81\xd5\x94\xbf\xe3\x9a\x6a\xaf\xc2\xb3\xd4\xd7\x44\x4b\x11\x7c\x5f\x09\x00\x37\x7c\x37\x89\x70\xf5\xb3\x3d\xb5\x0f\x84\xbd\x12\x7b\x62\xb0\xde\x70\xc2\x1f\x88\xc6\xd8\x5b\x4f\x8c\x74\x6c\x6d\xee\xc9\x90\x4f\x50\x13\x7b\x6a\x12\x81\x38\xad\xe2\x0c\x29\x82\x5b\x79\x1f\x21\x58\x4f\xbd\xa0\x44\x04\x8a\x33\x14\x56\xfb\xb4\xe5\x21\xae\xfc\x49\x8f\xbc\xc5\x11\xd3\x51\x8a\x54\x13\x17\xcf\x30\xa4\xd5\x7e\x11\x67\xe2\xd2\xd0\x57\x99\xa9\x43\x20\x34\x3a\x06\xa7\xf4\x32\xb8\x0c\x07\x00\x34\x61\x94\xf5\x14\xc9\x2f\x00\xc0\xad\x8a\x17\x19\x08\x97\x40\x80\x31\xca\x32\x05\x12\x17\xc9\xa0\x78\x9e\x74\xd3\xcd\xe8\x42\x0f\x68\x38\x84\x72\x18\x95\x00\x20\x60\x34\x9f\xb8\x49\xdc\x3a\x1f\x92\x58\x9d\x8f\x11\x5a\x07\x35\x5a\x6e\x75\x3e\x2c\xba\x3a\x1f\x96\x1e\x87\x19\x23\xc0\x0e\x76\x94\x0c\xeb\xfc\x6d\x62\xec\xfb\xe4\x5e\x92\x04\x44\xb9\x59\x6f\x99\x28\xf3\xc1\xc1\x97\x8f\x1a\x7f\xf9\xe4\x21\x98\x8f\x18\x85\xf9\x88\x81\x98\x4f\x18\x8b\xf9\xa4\xe1\x98\xbf\x71\x44\xe6\x77\x1f\x94\x96\x43\x6a\x89\x9b\x1d\x86\x44\x99\x1d\xc6\x88\xb2\x83\x1a\x2d\xca\xec\x30\x2c\xca\xec\x30\x2c\x4a\x0e\x33\x46\x94\x1d\xec\x28\x51\x66\x87\xb7\x89\xb2\xef\x93\x77\x14\xa5\x4f\xce\x01\x10\x59\xb6\xd9\x90\x2c\xdb\x6c\x8c\x2c\x3b\xa8\xd1\xb2\x6c\xb3\x61\x59\xb6\xd9\xb0\x2c\x39\xcc\x18\x59\x76\xb0\xa3\x64\xd9\x66\x6f\x93\x65\xdf\x27\x77\x93\xe5\x3c\xc1\x13\x92\x53\xa3\x74\x9d\x22\x35\x26\x71\x02\x79\x31\x54\x51\x7b\xbb\x47\xad\x48\x7b\x14\xee\x21\x0d\x51\xb1\xdf\xc2\xff\x14\xfd\x32\xa0\xb0\xa9\xfa\x75\x8e\xf2\x08\x87\xf3\xa8\x2e\x8b\x53\x9d\x7e\x87\xae\x85\x81\x76\x8e\x91\xc5\xd1\x3e\xcf\x86\xb6\x89\x43\x45\xab\xdd\xdb\xc6\x62\x56\x21\x50\x55\xab\x38\x5a\x09\xf9\xac\x37\xd3\x01\x49\x01\x50\x9e\x92\xdc\xd2\xc0\x8b\x22\xfa\x07\x8a\x1b\xe0\xc5\xf7\x34\x41\xc5\xf0\xb7\x49\xb6\x78\x0c\xad\x13\x77\x17\xef\xee\x3c\xbd\x49\x6e\xe0\x47\xaf\x4f\xfd\xda\xb8\xb0\x88\xbb\x0c\xe6\xdb\xd5\xc6\x5f\x2e\x3e\x02\xd5\xfc\xb5\xa9\xda\x6a\x3d\x0f\x56\x50\x95\x65\xf4\xba\x00\x6b\x6c\x40\x70\x3f\x7a\xf5\x41\x70\xfa\x41\x8d\x7c\x07\xc1\xb6\x06\xc8\x4f\x21\x19\x1c\x35\x4d\x85\x62\x8d\xc8\x5b\x9a\xba\x02\x42\x45\xdf\x98\xb1\xa9\xef\x7b\xc6\xdc\x0a\x7d\x47\x55\x8d\x0c\x0c\xf2\xd7\x56\x46\x75\x20\x89\x61\x1b\x09\x19\x62\xa8\x01\x46\x42\x2f\x55\x28\x5c\x88\xdb\xdd\xbd\xa8\xe2\x03\x5e\x30\x04\xf4\xb6\x28\x05\x05\x2d\x04\x91\xa8\xaf\x04\x3e\xf4\xe6\x76\x64\x4d\xed\xb4\x00\x5c\xe7\xca\x97\x33\x9a\x41\xe3\x22\x7f\x64\x23\x65\x02\x56\x30\x43\x83\x02\xa4\x63\x46\xa7\xe4\xa2\x65\x7b\x18\xc2\x2a\x81\xe8\x38\xe9\x47\x93\x0b\xf4\x4d\xd0\x82\x59\x05\xd0\xf1\xb2\xac\x20\x17\x30\x93\x88\x05\xb3\x94\x53\xc4\x46\x20\x24\x2b\x0b\x0a\xfe\x24\xad\x9b\x2a\x8d\xce\x0d\x1a\x24\x41\xeb\x8b\x14\x84\x1d\x16\xaa\x10\x85\xa3\x7d\x02\x62\x38\x79\x8a\x09\xa5\x24\x3d\x8a\x50\x16\x9f\x86\x0e\x99\xf9\x53\xc5\x26\x7e\x01\x33\xa0\xd4\x65\x26\x22\xec\x3e\x97\x29\x28\xf5\xcf\x65\x12\x52\xf3\xd7\x34\xde\x8f\x15\x6a\xe2\xa3\xde\x93\xa4\xd8\x80\x54\x7b\xcb\x71\x1a\x86\x18\x09\x1a\xc0\x71\x26\x55\xb3\xca\x08\x1c\x63\x3d\x62\x48\x52\xb6\x61\x26\x23\x55\xa5\xd5\xe3\x35\x48\xcc\x3c\xce\x64\xc4\xda\x28\xeb\x31\xeb\x43\x4d\x46\x6d\x1c\x68\x32\x05\x75\x98\xf5\x04\xc0\xb1\x06\xd1\x30\x8d\xb4\x5e\x9a\x8a\x8e\x88\xf2\x84\xf5\xa4\x23\x60\xd2\x94\x1a\x65\x7b\xb2\xff\xba\xc7\x4a\xd3\xdd\x13\xf5\xc3\x2f\x34\x9c\xb8\x8a\xf2\x46\xc2\xa6\x28\x9d\x80\x0e\xd6\x3a\x82\xcf\xa6\x72\x04\xab\xa4\x6f\x02\x4e\x48\xe1\x7a\x8c\xa0\xb6\x11\x7c\xaa\xaa\x09\x28\x0d\xba\x46\xb0\x9a\x14\x8d\xe0\xd4\x6d\x83\x80\xd5\x68\x20\x08\x5e\xb3\x7d\x60\x7d\xaa\x88\x5e\xea\x55\x58\xf6\x04\xaf\x2e\x78\xf3\xca\x23\x95\x41\x7e\xb7\x30\xaf\xce\xef\x1f\xe9\x51\xf6\xde\x35\xd8\xeb\xd8\xfe\x0d\xe2\xbd\x3a\x7f\x7b\xc8\x47\x96\x8b\xef\x12\xf5\x31\x6e\xde\x3d\xf0\xcb\xdf\x31\xf6\xab\xf3\x77\x09\xff\xb0\x52\xbc\x53\x04\x58\xe7\xef\x1f\x04\xd6\xf9\x7b\xc7\x81\x9a\x4c\xef\x11\x0a\xaa\xc2\x7c\x6b\x34\x08\x48\xf1\xcd\x01\x21\x16\xdf\x3b\xc5\x84\xf9\x7b\x85\x85\x9a\xb0\xee\x19\x19\xaa\x42\xbb\x57\x70\x08\x08\xef\x6e\xf1\x21\x34\x06\xef\x1e\x22\x02\x83\xf0\x3d\xa2\x44\x40\x6b\xee\x15\x28\xe2\x16\xdc\x37\x56\xd4\x34\xf1\x4e\xe1\xa2\xaa\x84\x77\x88\x18\x01\xfd\xbb\x47\xd0\x08\xda\x8f\xbb\xc5\x8d\x80\x32\xdc\x1e\x3a\x5a\x3e\x75\x12\xcc\x79\x72\xb7\xd8\x31\x4f\xee\x1f\x3b\x52\xf6\xde\x35\x76\xec\xd8\xfe\x0d\x62\xc7\x3c\x79\x7b\xec\x48\xbe\x4f\xdf\x25\x76\x64\xdc\xbc\x77\xec\x98\x27\xef\x18\x3b\xe6\xc9\xbb\xc4\x8e\x58\x29\xde\x29\x76\xcc\x93\xf7\x8f\x1d\xf3\xe4\x9d\x63\x47\x5d\xa6\xf7\x88\x1d\x55\x61\xbe\x35\x76\x04\xa4\xf8\xe6\xd8\x11\x8b\xef\x7d\x62\x47\xd2\xa7\xef\x11\x3b\xea\xc2\xba\x67\xec\xa8\x0a\xed\x5e\xb1\x23\x20\xbc\xbb\xc5\x8e\xd0\x18\xbc\x7b\xec\x08\x0c\xc2\x77\x88\x1d\x21\xad\xb9\x57\xec\x88\x5b\x70\xd7\xd8\x51\xd7\xc4\x3b\xc5\x8e\xaa\x12\xde\x21\x76\x04\xf4\xef\x1e\xb1\x23\x68\x3f\xee\x15\x3b\x42\xca\x70\xd7\xd8\x91\xef\xad\xa2\x6a\x76\xb8\x5b\xec\x98\x1d\xee\x1f\x3b\x52\xf6\xde\x35\x76\xec\xd8\xfe\x0d\x62\xc7\xec\xf0\xf6\xd8\x91\x6c\x88\xbb\x4b\xec\xc8\xb8\x79\xef\xd8\x31\x3b\xbc\x63\xec\x98\x1d\xde\x25\x76\xc4\x4a\xf1\x4e\xb1\x63\x76\x78\xff\xd8\x31\x3b\xbc\x73\xec\xa8\xcb\xf4\x1e\xb1\xa3\x2a\xcc\xb7\xc6\x8e\x80\x14\xdf\x1c\x3b\x62\xf1\xbd\x4f\xec\x48\xfa\xf4\x3d\x62\x47\x5d\x58\xf7\x8c\x1d\x55\xa1\xdd\x2b\x76\x04\x84\x77\xb7\xd8\x11\x1a\x83\x77\x8f\x1d\x81\x41\xf8\x0e\xb1\x23\xa4\x35\xf7\x8a\x1d\x71\x0b\xee\x1a\x3b\xea\x9a\x78\xa7\xd8\x51\x55\xc2\x3b\xc4\x8e\x80\xfe\xdd\x23\x76\x04\xed\xc7\xbd\x62\x47\x48\x19\xee\x1a\x3b\x76\x9b\xb9\x09\xea\x36\xbb\x5b\xf0\xd8\x66\xf7\x0f\x1e\x29\x7b\xef\x1a\x3c\x76\x6c\xff\x06\xc1\x63\x9b\xbd\x3d\x78\x24\x3b\xf0\xef\x12\x3c\x32\x6e\xde\x3b\x78\x6c\xb3\x77\x0c\x1e\xdb\xec\x5d\x82\x47\xac\x14\xef\x14\x3c\xb6\xd9\xfb\x07\x8f\x6d\xf6\xce\xc1\xa3\x2e\xd3\x7b\x04\x8f\xaa\x30\xdf\x1a\x3c\x02\x52\x7c\x73\xf0\x88\xc5\xf7\x3e\xc1\x23\xe9\xd3\xf7\x08\x1e\x75\x61\xdd\x33\x78\x54\x85\x76\xaf\xe0\x11\x10\xde\xdd\x82\x47\x68\x0c\xde\x3d\x78\x04\x06\xe1\x3b\x04\x8f\x90\xd6\xdc\x2b\x78\xc4\x2d\xb8\x6b\xf0\xa8\x6b\xe2\x9d\x82\x47\x55\x09\xef\x10\x3c\x02\xfa\x77\x8f\xe0\x11\xb4\x1f\xf7\x0a\x1e\x21\x65\x78\x43\xf0\x38\x27\x57\x19\xd3\x53\xfe\xf4\x56\x63\xfc\x28\xc7\x11\x18\x80\x66\x34\x10\xee\x3d\xd6\x41\xc8\x49\x2a\x0a\x01\x1f\xde\x02\x77\x55\xe2\x9a\x75\x3e\xcc\x40\x9d\x8f\xe1\x81\x9f\x0e\x07\xd9\xb0\x7e\xa1\xc7\xb5\xf3\x64\x98\x8f\x3c\x19\xc3\x07\x3f\xda\x3c\x96\x8f\x7e\xb5\x97\x48\xe3\x30\xcc\x47\x76\x18\xc3\x07\x3f\x97\x3b\x96\x0f\x61\xe6\x80\xab\xb7\xd9\x30\x23\x38\x7e\x1f\x66\x84\x1f\x2a\x85\x19\x99\xf3\x33\x65\xd8\x02\x34\x69\xdc\x9f\x31\xa3\xbf\x45\x7c\x1d\x28\x3f\x81\xa7\x9f\xc9\x03\xc1\xf9\x69\x35\xfd\xfc\x1a\x08\x4e\x6e\xe7\x55\x2e\xeb\x05\x01\xeb\x26\x8d\xbf\x09\xf7\xba\xf2\x9c\xa1\xb4\x5c\x18\x88\x42\x9b\xe4\x37\xd7\x39\xc1\x4e\xaf\x3a\xb4\xdd\x0e\xac\x5d\x96\xb5\xf0\x78\x5d\x7e\xd5\x9c\x5c\x7d\xf8\x5a\xe1\x85\x27\xa5\x59\x35\xb4\x82\xa6\x56\x55\x1a\xf0\xf8\x78\x99\xd3\x27\x99\x73\xb9\xaa\xda\x6c\xd6\xa4\x9e\x83\xc0\xbb\x5e\xe7\x75\xe5\x16\xa7\xec\x15\x38\x5b\xc8\xf4\xb2\x4f\xd8\xe7\x0b\xd7\x95\x69\x47\x2b\x9f\xc9\x8d\x52\x78\xaa\xc6\xd2\xaa\x7b\x8f\xca\x7d\x56\x78\x4a\xd3\x25\x8a\xc6\xd0\x6e\x19\x36\xc7\x5d\x7a\xaa\x51\xf3\x69\xe5\x7d\x7c\x7c\x06\x0b\xfb\x53\x8b\x8c\x55\x97\xe4\x63\x0a\xa3\x0c\xed\xd8\xbd\xf3\xc0\x1b\xf2\xa4\x2a\xb3\x78\x65\x36\x6b\x13\x79\xee\x9a\x42\x12\x5b\x67\x88\xb6\x85\xa6\x2d\xd4\xaf\xe4\xd2\x9b\x40\x72\x9b\xca\x3f\xaf\xf3\x17\x37\x58\x5d\x58\x46\xd1\x95\x94\x53\xe5\xc5\x5d\x79\x17\x7e\x61\xad\xf2\x66\xc3\xeb\x6c\xd4\x3a\xbe\xc7\x2b\xf9\x9e\x5c\xeb\x88\x29\xf1\x84\xa5\x2b\xe5\xd5\xca\xbb\x74\x57\xec\x2a\xaf\x36\x5d\xad\x8d\x5a\x0b\x13\x13\x8e\x8e\x8a\x2f\x73\xca\x4a\x7f\x39\x9c\x06\x70\xec\x00\x4c\x28\x5c\xef\xc2\xaf\xc3\x95\xca\x1b\xd7\x9b\xcd\xf3\xd7\xee\xb5\x9e\x83\x2a\xaf\x08\x48\xdb\x83\x00\xf9\xa7\xf2\x48\xc5\x03\xa5\x9e\xca\x33\x15\x95\x9e\x77\x2a\x77\x7d\xce\xa9\x9e\x47\x27\x6f\x5c\x9f\x90\xf1\xa5\xfb\x5e\x74\xb8\x8a\xc0\xb5\x3d\x9c\x78\x87\xb2\xc2\xb8\x82\x91\xdf\xf4\xa5\x83\x66\x2a\x52\xe1\x2e\x67\xb9\x09\x41\xd7\x04\xa0\x05\x01\xa1\x17\x48\x2d\x00\x1a\x10\x10\x5a\x81\xd2\x00\x80\x7f\x05\x1f\xe7\x1f\x60\x5f\x41\x49\xd9\xd7\xb9\x5f\x70\xee\x7d\x9d\xf9\x05\x21\xb6\x10\x99\xd7\xa0\x2a\x02\xd5\xf6\x50\x2c\x99\xa5\xce\xba\x82\x8d\xa7\x69\xd5\x39\x57\x10\xd2\x3c\x98\x1a\xe3\xcb\x8e\x71\xa8\xdf\x97\x84\xd8\x52\x62\x1d\xea\xf8\x25\xa1\xb5\x54\x98\x87\x7a\x5e\xc1\xc8\xd9\x87\xba\x5e\x41\x4a\x1b\x00\xf4\xfd\x8a\x37\x61\xa1\x37\x60\x45\xc8\xad\xc4\x06\x68\x50\x15\x81\x6a\x7b\x28\x96\xe8\x55\x67\x5e\xc1\xc6\x98\xd7\x00\x33\x15\x21\x4d\x14\xab\x80\x95\xae\xd7\xdf\x4b\x2a\xbd\x20\x06\xa6\x7c\xed\xdf\xeb\x16\xa6\x24\x16\xa6\x6c\x05\x18\xc0\xc4\x94\x91\x86\x09\xb2\x31\x65\xa6\x21\xd3\x8d\x4c\xe9\xfa\xfd\xcd\x16\xda\xf8\x2d\x89\x95\x29\x5f\x7b\x20\x83\x99\x29\x89\x99\x29\x5b\x01\xd0\x64\x67\xca\x48\xc3\x69\x34\x34\x65\xa6\xa1\x35\x58\x9a\xd2\x0d\xe4\x1b\x3a\x94\x66\x04\x84\x64\x20\x37\x03\x68\x45\x40\xc8\x05\x6a\x2b\x80\x46\xa8\x18\x4d\xd6\xa6\xcc\x34\xa4\xb0\xb9\x29\xdd\x45\xd7\x04\x75\x44\x97\xc4\xde\x94\xaf\x3d\x08\x68\x70\x4a\x62\x70\xca\x56\x00\x83\x2d\x4e\x19\x69\xf8\x0c\x26\xa7\xcc\x34\x94\xa0\xcd\x29\xdd\x65\xcf\x3d\x24\x81\x25\xa1\xb7\x94\xf9\x87\x44\xb0\x24\xe4\x96\x6a\x0b\x20\x19\xa8\x38\x8d\x76\xa7\xcc\x34\xb4\x06\xc3\x53\xba\xab\xae\x1d\xda\xd8\x26\x96\xa7\x7c\xed\x41\x40\xd3\x53\x12\xd3\x53\xb6\x02\x18\x6c\x7b\xca\x48\xc3\x67\x30\x3e\x65\xa6\xa1\x04\xad\x0f\x3b\x8c\xc0\x2c\xa7\xba\x60\x93\x37\xe4\x35\x31\x77\x02\x1c\x69\x84\x06\x5b\x71\xd8\x56\x82\xad\xba\xd0\x55\xb1\xa2\x20\x66\xd6\x1c\x0d\x3c\x83\x91\x93\x36\x29\xc0\xe6\x65\x84\x1c\x4f\xfc\x8d\xd1\x1c\x7e\x47\xf8\x11\x80\xc0\x98\x8e\x01\xb6\x12\x20\x1c\xd9\x81\x38\x0d\xf1\x1d\x88\x16\x8a\xf2\xea\xa1\x40\x0f\x03\x70\xaa\xc3\xe1\x1e\x83\x6e\x25\x68\x4b\xd0\x07\x62\xb7\x85\x7e\x20\x01\x63\x00\x58\x0f\xc4\x80\xf8\x3d\x27\x3f\x18\x09\x32\xe0\x56\x02\x36\xc7\x83\x20\x6e\x4b\x54\x08\xa2\x37\xc5\x86\xb5\x3d\x3c\xc4\xaf\x39\xed\xa1\x20\x91\xc1\xb6\x12\xac\x31\x54\x04\x31\x9b\x03\x46\x10\xb9\x21\x6c\xac\x87\x22\x47\x0c\xc0\x69\x0f\xc7\x8f\x0c\xba\x95\xa0\x2d\x51\x24\x88\xdd\x16\x4b\x82\x04\x8c\x11\x65\x6d\x0f\x2a\xf1\x6b\x4e\x7d\x28\xb4\x64\xb0\xad\x04\x6b\x0c\x30\x41\xcc\xe6\x30\x13\x44\x6e\x08\x36\x89\x71\x31\xc5\x9b\xd4\x04\x95\xaf\x12\x14\x18\x75\x32\xc8\x56\x86\x84\x63\x4f\x18\xab\x21\x02\x85\x11\x43\x71\x28\xb1\x26\xd6\x50\x94\x1a\x9e\xf2\x55\x02\x35\x07\xa4\x0c\xbc\x95\xc1\x2d\x61\x29\x8c\xdf\x16\x9c\xc2\x24\x8c\x21\x2a\x31\x2b\xb6\x28\x95\x1a\xa0\xf2\x55\x82\x34\xc6\xaa\x0c\xba\x95\xa1\xcd\x11\x2b\x8c\xdd\x12\xb7\xc2\x04\x4c\xd1\x2b\xb1\x2f\x96\x00\x96\x1a\xa2\xf2\x55\x02\x34\x85\xb1\x0c\xb8\x95\x81\x8d\xc1\x2c\x8c\xdb\x1c\xd2\xc2\xe8\x0d\x81\x2d\x31\x2e\xd6\xd8\x96\xda\xa1\xf2\x55\x02\x35\x47\xb8\x0c\xbc\x95\xc1\x2d\x71\x2e\x8c\xdf\x16\xed\xc2\x24\x8c\x31\x2f\xb1\x34\x96\xb0\x97\x9a\xa4\xf2\x55\x02\x34\x05\xbf\x0c\xb8\x95\x81\x8d\x21\x30\x8c\xdb\x1c\x08\xc3\xe8\x0d\xe1\x70\x3d\x18\x11\x33\x08\x6e\x9f\x47\xc4\xc5\x7d\x8d\x56\xad\x61\x8c\x8e\x2d\x54\xcc\x31\xb2\x85\x10\x14\x29\x5b\xbe\x74\xe5\x6e\x9e\x98\x43\x65\xfc\x8e\x70\x26\x00\x81\xa1\x32\x03\x6c\x25\x40\x38\x54\x06\x71\x1a\x42\x65\x10\x2d\x14\x2a\xe7\xc9\x40\xa8\x8c\x01\x38\xd5\xe1\x50\x99\x41\xb7\x12\xb4\x25\x54\x06\xb1\xdb\x42\x65\x90\x80\x31\x54\xce\x13\x7b\xa8\x8c\xdf\x73\xf2\x83\xa1\x32\x03\x6e\x25\x60\x73\xa8\x0c\xe2\xb6\x84\xca\x20\x7a\x53\xa8\x9c\x27\xd6\x50\x19\xbf\xe6\xb4\x87\x42\x65\x06\xdb\x4a\xb0\xc6\x50\x19\xc4\x6c\x0e\x95\x41\xe4\x86\x50\x39\x4f\x06\x42\x65\x0c\xc0\x69\x0f\x87\xca\x0c\xba\x95\xa0\x2d\xa1\x32\x88\xdd\x16\x2a\x83\x04\x8c\xa1\x72\x9e\x58\x43\x65\xfc\x9a\x53\x1f\x0a\x95\x19\x6c\x2b\xc1\x1a\x43\x65\x10\xb3\x39\x54\x06\x91\x1b\x42\x65\x62\x5c\x4c\xa1\x32\x35\x41\xe5\xab\x04\x05\x86\xca\x0c\xb2\x95\x21\xe1\x50\x19\xc6\x6a\x08\x95\x61\xc4\x50\xa8\x4c\xac\x89\x35\x54\xa6\x86\xa7\x7c\x95\x40\xcd\xa1\x32\x03\x6f\x65\x70\x4b\xa8\x0c\xe3\xb7\x85\xca\x30\x09\x63\xa8\x4c\xcc\x8a\x2d\x54\xa6\x06\xa8\x7c\x95\x20\x8d\xa1\x32\x83\x6e\x65\x68\x73\xa8\x0c\x63\xb7\x84\xca\x30\x01\x53\xa8\x4c\xec\x8b\x25\x54\xa6\x86\xa8\x7c\x95\x00\x4d\xa1\x32\x03\x6e\x65\x60\x63\xa8\x0c\xe3\x36\x87\xca\x30\x7a\x43\xa8\x4c\x8c\x8b\x35\x54\xa6\x76\xa8\x7c\x95\x40\xcd\xa1\x32\x03\x6f\x65\x70\x4b\xa8\x0c\xe3\xb7\x85\xca\x30\x09\x63\xa8\x4c\x2c\x8d\x25\x54\xa6\x26\xa9\x7c\x95\x00\x4d\xa1\x32\x03\x6e\x65\x60\x63\xa8\x0c\xe3\x36\x87\xca\x30\x7a\x43\xa8\xcc\x4f\x23\x9b\x43\x65\x06\xc1\xed\xf3\x88\x50\xb9\xaf\xd1\xaa\x35\x8c\xa1\xb2\x85\x8a\x39\x54\xb6\x10\x1a\x19\x2a\xf3\xcd\x58\xb9\x9b\x1d\xcc\xa1\x32\x7e\x47\x38\x13\x80\xc0\x50\x99\x01\xb6\x12\x20\x1c\x2a\x83\x38\x0d\xa1\x32\x88\x16\x0a\x95\xb3\xc3\x40\xa8\x8c\x01\x38\xd5\xe1\x50\x99\x41\xb7\x12\xb4\x25\x54\x06\xb1\xdb\x42\x65\x90\x80\x31\x54\xce\x0e\xf6\x50\x19\xbf\xe7\xe4\x07\x43\x65\x06\xdc\x4a\xc0\xe6\x50\x19\xc4\x6d\x09\x95\x41\xf4\xa6\x50\x39\x3b\x58\x43\x65\xfc\x9a\xd3\x1e\x0a\x95\x19\x6c\x2b\xc1\x1a\x43\x65\x10\xb3\x39\x54\x06\x91\x1b\x42\xe5\xec\x30\x10\x2a\x63\x00\x4e\x7b\x38\x54\x66\xd0\xad\x04\x6d\x09\x95\x41\xec\xb6\x50\x19\x24\x60\x0c\x95\xb3\x83\x35\x54\xc6\xaf\x39\xf5\xa1\x50\x99\xc1\xb6\x12\xac\x31\x54\x06\x31\x9b\x43\x65\x10\xb9\x21\x54\x26\xc6\xc5\x14\x2a\x53\x13\x54\xbe\x4a\x50\x60\xa8\xcc\x20\x5b\x19\x12\x0e\x95\x61\xac\x86\x50\x19\x46\x0c\x85\xca\xc4\x9a\x58\x43\x65\x6a\x78\xca\x57\x09\xd4\x1c\x2a\x33\xf0\x56\x06\xb7\x84\xca\x30\x7e\x5b\xa8\x0c\x93\x30\x86\xca\xc4\xac\xd8\x42\x65\x6a\x80\xca\x57\x09\xd2\x18\x2a\x33\xe8\x56\x86\x36\x87\xca\x30\x76\x4b\xa8\x0c\x13\x30\x85\xca\xc4\xbe\x58\x42\x65\x6a\x88\xca\x57\x09\xd0\x14\x2a\x33\xe0\x56\x06\x36\x86\xca\x30\x6e\x73\xa8\x0c\xa3\x37\x84\xca\xc4\xb8\x58\x43\x65\x6a\x87\xca\x57\x09\xd4\x1c\x2a\x33\xf0\x56\x06\xb7\x84\xca\x30\x7e\x5b\xa8\x0c\x93\x30\x86\xca\xc4\xd2\x58\x42\x65\x6a\x92\xca\x57\x09\xd0\x14\x2a\x33\xe0\x56\x06\x36\x86\xca\x30\x6e\x73\xa8\x0c\xa3\x37\x84\xca\xfc\xf0\xb5\x39\x54\x66\x10\xdc\x3e\x8f\x08\x95\xfb\x1a\xad\x5a\xc3\x18\x2a\x5b\xa8\x98\x43\x65\x0b\xa1\x91\xa1\x72\x77\x5e\x20\x77\xdb\xcc\x1c\x2b\xb7\x19\x8b\x6b\x05\x20\x30\x56\x6e\xf9\x6e\x58\x11\x10\x8e\x95\x41\x9c\x86\x58\x19\x44\x0b\xc5\xca\x6d\x36\x10\x2b\xb7\x19\x8b\x66\x05\x48\x73\xac\xdc\xf2\xed\xb1\x22\xb4\x25\x56\x06\xb1\xdb\x62\x65\x90\x80\x31\x56\x6e\x33\x7b\xac\xdc\x66\x2c\x9e\x15\x00\x8d\xb1\x72\xcb\xf7\xce\x8a\xc0\xe6\x58\x19\xc4\x6d\x89\x95\x41\xf4\xa6\x58\xb9\xcd\xac\xb1\x72\x9b\xb1\x88\x56\x80\x33\xc5\xca\x2d\xdf\x58\x2b\xc2\x1a\x63\x65\x10\xb3\x39\x56\x06\x91\x1b\x62\xe5\x36\x1b\x88\x95\xdb\x8c\x45\xb3\x02\xa4\x39\x56\x6e\xf9\x7e\x5b\x11\xda\x12\x2b\x83\xd8\x6d\xb1\x32\x48\xc0\x18\x2b\xb7\x99\x35\x56\x6e\x33\x16\xd1\x0a\x70\xa6\x58\xb9\xe5\xdb\x71\x45\x58\x63\xac\x0c\x62\x36\xc7\xca\x20\x72\x43\xac\x4c\x8c\x8b\x29\x56\xa6\x26\xa8\x7c\x95\xa0\xc0\x58\xb9\xe5\xbb\x75\x25\x48\x38\x56\x86\xb1\x1a\x62\x65\x18\x31\x14\x2b\x13\x6b\x62\x8d\x95\xa9\xe1\x29\x5f\x25\x50\x73\xac\xdc\xf2\xed\xbb\x12\xb8\x25\x56\x86\xf1\xdb\x62\x65\x98\x84\x31\x56\x26\x66\xc5\x16\x2b\x53\x03\x54\xbe\x4a\x90\xc6\x58\xb9\xe5\x7b\x7b\x25\x68\x73\xac\x0c\x63\xb7\xc4\xca\x30\x01\x53\xac\x4c\xec\x8b\x25\x56\xa6\x86\xa8\x7c\x95\x00\x4d\xb1\x72\xcb\x37\xfe\x4a\xc0\xc6\x58\x19\xc6\x6d\x8e\x95\x61\xf4\x86\x58\x99\x18\x17\x6b\xac\x4c\xed\x50\xf9\x2a\x81\x9a\x63\xe5\x96\xef\x07\x96\xc0\x2d\xb1\x32\x8c\xdf\x16\x2b\xc3\x24\x8c\xb1\x32\xb1\x34\x96\x58\x99\x9a\xa4\xf2\x55\x02\x34\xc5\xca\x2d\xdf\x2e\x2c\x01\x1b\x63\x65\x18\xb7\x39\x56\x86\xd1\x1b\x62\x65\x7e\xd6\xdc\x1c\x2b\xb7\x59\x1f\xc5\xca\xd0\xa6\x58\xb9\x15\xf6\x0f\x2b\x35\x8c\xb1\xb2\x85\x8a\x39\x56\xb6\x10\x02\x63\xe5\x79\x83\xda\xc6\x65\x79\x06\x2e\xe4\x07\x3d\xa1\xad\xa5\x1e\x60\xa0\x2c\xe3\x8b\x7e\x5a\x51\x83\x6c\xaa\xf3\x29\x0e\x1b\x74\x51\x0f\x3f\x92\xb7\x5d\x21\xca\xb2\xb4\xac\xd3\x1a\x38\x00\xc9\x10\x91\xb3\xbd\x02\x6b\xea\x01\x5f\xf2\x8a\x1e\xee\x15\xa0\xb4\x13\xbe\xe4\x1d\x3b\x48\x2f\xc0\x69\x67\xe4\xcd\xfb\xb7\x49\x2d\x7e\x0a\x7c\x88\xa1\xee\x24\xf8\x20\x4f\x7d\x52\x7a\x1b\x5b\x96\xcd\x32\xa4\x1a\x3f\x15\x3e\xc4\x57\x77\x32\x7c\x90\xaf\x3e\xe1\xe9\x44\xbe\xf8\x97\x09\x2a\xbd\xc3\x38\xbe\xba\x93\xe2\x83\x7c\xf5\xc9\xb4\x26\xf2\xd5\x4d\x03\x49\x3d\x7e\x6a\x7c\x88\xb1\xee\xe4\xf8\x20\x63\x7d\xa2\x06\x2b\x63\xac\x15\xc5\x0b\xaa\xe2\xb0\x46\x17\x36\x5a\xc2\x53\xbd\x2f\xaa\x7c\xd7\xbd\xd0\xf0\x9f\xcb\x12\xae\xd2\xbd\xd0\xf5\x3d\x2c\xd3\x26\xcc\xd2\x7f\x6a\x75\xfa\x37\x62\xa5\x7d\x71\x6a\xdc\x17\x72\x12\xd5\xcd\xe8\x79\xf9\xbe\x64\xb7\xf0\x3c\x13\x30\x3d\xef\x2b\x41\x2f\xcd\xd0\x51\x91\x25\x12\xec\x06\x80\x25\xec\xc5\x14\xac\x6e\x5e\x33\xb4\xa3\x25\x5a\x23\x89\xe5\xb8\xc4\x45\x56\x54\xbb\x0f\xfb\xfd\x5e\x03\x28\xab\x34\x0f\xab\x57\x0e\xe2\x79\x9b\x48\x82\x0a\x25\x30\x7a\x1e\x7a\xa6\x14\x1e\xb1\xc5\xea\x31\xac\x83\x58\x67\xa4\x46\x71\x71\x4a\x04\x4a\xdb\xf5\x16\x3d\xad\x75\x4a\x1d\xa0\x4c\xab\x2f\x96\xa8\xad\xe3\xcd\x6a\x93\xe8\xd4\xce\x71\x8c\xea\x9a\x43\x05\xdb\x70\xb3\x5c\x01\xb4\x28\x98\x42\x89\x15\x4a\x74\x7c\xb4\x41\x8b\xa5\x46\x27\x3d\xed\x8b\x0e\x64\x13\x06\xd1\x56\x27\x82\x61\x64\x0a\xa4\x44\x46\xef\x6f\xc2\x6d\xa4\x4b\x2f\xac\x4e\xe9\xe9\xd0\xcb\x2f\xf6\xbd\x8d\x4e\x81\x81\xc9\x44\x78\xa1\x44\x27\x59\x3c\x21\x59\x9d\x08\x6c\x12\x9e\x0e\x02\x50\xbc\x58\x41\xbd\x45\xa1\x64\x2a\xac\x4c\x22\x12\x25\x81\xbf\xd0\x89\xd0\x31\xc3\x9b\xb2\xdd\x3f\xed\x43\x9d\x06\x01\x92\x49\xd0\x22\xb9\x19\x21\xf2\xd0\x0a\x68\x46\xf5\x8d\x83\x2c\x96\x8b\x70\xe9\x41\x8d\xa8\xbe\xa9\x4d\xa8\xbe\x29\xd2\x48\x02\x3f\xd0\x85\x9d\x9f\x1b\x94\x18\xd5\x97\xc2\x1c\xd3\x04\x91\x61\xb9\xf3\x3e\x7b\x4e\xf8\x4c\xa1\x89\x69\x29\xc3\x0a\x9d\x1a\xea\xe2\xeb\x63\x98\x14\x2f\xf4\xc0\x7f\x14\xc6\xdf\x0e\x24\x81\x90\xab\x43\xf7\x59\x0b\x58\x4e\x81\x0b\xf9\x9b\x66\x69\xf3\xca\xd3\x0c\x88\x4c\xa4\x27\x00\x8e\x06\x17\x02\xd8\xff\xf8\xfc\x87\x0f\x4e\x5d\x9c\xab\x18\xfd\x12\x96\x65\x7a\x3a\xfc\xd7\x7f\xfe\xed\x4b\x54\x14\x4d\xdd\x54\x61\x39\xcf\xd3\xd3\x3c\xae\xeb\x79\x1e\x96\xce\x1f\x3e\xff\xff\x01\x00\x00\xff\xff\xc4\xaa\x95\x3d\x6f\xf1\x01\x00") func cmdInternalPagesAssetsStylesBootstrap400Beta2MinCssBytes() ([]byte, error) { return bindataRead( _cmdInternalPagesAssetsStylesBootstrap400Beta2MinCss, "cmd/internal/pages/assets/styles/bootstrap-4.0.0-beta.2.min.css", ) } func cmdInternalPagesAssetsStylesBootstrap400Beta2MinCss() (*asset, error) { bytes, err := cmdInternalPagesAssetsStylesBootstrap400Beta2MinCssBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "cmd/internal/pages/assets/styles/bootstrap-4.0.0-beta.2.min.css", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x41, 0x4c, 0xaa, 0x66, 0xbb, 0x79, 0xbc, 0x88, 0xc1, 0xba, 0x6a, 0x2a, 0x41, 0x5d, 0x23, 0x33, 0xc0, 0xa0, 0x1a, 0xab, 0x1c, 0x15, 0xf7, 0x46, 0x84, 0xdf, 0xa7, 0x54, 0x2a, 0x97, 0xd2, 0xf7}} return a, nil } var _cmdInternalPagesAssetsStylesBootstrapTheme311MinCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x5a\x4d\x6f\xdb\x38\x13\xbe\xe7\x57\xe8\x45\xf1\xa2\x4d\x61\xc9\xfa\xb0\x63\xcb\x41\x73\xd8\x6e\xb1\x08\xd0\xee\x65\x73\xd8\x2b\xbf\xe4\x08\xb5\x25\x81\xa2\x13\x17\x81\xff\xfb\x82\xa4\x64\x4b\x36\x69\xda\x94\xe5\x1c\x1a\x21\x68\x45\x51\xcf\x8c\x1e\x3e\x24\x67\x86\x19\x7e\xfe\xdf\x8d\xf3\xd9\xf9\x23\xcf\x59\xc9\x28\x28\x9c\x97\xc8\x0b\xbc\xc0\xf9\xf4\xcc\x58\x31\x1b\x0e\xe7\x84\xc1\xfa\x99\x87\xf2\xe5\x2d\xef\xfd\x35\x2f\x7e\xd1\x74\xfe\xcc\x9c\xd0\x0f\x02\x37\xf4\x83\x91\xf3\xf4\x9a\x32\x46\xe8\xc0\x79\xcc\x90\xc7\x3b\x7d\x4f\x11\xc9\x4a\x82\x9d\x55\x86\x09\x75\x7e\x3c\x3e\x49\xd0\x92\xa3\xa6\xec\x79\x05\x39\xde\x90\xbd\xc2\x72\xb8\x35\x31\x84\x8b\x1c\x0e\x97\xa0\x64\x84\x0e\xbf\x3f\x7e\xfd\xf6\xf7\x3f\xdf\xb8\xc9\xe1\xcd\x8d\x07\x59\xe6\x62\x92\x80\xd5\x82\x0d\xc4\x4d\x41\xd3\x25\xa0\xbf\xe4\x4d\xb9\x42\x88\x94\xa5\xbc\x49\xb3\x24\x97\xff\x7b\x05\x34\x4b\xb3\xb9\xbc\xc1\x20\x9b\x13\xfa\xc6\xc8\x9a\xb9\xe5\x33\xc0\xf9\xeb\xcc\x77\xdc\xa0\x58\x3b\xbe\x43\xe7\x10\x7c\xf2\x07\xfc\xf2\xc2\xdb\x7b\xf7\x95\xc0\x9f\x29\x73\x61\xbe\xae\xbb\xa6\x59\x49\x98\xe3\x3b\x8d\xfe\xe1\x78\x3c\xa8\x7f\xbd\x60\x7c\x3b\x90\x4f\xf9\x6f\x13\xcf\x9f\x8c\x6f\xef\x2f\x86\xb4\x69\x32\x31\x03\x88\xa5\x2f\xa4\x45\x48\xab\xad\xe2\xa5\xd5\xc6\xe9\x69\x35\x54\x2c\xb5\xda\x24\x59\xed\x26\x69\xd3\x53\xd8\xf4\x14\x36\xbd\x7d\x9b\x9e\xc2\xa6\x77\x68\xb3\x6a\x7a\x3b\x32\x06\x51\xb1\x76\xc6\x7b\xdc\x04\xa1\x9a\x65\x5d\x5f\xc1\x63\xf3\xfb\x6a\xbb\x10\xa0\x9f\x73\x9a\xaf\x32\xec\xa6\x4b\x30\x27\xb3\x2c\xcf\x48\x8b\xf5\xc3\x2e\xb5\xaf\x8b\x34\x23\x80\xba\x73\x0a\x70\x4a\x32\xf6\x89\xe5\xc5\xe0\x43\x92\x24\x8e\x3f\xf8\x40\x7c\x7e\x39\x81\xef\xff\xff\xf6\xfe\x00\xe1\xf0\x4d\x07\xe6\x8c\xe5\x4b\xf5\xfb\x49\xba\x60\x84\xce\x0a\x9a\xcf\x53\x3c\xfb\xf3\xdf\x47\x0e\xf2\x44\x41\x56\x26\x39\x5d\x7a\x3f\x52\x44\xf3\x32\x4f\x98\xb7\x05\x2c\x19\xa0\xec\x6b\xbe\xc8\x69\xc9\xe8\x97\x8f\x1c\x55\xfc\x7c\x1c\x38\x24\xc3\xad\x07\xd2\xd2\xc7\x81\xf3\x57\xf5\xf2\xd3\xaf\x82\x7c\xf1\x6d\xac\x92\x0c\xc0\x05\xc1\x5f\x12\xb0\x28\x49\xeb\xb3\x29\x29\x08\x60\x33\xf9\x8f\xbb\xbe\x87\x39\xc5\x84\xba\x88\x3b\x32\xfb\x80\x21\xbf\xee\xdb\x73\x55\x4e\x18\xee\xf9\x5e\x6f\x84\x50\x7b\x5a\x3c\xe7\x2f\x84\xb6\x54\x3b\x4b\x72\xb4\x2a\x9b\x23\x57\xbd\x2b\x3f\xb6\xe9\x59\x91\x97\x29\x4b\xf3\x4c\xac\x0e\xe3\x62\xad\x9f\x71\xed\x19\x71\x04\x5c\xf1\x6d\x9b\xe6\xfc\x39\x53\x51\xa3\x70\x0a\x11\xe0\xa2\x08\xf1\x1d\x02\xa1\x85\xa8\x34\x10\x97\xd0\x95\x84\x56\xe8\x4a\x5a\x7a\x57\x5d\x85\xf0\xee\x2e\x06\x2d\xee\x9b\x62\xa9\x9b\x74\x62\x91\x5f\x60\x16\x8b\x6a\x29\x6e\x2f\x95\x47\xc0\xb5\x0e\x57\x0b\xeb\x99\x62\x19\x23\x38\x1d\x23\x3e\xd2\xa3\x20\xbe\x1b\x05\x16\x62\xd1\x40\x5c\x42\x2c\x12\x5a\x21\x16\x69\xe9\x5d\xc5\x12\x91\x69\x12\x91\x16\xf7\x4d\xb1\xd4\x4d\x3a\xb1\xc8\x2f\x30\x8b\x45\xb5\x47\xb7\xf7\xd0\x23\xe0\x5a\x87\xf9\x8e\x7b\xae\x52\x20\xf2\x31\x11\x6b\x02\x00\x10\xdb\x2c\x2b\x1a\x88\x8b\x28\x45\x40\xab\x96\x15\x61\xe9\x7d\x97\x95\x29\x18\xa1\x78\x47\x7c\x53\x26\xe2\x5e\xbb\xa0\x08\xdf\xcd\x1a\x39\x88\xd9\x1a\x01\xd5\x11\x58\xad\x93\x55\xf8\x75\x6e\x24\xe3\x03\x3c\x12\xa3\x4b\x60\x1c\x05\x77\x36\xc1\x8c\x1a\xe2\x22\xf1\x8c\x80\x56\xc5\x33\xc2\xd2\xbb\x0a\x84\x44\x53\x1c\x44\x2d\xee\x9b\x1a\xa9\x9b\xb4\x41\x8a\xf8\x02\xb3\x4c\x54\x91\x7c\x3b\xd2\x3e\x02\xae\x75\xb8\x4a\x9c\xce\xd3\x0a\x8e\xc7\xd1\x48\x04\xae\x28\x08\x49\x08\x2c\xb4\xa2\x81\xb8\x84\x56\x24\xb4\x42\x2b\xd2\xd2\xbb\x6a\x05\xc6\x21\x0a\xa7\x4d\xea\x5b\xf1\xac\x6c\xd1\x29\x45\xfa\x7f\x42\x38\xab\xc8\xef\x5a\xe9\x97\x1e\x5a\xe9\x2c\x7b\x5e\x2d\x61\x06\xd2\xc5\xc0\x4b\x97\x73\x77\x7b\xab\x4a\xe3\x64\x24\x1f\x1a\xd2\x64\x7d\xaf\x8d\x87\x69\x5e\xe0\xfc\x35\x73\x97\x24\x5b\x3d\x2c\xd2\x07\x50\x53\xa4\x78\x72\x40\xd5\x29\x2b\xdd\x98\x5f\x62\x99\x9a\xf2\xcb\x66\xa5\x33\x42\xec\xcb\xe0\x22\x8b\xa0\xb0\xaa\x5a\x04\x85\x13\x0a\x61\x2b\x16\x04\xd1\x75\x9f\xe5\x4a\x18\x0f\x60\x9f\xe4\xed\x03\xf5\x18\xec\x1e\xdb\x0c\xc4\x2e\x4f\x89\xc6\x13\x02\x71\xa7\x54\x47\x07\xd1\xc7\x40\x68\xb3\x20\xe9\xc4\x49\x03\x21\xbb\x6e\xbc\x0c\xbc\x40\x40\xbb\x95\x1f\x92\x29\xbf\xec\xcb\x0f\xba\xf7\x7b\x11\xb1\xae\x32\x21\x9d\xe8\x65\x75\x96\xab\x1a\x7f\xba\x2a\x67\xa3\x62\xdd\xad\x06\xb8\x5f\x71\xb2\xaf\x01\xaa\x90\xf6\x15\xe1\xd4\xf7\x19\x78\xd9\xcd\xb7\x33\x75\x42\x20\xbf\xc4\x50\x47\xfc\xb2\x90\x8a\x19\xa2\x0f\xb5\x48\xab\x2a\xb5\x08\x27\x14\x6a\x31\x94\x16\xe3\x13\x07\x4f\xd7\x77\x3b\x3c\x90\x82\x0c\x0f\x9a\x83\xc3\x37\xa4\x37\x55\x55\xeb\x50\x02\x61\x03\x28\xcd\x5e\x08\x2d\x15\xb5\xc9\xa3\x23\x1a\x21\x7e\x89\x64\x2c\xb4\x49\xe6\x0c\xef\xf7\x31\x96\xd2\xa4\x2a\xc9\x13\x3f\x3d\xcc\xfc\x7d\x8e\x2f\x32\x97\x38\x5f\x9c\xb6\x29\xbf\x2c\x98\x37\xbc\xdf\x07\xf3\x5b\x82\x0f\x98\x17\x4e\x74\x9f\x45\x47\xea\xf3\x8a\xae\xda\x61\x69\xcf\x29\xd5\xa0\x29\xe6\x98\xea\x94\xa7\x61\xa3\x64\x80\xa5\xc8\xe5\x43\x57\x37\x25\xe9\x9a\x60\x45\x8b\x1c\xa1\xb7\xf6\x76\xe1\x6f\x3c\xb0\x20\x94\x9d\x3a\xb3\xad\x0e\x98\xc2\xed\x96\x70\x10\x13\x9f\xb7\xb7\x1c\x05\xaa\xbe\xc4\xb2\xd6\x88\x93\xc4\xc7\x53\x91\xb1\x4d\xc9\x18\x22\x9b\xa4\xcf\x08\xd1\x87\xfa\xa5\x55\x55\x3e\x28\x9c\x50\x45\x6b\xed\x34\x28\xc4\x10\x04\x35\x79\x16\xb5\x37\x1c\x13\x9c\x4c\xf8\x67\xc3\x18\x93\xc4\xe6\x9c\xc8\x0c\xd1\x0b\x73\xc2\xaa\x82\x39\xe9\x84\x91\xb9\x18\xa0\x84\x80\x9a\x39\xcb\xba\x14\x4a\xa6\x24\x92\x51\x2a\x49\x90\xd5\x21\x9b\x11\xa2\x97\x40\x57\x58\x55\x06\xba\xdc\x09\x23\x79\xc9\x98\x4c\x62\x52\x93\x67\x55\xa7\x49\x42\x4c\x64\xc5\x96\x4c\xf8\xe6\x6b\xc3\x9d\x11\xa2\x17\xee\x84\x55\x55\xa6\x2b\x9c\x30\x72\x87\x11\x98\x80\xc9\xc6\xe3\x4e\xd0\xf3\x97\xba\x46\xac\x2b\x13\xfd\x4e\xe1\xb2\x06\xe2\xba\xe1\x72\x5d\x3a\xd8\xe3\x6d\x47\x91\x0b\xc1\xb9\xf2\x6a\x24\xdf\xfe\x24\x00\x71\xb7\xfc\x5d\x03\x71\xdd\xfc\x5d\x38\x61\xa2\xa9\xfb\x61\xdd\x28\xc6\xa3\x51\xb7\xc3\x3a\x0d\x44\x1f\x74\xe9\xcf\xf1\x84\x13\x46\xba\x3a\x1d\x57\x45\x01\xf4\xb1\xcd\x0c\x34\x43\xf4\xc2\x95\xee\x24\x4b\x3a\x61\xe4\xaa\xf3\xe1\x0d\x8a\x27\x41\xd2\xed\xf0\x46\x03\xd1\xcb\x42\xaf\x3d\xd7\x11\x4e\x18\xe9\xea\x7a\x7c\x11\x47\x7e\x68\x15\xc9\x1a\x21\xfa\x89\xc7\x74\x27\x1b\xc2\x09\x15\x5b\x8b\xb4\x64\x2e\x77\xa9\x78\x3b\xa9\x0c\xd6\xbd\x7e\xbf\xb3\xe8\xa6\x8c\x2c\xb7\x7f\x05\xa6\x6e\xaf\xeb\xca\x9a\xa7\xb2\xac\xac\x4c\xf8\xaa\x1d\xe3\x70\xd8\x4e\xdd\xb3\xc2\xc9\x14\xda\x84\x44\x66\x88\xeb\xee\x59\xc2\x09\x63\x48\x24\xbb\x6d\xbc\x02\x64\xe4\x9c\x93\x9b\x93\x06\x9e\x8f\xbb\x00\xae\xab\x96\x0f\xd5\xed\x33\x01\xd8\x62\x39\xfb\x6d\x4e\x68\x6a\xda\xaa\x3f\x20\xea\x46\xdb\xef\x73\x9e\x52\xd3\x56\x05\x62\xdd\x68\xdb\x55\x25\xb0\x4f\x62\x64\xf3\x97\x0f\x66\x88\xab\x16\x36\xa4\x13\x7a\xda\x78\x40\xd6\x91\xb3\x6d\x3d\x02\x8d\x88\xdd\x81\x82\x19\xe2\xaa\x25\x0d\xe9\x84\x9e\xb3\x2a\x30\xeb\xb8\xb0\xed\x2a\x11\x20\x09\x91\x4d\xe4\x61\x86\xb8\x6e\x31\x43\x38\xa1\xa7\x4d\x06\x68\x1d\x59\xdb\xd5\x20\x20\x42\x76\xac\x19\x21\xae\x5b\xc6\x10\x4e\xa8\x58\x7b\x25\x8b\xc5\xb9\xd5\x0a\xb9\xc1\x75\xaa\x56\x18\x21\x7a\xa9\x56\xd4\x9b\xe2\xa9\xd5\x8a\x83\x2a\x0f\xbf\x4c\xf5\xf6\xe8\x30\x58\x19\x1c\x39\x9c\xd5\x96\xdb\xcf\xc5\xd9\xdc\xfc\x17\x00\x00\xff\xff\x3b\xfc\x2f\xb1\x82\x33\x00\x00") func cmdInternalPagesAssetsStylesBootstrapTheme311MinCssBytes() ([]byte, error) { return bindataRead( _cmdInternalPagesAssetsStylesBootstrapTheme311MinCss, "cmd/internal/pages/assets/styles/bootstrap-theme-3.1.1.min.css", ) } func cmdInternalPagesAssetsStylesBootstrapTheme311MinCss() (*asset, error) { bytes, err := cmdInternalPagesAssetsStylesBootstrapTheme311MinCssBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "cmd/internal/pages/assets/styles/bootstrap-theme-3.1.1.min.css", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9a, 0xa3, 0xa3, 0xf9, 0x25, 0xf2, 0xa8, 0xa6, 0x23, 0x60, 0x11, 0x85, 0x51, 0xe5, 0xe1, 0x2c, 0xa9, 0x80, 0x52, 0x74, 0x43, 0x29, 0xb1, 0x3c, 0x5d, 0x4c, 0x10, 0x8b, 0xe7, 0x22, 0xcb, 0xe1}} return a, nil } var _cmdInternalPagesAssetsStylesContainersCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\xb9\xd7\x8e\xe3\x68\x9a\x28\x78\xdf\x4f\x91\x3b\x83\x05\xce\x39\xec\x6c\x7a\x57\x85\xbd\xa0\x11\x45\x27\x7a\x7f\xb3\xa0\x27\x25\x7a\x27\x92\x85\x79\xf7\x85\x22\x22\x23\xb3\x4c\x57\x75\xcf\x6c\x20\x95\x11\xfc\xf9\x7f\xde\x7f\xfa\xdb\x3f\xca\xbe\x2f\x9b\xfc\xeb\x56\xcf\x6b\xdc\xd4\x67\xbc\xd4\x7d\xf7\x75\xe9\xfb\x26\x89\xa7\x5f\x8a\xbe\x5b\xbe\xce\xf5\x99\xff\x04\x43\xd0\xff\xfd\x5f\x7f\x7a\xf9\xcb\x9f\xbe\xfd\x9a\xef\x43\x3f\x2d\x5f\xeb\xf7\x4b\x7f\xff\xff\x01\x55\x16\x2f\xf1\xff\x08\x4f\xb5\xb4\xcd\xd7\xb4\xcf\xf2\x5f\xda\x78\x2a\xeb\xee\xeb\x54\x97\xd5\xf2\xd3\x3f\xe0\xbc\xfd\x73\x51\xbf\x43\xbe\x78\x69\xe2\xee\xed\xed\xbb\xb6\x9e\xf9\x1b\x92\xa4\x6f\xb2\xbf\x40\xd2\x3f\xbe\x26\xeb\xb2\xf4\xdd\x2f\x43\x9c\x65\x75\x57\xfe\x84\x0c\xfb\x5f\xc0\x2c\x53\x1d\x77\x65\x93\xff\x32\xf4\x73\xfd\x7a\xf3\x53\x9c\xcc\x7d\xb3\x2e\xf9\xcf\xef\xcc\x43\x3f\x2f\xfd\xf0\x13\xf4\x17\x68\xd2\x78\x78\x7f\x8e\x93\x26\xff\xe5\x59\x67\x4b\xf5\x66\xe1\x9f\xbf\x71\x02\xfd\xfc\xae\x92\x9f\xa0\x9f\x93\x7e\xca\xf2\xe9\xf3\x8f\xaf\x69\xdf\x34\xf1\x30\xe7\x3f\x7d\xfb\xe3\x2f\x68\xcd\x6d\xdc\x34\x5f\xb3\x3a\x6e\xfa\xf2\x83\x14\x0e\x41\x7f\x29\x69\x52\x97\xbf\x06\xa2\xfe\x05\xa0\x1f\x69\xfd\xb9\x6b\xfc\x88\xff\xf7\xba\x4c\xe2\xf4\x51\x4e\xfd\xda\x65\x2f\x71\xfb\xe9\xa7\xff\x4c\xe1\x8c\x2e\x8a\x6f\xca\x80\x87\xfd\xcb\xdc\x37\x75\xf6\xe5\x3f\xd1\x18\x27\x49\xec\x53\x71\xd4\xbf\xc5\xe3\xd7\xe4\x5f\x67\xf3\x6b\x52\xfe\xf2\x7b\xbe\xb2\x2c\xfb\xf9\xf7\xfc\xbf\xf9\xc0\xcf\x4d\x5e\x2c\x7f\xe9\x0a\xbf\x62\x67\xa9\x97\xbf\x8a\xcd\x1f\x39\x7a\xbb\xfe\x07\x4c\xe5\x50\x9e\x15\xf9\xcf\x1f\x4f\x10\x04\xfd\x9c\xae\xd3\xdc\x4f\x3f\x0d\x7d\xdd\x2d\xf9\xf4\xa3\xb6\xbe\x73\x3f\xe5\x4d\xbc\xd4\x5b\xfe\xf3\x0f\x59\x07\x19\x96\x9f\x7f\x1b\x56\x3f\x6f\xf9\xb4\xd4\x69\xdc\x7c\x8d\x9b\xba\xec\x7e\x6a\xeb\x2c\x6b\xfe\x1d\x2f\xfc\x9a\xf6\xdd\x92\x77\xcb\xbf\x2e\xe8\x07\xc0\x1f\x88\x5a\x14\xc5\xa7\x34\xd8\xb0\xff\x8a\xd9\xae\x9f\xda\xb8\xf9\xb9\xdf\xf2\xa9\x68\xfa\xe7\x4f\xf1\xba\xf4\xff\xb6\x35\xbe\xa6\x4d\x3f\xff\xbb\x36\x79\x07\xfa\x81\xdd\x9f\x96\x29\xee\xe6\x21\x9e\xf2\x6e\xf9\xb2\x4e\xcd\xff\x7a\xbb\xf0\xff\x26\xfd\xfe\x8f\xb2\x2e\xfe\xf7\x97\xae\xff\x3a\xe5\x43\x1e\x2f\x5f\xe6\x74\xea\x9b\xe6\x4b\x9a\xbf\x19\xaa\x7a\x97\x04\xc6\x7f\x34\xd4\x6f\x52\x0e\x0c\x0d\xfb\x9b\xc7\xbd\xac\xf9\x91\x4b\xf0\x7f\x2f\x0c\x3e\xf4\xfb\xa5\x2e\xa6\xb8\xfd\x37\x84\xfd\x35\xdc\x8f\xd9\xe5\x1b\xe7\xe4\xdb\xc3\xef\xc2\x36\x69\xe2\xf4\xf1\x5f\xff\x48\xab\x78\x5a\xe6\xaf\x75\xd7\xd4\x5d\xfe\x35\x69\xfa\xf4\xf1\xcb\xef\xfd\x31\xab\xe7\xa1\x89\x8f\x9f\xbe\xb6\xfd\xf9\x79\xb7\xdf\x3f\xcf\x7f\x04\xff\xaf\xff\xf3\xe5\x55\x1c\xbe\xfc\x11\xea\xbf\xff\x9f\x9f\x8a\x7a\x9a\x97\xaf\x69\x55\x37\x19\xf0\x4f\xef\xfd\xf2\x6b\xc4\x9f\x6c\xb6\x79\xb7\xfe\x68\xd3\x37\xe7\xfb\x9e\x95\xdf\xd2\x54\x9a\x7e\xf9\x4f\x82\x20\x3e\xfe\x4b\xd3\xf4\xdb\x85\x79\x39\x9a\xfc\xa7\x37\xe9\xbf\x1d\x7d\xd8\x6a\xd8\xbf\x85\x67\x96\x17\xf1\xda\xbc\x47\xdc\x87\xf7\x7e\x81\xd1\x61\xff\xc2\x4c\x75\xdc\xfc\x7d\x8e\xbb\xf9\xeb\x9c\x4f\x75\xf1\xbd\x3a\xf4\xeb\xf2\xe2\xf1\xa7\xae\xef\xf2\x1f\x03\xe1\x0b\xf4\x07\xfe\xf2\xd2\x5e\x96\xef\x3f\x21\x10\x04\x41\xbf\x12\xeb\x5b\x25\xfc\x51\xba\x2c\xcb\xde\x5c\x15\x04\xe7\xb9\xf9\x47\x39\x2f\xf1\x52\xa7\xff\x48\xfb\x16\xcc\xb3\x7a\xe9\x27\xf0\x1d\xe6\x6b\x52\xfe\x63\xe8\xca\xff\xfd\xe5\xdd\x81\xbf\xee\x5f\x96\x7e\xf8\xf2\xca\x7d\xdf\x4b\xd7\x3f\xcf\x44\x4d\x3d\x2f\x1f\xba\x79\x13\xe1\x43\x30\x64\xd8\xff\x58\x34\xe8\xe7\x25\xdf\x97\xaf\x59\x9e\xf6\xd3\x9b\x5b\xbe\xbf\xfe\x27\x29\xe9\xf7\x12\x7e\xed\xd7\x25\x9f\x5e\xee\xf3\xf7\x3f\x7a\x5b\x77\xdd\xfb\xdb\x5f\xfe\xb9\xd9\x3e\x84\x89\xe3\xf8\xb7\x64\x97\x7e\xf8\x73\x9a\xbf\xfc\xa6\xaa\x7f\x77\x81\x97\xbd\xbe\x89\xf8\x87\x38\xbe\x73\xf6\x0d\xc7\x97\xaf\xf0\x67\x68\x7d\x20\x82\xbe\xbc\x8e\xbe\x21\x7a\x79\x0e\x36\xec\xbf\x0d\x89\x3f\xc6\xfa\x56\xac\x5e\x18\xff\xec\xfa\xb4\xfc\xf1\xf9\x77\x01\x3f\xd1\x7c\x24\xa7\xb7\x9c\xfb\xdf\xc0\xf8\x9d\xb1\x1f\xf1\xfc\xf3\xf8\xfd\x4b\xa1\xfe\x35\xd0\xbf\x66\xe7\x0d\xe5\x6f\xe4\xfb\xe9\xa7\xa9\xef\x97\x3f\x02\xfc\xe5\x2d\xab\x7c\xe4\x42\xe8\x4f\x2e\xfe\xa8\xc2\x7f\x15\xe4\x07\xa6\xfe\x55\x90\x8f\xc6\xf3\x57\x00\xef\x89\xe6\xcf\xa0\xb2\xa9\x1f\xb2\xfe\xf9\x87\x60\x7f\x78\xbf\x9e\x5f\x8d\x6d\xf6\x63\xbd\xae\xdb\xb8\x7c\x8f\xe5\xff\xab\x6e\x5f\xf3\x43\xdc\x2d\x3f\xf7\x43\x9c\xd6\xcb\xf1\xd3\x3f\xd0\x9f\xdf\x92\xfb\x0f\xcf\x45\xdd\x2c\xf9\xf4\x53\xdc\x0c\x55\xfc\xbf\x3e\xce\xff\x1f\x14\xfa\xdf\x7f\x4a\xf0\xcf\x35\xfb\x87\x11\xff\xa7\xa0\x9f\x1a\xfe\xf7\x41\x3f\x34\xfd\xef\x03\x7e\x2a\xfb\x23\xcf\xa0\x28\xfa\x83\xc6\x7e\x9d\x83\x68\x9a\xfe\xfe\xee\xcf\xc2\xec\x1b\xc5\x3f\x2b\x81\x7f\x68\xc1\xef\xf9\xf8\x95\x5a\x7e\x60\xe4\x33\x5b\xfd\xfa\xfc\x0f\xcd\x53\xbd\x5a\xb0\xff\x86\x6d\xfe\x39\xdc\xef\xf2\xf4\x37\x85\xa4\xc5\x97\xff\x24\xe8\xfc\xe3\x3f\x32\x2e\xfe\x82\xb5\x38\x7d\xb5\x18\x7f\x48\xbd\x1f\xf2\xee\x0f\x3a\xce\x24\x49\x7e\x9c\x4f\x3e\xab\x6c\xd2\x2f\x4b\xdf\xbe\x15\xbe\x3f\xa4\x54\xf4\xe9\x3a\xff\xb7\x5c\xf4\xcf\x20\xff\x89\x22\xfa\x29\xee\xca\x3f\x2e\x80\xdf\x52\xc0\x77\x03\xbe\xb5\x0b\x5f\xa0\x7f\xb5\x9a\x7d\x3a\xe8\x8f\xcd\xe9\x7b\xfd\x21\x5f\x05\xe9\x7b\x0b\xf1\xa7\xdd\xc3\xfb\xaf\x8f\xa6\xf2\xbd\x83\xf8\xde\x05\x7f\x45\x29\xea\xad\x28\xfe\x8b\x3c\x7d\x9b\x85\xdf\x57\x08\x7f\xa8\xc5\x5f\x5f\xf9\x6f\x98\xe1\x5f\x40\xf0\xdb\x22\xfd\xb1\xd1\xf8\xe3\x8a\xfe\x89\xef\xe5\x32\x7f\x4e\xf1\x75\xe3\x2f\xaa\xc6\x07\xc1\x6f\x33\xe7\x7f\x0b\xdb\xef\xd8\x7f\xc7\xf6\x2d\xe9\x7c\x2b\x7d\xdf\x46\xef\xa2\x28\xfe\x9a\xd0\x1f\x5e\xa8\xf2\xf4\xf1\xaf\x3a\xf4\x6f\xa9\x66\x59\xf6\x2b\xaa\xf5\x92\xb7\xbf\xfc\xd0\x60\xfe\x75\xf3\xfc\x4f\x7a\x4e\xe8\x57\xfd\x33\x99\xb7\x6f\x81\x81\xbc\x4d\x55\x55\xbd\xe4\x5f\xe7\x21\x4e\x5f\x20\xcf\x29\x1e\x7e\xc7\xc2\x6f\x9f\x5f\xad\xc4\xb7\x18\x7b\x97\x81\xcc\xdb\x6f\x14\x3e\xfc\x02\x79\xdb\x56\xfc\xa8\x84\xae\x7f\xd3\x4d\xd2\xef\x5f\x7e\x8b\xf0\xef\xbf\xb9\x58\xa7\x7d\xf7\xbb\x4b\xbf\xa6\x08\x23\xbf\xc7\x1f\xa7\x69\xde\xfc\x73\xb8\x0f\xc6\xa0\xdf\x00\xbe\x49\xf4\x6d\x0a\xff\x77\x94\xfd\x7b\x2c\x7f\x58\xfc\xde\xde\xbc\xb1\xf6\xf7\x7f\x03\xe0\x37\x0c\xa5\x69\xfa\x4f\xb2\xfd\x5f\xe0\x79\xa9\xf2\x97\xff\x69\x2f\xf2\x86\xa9\xaa\xcb\xaa\xf9\x5d\x0a\x7a\x7f\xf5\x2a\x66\x7f\xb4\x41\x22\x72\xba\xa0\x7e\x53\xd8\x7f\x7d\xf8\xee\xab\x59\xbf\x2c\xf9\xef\x87\xc7\xef\x93\xc3\xd7\xf7\x12\xf4\xea\xfb\x3f\x8f\x96\x7e\x78\x3d\xff\x81\x31\x3f\xfc\xec\xf7\x8c\xbe\x69\xe3\x07\x3e\xdf\x53\xf2\x4f\x9f\xc9\xf9\x73\x29\x41\x0c\xfb\xfb\x8e\x8b\xf8\x93\xed\xc4\xab\x41\xfe\xe3\xf1\xec\xdb\xae\x82\xf8\x23\xf6\x7e\xdb\x88\xff\x05\xcf\x7f\x78\xfd\x4d\x90\x37\x06\xdf\x98\x78\xe7\xe7\x47\x6a\xfd\xfb\x16\x76\xce\x9b\x3c\x5d\xfe\xd0\xc1\x7e\x4b\xf0\x2f\x21\x7e\xa3\xbc\xff\x49\x09\xc4\x5f\xe1\xfb\x05\xfa\xbd\x6e\xde\xe2\xe4\x97\xef\x2d\xe0\xcf\x59\x3d\xe5\xe9\x9b\xf2\x9b\x65\xfa\xf9\xbb\xc4\xdf\x4b\xfc\x9f\x59\xe8\x63\xa4\x7e\x37\xcd\xdb\xd1\xbf\x68\x8e\x77\x3e\x3e\x6a\xc4\x0f\xd6\xfe\x01\xdd\xef\xba\xa1\x37\xc0\xb6\xcb\xdb\xbe\xab\xd3\xaf\x55\xdd\x2d\xbf\xfc\x76\xa0\x5f\xbb\x2c\x9f\x7e\xb7\x78\xf9\x35\xe0\x9c\x0f\xf1\x14\x2f\xfd\xf4\xa3\x1a\x7e\xb5\xb7\xfc\x1e\x02\x6f\x0c\xbe\xe6\xe0\xbf\xfd\xed\x1f\x2f\x1b\x7c\x6d\xe2\x24\x6f\xbe\xfc\xf2\xb7\x2f\x5f\xbe\x7c\xf9\xdd\x72\xf3\x6f\xff\xf5\xb7\x7f\xac\x5d\xfd\xeb\x5b\x1f\x44\xa8\xb7\x9f\x9f\xbf\x03\xbe\x07\x66\xbd\xc4\x4d\x9d\xbe\x41\xbe\xb7\x93\x5f\xd3\x61\xfd\xa7\xf8\x7f\xc0\x07\xbd\xfd\xbc\x01\xd6\xdd\xef\x40\x7f\x43\xf4\xbf\xfe\xf6\x8f\x29\x7e\x7e\x7d\x49\x30\xff\x88\xbc\x88\xdb\xba\x39\x7e\xfa\xf2\x1f\x5c\xbf\x4e\x75\x3e\x7d\xd1\xf2\xe7\x7f\xbc\x93\xf9\xb1\x6c\x7d\x19\xa6\xfc\xeb\xab\x72\xbd\x93\x9b\xfb\xe6\x63\xab\x57\x2f\x4d\xfe\x6b\x8a\xc2\xdb\xcf\xdb\xbd\x21\x2e\x5f\x03\x5f\x9c\xe5\xd3\x97\x0a\xfe\xb8\xf6\xec\xa7\xec\x0d\xd5\x4f\x5f\x92\x29\x8f\x1f\x5f\x5f\x07\x6f\xd7\xdf\xbe\xcf\xf8\x3a\xf5\xcf\x3f\x64\x30\x7d\x67\xf0\x3f\xfe\xfe\xe5\x3f\xda\xbe\xeb\xdf\xf8\xfa\x8f\x1f\xb5\xf9\x32\xdd\x97\xb7\x76\xf2\xed\xf0\x07\x3f\xfa\xf2\xe6\x5e\xef\xc7\xbf\x49\x26\x5f\x96\x7e\x78\x7f\xf1\xb1\x6e\xfa\xf2\x89\xe0\xc7\x2e\xe6\x0b\xfa\x9b\xd3\x77\x87\xfd\xdd\xf1\x2b\x61\xfe\xee\xf0\x23\xb1\xbe\x9f\xff\xd7\xdf\xfe\x31\xaf\xc9\xab\xf6\xc4\xf5\xab\x57\xf9\xd8\x16\x7e\xad\xbb\x61\x5d\x3e\x04\xff\x15\x65\xec\x1b\xb6\xf7\x84\xf7\x05\x83\xde\xd1\xfc\x67\xd3\x97\xfd\x37\x4d\x35\x7d\xbc\xbc\x85\xcb\xfb\xd5\x8f\x1c\xfb\x05\x79\xdb\x9f\xfe\x8e\x41\xe4\xf3\xf4\xf7\x89\xfa\x7b\x0e\xf9\xdd\x8d\x77\x0d\x7f\xb0\xfe\xbb\xb7\x9f\x09\xe2\xdb\xf6\xf9\xb7\x17\xde\x67\xf8\x57\x4a\xfb\x8f\x2c\x5e\xe2\x9f\xde\x9e\xc1\xa1\x2b\x7f\x4e\xe2\x39\x27\xb0\xbf\xd7\x1e\xab\x5b\x4f\x48\xb9\x96\x3d\xc3\x30\x8c\x66\xbb\xd5\xc5\x2d\x19\x86\x25\xdd\xd7\x63\xcd\x31\x12\xc3\x30\x1c\x8b\x98\x03\xca\x30\x8c\x62\xfb\x0d\x6f\xc2\xec\xe9\x3e\x32\x4e\xba\x34\x82\x79\x86\xbb\xee\x84\x88\xea\x48\xeb\xcd\x64\x98\x5c\x1b\x33\x17\xcd\xc2\x07\x98\xfa\xc6\x02\xa2\x91\x49\xfb\xe6\x72\x7f\xce\x51\x36\x97\x26\x53\x4b\xc4\x53\x3a\x58\x36\xea\x2b\xce\x66\xae\xd7\xcb\x85\x95\x99\x3d\xf4\x25\xae\x09\x5d\xc1\xba\xa6\xb6\x10\x5c\xca\xc5\x55\x6c\x19\x91\xb0\x91\xe9\xd7\x6b\xc6\xd6\x7d\x15\xd7\xb0\x97\xea\x3a\x56\xa0\x4a\x0e\x17\xc1\xb4\x91\x39\x4a\xc2\xe0\x4a\xe1\xf8\xd9\x81\x37\x1c\x3f\x9f\x00\x73\xb1\xa4\xf6\x91\xc7\x75\x5c\x32\xb8\xdb\xbb\x94\xbe\x94\xc5\x1d\xa2\xa5\xfd\xd6\xd2\x25\x23\x79\xb6\xce\x5c\x24\x96\x6f\x0f\x4a\xee\xd8\xd4\x65\x18\x83\xe1\xf3\xa0\x02\x32\x95\x01\x41\xe6\xba\x25\x4f\x86\x63\x44\xde\x53\x6b\xd3\xde\x01\x11\x2c\xc9\xc1\x94\x9b\x94\x91\xe4\x0b\x83\x71\x92\x8d\x3f\x67\xf6\x21\x48\xcc\xc1\xe1\xee\xc1\x9a\xcc\xc1\x96\xcc\x2c\xe8\x67\xc4\xf4\x4c\xc3\x30\x4c\x22\x36\x94\x59\x4b\xcc\x58\x42\x0c\x69\x58\xb2\x51\xba\x0c\xa2\xb4\x0e\xca\xa6\x0c\xa2\x48\xe9\x68\x96\xcc\xdd\xbc\x30\xad\x5d\x89\x32\x23\x33\xeb\x93\x2d\xbd\x50\xb0\x55\x46\x65\x9e\x25\x57\x4e\x17\xa6\x56\x4b\x87\x99\xca\x2b\xe3\x27\xe1\x61\x3d\x15\x66\x33\x5d\x26\xeb\xf1\xf0\xc1\xd0\x4c\xc8\x70\x4c\xeb\x4a\xf3\xc9\x30\xa5\xce\x48\x8c\xb9\x63\xce\x69\xde\x4a\x87\xd1\xcb\x9b\xa6\x80\x98\xd2\x14\xa9\xe4\x63\x36\x73\x61\x9e\xb7\xd5\x3b\xa3\x4c\x85\xee\x37\x77\x95\x03\xf3\xda\x15\x07\xa5\xf3\xb5\x94\xab\x5c\xa2\x0a\x5c\x68\xa5\xc3\xe5\x1a\xca\x38\xa7\xa4\x0d\x3e\xdf\x2f\xd0\xbd\x63\xa0\x53\xe7\x19\x86\xb9\x6e\x9d\xf5\x2c\x30\xcc\xc0\xf9\x0e\x5f\x9d\x0a\x6f\x93\x2e\xd1\x41\x68\x8f\x55\x20\x06\xd9\x4d\xba\x63\x15\x95\x81\xc0\x26\x3d\x39\x96\x61\x4c\x67\x06\x37\xa4\x01\x1b\x3c\x0b\xf9\xf4\x96\xb2\xb3\xe8\x83\x31\xd1\x24\x8c\x36\xf8\xcc\xf5\x5e\x00\x1e\x74\x22\xcf\xb6\xf4\xcb\xc9\xcc\xb7\x56\xcd\x9d\x3b\x65\xb2\x44\xde\x7b\xbc\x64\xb0\x50\xca\x95\xb3\x4a\xda\x5e\xdd\x27\xd0\x13\xc3\x66\x00\x3c\x8d\x2a\x01\x38\xb5\xd8\x12\xca\x64\x49\x00\x41\xa7\x27\x23\x5e\x63\x53\x6e\x97\xa7\xa2\xf3\x60\x20\x54\x49\x17\xaf\x6e\x4f\x76\xc7\xd3\xe2\x6e\x3e\x89\xe2\x87\x01\xec\x98\x07\x82\x21\x36\x40\xb9\x04\xcd\xde\x73\x16\xc2\x69\xf7\xa5\x16\x73\x39\x59\xdb\xd1\x16\x77\x07\xe1\x22\xa5\xad\x87\x55\xea\x50\x9c\xea\x2e\xe2\x09\xcd\x45\x1a\xca\x9b\xdc\x5c\x3d\x40\xc6\x99\x42\x71\x49\x97\xf9\x29\x92\x2b\x63\x2a\x2a\xdf\xdc\xed\xac\x64\x99\x62\xbb\x2d\x77\xb6\x57\x1f\x26\x63\x46\xa7\x79\xe4\x45\xca\x30\xb2\x0e\x02\x21\xcd\x28\xcf\x0b\x73\x46\xf9\x03\x7b\x32\xcc\xa6\x97\x61\xa0\xd4\xae\x00\x9d\x57\x8e\x61\x18\x4b\xe1\x58\x65\x62\x59\xf6\x79\xb2\x82\x72\x32\xfc\x70\xb2\x62\x72\x32\xc2\x53\xae\xd8\x87\xc5\xf0\x9c\xc3\x18\x2c\xcb\xb1\xab\xcd\x88\xcc\x58\x5d\xe5\x88\xbd\x7a\x0e\xa3\x2f\xe5\x65\x49\x18\xfe\x3a\x32\x56\xbb\x5e\xcc\xe5\x76\xd9\x75\x06\xed\x30\x56\x4e\xcb\x7c\x79\x0a\xcf\xa8\xbc\xca\x24\x77\x55\x8f\x2b\x67\x5a\xec\xc1\x94\x4e\x68\x5f\x88\x9a\x15\xea\xfb\x52\xd6\x67\x59\x06\x6d\x88\x5d\xa4\x56\x90\x34\x59\x61\x06\x8e\x1f\x6a\xd6\xb2\xa4\x39\x78\x39\x21\x37\xba\xf2\xf8\xf0\x60\x49\x02\xa5\x25\xad\x4c\xfc\xee\xed\x0c\x30\xf0\xc9\xc1\x31\x47\xbd\x1d\xca\x76\x49\xf7\x46\xba\x1e\xae\x69\xb8\x4c\xe7\x31\x6b\x5c\x16\xd7\x7e\xba\xf6\xa2\x61\x65\xbc\x69\x04\x21\xe7\xf7\xed\x66\x5d\x27\x33\x37\x42\x0e\xe9\xc7\xc2\xb2\x81\x0a\xce\x18\x96\xae\x7b\xfc\x5e\x6a\x97\x9d\x6f\xe3\x1b\xe2\x0b\xe9\x5d\xca\x84\x50\x6a\xc2\x6b\x9d\x88\x42\x6b\x34\x3e\xef\xf9\xf7\xd3\xbb\x8b\x5e\x89\x66\x95\x9b\x3c\x65\xbc\x22\x9f\xe5\x83\xe9\x57\xe6\x02\x3c\xa5\xa0\x37\xcd\x67\x7b\x70\x0f\x99\x15\xfd\xcb\x1e\x9a\x44\xd9\x90\x9c\x0e\x5d\xa6\x5e\xf2\x9e\x2d\x5f\xf1\x22\x27\x1f\x8a\x33\x5e\x00\x48\x0e\x7a\x1b\x48\x2d\x2c\xbc\x8f\xfb\x43\xa8\xae\x13\x97\xac\x92\x85\x55\x5d\xed\xe5\xf2\x13\x73\x02\x5c\x93\x64\x86\x94\x1f\xab\xa5\x73\xf5\xa5\x79\xf0\xb2\xcc\x41\xcd\x64\x6b\x8b\xa4\xc6\x96\x33\xf0\xa4\x7d\xb9\xb6\xa9\xc3\x25\xd3\xe3\x8a\xca\xe8\x6a\x4a\x73\xcf\xcd\x92\x9c\x5b\x0b\xce\x18\x8f\x0b\x60\x03\x54\xc7\xe3\x6a\xea\xea\xb3\x2f\x61\x8f\xa7\xdc\xd7\x96\x3d\xc8\xa6\x6d\xdf\xbd\xc6\x00\xdc\xcb\x10\x51\x87\x39\xb4\xe5\xd8\x88\xda\x18\x91\x2e\xa7\x8c\x92\x3e\xd0\xb1\xed\x23\x65\xd6\x30\x9b\x8b\xe5\xc3\xe5\xb4\xe0\xb6\x0e\xb4\x76\x8f\xf8\x83\x30\x97\x9e\x0e\xcc\xb6\x6d\xba\xb8\xc8\x7a\x15\x68\xa0\xb5\xec\xb2\x72\xc7\x85\x86\xe6\x02\xa8\xdd\x7a\x16\xe8\x3a\x22\x34\xa0\xec\xf9\xd4\xaa\x12\xe1\x77\xa8\xaa\x15\xb6\x99\xae\xc1\x1c\x0d\x7b\x8d\x5e\x6d\x20\x72\x94\x50\x80\xf0\x3c\x3a\x04\xf3\x09\x9f\x52\xd2\xfa\x79\xc8\xe3\xd5\xe6\x79\xe5\x48\xd7\x03\x25\x44\xa2\x72\x19\x5c\xa2\xf1\x62\xaf\x18\x82\x6e\x6c\x2c\x2f\x85\x5d\x10\x0e\xda\x91\x83\xed\xc9\x33\x81\x29\x68\x22\x7a\x78\x44\xde\x0c\xf3\xf7\xd1\xec\x5c\x61\xdc\xbc\xd1\x82\xbd\x95\x78\x20\xd3\x8c\xdb\x19\xac\x18\xee\x8d\xb6\x02\x42\x07\x02\x10\xe1\x80\xf6\xa6\xcd\x7d\x2c\x58\x23\x77\xb5\x15\xcd\x0d\xc9\xe2\x7a\x0d\xa1\x4a\x98\xc3\x23\x2a\x84\xd0\x5c\xa2\xc3\x2b\x8d\x49\xbd\xae\xa1\xe3\xcb\xc9\xbc\x75\xb3\x23\x86\x02\xb0\x2f\x88\x8a\x2e\x37\x17\xd2\xce\xb1\x8d\xe7\x68\x10\xda\x2e\x8f\xf6\xd3\xbc\xe8\xfb\x24\x96\x14\xdf\x45\xdd\x65\xd2\xa5\x14\xd3\xce\x6e\x5e\x98\x03\x02\xd5\x44\xf4\xe3\x11\x6e\xa7\x80\x58\x34\x7a\x20\x90\x89\x8c\xc3\x15\x3e\x48\x2b\x59\x08\x7a\xda\xb2\x80\xcb\x4c\x19\x9a\xbb\xc2\x25\x12\x67\x42\x33\xb3\x25\xb4\x69\xb0\xd6\xde\x27\x10\x34\x30\x88\x3b\xe9\x84\xc0\x82\x13\x66\x07\x1f\x9b\xab\x13\x19\x6a\x59\xa0\xb7\xd0\x8a\x01\x0b\xc0\xb4\xc1\x2b\x68\x89\x67\xfa\xd4\x98\x12\x79\xb0\xcd\x7c\x73\xaa\x3b\x75\x3b\xcc\x10\xa8\xa6\xf6\xda\x62\x50\xc1\x5d\xb0\xb8\xb4\x0e\xa4\x26\x1e\xa9\xd5\xf7\xb4\x20\xf7\x47\x8e\xc9\x2b\x21\x46\xc0\x0d\xce\xd9\x14\x88\xc6\x7d\x13\xaf\xca\xac\x69\x78\x83\x5e\x67\x2a\xf4\xe5\xe1\xb6\xac\x8f\x5d\x71\x04\x5c\xc5\x86\x33\xb2\xa6\xb6\x8d\x09\x28\x71\x9c\xec\x76\xde\x0e\xee\x4c\x27\xad\x9e\x8f\xfc\xd0\xf5\xcc\x4f\x63\x1c\xaf\xb6\xa5\xa5\x10\xf0\xd0\xaa\xd8\x13\xba\x9b\xa7\xd4\x67\xac\xee\x78\x12\x37\xdd\xa9\xb2\x51\xa4\x35\x5b\x3e\xb7\x42\x08\x78\x5d\xe3\xd3\x5e\x12\x4c\x97\xce\x0f\xf4\x79\x26\x10\xd4\xf7\x90\xdd\xbc\xc2\x79\xc2\xcb\x33\xd1\x52\x2b\x32\x2a\x48\x32\xa5\x16\xd2\x22\x68\x21\xe8\x92\x7b\x3f\x3a\x5b\x29\x3c\x27\x59\xfa\x9d\x34\xce\x99\x5b\x8f\x98\x64\x92\x45\x2f\xa2\x8a\xae\x03\x24\x29\x12\x43\x4c\x9f\xe9\xa5\x42\x7d\x1d\x35\xc9\x42\x94\xa1\x2c\xdd\x91\x44\xe4\x28\x82\x70\x2a\xed\xa6\x0f\xbb\xd2\xf1\x84\x97\x75\x57\x24\xaf\x52\x1c\x3d\x35\x2b\x6f\x6d\x9c\x57\x2f\x43\x86\x34\x7b\xe6\x24\x71\xae\x0c\x08\x51\xe4\xf3\xea\xe1\xd6\xb4\xae\x8b\x02\x43\xa0\x7f\x6f\xc9\x35\x41\x15\x34\x4a\x32\x27\x3b\x79\x54\x28\xe2\x8d\x74\x6c\x22\xb9\x52\x4d\xf6\x3c\xd1\xcd\x2c\x9c\x27\x0d\xdf\xeb\x34\x3d\xef\x5d\x9c\x27\x03\xa5\x9e\x0f\x3d\xdd\x82\x2e\xca\x7d\x8f\x24\x37\x0b\x37\x66\xfc\xd9\x76\x4b\xf8\x4c\xd2\x7b\xb2\x0b\x5b\xb9\xa5\x0b\x19\xf2\x3d\x60\xf8\x01\x71\xae\x0f\xde\x98\x43\x80\x19\x68\xa2\xc3\x72\x60\x98\xb0\x1a\x3d\x11\x40\x42\x49\xbf\x18\x1a\x80\x05\x8f\x1c\x38\x37\xe2\x00\x11\x03\x50\xc1\x2a\x2f\x24\x9f\x72\x31\x21\x64\x44\x96\xc9\x5d\x76\x0b\x2f\x71\x99\xdc\xf8\xf8\x79\x2b\x58\xf9\x71\x19\xcc\x14\x66\x43\x48\x58\x9f\xe1\xc6\xf3\x98\x67\x96\x4f\x99\xf7\x1e\x45\x3a\x68\xdb\x93\x2d\x8e\x2b\xd8\xdc\x6f\xf4\xde\xa9\xf2\x64\x09\x69\x2f\x75\x96\x17\x5f\xc1\xfe\x79\x72\xd1\x4d\x5c\x42\xeb\xde\x27\x06\xa7\x51\x66\xd1\x02\x2d\xe0\x9e\xc3\xa9\x86\x52\xad\xb3\x62\x22\xd5\x98\x88\x3c\xa2\xd6\x2a\xf0\xc2\x32\x07\xe5\xae\x8c\xea\x3a\x58\x8b\xa0\x41\x69\xe0\xa0\xaa\x16\xcf\xb8\xd0\x91\x11\x89\xe8\x54\x08\x0c\x77\xf5\x41\x22\xc8\x88\xa4\x5d\xd4\x4d\xd7\x61\x76\xdb\xfd\x4e\xca\x2b\x56\xaa\xf5\xb8\x4a\x02\x56\x81\x95\x40\x45\xa9\x9d\xb1\xb7\x07\x97\x23\x32\x7e\x73\xc2\x9d\x47\x64\x0c\xbd\x71\x38\x72\xc4\x37\xfc\x7c\xb4\x8d\xed\x67\x57\x7d\xc5\xb3\xa3\x5e\xad\xa2\x25\x52\x52\xed\xba\x94\xf2\x1d\x2f\x7a\x88\x4f\xac\x8a\x4a\xbb\x21\x25\x10\x0f\x6f\xa5\xd9\x30\xdb\xf5\x02\x36\x03\x82\x6b\xa2\x65\x1c\x95\xbc\x0a\x0e\xe4\x03\x7d\x8f\xd4\x6e\x72\x45\xd7\x4b\x4f\x3d\xd6\x38\xf3\x86\x00\xd1\x35\x88\x2c\x5c\x83\x88\xa5\xc8\xb0\xba\xe0\x7a\x7b\x36\x86\x5b\x2f\xf8\xc3\x6a\xed\xd5\x36\x4e\xc7\x8b\x2e\xf0\x42\xcc\x27\xdd\xec\x88\x0d\xe1\x8d\x7c\xb8\x9d\xa2\xd9\xbc\xdf\xfa\x0b\xb7\x05\x37\x35\xed\x17\x88\x6e\x95\x63\x75\xf8\xdc\xc2\xf1\x16\x55\xae\xb8\x2e\x1e\x5b\xf1\x90\xc0\xe6\xa4\xe8\xd9\x4b\x24\xef\x06\xc5\x3a\xe4\x8e\xb8\xc9\x57\xd1\x4d\x25\xca\x29\x17\xe6\xd0\x47\x6b\xcc\x56\x61\xc9\x5f\xcc\x13\x45\x12\x80\xd8\x1e\x77\x0e\x93\xfc\x42\x45\xcc\x59\xe0\xb0\x59\x35\xc2\x55\xac\x22\x2a\x67\xea\x0d\xf2\x49\xa1\xd6\x55\x77\xcf\x50\xf5\x2e\x64\xee\x34\x3c\xf2\x6b\xf7\x84\x3a\x54\x8d\x6f\xeb\xd1\x6c\xb0\x89\x35\x95\xed\x15\xf2\x98\x67\xe7\x71\x6f\x14\x1e\x1a\xfd\xc6\x3c\x56\xce\x3b\x6d\x6f\x8c\x1c\xf9\x40\x88\x95\x16\x46\x3c\xdc\xbd\xaa\xf1\x2d\x8f\x44\xc6\x00\xf6\x16\xbf\x38\xfa\xa0\xf1\x80\x39\x55\x8e\x7e\xda\xea\xa7\x35\xdd\x5b\xac\xc9\xf4\x80\xf6\x28\x3a\x68\x16\x64\x99\x72\x7b\x2a\x14\x32\x5f\x24\x82\x70\xa6\x64\x3c\x51\x3f\x01\x36\x7b\x82\x47\x33\x0b\xcc\x6a\x63\xb4\xc9\xda\xf6\x7b\xee\x26\x01\x02\x2b\x68\x67\x57\x79\x3b\xc1\xf7\x19\x81\x5e\xd9\x81\x39\xbd\x4a\xcb\xe1\xe4\x54\xe3\x19\x01\x95\x4a\x1b\x0d\x24\x1f\x60\x30\x48\x17\x1f\x8c\x91\x69\x21\xc9\x48\x5e\x26\x7f\xa3\x61\x34\x07\x6f\x7a\xb9\x43\x9e\x4e\x93\x5b\xa3\x1f\xd4\x62\x2f\x98\x87\xac\xb4\x15\xa0\x70\xb2\xa8\x6b\xb9\x20\xc6\xb5\x95\x92\x75\x02\xdb\x62\x41\x30\x0b\xcd\x8c\x3d\x22\x8c\x9c\xf0\x48\x16\x8c\x04\x12\x58\xc6\xec\x4a\xcf\xa8\x02\x80\x1b\x29\xc9\x89\x27\x21\x77\x0b\x97\xf4\x8e\x6f\x5a\x8c\xdd\x90\x61\x5b\xda\x2e\x87\x53\xa1\x1f\xf9\x59\x66\xf1\xf4\xd2\xa1\x44\x44\xe5\x80\x66\x12\x8a\xa8\x3f\xe9\x93\x3f\x33\x20\x2a\xc8\x02\xe6\xf4\x45\xca\xed\xcd\xd6\x27\x1a\x9e\x38\xe4\x9e\xc4\x0c\xdd\x27\xe8\x46\x48\xc7\xbd\xb3\xe0\x5c\x74\x73\x60\x01\x69\x80\x3c\xc5\x7b\x88\x06\xa2\x16\xd2\x41\x37\x72\x99\xc2\xa3\x3b\x90\xdb\xdc\x03\xd0\xbb\x48\xc9\xf3\xce\xc5\x40\x23\xb3\x23\x54\xec\x50\xc7\x38\xa2\x18\x86\xad\x20\x81\x3b\x93\x02\x72\x63\xcf\x20\xf2\x71\xa0\x01\x58\xc8\x14\x4d\x76\x77\x18\x7d\x6e\x22\x0f\x49\x5b\x56\x23\x87\x8f\xda\x04\x44\x4f\x77\x58\x2c\x3a\x9e\xc6\xdc\x7a\xf3\x11\x70\x8a\x8a\x42\x25\xbd\x94\x9a\x3a\x07\x72\xf2\x99\x84\x72\xd0\x29\xc0\x61\x7c\x6a\xde\x09\x83\xf7\x40\x6d\x90\x22\x4f\xd0\x6d\x5f\x9f\xc9\x82\x60\x2d\x6a\x1d\x98\x9c\x4c\x30\x20\x26\x08\x69\x65\x28\xb7\xe2\x37\x54\x80\x89\x3b\x5a\x6f\xa0\x4a\xc6\x60\xde\x8b\x40\x09\x8e\x05\xe9\x00\xb3\x1f\x30\x49\xce\x63\xe1\x8d\x2d\x4f\x4a\x8b\x78\x80\xd2\xb9\x30\xcf\xc1\xc1\x01\x21\xac\xa8\xa0\x47\x71\xb3\x68\xf7\x6e\xd5\xba\x76\xc7\xa1\x42\xdc\x67\xed\x3a\xa1\x47\x74\x23\x1c\x2c\xce\x8f\x61\x37\x8c\xa3\xc3\x7d\x10\xed\xa6\x94\xd8\x3a\x14\x44\x6b\x00\xda\x0c\xdf\x38\x43\x8a\xd9\xf0\x9a\x02\xc0\xa9\x6b\x07\x0a\x55\xb7\x91\x68\x37\x7d\x4e\xef\xfb\x0e\x50\x67\xf7\xa0\xa9\x38\xa1\xa6\x94\x4c\x8a\x1c\xc0\x48\x72\x2a\x76\x12\x2a\x5a\xfb\x4e\x99\x06\x6e\x52\xb4\x48\x84\x54\xde\x41\x17\x10\x35\xd6\x8c\x02\xb7\xe7\x46\x63\xce\x09\x40\xa0\x2c\x45\xd4\x6b\xce\xbb\x86\x8f\x45\xb4\x18\x1e\x64\x0c\x8a\x01\x09\x8e\x1e\xf0\xdb\xeb\x5c\x4e\x2f\x55\x94\x3e\x19\x46\xad\x6f\x0c\xc3\x61\x77\x26\xa8\x1b\x03\x0d\x5f\xef\xc4\xec\xd2\x68\x96\x59\xe4\x6c\x69\xda\xd2\xdd\xb8\x33\xeb\x6b\x52\x64\x4a\xe6\xd2\x5c\x4c\xcf\xc2\x90\xf5\xcc\x32\x84\x4d\x60\xb4\x43\x53\x5f\xb2\xa4\xcb\xc5\x96\xd5\x3b\x3a\xd4\x96\x9e\x84\x4d\xbc\xd4\x41\xd4\xac\xe6\x92\xa7\xfd\x7d\x8e\x90\x87\x9f\x22\x3a\x74\x44\x0b\x46\x5a\x1b\x84\x5a\x0f\x7d\x6e\x93\xa1\x6d\xae\x18\x09\x37\x3e\xa5\xc5\xf0\xc4\xb4\x15\x64\x29\x22\x27\x35\xe4\x1d\x62\x1f\x25\xcb\xde\xa5\x0d\xe5\x09\x0f\x10\x4d\x5a\x90\x7a\x81\xe4\x31\x7e\xc3\x9f\x00\xfa\xb0\xdb\x14\x3f\xc9\x8e\xba\xa9\x14\x56\xb0\x69\x93\x15\x13\x6f\xbe\xc9\xc4\x48\x5c\x89\x89\x0c\xc1\x3f\x5d\xa6\x60\x24\x73\x5e\x69\x28\xbf\x5a\x8d\x2c\x62\xdc\x34\x28\xa1\xf0\xed\x92\xeb\xc1\x0e\x40\xc5\x49\x02\x3f\x3a\xb9\x2d\x85\x52\xe0\x1d\x88\x36\xc8\x0a\xa4\xf1\x75\xd2\xa7\x16\x0e\x19\x0f\x02\x05\xb0\xbb\xbc\x81\x98\x1a\x17\xb6\x51\x87\xdf\x77\x90\xde\x75\xef\x50\x3d\xe4\xc8\x35\x84\x58\x1c\xd1\x82\x0a\xf3\x62\x6a\xfc\x44\xe4\x10\x9d\x1b\xac\x69\x23\xcb\x64\x3f\xa6\x43\x38\x41\x50\xb7\x7a\x2e\xe0\xd1\x23\x35\x5f\x58\x58\xc6\xd5\x1a\x10\xd3\xb9\xea\x09\x15\xdc\x73\x56\x20\x7f\x45\x8f\xc8\xdd\x82\xc9\x83\x1c\xc1\xf2\x04\xff\xc9\x5c\x86\x82\x04\xc0\xf2\x26\xf2\x30\xdc\xc7\xc9\x23\xa5\x32\x18\x25\x4f\xb8\x19\x6c\x1f\x62\x93\x8a\xc0\xf5\x77\x59\x4b\x85\xad\x17\x7a\x03\xc1\x30\x05\xb3\xa9\x49\x1b\x10\xe8\x9c\x31\x27\x3b\x59\x4a\xee\x6e\x1c\x33\x07\xdb\xf3\xcc\xf3\x26\x76\x67\xe7\x0a\xda\x49\xa1\x5b\xd5\xdd\x1f\x2b\x39\x2e\x05\x10\xc9\xca\x10\x4b\xf8\x53\x73\xef\xe2\x33\x7d\xc3\xc7\xca\x33\x8a\xd2\x03\x4e\x74\x8e\x07\x80\xe0\x23\x7d\x8c\x40\x36\xc3\x23\x3d\x48\x3c\x27\x9a\x6f\xa8\xd0\xb3\xa3\xc0\xd6\xa1\xe6\x65\x59\x37\x3f\x10\xa8\x36\x80\x58\xb2\x6c\x3f\x79\xba\x32\xa7\x76\x27\x81\x07\x4e\x01\xb2\xdb\xd9\x2c\x48\xa4\x0d\xbb\x33\xa6\xb1\x62\x11\xff\x9c\x55\xee\x79\xdc\x36\x45\x4e\xd0\x5d\x1b\xe9\xc0\x96\x73\x2e\x7e\x48\x14\xff\x6e\x17\xd5\xbc\x51\x14\x00\xd3\x16\x85\xd9\x06\x28\xd8\x0f\xbc\x94\xd8\xb3\xf2\x1d\x6a\x5e\x37\x7f\x4a\xe0\x1d\x7b\x86\x31\xeb\x3d\x27\xea\x9b\x5d\x58\x76\x8c\x91\x0d\x24\x73\x10\x4c\x25\x77\x83\xf4\x06\x3a\xf0\x70\xf5\x93\xa5\xcd\x02\x0b\xd2\x74\x88\x93\x94\x13\x00\x7b\x01\xe5\x1b\x68\xb8\x9a\x94\xca\xd1\x5a\xaf\x09\x20\x48\x0c\xd9\x3d\x6c\xe5\x5e\x40\xb9\x05\x90\x21\xf5\x0d\xe1\x85\x31\x8f\x79\x53\x1d\x17\xd7\xaf\xd5\x33\x05\xa6\x72\x4b\xd5\x26\xdd\x21\x20\x9d\x94\x71\xf5\x13\x19\x83\xb2\x11\x8e\xa1\xf3\x61\x97\xcc\x05\xa2\xb7\x84\xa6\x88\xea\xb9\x67\xb1\xbf\x91\x35\xbd\x24\x35\x56\xfa\x17\x8c\xe2\xe7\x59\xa4\x3e\x14\xcb\xa5\xce\x80\xac\xf9\xa6\x2f\x9d\x57\x9c\x8d\x37\x2e\xd9\x76\xad\x2b\x7f\x0b\xa6\xbe\x55\xef\xb1\xb7\x31\xac\x13\xc0\x59\x40\x9f\xa3\xc8\x4f\x56\xba\x05\x6b\x10\x14\xc0\xb8\x5b\xa8\x76\xcc\xeb\x23\xb9\x31\xdb\xdb\xdc\xc9\x30\x1c\x83\xe9\x16\xa4\x6f\x20\x8c\xa2\x14\x76\x3b\xb5\xb3\xf1\x80\x0d\xf2\xcb\x51\x99\xc7\x2d\x20\x0b\x3f\xe1\x13\xc7\x30\x39\x25\xbe\x82\x9b\x2e\x3a\xd8\xa1\xf8\xc8\x32\x6e\xa0\x02\x35\xb2\xed\x81\x04\xb6\x66\x83\xe8\x30\x64\xa7\x50\xdc\x1b\x7f\x4c\xa5\x63\xb9\x58\x09\xb9\xd7\x0c\xc4\x3a\x4e\xa0\x3a\x19\x16\x6e\x24\x39\x12\xcd\x48\x31\xbd\xf4\x31\x4d\xf4\x1a\xb8\x32\x65\xf0\xd0\x45\x92\x17\xb5\xa1\xa7\x5c\x0f\x0e\xac\x27\x8c\xd3\xdf\xc0\x9a\x6a\x3d\x95\xb0\xb0\x67\x0c\x38\xf7\x6f\x31\xb6\xf8\xce\x8e\x8d\x9b\xb1\x1f\x80\x23\xeb\xdd\x8c\x24\x13\x01\x74\x86\xc0\xed\x51\xba\x20\xf8\x12\xb7\xbd\x92\x98\x4e\xe9\x41\xa8\x26\x60\x58\xaa\x67\x53\x06\x9d\xba\xba\x11\x9b\x17\x57\x99\xdf\x68\x1a\x1f\x6a\x89\xb4\x3f\x3f\x6c\x6d\xcf\xb4\x61\x43\xb8\x1e\x34\xcf\xd4\x60\x63\x90\x90\x1e\x76\x9e\x26\xd7\xaa\x8f\xaf\xd8\xac\x70\x04\x40\x26\x2d\xec\x47\x75\xa2\xb1\x3a\x9b\x04\x23\x88\xa2\x46\x7b\x7d\x42\xb9\x7e\xae\x52\x4e\x47\x64\xcd\x16\x37\x8d\x2d\x0d\x8d\xbd\xc6\x5a\xc1\x3e\xdf\x4d\x7e\x7b\xfa\x2a\x3c\x62\x39\x05\x26\x33\xb8\x92\x2f\x38\xf3\xb1\xa9\x55\x14\xfb\xa8\x7c\xa4\x04\x1d\x2f\xaa\x7d\x97\x06\x9c\x62\xf0\x07\x61\x0f\xbc\xd6\x11\x18\x96\x17\x41\xf6\xc8\x44\x47\x5f\xc8\x4a\xa0\x59\x3d\xe4\x40\x79\xff\xf0\xa1\xa7\x0f\x57\xd6\xd6\x15\x45\xd1\x83\xe2\x0d\x4f\x83\x38\x07\xfb\x58\x07\x7b\xfb\x42\x1b\x2b\x42\x66\xeb\x2a\x09\x14\xf0\x18\x4b\xad\xd9\x57\x1a\xf5\xb4\x24\xd8\xb6\x6e\xbb\x85\x53\xa0\x83\x99\x77\x93\x1b\x0d\x28\x2a\x3c\x63\xf3\x98\xfb\xce\xe7\x71\xb3\x5a\xcd\x0a\x7d\xc1\x49\x41\x23\x0d\x88\x11\x5d\x00\x30\xc2\x71\xdc\xb0\x1f\x43\xbc\x22\x11\x6c\x05\x6d\xe4\x8f\x48\xbb\x99\xdc\xfa\x98\x8d\x4a\x17\x7d\x82\x98\x1d\xd9\x85\x35\xc7\x25\x71\xe2\x74\x5d\x55\x81\xcd\x51\x48\x20\x01\x7f\xa8\x0d\x1d\x4c\x03\x53\xbe\x87\x6e\xcd\xbb\x70\x80\xde\x5b\x24\xcf\x28\x00\x1f\x77\x79\x31\x46\x38\x5e\x7d\xb5\x69\x67\x08\xe8\xfa\x9b\xc4\x4c\xad\x7c\xa4\x86\x48\xd6\xb8\xde\x8e\xc4\xd0\x46\x57\x0b\x00\xa6\xcb\xd8\x00\xeb\x18\x80\xf4\x30\x6b\x8b\x56\x85\x1c\x19\x1a\x4f\xec\x0d\x29\x27\xaa\x67\x5d\x8e\x9a\x35\x1a\x5a\xb4\x19\x55\x0c\x8f\x33\x3c\x20\x64\x36\xd1\x27\x61\x70\x0a\x9e\xce\xa3\x47\x10\xd2\x5d\x3a\x1e\xe7\x93\x01\xc2\xab\xf5\xc0\x6f\x35\xb9\x03\xd3\x74\x92\x5d\x96\x0c\x00\x98\x0b\x51\x2b\xaf\x17\xec\x26\x16\xf3\x67\xae\x52\x29\x14\xed\xce\x29\x13\x7c\xb8\x83\x31\xca\xe0\x77\xea\xc8\x65\x61\x84\xf3\xad\xbe\xfb\x51\xcc\xfb\xcc\x2b\xd9\x90\x03\x91\xf7\x50\x6e\x68\x1e\x80\x49\x97\xd6\xee\xb0\x18\xa3\xa3\x70\x51\xe0\x74\x1e\xe8\x80\x11\x55\x01\x14\xdf\x83\xc0\x04\x6f\x83\x62\x83\x48\x70\x3f\xd7\xec\xac\x6e\x9d\x83\x23\xeb\x58\x63\x8b\xea\xb5\x67\xdc\x78\x63\x5c\xf6\x1a\x0b\xc9\x3e\x85\xf9\x7e\x48\xe5\xfa\x82\x66\x10\x20\xba\xee\xe2\x0d\x99\xdf\xc8\xb7\x05\xbb\xe2\xd2\x4e\x7d\xa0\xb3\xc1\x4e\x3e\x67\x42\xbf\xf7\x47\xda\xc8\xe0\x13\xad\xa8\xe0\x3e\x12\xeb\x34\x11\xeb\x74\x52\xa0\xea\x4f\x02\xee\xf9\x42\xc5\x20\x98\x68\x62\x41\x4c\x9e\x74\xe2\x89\xe7\x82\x14\x62\xf5\xb0\x64\x9c\xf4\x1b\xcb\x15\xae\x90\x88\xf7\x38\xf5\xc9\xa3\x60\x8e\x9e\xdf\xc8\x54\xd8\x3a\x03\x62\x86\x04\x2c\x27\x08\xf1\x8a\x6f\xfb\x31\xf0\xfe\xe4\xc1\xbe\xdb\x20\x0f\xe8\xba\xf5\x06\xcb\x5f\x49\x34\x20\x0f\x58\x6f\x9c\x81\x58\x28\x00\xe7\x78\xe5\x98\x27\x35\x0e\xce\xf2\x0a\x02\x1c\x26\x9e\xdf\x62\xab\x8f\xb9\x69\x05\xb7\x00\x04\x83\xe2\x56\x52\xb1\x60\xf9\x70\x3a\x07\x87\x90\xae\x81\xe5\x5a\x97\x1b\xe3\x31\x0f\xf6\x11\x89\x0e\x0c\x80\x37\x3b\x9a\x51\x77\x6d\xa0\x4d\x4f\x1d\x37\x3e\x33\x8a\xa2\x4c\x74\x55\x7a\xd6\xf8\x9e\xf3\x18\x7b\xbe\x4b\x67\x08\x41\x6d\x4d\xbb\x23\x4e\xb0\x8e\x0b\x1b\x24\xbf\x3f\xa9\x74\x73\x32\xcb\x9c\x27\xa5\xc9\x57\xfb\x52\x49\x21\xa7\x30\x92\xc6\xfb\x70\x47\x52\xfb\xad\xf5\xe1\x26\x01\x8d\x80\x3c\xb9\x4d\x3d\xd2\xb2\x13\x19\x8f\xaa\xbe\xd9\xbd\x92\x46\xfb\xb1\xca\xf7\x1d\x02\x25\x83\x20\x1d\xc2\xd9\xe1\x75\x1d\x20\x2f\xf0\x2a\x33\xbd\x8e\xc7\xe0\x0a\x6c\xd1\xdd\x58\x8b\x93\xd0\x2b\x8e\x06\x05\x82\x63\x47\xa6\xf3\x25\xa6\x2b\x4d\x75\x8d\xdd\x87\x9c\x3e\x45\x8c\xdb\x1e\x1f\x0e\xca\xba\xa7\x4c\x81\x0e\x2e\x50\x20\xaf\x6c\x30\xbd\xbd\x95\x6f\x64\x18\xc3\x87\xca\x1e\x78\x38\x09\xf5\x9e\x8c\x19\xdf\xb7\xac\x59\x4a\x17\x5c\x77\x06\x88\xc8\xa6\x71\x5c\xe7\x6c\x5b\x8e\x26\xae\xbd\x71\xeb\xce\x63\xa9\xad\x92\x2d\x24\xeb\xc3\x54\x92\xad\x90\xca\x31\xd7\x52\x2d\x11\x79\x33\x44\xe9\x1c\x8a\x55\x83\x53\x04\x92\x01\x4f\x2a\x0d\xd4\xe1\x41\x85\xbd\x77\x20\x9a\x26\x8f\xe1\xf5\x22\x44\x86\x03\x80\xfb\xe3\x78\xcb\x67\xb4\xd8\x53\x12\xed\xdb\x8f\x61\x5f\x35\x6b\x0d\x05\x8a\x0d\x3e\x7b\x88\x51\xe0\x26\xd8\xf5\x84\x2a\xf0\x60\xda\x96\xdc\xdb\x09\xd1\x45\xe1\x64\x2f\x9f\xec\xf0\x12\x9c\x90\xbb\x40\xad\x01\x0e\x04\xcd\xed\xc2\x31\xfa\x42\x2f\x34\xd9\x9d\x3c\x91\x69\x1e\xea\x40\xb4\x59\xb9\x48\x01\x62\x54\x54\x16\x4f\xa9\xf8\xcc\x59\x52\xeb\xd0\x5b\x57\xf3\x38\x70\xf5\x6d\x99\x77\x11\xcd\x49\x11\xcd\x2e\x2e\xfb\x41\x27\x4b\xe7\xec\x7d\xef\x52\x59\x49\x9b\xf0\x72\xc7\x72\xc1\xf3\x32\x17\x5d\xae\xa9\x6f\xb8\x5b\x8b\xb5\x7b\x75\xb2\x46\x69\x02\xce\x7b\x32\x91\x24\xd3\x15\xac\xa8\xd7\xd8\x81\x3d\x1f\x0d\xb6\xe1\xa2\x05\x65\x30\x89\x2e\x38\x88\x5d\xd9\xc8\xcf\x5b\x25\x4a\x37\x1b\xa2\xf5\x50\xbd\xb0\x7a\x30\x02\x28\xe0\xca\xaa\xe7\x05\xf0\xee\xae\x81\x7c\x79\xd8\x33\x54\x9d\x81\xb0\xdb\x6e\xad\x38\x6c\xf1\x23\x6e\xa7\xa7\x8b\x31\xed\xf4\xfd\x55\x87\x2e\xea\x0d\x6c\xd2\x25\xf0\xbb\xb1\x5d\x8c\x48\xcf\xbb\x29\xa2\x90\x44\x3d\xe6\x46\xc9\x31\xb3\xc3\x5a\x0a\x6e\x47\x82\x18\xa6\x78\x5c\x67\xaf\x9c\xcb\xa1\x50\x30\x7b\x64\x4e\xa2\xa5\x82\x9a\xce\xde\x43\x8b\xbb\xdc\x5f\x31\x0f\xa0\xe9\xe2\xcc\xa5\x7d\x77\x43\x5e\xf7\x9a\xc1\x9d\x7d\x15\x09\x49\x3d\x67\xcf\xf7\xba\xb0\x4c\x8e\x0b\x2f\x36\xb2\x4e\xa5\x4a\x3b\xd4\x70\xc9\xc1\xdc\xbc\x03\xc1\x83\x1a\x9f\xfc\x53\x2e\x62\x83\x79\xbe\x17\x7d\x1b\x12\x4b\x83\xe9\x1c\x2c\xe0\xd2\x69\xec\x81\xc0\xf3\xb3\x76\x18\x8f\xc8\x10\xeb\xca\x0a\x1a\xb6\xd7\xd9\xab\xe9\xb4\xb1\xb8\x53\x9b\x92\x20\x8e\x8e\x44\xf3\x7e\x73\x2e\x4f\xc1\x5d\x1e\x44\x77\x50\xa4\x12\x6e\x3d\x83\x1e\xd2\x47\x09\xe0\x2e\xcd\xec\x5c\x76\xfd\xde\x13\xb7\x4e\x3e\x4c\x6e\x5c\x13\x1a\xc4\x14\x24\x5b\x69\x32\x5f\x09\x00\xcb\x6f\xa2\xbd\x87\xcb\x99\xa2\x7a\x68\x01\x6c\x9c\x3b\x47\x5e\xcd\x71\xdb\x0e\x53\xbc\x6c\x09\x62\xf2\xbb\x29\x39\xf3\x64\x13\x73\x73\x94\x1a\x75\xbf\x52\xe3\xbb\xfd\x79\x49\x49\xef\x86\x8e\xea\x88\xba\xf2\xca\xab\x9f\xcc\x82\x57\x4b\x12\xc0\x54\x21\xee\xf5\x1e\xf9\x9e\x6c\x07\x7b\x1a\x08\xb7\x68\x3b\x28\x74\xa4\xbb\x0d\x6c\xe8\x60\x7c\xfd\x13\x1f\xd3\x09\xda\xa0\x0b\x10\xf3\x06\x7a\xca\x0c\x5f\x67\xb4\x29\x88\xc1\x55\xaa\xbe\xdf\x00\x72\xed\x26\x0d\xce\x8a\xa0\x3b\x1f\xb4\xe1\x3c\x8b\xe7\x3d\x9e\xcb\x8e\x78\x5c\x0a\x89\xfc\xcc\x41\x52\x9e\xcd\x41\x81\xaa\x13\xf9\x8c\x29\x1e\xb4\x47\xd8\x8a\xda\xe8\xe1\xbd\xf5\x25\xb6\x6b\x5d\x2c\xe1\x46\xd0\xc1\x99\x4f\x2f\x2f\x36\x10\xc2\xef\xc4\xe5\x66\x54\xab\xf1\x34\x2a\xca\xa8\x5a\xb9\x8d\x52\x67\xcc\x6e\x10\xd1\x41\x40\x03\x9d\xf7\xaa\xeb\x78\x6d\x6d\xe8\x6d\x48\xa7\x26\x55\xa7\x22\x21\x83\x98\x0c\x6c\x32\xc0\xdd\x9d\x82\x1f\x5a\xe1\xcc\x2d\xec\x8f\xb0\x3f\xd2\x5e\x36\x2c\xc1\x98\xa9\xd3\x93\x32\xd8\x27\x18\x81\x40\xff\x9a\x2b\x0a\x6a\xc2\x1e\x20\xe8\xed\x54\x74\x4d\xbb\x41\x5f\xb2\x31\xb9\x9e\x73\x22\xa0\xf4\xab\x9f\x99\x93\xeb\x2e\xa9\x75\xaa\xa2\xe7\x3a\x13\xed\xa0\xb8\xcf\x09\x13\xb6\xcf\x3a\x55\xc9\x07\x07\xf2\x87\xa7\xac\x2c\x7a\x17\x5b\x1a\x9d\x89\x75\x7a\x7d\x5e\x35\xb0\x4a\x3d\xa1\x89\xdc\xe6\x06\x14\x1e\xe5\xec\x1c\x22\x54\xa1\x4d\x04\x31\x22\x1f\x69\x3b\x1c\xf1\x3c\xb4\x2d\x3e\xc6\xed\xf0\xfa\x1c\xf1\xfc\x80\x35\x24\x47\x1d\x6d\xda\xb2\x64\x4a\x49\x91\xc1\xe5\x47\x65\x0f\x4e\x24\x3d\xec\x48\x4e\xd5\x25\x9d\xc1\x11\x8f\xa7\x90\xa0\x54\x4e\xaa\x6f\x77\xa9\x7e\xb9\x8a\x52\x4f\x4a\xcc\x9b\xf1\x3d\x4d\xfa\x51\xb9\xf7\xad\x5e\x87\xc4\xb5\xd6\xac\xf9\xc6\xb5\x32\x91\x1b\x5d\x0e\x60\xf9\x19\xad\x23\xb9\x92\x23\x87\x2b\x8a\x61\xd9\x7c\xa9\x03\x8c\xb1\xb5\xe5\x7b\xcf\xf9\x60\x6f\x9e\x10\xf9\x6e\xf3\x4a\xa4\xac\x99\x36\x80\xb1\xe7\xf2\x18\xb7\xf8\x1a\xb7\x4f\xe8\x6a\xa2\xe2\x5e\x4e\x8a\xfd\xd8\x4e\xca\x50\xbd\x58\xcc\x0e\x87\x10\x63\x52\xf5\xe2\x29\xca\xf6\x7a\xf6\xc6\xc5\x1b\x37\x21\x1c\xda\xb4\x93\xc7\xb0\x93\x8f\xb0\x15\x19\x4c\xbc\x08\xf8\x11\x49\x8f\x20\x24\xc9\x09\x64\xe0\x47\x74\xb5\x6e\xce\x65\x1f\x86\x3a\x6c\xe5\x7b\x8f\x68\x55\xf8\xa0\x1e\x6e\x7c\xaa\xc2\x3e\xfb\x71\xd8\x2a\x1c\xd8\xd6\x41\x1b\xb5\xd1\x3e\x26\x2d\x05\xa4\x89\x3a\xf9\xf0\x9a\xa1\xab\xa4\xae\xc4\xa6\xee\x69\xb2\x20\x8c\x81\x73\x9f\x71\xe8\x06\x78\x1e\x2c\xfc\x03\x03\xe8\x5d\x67\x0f\x78\xf1\xb3\x31\xa6\xe8\x8b\xf5\x08\x57\x9f\xe7\xc0\x45\x31\x31\xf5\x4c\x51\x8e\x0f\x5d\x07\x82\xb5\x7b\x78\xe8\x2f\xca\x77\x0c\x30\xee\x18\x62\xdc\x31\x40\x7b\xfd\x46\x90\x27\x72\xf6\x27\x7d\x53\x5f\xfa\x2f\x12\xf6\x19\x5e\x8d\x8d\xef\xe2\xc9\x25\xe4\x3a\xb9\x8a\x6c\x1a\x44\x18\x76\xee\x54\x20\xec\xa9\x1f\x9d\x81\xb8\x47\xdd\xcd\xec\x6e\xcf\xd3\x70\xd0\x0c\x15\xcf\xaa\xb8\x68\x77\xf7\x96\xd4\xe4\xd1\x49\x07\xa2\xe1\x0c\x48\x32\x40\xfe\x31\x3b\x09\x6f\x49\x17\x22\xc5\xdb\xc6\x1a\x70\x73\x2d\x8f\x6b\x3f\xaa\x1c\xb6\x75\x27\xf7\x9c\x55\x5a\x1c\x69\x80\xf1\x49\x34\x27\x2b\x2c\xba\x56\x58\xfe\xca\xa9\xd7\xb7\xcf\x23\x7b\xfb\x3b\x6a\xad\xc6\x9f\xe4\x37\xd9\xda\xfd\x56\x88\x32\x65\x76\xfb\x2d\xed\x64\xce\x7c\xc8\x76\x70\x6d\x29\x88\xa5\xd2\x59\xf4\xc6\x15\x1e\x8b\x86\x0b\x11\xcd\x89\xe0\x3c\xd8\x81\x9b\x0c\x0c\x1d\x41\x0c\x05\xa8\xdf\x31\xa0\xab\x5c\x15\x60\x4f\xf2\xb3\x3f\xb0\xcb\x4e\x3f\x67\xe9\x5e\xf3\x60\xbd\x3f\x75\x0b\x45\xe9\xb5\x98\x88\x74\x1f\x35\xb9\x4e\xc9\x9c\x26\xa8\xbe\x6b\x84\x2a\x57\x1e\x09\x4b\x18\x11\x52\xf5\xb9\xc8\xf6\xb1\xc8\x3e\x29\x51\x9a\x93\x49\x08\x1b\xbe\x8f\x0c\xde\x89\xc8\x22\x5c\x57\x10\xa5\x71\xd4\x9a\x34\x79\xc2\x00\xa3\x7e\xbc\xd2\xde\x2e\x39\x0f\x5c\xb7\xdd\x46\xb7\xb0\x19\x6e\xcd\x19\x6e\xa9\xa0\xa5\x0d\x07\x00\x84\x66\x48\x5a\xee\x80\x0a\xb4\xbe\x15\xbb\xa2\xd4\x7d\x79\x17\x19\x87\xae\xc0\xf3\xa3\x26\x5c\x1c\x9a\x56\x9a\x82\x67\x28\xa3\x02\x38\xe1\x65\x03\xc1\x4a\x1e\x38\x50\x74\x38\x50\x34\xd7\xf2\x79\xd5\xc3\x1c\x41\xfc\x93\x06\x4d\x8d\x06\x0b\x94\x66\x9e\x3a\x5f\x42\xaf\x08\xd1\xab\xd9\xb8\xa1\xaf\xd9\x71\x5d\xed\xc7\xa0\xdb\x2e\x2e\x3b\x0f\x5c\x75\xde\xda\xe6\xc6\xe0\x9f\x29\xff\x50\x67\xa1\x9c\x85\x03\x80\x83\x64\xc7\x08\x4f\x4e\x10\xd0\x81\x32\xa6\xd2\xcd\x57\x3f\x56\xa0\x28\x9a\x2e\x36\x6b\x1c\xec\x67\xbf\xae\xc8\x39\x0a\x0a\xd7\xcc\x85\x17\x45\xcc\x98\xc9\x7b\xb9\x7d\xd1\xe1\xad\xd5\x45\x48\xd1\x45\xd7\x34\xba\xbb\x71\xc1\x9f\x17\x58\xcb\x02\x07\xa1\x8b\x04\x41\x67\x5c\x18\x80\xb0\xbd\xf2\x15\x9b\x5e\x8f\x5b\xb4\x69\xb1\xdf\x0e\x71\xdc\x0e\x84\xdf\x0c\xaf\xbf\xc1\x7b\x4d\x44\xc8\x3e\x4f\x8a\x7e\x8e\x84\x7e\xce\x24\x42\x87\xe8\x4e\x19\x37\x8b\xdc\xda\xe0\x1c\x1a\xdf\x53\xe0\x86\x2c\x79\xc0\xbc\x3f\xdf\x7d\xcb\x6c\x2c\x8d\x8c\xba\x20\x58\x68\x56\xa4\x31\x47\xd8\xf3\x57\x0c\x59\x8f\xe8\xd5\x9d\x8c\xf1\x63\x90\xa8\x95\x40\x1b\x75\xc8\xa7\x85\xcc\xb7\x81\xcc\xd1\x81\xc8\xd1\x81\x2c\x82\x70\x12\x4d\x44\xe7\x5a\x77\xec\x6a\x0c\xb8\x9d\xb7\x45\x3a\xa1\xe5\x76\x42\x8b\xe1\x40\x8d\xdc\x65\xe8\x81\xef\xfe\xb4\x90\x3b\x15\x5e\xd9\x1a\xdb\x44\x79\xd6\xaa\x95\x2e\x52\xba\x33\x40\x63\xb8\x4b\x3b\x04\x94\x3c\xc6\x00\xf9\x67\x4c\x7a\x42\xd4\xb2\x0f\x18\xdb\x40\x71\x7f\xd5\x17\xea\xe5\x4b\x78\x01\x0e\x54\xf3\xb0\x1f\xc3\xed\x2e\x51\xe8\xab\x6e\xbf\x62\x5f\xb4\x5c\x4f\xb4\xb4\xe5\x2e\x9d\x2e\x11\x38\x5b\xe7\x26\x0b\x1d\x4c\x4b\xb6\x6d\x0f\x5c\x77\x4a\x48\x64\xd1\x0c\xcd\x3a\x0f\x2c\x4c\x88\x65\xc5\xa1\x37\xdd\x89\x4e\xc9\xdb\x5d\x3a\x6e\x77\xf9\xa0\xdb\x3d\xf3\x85\x3a\x74\xc6\x4c\x75\xa0\x4d\x3d\x6f\xa7\x74\xde\xf6\x9b\xfd\x18\x6f\xb7\x6a\x2a\x40\xe8\xaa\xca\x97\xc7\x79\x3b\x6f\xc8\x8a\xc2\xe3\x2b\xf7\xa6\x9d\x9a\x86\xd5\x23\xfa\x88\xb0\x58\x2c\x49\xad\x84\xf5\xb5\x6a\xe2\x57\xfd\xd7\x7a\x13\x60\x36\x92\x14\x62\xe6\xa3\x76\xf1\x66\x23\xd7\x61\xcc\x33\xb1\xf8\x84\x2e\x93\x31\xbc\x32\x9f\x17\x4f\x31\x14\x18\x80\x5c\x04\x21\x29\xc9\x6e\x77\xe4\xfc\x49\x85\xf7\x29\x3f\x01\xef\xc8\x02\x0b\xc9\x3a\x0b\xd9\xb6\xb4\x23\x36\xaa\xb1\x23\x35\x21\xe3\x48\x80\x8f\x7e\x51\x3d\xff\x0e\x65\x8c\xf8\xbc\x80\xee\xf2\xde\xa0\x30\x17\x55\xb5\x21\x5a\xee\x9f\xf5\x81\x05\xdc\x5b\x8d\x43\xd6\x67\x27\x52\x56\x96\xdd\x67\x77\x53\xf7\x9a\x78\xfa\x90\x72\x61\x50\x5c\x7f\x07\x29\x33\xc5\x6f\x86\x4c\xba\x30\x9c\x74\x17\x9f\x05\x55\x77\xdf\x06\x28\x8e\xe0\x64\x8c\xe1\x38\x42\x43\x76\xa7\x74\x3e\xe7\x76\xde\x6c\xd2\x09\x48\x4d\x86\x7b\xd5\xd0\x3a\x7c\xc8\x34\x23\x3e\xc5\xcf\xd9\x96\xef\xeb\x7b\x9e\x3c\x29\x83\x27\xcc\x1b\x73\xb3\xdd\x4e\x8e\x1b\x57\xd9\x7a\x06\x60\xc0\x4f\xba\x03\xe7\x76\x32\x7d\xb9\x30\x92\x9a\xf7\x82\x62\xc7\xa6\x5a\x7a\xdf\x77\x03\x66\x33\xec\x37\x90\xb1\x18\x97\xeb\xd2\x9e\x61\xc0\xcf\xb9\x49\xb2\x21\x9c\x73\x90\xfb\xf3\x66\x7a\x82\x6c\x4b\x0f\x88\x01\xa5\xe1\x73\xfe\x81\x2a\xc9\xc9\x8d\x30\x63\xae\xb8\x69\x4a\x65\xfd\x59\x67\x55\xfb\x62\xe9\x52\xc7\x70\xaa\x4d\x80\xee\x7e\x73\x44\x88\x29\x98\xef\x7b\xa2\x4b\xad\x6a\x51\x03\xe9\x15\x4c\x33\x1c\x17\x57\x92\x85\xb5\x25\x8f\x5d\xc1\x6f\x73\x00\xef\xbe\x7a\x1b\xc8\x34\x99\xfe\x2e\x9c\xf1\x53\xa5\xee\xe8\x37\x5d\xf1\x23\xa7\xbc\x54\x58\x1b\x64\xc9\x44\x9f\xfb\xaa\x8b\x92\x21\xee\x53\x62\x5d\x9e\xf1\x71\x3d\x92\x4b\x1e\xb0\xee\xd8\x87\x0a\x2a\x58\x1e\x74\x59\x2e\x19\xd3\xb1\x0f\x54\x9e\x79\xf0\xb8\xa5\xec\xdb\x2b\x45\xd4\x05\x56\xe3\x2f\x4f\x4e\x92\xfb\x28\xb9\x00\x2c\xf8\xb9\x3f\x13\x98\x20\x3c\x94\x0b\x53\x33\xe9\x85\x4c\xdb\xa7\x01\x4a\xdf\x73\x30\x46\xe8\x43\xdf\x32\x2c\xa7\x38\x63\xe1\x10\x60\xf0\x92\x11\xfd\x94\x51\x29\x4f\xeb\x91\xd8\x2c\xc3\xd6\x68\x94\xdf\xac\xa1\x67\x0e\x89\xfd\xd4\x1d\x31\xab\xfc\x13\x75\x09\x31\x80\x18\x89\x21\xee\x8f\x14\x5c\x18\xbe\xfd\xcc\x11\x17\x36\x8c\x2e\xee\xc5\x61\x98\x0a\x72\x01\x15\xf5\x4b\xf6\xbb\xac\x2c\x7f\xd5\x13\x8a\xd9\xd5\x7e\xa8\x02\xcd\x61\x56\x8b\x31\xca\x77\xd5\x31\xc6\x03\x63\x6e\xc2\x6a\x97\xd1\x6a\xf7\x4c\xfa\x29\x27\x53\xaa\x30\x56\x38\x2c\xc3\xd7\x90\x94\x9d\xee\x53\x7d\x98\xfc\x87\x7e\x2e\x5c\x68\x8d\x7a\xc5\x99\x1c\xa6\x98\xd7\xaa\xfa\xe6\x97\x12\xf3\xbc\x47\x7d\xcf\xf5\xac\xa4\x1d\xc1\x91\xba\x2f\xd5\xbe\xf3\xc7\x48\xd6\xa0\x19\x07\xc3\x5f\x98\x32\xbe\xbb\xa8\xec\x72\x3e\x79\x7a\xf1\x47\xff\xce\xc8\x62\x33\x30\x25\xbb\xe7\x2a\x9a\x36\x0c\x83\x7f\xe7\x9d\x69\x6d\x4b\xd6\x18\x8e\xd1\xef\x54\xc6\x5f\x9e\xcc\x8f\x72\xb5\x8f\xb0\xae\x19\xa6\xbe\xf0\x00\xc4\xe4\xd1\xb7\xbe\x81\x31\xf1\x61\xdf\xa1\xd2\x64\xb0\xa1\x8e\xda\xf8\x22\x97\xcc\xf9\x69\x0b\x4e\x34\x6e\xfa\xb5\xe4\x18\x59\x58\xed\xd5\xb9\x97\xec\x0f\xef\xe4\x35\x97\x2b\x4a\x94\x58\x46\xd4\x0e\x8f\x11\xd6\x6f\x7e\xcf\x9a\x38\xe8\x11\x89\x13\x26\x85\xc9\x94\xf7\xbe\x93\xed\xe8\x37\x36\x7a\xb5\x7a\xf7\x67\xde\xcd\x94\x6c\x72\x8c\x73\xd9\x6f\x10\x13\x31\xec\xe7\xec\xa3\x59\x91\x2a\xc4\xaf\xb4\xd3\x43\xb4\xe1\x18\x8a\xe4\x3c\x18\xf1\x33\xee\x60\x06\x32\x78\xfa\x76\x61\x74\x35\x6b\x1f\x51\xcf\xac\xec\xf6\x83\x6f\xa1\x16\x8f\xe9\xa5\x30\x3b\x17\x59\xfd\xee\x57\x31\xd1\x2d\x78\xda\x32\x2c\xab\xa9\xbf\xf1\x39\xc9\x45\xec\x41\x23\x73\x63\xeb\x19\x93\xb7\xb3\x20\x83\x7e\xed\x73\x97\xfb\x44\xae\xf8\xbe\x7a\x27\xc4\x84\x6c\x5f\xf5\xf1\x95\x14\x43\xb2\x30\xf9\x1f\x72\x0d\x6f\xb7\x35\x9d\xf6\xcc\x83\x61\x39\x4b\x76\x1f\x8b\xaa\xa0\xbf\x8d\xeb\x31\x69\xdb\x07\xc7\xf0\x17\x58\xe3\x13\x8b\xbd\x71\xdb\xf7\x78\xb9\x4e\x5b\x02\xdf\x33\xd1\x76\x8d\x92\x31\x5d\x68\x99\x08\xc0\x79\xc8\xe2\x0b\x47\xf6\x89\x63\x7d\x10\xb9\xfe\x70\x1d\x86\xb9\xab\x18\x78\x4d\xa7\x71\x6c\x79\x8c\x07\xbf\xc7\xab\xec\x16\x20\xc5\x54\xc4\xcc\x5c\xb4\x43\x7e\x10\x79\x3b\x10\xc5\xc0\x00\x4c\xf7\xa9\x23\x96\x83\x23\x80\xce\x27\x3a\x53\xc5\x27\x27\x9d\xba\xf0\xdc\x44\xa3\xbf\xbd\xd1\xb2\x3e\x69\xd5\xe3\x30\xc5\x35\x9d\xc5\xe3\xcd\x60\x6e\x16\x4a\x2d\xce\x70\xce\xd8\xfa\x56\xe7\xbe\xe7\x94\xd7\xb4\x03\x91\xcb\x01\xb7\x27\xc6\x70\x4c\x6d\xcb\x3c\x0a\x62\x8f\xcd\xaf\xcd\x26\x66\x8a\x3a\xad\x1b\xaa\x61\xbe\xcd\x76\x6a\x8c\xd0\x6b\x96\xe7\xb2\x78\x16\xcc\xe5\xd2\x6c\x77\x0c\x90\xd2\xbc\xe0\x98\x5d\x0a\x05\x9f\xe1\xf1\xcb\xb7\x98\xe3\xb8\xab\x78\xdf\x9f\x74\x6a\x30\x99\x1d\xc9\x3d\x1b\x72\xcc\x65\xc7\xf2\x62\xc9\xb3\x0c\xb7\xbd\x66\x61\x94\xa7\x50\x7c\xb7\x63\x2a\x0e\x99\x4a\x42\xd4\xb8\x68\x67\x8a\x40\xcc\x83\x65\x7c\x12\x19\xd3\xc5\xd0\x34\xa2\x71\x95\xa6\x67\x4f\xf6\x7b\xdd\x00\x24\xe4\x76\xbf\x93\x27\x69\x18\xfc\x93\xd2\x21\xe6\xc1\x98\xc7\x6d\x53\xb7\x02\xcc\xf3\x43\xba\x4b\xc8\x43\xb8\x5d\x8a\xcf\x9d\xb4\xa4\x65\x54\x9f\x07\x8d\x07\xe3\xb0\xce\x1e\x10\xf3\xe0\xcd\x5a\x5a\x35\xb4\x20\x19\x30\x6e\x07\x25\x31\xb9\x96\xd9\x3e\x77\x18\x37\x7e\x23\xc8\x49\xa0\x81\x27\xfd\xc4\xf8\x9a\xc1\xd8\x5b\x2e\x4e\xf8\x42\xe0\x50\xb3\xa7\x3e\xc4\x0c\x25\xfc\xe9\x63\x22\x7f\xe4\xfc\xb1\x6d\xa0\xd8\xb6\x8e\xd6\xc5\xa6\xcf\x84\x8a\x67\x8f\x4e\x3c\x6f\x80\x48\x10\x74\x62\x71\x2d\xe7\xa3\x90\xf3\x7d\x47\x7e\xd5\x51\x04\xa7\x71\x72\xeb\xf4\xb3\xc6\x63\xc6\xe6\x7b\x2f\xb2\x83\x24\x41\x27\xa7\x87\xaf\xe6\xb1\x32\x31\xe4\x02\xfc\xb7\xb0\x6a\xb5\x7b\x88\x82\x18\x76\xbe\xf5\x83\x10\xf3\xe0\xa4\xe3\xd6\xe9\x45\xc7\x93\xa0\x75\xb1\x2e\x89\xc9\xad\x5c\xf2\x89\xbf\xd7\x54\x0f\x2d\x50\xe8\x46\x81\x11\x19\x44\x31\x63\x73\x0f\x99\x0b\x1f\x86\xa1\x4a\x26\x7a\xdd\xe7\xd7\x7d\x71\xfa\xce\x8f\x26\x86\xb0\xe1\xd8\x07\x01\x10\x01\xf7\xe2\x87\xb9\x58\xae\x27\x18\xc5\x69\xd2\x9b\x0d\x69\x42\xcf\x06\xdc\xf7\x1d\xcf\x43\xa9\xc7\xa9\xeb\xce\x29\x42\x6c\x59\xbb\x28\x0c\x27\xa8\x13\x9d\x6d\x05\xc0\x01\xa0\xfa\xa4\xfc\x52\x48\xf9\xef\xbb\x9b\xe7\xdb\x9e\xdf\xc0\x78\x16\x32\x96\x71\x36\xf8\xcc\x8d\xef\x37\x5b\xaa\xa5\x59\x2e\x39\x86\x32\x60\xa0\x81\xf4\x01\xd6\x07\x4f\x19\xe0\x7c\x7c\xce\x3c\xb7\xc1\xc0\x06\xe7\x0d\xf4\x9a\x8f\x97\xec\x3e\x66\xd0\x93\x10\x43\x7a\xa8\x3a\x32\x49\xc8\xec\x36\x5f\x19\xb3\x6e\xdc\xde\xbb\x5a\x8f\xe8\x1a\x34\xf8\x61\xcd\xeb\x84\xd6\x9a\x35\x6a\xf6\xe8\x99\xa3\xe7\x55\x61\xcb\x59\xb2\xf8\x68\x8e\x15\x7e\xae\x0b\xbd\x55\x29\x5f\xa6\xf7\xb5\x1b\xe2\x68\xd3\xc8\x2e\x26\x4d\x62\xb0\xfc\x11\x46\x10\x3a\x26\x8f\xc7\xa0\xfa\xbc\xc1\x04\x24\xb1\x7f\xc6\x24\xa3\x66\xd3\x02\x93\xf7\x81\xc2\xae\xa9\x19\x8c\x5a\x2e\xbe\x46\x43\x79\x76\xc4\x57\x0f\xdf\xe6\x46\xed\x70\x91\x93\x28\xcf\x41\xa9\x07\x65\xa0\x0d\x0d\x5b\xdc\x87\x9d\xa8\x51\xa2\xc5\x32\x17\x6f\x82\xde\x62\x91\xb8\xcf\xc9\xeb\x73\xdd\xfb\xbc\x1b\x8e\x34\xac\x61\xf6\x22\x0a\xfb\x1c\x3e\x64\xce\x8f\x4f\xc4\x3f\xf4\xfa\x0c\x84\xb6\x95\xb5\xd7\x6c\x79\xbc\x9a\xc3\xb3\xc3\x96\x68\x8c\xda\xa8\x4d\xdb\x49\x8e\x27\x36\x9e\xf0\x42\xe1\xc4\x1d\xca\xae\x3b\x16\x71\xb9\x9a\x06\x0a\xec\xa3\xe8\xa4\x36\x6b\xa0\x36\x93\xe2\x97\xdc\xfc\xfd\xfb\xb2\x97\x0e\xc1\x8d\xb8\x22\xa0\x0f\x6b\xe6\x15\x09\x3c\xc1\x7a\x44\x8f\xa8\x8d\xdf\x1b\xf6\xd7\x67\x4c\x2e\xfb\xcd\xb9\xa9\x55\x4c\xc9\xaf\x7e\xf9\x35\x73\x80\x28\xcd\x80\x28\x0d\x66\x10\x6d\xc4\xfa\x3d\x3c\x9e\xcf\x83\x0b\x71\xdd\x7e\x4c\xb7\xf3\xd6\xc8\xb6\xbb\x68\xb6\x3b\x28\xf6\x83\x32\xb4\xb3\x90\xa0\xd1\xd6\xf8\x10\x30\x16\x06\x84\xb4\xa2\x40\xe9\x22\x80\x69\xd4\x21\x50\x93\x28\x89\xb6\x51\x86\x60\xc4\x87\x65\x0d\x54\x8d\x10\xe2\x59\x5d\x35\x19\xfd\x61\xbf\xc9\xd8\x91\x0a\x51\xe3\xba\xc1\x59\x5e\x70\x18\xa9\xd6\x21\xa2\x9d\xe9\xa6\x1d\xe9\xa4\x1c\xf3\xa4\x38\x52\x6d\x34\xc7\xc5\xdc\x48\x65\x18\xe3\x76\x9d\x56\x62\x25\x57\xf2\x35\x5c\xe4\x68\x43\xfa\x57\x74\x57\x7b\x5a\x78\x44\x7e\xd4\x46\x48\xd6\x44\x88\xd7\x44\x6d\xd2\xd3\xc1\x24\x90\x47\xca\x97\x98\x9e\x75\x1e\x9c\xa1\x19\xba\x90\x39\x84\xb4\x27\x84\x01\xd3\x09\x54\xeb\x16\xa0\x28\x43\x13\x4f\x14\xd3\xf5\xcf\xde\x8f\x91\x2f\x9d\x4d\x1d\x00\x05\x6b\x77\x57\xd0\xd8\xa0\xcf\x84\x3e\x9d\x94\x93\x2b\x67\xb5\xc6\x7a\xe5\xb2\xdf\xec\x4a\x41\x9d\x68\xd2\xb2\x4d\xac\x87\x21\xf1\x61\x3a\x57\x1a\xc2\x6f\x75\x95\x2a\xe6\xd6\x3d\xda\x7e\x56\xb8\x67\xaf\x70\xaf\x79\x7f\x77\x8c\xfd\x0e\x18\x70\xbe\x6d\x04\x00\x2f\xb1\xdf\x2c\xb1\x8f\x2e\x24\xf0\x94\x68\xc3\x5b\xc9\x68\x0b\x34\x8d\x46\x25\xa4\xbc\x01\x97\x4f\xbd\xf0\x4f\x56\xec\xb1\x69\xf1\x46\x7c\x77\xbd\x66\x88\x5d\x81\x75\xbd\xa3\xe3\xf4\xea\x4a\x91\x28\x8d\x66\x45\x42\x54\x73\x7c\xdd\x1f\x85\xa1\xa4\x45\x50\x9f\x79\x62\x43\x83\x6a\x43\x83\xe2\xe2\xba\xc3\x8c\xcb\xbe\x2e\x67\x8a\x68\x11\x05\x16\x24\x41\xf7\x90\x6e\x33\x77\xef\x2a\x1d\x92\x68\x94\xe4\x67\x2e\x7d\x32\xd6\xaa\x2b\xb8\x3f\x02\xa9\x27\x44\xb1\xd7\xcc\x44\xe2\xed\x56\x38\x17\xb5\x98\x27\x68\x7e\xef\x49\x9d\x7a\x42\x1a\x4e\x11\x45\x87\xe3\xc8\xcc\x9d\xfb\xc3\x7d\xb6\x2e\xe4\xe1\xbe\xdf\x0c\xb6\x3f\x28\xf6\xc8\x16\x35\x05\xb7\x31\x52\xcd\x7a\x57\x00\xc5\x25\x13\xa3\x83\xf7\x37\x84\x5c\xda\x61\x59\xd1\x5b\x1d\xb3\x3c\xc1\x7c\xce\x9e\x97\x9a\x0a\x56\xf0\x54\xc9\x33\x84\xd8\xaa\xc4\x92\x12\x57\x5b\x52\x7e\xcc\xbe\x2a\x1c\xc8\xad\xee\x7b\x65\xae\x9a\x7d\xa5\x11\xed\xee\x42\xf0\x92\x78\x0b\x69\x21\xb3\x03\x1f\xed\xc7\x3e\x3b\x9e\xbb\x6a\x37\xdd\x2b\xe0\x8f\x90\x3e\x8f\x73\x72\xb5\x90\x65\x8c\x1f\x74\x4a\x26\x7a\x34\xdd\x04\x6f\x0d\x82\xc9\x5b\x48\x8c\x0a\xb5\xe9\x02\x96\x60\x7a\x17\x19\xf3\xdd\xe9\x70\xc5\x0b\x82\x11\x99\xc6\x27\x10\x76\xe4\xe0\x8d\x65\x70\xe2\x04\x1c\x6e\xf7\x27\xaa\x41\xc5\x8e\x23\x28\x81\x50\xf7\x3e\x16\x3d\xd8\x09\x3c\x8d\x4c\xcf\x1b\xcf\xcc\x70\x74\xf1\x44\x8b\xa0\xd3\xd9\x79\xf6\xc6\x73\x22\x18\x09\x14\x21\xf4\xac\x9e\x7d\xeb\x0c\x67\x4f\xae\x4f\xa5\x27\x25\x28\x81\x1b\x1a\x44\x9d\xde\x57\x36\x1e\x44\x89\x4e\xfe\x56\xe7\xca\x5c\x85\x35\x9a\x98\xa7\x11\x93\x6b\x41\x86\xf5\x05\xad\xdf\xbe\x6b\x80\x8b\x6b\x4b\x41\x95\xe6\xa6\xe7\xed\x34\x3c\x2d\x71\x3b\x67\x20\x0e\x7f\x44\x66\x44\xe6\xec\xc7\x70\x50\x79\xe3\x35\xbe\xd7\x0e\xd6\x78\x93\x47\xf3\xe5\x4c\x33\x99\x6d\xe7\x05\x08\xe3\xab\xc9\xb7\x59\x71\xdb\x5a\x27\x9e\x47\x8f\x94\xeb\x32\xdd\x3e\x6b\x6b\xe9\x8b\x01\x79\x47\x45\x07\x7f\xba\x1b\x45\x48\xdc\xcd\x18\xbd\x28\x50\x9b\x03\x51\x6b\xa9\x94\x90\xb4\xb5\x65\xbd\xa1\x4c\x4a\xb7\x24\x80\xd2\xf9\x12\xd9\x33\x49\xcb\x93\x07\xa9\xaf\x93\x37\x51\x9b\x71\x96\x1b\x11\xc8\x0a\xc9\x84\xd3\x25\x35\xd0\xeb\x31\x4e\xd3\x95\x0c\x42\x35\x18\x07\x65\x48\xa6\x3b\xbd\xac\xbe\xda\x74\x37\xa8\x0c\xb8\xef\xfd\xb5\x58\x1d\x9a\x80\xd2\x00\x99\xa8\x68\x6d\xe5\x13\x0c\xd0\xf1\xa4\x78\x91\x3b\xd1\x41\x4f\xbb\x7b\xe8\x0b\x6b\x02\xe7\x33\x90\xe9\x20\xa8\xf7\xe9\xed\xde\x13\x1a\x24\x1d\x55\x13\xb5\xd1\x1c\xa8\x14\xa0\x1e\x40\xe0\x35\x4f\xe4\xe6\x08\x3b\x70\xbb\x5b\xed\x32\xc4\x77\x28\xb5\x57\x97\x80\xfd\x0e\x05\x8b\x22\xf5\x55\xfc\x6e\x34\x8c\xf8\x51\xcb\x18\x06\xca\x02\xbf\xeb\x9a\x65\xdf\xe7\x1a\x7c\x72\x13\x04\x3c\x46\x8f\xc0\xc3\x19\x1d\x3c\x45\xa7\x22\xf0\xac\x6d\x59\x0b\x82\xee\xdc\x9e\x67\x7d\x55\x77\x57\x42\xcb\x47\x14\xc7\xeb\x78\xa5\x9d\xd4\x15\xac\xc0\xae\x4b\x2a\x59\xe0\x52\x17\x9d\x81\xc2\xdb\x23\xc3\xc4\x7c\x71\xce\xf3\x70\x2f\x38\xa2\x6d\xba\x70\xb9\xa4\xdf\x6a\xb3\xe9\x6f\xba\xd0\xb4\x79\x91\xc3\x84\xbd\x6b\xc8\xcd\xf7\x84\x3c\x5b\x74\xed\x8a\x68\x75\x38\xd4\xb3\x82\x72\x24\x9a\xe6\x7a\x77\x56\x07\x2d\x20\x1d\x04\x3d\x50\xa6\x19\xa0\x4c\x73\xae\xbc\x35\xfb\x6a\xfc\x94\xf0\x4c\x73\xa7\x39\x61\x30\x9d\x5f\x0d\x1f\x40\x97\xc4\x55\x7d\x42\x64\x43\xe3\x0e\x61\x18\xd5\xca\x47\x7a\xfa\x66\xd5\x7c\xce\x1a\xa2\x08\xd3\x45\x00\xe2\x53\x0e\x5e\xce\xc8\x3a\xdd\xca\x40\x49\xb9\x71\x91\xe8\xca\xde\x35\xb8\x79\xe5\xf6\x2d\x59\x0c\x98\x25\xf1\xfa\x58\xb8\x8b\x15\x4f\x7e\xe4\x45\xb9\x07\x13\x74\x7c\xad\xb0\xc2\xb9\xc7\x9b\x0b\x6b\x36\x15\x01\x60\x3e\x27\xc2\x7e\x4b\xe7\xb3\x75\x8f\x02\x4c\x8f\xae\x1f\xf5\x7b\x6b\xb7\x17\xd5\xf8\xa8\xe1\x12\x57\x4e\x42\x32\x4d\x28\x49\xb7\x54\x27\xdb\xa6\x30\xd5\x58\xf9\x44\xc5\xd3\x71\xc2\x39\x50\x7d\x53\x25\xed\x13\xa2\xb7\x18\xd8\x56\x43\x2b\x53\x81\xf5\x2b\x81\xe1\xca\xe9\x48\x48\x10\x6e\xa6\x1a\xd3\x85\x61\x9f\xb2\x7d\xa5\xc9\x4d\xbc\x57\x10\x51\x68\xce\x9d\x32\xab\x30\x68\x87\x91\x18\xd3\xa2\xc0\x1d\xc3\x60\xb9\xe3\xd3\x7f\x38\x25\x6e\xa3\x0e\xa7\x7d\x10\xc8\x51\xf6\x69\xdf\xf8\xd8\x7e\xac\x4a\x42\xb7\x87\x6e\xf7\x63\xdd\xb6\xb1\x16\x82\x22\x05\x10\x3b\x86\xa5\xba\x88\xc6\xa4\x11\x58\x7c\x2a\x5f\xad\x4b\xb4\x6c\x5b\xd7\x55\xcf\x72\x88\x6f\x56\xf1\xea\x11\xb7\x0d\x14\x5a\x0f\xce\xd1\x52\x0d\x34\xe5\x18\x08\xe2\x76\x11\x01\xd5\x34\xfa\xb0\xf9\xd6\x37\x97\xa2\x02\x06\x00\x95\x77\x1d\x02\x0f\x89\xe5\x2f\xf3\xab\xdd\xd2\x96\x6d\xf3\x03\x00\x14\xbb\xdb\xc3\x05\x6e\x77\x89\x5c\x11\x43\x68\x2d\x24\xed\x26\x8b\xf5\x73\xaf\x1b\x9a\x19\x49\xee\x97\xf0\x3e\x15\xbc\xdc\xe5\x30\xe4\x15\x41\x5e\x14\xb3\x60\xf0\xda\xf8\xf2\xf9\x33\x5a\xd6\xa8\xc7\xcc\x72\xfe\x96\x83\x78\x0e\x29\x0c\x04\xed\x72\x43\xb4\xf2\x65\x1c\xd4\x9a\x0d\x8a\xb4\x68\x96\x8b\xc5\x98\x0e\x7e\xd1\xf2\x09\x2c\xb2\x90\x4a\x0d\x91\x3f\x7b\xca\xad\x20\xf3\x28\xaf\x25\x48\x22\x3e\x42\x2d\xca\xb1\x36\x42\x82\xc1\xda\x9d\x04\xa0\x79\xdd\x5e\x7d\x7c\xdd\x24\x21\x3c\x6d\x6b\xa0\xee\xbd\x64\xe9\x17\xf7\x72\xfb\xf4\xd1\x03\x6f\xcf\x2c\x06\x28\x60\x18\x4c\xf9\xd5\x54\xd5\x48\xa2\x1d\x70\x36\x0f\xf7\x88\x8a\x74\x60\x9b\x88\x20\xe8\x70\x38\x12\x6d\xd7\x2b\xcb\x5a\x3f\xb7\xa9\x6b\xe1\xc4\xb1\x43\x67\x2a\x18\xd1\x8e\x24\x7d\xeb\x8c\xfe\x15\xcf\x55\x3a\x35\x8b\x30\x2d\x21\x46\x03\x52\x3d\x9f\x8f\x67\xc3\xd9\xdc\xe5\x5b\x6a\x97\x06\x15\x00\x41\x3a\x07\x81\x18\x55\x71\x4b\xe9\x06\xcd\x71\x1b\x71\xdb\xd0\x21\x36\x1f\x37\x7e\x06\xe4\xc0\x21\xb2\x03\x8f\xd1\x62\x69\x13\x1d\x32\x9b\xc7\xd8\xf8\x13\xcd\x67\xf9\xe6\x93\xcb\x75\xf2\x12\x87\x4f\xc0\x91\xd4\x07\x82\x8a\xbd\x40\xae\xc3\x76\xe7\x1e\x83\x7e\x9f\x08\x0e\x07\x49\x65\x27\xd6\x52\xe3\x08\x22\xba\x7e\x9b\x85\x2f\x37\x07\xa2\xc1\x74\x03\x01\x1c\xbc\x0b\xfd\x8c\xc9\x36\x1c\xfb\xa2\x98\x4c\x49\xd1\x67\xfc\xd0\x5a\x3b\xf6\xaa\x21\x1b\x99\x9d\x82\x79\xae\xde\xa5\x7a\x44\x79\x4e\xd1\x08\xa8\x9e\x54\x5b\x0b\xc6\xf5\x89\x20\xd8\xbc\x6d\xb4\xea\xc3\x35\xae\xdb\xce\x03\x47\x42\x9a\xa6\x2a\x8d\xd2\x7b\xd5\x34\x9d\x8f\xbd\x00\xcb\x0b\x22\x48\x62\xd9\x75\x9b\x2c\xf7\xaa\x40\x7e\x09\xf9\x67\xb4\xf9\x13\x3e\x2b\xc5\xad\x9e\x49\x02\xd8\xda\xbc\x28\x68\x61\x5c\x32\x49\x69\x63\xbf\x1b\x4e\xf8\x89\x92\x48\x3a\xda\xd2\x69\x47\x2a\x22\x9e\x15\x46\x6b\xf0\x1d\x1b\x6c\x68\xec\xd4\xe6\xe5\x3b\x2d\x3b\x5e\xb8\xcf\x58\x63\x4c\xbe\x82\x80\x79\x03\x19\xd3\xbd\x2a\x75\x48\xe8\xe8\x46\x32\x85\xd5\x0d\x44\x7a\xa8\xd2\xba\x23\xc0\x8b\xd7\x60\x97\x87\x0b\x02\x9b\x3e\x28\x63\x8f\x57\x1b\x28\x0b\x23\x1d\xd8\xdc\xc3\x85\xb4\x7b\x4c\x53\xcb\x30\x39\x63\xda\x5b\xd0\xb2\xbc\xfa\x72\xac\x74\xd5\x96\xcd\x2f\xcc\xf6\x8d\x0e\x7f\xbc\xdc\xbb\x00\x37\xd2\x80\x6a\x5b\xbe\x48\xbb\x92\x76\x32\x7f\x02\x90\x61\x87\x6d\xd5\x35\xd6\x83\xb3\xe4\x84\x3c\x71\xef\x81\x2e\x57\xaf\xaf\x4a\x7c\x59\x51\xb5\x42\x4e\x7f\x22\x7a\xe5\x00\xc0\x8d\xe8\x3a\xb4\x41\xd2\x4e\x56\xaa\xab\x54\x4b\xb5\x02\x50\x6a\x0b\xd6\x3d\xa2\x45\x1e\x66\xd2\xb7\x6f\xfe\xce\x28\x33\xbd\x2d\x06\x08\x36\xd3\xd3\xc2\x6d\x01\xae\xcc\x02\xa7\x69\x9a\xb8\xc3\xc0\x1a\x09\xfb\x25\x35\x3a\xd9\xed\x34\x6a\xe4\x2e\x43\x3c\xf9\x49\x12\x04\xb9\xd7\x0c\x89\xc9\x55\x42\x38\x65\x09\x98\x17\x63\xd4\xc7\x42\x75\x09\x27\xf9\xbc\xdd\x31\x5a\x49\x73\xec\x60\x0f\x96\x47\xb5\x07\x44\x01\xb6\xf5\xde\xf7\x32\xcc\x40\x80\xbd\x1f\xbc\x9c\xda\x52\xaa\x07\x11\xa9\x02\x4d\x1f\xf4\x3d\xce\xf6\xba\xbe\x75\xfa\x39\x57\x52\x41\x72\x95\x15\x23\x34\xd8\xf0\xd1\xd5\xb9\x48\x4f\x0a\xf4\x84\x2a\x34\xb9\xf9\x12\x3a\x4c\x28\x34\xb1\x4b\x83\x09\x7c\x0f\x01\x43\x81\xc9\xdb\x7e\xb3\x2f\x08\x00\xad\xc7\x8d\xee\x82\x8a\x4f\x01\xa6\x94\xde\xa5\xe2\x1e\x10\x1c\x78\x02\x3c\xc4\x2f\x5a\x67\x3e\x78\x19\xbd\x03\x57\x7c\x6e\x2c\x4f\xcb\xbd\x2d\x29\xe9\x6d\x81\xf5\x99\x14\xe8\xe9\xda\x8f\xca\x5d\x14\xd1\x19\x52\x4e\xdd\xf1\xca\x4a\x98\xe8\x14\x04\x75\x1e\xc1\xca\xe0\xb4\xec\x7b\x8b\x18\x17\x47\xb4\x90\xcc\x61\x46\xee\x0a\x80\xc4\xbb\x3c\xbc\x70\x97\x08\x9d\xec\x1a\x72\x7a\xd6\xde\xa4\x82\x15\x30\x2c\xdb\x3a\x5c\xa2\x8b\xa7\x55\x66\x2a\xf2\xfc\x09\x85\x62\x85\xeb\x0a\x7a\x0a\x11\x2f\xd3\xc4\x26\x88\x8f\x5d\x72\xe2\xd0\x67\x34\x76\xd2\x8a\xa2\xc8\x5d\x58\xc8\x87\xae\x6c\x1e\xb5\x4d\x83\xfa\xf0\xea\xe5\xcf\x37\x3a\xc6\x47\xcf\x79\x61\xa2\x60\x04\xd1\xc1\xcb\xf2\xcc\x19\xb3\xba\xc9\x8f\x3c\xd3\x34\x0d\xde\x41\xd1\xb9\xd5\xf3\x72\xa4\xdd\x25\x05\x01\xb7\xba\x54\x92\xe0\x9f\x02\x4c\x6d\x46\xe7\xdc\x4f\x2a\x4e\xce\xc4\xe1\xda\xeb\x00\xe7\xc3\xe2\x03\x74\xbc\xb6\xf6\x8e\x0d\x5e\xa8\xca\x31\x9a\xad\x78\x6d\x55\xfc\x0d\x45\x08\xe8\x5d\x1e\xae\xac\x15\x63\x13\xd7\x6d\x20\x3c\x9f\xba\x73\x48\xa2\x11\xc8\x38\x5d\x4d\x62\x97\x73\xab\xdb\xc8\x5e\xde\xb1\xfd\x2a\x56\x10\x31\x1c\xe1\x19\x5c\x0d\x03\x1c\xe4\x07\xd5\x5c\x94\xa7\xdd\xb9\x63\xb3\x6e\x00\xea\x47\xee\x1a\x28\x02\x29\xb7\x89\x06\x9f\x56\x16\xb7\xec\xe5\xa2\x80\x9f\x31\xc4\x55\x7d\x2e\xf2\x24\x7e\xda\xc6\xe5\x48\x96\x03\xdb\x3a\xb5\xe1\xc6\xf0\xee\x2a\x76\x3b\xdc\xc9\x03\x92\x8c\x0a\x73\x76\x26\x8b\xa2\xdb\x30\x54\xa2\x01\x0a\x52\x26\x9a\xd0\x64\x96\xd2\x6b\x66\x59\x9a\x65\x1b\xe3\xb2\xf7\xc8\xc3\x16\x7d\x80\x22\x02\x06\x7b\xd1\x90\x8b\xcf\xf8\x49\x37\x81\xdc\x14\x02\xa0\x5f\xb3\x64\x63\xc3\x77\x34\xeb\x5f\xf5\x75\x8d\x9c\x9e\xb3\x91\xa8\xc5\xfb\x9b\x61\x28\xbc\x17\xb7\x77\x61\x71\xa4\xf8\x1e\x81\xd4\xce\xe9\xaf\x49\x10\x92\x7a\xae\xf7\x24\x29\x3d\xce\xf2\x35\x82\x33\xb6\x6b\xb1\x9e\x32\x2e\x19\x8d\x5b\x81\xba\x33\x88\x23\xb5\xf2\x91\xa1\xe4\x32\x69\x19\xc7\xf4\x8f\xf0\x63\x26\xd5\x2d\x84\x5a\xac\x61\x77\x69\xdf\x4f\x04\x0a\x09\xa1\x44\x3b\x99\xa0\xb4\xcb\x4d\x05\x0b\x20\x07\x68\x6f\x84\x7d\x08\x5b\xfb\x88\x97\xa2\x97\x5c\x4f\xb3\x7b\x52\x93\x59\x62\xf1\x14\x10\xaf\xbc\xce\x81\xea\xd9\x70\xe8\xfd\xd4\x5a\xc2\x46\xe0\xc5\x61\x72\x8e\x12\xd6\x9b\xf0\x5e\x2f\x18\x9c\x37\x77\x3d\xe9\xc0\xe7\x45\x68\x62\xb8\x7e\x86\x06\xb6\xf8\x67\x78\x0a\x98\x30\xa1\xd3\x51\x23\x08\x41\x57\x0e\x9e\xca\x21\x7c\xdd\x0a\x14\x00\x70\xc5\x79\x20\x8d\x50\x6a\xf2\xb8\x14\x45\x91\x21\xb4\x52\xcf\xd2\x09\xdc\xe2\x44\x3f\xa1\x9c\xa7\x75\x56\xfa\xac\x47\x9c\x09\xa7\x44\xb6\x22\x51\x1b\x55\xe6\x2c\x71\x37\x1a\x8c\xf0\xc5\x87\xdd\x31\xab\x28\x71\x19\x3d\xb5\x19\xf7\x64\xc5\x42\x20\x90\x10\x92\x9c\x9e\x77\xed\xcc\x45\xa3\x34\xa1\xcd\x23\x41\x4a\x32\x92\x10\x51\x5c\x83\x5f\x80\x4c\x74\x20\x48\xbf\xdc\x4f\xc6\xe7\xf8\xef\x7e\x0c\x4c\x31\x14\x5c\xf7\x31\x11\xb8\x67\xa9\xdd\x13\xe4\x99\xa3\x28\x81\x9a\x14\xc6\x5f\xc2\x44\x3b\x9e\xdb\x78\x40\x15\x8f\xa7\x48\x98\xc0\x30\x9c\xbb\x0d\xad\x8b\x12\xcb\x38\x17\xd0\x78\x9a\x4f\x70\xa4\xf3\x8b\x02\x77\x3c\x84\xfa\xda\x3d\x44\x8c\x1b\x1b\x4a\xf2\xb7\x1d\xa7\xc9\xc5\xb6\xcc\x75\x64\xc5\xe7\xb4\xb1\x1d\x56\x45\x46\xa2\xe5\xba\xbb\x40\x09\xec\xe0\xc9\xcb\x96\x6f\xfa\x5d\xda\x21\x7f\x13\x76\x65\x9e\xd4\x69\x02\x57\x7d\xeb\x4d\x4d\x50\xec\x07\x00\xd0\x38\x82\x09\xdc\xab\x27\x74\x16\x94\x44\x2e\xf5\xe5\xf2\x7d\x37\x7b\xbb\x37\x00\xb6\x3a\x12\xa1\xd4\x1c\xeb\x1f\x34\x45\x91\x97\xfd\x62\xb6\xd2\x50\xf5\x4b\xd6\x8b\xe4\xb4\x05\xb1\x74\x3c\x04\x0b\xf0\x1f\x83\x4c\xed\x00\x82\x42\x61\x5a\xba\xb0\x15\xae\x57\x91\xe6\xcd\xde\x4f\x75\x81\xb3\xa1\x65\x52\x76\x9d\xed\x2f\x97\x4f\x9d\x97\x14\xdc\xe6\x40\x61\x86\xa6\xab\xfa\xea\xd2\x66\x81\xb8\x33\x75\x58\x03\x37\xe7\xb2\x6b\x3b\x7a\x9e\xf0\xa8\x99\x85\x02\xe2\xad\xc4\xdd\x6e\x3c\x4d\x83\xa2\xeb\xca\x2c\x91\x0c\x70\x0c\x14\x9a\x02\x2b\xcf\x52\x40\x48\x14\x0f\x1f\x75\xd8\x30\x29\xf7\x6d\x9c\xe3\x25\x2c\xe5\xd9\x6c\xb7\x28\xf5\x9a\x01\xc1\x4a\x5e\xf9\x7c\x8d\x2a\x9f\xf3\x5a\x7c\x39\x21\x0c\x42\xa1\xbe\x40\x57\x74\x4b\xbc\x4e\x4b\x45\x11\x92\xec\x7a\xf4\x88\x95\x58\x32\xca\x4f\x4e\xb7\xf7\x6e\xbc\x74\xbc\x2d\x44\xfb\x5f\xe1\xc5\xd0\xf4\x2e\xd9\x17\x74\xb9\xc6\xde\xf5\x8e\xf5\x07\xda\x19\xa8\x36\xf9\xb1\x88\x5d\x79\x24\x1f\xbc\xa6\x30\xba\x93\xb8\x19\x0d\x01\x27\x2b\x11\xf7\xb3\xcc\x00\x2c\x7f\xe5\x9f\x01\x0f\x16\x45\xd6\x6b\xec\xd8\x70\xdd\xbd\x83\xae\xd7\x0e\xa2\x9a\x8b\xc4\xdc\x9f\xdf\xf6\x23\x8c\x4a\x93\x39\x40\x03\x77\x2a\xbf\xc3\x7a\x95\x90\xe4\xe9\xc4\xbc\x79\x70\x90\xb8\x4d\xf7\x65\xc5\x81\xeb\x14\xfa\x42\x45\xf8\xcd\x40\x20\x00\xd6\xdd\xb1\xcb\x16\xd9\x6e\xc3\xce\xa8\xb2\x45\xd3\xcd\x89\x13\xb2\xe0\xac\x9e\x7a\x72\x65\xc9\x7f\xcc\xd3\x3c\xb3\x91\x03\x99\x0f\x63\xdc\xe2\x6e\x5c\xe4\xbe\x82\x87\xbe\xc0\xa6\x3b\xa7\x48\xf5\xed\xae\xed\x04\xbc\x43\x15\xda\x3b\xcf\x54\x83\xe8\x0c\xa1\xbd\x54\x98\x77\x5c\xb5\xc7\xf9\x2e\x6d\x2a\x9c\x0f\x90\x0b\xa4\xc6\xd5\x3f\x91\xa8\x14\x58\xbe\x5f\xd4\xf7\xfa\xc9\x00\x9a\xcf\x96\x00\xd5\x6b\x81\x65\xbb\xab\xaa\x69\xcf\x60\x99\x33\x4b\x1f\xc8\xb7\x9d\x20\x3a\x90\xf9\xb6\xa0\xd9\x33\x15\xd9\x3a\x9c\xe5\x7a\xce\xea\x76\x18\x9e\xeb\x80\x1a\x57\x25\x68\x69\x7d\x84\x90\x40\x01\x8c\x9a\xe7\xc2\xb7\x9d\xd5\x75\xe7\x8a\x8b\x4c\x58\xdd\x10\xe7\xdd\x80\x64\x53\x22\x47\xcc\xa4\x74\x95\xe9\x0b\x82\xbd\x06\xa2\x58\xe3\x4a\x6b\x82\x41\x92\x6c\xd7\xc6\x29\xc4\x9d\x72\x05\x22\xde\x01\x6d\x48\x10\x70\x8b\x75\xb0\x27\x01\x2a\x11\xd9\x32\xbd\xee\x2b\xec\x2b\x4f\xc7\x1b\x37\x87\x88\xf6\x5d\x5f\xa0\xb5\x81\xe2\x3b\x94\x37\x10\x96\x8b\xd5\x2d\x8e\xc3\x96\xad\xde\xf6\x64\xb2\xfd\x1a\x3b\x20\xd8\x70\x20\x5a\x3d\x29\xf0\xc5\x3d\x20\x8e\xb5\x3b\xb6\x08\xfa\x1a\xcb\x50\x10\x1f\x81\x6e\x88\x5d\x6f\x35\xdd\x5c\xdf\xa6\x05\x87\x28\x84\x3a\xed\x6b\xf9\x99\x03\x8d\xa3\x9f\x89\x6d\xc2\x66\x4f\xad\xcb\x63\xf1\xc6\x15\x49\x12\x58\x1d\x9f\x48\xde\xa1\xcf\xc6\x4e\x26\xb3\xd0\x85\xb4\x28\x10\x3c\x05\xb2\xf8\x65\xc2\x1c\x1d\xda\xc2\x1f\xb4\xb0\x95\xeb\xe2\x21\xb0\xb6\xdf\xc8\xb9\xeb\x09\xaf\x97\xd1\xd5\x7a\x40\xa2\x33\x0c\xd5\x8c\x2e\x53\x94\x8b\xec\x23\xe3\x53\x61\x5b\x08\x95\x2b\x47\x4f\x15\xca\xc2\x11\x8a\x00\xa2\x35\x3b\xd3\x83\x6d\x45\xd5\xee\x5a\xf5\xb1\x7e\x2f\x89\xe0\x38\x83\xa9\x81\x06\xc5\x19\x30\xb0\x80\x71\x3c\x77\xbd\xc8\x0a\x9a\x3d\x0d\x44\x13\x65\x9b\x3a\x6c\xe5\x75\xf3\x83\xd3\x3e\x00\x70\x9c\xef\xfd\x40\xac\x23\x4c\xe0\xd1\x99\x34\x57\xee\x5a\x8e\x13\x9d\xa9\xc2\xc7\xec\x5a\x6c\x0a\x89\x82\xa0\x31\x24\x21\x62\x85\x51\xfe\x9a\x59\xd3\xeb\x33\x6f\x0e\x6b\xc8\xaf\x75\xbf\x6d\x64\xea\x23\x00\xe5\x7a\x9a\x83\x81\xba\x83\xaa\x5e\x9c\x78\x0d\x9e\xe7\xfe\x78\x4c\xde\x04\x03\xc9\x03\x2f\x23\x76\xa7\x7b\x52\xef\x48\x72\x3d\x81\x0b\xb2\x65\x71\xae\xde\x57\x1b\x06\x29\xb3\xe3\xa9\x68\xe6\x1f\xf8\xd5\xea\x2c\xaa\xa8\x4c\xac\x40\xc9\x6c\x26\x75\x9e\xef\x29\x3a\x37\x6a\xa9\x0a\xe7\xce\x19\x8e\x79\x52\x5e\x3e\x6f\xdc\x6b\x04\x01\xc1\x9d\xf0\xb3\xd8\xaf\xa9\xf1\xd6\x39\xcd\x51\xf9\x68\xa2\x75\xb7\x76\x87\x38\xe1\xdb\x77\x09\x37\xb6\xc8\xbb\x81\x2c\x40\xbf\x00\x89\x40\x82\xae\xd1\x89\xb2\x29\x08\x9e\x6d\xe6\x54\xd9\x43\x4d\xbc\x78\x2a\x36\x94\xec\xb6\x69\x4a\xf2\xb8\xc5\x27\x8a\x2a\x46\x3c\x0f\x1e\x89\xd6\x9e\xe1\x76\xf5\x54\xbf\x1b\x62\x93\xcf\xc6\x7d\x5f\x36\x6f\x29\xdc\x6a\xb1\x51\xe4\x80\x13\x6d\x84\xd3\xd9\x56\xb1\x69\x5c\x87\xd9\xef\xd0\xa9\x81\xc9\x6c\x05\xf2\x4e\x3e\x21\x20\x5c\xff\x3f\xaa\xae\x63\xcd\x55\xa4\x59\x3e\x10\x8b\xc2\x43\x2d\x25\x21\xe1\x8d\xf0\xb0\xc3\x7b\xef\x79\xfa\xfb\xf5\xf9\xe7\xf4\xcc\x5d\xb7\x3e\x75\x43\x55\x66\x46\x64\x46\x46\xcf\x58\x36\x7e\xaa\x33\x5c\x77\xbd\xe7\x3b\x9c\xa6\x65\x5b\xfe\xf6\x88\x34\xaf\xee\x08\xe0\xae\xe5\xfa\x88\xe9\x48\x90\xe8\xdc\x01\xc0\xb9\x66\xc8\xbb\xb9\x40\x41\x4a\xdf\x81\xe8\xaf\xcb\xca\xff\xd1\x17\x73\x0f\x01\x32\xd1\xe6\xad\x64\xf8\xb6\xcc\x21\x43\x00\x03\xe9\x77\xc0\x5d\x1f\xdc\x7b\x1c\x1f\x29\x71\x08\xa2\xf7\xfb\xef\xe2\x2b\xe5\x91\x08\x7a\xbd\x33\x20\x5f\x69\x6c\xe7\x4f\x7c\x9d\x23\x0c\xd2\x6c\xe2\xd3\x48\x3d\x71\xa2\x25\xf6\x12\x9a\xb5\x4e\xe1\x56\x03\x21\x5f\x0b\x0b\x3c\xcc\x6a\xac\xcf\x35\x54\xe2\x65\xc0\x7a\x5d\xb7\x17\xe4\xa4\x6d\x56\xde\xa7\x6a\xcb\x6e\xb4\xe1\x44\x8c\xae\x72\x3d\x4d\x63\xe4\x62\xe7\x26\x1c\x64\xb0\x32\x7b\xca\x20\x60\xa7\x6a\x86\x61\x18\x74\x58\x76\xb8\xc7\xb8\x54\x39\xbd\x74\x7d\x9b\xa7\x5e\xa5\xdf\x08\xf8\xeb\x35\x9d\x65\x7a\xd7\xac\x57\xa0\x7c\xe1\xe4\xef\x63\xfe\x33\xf6\xf8\xdf\x99\x3c\xf6\x1f\x0c\x94\x22\x4c\x34\xb0\xf5\xf7\x63\xfa\xed\x84\xa5\xee\xb3\x4f\x19\x14\x2a\x76\xcc\xf4\x18\xb6\xdf\x6c\xd1\x1b\xfd\xbd\xb6\x8b\x36\x22\x20\xef\xe0\xce\x90\x02\x44\x88\x7c\x27\x26\xcc\x9b\x8e\x41\x7e\x15\xca\xb6\xf0\xd1\xea\x76\x9b\xac\xda\x0e\xaa\x0d\xf1\x0b\x52\xa3\x3c\xfa\x33\x39\x64\x84\xf9\xf5\x51\x7e\x7d\x91\xec\x2e\xcb\x15\xb9\xc7\x71\x4c\x21\x49\xaf\xdc\x5f\x42\xbf\x6f\x8c\xc8\x18\xc2\x42\x7d\x65\xbe\x11\xbc\x5b\xb1\x10\xd9\xd5\xb0\xd7\xf8\xb0\x89\x1f\xab\x55\x40\x23\xc3\x5e\x16\xbb\x37\x94\x64\xb3\xdf\x83\xd5\xb9\x08\x4b\x16\xf7\xaa\xd1\x9c\xe3\x4b\xf4\xf9\x3b\x4f\x62\xc5\x15\x22\x07\x40\x61\xee\x2b\x06\x4e\x91\x9b\x4e\x97\xcc\x17\x0c\x30\x1f\xbf\x91\x20\x6d\xf1\x46\xa6\x29\xbc\x33\x0c\xe6\x3e\x35\x42\x8e\xa8\x92\x5e\x42\xd9\xc4\x00\x42\xd7\xe1\x60\x48\x95\xa9\x1a\x26\xe5\x71\xcd\x88\xd5\x8c\x4a\x84\xaf\xdb\xea\x76\xfb\x57\x21\x8d\xf6\x7f\xfb\x18\xc7\xf0\x79\x46\x2c\xd1\x3d\x83\x85\x88\xd7\x63\x70\x14\x9b\x42\x59\xdd\x46\x21\x13\xb0\xe5\x0f\x97\x20\x56\xfa\xa6\xa0\x25\x35\x57\x37\x4e\x59\x3f\xd2\x5f\xc1\x11\x24\x57\x6e\xc3\xcb\xf1\x84\xbd\x9b\x8d\x93\xdb\x20\xb6\x0d\x90\x0f\xf8\xe0\x91\xcb\xc5\xb3\xfc\xb7\x5f\x83\x1c\x38\x82\xef\xfb\x4c\x71\x4d\x65\x53\x25\xc3\x94\xc8\xb6\xc9\xd5\x30\xbe\x46\xe8\xd1\xac\xc1\x61\x3c\x8c\x62\x5b\x8e\x6c\x09\x65\xe8\x28\x28\x47\x04\x58\x12\x79\xa5\x38\x93\x0e\xa1\x70\x22\x79\x4f\xb1\xf9\x57\xc5\x24\xdb\xe9\xc6\x69\x22\x25\xa6\x70\x0b\x55\xaf\x08\x83\x78\x02\xf6\x89\x63\xf9\xe1\x8e\x74\xd6\xc5\x5a\x87\x6c\x7f\x94\x7f\xe5\x7c\xa1\xe7\x93\xfb\xa2\x1a\x93\x6e\xf8\x36\xd3\x5b\xae\x11\x10\xf1\x3f\x67\x32\x08\x36\x1f\x72\xb2\x56\x8b\x0c\x3d\x5f\x98\xaf\x72\x03\xbd\xf5\x4a\x5b\x4d\x0f\x96\xfc\xa6\xcf\x5f\x6d\x81\xfe\x64\x4e\x92\xce\x37\xa1\x3e\x9b\xfd\xae\x7f\x80\xeb\xff\x6a\xb0\x1b\x09\xde\xa0\x29\x57\x33\x5e\xc9\x6e\xe8\xc4\x3d\x2c\x06\x8b\x34\xcc\x53\xc3\x53\x92\x42\xde\x8c\x4b\xa7\xc6\x47\xb2\xdc\x6e\xb9\x9b\x02\x2f\xc5\x1f\xa8\x76\xaa\xa9\x90\x1b\x27\xf7\x76\x08\x50\x9f\x03\x5a\x66\x86\x79\x87\xbc\xdd\xd8\x76\x9e\x13\xda\x6c\xe1\x2b\x91\x32\x31\x34\x91\x7e\x64\x52\xe6\xc6\x91\xb9\x6c\x73\x5d\x78\x95\x81\x70\xbd\x1c\x93\xcf\xfa\xd1\x4d\x63\x9f\xed\x51\x4c\xd7\xcf\x73\x8c\xa2\x4e\x2a\xfc\x96\xd6\x51\x31\xf9\x8b\xcf\x0e\x35\x69\x2c\x7f\x1e\x5b\x37\xed\xc3\x2e\x6e\x04\x30\xe3\x38\x4e\x49\xb6\xd3\x48\x77\x1c\xf7\xd4\x16\x77\x14\x92\xe4\xb8\x00\x1e\x33\xad\xaa\x5c\x41\x23\x8b\xa7\x0b\x17\xe2\x4d\x93\x5c\x88\x95\xae\x79\x6a\xad\x58\x13\x3d\xcd\x86\x49\x8e\xf2\x2b\x81\x44\x77\x67\xd9\x9a\xa5\x62\x5e\x3d\x9d\x4f\x19\x74\x9f\x68\x26\xe2\xe7\xf9\x45\x0c\xaa\x5c\x99\xcc\xdf\x11\x8d\xdc\x5d\x9a\x3f\x97\x08\x22\x77\xd6\x50\x9e\xdb\x85\x9e\x2b\xf9\x54\xcc\x3d\x22\x0e\x47\x88\x91\xd6\x2f\x27\xc7\xeb\xb8\xe5\x09\x73\x18\x3c\xf6\x71\x29\xc5\xef\x9c\x49\xb8\x96\x29\x6f\x5f\x69\x80\xbe\x4a\x6c\x68\xa4\x2b\x4f\xb7\xce\x55\x64\x03\x79\xe5\x28\xa5\xd7\x75\x9f\xe5\xfa\x9d\x06\x04\x99\x9a\xa1\xdc\x2c\x78\xae\x0b\x35\x76\x85\x3a\x5f\x99\x99\x98\x1b\xe6\x3b\x13\x36\x0a\xd5\xeb\x8d\xd9\x06\xe9\x3a\x3b\x10\x2e\x55\x83\x69\xb6\xdb\x7c\x98\x33\x9a\x5d\x8a\x00\xbe\xd7\xdb\x14\x19\xf1\x66\x7f\xd2\xe8\x03\xef\x70\x62\xc7\x89\x55\x28\x9b\xcc\x53\x5c\x76\x03\xb3\x36\xa1\x98\x64\x4f\xf4\x38\x13\x3c\x4d\xdc\xba\x16\xcd\x5a\x24\xb3\xb3\x22\x5e\xef\x3a\x7b\x3e\x3f\x45\x7a\x4a\xff\xe8\x19\xb8\x63\x8e\xe6\x29\x6a\x7c\x9e\xf0\x39\x8e\x0b\x4f\x24\x83\xb9\x37\xc7\x79\x92\x4d\x8b\xfa\xc0\x70\x36\x33\xf8\xd3\x26\xee\x6b\x34\xd3\xfc\xa3\xb0\x7d\x84\x45\x3b\xba\xed\x5c\x81\x23\xdb\x4f\xe2\xbb\x9a\x51\xf9\x12\xf7\xd3\x44\x43\x3e\xdf\x59\x01\x9c\xa2\xfb\xb1\x7c\xce\xe3\xd6\x2c\x07\xa8\xcd\xdd\x90\x5d\x62\xd7\x65\x25\x32\xe0\xc4\x00\x9b\xae\xbd\x15\x60\x3e\xc3\x6f\x0c\x93\x9c\x15\xad\xbf\xba\x85\xc7\x33\x5f\xda\x62\x69\x2f\x1a\xbb\x6c\xb8\x79\xed\x3c\x81\x1f\x58\x28\xc0\xc0\xd3\x0a\xa2\xdf\xcb\x6e\xac\x0e\xe1\xfb\xa7\xb5\x7e\x0f\x06\xc1\x90\x1c\x01\x08\x48\x4e\xc9\xe8\x1b\x98\x58\x89\x95\xdb\xba\xde\x73\x85\xef\x99\x01\x25\xb2\x3e\x58\x2f\x73\x38\x67\x35\x2c\xb0\x07\x0c\x41\x85\xfd\xac\xd2\xfa\xdd\xb0\x00\x4c\x1d\x01\x91\xc3\xdc\x5f\xc9\xec\xd2\x97\x58\x8b\xd7\x37\x87\xc7\x1d\x22\x0b\x2b\x14\x70\x7e\x0f\xfc\x07\xbf\xfe\xb9\x87\x52\xae\xf7\x32\x6e\x03\xf8\x39\x02\xef\xc8\xf2\x13\xe1\x8e\x9c\x7b\xaf\x14\xfd\x8d\xe3\x12\x66\x20\x45\x90\x59\x10\xca\x23\x12\x4c\x9d\x91\xa6\x65\x72\x9f\x83\x5a\x76\x7c\x40\xe9\x76\x37\x8e\x4a\x15\x60\x3e\x13\x22\x05\x1a\xbb\x13\x96\x49\x09\x0c\xb8\x21\xaf\x2f\x1f\x90\xcc\x02\x11\xb6\xd5\x4d\x9e\x56\x7c\x1a\x66\x8b\x5f\x11\x60\xe3\xa2\x78\xce\xdb\xd7\xeb\x58\xac\x22\x70\xff\xe9\x69\x72\x85\x85\xe7\x33\xbd\x39\xb9\xc6\x35\xd4\x14\xbf\x8e\x42\x8f\x40\x88\x74\x57\x68\x2e\x78\x3c\x9a\xeb\xa6\xc5\x1e\xd6\xb0\x10\xb6\xa5\x52\x31\x15\xd5\xa9\x9f\xc2\x53\xa8\x25\xb2\x9f\x1a\x1b\x0f\x58\x04\xca\x07\x6d\xe0\x08\x1c\xb0\xfd\x12\x9a\x0b\x11\x0c\xc3\xd8\x17\xc2\x26\x4e\x85\xd2\x90\xe4\xe7\xb3\x93\x4b\xef\x2e\xf2\x58\x49\xfe\x48\xa7\x93\x7f\x96\xfe\xdf\xfc\xf1\xb8\x89\x14\x85\x03\xad\xd7\xec\x80\x30\xe1\xea\x4c\xcb\x22\x1a\x99\x71\xda\x35\xbb\x50\xc4\x9f\xf1\x7d\x0e\xe8\x59\xeb\xa3\x85\x15\x71\xea\xe5\xca\x54\x38\x6b\xd2\x5c\x74\x9f\xcb\x96\xa3\xa8\x29\x55\xa2\xce\xaf\x00\x1a\x3e\x61\xb7\x0b\x76\xd5\x7d\x4d\xa2\xf2\x7b\xcf\x73\x5e\xd1\xc6\x55\xbb\xc5\xf8\xa7\x0e\xb4\x16\x95\x8b\x06\x4e\x29\x11\xb2\xa3\x90\xfb\x2a\xef\x82\xff\x6d\x4a\x92\x9c\xd6\xd3\xa7\x1d\xe8\x66\x91\x0a\x2e\xe6\xb9\xcd\x7c\x1b\xd7\x83\x50\x70\x90\xa6\xd9\xde\x08\xda\xa7\x5b\x08\x62\x95\x31\x96\x4a\x73\xb9\xe9\x1e\xb8\x54\x0f\xe4\xa6\x5c\xac\x52\x2f\xdd\xea\x2b\xcd\x15\x29\x12\x22\x10\x73\xd3\x38\x69\x23\xcc\x3c\x32\xef\xb4\xd2\x83\x9d\x2d\x35\x67\xa2\xeb\x31\x1c\x52\x41\x14\x72\x8c\x32\x24\xea\xa6\xce\x35\xa8\xbf\x45\xf1\x9b\xff\x35\x70\x64\x33\xaa\xd5\x0e\x71\xd5\xd8\x46\x25\x85\x1b\x92\x4e\x46\x33\x79\xc0\x84\x4f\xc6\x24\xfd\x07\xcb\x06\xd8\xee\x8e\xf8\xf6\x9e\xd5\x72\xc2\x92\xcf\x81\xa9\x34\xf4\x67\x88\x56\x9e\xe2\xa5\x64\xde\x8e\x9d\xbb\x7a\xd5\x49\x48\xd8\x18\x77\x0c\xc2\xb6\x10\x58\xc9\x99\x52\xdc\xfb\x54\x23\xaf\x7d\xf5\x27\x9e\x49\x14\x2b\x3c\xf8\xcf\xef\x73\x3f\xb7\xb4\x77\x31\xdb\xc1\xd4\x8b\xa3\x67\x3b\x4a\x1a\xd9\x60\x19\xf9\x1a\xbd\x73\x89\xdf\x17\x87\x8c\xa8\x3e\x03\xec\xf6\x80\x87\xc1\x44\xc1\x25\xae\x19\x65\x9b\x05\xca\xf9\xe8\x61\xfc\xa9\xce\x60\x4a\x26\x0a\xfd\x6a\xc5\xc2\x9c\xef\xb9\xbd\x1d\x42\x23\x00\x76\x61\xf0\xd4\x9f\xc7\x4b\xeb\x6c\xf7\x2a\xfd\x8b\x83\xb3\x89\x5b\xfd\xb2\xd8\xc6\xa3\xa4\xfe\xf6\x65\x9f\x2c\x49\x5c\xdc\xa3\x5f\x78\x8b\x9c\x14\xf1\x12\xab\xc8\xa0\x04\xb4\x9b\x30\xf9\x5a\x5c\x9c\x7b\x43\xc3\x26\xe0\x1d\x41\xb8\xc7\xfa\xed\xb0\xaf\xec\xa9\xf2\xbd\xec\x1f\x45\xfa\xf0\x66\x97\x86\x66\xa8\x9d\x37\xcc\xfd\x1c\x49\xd7\xdd\xa2\xc4\xc6\x6b\x0c\x0b\x5d\xff\x30\x88\x46\x68\x2d\x6b\x54\xa3\x2e\x6c\x83\xfa\x51\xf8\xbf\xfc\x4b\xa3\xa6\x48\x61\x0b\x20\x7f\xfa\xd2\x47\x6a\x03\x9d\x3c\xb9\xe6\x96\x53\xcd\x79\x6c\x26\x4e\x2c\x17\xce\x64\x15\x83\xa5\xe3\x40\x1e\x89\x87\x4a\x3c\x7a\xed\x5a\x4e\xd5\x6a\x06\x6b\xb6\x26\x86\xb0\x28\x51\xca\x42\x32\xc1\xe9\x4c\x9d\xd9\x2a\x31\xee\x60\x31\x01\x82\x10\x88\x98\x3d\xb5\x60\x58\x9e\xb6\x5e\x6e\xae\xce\x2f\x4a\xf7\xfc\xbb\x3b\xfb\x7a\x70\xc7\xa1\x72\x9f\xb1\xcd\xd1\x32\x0d\x1a\xe9\x95\xf6\x11\x1e\xc9\x28\xe9\x12\x50\xef\x79\x49\x6e\x85\xf5\x8a\x5c\xb8\x33\x90\x65\xd9\xc0\x16\xc8\xf3\x33\xa5\xf5\x37\xba\x13\x59\xae\x16\x0e\x9a\xed\x52\x11\x45\xfa\x2a\x48\x9d\x7b\x0e\xda\xb3\x17\x06\x47\xf7\x05\x66\x69\xd3\x3c\xcb\x7c\xd7\xc5\x48\x33\x0e\xc4\xe9\x5a\x56\x54\x1f\x09\xb5\x60\x42\x22\x55\xca\x44\xf9\x81\xac\x26\xf7\xdb\x43\x30\xfa\x57\x39\x3a\x3e\xf2\xfd\xfa\xea\xab\x61\x13\x03\xe7\x4f\x4f\xb5\x46\xe9\x52\xeb\x2f\xcb\x0b\x2d\x8c\x7d\x2c\x07\xcd\x79\xb3\x5e\x1c\x90\x2f\x48\x24\x3a\x14\x46\xe8\x79\x9d\xe4\xbc\x1c\xaa\x4f\xe8\x3e\xdf\x87\x7b\x75\xa7\x22\x7f\x35\xbd\x84\xe6\x4f\xd4\x07\xd7\x70\xb2\x44\xcf\xb1\x3b\x3e\x8b\x63\xeb\x13\xe1\xa6\x11\x5b\x45\xe5\x51\xc6\xa7\xef\xef\x7f\x38\x7b\xf1\x52\xa8\x4c\x69\xaf\x8e\x56\x01\xba\x73\x5f\xd4\xc8\x10\x04\x12\xea\xfd\x38\x4f\x6b\x95\xa6\xd5\xea\xae\xfe\x66\xd8\xbc\x42\x00\xa2\xc9\x4f\x90\x6f\x9f\x6e\x8a\xde\xa5\x68\xa1\xab\x66\x3e\xc0\x8b\x9c\xfd\xfa\x99\x83\x81\x78\xb8\x20\xae\x05\x40\x88\x8c\x1f\x28\xae\x2b\xf3\xc3\x8a\x3c\x94\x31\x9f\x71\x02\x30\x4c\xd2\x4b\x56\xf4\xa1\x9d\xf6\x93\x49\x3b\x52\x28\xce\xc4\xca\xdf\xd7\xfd\xab\xe1\x93\xaa\xb9\x0b\xbb\x90\x58\x49\xa4\xfb\xe6\xda\x95\xd0\x7a\x3d\x90\xde\x54\x80\x3c\x03\x12\xe3\x4e\x0b\xa6\x57\x21\x3f\xc9\x53\x35\x9c\xde\x46\x61\x00\x50\xdf\x94\x2b\x50\xed\x05\x1d\x0b\xf5\xd3\xd2\x9f\x5c\xeb\x58\x06\x36\xd3\x73\x85\x9e\x68\xf8\x39\x51\xeb\x26\x35\xb8\x47\x02\x77\x3c\x21\x00\x7b\xfb\x80\x57\x42\x48\x4d\x0e\x02\xe0\xec\x8b\x80\x66\x8f\x5f\xb9\x9c\x7a\xba\x26\x9e\xf5\x40\x4d\xd5\x8a\x0a\x5c\x63\xdf\x55\xf5\xf6\x5d\xcc\xfb\x94\x81\xf9\x36\xdf\x8e\xe8\x86\xc3\xe9\x20\x02\xef\x34\x94\x6e\x03\x50\x37\x0d\xaa\x60\xa3\xfc\x6d\x58\x43\x39\xab\x47\xc9\xed\x8d\x64\xf4\xfb\x29\x92\x88\x51\x13\x80\x05\xe0\x3c\xbc\x4f\x17\xa9\xda\x63\x76\xa7\x77\xf1\xec\x67\x48\xb3\x2a\xf7\x24\xe2\x15\xaf\x52\xd5\x5e\xdd\x31\x75\xda\x63\x61\xe9\x67\x4d\x22\xda\x4b\xb0\x83\x4f\xae\x1f\xc4\xeb\xf5\x4f\xeb\x55\x3d\x4d\x0f\xdb\x98\xfb\xa5\x4f\xae\x3c\x59\x64\xe1\x57\xa9\xfc\x22\x56\x90\x01\xb0\x1b\x3e\x03\x9d\x0e\xdb\xbf\xa2\xf3\x86\x9a\x9d\xe0\x3a\x46\x64\x22\x4a\xc9\x24\xae\x55\x2a\x34\xec\x07\x52\x91\xb3\x3f\x3f\x1f\x47\x64\x34\x06\x72\x0b\x06\xb8\xcb\x1e\x4a\x06\x99\x46\xcc\xfb\xe1\x43\xa8\x26\x80\x37\xd9\xfc\x43\x27\xeb\xe8\x8c\xac\x54\xd9\xc0\x3b\xd4\xe3\xf5\xaf\xb6\x96\x8a\xba\x7d\x6f\x84\xfe\xcd\xe8\xd7\x32\xc9\xc5\x90\xd8\xf3\x51\x20\x00\x54\xac\x51\x6e\xc6\x0d\x70\x04\xc3\x07\x2f\x14\x1a\x61\x44\xd8\xd4\xb4\x7f\x6a\x07\x39\x5b\xed\xaa\x7c\xc9\x45\x61\x14\x4a\x03\x20\x3b\x7c\xa1\x3e\x89\x78\x25\xf2\xbc\x3f\xa3\xc0\x8e\x1f\x9f\x98\xd1\x25\x47\x8c\xdd\x68\x27\xcc\x1c\x9c\xdf\x5e\x89\x1b\x8a\xff\xc6\xb5\xaf\xec\x90\x07\x33\xfd\x28\xb8\xf2\x77\x6e\xfb\x0a\xde\x74\x6e\xeb\x76\x41\xca\x86\x5e\xb0\xe4\x20\x9f\x59\xff\x28\x72\x82\x99\xe8\x6d\x22\xf6\x2d\x1f\x6a\x3c\x8a\xd1\x49\xcd\xaa\xa0\x97\x08\x70\x62\x1f\xa3\x5a\x65\x6f\x58\xb8\xd7\x63\xff\x89\xc1\x0e\xdb\xe2\x81\x2c\xce\xb8\x4e\x99\x12\x00\xf6\x9d\x83\x9c\xfc\x68\x55\xec\x17\xd2\x95\xf5\x4f\xb9\x6d\x00\x43\xc1\x35\xf6\xb0\xa2\xb4\x6a\x67\x6a\xe4\xd7\xb1\x36\xc2\x6c\xcd\x13\xb5\x11\x96\x58\x19\x7f\xf3\xb4\xfa\x4a\x7e\xe8\x9d\x25\xa9\x0d\x1b\xc9\xef\x83\xcc\x62\xf5\x07\xad\xe4\x20\xec\x17\x0f\x1a\x29\xc9\x92\x0b\x62\x9c\x99\x31\x33\xc8\xe1\x8c\xe1\x02\x36\xe3\x8b\x6a\x5c\x20\x3a\x0d\x55\x05\xfc\x73\x9d\x5f\xa3\xbd\x2f\xeb\xfd\x47\x13\x24\xa3\xc5\x79\xdf\x80\xf0\xdf\xd0\xa8\xa9\x42\x31\xaa\x63\x99\xe5\x54\x18\xde\x37\x2e\xdd\x80\x5e\xd2\x7c\xfe\x44\x56\x20\xae\xfd\xcd\xc6\xfc\xa9\x86\x4b\x80\x83\xee\x29\x5f\xbf\x71\xac\x5a\x71\xbe\xd0\x6e\xa9\xda\xef\xf3\x72\x46\xb1\x68\x01\x78\xb1\x17\xab\x72\x8f\x8b\x05\x28\x42\xeb\xf5\xfe\xe9\x42\x1c\x21\x5a\xfa\x87\xa7\x8b\xaa\x4b\xef\x90\xee\x72\xf0\xb1\x12\xaa\xfc\x7a\x9f\x87\x2d\xa7\x54\xcf\x5e\x59\x2c\x74\x61\x15\x20\x06\xb1\xe7\x3b\xe8\x53\xf2\xb9\x25\x96\x54\xa0\x31\xf9\xf4\xb0\x35\x4a\x37\xd4\xa1\x1c\x3e\x7d\xfe\x30\x9c\x12\xe8\xc4\xea\x6b\x9f\x5e\x16\xeb\xbf\xfa\x4c\xee\xd1\x1b\x36\x0e\xd5\x81\x1d\xec\x36\x1c\x56\xb8\xe5\x79\x3e\x8f\x1c\x38\xcb\x2f\xab\x51\x89\x17\x0a\xbd\x41\x44\x2d\xf4\x5d\x2c\x44\xe9\xcc\x95\xbf\x41\xa1\x0c\xd5\xd3\x3d\x87\xfd\xec\x7b\x82\x89\xb4\xdd\xed\x9f\x54\x41\x0a\x22\xa5\xb4\x17\x2d\xad\x7a\x10\x97\xe1\xc4\x10\x80\x21\x72\x62\x61\x85\xf2\x3d\x55\x41\x25\x5e\x6a\xf5\x45\x18\x1e\x65\x67\xf8\x7c\x68\x99\xfc\xef\xf9\xe4\x30\x67\x28\xc6\x2b\x62\x0a\xf1\xbb\x97\x6f\x2c\xca\x7d\xc3\x7d\x75\x07\xc0\x8a\x19\xa6\xc5\x7e\x15\xcb\xd9\x3a\x45\xa4\x17\x27\x02\x8b\x11\x00\xf1\xc6\xa7\x9c\xf4\xda\x8d\xf1\x93\x8b\x68\xb0\x4a\x7c\xfe\x0c\x67\x2d\x2c\xdf\xd3\xe2\x6e\xab\xa2\x30\x0c\xfa\x4e\xb6\xc5\x1a\xcd\x36\x9c\xdd\xe8\xe7\x5d\x94\xd2\x84\xec\x2b\x93\xf5\x1e\x02\x25\xa7\x38\x7f\xde\xc9\x37\x67\xf9\xc7\x7f\x3c\x05\x0e\xfd\xd4\x6c\x14\xc6\xca\x33\x0a\x9f\x2c\xa1\x5f\xa5\x52\xe2\x5d\xda\x85\x2d\xc5\x82\xc1\x31\x00\xd3\x7f\x82\xae\x5d\x3e\xbc\x28\x4c\x6c\x5e\xeb\x7e\x5f\x8d\x7c\x39\x8f\x13\x5f\x7e\xc3\x97\xf0\xd9\x66\x0c\xd9\xec\x26\x34\x78\x70\x1d\x66\xc8\xf2\x9f\x32\x88\x10\x16\x2a\x4a\x1a\xef\xe0\xe8\x4f\x16\xe4\xcd\xf5\xfd\x53\x3b\x2e\xa1\xe0\x38\xe6\x86\x9c\xfe\x72\x25\xd9\x6d\xad\xfe\xae\x0c\x02\x52\xba\xfa\x15\xfe\xf6\x19\x78\x0e\xa7\x34\x36\xe6\x9f\x4b\xcc\x9f\x68\xaa\x24\x32\xc6\xc0\x89\x62\x11\x15\xe1\x61\x75\x5b\x64\x61\x97\xf8\x36\x4d\x68\xca\x9b\x85\x99\x68\x0b\x60\x59\xaf\x7d\xca\xe5\xbb\xcf\x66\xfa\xa5\x70\xbc\x9c\x72\x53\xaa\x30\x00\x45\x9b\x1c\x99\xe8\xd9\x76\x13\x83\x3b\x2e\xd1\x91\x93\x8a\x20\x8a\x14\x4d\xfd\x20\x33\x7c\xe9\x5d\xbe\x87\x4b\xbd\xa5\xc6\x18\x24\x36\xe9\x65\xcb\x24\xcc\x57\xf2\xab\xdd\xe2\x42\xfe\x9c\x2c\xfd\xb4\x95\xb6\x27\x00\xc9\xe6\xd4\xa5\x12\x75\x8b\x60\x30\xa3\x01\x47\xba\x2f\xf6\xa8\x53\x7c\x7f\x09\xdd\x52\xb7\x27\x10\x2a\x83\x7f\x83\xf5\x3a\xa5\x4e\x0f\xda\x9c\x52\x68\x02\x92\xf4\x4f\xa2\x6d\x76\x20\xd1\x7b\xbc\x67\xf8\xd4\x92\xe5\x57\xe5\x1e\x74\x6a\xf4\x67\x78\xbf\x5b\x40\x22\xda\xf6\xe9\x0d\x93\xce\x83\x79\xd9\x6f\xf5\x94\xd4\xb0\x97\x58\x4e\xf8\x95\xdf\xaa\x57\x06\xb4\xcd\x7e\xa6\xad\xe2\x61\xa9\x8f\x41\xc1\x64\x7d\x01\xa4\x9d\x54\x05\x4b\x3a\xcf\xd7\x1a\x07\x0e\x24\x20\xfb\xe6\x9e\xac\x99\x68\x2d\xbd\xbb\x14\xb7\xf8\xfb\x0d\xc9\x23\xe2\x44\xab\x39\x9d\xc0\x94\xd3\xed\x0e\x92\xc0\x05\x08\xab\xdc\x37\x0b\xd4\xfb\x55\xc6\xa4\xad\x01\x20\xab\xa4\x09\x20\xf8\xf2\x98\x66\x3b\xd0\xa8\x8f\xca\xbd\x0c\x78\x5e\x6c\x2d\xca\x3a\xe2\xbe\x9f\xfd\x3f\x58\xe8\x59\xc0\xed\x6b\x18\xb5\x78\xa3\x8d\x47\xb2\x5c\x9a\x11\x84\xd0\x2a\x44\xdd\xd1\x51\xe6\x12\x8e\x82\x6c\x10\x20\xf6\x5a\x2d\xea\xeb\x58\x62\x2d\xd7\x7b\x93\x36\x4c\xf0\xbe\x82\x4e\xaa\x9e\x5c\xb7\x51\x88\xd6\x84\xb2\xad\xe4\x2f\x8e\x37\xf1\x71\x8f\xee\xd5\xf7\x09\xe4\xa3\x9c\x45\x2e\x10\x60\xc5\xdc\xc4\x9d\x85\x27\x19\xbd\xeb\xc0\xa7\x0a\xf1\x75\xec\x77\x36\x63\x7b\xd5\x7e\xb2\xb0\x89\x78\xe2\x63\x70\xa0\xe7\xc5\xfa\x2f\x1f\xe0\x9e\x8c\x48\xeb\x17\xb5\xa9\x51\x6d\x0f\xa3\xec\xf4\xe7\x44\x04\x74\x1f\xe4\x59\x96\xe5\xb2\x7f\xab\xac\x61\xdc\x0c\x01\x30\x7d\xfa\xce\x46\x7f\x6f\x44\x84\xa4\x7a\xe3\xe6\x3a\xad\x97\x03\x96\x35\xd3\xdb\x1a\x25\x0b\x45\xcd\xcd\xe5\x47\xd9\x91\x1d\x08\xe2\x38\x06\xe0\x33\x83\x5e\xcb\x01\xd6\xc5\x82\xa9\x4e\xdf\x11\xb0\x9b\x9e\xeb\x12\xa6\x37\x51\x7a\x31\x98\x8f\x3a\x22\xe9\x4a\xf9\xf6\x6a\x41\xbb\x3e\xe6\xd2\xfb\x57\x77\xde\x59\x12\xdf\x56\x41\xa3\xe8\xef\x50\xb5\x9a\xfb\x1b\xd5\x99\xe8\xe7\xfb\x1d\x24\xf1\x9e\x82\x32\x03\x8c\xd4\x00\x63\x25\x32\xac\x0a\x41\x66\xd1\x3e\x0d\x01\x02\x53\xf0\xf6\x6f\x56\x80\x1b\x6b\x0f\xc1\xed\x60\x1f\xcb\xdc\xa8\xef\x64\xf6\x17\xc8\x21\xcc\xfb\xea\x8e\x31\xcd\x32\x72\xf0\xad\xcd\x64\x60\x92\xfc\x22\x17\x39\x91\x76\x2f\x2d\x02\x9d\x63\x37\x5f\x97\x5b\x8a\xff\x36\x32\xe7\x46\x9b\x93\xa0\xb6\xb4\x91\x19\x6a\x89\x95\xfa\x9b\x83\xd1\xc5\x7e\x97\x2f\x53\x4a\x06\x3a\x68\xa5\xa3\x39\x06\x37\x0f\x4d\xa5\x4f\xe7\x1d\x30\xf5\x0a\x24\x80\x94\xb7\x02\x49\x7a\xcb\x56\xc5\x22\xaa\x99\x02\x5c\x79\xd0\x4a\xa2\x9a\x72\xd2\xca\xd6\xf5\x41\xad\x21\x3e\x94\xcf\xc5\xa0\x70\x37\xb3\xdb\xcd\x37\x82\xc9\xf7\xdb\xce\x1b\xa3\x71\x9b\x4c\xa8\x49\x81\x02\xac\xdf\x70\x89\x7a\xb0\xe2\x5b\x97\x67\x2c\x9b\xdf\xe5\xe3\x4b\x99\x8c\x19\xcc\xf1\x99\x7e\xbb\x7f\x75\xcb\x5e\x28\x02\x68\x72\xe5\x37\xf0\x2c\x49\x42\xe9\x2c\x17\xa7\x9d\xa9\x57\x74\x72\x01\x92\xe5\xfb\x45\x34\x3a\x62\x50\x10\xc1\x28\x12\xec\xdd\xc3\xe3\x10\xbb\xa1\xd4\x2a\x96\x53\xcd\x7e\x0f\xce\xda\xb8\xd3\x6a\x0f\x88\xd1\x32\xa7\xda\x90\x89\x41\x30\x98\x0f\x6e\x2e\x07\x88\x41\x4d\x41\x87\x7b\xe3\xad\x8f\x18\x00\x08\xb1\x7b\xaf\xeb\xb9\x38\x06\xd5\xd5\xf3\x78\x9e\xdb\xb8\xf3\x7b\x46\xfb\xa6\x6e\xa3\xe0\xae\x8b\xf6\x64\x18\xeb\x1f\x50\xf3\x93\x12\x0d\xef\x15\xb6\x42\x2b\xf4\x31\x89\xa6\x93\xae\xc1\xc3\x8e\x72\x79\x57\xb0\xfe\x66\x21\x80\xe3\x97\x5d\x43\x14\xc9\xf3\x91\x21\x08\xf4\x2a\xa4\xe8\xfb\x12\x3e\xe5\xae\x35\xcb\x51\xa8\x87\x41\x89\x94\xd2\xd0\xef\x07\xe9\xea\x42\x0d\x4f\xe8\xb2\xac\x7a\x1b\x37\x66\x41\x30\xc6\xdb\x6c\x91\xf1\xcb\x78\x32\x46\x0a\x00\x22\x20\xf3\x44\x17\x52\x7b\xf8\x29\x9e\x1a\x31\x01\xad\x36\x33\x07\x65\xd1\x30\x79\x66\x78\xd6\xfb\xaf\x67\xcd\xad\xc9\xce\x6d\xc5\x77\xa5\x87\xe4\x82\x48\xbe\xef\xfb\x34\x54\x7c\xa4\xf5\xb2\x3c\xcb\x02\xdf\x00\x08\xb5\x13\x99\xd9\xdf\x23\xc5\xb6\x7b\x8e\xc8\x71\xcc\x7c\xe9\x42\xf2\xcd\xa8\x78\xa7\x68\x34\xbb\x51\x73\xb5\xfc\x6d\xd0\xe2\xa2\xbf\xfa\x91\x4e\x62\xbe\x9c\x36\x3a\x82\x81\x22\x05\x7b\xbe\xf1\x8a\x60\xa2\x69\x5e\x11\x2a\xe5\x4b\x90\x61\xf6\x1c\x04\xab\x71\x95\xae\xe6\x86\xfe\x15\xdd\x4c\xa6\x18\x19\xbd\x2c\x3d\x12\x16\x9f\xc4\xf8\x3b\xbb\x56\x1f\x8b\xed\x60\xda\x65\x5f\x95\x6e\x51\x3a\x1b\x6d\x5b\x0f\xdd\x0e\x8b\x72\x40\x91\x00\x80\x37\x00\x27\xe2\x5e\x48\xd4\x4d\xc6\x0f\xca\x42\xb4\xd9\x27\x12\x52\x10\x79\xac\xfc\x8c\xb1\xb7\x7d\x41\x0f\xd0\x1a\x1b\xfd\x50\xe1\x43\x60\x7e\xea\x83\xcb\x72\xe3\x46\x24\xae\xa5\x85\xe7\x91\x40\x04\xa9\x0d\x0c\xe6\x3e\xb2\x81\x96\x65\xf1\x35\x27\x98\x94\xf0\xb1\xaa\x98\x22\x64\x76\x09\x2a\xbd\x72\x9a\xba\x4e\x9b\xd2\x1f\x26\xff\xb7\xcf\xdb\xbd\xbc\x98\xb0\x98\x3e\x79\x87\xf5\xf8\xa6\x7b\x07\x44\xd6\xee\x32\x3b\x92\x1b\x7d\x08\x52\x22\x65\x18\x0c\xeb\x92\x0c\x60\xe6\x1e\xd3\x70\xb7\xa8\x29\xec\xf2\xde\x17\xc0\x5d\x64\x10\x42\x75\x7e\xe2\x75\x0b\xba\x74\xde\xf6\xd4\x43\x2e\x83\xb5\x22\x9b\x57\x70\xe9\x0e\x70\x77\x7f\x47\xe1\x48\xf4\xde\x44\x78\x37\x00\x6e\x48\x01\x8a\x84\x2a\x02\x58\x5c\xa2\xa6\xa8\xb3\xef\x9b\xbd\xe4\xd6\x1e\x0f\xe5\x5c\xdb\x66\x3f\xf8\xe6\x60\x2b\x48\xc2\x01\x72\xe1\x6f\x8d\x79\x86\xdd\x1c\x2b\xc8\x52\x60\x0e\x79\x5f\xa2\x17\xfa\x2e\x4c\x93\x62\x64\x3a\x6a\x8b\x84\xf5\x06\x24\xc3\x19\x46\xc6\x1d\x59\x0f\x4d\x3b\x8d\xe7\xa9\x09\x92\x2c\xdf\x09\x17\x3b\x24\xe2\x63\x3b\x84\x56\xb5\x59\x81\xf6\x4e\xfe\xb9\xde\x05\x86\x44\x1d\x9e\x80\xaf\x49\x1b\x14\x92\x1a\x46\xee\xfb\x3d\x80\x2f\x93\xd8\x18\x9b\x1c\x4f\xfd\x79\x01\x64\x73\x76\x03\x10\xe4\x08\x46\x16\xd8\x9d\x1d\x0b\x23\x9d\x95\x5f\xa3\xba\xd4\x5a\x64\xdc\xc8\x4b\x10\x6c\x65\x77\x26\xb0\xc6\xc3\xfe\x57\xe3\x7a\x6b\xba\xee\x40\xcf\x52\x3b\xa9\x1c\x4e\x0b\x50\x41\xb7\xcf\xc2\x07\x96\x59\x3f\xd3\x53\x08\x10\x46\x17\x56\x0e\x61\xf2\x15\x43\xac\xf1\xd3\x81\x7b\xf0\x3b\xaa\x83\x90\x25\x9b\x3f\xbd\x15\x3f\xc4\xd3\x47\x8c\xcb\x4a\x4b\x2d\x6e\x7c\xf0\xef\x30\xf6\xce\xf3\xeb\x89\xec\x2b\xda\xef\x5a\x70\xe9\x6a\x9c\xfc\x76\x40\x48\x03\x80\x09\x00\x6c\x05\xb9\x81\x2c\x7e\x62\x4f\xe9\xcc\x00\x1c\xef\x09\x82\x30\x36\x81\x00\x6c\xf9\x16\xa0\x4b\xd6\x58\x36\x83\xbc\x3a\x83\x5d\xc6\xa6\xa7\x35\x79\x72\x15\xba\x58\x64\x4f\x99\x9d\xa2\x87\x68\xa1\x8b\xf2\x8f\x3e\xe4\x26\xa9\xcb\xd4\x72\x59\xac\x86\xd1\x02\x92\xb8\xfb\xf1\xdd\x34\x30\x1d\x63\x1c\x00\x04\x81\x2c\x05\x33\x70\xcd\xf7\x5a\xaf\x0b\x11\xa7\x93\xd3\x49\x26\xda\xfa\xc0\x24\xfd\x47\x62\xf4\xe6\x40\x61\x0b\x13\x02\x3e\x70\xb8\x4f\x0a\x3f\x1f\x85\x62\x2c\xb4\xfe\x7c\x2a\xad\xca\xe5\xe8\x63\xe1\x0f\x65\xd7\xb4\xfa\x71\xa8\x46\xee\xb3\x7e\xc1\xce\x0c\x73\x5d\x03\xe3\xfb\x10\x39\x92\x4c\xf7\x3c\x26\x58\xfc\x38\x54\x07\xa6\x8f\x40\xb2\xa7\xbe\x8b\x31\xe9\x06\xa9\x80\xcd\xf4\x26\xe4\x4d\xf2\x53\xdf\xed\x45\x65\xb3\x5c\x0d\x8e\x12\xf0\x03\x7c\x93\x5a\x4d\x6e\x38\xf1\xa8\x0c\x3e\x78\x20\x5c\xfd\xdf\x9c\x49\xb1\xf5\x63\xea\x4d\x8f\x2f\x03\x17\x4b\x89\x9c\x81\xab\x8b\x20\xb9\x96\x03\x0d\xe6\x40\x50\x90\xa2\x70\x95\xf6\x22\x57\xf9\x02\xc6\x9d\x60\x92\xed\xec\xcc\x57\xf8\x92\x7a\x3d\x47\x78\x2a\x98\x84\x66\x26\xbe\x8b\x61\xe3\x1e\xaa\x07\x87\xbf\x59\x76\xa4\x73\x6d\xb6\x3c\x8b\x5e\x65\x59\x0f\x6e\xf7\xc3\xde\x7e\x4e\xfc\xa0\x01\x28\xbc\x8c\x93\x31\x08\x26\xce\x89\x7d\xc7\x70\xff\x73\x27\x68\xe7\x2b\x6d\x75\xa6\x5e\x6b\x3a\xad\x84\xa7\x9f\xbc\xef\x5b\xa4\xff\x1f\x9f\x58\xe7\x08\x5f\xe8\x44\x77\x35\xb8\x35\xf3\x49\xa4\xd1\x8b\x40\xc3\x4e\x42\xe7\x4c\xb3\xd9\xfb\x00\xd4\x59\x89\xeb\x5f\x8d\xe4\x61\xe1\x64\x2e\x44\x12\x6c\x2d\xb1\x12\x4b\x0b\x50\x06\x8d\x18\x23\x02\xc6\x35\x9f\x63\x6f\x5c\x62\x7e\x5c\x80\xa6\x1a\x74\x3b\xae\xee\xc7\x72\xd4\x64\x1a\xdc\x6e\x5f\xd2\x71\x5d\xaf\x32\x6c\x8a\xbc\x10\xec\x37\x34\xbc\xeb\xf0\x42\x13\xbe\xe5\x44\xb1\x90\xfa\xa5\x99\x13\xe1\xd3\x94\x9b\xb1\x06\x81\x64\x5a\x7f\xb2\xf9\x07\x66\x20\xdf\x70\x66\x27\xd8\x9d\x45\x3b\xe7\xe4\x07\xec\xb3\xab\x4a\x99\x2a\xe3\xcf\xf9\xbd\xcf\x77\xfa\xe8\xa7\x57\xed\xba\xa1\xe0\xef\x6a\x62\xdf\x4f\x5d\xfe\xfe\x87\xe3\x49\x4e\x9f\xe5\xda\x59\xa8\xaf\x12\xb9\x7c\x95\xfa\x1a\xcd\xb4\xa5\xd8\x56\xb1\x6e\xb5\xb8\xe5\x2b\xbc\x04\x0c\x02\x67\xee\x45\x56\x59\x14\xf3\xed\xe7\x4f\xa8\x0e\x67\xb5\xba\xd3\xea\x76\x8b\xa8\xf8\x65\xb8\x55\xb3\x43\xef\x8a\x4a\xba\x8d\x52\x28\xe0\xcc\xdf\xff\xcb\x55\xc7\xeb\x96\x04\xa1\x09\x38\x61\xfe\x28\x77\xd7\x04\xdd\x1e\xd6\x22\x62\xc8\xee\xf6\x20\xd7\x0d\x2d\x23\x6c\xca\xf9\x2b\x81\x66\xe7\xf8\xa1\x43\x09\x54\xc2\xfe\xe0\xe6\xdf\x99\x29\xff\xf2\x24\xa1\xbf\x93\x10\xd3\x47\xe4\xc6\xec\xe6\x54\x2d\xfd\x7a\xc1\x87\xf1\x81\x07\x35\xaf\xee\xe4\x5a\x95\x1b\x79\xa7\x99\xb3\x2f\x49\xe5\xbe\x0b\xa2\x7f\x22\x9f\xd2\x7d\xfd\xe5\xf3\xe6\xdf\xbd\xc8\x70\x5f\xea\xd1\x9d\x3d\xe1\x9a\xdc\x9b\xcd\xa5\xd7\x8e\xd6\x4f\xdd\x78\x7d\x5f\xed\x18\x74\xf2\x0b\x66\xed\x6d\x4f\xa9\xcd\x06\x89\x4c\x0b\xd6\x25\xcc\xdd\xe2\x8e\x9f\xc7\x77\xe3\x40\x27\xbf\x3f\x7f\xb1\x33\xea\x15\x68\x52\xd0\x7d\xeb\x67\x24\x47\xad\xa7\x3e\xb6\x68\x4e\x70\xba\xfe\xd6\x56\xf5\x9b\xca\x96\xad\xde\xdc\x1a\xf5\x39\x8c\x59\xfb\x5d\xad\xca\xec\xf1\xcf\xa7\x52\x05\xbd\xf3\x3f\x9f\x2e\x3e\x94\x44\x04\x20\x49\xe8\x46\x64\x08\x4b\x3f\xb3\x6b\xb0\x7d\x50\x39\x85\xc1\xea\x4e\x24\x8b\xb9\x6f\x5c\x50\xe6\x64\x6e\xc3\x1e\x50\x21\x7b\xd1\xed\x87\xb9\x96\x09\xdd\x6a\xac\xe6\xc6\xf7\x33\xfe\xc5\xad\x6b\x0d\xad\x6b\x3e\x38\x27\x6b\xec\x61\xc5\xb6\x65\x91\x8b\x38\xba\x1e\x14\x89\x28\x6f\xad\xbb\xa9\x41\xc7\x16\x5b\xdc\xb3\x07\xc1\x9c\x97\x70\xe5\xec\xfd\xfd\x3b\xc7\x65\xd4\x1a\x29\xb9\x6c\x5f\xd6\x6c\xc6\xbc\x29\x84\x3f\xe4\xf8\x93\x8f\x58\xee\x98\x2f\x8c\xb2\xf6\xea\xfb\xac\x29\xac\xbc\xbf\x79\x55\x94\xf9\x91\x0b\xa0\x30\xb2\x7f\xf3\xbb\x5a\xd6\x68\x52\x30\x7d\x6b\x99\xed\x8c\xa5\xca\xa9\xab\xb9\x3e\x11\x57\x6d\x3a\x65\x6d\x50\x85\xe5\x52\x12\x6b\xce\xaf\x03\xeb\x6f\xd0\xf6\xb7\xb5\x42\x35\xfc\x30\xc7\x73\xd0\x9f\x56\x90\x1d\xbf\xfa\x65\x45\x6b\x50\x75\x89\xb2\xb8\x80\xc2\xe4\xed\x2e\x8b\x34\x08\x69\x64\x83\x70\xd6\x86\x33\xed\x73\x81\xd8\xc6\x4b\x69\x48\xfa\xa4\x8c\xdb\xc1\x0d\xf9\xeb\xed\x12\x1d\x4b\xc7\xff\xab\x87\x21\x24\x11\xa6\xf5\x29\x27\x10\x4c\x95\x93\x8c\x8d\xbb\xdf\x2f\x4d\x8b\xd7\x74\xe8\xbd\xcf\x98\x2b\x67\xfa\x7d\x4b\x21\xa6\x7f\xce\xb7\xf9\x76\xe5\xb9\x02\x44\xfd\x5f\x0e\xd0\x76\x96\x9e\x3d\x2d\xe3\x85\x6b\x55\xb0\x9a\x53\x3e\x30\xb8\x11\x1a\xd2\xc8\x1f\x4f\x61\x80\xc2\x61\x68\xae\xa9\xd6\x82\x1d\xbf\x3b\xac\xcb\x0f\xc5\xaf\x29\x97\xca\xff\xac\x47\xba\x2c\xc7\xe8\xc5\x3f\xdf\x33\xc9\xd5\xb0\x7d\x93\xbb\x16\x6a\xc7\x08\x69\xd7\x9a\xdc\x97\xfa\xf1\x58\xb1\xb9\x3b\xca\x59\x0f\xfd\x73\xbc\xb4\xc2\x3b\xd9\x4b\x65\x5b\xd5\xfe\xb0\x39\xcd\xa9\xd3\x76\x2f\x15\xb3\x4d\x72\x3d\x50\x25\xf1\xfa\x6f\x1e\xb9\x05\x13\xf5\x45\x5d\x42\x65\xb1\x0b\xe5\xe8\x9a\x6f\x66\x9f\x96\x51\x4e\x06\x4f\xe4\x0b\x84\x19\x4b\x6f\x17\x43\xe7\x33\x1f\x60\x1b\x27\x4f\x5e\xb8\xa9\xe9\x7d\xcd\x44\xd3\x8f\x8a\xb0\xdf\xcf\xfe\x6f\x1c\x0d\x9b\xaf\x9d\x08\x86\x93\x8b\x58\x84\xdc\x23\xb8\xdf\xf3\x2e\x50\x48\xd6\x97\xd1\xa1\x9e\xb4\x41\x09\x5f\xda\xcb\xb9\xa7\x74\x3b\x98\x9d\xbf\x23\xc6\x90\xb7\x2c\x8f\x8c\x2f\xfe\x1f\x6c\x1b\x4c\x7a\x63\x3b\xf9\x0a\xdb\xa5\x6a\xe1\x15\x76\x01\xcf\x22\x54\xcc\x9b\xbd\xbc\x12\xa6\x5c\xc8\x4e\x1b\x76\xef\xb0\x0b\x9b\xc5\xb1\x21\xea\xe6\x0d\x16\x53\x9b\x15\xe3\xed\xa8\x3d\xa7\x1a\x4d\x2a\xf6\x8b\xd5\xff\xfd\x3e\xa5\x76\xbd\xd1\x55\x44\xed\xcf\x33\xba\xf0\x7b\x28\x87\xe0\xa3\x5b\x3f\x16\xb6\x76\xe2\x98\xed\xb0\x83\xf7\x7e\x3a\x6e\x1b\x5a\xc9\xfd\x9a\x31\x36\x9c\x8d\x0f\xce\x69\x38\x62\xc6\x5e\x15\xd9\x56\x42\x11\xaf\xed\x19\xfd\xea\x5e\xf8\x50\x9a\xa0\x2f\x67\x89\x2d\x9f\xaa\xf5\x26\xc7\x34\xf9\x72\xcc\x16\x81\xe6\x83\x04\xb3\x2f\xaa\x8a\x85\x6c\xf5\x4b\xaa\xd2\x90\xa5\x4f\xaa\x07\x1a\xbd\x87\xea\xa5\x54\xf8\xdd\x45\x19\xfb\xed\xfe\xfd\xfb\xf0\x50\xbd\x11\xe5\x19\xb5\x5f\xf6\x5c\x08\xed\x12\x2b\xb1\xea\x84\x24\xef\x6a\x08\x8a\x4c\xc4\x5e\xd2\x66\x54\x0c\xd7\x51\x17\x12\xdc\xd7\x8c\x0d\xb1\x85\xae\x52\x15\xf0\xbc\x3b\x77\x12\x9d\xa5\x73\x9f\x2c\x05\xea\xcf\xe0\xcb\x3d\x87\xc7\xfc\xbb\x23\xaf\x5e\x59\xff\x86\xde\xaa\xb5\x4b\x3c\xa7\x31\x9e\xad\xee\x04\x9d\x76\x8c\x7c\x75\xa3\xe1\xa0\x49\xb3\xa5\x6e\x3e\x13\xc5\x9f\xe8\xcc\x2e\xe3\xf4\x24\x73\x17\xe3\x8b\xed\x45\x6f\xaa\x00\xe3\xb9\x6f\x33\x2a\xf6\xcc\xe6\x48\x7d\xf9\xd5\x78\x3f\x3b\xe5\x6a\x4e\x27\x61\xca\x73\x89\x85\x4f\x0c\x1b\xb2\x11\x73\xb9\x2a\x86\x37\xff\x06\x60\xad\x83\x4e\xaa\xe1\xdb\x13\x9e\x2d\xe5\xb9\x53\xea\xbf\x4d\x86\x66\x0a\xf7\x3b\xe4\x87\x1a\xf2\x94\x8b\x1d\x56\xd2\x49\x35\xb7\xbf\x9f\x0d\xf1\x77\x56\xc0\xbc\x9c\x5e\x62\x1b\xaa\x57\xaf\xf3\x6e\xd2\x68\xed\x8f\x90\x45\xc8\xd9\x3a\xdc\x61\x5c\xf2\x7a\x09\x26\x3a\xc7\xae\xf7\xd3\x84\xa3\xf6\xa2\x82\x45\x7c\x61\xf4\xac\xc6\x17\xa7\xb4\x18\xb8\x83\x4d\xbe\x67\x79\x6c\x85\xfd\x2d\x2d\xbf\x7c\x52\xeb\x6c\x3d\x2f\x02\xde\xc4\x4c\x20\x29\xca\xb5\x6c\x9a\xe3\x7e\xd4\xdd\x81\x8e\xdb\x06\x93\xbf\x18\x03\x2e\x15\x4d\x96\xf8\xcb\x0d\x6b\xb2\x7b\x99\xd2\xd5\x00\x7b\x6a\xbd\xc5\x0d\x81\xf8\x67\xf7\x4f\x3d\x9d\x5d\xbc\xcb\x20\x6f\xb7\xf1\xf9\x36\xdf\x56\xd4\xde\xd8\x22\xcc\xc3\xaf\x81\xdb\x91\xfd\xc4\x4f\xc8\x9b\x4d\x2c\x6a\xda\x5d\xa0\xb3\x51\xb4\xd1\x6d\x45\x1f\x6b\xf3\x54\xe0\xde\xe1\xfd\x8d\x3e\x17\x15\x8d\x42\x11\x1e\x87\xb8\x4c\x03\xa8\x59\xa7\xaa\x07\x5a\x97\x5b\xe6\x33\x41\x6f\xf2\x26\x94\x15\xd9\xa6\xe7\x50\xe5\xc9\x46\x18\xd3\x11\xf7\xfb\x15\x0e\x9f\xdf\xdf\x21\xd1\xcd\x28\xc7\xb2\xa6\xd9\x5f\x52\x52\xc5\x96\x60\x9e\xc8\x03\xa8\x48\x8a\xef\xfe\x69\x12\xb9\x5a\x3c\x1e\xe2\xe3\x29\x99\xef\x8f\x33\xa7\xda\xa0\x89\x93\xaf\xda\x05\x2a\x09\xb2\x5f\x16\x96\xc8\x9c\x89\xa3\xa0\xa5\x66\x7b\xfe\xe7\x5e\x09\x9a\xcb\x16\x77\x46\x79\x4b\xe2\x7a\xa2\x66\x77\xea\x59\x08\x2a\xf7\x1b\xc7\x4f\x5d\xad\x15\x2b\x34\xd7\x39\x12\x6a\x91\x04\xef\x21\x5f\xda\x19\x9b\xc8\x93\x7f\x9c\x2a\x30\xcf\x15\x57\x4a\xb3\xe4\x14\xfa\x79\x84\x6f\x66\x14\x0b\x2a\x22\xf2\x8b\x4f\x5f\x09\xe5\x7d\x9b\x17\xf7\x52\xd0\x4b\xad\x07\x9c\xf2\x5f\x4c\x58\x2e\xbb\x7a\xf1\xdc\x24\xda\xf5\x3f\x33\x1a\xee\xd1\xf3\x66\x77\x95\x29\xd8\x34\x3c\x6b\x4c\xa1\xad\xaf\x07\xc1\x3f\xce\x19\xa3\xb1\x9a\xde\xf2\xd7\xe7\xb9\x31\x4b\x2f\xb7\x2f\xc9\x47\x21\xc8\x14\xe2\x55\x3e\xaf\x79\x1f\xa9\x71\x0d\x57\x41\x43\x49\x14\x25\xca\xec\x25\x37\xbb\xaa\x3d\xc6\x22\xfd\xed\xc9\x49\xb7\xb8\x73\xf8\xb1\xd1\xa9\x50\xca\x1b\x42\xb2\x24\xd3\x19\x13\x85\x2b\x67\xbb\x60\xd1\xec\xc6\x97\x7a\x25\xad\x34\x11\xee\x8b\x7a\xc7\x18\x34\x42\x7a\x4f\x06\x60\xcc\xd6\x30\xf1\x35\x02\x8c\x6e\xc1\x99\x8e\xf4\x83\x2b\x36\x1b\x68\xcc\xf8\x59\xf3\x01\xc1\x6f\x4a\x41\x8e\x25\xfd\xfa\x4f\x6c\x49\x3f\x75\xba\x63\xf1\x8b\x4b\x73\x17\xb3\x88\x97\x6b\xc1\x70\xab\xbf\xb7\x4a\x19\x61\x7f\xe2\xae\xd5\xfb\x42\xef\x67\xb2\x23\x36\xc5\x85\x34\x32\x63\xc4\xe3\xfb\xfb\xce\x50\xb3\xf1\x3e\x7d\x2c\xf8\x7e\x76\xa5\x7c\xb6\x0e\x93\x58\x49\x57\x2a\x94\xef\x81\xde\x98\xb1\xe1\xaf\x4d\xb9\x33\x55\x7c\xfe\xbb\x0b\x49\x5d\x0b\xa1\x35\x1e\xba\x24\x5f\x45\xdb\x10\x04\x96\x74\x97\xf7\x9e\xaf\xb4\xa4\x5b\xb8\x75\x25\x68\x16\x7c\x37\xe1\x82\xc7\x24\x2d\x55\x9e\x80\xdd\x0b\x09\x21\x44\xe7\x6f\xd9\xea\x23\xa1\x3d\xce\xd2\x58\x13\x42\xbb\x3b\x7f\x12\x7f\x35\x25\xdc\xd3\x47\x6c\x99\x17\x65\xad\x0e\x30\xcd\x76\x2e\x29\x81\x19\x46\x10\xcf\x77\x2a\x24\xc4\x72\xb3\x0a\xfe\x3c\x59\x67\x7c\x2a\x27\x24\x11\xe1\x07\x33\x57\x2d\xdf\x1c\xde\x8b\x8c\xe0\xea\xb9\x1b\xbb\x8c\xb2\xd7\x12\xf1\x13\xd9\xbf\x95\x0b\x0d\x1b\xb5\x46\x89\x3d\x81\xdf\x34\x01\x5b\xbf\xa5\xbf\x1e\x09\x5c\x27\x57\xd0\xc0\xca\x57\x63\x51\x15\x99\x68\x0b\x4c\x6f\x83\xc1\xe8\xe9\x98\xf8\xfa\x63\x55\x7c\x76\xeb\x2d\xaa\xef\x6b\x4b\xbc\x17\x06\x39\xfc\x5c\x4e\x86\x0e\x12\xfb\xbe\x3b\xc8\x8e\x31\x3a\x3f\x43\x87\xe3\x70\xca\x9f\x48\x4f\x24\x95\x89\xa6\xdc\x55\xf9\xc1\xff\xb2\xd5\x4b\x37\xc7\xbc\xcd\xfb\xdf\x59\xd3\x4f\x79\x3c\x55\xf3\x8d\x07\x11\x83\x69\x41\x77\x89\xee\x9e\x03\xee\x39\xc9\xc5\xf0\x59\x1e\x18\x92\x9b\xbd\x51\x69\xa2\x94\xa1\xa9\x10\x8a\x4d\x95\x22\x27\x1a\xf3\x67\x12\xac\x9f\xf2\x3d\xab\x6c\x16\xad\x38\x13\x9d\xe5\x04\x25\xa7\x97\x2f\x51\xce\xd7\x92\xf4\x3e\x7e\x7c\x0c\x04\x8b\xdb\x3f\x67\xf3\xf9\x7b\x36\x8f\x47\xde\x7d\x52\x47\xd6\xd6\x40\x89\x50\xff\x19\xf7\x13\xad\xd7\xc3\x93\x09\xf7\x10\x44\x3b\x31\x28\x7f\x26\x35\x58\x31\x5a\xb6\xbc\x1c\x2f\xa4\xd9\xb7\xbe\x34\xdb\x8f\x98\x23\xd9\xb7\xff\xc9\xf5\x9e\xda\xfa\x0c\x23\x08\xc2\x6a\x8c\xe9\x4b\x72\xc8\xfe\x41\x6e\xfd\xde\x20\x88\x17\x8b\x65\x9f\x7f\xc4\x17\xf5\x3b\xcb\x32\xea\xc7\x2e\xb4\x9f\x65\xc0\xda\xc5\xad\x78\x13\x0d\xde\x5b\xce\xad\xdc\x8d\x0e\x14\x64\xa8\xaf\x91\xb5\x0a\x01\xa5\x9e\x97\x22\xe5\x08\x55\xa3\x62\xf4\x10\x95\xcf\x25\x7e\x1b\x06\x10\x45\x19\x34\x13\x95\xc5\x1d\xd1\xcf\x4c\x1c\x88\x4e\x42\x77\xab\x1d\xc7\xdc\x09\xdd\x09\xda\xf7\x95\x7c\xbf\xe2\xdf\x58\x2a\x1e\xb0\x09\x71\x5f\xda\xa2\xd5\xe9\x25\x1c\x3c\x07\xa3\x4c\x30\x40\x1a\x8f\xbd\x88\xa6\x3b\x5f\x78\xa1\x1c\x1a\xef\xf5\xe1\x54\x5a\xab\x03\x5c\x2b\xc9\x61\xf6\xd6\x39\x02\x29\x69\x88\xa2\xc3\x22\x1c\xc7\xd1\x5e\x33\x2a\xaf\x6c\x66\x43\x7f\xdf\x43\xb7\x76\x82\xda\xe2\x3e\x17\x51\xc7\x36\x0a\x65\xd5\xac\x54\xe5\x27\xe1\xfc\xce\xc9\xc5\x25\x57\xa0\x3f\x1d\x83\xc4\xe2\x41\x38\x47\x1e\xea\x52\x70\x20\x62\xd8\x5a\x6e\xfb\x73\x11\xaa\xab\x12\x2b\x71\x3f\xc3\x91\x25\x4a\xc5\xc2\x97\x47\x9a\x80\x31\x15\x42\x34\xfd\x79\xc7\x42\x49\x22\x52\x86\xb0\xa5\xe7\xc1\x0f\x82\x32\xf3\x3c\xb7\x13\x0c\x44\xa7\x38\xfd\x09\xfa\xf7\x0a\x5f\x1d\x07\x81\x50\x2c\x8f\x47\xae\xe6\xea\x5f\x51\xaf\xfe\xb0\x25\xcb\xff\x2c\x03\xe1\x12\x2b\x55\xae\x70\xff\x6c\x79\xb8\xe7\x48\x1e\x17\xe5\x71\x2a\xf2\x0f\xff\x3f\xfb\x32\x1d\x51\x42\xe3\xbe\xfc\xa7\xd0\x3e\xf2\x5c\xf0\x30\xce\x17\x9d\xa6\xd3\xe8\x9e\xe4\xfb\xc9\x9b\x3e\x51\x57\x1e\x22\x3b\x28\x24\x52\x90\x37\x94\x6c\x2e\xc7\xe9\xf8\x0a\xfe\xd0\xc4\xcf\xeb\xd7\x43\x25\xe7\xb5\xcc\x71\x3f\x64\xa6\x14\x6c\x80\x76\x16\xa6\x71\x81\xa4\xd2\x18\x85\xd8\x5d\xbe\x2b\xa6\x89\x35\x9c\x40\x67\xe8\x6a\xd8\x19\x82\xb0\xf6\x48\xd1\x52\x15\xf4\xfa\x3c\x31\x0f\xba\xfb\x70\x01\xa5\x36\x56\xa6\x38\x2c\x89\xf6\xfd\x50\xc9\x55\x27\xad\x39\x75\x1b\x39\x22\xdc\xdf\x1a\x0f\x49\xed\xa6\x9e\x6b\xcf\x5b\x4d\x2b\xd9\xcd\x29\x06\x0f\xb4\x70\x7e\xe3\xf1\xc9\x7e\xe9\xdd\xbd\xf6\x86\x81\x59\x12\xf3\x83\x45\x83\x37\x8b\xc0\xae\x1c\x23\xab\x57\x48\x55\xad\xc4\x4b\x07\x08\x09\x72\x87\x6e\x1d\x72\x34\x51\x63\x7d\xe0\x35\x99\x7d\xca\xb4\x5f\xe1\x1c\xe3\x69\x2f\x4c\x96\x73\xaa\x40\x8f\x88\xbe\x7b\x52\x39\x6d\xcb\x6e\xe8\xc6\x2b\x8e\xda\xe3\x49\xef\x18\xdc\xbf\xb2\x86\x44\x0a\xa2\xe9\x95\xf8\x7c\xfd\xea\x07\xa5\xee\x42\x4b\x25\x3c\xbb\x71\x67\x18\x2e\x8c\x1f\x0a\x2c\x64\xcc\xcb\x11\x24\x07\x43\x2b\xa0\x3d\x11\x60\x0c\x83\xc0\xe0\x52\x39\xf9\x23\xeb\x3d\x82\x88\xe6\x83\x91\xdd\x39\xd4\x20\xc6\xb2\x74\xac\x75\x58\x5f\x0a\xf8\x03\xef\x00\xd8\x04\x40\x3d\x27\x49\xa4\xf5\x7a\xe9\x25\x3a\x6d\x78\x9a\x72\xce\x3a\x79\x1d\x8f\x74\x27\x98\xdf\xb3\x9d\xcd\xc0\xfb\xfc\xe4\x0b\x76\xb8\x5b\xe8\xcf\xf3\x4d\xa1\x3e\xbd\x2b\x40\x20\x76\x42\x30\x81\xef\x67\x39\xc8\x17\x3a\x51\x67\x6c\xc0\x78\x6f\xbe\x28\x25\xf9\x52\xf7\x5b\xb6\xbe\xa5\xdd\xb0\xc3\x23\xbc\xde\xcb\x7e\x6c\x8b\x90\xf9\xcb\xe8\xa7\x17\x15\x0b\x4c\x4d\x6e\x3b\x82\x2d\x45\x0a\xb3\x76\x9e\xbe\xef\xb7\xf4\xd2\xc7\xc7\x1b\x1d\x0f\x12\xb3\xbc\x6d\xb1\x30\xc2\x63\x14\x77\xbb\x2d\xd8\x83\x4d\x38\x9e\xb5\x90\xd8\x56\x84\x86\xfd\xde\xf9\x0d\x84\xe0\x53\xc4\x96\xa1\x21\xd9\x7c\x1b\xbe\x8e\xd0\x02\x8e\xb0\x77\xa3\x59\xe7\x8c\x50\x1b\x40\xdc\xa9\xd2\xd0\xc6\x25\x70\x04\x27\x08\x40\x3f\xe1\xb1\x60\xa3\xdc\x8d\x53\x4e\x3f\x1f\xb6\xea\xb1\xc8\xab\xfc\x22\x2d\xea\x4d\x45\x09\x12\x37\x07\x9e\x3b\x47\xd7\xde\x23\x66\x77\x29\x06\x80\x06\xa0\x38\xf1\xf9\xf8\x46\xad\xcd\xc0\x0d\x25\x98\x4f\xa5\x59\x54\xea\xbd\xf6\xb8\x7e\x9c\xe9\x2f\xb7\x91\x9f\x65\xd8\xae\xd9\xa2\x6d\xb4\x0d\xe3\x15\x67\xcc\x68\x7d\xac\xe9\x8a\x1b\x2f\x89\x00\x4d\x13\xb2\x72\x32\x4f\xf4\xb6\x83\x7b\xde\x4f\x69\x75\x95\x15\x67\xee\xcf\x68\x78\xfa\x89\xbc\x79\x13\xdf\xa8\x58\x79\x46\xc2\x01\xf8\x1d\x80\x70\x57\xca\xc9\x04\x70\xee\x77\x50\x7d\xd2\x30\x4d\xc4\xd5\xfa\x36\x4b\xd7\x34\x71\x62\x29\x0c\x43\x1a\xe1\xc1\xab\xcf\xfc\xd7\xc3\x42\x8c\xd0\x5b\x7d\x1e\xa1\x60\x2e\xf1\x9b\x67\x6b\xf6\x99\x03\xf2\x81\x6c\xbb\x3e\x4c\xf7\x60\x4f\xf4\x36\xfe\xdc\x45\xa0\xea\x97\x39\xe7\xba\x73\x7b\x21\xc1\xc0\x76\x26\xa6\x79\xc3\x15\x57\x59\x5f\x6f\x4c\xb3\x73\x08\x6c\xc0\xee\xd6\xad\xf4\x86\x4e\x10\xc2\x3c\x33\xc4\x3d\x39\xb4\xac\x45\x3b\xf2\xec\xbb\xef\x15\x25\xd7\xe9\x7e\x1c\x8c\x2d\x83\xd1\x79\x72\xbf\xf8\xfb\x3b\x4d\xfb\x4c\x23\xf3\x74\xfb\x4b\xc2\xed\x1f\x1c\x95\xb6\xd5\x9d\x01\xed\x02\x64\x8b\x37\x66\xa3\x4e\xe3\x41\xe7\x36\x62\xc2\x1c\x60\xa3\x16\x07\xd8\xf0\xb8\xd7\x8b\xe2\x0b\x52\xe0\xc2\x3d\xc8\x77\xda\x6e\x30\xdd\x1e\x06\x7c\xaa\xb6\x7d\xdb\x46\x25\x07\x4c\x1f\xfa\xcc\xb8\x11\x75\x7a\xfa\xe0\x4e\x09\x76\x26\xd5\x27\xce\xf7\xa5\x11\x26\xfe\x15\x8f\xbb\x76\xd6\x83\x98\x5c\xbf\xd2\x28\x07\x97\x1d\x7e\x2d\xf3\x20\x47\x9e\x0f\x71\x7c\x7f\xe7\xaf\x84\x6f\x00\x05\x3b\x60\xb0\x73\x89\x79\xb6\x3e\x9e\xda\x9b\x60\x5a\x1a\x20\x11\x9e\xf6\x23\xf9\xac\x71\xa6\x65\x56\xd8\x2b\x32\xf2\x80\x62\xb0\x7f\xd8\x95\xd7\x04\x40\xa8\xe1\x0d\xe3\xb5\xcc\xe0\x3d\x31\xfa\x0c\x18\x66\xbf\x36\x59\x5c\xe7\x87\xb9\xe4\xfc\xb3\x08\x78\xce\xde\x13\x29\xcc\x96\xe0\xf0\xde\xf4\xbf\x5e\x46\x32\xc3\xa1\xfe\x6c\xbb\xcb\x0b\x7f\x5f\x5d\x3a\x41\x93\x35\x71\x74\x10\xe4\x83\xcb\x10\x98\xe0\xf4\x36\x8f\x57\x47\x60\x1f\x27\x67\xca\x1e\x30\xe7\xb2\xfb\xf3\xd3\xbc\xe3\x53\xb7\x1b\x34\x32\x84\xfb\xc3\x94\x7e\xbc\x13\xe3\x47\x1c\x1f\xdf\x1c\x47\x28\x00\x08\x0d\xcd\x01\x56\x84\xfe\xfe\x89\xbc\x76\x46\xe8\x73\xcf\x93\xc7\x1e\x96\x02\x31\x63\x1d\xce\x0b\xd1\x86\xaf\x53\x84\x8d\x81\xe3\xbe\xe5\x90\xfb\xbd\x97\xdc\x53\x43\x21\x75\xa3\xee\xcc\x71\x73\xda\xd2\x4c\xb8\x68\xd5\x5a\x08\xde\x38\x47\x0c\xa0\x18\x8f\x25\x34\xce\x72\x6e\x68\xcd\xd3\x3e\x13\x00\x14\x06\x86\x9d\xcc\x1c\xd6\x1c\xce\x48\x6d\x74\x34\x8e\x6e\x46\x4a\xe5\xb7\xc6\xc5\xcb\x27\xd0\x3b\x7f\xef\x6d\x9f\xf0\x33\x1f\xcb\xbc\x6d\x8d\x88\x75\x67\x00\x54\x62\x90\x2b\x08\x17\x1c\x9b\x70\x78\x60\xc7\x79\x3f\x22\x61\x98\xa6\xe7\x2e\x0a\xea\xaf\xa7\xea\xc3\x21\xf6\x19\x6b\xd1\xce\x0a\xd5\xeb\x0c\xbb\xb0\xcb\x0e\x32\xfb\x28\xaa\xce\x39\x4b\xb4\xef\x3a\x64\xee\x00\xd3\xa8\x9c\x1b\xb5\x7d\x85\x13\x40\x10\x06\xa6\x2b\xce\x73\x9d\xaa\x2b\xe6\xa4\x31\x70\xa6\x5c\x7e\xf2\xb3\xa5\xf1\xbf\x19\x2a\x7a\x15\xe2\x2a\x39\xa0\xfa\x1e\x30\x4b\xc8\xce\xcd\x77\xcd\x53\x22\x27\x56\x86\xa0\xfb\x65\x96\xac\x5b\xff\xac\x39\xa1\x09\xfa\x88\x9e\x8c\x8e\xed\x14\x8f\x99\x83\xf8\xaf\xbe\xa8\x74\xd3\xd4\x4d\x7d\x93\xe8\x98\x80\x4c\x29\xf2\x0b\x4f\x78\xa4\x0e\xa6\xa5\x80\x01\x3b\xb2\xf8\xb3\xde\xad\x7c\x9e\x50\x20\x07\x18\x01\x01\x49\x0e\xf3\x7c\x9a\x78\xa9\xed\x39\x21\x7d\xf4\x11\xdd\x6a\xbc\x35\x6c\x94\x4c\x74\xe1\x0c\xf1\x4c\x02\x0c\xd0\x33\x00\xf9\x14\x84\xb3\xe7\x65\x7a\x85\xe6\x3b\x41\xc7\x04\xd3\xe3\x37\x9d\xdb\xec\x5d\x8e\xae\x3c\x32\x1e\xd8\x54\xfd\x3c\x5a\xfa\x62\xbc\x8f\xeb\x62\x35\x1d\xfc\x6a\xdd\xf9\xa7\xe9\x0b\x04\xe6\x06\x41\x1a\x11\xcf\x81\xd6\x6d\xc9\xef\x3e\x0a\x99\x1b\x14\xd8\xd7\x98\x80\xe7\x01\x82\xd0\xea\xb3\x9d\x1f\xa7\x78\x27\x80\xce\x69\x5f\x25\x7f\xa0\x45\xd7\xc0\x0d\xdf\xb1\x56\xd6\x7c\xb0\xae\x76\x8a\xfa\x66\x8a\x67\x42\x0a\x19\x9d\x02\x20\xce\x76\x7c\x23\x70\xa7\x26\x7a\x02\x80\x27\x07\xee\x1e\x80\x8e\x46\x91\xc6\x49\x87\x2f\x93\x22\xb8\x7e\x7a\x0a\x2f\xbc\x37\x8f\xb2\xb6\x7d\x93\x4e\x97\xbb\xc2\xcf\xdf\xbb\xe4\x3d\x7f\xc8\x0c\xa6\xb4\xd7\x71\x32\xc2\x63\xdf\x67\x33\xa4\xf8\x71\xe8\xf6\xd0\x00\x40\xdc\x7b\xb0\xbf\x28\xdc\x0d\x95\x99\x97\xf6\x5d\x9e\x26\x84\xa1\xc8\xf8\xe7\xf3\xa4\x9b\x85\x5c\xbc\x76\x88\x61\x4e\x7a\xeb\x1a\xf1\x73\x88\xde\xb5\x49\x22\xb2\xa1\xca\xf3\xcc\xf4\x1d\x02\xf2\x4c\x04\x95\xb4\x7c\x5f\xf2\xb0\x1f\xc0\x07\xcc\x45\x80\x7b\x25\xc8\x99\xf5\x1b\xba\x75\x26\x04\x81\xf3\x58\x96\xd8\xc6\x84\xb3\xef\xd3\xb8\xef\x16\x68\xf7\xdb\x37\xfc\x0c\x9b\xe9\xb1\xa5\x01\x41\x92\xeb\x44\x98\xb0\xa2\xc4\x22\xb5\x9e\x23\xe9\x08\x80\x09\xcb\xed\xf4\x7b\xab\xe5\x1d\x02\x80\x84\x02\xcc\x4d\x63\xf0\xde\x20\x5a\xd5\xb7\x9a\xd5\x0c\x40\xce\x31\xb6\x32\x02\x81\x88\x26\x75\x4d\x9c\x7d\xbd\xeb\xf2\xe0\x1e\xe3\x19\x01\x51\xe2\xf6\x7d\xbf\x55\x2f\x2d\x42\xd6\x09\x10\x5e\xca\x30\x37\x6a\x2f\xc4\xab\x66\xf4\x9f\x73\x7c\x89\x39\x77\x96\xa7\xd2\x4c\xd6\x4c\x10\x9b\xfb\xb4\x1f\xeb\x2f\x97\xe2\xa5\x70\xf1\x4f\x2a\xf5\x3d\x2c\x08\xf2\x18\x6a\x92\x52\x2c\xd9\xe7\x33\xec\xed\xb2\x2c\xdb\x06\xc0\xf3\x49\xd3\xec\xb5\x9b\x27\x3a\xca\xad\xc5\x30\xf7\x9e\x41\x84\xea\x13\x20\x03\xea\xbb\xe2\x77\xfa\x19\xf6\x8f\x85\x00\xa8\xd9\xe2\x95\xed\x5c\x21\x26\x6f\x81\xf6\x23\x66\x07\xf3\x0e\x00\xd3\xee\xe0\x52\xde\x5b\x85\x2d\x9b\x40\xd3\x08\x04\xa4\x28\xb8\x11\x16\x28\xc6\x42\xbd\xc5\x5d\x88\x68\x9c\x0d\x32\x89\xd8\xb5\x5d\xa4\xb9\xf3\xfb\xab\x2d\x0f\x94\x8f\xd8\xcc\x76\x99\xa7\x49\x94\xce\xd5\x9f\x15\xd3\x92\x44\x44\x9f\x8a\xe4\x6a\x98\x01\x30\x66\x1f\xec\xf1\x0e\x16\xba\x11\xbe\xdd\xe2\x6e\x3b\xaf\xdf\x79\x06\xd8\x07\x27\x63\xd9\xfa\xee\x11\x14\xf5\x4a\xf4\x82\xe1\x3a\xe6\x83\x97\x11\xc2\x4d\x75\x07\x2e\x03\x92\x34\x80\x62\xd6\x90\x22\x00\x40\x7d\xdf\xb7\x4c\x2b\xdb\x17\x08\x76\x40\x00\x00\x77\x00\x46\x1f\x30\x21\x09\x78\xd1\x80\xd3\x8a\x93\xf7\x2c\x55\xa6\x84\x0e\xf1\x4c\x2c\x69\xf5\xc4\xd4\xdf\x99\xa3\x22\x2b\xee\x84\xe5\x2e\xa6\x7d\x83\x74\xae\x7b\xbf\x2f\xca\x86\xed\x82\xa1\x96\x89\x1c\xe1\xa0\x41\xf4\x24\x69\xae\xdb\xae\x7d\x92\x37\x9c\x33\x62\xa7\x53\x86\x20\xf6\x9b\x01\x6c\x18\xe4\x5c\x10\x0c\xcf\x9d\xb1\x29\xca\xf9\x56\x4e\x34\xef\x33\x10\xce\x2a\xc4\x99\x74\x5c\xab\xe9\x4d\x68\x76\x0a\x10\xa2\xcf\x01\x3b\x01\x70\xb5\x17\x51\x5a\xa6\xb4\xed\x04\x64\x08\x40\xa2\x4e\xba\x6d\xb9\xe3\x39\xc7\x41\x7e\x1e\x43\xb8\xf9\x2d\x4b\x05\x73\xbb\xc6\x1e\x36\x0b\xdf\x43\xcb\x9b\xd9\x07\x8d\xec\xfe\x03\x91\x94\x27\xed\xa3\x44\x57\x50\xf4\xe3\x3c\xc9\xf9\x13\xf4\x11\x33\x47\xdd\x89\x9a\x96\x9b\xd8\x45\xca\xd3\x4c\x9e\xe8\x5d\xdb\x9e\x24\x93\x75\xe7\x95\xb4\xca\x81\xe6\x33\x04\x35\xa0\x9b\x1b\x20\x34\x03\xa8\x8e\x99\x68\x7d\xd6\x93\x0c\xd7\xea\xe0\x86\x0c\xdb\xf4\x65\x87\x30\x4d\xe8\x3d\x0b\x56\x93\x14\xac\xea\xe4\x60\x98\xcd\xb4\x82\x39\x98\xde\x0c\x33\xd4\x42\xd0\x64\xba\xf0\xe4\x01\x0f\x15\xb9\xb5\x76\x80\x44\x3b\xd8\x76\x41\xaf\xed\xf8\xd6\xc4\x9c\x3a\x6d\xc3\xe0\x0a\x52\xe7\x7b\x75\x99\xa0\x4b\x63\x14\x1a\x13\x1e\xe9\x5f\xe7\xa9\xfe\x6a\x19\x94\x17\x19\x75\xe3\xc4\x95\x28\x12\xac\x35\x47\xee\x83\xf0\x5c\xd3\x14\x3c\x29\x0d\x65\x4f\xab\x67\x26\x7a\xab\x17\x84\xdd\x78\xaf\x5d\x23\x84\x58\xe9\xb0\x33\x9b\xa7\x89\x94\xf8\x76\x03\xd8\x25\x80\x05\x36\x80\x24\x35\x61\xd1\xe5\x4a\xea\xca\x53\x10\xa9\x6b\x1b\x3d\x35\x3b\xcc\x71\xe4\xda\x5c\xab\x73\xae\xce\x73\x52\xc1\x0b\xc2\x45\xc5\xba\x0d\xc8\xd3\x44\xd3\x80\x0d\xa2\x9f\x52\x80\xec\x35\x79\x3a\x40\xf1\xb0\x35\xd8\x01\xe2\xe6\x40\xed\xfc\xbd\xb3\x9b\x13\x03\x97\x76\x17\x28\x34\x6c\x7b\xbf\xed\x25\xe1\x77\x6f\x56\x98\x05\x6d\xd6\x80\xc4\x9f\x78\xd3\x32\x51\x8a\xbd\xff\xf1\x69\x11\xc9\x24\x53\x9a\x3d\xcf\xe1\xa5\x70\x9c\x1f\x2b\x1b\x59\x40\xc8\x3e\xf4\x6e\xa2\xe4\x8d\xbe\x7e\x12\xa4\xfd\x00\x36\x8b\xe4\x46\x75\x88\x6f\x55\x7e\x3e\xc4\x98\x61\xee\xfb\x9e\xf7\x3d\x99\xf7\x74\x9c\xf6\x9e\xb4\x34\x41\xe8\xeb\x63\xf0\x25\x32\xc7\xba\x15\xab\x01\x5d\x5c\xd0\x71\x5d\x2f\x8c\xb7\x6f\x6f\x53\x0c\x8b\x7e\xc1\x9e\x11\x82\x3d\xf6\x5f\x5a\x49\xaa\xef\x36\x6f\x8c\x01\xba\x91\x60\x7a\xa4\x2c\x77\x35\xb5\xd6\x81\x29\x94\x0b\xf8\xfb\x66\xf8\x38\x4d\x50\x35\x27\x07\xf3\x35\x12\x80\x2d\x09\x1a\xf4\x87\xa3\x87\xcd\xaf\xf7\xca\x71\xf4\x28\x40\x76\xfe\x24\xd9\x44\xd3\xe1\xbd\x03\x88\xe4\xb1\x6d\x4a\x2d\xe5\x11\x38\xe3\xde\x14\xa2\x1b\x46\x1e\x47\x13\xcd\xba\xaa\x6d\x26\x9b\xaf\xb4\xe5\x4d\xb1\xe7\x85\x13\xc4\x34\x4d\x53\xd9\xce\xdd\xfb\xe8\x76\x20\x68\x31\x4b\xa8\xb7\x14\x4b\x08\xbd\x61\x63\xe6\xdc\x3d\xa0\xf2\x71\x58\x51\x8a\xbc\xb4\xba\x26\x70\x5a\xd6\x41\x66\xcc\x7f\xdc\xae\x83\x01\x7b\x3a\xa1\x35\xcf\x4c\x4b\x93\x14\x46\xf8\xf3\xb9\xf5\x6e\xb7\xf3\xcc\x4f\x69\xb9\x7b\xfb\x1c\xf1\xcd\x48\xb3\x34\x73\x56\x0d\x82\x37\x3a\x04\xd6\xaf\x2e\x95\xe3\x5e\x97\x5a\x0f\x2b\xc3\xdc\x84\x77\xe0\x11\x7b\x97\xd1\x34\xcd\x3f\xb8\xf5\x66\xbb\x2b\xd6\x68\xf9\x4e\x6e\xd5\x30\x76\x55\xa5\xb6\x2c\x47\x84\xe2\x08\x74\x1e\xe4\x52\xe6\x62\x29\x01\xbe\xe8\x0f\xce\x64\xe2\x8c\x58\x99\x28\x40\x08\x8a\xa2\xe0\xdc\xac\x1e\x93\xb9\x98\xbb\x2f\x75\x01\x61\xa0\x11\x9f\x0f\xb5\x12\x40\x6a\x55\x6a\x75\x7d\xbf\xef\xf1\xce\xcb\xf0\x18\xae\x1b\xf5\xd2\x5c\x9d\x59\xe8\x98\xb9\xc7\x71\x5d\xb7\xed\xc6\xbe\xbc\xfd\xdc\x61\xa2\x94\xac\x00\x21\x49\xed\x67\xa6\x5d\xc1\x71\x37\x49\x5d\x03\x80\x8e\x20\xb8\x53\xdd\x13\xe2\xe2\xf1\xcb\xd1\xdf\x1f\x04\x6e\xa6\xad\x13\xf9\xa6\x6e\xe7\x81\x31\xc4\x8e\x17\x84\xbf\x47\xec\x9b\xae\x03\xd6\x30\x6e\xf9\xba\xe0\x4e\xc4\x52\xcb\x50\x34\xbc\x3c\xeb\x62\x35\xfe\x21\x09\x2e\x9a\x7e\x4e\x0a\x0b\x5d\x7f\xcf\xf3\x09\xf3\x56\xaf\x45\xb9\xcf\xb3\x08\x84\x1d\x24\xc0\xb8\x2a\xe2\x54\xb5\x6d\x05\x40\x12\x00\xfe\xe4\xed\xbd\xec\x5f\x6a\x54\xc7\xcc\x89\x6c\xeb\xbe\x1b\x0c\xbf\x76\x44\x1c\x96\x59\x2f\x32\x48\x25\xf3\xbb\x3f\xcf\x04\x7b\x55\x7b\x96\x42\x0c\xb3\xa8\x64\x53\x02\x21\xcc\x91\xca\x34\x89\x4d\xcd\x8a\xeb\x3a\x3d\x99\x02\x71\x18\xcf\x4c\xc9\x1a\xc1\x12\x59\x85\xf1\xab\x15\x17\xb5\xcf\x00\xf5\x1d\xc0\x00\x0b\x14\x3e\x56\x49\xcf\x0c\xc1\x26\xfa\x46\x9b\xda\xbe\x8b\x5e\xcf\xe0\x16\x48\xb0\xe3\x4c\xba\x03\x6c\x66\x20\xf2\xa7\x56\x0e\x68\x8f\x07\x0e\x37\x64\xf5\x1e\x63\x90\x8a\x46\x37\x82\xd1\xe6\xf9\xbb\x69\x86\x9e\xdb\x5a\xae\x3d\x3a\x47\xc7\x22\xc4\x9e\x77\x10\x4d\xe5\x43\x25\x70\x71\x76\xaf\x1b\xe0\x1a\x46\xb4\xc9\x65\x0c\xc8\x4e\x37\x89\x2e\x40\x84\x49\x37\x02\xe4\x60\x50\xff\x78\xad\x0d\xa0\x6b\xbc\x17\x4d\x6c\xf4\x36\x27\x2c\x11\xad\xd1\xea\xcf\x0c\x33\x0c\xc3\x96\x28\x6d\x2e\x7d\xf4\xf9\x4b\x26\xaa\x01\x36\xb3\x3c\x0e\xca\xf7\xb0\x9d\x29\x31\xc0\xee\xef\x2e\x46\xbe\xcf\xfd\xb7\x1f\xc5\x71\x3a\xac\x53\xc2\x30\x7c\x54\x39\x0e\xc6\x7f\x6b\x10\x64\x00\x10\x1b\x12\x6d\xcb\x2e\x3f\x93\x5b\xbd\xa5\x83\x4d\x3c\xe9\x48\x84\x67\x93\xf1\xe6\x12\x73\xdf\x80\x53\x19\xf5\x16\x6d\xae\x71\xbf\x57\xe7\x14\x1d\xf4\x4e\xcf\x75\x5d\x0d\x45\x0e\xbd\x64\x41\xcf\x82\x1d\xba\xae\xeb\xfe\xb1\x78\xfb\x12\xd8\x6d\xa1\xab\x45\x05\x8b\x9c\xba\x37\x23\xba\x9a\xc2\x30\x34\xbe\xad\x2d\x72\x46\x4c\x82\x68\x02\x36\x9d\x99\x1f\x8a\xc0\xab\xbf\x96\xee\x0b\x55\xf8\x81\x39\xc3\xd6\xc7\xa5\x71\x5f\x54\xb5\xdf\xa7\x7e\xab\x37\x7f\x1c\xdd\xfb\x68\x9a\xa5\x6d\xe4\xd1\xb3\x42\xb7\x75\xdd\x04\xef\xb2\x18\x45\x7a\x98\xcf\x2c\xd8\x67\x1e\x99\x67\x1a\x99\x7c\xad\xa2\xd6\x08\x47\xf6\x89\x5e\xe6\x2b\x96\xde\xe2\x28\x00\xb0\x46\xc4\x81\xf0\x62\xe0\xe4\x2c\x91\x40\x64\x9b\xbd\xb6\xcc\x1c\x55\x0a\xb4\x7f\x9a\x57\xcf\x42\xf8\x10\xfe\x0e\xfa\x95\x21\x69\xb5\x7e\x96\xf8\x29\xef\x79\x06\x5d\x4d\x83\xd4\x83\x4a\xd6\x37\x41\xb7\x36\x84\x27\xe3\xdf\x6d\x2f\xd8\x51\xcc\x7c\x11\x04\x31\x1a\x79\xa7\x10\x7b\x70\xae\x6d\x7a\x00\x96\x92\x7f\xf0\x17\x19\xa5\x8b\xfd\x53\x5f\xd3\x3c\x4b\x79\x79\x80\x56\x30\x39\xff\x0b\x8a\x07\xc7\x59\x92\x84\x9e\x47\x02\x02\xc5\x89\x20\xdc\x87\x88\x46\x00\x9a\xee\xb1\x89\xf8\xca\xd7\x3e\xb2\x1c\xb9\x4f\x89\x1d\x59\x11\x7f\x54\x8d\x5f\x2f\xac\x95\xa8\xd9\xf9\xd8\xaa\x6e\x17\xee\x11\xe3\xcb\x4d\xc3\x37\x40\xe0\x1e\x8e\x94\xcc\xab\x38\x7f\xf7\x47\xde\xea\xea\xc7\x63\x03\x3c\xcf\xe7\xfb\xfe\x7d\x52\x0c\x39\x79\x1f\xed\xc6\x3e\x6f\xfb\x66\x30\xa8\x9f\x4b\xc3\x4d\x89\xb1\x62\xf9\x5d\x62\xdd\xb5\xe4\x24\x62\x54\xf7\x7d\x63\x3b\xf5\xfc\xec\xfb\xd6\xf3\xef\xbe\x78\x28\xc2\x43\xff\x8d\x61\xed\xb3\xed\xfa\x87\xee\x59\xd8\xe3\x3a\xff\x3a\x32\xae\xb6\xc1\xe5\x80\x49\x6e\x99\x04\x4d\x75\x10\xe4\xb4\xfc\xd6\x93\x3b\x02\xc0\x50\xa4\x86\x21\x9c\x21\xf8\xb6\x0d\xdb\x09\x42\x4f\xa2\xad\x33\xc4\xe9\x62\x79\xd4\x16\x2a\x0a\xd6\x0a\x94\xfb\xa1\x7f\x67\x9f\xef\xd8\xd6\x74\x94\x63\x18\x90\x5e\x2f\x35\xd3\xfd\x79\xa1\xdc\x34\x1b\x73\xb9\x9d\x7a\x58\x90\x52\x6e\x18\xef\x25\xbd\x97\xb2\x83\x4e\x92\x65\xd7\x11\x84\x5c\x0a\xa3\x54\xc2\x40\x94\x00\x04\xf4\x01\xa2\x94\xa5\x89\x7d\x1d\x2a\x20\x8d\x3c\xe0\xe4\xe1\xb2\x7e\xb1\x6b\x35\xbd\x98\x09\xa8\xf0\x43\xa3\x18\x3b\x14\x7b\xec\x33\x14\xad\x7d\x6a\x57\x61\xd0\x52\x35\xca\xfe\xbe\x51\xeb\x15\x72\x27\x42\xe4\xef\xa1\x7d\x0b\xc4\x3d\x90\xfe\x97\xb6\xad\x56\xbe\xa9\x68\xf5\x0e\x80\x0a\x9c\x7d\x55\x5a\xba\x6f\x32\x3d\x4d\xc3\xfc\xff\xbf\x7f\x33\x70\x1c\x67\xb0\x2c\xc6\x78\x61\xe7\x4f\x89\xa2\x83\x6e\x9c\x2a\x76\x72\x9a\x86\x6d\x58\xa0\x96\xf5\xe0\xbe\x44\x67\xbe\x53\x52\xe7\xbe\x0a\xc1\x50\x9c\xe0\x0c\xaa\x95\x32\x19\x05\x41\x10\xea\xa6\x89\x9f\x53\xd4\xdf\xbb\xeb\xa6\x56\x16\x7e\xa7\x7f\xfd\x42\x85\x80\xc9\x03\x86\xd9\xab\x42\x7a\x77\xbc\x60\xbf\xbd\x0a\x02\x40\x1e\x29\xe5\x76\xc9\x98\x65\xf3\xe8\x03\x2b\xd5\x1b\x27\x25\x96\x5e\xf7\xe3\x8d\x88\x35\x4c\x16\x9c\x99\x3f\x55\xfb\xfd\x3d\x58\xd0\x2c\x68\x04\xef\xef\xc7\x4e\x55\x04\xd9\xde\x4c\xad\x9c\xdf\xc7\x11\xfc\x62\xc0\x8f\x8a\x5f\x75\x41\x73\x02\x28\x70\xd5\xee\x29\xf2\xad\x1a\xe1\x2d\x86\x55\xcb\xbe\xfc\xbe\xc7\x56\x17\x67\x20\xf6\x12\x5e\xc4\xde\xe1\x59\x62\x08\xf5\xf8\x16\x9c\xf1\x21\x3d\x65\x0a\xb0\x89\x71\x76\xd2\x29\x1e\x90\x46\x49\x94\xf8\xf3\x8f\x15\xfa\xcb\x51\x8d\x5f\x3f\xcf\x93\xf0\xe3\xf9\x8f\xfd\xbc\x13\x64\x4b\x04\x76\xec\x0d\x01\x98\xac\x8d\x3e\xed\x1c\x33\xe2\xdd\x60\xb8\xf1\x0c\xb3\xe1\x20\x0e\x16\xee\x85\xfd\x20\x75\x0e\x53\x05\xc7\x99\x7a\xe7\x71\xb0\x88\xc6\x39\x30\xce\xcc\xe7\xc6\x6c\xb4\xd2\x42\xc0\x27\xae\x10\x59\xea\x2f\xe7\x6d\x68\x71\x48\x21\x42\x39\xae\xeb\x8a\x07\xa0\xb1\x76\x67\xaa\x4f\xa8\xcd\x71\x46\x30\x64\x97\x83\xe0\xa0\xef\x8f\x3a\xb5\x39\x73\x3e\x6e\x24\x1c\x8d\x0e\x89\x3c\xef\xc6\x93\x24\xcb\x69\x09\x04\x2a\x27\x16\xc4\x04\x89\x01\xb2\xc8\x5b\x75\x84\xcb\xfb\xd5\xda\x3b\xbc\x85\xad\xb6\x43\x10\x84\x55\x1f\xdf\x14\xc2\xd8\xf7\x7d\x62\x87\x69\x30\xee\xe6\x8e\x72\x8f\x1b\x22\xec\x2b\x1f\xb5\x37\x76\x25\xe5\x4b\x32\x75\x06\x92\x3e\x7e\x2f\x8c\xee\x1c\xbd\x89\xfa\x39\x18\x6f\x82\x42\x58\xed\x59\x8a\x07\x9c\x56\x77\x20\xf2\xcd\xe6\xec\x29\xb3\x91\xc9\x68\x7e\x67\xb5\xe2\xbc\xb3\xbb\xe7\xcf\xee\x75\x12\xfa\x8b\x33\x76\xf0\xaa\x7e\xa0\x14\xda\x9f\xb7\xe7\x92\xa1\x6e\x0a\xf0\x46\xbe\xf6\x2b\x18\xcd\x88\xea\x42\xd2\x20\x80\xf1\x42\x9c\x57\xf9\x96\x9d\xf3\x8d\x01\xaf\xef\x77\xe6\x43\xcc\x39\xce\xfb\x77\x12\xd1\x08\xb5\x4d\xf8\xda\xe6\x53\x2d\xfc\xf6\x54\x5f\x6f\x56\x7a\x1b\x04\xf6\x69\x91\x8f\x51\xe4\xbb\xa0\x84\x44\xbc\x93\x5f\xde\x18\xeb\x37\x62\xec\x0c\x87\x20\xb4\x71\x22\xba\x13\x74\x7c\x37\x4e\x21\xc8\x34\x00\x51\xaf\x72\x9c\xb1\xfe\x24\x2c\x02\x16\xde\xe8\x95\x41\x35\xf0\x55\xc8\xf6\x8d\xa7\x21\xf6\x61\xdb\x47\xff\xbb\xd7\xf4\xe6\x0f\x1c\xbf\x12\x24\x9f\xb3\x2e\xfa\x06\x39\xa4\x13\x90\x41\x85\x44\x1e\x8d\xa2\x72\xe2\xc5\x0e\x1a\x93\xa3\x15\xde\xd1\xd9\xc9\xe6\xef\x9c\x30\x76\x2e\xe1\x4a\x55\xfe\x5a\x3d\x0d\x86\xfb\xbe\x19\xe2\x1c\xa3\xf5\x59\x02\x9f\x01\x46\x9a\xa7\x29\x6f\x85\x72\xf0\x18\xbf\xd2\x6f\x2e\x7a\x95\x53\xd4\x0d\x08\x54\xdf\x06\x2f\x80\x44\xa2\x20\x9d\x2d\xbb\x37\xa7\x66\x1e\x3e\x74\xae\x00\x39\xcb\x2a\x94\x58\x0a\x2f\xf6\xa1\xc6\xfc\x39\x43\x70\x33\x04\x2a\x96\x59\x38\x6f\xab\x61\xec\x3e\xda\x4e\x44\xcc\x71\xf4\x36\x54\x45\x8e\xc0\x32\xe5\x86\x8c\x93\x1d\x8e\x6a\x14\x70\xb5\x11\xfc\x3e\xff\x79\x1e\x51\x1f\xa7\xe8\xd4\x25\x53\x00\xa0\x50\x05\xc1\xf0\x19\xb6\x7c\x99\xd2\x6c\xa1\xab\x2d\xf2\x0f\xa4\xa1\xd3\x6d\x83\x82\x81\x92\xcd\x7b\xb4\x2a\x87\x97\x4f\x4f\x05\xcf\x2f\x86\xa5\xbd\x43\x5b\x8e\xf1\x69\x16\xd8\xf4\xf9\x3e\xdd\x86\xbf\xe7\xea\xce\x7c\x53\xe2\x3e\x1e\x7f\x7e\x7e\x3c\xaf\x62\xfe\xab\xbd\x78\x28\x4f\x62\x65\x72\x94\x7b\x60\x9a\x8d\x1e\x41\xbe\x32\xd9\xae\x50\x1f\x31\x55\x2c\x02\xc5\xca\x87\x2c\x26\xba\x00\x18\xe9\x7b\x20\xbd\x53\xb5\xb2\xe3\x56\x92\xa9\x4b\x8f\x9b\x15\xf0\xb5\x8d\x8c\x13\x55\xb1\x53\xfa\xc8\xa3\x49\x21\x94\xc6\x67\x05\x99\xa9\x06\xb0\x5c\x17\x3b\x91\xdb\x76\x7d\xf5\x70\x06\xed\x07\xa3\x63\xdf\x7f\x3c\xf3\x5e\x4e\xc6\xdd\x48\x9f\x01\xe4\x66\xed\x66\x34\x78\xc1\x9f\x79\x36\x43\x34\xc1\xa0\xe5\x49\x9e\xd5\xa2\xe8\x88\x78\x05\xe0\xea\xb2\x5c\x54\xca\xc8\x18\xa7\x96\x88\xd3\x5b\x6c\xbb\xcf\xf3\x27\x77\x22\x27\x24\x13\xbe\x1c\x70\xa3\xe4\x56\x26\x23\xf2\x7c\x04\x79\x30\x31\xc5\x55\x72\xbf\xf5\xe8\xf9\xd1\xec\xf7\xc9\x42\x02\x22\x6f\x71\xff\xd4\x1c\x40\xd1\xca\x55\xf2\x2d\xb3\x05\x22\xa3\x7c\xf5\x7c\xbd\x13\x14\xf6\x02\x37\xaf\x1b\xee\x04\xf3\x47\x6a\x76\x1b\xc1\x71\x04\x32\x9a\xa4\xc8\x8e\x7b\xd6\x01\x6e\x10\x00\xd4\x4f\x3c\xec\xaa\xf5\xe1\xef\xd3\x74\xb1\xbb\x9e\x23\x37\xce\x10\x09\xb9\x0c\xcf\x6b\x2f\xb2\xdf\x79\xd7\x09\xf3\x18\x23\xf2\xac\x16\xe8\xdc\x8e\x32\xd5\xf0\x5d\xa1\x04\x88\x2d\x18\x58\x18\x7b\xec\xb2\x7c\xde\xce\xdf\x9a\xaa\x0b\x77\x2b\xcb\xdf\xf3\x3e\x33\x7f\x8e\x99\x9e\x92\xa6\xdd\xb5\xaa\x4e\x26\xd7\xfa\x24\x49\x96\x45\xda\x82\xf5\x87\x6f\x87\x5c\xb4\x4f\x13\x3a\x80\xcc\xf6\xfc\x8a\xcf\xf0\x2b\x34\xbf\x9e\xfd\x15\xbf\xef\x1e\x58\xb2\x1c\x91\x7b\x33\xef\x5d\xd7\xf5\x5d\x8e\x00\x43\x41\xaf\xfe\x8c\x8b\x1e\xc7\x05\x3f\xf1\x55\x7c\x0f\x68\xd8\xef\xd3\x7a\x0d\x3a\xb6\x72\x76\xfe\x83\x0b\x56\xb8\x6a\x72\x70\x35\x34\x18\xe6\x99\x61\x70\x74\x8b\xfc\x8a\xf0\x4a\x04\xb9\x7a\x40\x03\xfe\x9c\x5c\xf5\xa9\x0e\xde\xaf\xa7\x10\x5f\xec\x3b\x50\xa6\xb1\x4c\x73\x79\x8d\xcd\x1f\xac\x0a\x12\xf4\x27\x45\x29\x6a\xa9\x95\xb5\x44\x67\x05\x0a\x58\x46\xcf\xa5\x50\x11\x8b\x19\x89\x2e\xc9\xa3\x92\x7d\x46\x1c\xba\x56\xdd\x24\x86\xf4\x2c\xec\xa7\xbf\x82\x9a\xf5\x6f\x36\x20\x12\x4c\xa9\x9c\x55\x73\x8a\x9f\x77\xc2\x56\x21\x9b\xe9\xfd\xd5\xc8\xef\x8c\xf0\x26\x8c\x20\x18\xf7\xa4\x82\xc1\xb5\x1f\xb6\xcc\xff\xed\xa1\xbd\x9f\xa8\x41\x80\x6b\x32\x51\x26\x3d\xfd\x99\x56\x31\xcd\xf6\xd3\x0d\x88\xb5\x41\xe1\x6a\xf5\x69\x9d\xae\x21\x7a\xa4\x74\xb0\x78\xed\xc8\x99\x51\x57\x84\xde\x15\x7f\xeb\x26\xc1\xa2\x43\xd9\x80\xed\x19\x26\xe0\x4b\x0e\xb1\xbf\x54\x77\x9e\xec\x9a\x46\x5f\x08\xd3\xbe\x13\x4c\x99\xe3\xb2\x09\x79\x41\x20\x5a\x34\xe9\xe5\xc9\x7b\xe8\xe4\x2f\x26\x37\xf5\xa7\xfa\x2f\xa7\xfb\xf6\x11\x33\x73\x37\xb8\x68\x91\xcf\x0a\xd6\x89\x0a\x0d\xdb\x00\x7c\x08\x04\x03\x27\xca\x99\xbb\x60\xe4\xd5\x3a\x60\x01\xb2\xd6\xb5\x78\xe9\xf5\xd3\x07\x2d\xdf\x80\x83\xa3\x21\x73\x57\x93\xfb\xdd\xc7\x33\x9b\xe6\x29\xa3\xe1\xaa\xea\x61\xd0\x27\x0b\x6d\xf4\xb7\x50\x22\x15\xb6\xf4\xb5\xbf\x72\x19\x1e\x6b\x04\x4a\x0e\x5b\x68\x2b\x61\x10\x10\x75\xbe\xa6\x79\x92\x18\x28\x4f\x15\xf2\x77\x07\xb2\x3b\x63\x8f\xbf\xba\x38\x51\x7a\xb7\xd1\x3e\x5f\xcc\x4e\xc0\x22\xeb\x27\x5a\x7e\x68\xe2\x08\x55\x68\x7c\xff\xf8\x0b\x44\x78\x3b\xb8\xa6\xf7\xe1\x5f\x4d\xed\x43\x3b\x25\x18\xe1\x26\x1b\x27\x7b\x1d\xe9\xb3\xda\x05\xb2\x89\x72\x95\x0e\x9a\x9d\x45\xe9\x60\x6f\x55\xff\xba\x54\x72\x0e\x3b\x4d\x0f\x0e\x92\xd0\x6d\x0f\x83\x34\x06\xb5\xd4\x77\xdb\xd0\x73\x7b\xd9\xfb\x7c\xbe\x07\x9f\x03\xe5\x10\xef\x95\x60\xaa\xb9\x1a\x57\x5f\x51\x66\xa2\xc1\xda\x75\x0b\x2b\xf2\xf1\x02\xfb\x3f\x1a\xdf\x67\xd7\x38\x47\xc7\x30\x3d\xb1\x0f\xc2\xf3\xb0\x64\x7d\x88\x94\x57\xce\x26\x82\x01\x6b\x0f\x5b\x46\xf4\xa3\xda\x0b\xa3\xdf\x46\x4f\xcc\x34\xae\x08\x75\x45\x0c\xce\x7a\x11\x48\x78\xe7\xac\xd3\x1a\xd6\x38\x51\xee\x0d\x39\xab\x47\x2e\x12\xdd\xeb\xda\x9f\x95\x8d\x1c\xd7\xff\xa3\xea\xba\x76\xdd\xe6\x99\xed\x03\xe9\x42\xbd\x5d\xaa\xf7\xde\x75\xa7\x2e\x59\xbd\x59\xe5\xe9\x0f\x92\x2f\xd9\xf9\x8f\x01\x23\x31\xe0\x4d\x8a\xe6\x70\xca\x9a\xe1\x9a\xef\x79\x88\xe7\x81\x5a\x84\xb8\xfb\xd5\x37\x02\x69\xea\x18\xa6\x84\x14\x31\xa1\xa8\xae\xec\x8c\xb5\x13\x00\x33\xcf\xa6\x8a\x84\x21\xff\xdd\xbb\x95\xb4\x1b\x61\xc0\xf3\x1b\xd1\x7d\xaa\x79\xd8\x45\x7e\x30\xdb\xad\xcb\x5f\x72\xf0\x4b\x17\x4b\x61\x7f\xc5\x65\x85\xe6\x31\xfd\x42\xd8\xfe\x15\xab\xc5\x9d\xd8\x0a\x99\xb3\x63\x72\xd0\xca\xae\x8a\x33\x7c\xc2\x0d\xfc\xe2\xe5\x39\x26\x57\xb0\xd0\xa7\x7a\x03\x26\x00\x02\x08\xba\x85\x1d\x30\xd9\x06\x22\xd3\xb6\x0f\x41\x14\x40\xd7\xfe\x2d\x3c\x95\x6e\x61\xef\xb9\xad\xb8\x5d\xdb\xf7\xb9\xd2\xb1\xf6\x61\xd8\xf7\xc7\x07\x95\x12\xef\x13\x64\xbf\x2c\x87\x7d\x53\xb9\xd4\x7d\x76\xe3\xa0\x0f\x18\x20\x10\x74\x1b\x16\xd1\x05\x35\x51\x62\xa1\x1c\x00\x27\x7b\x02\xe6\x5a\xe2\xf9\xbd\x53\xd7\x02\x3c\x14\xf3\x0b\xfa\x09\xf6\x64\x07\x62\x66\xfe\x83\x12\x37\xf8\xa2\xa2\x5c\x58\x1a\x5e\xa2\xdf\x2f\x08\x21\x1f\xaa\xe6\xb9\xf4\xd9\x72\x3e\x23\xf3\xfa\x8b\xf8\x1e\x7d\xfa\x6b\xe8\xdd\x2e\xac\xe2\xa4\x3a\x4c\xe0\x2b\xdc\x88\x9b\xa6\x83\xc6\x18\xd4\x0f\x07\xe2\x28\x5c\x84\xfc\x05\x01\xbe\x7a\x8a\x51\xc5\x76\xa0\xdf\xf2\x68\x38\x8e\xf3\x9b\x45\xc8\xb1\xa4\xea\x98\x95\x89\x6e\xe7\x1e\xbe\xd4\x35\xaa\x0b\x9f\xf1\x0d\x88\xcf\xd6\xf5\x40\xe5\x94\x22\x00\x41\x09\x2d\x77\x5a\x1d\x6e\x23\x42\xd8\xea\x16\x75\x1f\xc8\xf7\x0f\xe9\xfc\x9e\xf5\xa6\x69\x0f\x31\x71\x20\x48\x4d\xfe\x9b\x02\xd4\x31\x4d\x2d\x74\xd0\x1d\x44\x77\x54\xec\xa1\x47\x8e\xac\x25\x88\xb3\xb2\x21\x4f\xca\xbf\xb8\xc8\x5e\x45\x87\x50\x71\x92\xbc\xcf\x7a\xe4\x3e\x00\x49\x47\xbf\x1c\xcf\x81\x20\xc8\xba\x50\x51\x9f\x88\xdc\x4a\xef\xb8\xfc\xad\xc8\xe4\xac\xce\xe1\x4d\xcf\x0f\x14\x76\x6e\xda\x6f\xe0\x0c\x9c\xd5\x06\xca\xc6\xb8\xe2\xd0\x7b\xd3\x05\x05\xac\x77\x3e\xc9\x52\x00\xcb\xed\x17\x88\xc6\x11\xce\xf6\xd9\x44\xb5\x13\xef\xb2\x69\x22\xcf\xf3\xb7\x9f\x39\xef\xd7\xc8\xff\x3a\x33\x20\x5d\x0c\xf6\xaa\x6d\xda\x97\xe1\xa7\xad\x21\x7f\xf8\x7b\x8d\x6b\x95\x2f\x10\x7c\x1b\x74\x9f\xd8\xb2\x15\xf3\x4d\x4c\x48\x39\x27\xcd\xb0\x02\x69\x50\x87\x87\x5b\x00\xbf\x29\x72\x12\x50\x65\xc9\xbf\xce\x71\x7f\x88\x28\xa4\xe7\xa1\xff\xa5\xd6\xe2\xa8\x0d\xb8\x86\xd3\xd1\xb6\x36\x04\x20\xcc\x14\x0a\xb7\x4e\x94\x32\xe8\xab\xf3\x7e\xb9\x67\xd2\xb2\xe3\xcc\x0d\x9e\x50\xd3\x53\xe7\xb2\x6d\x24\x80\x27\x50\x41\x4c\xae\xd8\xda\xc6\x4e\x58\x1f\x12\xef\x12\xe0\x2e\xee\x0b\xd3\xff\x71\x09\x2e\x4b\x69\x2f\xf1\x4b\x92\xa0\x8e\xd3\x00\xa0\xde\x41\xba\x68\x27\x8d\x9c\x19\x41\x00\xc0\xa1\xea\xf0\x22\xf2\x53\x2c\x43\x84\x2e\xc4\x26\x42\x55\x52\x3b\x47\x29\xff\xd4\xdf\x5a\x1f\x8e\x73\xbe\x85\x3b\xbe\xf6\x12\xdd\x68\x30\x41\xb9\xf7\xa4\xde\x31\x28\x61\x04\xc0\xb6\x55\x6a\x9b\xd0\xa4\xfd\xee\x8a\x2a\x10\x31\xf5\xf2\x44\x72\x88\x1a\x03\x4c\x31\x9e\xca\xbe\xe3\xa9\x2e\x81\x87\x20\x71\x49\x1d\xd9\xb7\xf9\xfe\xf3\x97\x86\x03\xcd\x89\xcf\x17\xa5\x9a\x9e\x1a\x0b\x5b\xee\x3b\x71\x3e\x55\xe3\xe5\xec\x1b\xb5\x0f\xb3\x02\x68\x80\x47\xbf\x5a\x55\xd1\xb8\xbe\x9e\xf2\x7b\x00\xa0\x1a\xc6\xf1\xe7\x5b\xa2\x0f\x18\x5c\xec\x46\x41\x30\x80\xa5\x8b\xd1\x8f\x9e\x61\x48\x29\x71\x00\x66\xae\x9b\xd8\x0c\xc2\x67\xac\x9f\x04\x40\x03\x1b\xac\x0f\xdd\xb5\xe0\xcf\xe1\x99\xec\x56\x1e\x5f\xd4\xd4\xc3\x13\x55\x5d\x45\x2d\x82\x7c\xa0\xeb\x35\x1b\xf1\x7d\xf0\xf2\x85\x02\xb3\xd0\xfc\x04\x47\x6a\x29\x1c\xfa\x53\xab\xa4\x7e\xec\xa7\x24\x80\x29\xff\x22\xaf\x0d\xe1\x23\x85\x22\xf4\x37\x95\x94\x51\x6a\xdd\xb3\x85\xac\x8e\xa0\x71\x55\xd7\x61\x18\x1c\xcb\xed\xab\x67\xe3\xe6\x11\xb5\x9b\x03\x60\xfa\x45\xf2\x05\xce\xa5\xbb\x78\x59\xb9\x3a\x23\x92\x44\xd6\x68\xf2\x45\xd9\xa8\xc8\xb2\xa8\x10\xbd\x30\x05\x1a\xcc\x23\xfc\xac\x4e\x20\x0c\xd1\x14\x2e\x83\xd5\x0b\xc5\x7c\x02\x2d\xbf\xc7\xd5\xec\x40\xc0\x7c\x47\xd3\x43\x5b\x92\x20\x8b\x84\x50\x9c\x6d\x39\xe6\x63\x36\x08\x73\x74\x69\x1b\xe8\x14\x31\x5a\x65\x0c\xfc\x27\x4f\x63\xa8\xc3\x65\xd9\x2f\xb5\xec\xe8\x42\x4b\x40\xa7\x89\x68\xec\xe3\xe8\xca\x5d\x19\x3f\x37\x70\x38\x9c\x11\x9c\xc1\xd9\x37\x46\xe9\xd4\x41\x61\xfa\x29\x68\x5d\x63\xfd\xec\x88\xbf\x36\xfd\x29\xd1\xd6\x30\xdb\xbe\xa8\x97\x12\xf2\x41\x5a\x49\x27\x51\x3a\x24\x4a\x9e\x2b\x39\x43\x41\x28\xcf\x36\x3f\x2e\xb2\x50\x0c\xc3\x78\x92\x71\x3c\xfa\xc6\x9b\x9e\xa7\xb9\x16\xd2\xd7\x79\x12\xf5\xa6\xa1\x25\x7d\x22\x64\x52\xd9\x32\x1b\x3e\xca\xba\xd9\x44\x7c\xf8\x61\x38\xe0\x68\x1c\xc7\x83\x59\xd1\x1c\xc2\x54\xff\xf4\x5a\xd6\x11\xe0\xaa\x8f\x30\x90\x8e\xcb\x02\x00\x24\x65\xf3\xb6\x6b\xfb\x10\xa0\x5b\xd5\x4b\x00\xdb\xa2\xc3\x2b\xb4\x3d\x25\x73\x8d\x14\x54\xd9\x28\xde\xc1\x00\x59\xb6\x18\x55\xbc\x51\xf6\x2e\xed\xe7\x7d\xbd\x2f\x1a\x97\xf0\x1d\x59\xdd\x4a\x1c\x2a\x98\x93\xf8\xa2\x5b\xce\x4b\x84\x63\xbb\x9e\xdb\x1a\x7a\xdf\x78\xcb\x4f\x4c\x65\xc1\x46\x72\x56\xb1\x3c\xc1\xf4\x44\xbf\xe8\xd4\x0d\xae\xfe\xb6\x70\x19\x07\xb0\x59\xd5\x38\x6e\x48\xeb\x50\x1c\xb1\x6e\xd1\xa3\xec\xc8\xd6\x4f\x7f\x21\x9e\xf3\x99\x17\x91\xf9\x16\x27\x6e\xc4\x7d\x2b\xb9\xc5\x6a\xf1\x2d\x96\x07\x58\xd7\x6d\x79\xf0\x64\x86\x57\x38\x83\x8f\x3c\xd6\xf6\xf1\x45\x4e\xb7\xa9\x24\x7f\xb8\x66\xa9\xfe\xe5\x73\x09\xa8\x3e\x80\x49\x9c\xc0\x74\x54\xa0\xa0\xa1\x2d\x6a\x12\x94\x58\x86\xfb\xb9\x0f\x96\x15\xd4\xab\x5f\x49\xdc\xb2\x75\xfe\x46\xdb\x81\xc0\xc5\x1c\x8a\x6e\x10\xa6\x5f\x3a\xed\xf7\xa9\xef\x3d\x53\xa6\x6f\x0a\x2b\x2c\x7f\x36\x22\xf1\xcb\x06\xa3\x77\x48\xbe\xda\xf7\x5c\x43\x6d\x2f\xb8\x95\xe1\x8a\xc6\x7c\x69\x3a\xf2\xfb\x5e\xa1\xf3\xc8\x85\xf9\xc3\x1d\xc4\x5d\xe3\x42\x24\x48\x8e\x62\x70\x45\xc9\x75\xca\x15\xa3\x3a\x67\x72\x7b\xf9\x60\x5e\xd6\xed\xae\xd1\xc9\x77\x7a\xc3\x67\x89\x8e\xcd\x43\x46\x8e\x5a\x64\x17\x2a\x6c\x9a\xbd\x28\xc8\x34\x5e\xc3\x17\x17\x74\xb2\x97\x6e\x4b\x3f\x07\x01\x56\x0a\x90\x27\x7d\x3b\x0d\x04\x7e\x9c\x1c\x15\x1f\x4b\xed\x8f\x71\xae\xf5\x49\x19\x6b\x43\x76\x44\xdb\x97\x27\xc1\x2a\xc9\x2a\x6f\x0d\xad\x69\x83\x10\x1b\xe3\x59\x0c\xab\xac\x27\xcd\x5a\x50\x7c\x23\x0d\x8d\xf0\x33\x1d\x3f\x54\x49\x36\x19\x78\x9f\x26\x84\xa2\x79\xd7\xb2\x16\x69\x33\x49\xf8\x53\xdf\x62\x28\xe5\x6e\x7e\xbf\x14\xf7\x50\xa2\x43\x88\x28\x58\x6c\x29\x26\xbd\x20\x51\x5a\x23\x61\x87\xed\x41\x7f\x33\xe4\x37\x0b\xcb\x4c\x0c\x68\x88\x7d\x43\xbc\xbd\xf1\xc1\x50\x7b\xa0\x22\x79\x98\x20\xcd\xee\xc6\xa8\x5f\xfe\x4c\xaa\x63\xb2\xe7\x6d\x65\x0f\x22\x35\xbb\x5f\x5c\xd8\xad\xa0\x6f\xba\x70\x06\x54\x72\x3b\xac\x39\xe1\x66\xc8\xba\x0e\x68\x08\x95\x1c\x9e\xc3\xc7\x5b\xa8\xb2\xaa\x59\x2f\x76\x17\xd5\x9b\x50\x95\x2d\x7f\xc0\x1a\x99\xfc\x8d\xcc\x9c\x9a\x0b\x5a\x6f\x38\xf2\xd8\xc4\x62\x8e\x22\xe0\x12\xd1\xcf\x13\xcb\x2c\x78\x85\x5b\xb7\xf9\xa9\xfb\x34\x98\x02\x3d\x16\x10\x33\x3a\x37\x01\x6d\x0a\x1b\x1b\x08\x39\xea\x38\xc3\x96\x80\xc0\xde\x6c\x5c\xb6\x08\x5e\xf2\xff\xda\x4c\xf6\x89\xbb\x7f\x55\x41\x39\xe4\xda\x46\x39\xe2\x0b\x82\x01\x51\x5a\x93\xbf\xa0\x56\xca\x2b\x43\xd9\x67\x47\xd6\x7e\x30\x44\x0b\x73\x97\x3d\x42\x4b\x92\x41\xa4\x39\x51\xd5\x37\xb5\x27\x07\x3e\x66\x80\xe4\x16\x20\x6b\x79\xcd\xa2\xbf\x4b\xcd\x84\x41\x70\x42\x2f\x1f\xf1\x3d\x23\xce\x3d\x5c\x8a\x06\xdc\x57\x72\xeb\x61\xf3\x77\x1f\x5d\xf2\x04\xbf\x36\x2a\x3f\x8b\x3e\x9d\x0c\x3d\x1d\xf4\x92\x45\x61\x8f\xfa\xf8\xd7\x16\xfb\xce\x2d\x4b\x00\x0d\xc3\x30\x0a\x75\xee\x64\x7e\x38\x6f\x24\x46\xa3\x80\x71\x2f\x66\x3c\xd0\x8e\x38\x87\xef\xd3\xbe\x8b\x17\xa3\xc0\x85\x42\x7f\xad\xa1\x0b\x4c\x3e\x38\x23\xd3\xf4\x43\xf8\xd8\x0e\x77\xf3\x33\x4f\xab\x7d\xe1\x36\xfc\x06\xb2\x79\x07\x32\x79\xd0\xf9\x15\x59\x5b\x1f\xd5\xa5\xb2\xda\x22\x32\xf1\xde\xb7\xdb\x9a\x3d\x0a\xb4\x50\xf8\x44\xe7\xec\x01\x50\x93\x6c\xf6\xe7\x82\x4c\x3a\x40\xcc\xcf\x2f\xa5\xe4\x40\x26\x9d\x88\xcc\x25\xad\xb0\x34\xf1\x45\xc1\x37\x94\xcd\x5f\x8f\xc9\x5f\x94\xc5\xb7\xd8\xb9\x51\xa0\x30\x8f\xd9\x1e\xcf\xd5\x87\xac\xf0\xd3\x1f\xa7\x6e\x9a\x0a\x72\x39\xce\x73\xc0\x90\xc5\xe8\x18\xec\x87\xaf\x99\xeb\x46\x94\x9e\x86\xbc\x04\x31\x60\xf2\x17\xcc\x64\x21\xb0\xe0\xa9\x78\xa6\xe1\x30\xfc\xed\xab\x36\x01\xd7\x18\x2d\x7f\x01\xdb\x05\x6c\x74\xbd\x94\xc2\xea\x1d\x3a\x13\xfb\x9c\xe3\xed\x94\xd8\x14\x7c\x82\x19\xef\xfe\x5a\xbf\x8b\x54\x7a\xdc\xfe\x08\xb7\xe9\x47\xe1\x9b\xa6\xb1\x77\x30\xc5\x68\x77\xf4\x0a\x53\x5e\xfa\xbe\x1f\xa5\xa2\x50\xf3\x00\x0a\x38\x0b\x9e\x9a\xfa\xea\xfb\x70\xff\x9a\xa5\x0c\xdd\x40\x61\xb9\x79\xd3\x40\x08\x40\xe9\x0b\xdf\x88\x6d\x6d\x56\xaa\xed\x83\xb6\x37\xdb\xae\x98\x52\xa4\xfc\xcd\xc6\xa6\xfe\x72\xa8\x9a\x42\xba\x01\x7b\xac\x6d\x00\x29\xc7\x75\x5d\xe7\xfc\x97\x1d\xa6\x14\x18\x8a\x1c\x79\xfc\xd7\x67\xc9\x45\x31\x8b\x6b\x9b\xab\xb0\x75\xf0\x93\xbb\x50\x26\xfd\xf2\x0f\xbd\x95\xda\xc3\xf5\x1b\x92\x71\x86\x4f\x1c\x91\xa3\x55\x76\x21\x08\x84\x8c\x44\xba\x74\xab\x9a\x6c\x65\x86\x4f\x99\x47\x6c\xe7\x49\x4c\xfd\x3a\x04\xeb\x10\x28\x8b\xa8\xa8\xac\x7e\x57\x9c\x92\x75\x58\xca\x61\xa1\xb3\xde\x71\x0f\xe3\xb7\x15\x7f\x73\xa9\xab\x07\xce\xb9\xca\x07\x04\x73\x58\x76\xdb\x35\x19\xe4\xb2\x3b\xe8\x6f\xa1\x6f\x75\x99\xc4\x75\x42\xfa\x19\x19\x87\x76\x78\xc6\x66\xd5\xaf\x1e\x5e\x41\x71\x9a\xf3\x59\xfe\x7a\x99\xff\x44\xce\x3a\x04\xf3\x98\x80\x22\xa6\xb3\x99\xee\x72\x9a\xeb\xe9\x3e\x24\x7c\x58\xb5\x5f\x92\x3d\x72\x67\x85\x65\x73\x8a\xf4\xcb\xbd\x12\x69\xb1\x4d\xc1\x97\x1b\x23\xeb\x87\x88\x5d\x77\x1d\xcd\xf6\x29\xee\xa1\x07\x6a\xfa\x26\xf8\xf9\xee\xbe\x4c\x83\xdf\x67\xac\x10\x66\xe4\xc3\x7c\xe1\x6a\xf2\x6d\xad\x72\xc8\x40\xd9\xfa\x94\x84\x3e\xb2\x08\x40\x7d\xee\x89\xad\xb5\x6e\x45\x8e\xb7\xc0\x26\x87\xa0\xd0\xd1\xe5\x36\x10\x6c\xdb\xf3\xec\x89\x66\x7c\xda\xe3\x68\xff\xf0\x04\x3b\xc7\x89\x57\x08\x35\x92\xf0\x9b\xe3\xa0\x89\x96\xdc\xf3\x22\xd1\x1b\x08\x40\x95\x7c\xe4\x56\x20\xec\xea\x88\x9e\xd7\xa6\xb5\x7b\xb0\x3e\x4c\xed\xaf\xe5\x86\xe4\xba\x65\x1b\xe6\xdd\x51\xc1\x63\xfb\xe6\x4b\x9a\xed\x4d\xcc\xfd\xf3\x93\xbb\x60\xd9\x38\xa7\x81\x85\xaa\x25\xb5\xd9\x9e\x00\x8d\xc8\x2f\x21\x7e\x46\x2a\xee\x16\x6d\x27\x6f\x68\x11\xc2\x2e\x77\x33\x94\x97\x77\x09\x69\xb2\x71\x1d\x1a\xfd\xcb\x9d\x5a\xb7\x6f\x08\xfd\xcd\xc5\x20\x58\x1e\x6d\x2f\x09\xbe\x0f\xcc\x98\xf2\xcb\x8e\xa9\xff\xe1\xe8\xc2\x10\x10\x03\x0d\xa0\xbb\x06\x28\xda\xa3\xeb\x15\x72\x1c\x79\x08\x7b\x28\xb6\xa7\xc9\xec\x95\x52\x4f\xa6\xd1\x07\x0d\x82\xc2\xe1\x97\xad\xae\x64\x47\xea\x12\x4e\x44\x32\x38\x5a\xce\x6c\x5c\x8a\x3d\x0a\x37\x46\x83\x1b\x62\x2a\x89\xb7\xbc\x01\xd8\x0d\x47\x70\x7f\x9a\x3f\xb8\x37\x6b\x00\x17\x08\xa9\xac\xa6\x36\x1b\xbd\xfb\x01\x7c\x64\xc8\x91\xcf\x71\x5a\xcf\x1f\x77\xb7\x4a\x01\x97\x50\x23\x22\x80\x4f\xee\x77\x44\xde\xf9\x6b\xca\x86\x0f\x83\x46\x78\x7d\xac\xaf\x4f\x3e\x20\x85\xbd\x8e\xcc\x62\xa5\xe4\x52\xd5\x6c\xfc\x2f\x46\x20\x38\xaf\x41\x5a\xb4\x0a\xee\x11\x51\xc4\x65\x3e\x95\x53\x8a\xd7\x39\x99\xe5\xd6\xa8\xda\xd6\xb3\xec\xd6\xe6\x6d\xda\x1c\x99\x2a\x59\x45\x1f\x0d\x6f\xb8\x58\x60\x45\x37\x62\xdd\x89\xe0\xae\x14\xa0\x80\xb8\xac\x16\x83\x9a\xfd\x7f\x63\x7a\x24\x4d\x12\x61\x5c\x3c\x94\x3b\x48\xc1\xb1\xa5\x48\xb5\xa2\xcd\x47\x47\x69\xbd\xb0\xde\xfa\xb4\xec\x13\x9c\xe6\x6e\x6a\xb5\xa5\xc6\x30\x1d\x1e\x23\xe9\x3e\x73\xa9\xdd\xf3\xad\x4c\x45\xde\x96\xb8\xb9\x64\x5d\xf9\xf0\xd4\xa2\xff\xe9\x57\xe5\xbc\xeb\xe4\x83\xae\xe1\xf7\x57\x52\xac\x5a\x36\x1e\x1b\x42\xc7\xa5\x01\x65\x0d\x59\x26\xd3\x88\xa4\x04\xca\xb2\x38\xa2\x9d\x7a\x8d\x96\x03\x4b\x4d\x6a\xed\x13\xe1\x83\x6c\xba\xd5\x5d\x73\x23\x1f\xbf\xac\x11\xe7\x54\x3e\xcc\xbe\x03\x27\xff\x60\x91\x11\xaf\xa7\xa4\x8d\xf1\x76\x92\x94\xef\x39\x40\x7a\xa8\xc6\x31\xfe\xb1\xba\x5a\xce\x12\xc4\x84\xdd\x96\xbc\xdb\xc0\xda\x0c\x78\xe2\xa4\xf4\x77\x7d\xc9\x2f\xfb\x81\xd0\x0d\xc9\x93\x07\x31\x04\x6b\xcf\xdb\x4e\xb5\xd8\xc6\xec\x0c\xc8\x7f\x22\xd1\x88\x9d\x25\x7f\xa0\xe8\x53\x64\x86\xad\x29\xfb\x03\xc1\xe6\x1b\xc0\xa6\x9f\x2b\x7b\x00\x52\x0f\x8d\xbc\x36\xb2\xde\x67\x60\x9c\x65\x53\x4d\x0c\xb8\x8b\x52\x36\xe3\x6f\xa6\x6e\x11\x7c\xa4\x55\x08\x97\xdf\xc2\xae\xa6\xef\x86\xfb\x3b\x69\xb2\xc4\x4c\x3f\xce\x3f\x59\x56\x94\x45\xc0\x6a\xcb\x4d\x02\x87\x3c\x68\xb8\x84\xca\x29\xc3\x51\x17\x1f\xe7\xf4\x31\xd9\x09\x26\x81\xe1\x34\xac\x32\x79\x6d\xb7\x74\x0b\xf5\xfa\x08\x4c\xfb\xfb\x3b\x31\x47\x7e\x78\x1c\x0d\xe9\xbc\x46\xe4\x88\xd1\x02\x89\xfc\xa9\xc1\x62\x3e\x93\x53\x3c\x5d\xe8\xb5\xf1\x46\x68\xeb\x7a\x6c\x11\x6c\xfa\xce\x1e\x95\xae\x8c\x05\xe2\x35\x5e\xc4\xe1\x8d\x41\x04\xa6\x86\xc0\x62\x55\x3c\xa9\xeb\x3e\x1f\x33\xe6\xc0\x52\x30\x2c\x79\xb4\x04\x7b\xde\xa1\x1f\xfa\xbf\xce\xbc\x7d\x99\x3c\xb8\x13\x0e\x9f\xef\x5f\xdd\xcf\x29\x31\xf7\xcd\x61\xda\x75\x69\x29\x0c\xc3\x70\xaf\xd3\xaf\x33\x7f\x5e\xc3\xc2\x31\x0c\xfd\xc4\x73\x8b\x75\x2b\xf4\xb5\x65\xf8\xe6\xd7\x58\x92\x50\x00\xfc\x12\xe7\xf6\x54\x1b\x2c\xca\xd7\x90\x3f\xa2\x78\xfe\xeb\x8f\xa7\x60\x90\x6c\x5c\x2b\xb0\x77\x1f\xc1\xf7\x0f\x3b\x47\xf8\x4f\xe6\x0d\x04\x1c\x7f\xd0\x52\x16\xb6\x5c\xac\x40\xa8\xac\x2b\xc8\x4f\xfc\x0d\xbf\x24\xed\x8e\x58\x57\xcc\x22\x7c\xc9\xa2\x65\x1d\xc6\x50\x6c\x6d\xd9\x78\x77\xa2\xb2\x0f\xd4\xfe\x6a\x2c\xb5\x1b\xd7\x1f\x8c\xdd\xb9\x8c\xd7\x20\x0d\xbe\xe9\x61\x95\x1f\xcd\x45\x23\xd1\x08\x1f\x17\xfa\xea\x21\x6a\xd5\x5b\xb8\x38\xa0\x79\x9f\xa0\x73\xd1\x5d\x38\xf5\x52\xb1\xd9\x87\x79\xd5\xba\x95\x38\xf3\x05\x8c\x55\xda\x9b\xf9\xf6\xa2\x36\xe5\xb8\xd7\x5b\xb9\x98\x7f\x1c\xe2\xca\xaf\x73\xcc\xa9\x1f\xe5\xbf\x7d\xce\x2b\xc4\xec\x7a\x8d\x59\xde\x50\x4c\x91\x69\x9c\x73\xfe\xa1\xb5\x1d\x3b\xe2\xcf\x83\x9e\xf8\xe4\x25\xcd\x0e\x8f\x23\x79\x22\x8f\xae\xec\xc8\xf1\xe1\xb0\x98\xfd\x92\xcf\x34\x72\x52\xc4\xfd\xe4\x1e\xe4\xcb\x17\x70\x9b\x57\x08\x9b\xe3\x47\xfa\xfc\x20\x45\x23\x48\xdc\xf8\xf4\x65\x34\xe0\xe4\x57\x8b\x1f\x9d\x32\xc7\x24\xa1\x4e\xd5\xdf\x97\xfc\xed\x5c\x75\x5d\xc7\x45\xac\x9f\x57\xf3\x11\x99\x1f\xab\x37\xf2\x12\x1d\x4f\xfe\x16\xe6\xb3\x4e\xcd\x94\x04\xdf\xf4\x80\x33\x8c\xd1\xf0\xe0\x47\x2e\x1d\xdb\x41\x4f\xfb\x2b\x56\xa9\xc5\xfb\x1e\xc4\x97\x69\x5c\x7e\xe2\xda\x96\xaf\x75\x70\xa5\x65\x4b\x87\x07\x08\x1f\x3d\xfc\x46\x51\x58\xc6\x2a\x34\x7a\x8f\x65\x19\x77\xa4\x4c\xfe\x37\x79\xe2\xa7\x91\x7f\xee\x32\x71\x5a\xfe\x9f\x5d\xa5\xd0\x3b\xe4\xff\xd3\x39\x48\x49\xd7\x3e\x6a\x93\xde\xe5\xbf\x37\x9e\x44\x14\x37\xda\x8f\xc9\x82\x38\xe9\x6f\xa1\x07\xdb\xda\xb8\x22\x87\x1f\xc0\x26\x59\x25\x79\x95\x63\x37\x99\x63\x9e\x2d\x23\x82\x66\x15\x3b\xfb\xfc\xd1\x11\xf3\xbe\xe0\x7c\x0b\x41\x50\xd4\x8f\xde\x2f\x09\x3e\xb7\x95\x00\x63\x0c\x2c\xe0\xfa\x61\xc7\x84\x03\xae\x2a\xe7\xbe\xe1\xda\x06\x68\x9e\x64\x9a\xee\x0e\x61\x58\x86\x65\x7c\xd0\x74\x9d\x64\x6a\x7b\x23\xda\xdd\x93\x30\xed\xb3\xb4\x26\xff\xf5\x25\x35\x2e\x51\xbb\x6a\x72\xfb\x5a\xf6\xf9\x72\x0f\xc3\x28\x1f\x97\x2d\x47\xe8\xef\xc1\x37\x95\x1f\x99\x4b\x65\xe9\x0d\x31\x79\x30\x53\x4f\x2a\xb5\x59\x24\x56\x71\x28\xac\xf3\x45\xf5\x21\xaa\x77\x27\xad\x76\x2e\x24\x43\x7e\x67\xbc\xb6\xdc\x39\x3c\xab\x8a\xef\xe7\x9f\xfa\xaf\x59\xfd\x18\x47\x3c\x51\x32\x47\xc4\x27\x6a\xa6\x38\xad\x0d\xde\x1d\x8a\x89\xb7\xe8\x70\xec\x07\x47\x0e\xa3\x51\x8a\x7d\xe7\xf3\xeb\xed\xd8\xf7\x3a\x04\x40\x79\xa5\xec\x3d\xf2\x0c\x39\xb6\x0c\x19\xeb\xaa\x65\x4b\xf1\x97\x43\x83\x8a\xa2\xa5\x42\x7d\xf2\x57\x67\xce\xe3\x32\xa6\x48\x2a\xb9\x41\x6e\x83\xa2\x22\x32\x69\x5c\xa3\xd4\xb2\x66\xd2\x2e\xd4\xa7\x52\x88\x15\x38\x29\xd4\xd0\x7a\x0f\x50\x84\xf4\xd7\x43\x3f\x8c\xbb\x3c\xa2\x71\xa6\xe2\x70\x66\xd2\x67\x26\xad\xf7\xa9\xf4\x7b\x04\xe1\xde\x92\xdf\x49\x63\x27\x2d\x30\xbf\x3f\x7d\x71\x5d\x99\xc7\x9f\x43\x70\x81\x93\x4c\x33\x02\xd8\x56\xbf\x2c\x6b\xc9\x36\x02\x0f\xe9\xbf\x32\x8c\xdc\x98\x44\xdb\x69\xe5\x9a\x2d\x9c\xba\xf7\xa4\x34\x5e\xa8\xc2\x65\x1c\xa2\x34\xa8\xad\xeb\xb9\x79\xa7\x24\x44\x9f\xde\x91\x80\xa6\x4a\xa2\xd4\xb9\xfe\xe5\x33\x45\x41\x59\x24\xb6\x29\x44\x0f\x98\x7b\xc8\x8f\x8e\x35\x1b\x56\x64\x33\xed\xa3\xfc\x58\xa0\x1a\xa5\x79\x4e\x95\x10\xac\x47\x17\x89\xa2\x1f\x57\x2c\x2e\x7f\x01\x09\xe8\xac\xd1\x10\x75\xe1\xb2\xac\x63\x93\xea\x9e\x58\x98\x41\x18\x10\x3e\x37\xde\x16\x03\xcf\xff\xd4\x69\x17\xee\x85\x57\xdb\xd5\x4f\xe0\x3b\x16\xfc\x27\x43\x8e\x25\x8f\xe8\xbd\xb0\xf5\xf5\x6d\x25\xef\x81\xcf\x5f\xff\xf5\xd8\x8a\x73\xdb\x0a\x80\x13\xf3\x0a\xf6\x3c\x22\xd0\x94\x1e\x9f\x77\xcd\x46\xb5\x47\x7d\xef\x04\xa6\x11\x27\x52\xa3\x32\xfd\x41\x11\x71\xa5\xfd\x7b\x7c\x5c\x56\x59\xe4\x99\xf4\xbe\xc3\x4d\xe2\xb8\xad\xe2\xc3\xf3\xae\xf9\x88\x7f\x4d\x00\x69\x80\x49\xb2\xc1\xc4\xb2\x99\x92\xe3\x63\x12\xdd\x96\xc7\x58\x84\x71\xaf\xd0\xa1\x7b\xe2\x87\x8e\x2b\xf4\x20\xa3\xf0\xd4\xd1\x8b\x6e\xb9\x4f\xab\xfe\xab\x6d\x57\x14\x5f\x45\xf7\x77\x0c\x5e\x15\xc4\x1b\x60\x22\x81\x6d\x25\xce\x7b\xcf\x85\xbe\xc4\xa3\x68\x8e\x4a\x12\x3e\x73\x88\x76\xcd\xf6\xc5\x08\xa0\x3c\x97\xa8\x6f\x2f\xcb\x45\x8e\x2d\x42\x0f\xb2\xa5\x8e\x10\xf8\x22\x81\xbb\xd7\x52\x3a\x56\xbc\xcf\x2f\xda\x4f\x6f\x38\x83\x9d\xa3\x10\x02\x8b\x4c\x43\x6b\x99\xac\xba\x79\x61\x42\xb8\x46\xa1\x35\xd4\xbd\x62\x32\xb7\x11\x78\x80\x83\x55\x2e\xf0\x01\xc1\x6d\xe4\x33\x52\x23\x5c\x13\xd6\x3e\x86\xdd\x66\xd2\xb0\x44\x79\xb6\x43\x80\x7d\x0f\x06\x6d\xd7\xb5\x8f\x15\x59\x52\xa9\x3f\x3d\x90\xd8\xe6\xb0\x49\x9f\x21\x45\xec\xab\xdd\x40\x2a\x8c\x1e\x33\xcb\xda\xb6\x92\xe7\xbd\xa7\xd2\x48\xa1\x92\x15\xb1\xd5\x0b\x46\xfb\x14\xd5\x3d\xea\x97\x69\x1d\xb5\x18\xe7\x06\x9b\x1a\x10\xd3\x4e\x44\x43\x59\x8e\x8f\xbf\x82\x71\x88\x60\x20\x00\x4c\x3e\x83\x0d\x7d\x3f\x19\xcc\x92\x94\xff\xe6\xd0\xf5\xb2\x7d\x5a\x15\x3a\xee\x8a\xda\x73\x49\xdd\xce\xf2\x7b\x7a\xa3\x69\x00\x91\x16\x6f\xe7\x1b\x36\x8d\xb1\xd4\x3a\x5c\x6e\x19\x7c\x48\xf7\x6b\x7d\xe1\x61\x2c\x44\x63\x19\x8c\x28\x46\x4f\x16\x88\xf8\xbf\x3a\x35\xd1\x3a\xb5\x2b\xa6\x85\x48\xfb\x47\x87\x54\xd1\x0d\xc2\x29\x85\x4b\xdd\x23\xbe\x3e\x51\x79\x81\xa1\xa2\xb8\x2d\xeb\xef\xa5\x28\x15\xde\xf4\x6c\x95\xa3\x15\xfd\xcd\xac\x5f\xef\xfd\x5c\xc7\x62\xc0\x26\x7f\x79\x83\x32\x85\x7d\xa6\x8b\xa4\x7f\xe3\x7e\x3e\x2a\x84\x7b\x2d\x3f\x54\x1b\x59\x7d\x12\x78\x20\x2b\xac\x96\x31\x22\xc8\xd4\x56\x55\x11\x11\x23\xe1\x09\x61\x75\xaa\xed\xb7\x82\xaa\x63\xc1\x6a\x7d\x01\xf1\x16\xde\x46\xf7\xf0\x3a\xc5\x2b\xba\x23\xee\xb9\x2b\xf9\x6e\x0a\xa5\x21\x66\xc3\xfb\xb9\x87\xf3\x51\x4d\x45\x65\x32\x35\x44\x89\xfc\x01\xc2\x35\xff\xb5\xe9\xd6\xb3\xaf\x4c\xab\x08\x3b\xfd\x98\x4a\x81\xfa\x93\x23\x62\x18\x8e\x02\x23\x80\xd2\x71\x6a\xb8\xd0\x10\xbc\xc1\x1a\xe1\xd5\x2f\x51\x22\x4f\xbc\x76\xd9\xea\x73\x64\x9b\xc6\x43\x3f\xb1\x8d\xf2\xfa\x08\xba\xaf\x3d\x05\x7b\x2d\x59\xbd\xc8\x8d\x98\x9f\x04\xd5\x07\x02\x98\xd7\x6c\x0c\xd3\x24\xe2\x38\x8e\x08\x7b\xbf\x28\xa3\x29\xae\xc0\x67\x8d\xa0\x01\x03\xce\x59\xf1\xc6\x54\x1a\xb3\x3a\x86\xf9\xe2\x8c\x37\xa2\xfb\xe6\x30\x1b\x0e\x89\x46\xa1\xe5\x07\xab\x78\x26\x98\x1b\x6c\x56\x7f\xf2\x71\xfc\x67\xb2\xda\x81\x04\x24\x51\x53\x16\x2f\x84\x2b\xb4\xb6\xa7\x47\x0d\xce\x68\x9f\xc4\xb0\x90\xbf\x44\x04\x65\xfc\x77\xab\x41\xe0\x39\xe4\x81\xaa\x3c\xe9\x1b\xdc\x22\xfe\x6b\x4f\xfd\x00\x35\x11\xfa\xab\xaf\x04\x32\xce\x83\xbe\x7d\x9b\xb4\xbe\xfa\x01\x95\x02\xd1\x24\xff\xa0\xc0\x1c\xcf\x2b\x80\xe1\x76\xaa\x4b\x7c\xf9\xf3\x4b\x1c\xf9\x96\x46\xe1\x90\x22\x65\x1c\xc1\x07\xe9\x13\xf5\x87\x48\xb6\xe4\x50\x61\xa2\x1c\xab\xa3\xaa\x29\x0c\xf5\x83\xa3\x8e\x7b\x63\x5e\x3e\xf3\xb7\xcc\x14\x96\x4d\x8e\xf5\x79\xbf\x39\xca\x93\x60\xe9\xf7\x76\x8f\xc1\x71\x41\xf4\xd4\xe0\xb0\xb8\x63\xd8\xdb\x1f\xee\x03\x9e\x55\x72\x84\xaa\xdd\xa2\x53\x11\x00\x46\x4e\x1a\x59\x42\x59\x7d\x8a\x49\x5d\xb3\x6e\x2d\xfd\xc1\xf0\x67\xf7\xca\xd7\x77\xbf\xe3\xe3\xa8\xec\x78\x1b\x63\x18\xc3\x0e\x7e\xf5\x53\xdf\xea\xb8\xa8\xcb\xc2\x61\x48\x45\xa7\x11\x52\x71\x1c\xa5\xcf\xa0\x2e\x83\xc2\x33\x90\x6d\xbe\x09\x12\x30\x6b\xc4\x7a\x6f\xf2\x1f\xbe\xc4\x74\xaa\x2b\xa9\x73\xa5\x38\x84\xae\x70\x6b\x36\x85\x30\xfd\xeb\xf7\x46\xda\x35\x9b\x32\x12\x75\x5d\x41\x33\x40\x68\x33\x63\x38\x46\xd0\x4b\xc6\x2f\x95\x64\x8f\x79\xee\x92\xae\x7f\x7c\x15\x07\x2d\xf8\xd8\x72\xf3\x08\x95\x56\x16\x81\xa4\x47\x61\x5a\x64\x84\xa1\x01\xd1\xbf\x79\xd2\x0f\xad\xa2\xeb\x0b\xaa\xfd\xfb\xb9\x95\xfe\xf4\x51\x00\x84\x81\xfa\xd1\xdc\x51\x5d\xb3\x49\x25\xaa\xf4\x73\xe2\x9c\x90\x8e\x60\xfc\x25\x47\x1a\xf4\x61\xa9\xba\x23\x93\xac\xf2\x26\xee\x20\xde\x39\x04\xa6\x11\x98\x25\xd2\x9c\x76\x8d\x36\x6c\x54\x9f\x98\xc1\xb0\x29\x23\x35\x26\xd4\x18\xb1\xf8\xd3\xb0\x97\x71\xab\x63\xf8\x46\x1c\x83\x8c\x04\x02\x7c\x57\xe9\xdc\x3e\x58\xc2\x0b\xb8\xed\x63\x21\xa7\x84\x68\xac\x05\xbb\x9b\xfb\x2b\x55\x1d\x91\x07\xb6\xf6\xe7\xc8\x21\x1f\x0e\x5d\xde\x14\xb3\x0d\xae\xea\x37\x0c\x1d\x01\xb0\x6e\x91\xa9\x46\x02\x3d\xbe\xf1\x81\x6e\xa1\xd7\xaf\xac\xd0\x33\x7f\x6c\x22\x9b\x94\xaa\xe5\x07\x94\xd8\x74\xfc\x1c\x40\xe2\x93\x73\x2a\x68\x0f\x10\x31\x2d\x44\xf5\xfb\x8d\x7d\x05\x2c\xf5\x46\x0d\x49\x3f\x1f\xba\x32\xcb\x52\x4c\xdc\x4f\x69\x2f\x5c\xe3\xac\xa0\x8d\x69\x2b\x1e\x23\xd7\x1c\xc7\x25\xb0\x41\xeb\x10\x6c\x55\x9c\x5c\xde\x28\xd0\xb8\x97\xbc\xff\x61\x35\xdc\x4d\x96\x2b\x4d\x53\xbe\x1a\x9f\xeb\xb5\x4a\xda\x8d\x18\xaf\x41\x1b\xaf\xe1\x73\x6b\x38\xb7\xb3\xd4\x3f\x57\x84\xb5\x21\x8b\x48\x17\xf2\xa5\xe9\x3a\x70\x65\xc7\x54\xe0\x55\xd7\x96\x6d\xdb\x88\x75\xdb\x32\xc9\xda\xf9\x1d\xe1\xa9\xff\x7c\x7e\xb1\x2d\xa2\x10\xfd\xca\x77\xd7\xf3\xf3\xd7\xc4\x62\x06\x93\x15\x92\x00\xe6\xf4\xb2\x78\x87\xb6\x7d\x83\xb4\x20\x9b\x2f\x29\xc3\xf9\xb4\x55\x39\x77\xbf\xed\x43\x37\xef\xfa\x52\x8a\x8a\x99\xe0\x17\x81\x06\x14\xf0\x19\x34\xac\x1a\x98\xff\xb8\x35\x0c\xae\x93\x5a\xac\xf2\xbc\xcc\x87\x0d\xe1\xca\xb7\x5a\x26\xeb\x64\x8f\xf3\x19\x92\x98\xd7\x7a\x8d\x47\x70\x7a\x89\x2b\x16\x67\x8d\xc2\x94\xb2\x17\xb0\x26\x51\x8b\xb4\x43\x9f\x4f\x14\x8b\x77\xf0\x51\xd7\x71\x75\x18\x43\x9d\x81\xff\x61\x3c\x3a\x41\xfb\x4b\x3d\x2f\xcd\x97\x37\xcc\x67\xb3\xd3\x9c\x67\x30\xeb\x35\x5e\xe1\x22\x64\xae\x58\x5c\x69\x74\x53\x7a\x5a\xe9\x7a\x03\x6b\xb2\x4e\x15\xa1\x47\xae\xee\xb1\x4a\xbf\xa1\x0c\xfe\x13\xa0\x66\xa8\x68\x23\xfb\x53\xef\xd0\x08\x59\xe8\xad\x95\xdc\x0a\xd5\xe2\xb8\xbf\xf7\x19\xf8\x52\xf6\xbe\xed\xc7\xb0\x6b\xac\x57\x4c\x29\x64\xb6\x81\x96\xfa\x4a\xae\x5d\xb2\x13\xb8\xb5\x8c\xd7\x22\xf1\x7d\x01\x18\x11\xb0\x53\xc7\x4c\x7f\xa9\xbf\xea\x3d\xda\x24\xe7\x34\xfd\x7f\x12\xad\x1c\x53\x21\x73\x89\x26\x26\x4e\xb8\x7e\x43\x1c\xb4\xc9\x5a\xc6\x4b\x98\xb2\x5b\xc8\xba\x77\x83\xed\x0a\x3f\xab\xfd\x90\xc9\x38\xe8\xf5\x4d\x02\x8c\xf1\x9a\x27\xe2\x07\x0a\xe0\x96\x57\x10\x73\xc1\x0d\x75\xea\x03\xad\x7f\xcc\xbf\xba\x7d\x57\x3e\x04\x7b\x25\x73\x33\x36\xbd\x57\xab\xd8\x97\x25\x6c\x18\x51\x53\x69\x86\xa5\x86\x12\x1b\x83\xf5\x8c\x1b\x51\x03\xb6\xd7\xca\x25\x20\x26\x08\xf8\xc2\xd5\x06\x01\x23\x05\x4b\x4e\xe1\x05\x6f\x94\xc8\xec\xfc\x3b\xf7\x3b\xb3\xc5\xa3\xff\x8c\x2b\x76\xde\x5a\xfa\x33\xc2\xb7\xb0\xa0\x4e\x3e\x11\x3b\xc4\x14\x87\x70\x59\x0c\xbd\xd1\x3a\x5a\x1b\xa8\x2c\xb2\x78\x9f\x8e\x75\xc5\x22\xff\x96\xf2\x0c\xc6\x04\x18\x2b\xc6\x26\x85\x5c\xed\xd8\xbc\xca\xd9\x17\xfd\xc4\x72\x30\xff\xb7\x76\xb1\xe9\x9b\xcb\xe4\x55\x0d\x1e\xe7\x68\xc8\x7e\xab\xc0\x28\x1a\xb6\xf3\x74\x3d\xc9\x39\x35\x0c\x94\x31\xd8\x91\x3a\x08\xf1\x54\xa5\xe6\x89\x5a\xc4\x6c\x96\xb0\x21\x60\xec\x15\x2b\x79\xec\x0f\xe1\x7a\x9c\x9f\x60\x17\xf8\xfe\xf8\x3c\xdc\x15\x8d\xeb\x99\xf4\x9e\xab\xe6\x5b\x9d\x93\x71\x1e\xc3\x74\x35\x05\xeb\x74\x6d\x98\xeb\xad\xae\x2f\x3a\x8e\x9c\xe6\x7c\x86\x22\x80\x8d\x9c\x26\x74\x1e\xcf\xab\x8b\x86\xd7\xef\xdb\x0c\xfc\xde\xf8\x23\xd5\xb4\x88\xf5\x7e\xe2\x04\x21\x72\x7d\x2e\x97\xef\xae\x9a\x1b\x62\x5c\xd6\x61\x71\x83\x50\x74\x83\x48\xba\x23\x56\x53\x6f\xf1\xf6\xe4\x79\x14\xaa\x6c\x9e\xc4\x3e\xf7\x4d\xb5\xdc\xc8\x2f\xa1\x47\x70\x18\x72\x83\x92\xb1\x4d\x22\x3d\x45\xd9\xc6\xff\x7a\xd1\x8b\x86\xef\x50\xce\x64\x85\xc1\xa8\xbd\x48\x74\x21\x11\x12\x0e\x4b\x11\x76\x9e\xe7\x78\x7d\xf0\x9b\xcb\x53\x50\x46\x19\x19\x2a\xb3\x7c\xef\x27\x7e\x7e\xe9\x6e\xf8\x3a\x8d\xaf\xec\x99\x3c\x76\x8f\xc1\x33\x98\x5c\x12\xe3\xbd\xf3\xa3\x4f\x44\xc5\xe4\xaf\xdb\x6b\x43\x03\x1e\xf0\x44\x64\xfe\x1b\x2f\xf3\xa1\xa8\xe9\x85\x79\x90\x66\x5c\xc4\x6c\x8d\xdc\xac\x6f\xb0\x14\xb8\xd2\x5b\x29\x6c\x2d\xb4\x01\xd3\x28\xa0\x39\xdf\x25\xc0\x36\x3d\x25\x4d\xde\x29\x84\xe3\x15\x88\x88\x91\x62\x49\xfc\x8f\x77\x86\x09\xe2\x2e\xf3\x25\x17\x4a\x17\x87\x1c\x1c\xd3\x80\xfc\xd2\xa6\xc0\x66\xd5\xef\x54\x37\xd3\xd5\x76\x3d\xdb\x8f\x33\xc3\xf4\xc2\xb5\x62\x21\x60\x80\x2c\xf5\x7e\x55\x61\xec\xd4\x31\x1c\x7a\xf9\x2a\x96\x7f\xf8\xc9\xfc\x55\x65\x77\x8f\x9d\xd1\xb9\x51\xed\x53\x86\x6b\x99\xef\x74\xbe\x95\x13\xb9\x02\x4b\xc8\xcd\xd9\xa7\x48\x3b\x28\x6a\x20\x69\xfe\x8a\xc6\x72\x79\x6a\xe0\x86\x61\x52\xf3\x86\x5b\x29\xd6\x7d\x59\xe6\x3c\xc6\x67\x29\xbb\x7b\x70\x8d\x17\x6a\x46\x49\x90\x16\xdf\x3f\x06\xa2\xf5\x4b\xa1\xb8\xc3\x44\xd7\xd6\x15\x98\x2e\x60\xa2\x28\x94\xa6\xcb\x40\x6b\x47\xf3\xae\xb4\x3b\x26\xc4\xfb\xcc\x87\x79\x3c\xd3\xcb\x62\x21\xeb\xa4\x4c\x56\x51\xf0\x77\x29\xed\x05\x2a\xa5\xbb\x9d\x53\xc2\x6b\x64\x1f\x0b\x67\xe9\x3f\x79\xea\xa8\x24\x5d\x37\x4c\x82\x83\xb0\xb6\x96\x71\x07\xc9\x95\x6c\xa8\x1e\x9a\xe4\xe4\x2b\x62\xb6\x8a\x2b\x37\x6b\xa9\x2e\x7f\x55\xcb\x0d\xe8\x9e\x6a\x0d\xc8\x09\x23\x23\x05\x9f\x07\xfd\xdd\xcb\xb9\x2e\xf3\xad\xcc\xb6\xd4\x11\xc5\x97\x81\x8c\x5e\x01\xf8\x8f\xf1\x53\x87\x23\x9a\x9f\x80\x96\x1d\x4a\x5e\x0b\xeb\xe4\xd9\x34\x3c\xee\x5f\x7f\x77\xd8\x5f\xe3\xbb\x86\xce\x3a\x06\xcf\x08\x21\x83\xd8\x07\x56\x1b\x70\x4d\xf2\x91\x85\x4e\xcf\x09\xfc\x46\x06\xe2\x1b\x12\x24\x9a\x92\x66\xda\x86\xe2\x51\x0e\x7b\xce\xd0\xf2\x36\x67\xf2\xe9\x41\x5a\x00\xa8\xdd\x9f\x63\x3b\x1b\xa2\xe2\xe9\xca\xb3\xfe\x7a\x45\xdd\x13\x91\x2b\x69\x9d\x4e\x41\x2d\x87\xbd\x14\x7c\x53\x70\x73\xcd\xcf\x21\x83\x09\xcd\x28\x5f\x80\x78\x59\x6c\xa6\x13\xf9\x62\x9d\x6e\xce\x64\x5b\x40\x4c\x01\x81\x22\x00\x7c\x83\x78\x86\x7f\x2b\x99\x4d\xa4\xf6\xca\x94\x66\x4d\x22\xb1\xdb\xcb\x8f\x41\x6a\x2f\x08\x83\x48\xc0\xe8\x46\xf3\x3f\xeb\xba\x28\xa6\x15\x2f\x45\x57\xf7\xcf\x15\x7f\x86\x7d\x17\xfb\xd0\x05\x65\x02\x44\x01\x0a\x04\xae\x03\x8a\x13\x5a\x50\x16\x71\x36\x59\x4d\x75\xad\x52\x50\x0e\x31\xd1\xd9\x4c\x87\x32\x71\xf8\xac\xeb\x5a\x60\xa0\x59\xf2\x63\xe9\x2f\xb5\x8e\xc7\xba\x09\x16\x62\x7b\xe0\xc0\x42\x96\xe7\x9d\xde\x37\x1e\x83\xb7\xfc\xeb\x5c\x59\xc3\x8b\xfd\xf1\xab\xc4\x41\x68\xfa\x65\x2c\xc7\x95\x31\x22\x52\x84\xfd\x5f\xf1\xf7\x3b\x4e\x46\xd1\x27\xeb\x90\x2c\xd2\x4c\xff\x9e\xc3\xbc\x5b\x4b\xad\xf8\xa7\x1a\xa5\xe3\x92\x67\x50\xc6\x40\x31\xd0\x86\x20\x93\x28\x6a\xf8\xdd\xdf\x9c\xcf\xf2\x37\x92\x50\x04\xb8\x91\x93\x82\xc7\x9d\x1e\x00\xba\xbc\x8d\x96\xb2\x97\x92\xc3\x76\x22\x4c\xc3\xa4\xd3\xfb\x34\x6e\xb1\x54\x1e\x50\x15\x8d\x98\xc7\x4d\x4a\xef\x0f\x76\xac\x69\x9c\x0b\xf9\x22\x11\x3f\x4c\x0d\x64\x1e\xb4\xae\x1b\x51\xf3\x64\x6d\x01\x77\x03\xc7\x01\x3d\x06\xd7\x28\xcc\x93\x80\xda\xb4\x0e\xf6\x33\xf1\x1b\x70\xdf\x87\x40\x5b\x60\x6d\x29\xd5\x17\xc4\x45\x6b\xa1\xad\xd4\x37\xb2\xa4\x87\x47\x4f\x15\x42\x57\x14\x87\x28\x14\x7f\xfd\x1b\x86\x66\xf8\xfb\xe5\xc2\x79\x0f\x66\xf8\x32\x02\x6f\x68\x42\xaf\x6b\x46\xd8\xdd\xee\x32\x55\x54\xe9\x9a\x8d\xfd\x3a\x04\x93\x59\xf6\x0d\xf7\x62\x86\xf2\x47\x3f\x76\x3d\x54\x0a\x77\x37\xb3\x94\x66\x2c\x5d\x1b\x1d\xd3\x31\xa0\x36\x08\xef\xcf\xaf\x67\xea\xa1\x61\x32\x96\x01\xb2\xa6\x1d\x00\x86\x87\xdb\xce\xe3\xad\xf1\x0f\x39\x3e\xae\xda\xef\x41\xe7\xa5\xaa\xd8\xaf\x0f\x08\xf6\xe0\x86\x50\x9d\x36\x77\xab\xa6\x1b\xc7\x4b\xe6\x80\xee\x2f\x4a\x1f\xa5\xc9\x3b\x3a\xd7\xa4\xb8\xc9\xb8\x02\xc7\x27\x01\x4c\x7d\xf8\xb8\x0e\xb7\xb4\x0b\x94\x09\x7f\xfd\x2b\x4e\x69\x69\x79\x1a\x3c\xb7\xfc\xc8\xfa\xde\xbd\xfa\x3e\x24\xc0\x1d\x16\x21\x35\xc9\x7d\x82\xb8\xbf\x1b\xbd\xe3\xa3\x36\xfc\x29\xfc\x63\x9c\xa5\x37\xd9\xd1\xbe\x2d\x39\x64\xec\xd6\x23\x12\xb6\xba\x01\x66\x2d\x8d\x94\x8b\xa1\x52\xbc\xbb\x86\x7d\x7f\x38\x6a\x59\xc7\x18\xa9\xca\xb5\xf1\x48\x39\xe6\x8f\x88\x03\x89\x40\xb5\x86\xd5\x3e\xb6\xab\xc9\x11\xd3\xfd\xcf\xdd\xdc\x74\xf2\x8c\x29\xb1\x15\xf1\x16\x8f\x20\xf9\xda\xaf\x33\xf5\x5f\x97\xbd\xe6\xdb\x1b\x9d\xbf\xf9\x5e\xae\x31\xd0\x48\x4b\x47\xb5\xeb\xf9\xbd\xf1\x85\x08\xba\x3b\x0a\x1c\xeb\xca\x3d\x6a\xf9\xe1\x94\x9d\x15\x7e\xf0\x40\x25\xb8\x8d\x17\xf1\xbd\x35\x9a\x19\x50\x6b\x1f\x5d\xe9\xbd\xd2\x6b\x23\xb3\xa3\x3e\xe0\x63\xf6\x09\xc8\x87\xff\x7c\x14\xd1\xf1\x32\x0e\xe4\x86\x5d\xee\xa8\xd5\x3c\xa9\x4f\x4d\xfe\x92\xcf\x47\x0d\x98\x2a\x61\xff\xd6\xae\x69\xcc\x75\xef\xe5\x62\xcf\x38\xd5\x17\x54\x34\x10\xca\x4c\x9a\xb4\xcc\xa4\x19\x6f\x44\x44\x7c\x7d\xfc\x7f\xf7\x57\x7d\xd1\xa2\x50\xb9\xff\xd4\x58\xe5\x66\xc5\xec\x33\xf2\x63\xfa\x29\x6b\x37\xa4\xff\xc3\x77\xc1\xfa\xcc\x6b\x5d\xfb\x5b\x54\xae\x8d\xa1\x34\x06\x5d\xec\x2b\x01\x5c\xcd\xbe\xe3\x4f\x2f\x58\xae\x63\x9e\xa4\x5f\xba\x99\xa7\xd6\x6c\x91\x84\x64\xa6\x58\x77\xc3\x2d\x5b\x09\xbb\xc0\xff\x50\x7e\x0b\x37\xdc\xf8\x13\xf3\x71\x23\xdb\xf5\x67\xb2\x6a\x0c\x4f\x7c\x5e\x43\xd4\xd4\x50\x6c\xd2\x73\x34\x98\x7f\x77\xd2\x99\x94\xb3\xe7\x87\x9f\xed\x87\x64\x44\x95\xb3\xe7\x9b\xd3\x99\x1e\xe8\x1b\xe1\xdf\x38\x54\x1b\xd9\xf7\x63\xb9\x9a\x1c\x32\x53\xeb\xa6\xc7\xb0\xa8\xda\xbc\x1a\xe0\x69\xcc\x9c\x44\x64\x57\x77\x27\xe5\xdf\x9e\x71\x95\xfa\xd2\x5c\xa3\x58\x03\xa5\x1b\xce\xb7\xc7\x9e\x4e\x18\xd3\x29\xcd\xf9\x54\x97\x3d\x06\xf8\xc1\x70\xf4\x5f\x46\x3b\x59\x98\xaf\x2e\x5f\xef\x20\xce\x5c\xa3\x9d\x60\xe7\x7e\x91\x0b\xb1\x5e\xe8\x75\x6e\xa8\xb1\x57\x1c\xfd\x63\x9b\x29\x3f\x40\xfc\x0f\x61\x30\xa6\x9d\xd9\x1d\x26\x1c\x38\xf7\x31\xa0\x9d\x3b\x02\xbc\x61\xff\x62\x65\x8a\x08\xfa\x10\x72\x79\x2e\x23\xce\x24\x4b\xc5\x29\xa7\x61\x41\x22\x72\xa3\xa4\x2e\x0d\xfb\xbf\xeb\x51\xb4\x36\xd4\x16\x51\x0e\x19\x70\x6e\x07\x37\xed\x95\x7c\xf0\x1a\xc1\x6c\x40\x7e\xf8\xa7\x2f\x71\x29\xf2\x58\xc6\x11\xe7\x71\x13\xf6\x59\x35\x58\xbe\x58\x03\x86\x6f\x0b\xb5\x23\x97\x9b\xa9\x7f\xe6\xe5\x28\xaa\x71\x20\x31\xc9\xc3\x4c\x0c\xc7\x91\xef\xd4\x06\x7c\x1b\xcd\x39\x6a\x98\x48\x87\x94\x68\x78\x37\xbc\x69\xed\x4f\x1c\xab\xdc\xd7\x7b\xb3\xd7\xca\xe2\xdd\x66\xb0\xc1\x72\x37\x15\x23\x69\xbd\x2b\xff\xc5\x72\x1e\xe6\x8b\x5b\xcc\xc2\xcd\xe4\xa8\x19\xa2\x1b\x0e\x9e\xa7\x5a\x33\x23\x32\x67\xf4\xd3\xcf\x7e\x97\x39\xd7\x53\x7d\x64\xef\x1a\x85\x9a\xa4\x91\x21\x22\xb9\x66\xdf\xee\xa7\x16\x86\xbb\x8a\x09\x87\xe5\xd9\xe5\x15\xa3\x85\x66\xbb\x10\x1d\x4d\xfd\x9a\x41\x53\x29\xff\x2e\x6e\xb2\x17\x44\xda\x3b\x1f\xb8\xad\x60\x34\x9a\xd9\x22\x90\x22\x14\x6c\xaa\xdb\x69\xc2\xb3\x82\xec\x31\xcf\xcf\x1d\x59\x43\x11\x53\xcc\x08\x18\x27\x6c\x95\x9b\x9e\xac\x81\xd3\xd2\xa1\x1f\x15\x3e\xff\xe1\x3a\xba\x76\x48\xe2\x7c\xdc\x61\x94\x79\x8f\x08\xb8\x17\x19\xb5\xb5\x5e\x3a\x51\x07\x66\x8c\xe4\xfd\x8f\x37\x70\xfe\xf2\x65\x3f\x98\xd3\xc2\x8e\x8d\x41\x12\x32\xee\x09\x6f\x72\xf6\x8c\x71\x5c\xaa\xd9\x0e\xf2\xfe\xf0\x15\xb0\xce\x2a\x39\xc3\x50\x2e\x17\xa9\x4c\x10\xf2\x06\x8e\xd7\x3e\xba\xb6\x6b\xcc\x02\x3b\x36\x99\xd8\x17\xc9\xfe\xd4\xbe\xb3\x99\xb2\x6d\xca\x2c\xfe\x92\x8f\xb7\x59\x72\x4e\x94\x95\xc0\xfb\xfc\xe7\xd3\x40\xcd\x4f\x5f\x71\x83\xe1\xd8\xc4\x68\xbb\x99\xe3\x30\x69\x74\x94\x1e\xd3\xcc\x07\x76\x38\x7d\x3d\x21\x44\x11\xff\x71\x21\x33\x7b\xc0\x35\xc5\xd2\x34\x33\x67\xc0\x52\x7d\xc7\x6d\x61\x1a\x1c\x1b\xee\xbb\xd3\x5d\x91\xc0\xd6\x3f\x31\x48\x93\x34\x54\xc0\xb2\xd1\x0a\x47\x03\x9c\x87\x98\xa9\x6e\xdc\x0c\x73\x3a\xeb\x97\xbe\x52\x2b\x99\xcb\xfc\x89\x2b\x98\xdd\x57\xbf\x2a\xa3\x94\xbc\xdc\xa0\x03\xdb\x79\x54\x84\x0a\x8f\x78\xfd\xeb\x59\xac\x0b\x09\x2c\x19\xef\xfd\xf0\x49\xd8\x24\x38\xf0\xf4\xac\x2b\xf6\x51\x94\x5a\x1d\x0b\x5e\x2e\x63\xaf\x18\x87\xfd\xeb\x77\x7f\xb0\xc5\x1d\x04\xdd\x8c\x8e\x18\xa0\x5a\x7c\xf8\x55\x02\x87\x6f\x0b\xc5\xe9\x1c\xf1\x1f\xef\x5a\xeb\xf1\x5f\x47\x13\x9c\xab\x99\x29\xb3\x7c\x08\x87\x91\x7a\x08\x18\x30\x5b\xc0\x4a\x85\xfb\xb7\x7f\xce\xec\x7c\x70\xcb\x98\x79\x41\x4d\x8a\xac\x92\xe0\x4f\x31\xf7\x42\xd3\x7b\xad\xd0\xa8\x7f\x71\x5d\x83\xe5\x5c\xe3\x23\x07\x4e\xf7\xe8\xdc\xa9\x39\x2d\x2a\xdc\x1a\xa4\x8b\xcc\x8a\x86\x9c\xb0\xff\xc8\x8b\xa0\x38\xe5\xca\x34\x9e\xc4\x8b\x53\x0b\x67\x28\xc1\x5c\xa7\x16\x68\xc9\xbf\x1e\xda\x51\xd3\x80\xfa\xfc\xf0\xca\x0d\xc5\x12\x39\x61\x01\xb7\x95\x81\xe2\xbd\x3f\xba\xe9\x5d\xb4\x25\xfc\x15\x13\x37\xa4\x32\xe1\x30\x15\xdb\x8c\xba\x7f\x4c\x56\x63\xd8\x73\x0d\xd4\xe4\x27\x16\x50\x6f\xd1\xf3\x17\x47\xe1\xf3\x2e\x24\xe5\x34\x8f\x33\x8d\x11\x13\xf3\x7f\x31\xdd\x77\xd5\x6e\x49\x08\x19\xb0\x73\xd5\xe4\x0b\x60\x98\xd4\x31\x0d\xa6\x29\x77\x65\x04\x4c\xa4\xfc\xf8\x7e\x38\x77\x45\xaa\x4b\xcb\x4c\xd6\xad\x5a\xdf\x7b\xa5\xcb\xa4\x60\x18\x3a\x82\x39\xec\x66\x8f\x0b\x7c\xf7\x8f\x07\xb3\x68\x33\x93\x0a\x06\x5c\x64\xf8\x74\x05\x1b\xc8\xcf\xcd\xac\x4b\x68\xa7\x53\x22\x5e\x22\x76\x47\x68\x8b\x3f\xb9\x1d\xde\xea\xf8\xc1\x11\x6c\x0f\x31\x9b\x28\xf7\x33\x43\xd1\x0c\x9e\x73\x22\xe3\xe4\x94\xbf\x38\x28\xe7\x18\x88\x62\x89\x8c\x4f\xde\x10\xf4\xf8\xe5\x2b\x39\x8c\xec\x8c\xcc\xd1\xfd\xc4\x51\x96\x67\x98\x9b\x32\x73\x8a\x1a\x17\xd0\xe5\x23\xe0\xed\x72\xfc\xd3\x09\xc8\xff\x7b\xfe\xca\x87\x19\x01\x17\x86\x30\x0c\xc7\x68\x4d\x6c\xec\x54\x10\x96\xe9\xa0\x02\xb7\x0c\xe7\x87\xbf\x80\x63\xd0\x5f\xbe\xc5\x10\x2c\x2e\x0b\x78\x2a\xde\x2d\x63\x92\x9b\x4b\xdf\xb9\xbf\x3f\xff\x7e\x7e\xf0\xdf\x77\x53\xf6\x9a\x39\x7d\x41\x46\x25\xe8\x3d\x3f\xc9\xcd\xd7\x72\x40\x7a\x63\xc1\x49\xfa\x37\xb9\xca\xe4\x46\x83\x05\xac\x08\x91\x3e\x1f\xa6\xb8\x65\x36\x64\xc0\x2e\xff\x9e\xdf\x19\xa7\x91\x07\x2d\x66\x63\x30\x8f\xa9\x4d\x8a\xee\x11\x17\x0a\x98\x78\xd0\x54\xd5\x20\xc2\x84\xfd\x27\xdb\xfa\xa0\xf6\x0a\xf5\xc9\xdf\xa7\x80\xe0\x37\x21\x15\x90\x22\xf2\xb5\xf2\xb9\x6c\x61\x20\x97\xff\xa7\x2b\x21\x96\x05\xf5\x49\x91\x28\x58\xcc\xbf\x65\xba\x05\x9e\xd2\xc9\x5f\xdc\xb3\x59\xaa\x91\xdb\x42\xea\xf9\xbf\x73\x3b\x05\xc7\x7e\xcd\x61\xd9\x46\x05\xb1\x35\xc5\x07\x2a\x1b\xd1\x1a\x57\xf8\xff\x63\x69\xf1\x0b\x92\x77\xc9\x2f\x25\x6d\x8b\xd3\x0e\x0f\x25\x0c\x1d\xe4\xcb\x44\x85\x31\x32\x16\x99\xf7\x8d\xf2\x73\x2f\x89\x3d\x85\xd3\xff\x3c\x0a\xd5\x7b\xf5\x04\xed\x14\x3e\xee\x50\x68\x23\x85\xe6\x76\x9c\xab\x2e\x3e\x3a\x16\x24\x3f\xc8\xcf\x55\x6b\xc2\xf4\x73\x1e\x51\x9d\x05\x65\x79\xf2\x4c\x0e\xa9\xd3\x23\xcb\x96\x26\xe2\xe7\xe0\x1a\x23\xe2\xbd\x7d\xe8\xb6\xac\x16\xb2\x20\x0c\x4d\xfb\xca\x4a\x5e\x5c\x9e\x8e\xcb\xf8\x15\x22\xa4\xbe\x28\x08\x9d\x92\xfe\xc8\xcb\x08\x7b\x5a\xc3\x98\x78\x51\x79\xb4\x40\x4f\x5f\xfa\x82\x4c\xfe\x2e\x07\x4a\x13\x9d\xc8\x00\xd7\x6e\xd5\x92\xac\x78\xdb\x5d\x25\x43\xb8\x7c\xe5\x9a\x4f\xcd\x30\x0a\x53\xfc\xbc\xc4\xe7\x2a\xb5\x9f\xfe\xc5\x1c\x83\xb2\xec\xab\x04\x20\x46\xf6\x61\x18\x1e\xd1\x94\x21\x66\x87\x5d\x9e\x69\xab\xaa\xf5\x49\x10\x2b\x1c\x1c\xc9\xff\xc4\x03\xd4\x44\xc6\x09\x18\x1e\x8b\x27\x46\xe7\xf0\xff\xb8\x2c\x51\xcd\xf5\xb2\x64\x65\x6a\xfe\xb3\xb3\x49\x9b\xae\xc4\xbc\xa6\x48\x3a\x35\x94\xe4\x24\x85\x6d\xa5\x9b\xc1\x33\x98\x15\x36\xc9\x2c\x9a\x58\x71\x63\x78\x0b\x66\x80\x3a\x3b\x09\x46\x0d\x18\x05\x01\x7e\x27\xfc\xe4\xb0\x8d\xd6\xb4\x7a\x08\xf8\xcc\x91\x9f\x66\x5f\x73\x39\x63\xd0\x1a\xb2\xed\xc8\xd6\xa7\x98\xda\x5e\x95\xc8\xa0\x78\x28\xb9\xc5\x92\x5d\xec\x8f\xdf\xa5\x78\x9f\x7a\xd8\x49\x96\x96\xa7\xad\xa3\xb9\xe6\x7f\xce\xe8\xc2\x6a\x0b\x1a\x96\xcb\x85\x27\x86\x7e\xd2\x09\x3b\x6c\x6e\x12\xd6\xc3\x19\xb1\x4d\x21\x1a\xea\x66\x27\xd7\x8d\xd5\xd3\xd5\xc9\xca\x1b\x87\xb0\x97\x14\x05\x1c\xb5\xf1\xc1\xb6\x07\x74\x7a\x37\x3f\x1a\x6c\xf0\xf5\xe3\x2b\xee\x7e\x7c\x59\xcb\x69\xde\x0a\x03\x71\xa3\x4c\x4f\x1e\x55\xfa\xce\x0f\x43\xb1\x9a\x82\x75\xc4\xe3\x52\xd3\xd5\xbb\xd1\xfc\xe0\xbf\x7d\xfc\x50\xe5\xb1\x7d\x04\x52\x66\x08\xfb\x86\xad\x19\x26\xdd\x6c\xf3\xb3\xfc\x13\x1b\x09\x87\xe7\x1d\x06\x15\x0e\xff\xef\x9c\xc9\xa3\xf3\x2e\xec\x57\xef\x4a\x36\x7b\x5c\xac\x8e\x09\x54\xc0\x48\x55\x54\x7e\x85\xd6\xb9\x2a\x48\x93\xd0\xf4\xed\x5c\xca\x3a\x9b\xea\x7e\x80\xc0\x44\x91\x16\x11\xc1\xdc\x20\x92\x13\x99\x2e\x71\xb6\xe6\xfb\x52\x32\x33\xd0\x8f\x3f\xcd\x3e\xbd\x41\x38\xf9\xc8\xb7\xaa\xd0\xaf\x15\x03\x6e\xe3\x39\x67\x1d\x15\x3c\xa6\x1f\xd0\xd6\xbd\xef\x80\xc2\xbd\x48\xf5\x32\x98\xc8\x20\x23\x18\x12\x36\x13\x14\xa7\x3b\xc9\xb6\x52\x44\xb8\xd1\xc8\x25\xdc\xb4\xff\x64\x9e\xb1\x8c\xf3\x05\x9c\x9b\xdc\xcd\xe1\xcb\x4a\x70\x43\x4e\x0e\x61\x23\x08\x72\x47\x42\x2a\xb9\x80\x7d\x57\x92\x58\xd7\x12\x7b\x69\xea\x60\x78\x8b\x1a\xc4\x25\x67\x22\x52\x52\x50\xf8\xe8\x16\xf7\xca\x8b\x8e\x37\xb4\xff\x74\x06\x4f\xcf\xd4\x47\xc6\x48\xd1\x0b\xcb\x2d\x5b\xe7\xc1\x4b\xb7\xdc\x84\x51\x06\x87\x09\xeb\x93\xc0\xb2\xd2\x4a\xfa\x1d\xea\x2d\x8d\x9c\xeb\xb3\x34\x87\x38\x9f\x9d\x66\xcd\xdd\x97\xbb\x13\x27\x61\xff\xdf\xbe\x38\xe4\xca\xda\x7c\x53\xbe\x7b\x88\x45\x01\xea\x83\x32\x51\xdf\x91\xaa\x2e\xa1\xc2\x37\x58\x88\x93\x63\x70\x49\xea\x5a\x8c\x9b\x9a\xe8\xba\xb2\x87\x70\x18\x1a\x67\x5e\xfb\x9c\x9a\x3f\x86\xa0\x35\xad\xca\xfd\xd3\x07\xf2\xc2\x7e\xb5\xbb\x32\xc5\xb5\x0c\xa3\x10\xfe\x65\xe1\xb9\xd7\xcd\x64\xb7\x37\x4d\x70\x8a\xbb\xc4\xeb\x2a\xc9\xed\xf3\x1e\x0c\xe1\x44\x4a\xc5\x1e\x41\xd2\x86\xef\xde\x70\x7c\x08\xbd\xc4\x05\x06\x87\xe4\x80\x5e\x81\x6f\xc0\x04\xca\xcf\x92\x71\x81\xb7\xd3\xae\xe7\xc4\x3d\x1d\xf7\x07\xae\x32\xee\xab\x17\x63\x38\x24\x16\x69\x43\xb4\xfd\xfb\x02\x05\x87\x12\x8b\xcf\xe5\xbe\xfd\x72\xc9\x1b\x25\xbf\xd6\xbc\xae\xb3\xa4\x71\x5f\xcb\xb4\x42\xee\xae\x6c\x7b\x2e\x55\xcd\x6e\xa0\x40\x58\x7e\xee\x1d\x73\x4e\x83\x3c\xd1\x16\xd3\xc9\x6c\xc4\xe7\x03\x0b\x29\xa7\x75\x9a\xf1\xad\x27\x2c\x95\x44\x1b\x2c\x9f\x42\x6a\xe6\x21\xd8\x4c\x30\x1f\x89\x73\xdd\x1a\xfe\xf6\xe8\x4b\x6d\x3f\x69\xdb\xbd\xcb\x3a\x69\x1b\x55\x18\xb8\x4e\x28\xbd\x42\xf3\xfa\x0f\x2f\x23\x53\xa4\x72\xd4\xf1\xde\xeb\x24\xdf\x7a\xe8\x39\x6f\x39\xb7\x65\x25\x77\x80\xd8\x1a\xca\xe0\x39\xb2\x49\x12\xee\x97\x9e\x70\x3d\xd9\x3f\x5f\x34\x23\xd1\xaa\x86\xa5\xcf\x34\x5e\x4e\x64\x55\xe5\xab\x18\xe1\x37\x71\x66\x9c\x12\x5b\xf9\x29\x9c\xee\x27\xe7\xd5\x33\x56\xc7\x7b\x4f\xc2\x14\x34\x4c\xdb\x03\x55\x2e\xc7\x41\xee\xc0\x52\xca\xcb\x95\xf0\xdc\x94\xe3\x94\xc9\xae\xd5\xb8\xec\x20\x75\xe4\xd9\x88\xcc\xdc\x23\x4a\xba\x11\x5c\x99\x3d\x06\x25\x94\x9c\x92\xce\xd9\xa8\xac\xb8\x9f\x1f\x5b\xcf\xef\x1f\x79\xff\x65\x28\xda\xc9\x1f\x34\x7b\xdc\x14\x06\x93\xe6\xd3\xfc\x28\xaf\x45\xdd\xdf\x0f\x55\xf8\x69\x0c\xdc\xc8\x79\xa1\xb9\x1a\x22\x98\x91\x9f\x86\x94\x5b\x3a\x58\x99\x8d\x10\x48\xcb\x4f\x4c\x66\x79\xdc\x14\xd3\x89\xa0\xd6\x7a\x56\x7a\x6c\xcc\x11\x31\x41\xdd\xf5\x82\x94\x63\x3a\xe6\x15\x98\x8f\xf1\x18\xdc\x63\x22\xf3\x97\x2f\x2b\x93\x17\xaa\x66\x99\x47\xec\xed\x4d\xc1\x28\xfd\x1a\x93\x6d\xcb\xf7\x70\xba\x79\x57\xd6\xeb\x23\xfc\xc4\xae\x46\xc3\x5e\x4e\x12\xdd\x7b\x53\xde\x64\x00\xc3\x51\x01\xce\xb2\xda\x97\xbc\x13\x55\x78\x3d\xc5\x0d\x66\x80\x67\x8e\x0f\x6d\xa6\xdf\x55\xfd\x22\xd1\x93\xf5\x75\x80\xa3\x78\xfb\x51\x66\x20\xd5\x2b\xb7\x11\x02\xf1\x7f\x9f\x53\x28\x18\x43\x4f\x2a\xc7\x97\x23\x08\x19\xc1\x6a\x4f\x61\x7f\x3d\x3f\xd8\x65\xa9\xad\xb5\xd0\xe0\x42\x40\xa5\x7c\x13\xba\x4b\xa8\x23\x18\xad\x68\x44\xac\x8b\xd6\x00\xc7\xfb\xfd\x08\x76\xe7\xdf\xe3\x82\x1d\x94\xac\x5d\xad\xc6\xc4\x3f\x3a\x3d\x66\xd9\x43\x91\x13\x02\x47\xa8\x5f\x1f\x19\x2f\x70\xd9\x50\x2e\x91\x13\x42\xa2\xd4\xb3\xec\x48\x34\xcb\x34\x8f\x01\xf5\xeb\x2a\x0b\x6d\xf0\x0d\x64\x13\x80\x3b\x93\xaf\x81\x49\x0b\x91\x4d\x2f\x48\xc4\x4f\xcf\x35\x9a\x01\xf3\x2f\x1f\x8e\xf4\x0c\xf0\xa1\xe3\x0d\x4d\xfc\xef\xec\x37\x0d\xb4\x37\xa6\xbd\x18\xdf\x4e\xe9\x56\x45\xd0\xba\xcd\x02\x97\x32\xd1\xf9\xe4\xb1\xa6\xdc\x1a\xa8\xf8\x43\xfd\x3a\x63\xb1\x05\x1a\x21\xeb\x0e\xdc\x9a\x66\xd4\x7f\xb8\xd9\xb3\xf5\xa6\xd8\x4a\xc9\x4f\x5f\x20\x86\x4d\x62\x0b\xef\x68\x4b\x9b\x37\xfe\x46\x3d\x30\x36\x5e\xe3\x85\x5e\xe3\x49\xbf\x14\x46\xa3\xa0\x56\xf0\xe5\x16\x86\x39\x00\x77\xe9\x7e\xc7\x28\x9b\xc5\xe9\x9b\x33\xc6\xf3\x53\xc3\xd8\x2b\xd6\x3b\x75\x8c\xf2\xda\x56\xd1\xa7\xaf\x48\x18\x61\x7b\x84\xeb\xa6\xed\xf4\xf1\xf8\x10\x61\xb5\x39\x4d\xc7\xc6\x97\xbd\x32\x39\x58\xa7\x3a\xfb\xb2\xc7\x4e\x4f\x54\x3d\x50\x6e\x86\x44\xa7\x91\x1f\xbf\x6c\x9a\x18\xb3\xcc\xbe\x71\x8a\xc3\xfd\x8f\x6e\x17\x1a\x01\x2f\x4e\x17\xb2\x94\x05\x46\x06\x37\x00\xf8\xd0\xb4\xc0\xa3\x2e\x45\xa8\x96\xd9\x5b\x5b\x68\xe3\x33\x13\xe6\x64\xd3\xf4\xe3\xf7\x30\x5c\x96\xb2\x9e\x66\xca\x6d\xe1\xd0\xa9\x37\x1f\xa5\x72\xa5\xbb\xd8\x71\xe6\xdf\xb9\x64\x8b\x7a\x46\x02\x40\x08\xbc\x33\x16\xc2\xc3\xf9\xca\x08\x60\x7f\x4a\x7e\x2b\x61\xb4\x5c\xab\x69\x1b\x51\x59\x20\xa6\x88\x40\x05\x06\xe6\xb3\x71\x1b\x2d\x24\x9d\x82\xa2\xd8\x1f\x38\x23\xd1\x22\x49\x3f\xed\x15\x0b\xb5\x7a\x73\x72\x6a\x05\x8d\xf2\x9f\xef\x6e\x3f\x77\xec\x7a\xb8\x36\x62\x00\xf9\x95\xb0\xc9\x21\x65\xab\x06\x12\x6f\xad\x6b\x70\x09\x60\xd3\x8f\xb8\xd0\x78\x3f\xd3\x09\x24\x19\xb6\xd3\x69\x5b\x1c\x8f\x2a\xbf\x4a\xaf\x64\x5c\x2e\x5e\xee\x9f\x71\x8a\x9d\x95\x31\x5c\xf0\xdd\x34\xd3\xbf\x7b\x84\x2d\xdf\xbc\x74\x10\xaf\x86\x9f\x6f\x10\x8e\xdd\xfb\x51\x07\x4a\xe6\xfb\xaf\xb2\x5e\xad\xc0\xbc\x7f\xe2\x29\xa6\x61\x81\xab\x76\x21\xbc\x60\x26\x67\x2f\xca\xcf\x11\xaf\xe0\x74\x8d\x25\x7c\x38\x5c\x79\xa3\x46\x5d\xc0\xb1\x7b\x03\x03\x64\x49\x6e\x8a\x7f\x5e\x19\x14\xc7\x63\x51\x05\x87\x54\x9f\xfe\x2f\x36\x05\x78\x86\xee\x40\x64\x91\x9c\xd7\x77\x5b\xc7\xf3\xbb\x73\xc7\x14\xb0\x62\x9b\xcd\xeb\xbc\x84\xa7\x3c\x9a\x91\xeb\x76\xd3\x03\x4c\xbd\x6d\xd4\x54\x9f\xd0\xfc\x29\x5b\x9e\xf0\x07\x2b\xc4\x7b\x6a\x44\x76\x8e\xf2\x52\xa5\xf7\x6c\xca\x0c\xc3\x60\xd3\xbe\xef\x64\x13\xe1\x70\x66\xeb\x1a\xec\xfc\x3a\x46\xb1\xd1\x7c\xde\x40\xd4\xd2\xd4\xd5\x3f\x2a\xb7\xcb\x97\x8d\xfc\x89\x73\xf9\xbe\x41\x76\x9e\x42\x2a\x18\x29\x02\x22\x59\xf7\x4d\xa3\x2e\x62\x5c\xd7\xc5\x43\x18\xe4\x58\xda\xe6\xd5\x8b\xce\xbd\xae\x8d\x93\xc3\x4c\x69\x71\xc3\xfb\xef\x4c\xf0\xfa\x86\xcb\x3d\x86\x37\xe8\x01\x7d\xd4\xd5\x7b\xf5\x21\x8d\xd8\x02\xc4\x5d\x88\x74\xb4\x2f\x0c\x26\xcc\x46\xf2\xa3\x18\xb5\xf7\x7a\xcd\xdd\x01\x9f\x38\x72\xc9\xda\xf5\x31\xaa\x61\xf1\xfe\x72\xd2\x83\xdc\xd8\x4b\xbf\xc6\xa0\xf7\x03\x96\x3f\x15\xba\x59\xe4\xb9\x2d\x1a\x25\xd4\xd6\x34\x82\x06\x9c\x69\xe6\xe8\x26\xdb\xc8\x15\x40\xe3\x38\xff\xe2\x68\x59\xc7\xcd\x50\x1f\x45\x68\x32\x3a\x42\x99\xcb\xed\x30\x57\x4e\x54\xfb\xc1\xf5\xe3\x38\x1e\xb7\x8b\x90\x2f\xe0\x7b\x73\x22\x2e\x05\xd8\x9d\x1e\xec\xde\xfe\xe6\xd1\x17\x7c\x4a\x7e\xb3\xe0\x4f\xa0\x7b\xd5\xc4\xda\x05\x8c\x6f\xb4\x50\xad\xbc\xa6\xbf\xd1\x29\xbe\xb0\x83\xea\x07\x08\xa2\x79\xf3\x0c\xa6\x73\x5d\x6e\x13\x3b\x5c\xfc\x7d\x4d\x3d\xcb\xfc\xc4\x72\xec\xe3\xe4\x23\x57\xb5\x26\xec\xc7\xe2\xe1\xe7\xb9\x98\xfc\x97\x5f\x12\x2e\xef\x15\x41\x3b\xca\xd0\x5d\xb2\xc6\xdb\xd9\xc6\xe6\x3d\x77\x81\xe5\xff\xc9\x0d\xb5\x7c\x0f\x48\x91\xde\xfd\x58\x8f\x7c\x29\xfc\x8f\x2c\xe3\xbf\x9c\x13\x17\x47\xfd\x38\x82\xbb\x6a\x5e\xc0\xa5\x5d\xf6\x44\xc7\x37\x8f\xef\xb1\x9b\xff\x1e\x9a\xf3\x07\xff\xe4\xf1\x9e\x80\xa3\x95\x8e\xb2\x37\x4a\x16\xd6\x23\x19\x3c\xf6\x34\xd0\x7c\x75\xd5\x81\xcc\xe6\x03\x44\x10\xea\x7e\xca\xed\x28\x62\x76\xba\xb6\xa3\x01\xf9\x46\xba\xeb\xfb\x8f\xde\x60\x8f\x6c\xb3\xd8\xb2\xf2\x6f\x8e\x7c\x12\x24\xf6\x9b\x13\x5c\x9a\xc1\x8b\x15\x7c\x4a\x5f\x3c\xb1\x47\x86\xf8\x1f\x9f\xec\xba\x52\x26\x56\x9b\xde\x8b\xfd\x5c\x13\x2c\x0e\xbd\x3d\x56\x30\x76\x59\xce\xe7\x46\xfe\xfe\x8b\x2f\x4c\x01\xf9\x70\x7a\xc3\xb4\x94\xd1\x3e\xaf\x0a\x6b\x7c\x79\x1e\xf4\x69\x48\xa0\xd9\x92\xb6\xca\xda\x0d\xd9\xfe\xeb\xe9\xac\xf2\xf6\x8c\xe9\xc9\x4d\xdf\x55\xaa\x0e\x48\x25\x5e\x01\x53\x5d\xb5\xc1\x16\xff\x13\x57\xb5\xcc\xc3\x9c\xaf\x60\xbe\x43\xae\x95\xd5\x48\x98\x98\x88\x44\x3c\xa8\xde\x9c\x52\xfe\xf8\x11\xd2\xa5\x58\xb1\xc2\x97\xf9\x5a\x8b\x85\x39\x3d\x15\x7f\x05\x8c\x5b\x66\xf6\xd6\x60\x0e\xff\xfe\xff\x58\x86\xad\x1b\xd5\x13\x8e\x84\x58\x3b\x48\x52\x44\x11\xbe\x80\x53\x87\x34\xec\x7f\xd6\x3b\x23\x3d\xd2\xcd\x2c\x8a\x7d\x23\xef\x83\xd7\x28\x57\x30\xa6\x30\xdc\x0d\x90\x73\xee\x07\x32\xb0\x7f\x5c\xe6\x6f\x42\x56\xfe\xa7\xd2\xca\xb7\x01\x92\x15\x4f\xb0\x08\xd7\x3f\x8e\x5a\xe8\xd2\xaf\x78\xee\x7f\xd6\xfa\x51\x00\x9e\xb1\x1e\x26\x6f\xb3\x75\xe5\xb7\xb3\xb4\x4e\xfe\x48\xc5\x21\x12\x95\x80\xf8\x7f\xb1\xc9\xaf\x67\xb4\x40\x01\x07\x43\x8f\x95\x3f\xf3\xee\xd8\x11\xbf\x34\xf2\x0f\x7e\xc7\x97\x94\xc3\x92\x93\xfd\x8a\xf3\xd6\x68\xfa\x1d\x69\x77\xa5\x0f\x66\xf3\xb5\xdb\x1d\x2a\xfe\x5f\x1c\x6c\x2e\x87\xd9\x77\xfe\xda\xc8\xd6\x55\xb9\xf7\x1b\x0a\xe1\x6d\xb5\x6f\xc0\x54\xd5\x05\xa1\x8d\xec\x74\x7f\x79\x14\xf9\xde\x5d\x94\xde\x2f\xad\x99\xa1\xc8\x76\xc9\x76\xa9\x9e\x8c\xa7\xd0\x0d\x01\x27\x94\xdb\x2e\xfe\x27\xee\x64\xc7\xdc\x41\xe5\x53\xab\x44\x88\xb2\x1c\x7a\xb2\x64\xb8\xfa\x76\x01\x57\x90\x6d\xa1\x72\xb6\x03\xfd\x5b\xcb\xc4\x8a\x2f\xc6\xbe\xbb\x48\xe5\x69\x2a\x0e\x88\xb5\xa0\x01\x93\x03\x74\x21\xb3\x1f\xd1\xfb\x1f\x1c\x40\x79\x12\x06\xa9\x7c\xd5\x98\xb6\x39\xef\xb5\x7a\xfe\xda\xf7\x03\xf9\xbb\xcc\x33\xec\x3f\xbc\x09\x9f\x49\x4a\x7b\xcf\x14\x39\x11\x37\x5d\x1a\x0c\x1b\xa9\xfa\x38\x86\x4d\x9d\x62\x1e\xb9\x76\x41\xfe\x3c\x4c\xb7\x0d\x7f\x71\x96\xe7\xe6\x5d\x76\xa2\x68\xb1\x60\x23\xfa\x73\x84\x33\x2d\x7f\x4a\x98\x61\x76\xd9\xd5\xe9\x24\x70\xfe\xd3\xfb\x8e\x46\x14\xfe\xa8\x58\xa0\x32\xef\x0f\x82\xa1\x86\xf7\xb1\x9a\x7b\x9f\x2c\xc1\x0c\x45\x31\x0c\x57\xc7\x10\xdc\xbf\xdc\x54\x46\x97\x3e\x54\xe4\xd3\x20\xb3\xc9\x33\x2d\xff\xfe\x6d\x6d\xb3\xd4\xc4\x47\x9b\x07\x46\x8e\xb8\x2b\x5a\xa8\x43\x14\x3c\x66\xfc\xc1\x8e\x0d\xa2\xf0\xbb\xca\xd5\xac\x1c\xab\x9c\xeb\x83\xb6\x83\x4d\x14\x4e\x61\xa2\x65\xa8\x78\xdb\x3f\xcc\xa7\x73\xd5\x79\x31\x76\x9d\xcd\xf4\x65\x9c\xbe\x25\x97\xf6\x3b\xdc\xbb\xee\xf2\x51\x53\x61\x21\xb9\xc6\xfb\xee\x34\x38\x61\x08\xc4\x75\x54\xdc\xa9\x2c\x20\xaf\xff\x83\xc5\x39\xc9\x1e\x46\x1c\x91\xd4\xc3\x7a\xc0\x03\x83\xc5\xe6\xdb\xaa\xa9\xad\x7e\xd8\xcf\x4d\x55\x8a\xfb\x35\x88\x6c\xf9\xf4\x45\x79\x60\x4b\xc1\x0f\xa9\xd1\xf1\x6b\x98\x3a\xde\x1f\x1d\x18\x35\x3a\xc3\xf7\x9d\x5b\x9e\xf2\x29\xe9\xc6\xd9\x06\xa6\xd4\x21\xc8\x85\x48\xd7\x23\x1d\xbc\x8a\xa9\x1a\xdf\x94\x75\x76\xb7\xee\x15\x75\xd8\x17\xc0\x6e\x26\xfc\xe1\xfd\xe3\xe4\x22\xff\x94\xa2\x26\x1b\xe7\x00\xda\x9c\x0f\xd3\x90\xd5\x3e\x6d\xc1\x75\xae\xc7\xa6\x43\x25\xd8\xfc\x85\xe2\x60\xe4\x79\x6f\x73\xd4\x29\x0e\x86\xd9\xe6\xb8\x8e\xce\x4e\x3d\x76\x33\xc1\xf0\xfc\x27\x07\x97\xa0\x62\x1c\xff\xd5\xa6\x03\x9c\x6a\xba\xfa\xae\xd9\xba\xcb\x6c\x53\x98\x3a\x2e\xd3\xc7\x07\x3b\xb5\x74\x11\x31\xf2\xeb\x61\x93\x52\xe6\x69\xb6\xb9\x98\x7d\xd0\xb6\x36\x76\xae\x8a\x8a\x9a\xb8\xff\xcf\xef\x81\x79\xf9\xa5\x8d\x80\x36\xef\xd7\x44\x9b\x0e\xf4\x56\xe1\xf3\x9b\xb3\xce\x1f\x91\x84\x6b\x20\xeb\x35\xf3\x30\x1c\x52\xfb\x30\xda\x4a\x45\xa7\xe2\xd9\x45\xb5\x78\xdb\xdd\x38\xa8\xb6\xe1\x3a\xec\xf8\xa3\x6b\xb9\x47\x68\x29\x84\xc1\x2b\x94\x9b\x8a\xda\x0e\x07\x38\x14\x13\x54\xbc\xf7\x5c\xfe\xb8\x43\xa2\x2c\x42\x22\xb7\xc4\xb2\xae\xf3\x7e\xe0\x58\xa5\x1c\x75\x4a\xc4\xee\x3c\xee\x19\xd9\x7e\x03\xee\x9f\xce\x67\x1b\xc5\x75\xc5\xbd\xfc\x1e\xb0\x26\xee\x6f\x4c\xcb\x3b\xf7\x9f\xbd\x7c\x8a\x71\x49\xb8\x0e\x42\x34\x5b\x4b\x79\x9d\x66\x30\x4b\x9b\x07\x37\x08\x55\x3f\xff\x30\x6d\x85\xbf\xfa\xc2\x26\xe0\x8b\x7d\x4d\xe9\x7f\x7b\x97\x34\x65\xe3\x45\x7a\x5a\xf8\x6b\x35\xae\xb5\x0d\x02\xfb\xc2\x38\x62\x14\x60\x95\xe4\xba\x9c\x76\xaf\x8c\x91\xcb\xec\x62\x2d\xa1\x02\xc3\x61\x3c\x58\x1e\xd5\xc1\xf4\xf4\xa5\xa0\xd1\xbb\xe5\x53\xbe\x1d\xc5\xe1\x7f\x38\x42\x39\xf6\x2b\x62\xb6\xeb\xb5\xb6\xe8\x46\xf8\x91\x5a\x91\xaa\x8d\xc4\xd9\xad\xf9\x5b\x27\x36\x2f\x25\xcf\x18\x04\x19\x5c\x7e\x92\x8a\x73\xbc\xc2\x6f\x0a\xb9\x07\xd2\x69\xe9\x3b\x18\x1e\xa3\x34\x03\x64\x0d\xca\x53\xbd\x4d\xab\xae\x61\xdb\xff\xc5\xba\x6b\xfd\xa2\xb4\x64\x7d\x1a\x86\xcf\x70\xd0\x4e\xf3\x3c\x0d\xb4\x4f\x80\x99\xfa\x95\xcc\xd7\x2c\x35\xb8\xe9\x07\x77\xa6\x2f\x79\x36\x9e\xcb\x3d\xb9\x80\x43\x00\xcf\x81\x79\x5d\xa5\xb3\x1e\x53\xfc\xe0\xb4\x8c\x76\xab\x39\x43\xe9\x79\xe7\x96\x02\x6c\x1e\x45\xd8\x75\x81\xd3\x25\x88\x21\xd6\x73\xda\xdb\x2a\x96\xc8\xed\x08\x47\xdc\x5d\x7d\xa8\xba\x2d\x54\x1f\x67\x99\x21\x4f\x89\x9a\x4f\x72\x3b\xad\x98\x2a\x94\xe0\xd0\x9d\xa4\x18\xdc\x66\x5f\xf9\x87\x4d\x7f\xfb\x04\x3a\x1a\x20\x15\xfa\xb5\xd0\xc0\x4b\x44\x19\xfd\x77\xce\x58\x4d\x75\x35\x57\xd7\x6c\x4a\x31\x1b\xb4\xd1\x09\x92\x8f\x41\xaa\xc1\xcb\x02\xd7\x1c\x99\xf2\x70\xaa\xde\xd9\xdf\x7b\xd6\xf3\x04\x31\xe5\x1e\x6a\xe9\x36\x30\xcf\x9d\xf0\x6c\x5e\x53\x89\x34\xd5\xfd\xce\xf5\xc3\x40\xdf\x3c\x77\x66\xc1\x2a\x67\x29\xba\x99\x21\x4d\x55\x4b\x50\x25\xcf\x6d\x2d\xc6\xe8\x8f\x4e\x6d\x91\x57\xff\x8c\xa8\xea\x50\x16\x01\x81\x28\x10\xf0\x92\x26\xfb\x27\x52\xaa\xaa\x05\x7d\xbf\x70\x48\xf8\xca\x42\xdb\x2f\x50\x35\xbd\x5d\x57\x38\x0e\xf4\x4e\x86\x97\xd8\xb4\xd2\xe8\x59\xe8\xad\x21\x8c\x1e\x7c\xde\x95\xcd\x91\xb4\xc5\x9e\x77\xcb\xbf\x24\x26\x5c\xab\xc7\xbe\xcf\xdf\x7b\xe3\x0c\xcb\x7c\xda\x40\x69\x7b\xaa\x77\x5a\xe2\xe9\xa0\xa8\x49\xda\x79\xc2\x5f\x00\x42\x32\xc2\x55\x13\xd8\xf2\xad\x9b\x71\x16\xac\xec\xbf\xd9\xde\x8a\xcc\xec\xb2\x92\x00\x49\x92\xb3\x77\xaf\xe4\x15\xcb\x0b\x5b\x2d\x6c\x2a\xf7\x18\xc6\x21\x5b\xb0\x9e\x63\xb5\xcf\x9f\x44\x1a\xc3\x29\xb2\xab\xd4\x48\x91\xf6\xa6\x91\xbf\x38\xaa\xe1\xb6\xae\x25\x26\x7b\x59\x30\x79\x08\x04\x27\x2f\xe5\xa7\x26\x6b\x9e\xe0\x14\xa9\xcb\x8e\xe1\x63\x48\x1c\xa7\xde\xf8\xd8\x69\x3a\x5c\x7d\x2e\x59\xd3\xa6\x75\x97\xaf\x72\x71\x50\xac\xf8\x33\x28\x93\xb4\xe5\xab\x45\x8b\xe2\x5e\x2b\x1e\x6b\x91\x76\x60\xc4\xf5\x46\x6b\xab\x29\x73\xd3\x89\xcc\x1c\x5a\xf4\xda\x49\xa5\x1f\x8f\xb4\x1c\xa1\x07\x89\x9b\xf4\xb8\x63\xe3\x48\xf8\x1f\x54\x77\x2f\xcb\x7b\x64\x8b\xca\xaa\x77\x71\xef\x69\xa6\x85\x24\x2a\x77\x2b\x0a\x34\xfb\x73\x8d\x8e\x79\xfa\x7f\x75\x05\xa3\xc8\x89\xa4\x33\xb1\xa9\xee\x39\x26\xce\xb4\x6c\x30\xaf\x7f\x5e\x9f\x12\x07\x2d\x1c\x2d\x90\x3b\xf7\x0a\x87\xe3\x3d\x1c\x4d\x45\x70\x7f\xee\x4d\x18\xed\x5a\x53\xb6\x95\xb4\x16\x2d\x4f\x39\xde\xf6\x21\x4a\xa6\xc8\xc6\x32\x8e\xc4\x1c\x94\x4a\xce\xf5\xe1\x54\x64\xca\x12\x9a\x9c\x3a\x8d\xbf\xcb\x71\x4e\xbc\xcd\xcd\x40\xcf\xe6\x68\xc8\xb6\xbb\x9a\xfc\x59\x4f\x73\x6b\x3e\x92\x83\x8c\xd0\x93\x84\xf9\xed\x94\x55\x03\x7c\xe9\x8c\x90\xd0\x33\xae\xc2\xf5\x10\x37\x2e\x56\x4d\xe1\x57\x84\x94\xec\xae\x8b\x59\xed\xbb\x93\xd6\x18\x3c\xe6\x66\x7f\x72\x41\x8b\xdf\xf5\x69\x43\x6e\x73\x97\x46\xe9\xf9\xef\x70\xff\x9d\xac\x53\x61\x6b\x23\x4c\x47\xeb\x04\x52\x62\x20\x69\x8f\x75\x47\x14\xc2\xf4\x35\xc1\x60\x97\xf0\xe7\xbc\x2c\xf6\xd2\x39\x04\x32\xf7\xad\xef\x18\xe5\x97\x6c\x24\xb3\xf8\x19\x42\x3d\x45\xca\x20\xe5\xed\xac\x57\x8d\xc6\xfc\x24\x50\x07\x77\x8f\x97\xab\x6f\x98\x6d\x61\xa1\xef\x25\xa9\xb5\x67\xc3\xb6\xa5\x22\x83\xfa\xdf\xba\x4a\x46\xe0\xcf\x6c\xfe\xb8\x19\x5f\x69\x0e\x15\x74\x9e\xa9\xac\x04\x7e\x94\xb3\x69\x7b\xa7\xd6\x20\xf2\x05\x46\x67\xbb\x0a\x31\x1a\xe1\xcf\xf9\x58\xb4\xd2\xd9\xbb\xb9\x9e\x98\x4e\xa7\x9d\x79\x54\x64\x6c\x8c\x5f\xb7\x24\x0b\xa8\xd3\xfc\x27\x5e\xe2\x5a\x2a\x91\x49\x80\x46\x85\xc6\x23\xc4\x61\xe0\x53\xe0\x89\xfe\x2f\x86\xc0\x70\xcc\xa9\xf1\x82\xf7\xc9\x1d\x22\xf6\x3b\x7c\x84\xd4\x66\x63\x45\x3c\x3c\x65\xb4\xb7\x3d\x02\x8c\x90\x03\x3d\x88\x1c\x99\x21\x69\x09\x35\xb5\x22\xac\x27\x72\x9e\x23\xdc\x86\x6e\x05\x26\x3c\x66\xe1\x52\x4e\x09\xbb\x24\x67\xbc\x24\x52\x39\x2a\x69\x66\x4c\x02\xcf\x16\x78\x66\x0b\x21\xc7\xd6\x9c\xbf\xbe\x09\xa3\x70\x58\x67\x2a\xb1\xe0\xf9\xd6\xa4\xf0\xe1\x77\x58\x4d\x77\x0d\x3d\xfa\x20\x21\x20\x7e\xe8\xda\x63\x64\xac\xa1\x04\x69\x39\x81\xca\xb9\xd5\xfe\x93\x6d\xa6\x2b\x7d\x61\x64\xbd\x01\xfb\x05\xf0\x25\x8b\x70\xc5\x41\x25\xe6\x42\xcc\x4f\x9a\xea\x52\xa6\xcd\x9b\xd2\xff\xb2\xf7\xd8\xe1\x64\x76\xc7\x30\x0b\xc3\xe3\xc5\xdf\xa3\xa4\x34\x3a\xd1\xb9\xfd\xd7\x70\xc3\x8e\xcc\xd3\xdc\x14\x50\x84\xde\xe9\x78\xa5\xd1\x99\x29\x5f\xdb\x02\xd6\xf2\x1a\x39\x48\x3e\xed\x78\x05\xe2\xe7\xb6\x3d\x60\x06\xc6\x2c\xb7\x53\xd8\xdc\x32\xf8\x90\xd3\xb1\xfa\x5c\xd4\xe7\xae\x43\x80\xee\x24\x23\x4b\x76\xe1\xee\xc0\xb7\x25\x55\x96\x9d\x66\x5a\x72\x3a\xdb\x60\x15\x16\x7e\x4e\xff\x25\x50\xe6\x61\x4c\x4b\xb8\xd8\xbf\x1b\x29\x0b\xb7\x64\xbb\x33\x94\x4e\xe9\xcb\xa5\x7e\xb3\x65\x7b\xc8\xb5\x90\x35\xa2\x90\x9d\xc0\x66\xfe\xa5\x18\xdb\x73\x4b\x3a\xc3\x9c\x1b\x8c\xab\x85\xfb\x68\xd9\x47\x98\x68\x31\x7a\x79\xd3\x4e\x10\xd6\x31\xd8\xd6\xc8\xe2\xa1\xe4\x93\xa7\x09\xbc\x83\xe5\x00\x45\xee\x50\xce\x63\x2d\xd3\x80\xb6\xb2\xde\x28\x9b\xd4\x12\xbe\x25\xb9\xb1\x67\x81\x58\xf8\xd1\x21\x1c\x84\xfa\x56\x8b\x78\x31\x3b\xe8\x73\xc8\xcd\x70\xb6\x09\x79\x49\x8f\x47\xaa\xba\x38\x5c\x08\x4e\xcc\x87\x27\xd9\x02\xb6\xe7\xe5\xe3\x71\x01\xdf\x17\x24\xe4\xcd\x56\x07\x93\xe1\xe0\xce\x55\xa3\x15\x89\x0a\xbe\x2d\x42\x80\xca\xaa\x1e\xd4\xb1\x68\x39\xf3\x73\x3a\xc9\x21\x59\x86\x72\x16\x68\x72\x0c\xd3\xe5\x35\xd5\xd6\x52\x77\xe4\x4c\x1f\xcc\xef\x30\x9c\xb1\xfe\x57\xae\x2a\x76\x30\x3d\x45\xed\x75\xdd\x4e\x07\x93\x3f\xf6\xe7\xcd\x17\xcc\xac\x3b\xcb\x2c\xe8\x8c\x9c\xab\xf7\xaa\x72\xf2\x2b\x0b\x28\x64\x5f\x2f\xab\x46\xea\xba\xc2\xc0\x1e\x16\x53\x3f\x8b\xb2\x02\x9b\x5c\xda\x01\x34\x61\x7d\x8e\x0c\x31\x57\xb5\x06\x53\x7b\xef\x7c\x5b\xdf\x87\xf5\x10\x4f\xe0\xf1\x95\xf8\xd7\x9c\xd1\xff\x9b\x53\x1c\x8c\xb4\x71\x5a\x85\x1a\x7a\x63\x40\x3b\x08\x2f\xa2\x1d\x1f\x47\xa2\x6a\xc9\x5a\xc6\x41\x88\xae\x69\xa5\x86\x81\x1a\xa4\x81\x7e\xc8\x74\xd5\x1f\x87\x15\x81\x10\x0d\x12\x1c\xb4\x44\xcb\xb7\x80\x3a\x1a\x98\x0d\x56\xd1\x5c\x98\xf8\xf8\xd9\x12\x6a\xae\xaf\x57\x0b\xae\x19\x05\xa1\xda\x97\xc0\xad\x3d\xe7\xa9\x57\x12\x41\x8d\x7d\x61\x7f\xb7\xfa\x36\x8e\xdd\x71\x95\xde\x81\xea\x68\x50\x1e\xf7\xe3\xfb\x3c\x29\x9b\xd3\x49\xd5\x1f\x2a\x6e\xf0\xcf\x7a\xa0\x66\xe0\xa3\x5d\xe7\x28\x4e\x47\xc4\xd2\xf5\x12\xb8\xe0\x32\x5b\x98\x6d\x70\xb4\x72\x8a\xb8\xe5\xc8\x76\x95\x72\xa4\x1e\xc3\x59\xe3\xd5\x52\x6c\x32\x43\xf8\xaa\x34\xc2\x51\x6a\xbf\xd1\xea\xa4\x29\x16\x16\xdb\x21\xce\x94\x48\xea\x36\xbb\x9a\x51\x97\xf9\x8a\x83\x35\x75\xd1\xfd\xcd\xad\x32\x8e\x7e\x43\x51\x87\x3e\x8a\x3a\xca\x69\x39\xf6\x47\x40\x41\x52\x02\xed\x0f\x98\xe1\x3b\x35\x1d\xdb\x8a\x6c\x38\xa1\x12\x6e\x90\xf4\x87\x1a\x0e\x35\x9a\xe7\xf5\x73\xa0\xe6\x1b\xe1\xcc\x25\xde\xd5\x14\x47\xe7\xbd\x70\xb3\xcb\xb2\x82\x90\xf1\x4e\x99\x7f\xdb\xa8\xcc\x27\x0e\x1e\x63\x85\xf3\x1a\x9f\xdb\x7b\x8e\xf8\x77\xa6\x19\xc6\xc5\xf8\x8d\xe0\xd9\xd7\x57\xed\xd4\x52\x85\xc9\x4b\xb7\x18\x3a\x43\xc3\x69\x25\xee\xca\x5f\x3c\x5b\x42\x75\x31\xad\xa5\xbf\x7b\xe1\x1c\xa0\x82\x80\x94\x9c\xc7\xe2\x35\xe6\x74\x88\x40\x2b\x7c\x9c\x28\x5a\x16\x18\xd7\x84\xee\x54\x0f\x26\x4b\x81\xe6\xe7\x0d\x96\x29\x91\x37\x8e\xe1\xaf\x88\x71\x3c\x06\xfc\x53\xaf\xc8\x30\x9c\x76\x8d\x2a\xa3\x3d\x5e\x63\x5c\x8f\x77\xb4\xfd\x28\xf8\x6b\xe9\x6b\x06\x5e\xb6\xc7\x59\x01\x62\x16\x81\xe5\xb8\x83\x0f\xca\xcb\xce\x2a\x12\x03\x64\x52\xd1\xab\x11\x00\x3c\x67\x08\x60\x83\xe6\xb1\x9b\xdf\x60\xe1\x54\x02\x2e\x8a\x34\xc3\xae\x97\x0a\x0c\x2e\x71\x96\x85\xa9\xdb\x1f\x03\x2f\x24\x7a\xd2\x88\xa9\x9a\x32\xf8\x26\xdc\x95\x45\x93\x56\xb5\xde\x1a\x1a\xff\x1f\x57\x6f\xb1\x2c\xbb\xb2\x73\x8d\x3e\x90\x1b\x66\x6a\x9a\x99\xd9\x3d\x97\x99\x19\x9f\xfe\xc6\x5a\x7b\x7f\xe7\x9c\xff\xc6\xec\xcd\x08\x57\x65\x65\x4a\x1a\x63\x28\x65\x89\x70\x1d\xad\xac\xb4\xee\xf6\x39\xe3\x8d\x5a\x03\x34\xaf\x89\x22\xa7\xe2\xfb\x89\x87\xfa\x30\x0a\x6d\xff\x98\x54\x1c\x91\x02\x3f\x95\x1d\x5a\x87\x60\x1d\x83\xd2\xa4\x07\x5e\x1d\x8c\xe5\x30\x17\xc1\x29\x14\x8e\xfa\xef\x79\xd5\x4c\xbd\xaf\x61\xad\x72\xf7\xc4\x19\xca\xe7\x66\x42\x07\x50\xc4\x12\xac\xbd\x98\x99\xa9\xd2\x67\x25\x1c\x4b\xaf\xbb\x7c\x52\xe2\xdf\x1f\xe7\x56\x64\x09\x1f\xe8\x49\xdf\x00\x19\xbe\x95\x49\xfd\xe1\x17\x32\x83\xcb\xbf\x61\x3d\x86\xd3\xab\xea\x94\x7d\x27\x0d\x8a\x38\x1a\x27\xa4\xdc\xd2\x0c\x22\x73\xec\xe5\x3f\xe5\x23\x0c\xc3\x8b\x40\x3c\x68\xc1\x1b\xb9\x82\xcc\xab\xbc\xd7\x64\xb6\x0b\x3a\xc8\x0d\x7c\xd7\xa6\x43\x43\xff\x4d\xfc\x0c\x1c\xa2\xa9\x4f\x45\x1d\xb0\x75\x24\x5e\x33\x99\x0f\xaa\xa0\xb8\xdc\x5c\xf0\x5b\xc1\xf5\x79\x52\x4f\x52\x94\x85\xde\x1a\x7a\xb3\xb3\x60\x4d\x30\xd5\x2b\x87\xf0\x49\x83\x96\xff\x17\x80\x18\x46\xf0\xd8\x46\x68\x46\xcf\x8c\x5b\xca\x69\x53\x5f\xfa\x39\x13\x11\x9f\x65\xa5\xfe\xa2\x2a\x9d\x4c\x76\xe9\x8d\x61\xea\x51\x40\xbc\x4f\x93\x0c\x0d\xdb\x2d\xa7\x00\x3e\x0b\xc2\x99\x52\xca\xc1\x35\xfc\xe9\x53\xfc\x7d\x08\xbe\xe9\x10\xed\x89\x58\x46\xf6\xd8\xea\xbf\x18\xa9\x30\xd8\x1f\x3e\x90\xde\xd1\x63\x21\xa5\xfe\x70\xc6\x15\x7f\x3e\x6f\x9f\xa6\xd9\x92\x13\x3d\x71\x6d\x8a\x87\x22\x4e\x12\x3a\x44\x5c\x21\x7e\x95\xe4\x39\xd1\x44\x2a\xcd\xb8\xcc\x39\x63\xaf\x3e\xcd\xa0\xbf\xbc\xc5\xfb\x5c\xaa\xe7\x53\x51\xd5\x72\xfd\x3f\xee\xcc\xb7\x86\x7a\x99\xa6\x12\x55\x63\x39\x9a\x69\x38\x76\x77\xca\x67\x55\xc4\xce\xc8\x78\xbf\x6e\x41\x75\x3d\x11\x02\xdb\xab\x41\x52\x0f\x43\x12\x34\x56\x1f\x5d\xfd\x7e\xa8\x51\x83\x3d\x57\xef\xe5\xf8\x7b\x70\xa6\xd7\x52\x69\x38\x0a\xcd\x30\x20\xe2\x4b\x1d\x46\xdf\x6a\x8b\x39\x14\xe5\xd2\xff\x63\xcb\x8c\x35\xae\xaa\x91\x36\x76\xdb\x9b\xc9\x2e\x4e\xe6\x2a\x62\xb4\xec\xf2\x15\xaf\x32\x1d\x97\x6d\xa1\x96\x64\x54\xfb\xe3\xd3\x1f\x6d\xa0\x48\x31\x83\x31\xf1\xa0\xf3\xed\x7e\xf6\x09\x2c\x45\xdd\xf2\x10\xba\xda\x31\x01\x84\xef\x18\xb8\x65\x7b\xfb\xdd\x26\x3a\x2b\x0b\xf4\x05\x37\x4e\x6c\x77\x2a\x7f\xcc\xe8\x7f\x7c\x95\x77\x71\xb3\x39\x38\x41\x27\xa4\xb5\x1e\x8b\x4a\x73\x55\x73\xf8\x7d\x03\xb1\x84\xd6\x0a\x45\xe7\x20\x78\xd9\xe0\x10\xb2\x3b\x91\x02\xdd\xf5\xf4\x0e\x3a\x1a\x6d\x85\x24\xb4\x3d\xb2\x44\x9b\xef\xa8\xf5\x83\xa7\xfe\xa2\x49\x92\x82\x4b\x81\x70\xa8\x90\x6f\xcf\x09\xff\xd7\xbe\x4c\xa1\xd6\x53\x3d\xda\xd8\x44\xc5\xbd\xc0\x2c\x37\x38\xd7\xdb\xca\xd2\xed\xfe\x10\x7e\xc9\x07\xc3\xbd\x5e\x9f\xdc\x5a\xa0\x32\x5d\x4e\x01\x62\xfe\x06\xba\x9a\x40\xc8\x8e\x7e\xbe\x54\x9e\xb0\x50\x96\x5f\xbf\x5f\x83\xb5\x40\x16\x49\xe5\xd0\x12\x3a\x2b\x80\x3f\x7f\x80\x1d\xc3\xff\xa3\x31\x58\xc6\xe4\xb2\x2e\xf0\xfe\xc4\x3f\x72\x59\x6d\xe0\x25\x54\xef\x43\xb2\x27\xdb\xc2\x6c\x08\x85\xf9\x08\xdb\x4f\x97\x66\x78\x82\xad\xde\xca\xd3\x77\x43\x9b\x90\xee\xa8\xaa\xfb\x55\x05\x36\x9f\x74\x23\x19\x69\x6f\xf4\xcb\x4d\x70\x41\x92\xe2\x57\xa8\x2c\x88\x66\x75\xcc\x7e\x2a\xb3\x02\xd5\xe4\x7f\xb9\x3e\xc7\x8c\xe7\x8d\x84\x29\x6d\x79\xac\x5a\x2c\x19\xed\xaf\x28\xfb\x92\xa6\x61\x0e\x46\x7a\x2c\xe3\x4c\x00\x0f\x50\xa1\x26\x8a\x16\x0d\x6d\x5f\x34\x58\x5d\x08\xf2\x47\x37\x35\xaa\xb9\x71\x61\xa2\xbe\x03\xc4\xe5\x51\x72\xdd\x8a\x23\x63\x39\x54\xa3\xff\xcf\x67\xab\x42\xe5\xf5\x41\xd6\x85\xeb\x10\x08\xc7\xfb\xd8\xdd\x30\x7b\x25\x92\x9c\x21\x85\x22\x53\x66\x3f\x80\xfd\xe4\xcd\x13\x93\xc8\xaa\x90\xfb\x5f\x3f\xcc\xf5\x2e\x4f\x68\x55\x2b\x18\x56\x33\x76\x2a\x6c\x87\xf3\xb7\xb0\x6c\x2d\x78\xa9\x82\xb9\xce\xb2\xb0\x77\x9e\xfd\xc7\x0d\x45\xf3\xf4\x6b\x4c\x53\x08\x27\xee\x5b\xf7\x08\x57\x0f\x6a\x76\xb8\x37\x75\x65\x47\x80\xca\x52\xb7\x92\x3c\x56\xa2\x6c\x81\x4d\x95\x12\x41\xe1\xe9\x22\xfd\x20\x8e\x79\xd8\xd1\x6c\xfa\x1a\x2f\x31\x06\xaa\xaf\xff\xe2\x5c\x2b\x8c\x4b\x68\x75\x30\xa1\x21\xb1\x7f\xb9\x84\x1c\xaa\x99\xe1\xb1\x2a\x34\xfe\x0e\x84\x16\x03\x41\x71\x6b\xc3\xec\x26\x7f\x0b\xb5\xa5\x90\x66\xe1\x27\x37\xc6\x72\x18\x60\x4e\x33\xb5\xea\x0f\x78\x99\xd4\x9c\xca\x22\xff\xc5\x6c\x86\xe9\x3d\x51\xec\xfb\x64\x6e\x37\xb5\xcd\x62\x6b\x2f\xf8\xb5\x70\x56\x01\xc3\x29\x73\x37\x1b\xa7\x68\xeb\x50\xed\x8f\x14\x48\x5f\x96\x79\x27\xf5\xcb\x6d\x4e\x36\xed\x3b\x77\x99\xff\x73\x24\x96\x89\x85\xd6\x5d\x58\xe9\x43\x72\x57\x39\xf2\x14\x8d\xba\x66\x3a\xa2\x88\xf6\xd7\xc2\x49\xe4\x01\xe8\x6c\x87\x98\x42\x6d\x71\xd8\xcf\xab\x7b\xad\x31\xd8\xcd\x0d\xdd\xd8\xe3\xff\x87\x77\x2b\xbc\xf6\x21\x89\x4b\xc8\xd1\xc8\xa6\xe1\xf8\x71\x5e\x54\x62\x84\xea\xad\xbe\x93\x7d\x01\x0f\x7a\xb8\xd2\x0f\x67\x25\xbf\x09\x19\xd2\x48\xdf\x9a\x54\x69\x29\x02\x43\x38\xd3\x7f\x75\xd6\xa3\x14\x82\x17\xae\x37\x92\x3d\xf3\xd2\xcc\x20\x40\xb1\x8d\xa9\x8e\x86\x6e\xec\xb5\x6b\x8b\x8e\xb6\x84\x84\x1c\xce\xd9\xa2\x48\xd4\x25\xde\x02\x53\x28\xee\xff\xe8\x9a\xda\x9e\xf3\x8e\x87\x24\xc7\xd2\xff\xec\x9f\xb9\x0a\x49\x85\xfd\xe1\xdb\x35\x4c\x56\x20\x4a\x64\x4b\x0b\x8f\x06\xa0\xf8\x36\x7e\x99\xde\x20\x2a\x49\xd0\x67\xf7\xc7\xe0\xc5\xfa\x41\x0d\xe9\x09\xf5\xbd\xff\x87\x03\xea\x6f\x25\x7f\x1d\x9b\x98\xed\x51\xa8\xc2\x94\xed\x79\x5a\xd9\x6c\xb6\x2d\x31\xc5\xc1\x88\xf2\x28\xc4\xbe\x71\x73\xda\xe4\x5a\xca\x12\x7b\x41\x9d\x18\x2c\xa9\xb7\xa9\xf8\x5f\x63\xfc\x07\x9f\xec\x66\x6e\x77\x35\x73\xda\xfe\x93\xea\xe7\x1d\x9d\xe7\x11\x98\x83\x87\x50\x68\x3d\xf3\xa3\x37\x56\x83\xbd\x9c\x45\x4c\x3e\x25\x4d\xd3\xf6\x11\xe6\x74\x6b\x5a\x96\x56\xfc\x7f\xdf\x51\xfa\x3b\x1d\x59\x84\xda\xc8\x79\x78\xc9\x82\xa3\x86\x91\xf3\x74\x32\x97\xb3\xd9\xd4\xf5\x89\x38\x64\x25\x5b\xac\xee\xbd\xf4\x79\xfb\xf7\xd5\xe6\x4b\x7d\xf3\x87\x91\x3d\x33\x57\xbb\xff\x10\x69\x96\x51\x4e\x7f\xc0\x57\x0e\x6b\x78\x3f\xfd\xf9\x89\xd1\x95\x8d\xd2\x9f\x37\x4d\x10\x6c\xa0\x0d\xf2\x2f\x8e\xdd\xf5\x08\xd7\xc9\x81\xbd\xe1\x95\x32\x78\xe7\x5e\xdd\x12\xb8\xec\xde\xf3\xe6\xff\x3e\x45\x65\x7c\x7d\x9f\xb2\x9d\xc6\x9d\xf2\x08\x57\x51\x95\x2c\x4e\xb2\x5d\xe2\x0c\x1f\x4b\x50\xfc\x22\xed\x03\x48\xa8\xa5\xa9\x58\x7d\x75\x4c\x01\x5b\x11\x78\xe2\xee\xfe\x7d\x77\xef\x8f\x2f\xad\x01\xe3\xb9\x96\xaa\x04\xfd\xfb\x60\x04\x32\x31\x43\xbf\xc3\x23\x1c\xad\xb0\xb7\x06\xce\x2c\xd4\xd2\x50\x7b\x9e\x32\xb7\x8d\x6c\xaf\xcb\xe2\xf8\x9b\x9d\x24\xce\x7f\x21\x71\xf7\x9b\x57\x0b\x17\x69\x92\x1c\x7e\xbe\xd2\x8e\xcb\x64\x2e\x0b\xdd\x15\x35\xbf\x9c\x49\xda\x3a\x78\xa4\x19\xd2\x1a\x87\x7d\xfb\x1b\x21\xbe\x77\x60\x73\xb6\x50\xd2\xff\xda\x07\xe7\x68\xcc\xc7\xe3\x1c\x1b\x6b\xec\xf0\x9e\xf9\xb3\x9b\xad\x60\xb5\x49\xfa\x39\xf3\x18\x8d\xb8\xc5\xa3\x6b\xe5\x61\xb1\xdf\x5a\xad\xa8\xfc\xfe\x87\x67\x38\x8c\x12\xe2\xfc\xee\xb0\xca\xa4\x38\x61\xe2\x1a\xb3\xca\x29\x7e\x9e\x76\x49\xcb\x8b\x26\x03\x4d\x25\xcd\xe4\x6e\xf8\xff\x7b\x46\x1f\xf0\x32\x7a\x79\xc5\xc0\x16\xf5\x73\x13\x91\x6b\x34\x3e\xed\xb9\xf5\x0a\xef\x55\x1b\x9b\xdb\xef\xf1\x33\xb9\x2d\x43\xe5\xc7\xde\x04\xfe\xe3\xd0\xac\xa6\x2c\xe7\x40\xe9\x9c\x68\x9b\x69\x3a\xfc\xfc\x64\xc3\x6a\x26\xad\x5f\x5f\xbd\xcc\x3b\x7f\x38\x79\x68\xeb\x35\xe7\x18\xad\xb7\x80\xff\xc9\x1d\xe8\x82\xc6\xe1\x22\xe3\xfd\xe4\x5c\xe6\x0f\x51\x71\x0c\x46\x0a\xa2\x21\x68\x7a\x93\xdd\x9d\xa6\x29\xdd\xb7\xf4\x48\x2b\xe8\x79\xe2\x26\xf2\xff\xf8\xad\xaa\xfe\xcc\x6c\x88\x96\x50\x69\xf8\xb5\xe9\xa0\x72\x0b\xb3\xce\x6f\x18\xb6\xc1\x7f\x3f\x31\x0d\xa2\x60\x6c\x98\x31\x07\xa2\x66\x61\xd8\x9e\xfd\xdf\x75\x9e\x82\x59\xd5\xcb\xdd\xe9\xc6\x94\x91\x7c\x2c\x31\x9d\xe0\xba\xa1\x84\x59\x70\x0b\x4c\xe4\xce\x59\x19\x66\xd4\x06\x86\xf5\x1c\xf3\x1f\x6a\xd3\x47\x83\xd8\x30\x89\xe6\x08\x5b\x8f\x9f\x59\xbb\x33\xcd\x60\x6c\x61\x92\x76\xc1\x4f\x50\xaa\x01\xb2\x56\x48\xed\x93\xd2\xa8\x0d\x5a\xf9\xbf\x87\x3c\xbe\x3d\xc2\xd1\x82\x23\x96\x93\x55\xde\xc8\xba\x68\x86\xb5\xe3\x60\x9a\xcd\xfe\x6d\xbc\x96\xf2\xb2\xa8\xec\x8b\xde\x2a\xb5\xc3\x1a\xb5\xfd\x5f\x8c\x50\x19\xc3\xd3\x92\x7e\x0c\xee\x71\xa7\xcf\xbd\x65\xcc\xde\x56\x95\x9e\x02\xd5\x37\x70\x6a\x72\x8c\x5a\xed\x1e\x42\xb6\xe7\xa5\xff\xd1\xd9\x6c\xff\xca\x39\x91\x5a\x6d\x3f\xbc\x77\xef\xf9\xab\x63\x24\xde\x3e\x87\xce\xac\x4b\xc9\x87\x2d\x0c\x54\x26\x18\xb5\x99\xa3\xdc\x29\xf2\xff\x38\xaa\xc3\xfb\xa1\x20\x12\xa6\x96\xea\x62\xa6\xbb\x99\xe8\x28\x0c\xe1\xd8\xde\x1d\xed\xb0\xb6\xb8\xec\xeb\xcd\x84\x87\x09\x82\xc4\xfc\xbf\xcf\xb9\xaa\x17\xf4\x6e\xbd\x30\x82\xb6\xc4\xda\x8f\xcf\x86\x8a\xcf\xb1\xae\xbf\x70\x7b\xf6\xf9\x24\x10\x1c\x63\x3a\x31\xa1\x2c\xca\x6e\x7b\xf2\xb1\xcf\x46\x0d\x10\xa0\x6c\x8b\x8b\xb4\x37\x72\x45\xb2\xeb\xf5\x3f\xfb\xcb\xaa\xc9\xc1\x6f\x81\x63\x34\x50\xd4\x66\xc5\xe9\x0f\xde\x28\xda\xa5\x8a\xd9\xf4\xe5\xf5\x45\x03\x10\xe7\xb6\x7f\xd7\x5e\x1b\xd8\xf1\xea\x69\x38\x92\x68\x42\xf0\x8e\xa6\x85\x43\x93\x74\x9c\xca\xaa\xff\xab\x07\x71\x6e\xe0\x93\x36\x66\xa9\x49\xfd\x24\x25\x73\xef\x85\x54\xf0\x58\xbb\xe0\x67\xb7\x1a\xd8\x82\x99\x17\x3a\x16\x3a\x58\xc3\x3c\xb3\x2d\x4b\xc9\xfd\x0c\xf4\xa5\xca\x25\x64\x26\xf7\x1a\xe2\xb7\x60\xad\x12\x84\x98\x64\xdc\xed\xff\x2d\x90\x73\x8c\xdf\x4a\x9c\x17\x49\x83\x75\xa9\x56\x4b\x86\xa3\x24\xf6\xda\x1f\x55\x41\x09\x6e\x5e\x9d\x59\xe5\x3f\xe6\x15\x98\xba\x16\x95\xa1\x36\x9a\x1e\x96\x66\x18\xa2\xf7\xb2\x36\xc9\x3a\x93\x16\x14\xef\x4e\x07\x3c\x8a\x6a\x5b\xbc\x56\x5b\xce\x61\x97\xe4\x4a\xb0\xc2\xc5\xea\x0e\xa8\xe2\x18\x8f\x77\xdc\xdb\x11\x56\x99\x19\x13\xd0\x9a\x54\xb6\xf9\xcf\xef\x51\x78\x03\x2a\x26\x97\xaa\x4a\x10\xf4\x50\xf7\xfb\x54\xe2\x63\xbb\xfe\x41\x4c\xa9\x8f\x5c\x35\x2f\xe5\x46\x81\xa9\x46\xd4\x54\x5f\x6b\x1c\x64\x85\x43\xef\x7c\x3d\x7f\xf7\x3e\xfd\xd8\xbc\xfc\x18\xe6\xe3\x8d\x9f\xb2\x7a\xd9\xfb\xdc\xa2\x63\xd1\xeb\xd9\xc3\x92\x32\x4f\x70\xa9\x5f\x9d\x4e\x07\xe8\xc0\x0f\x20\x0d\xa6\xdd\x69\xd7\x75\x4f\xf8\x63\x8b\x27\xf2\xe3\x82\xff\x98\x31\xf3\x86\x6e\x16\xf4\xcf\x50\xf6\xd3\x8c\x6b\xe6\x82\x9c\xb2\xd2\x23\xdc\xf1\xcb\x2e\x11\xb5\xf0\x85\x04\xba\xdd\x37\xe7\x2f\xef\xbe\x6b\x9d\x8a\x54\x97\x92\x77\x24\x92\x14\x6b\x1e\x53\x5f\xaa\x01\x31\x45\x26\x98\x9e\xb1\xa7\x86\xd9\xe4\x18\xab\x97\xfe\xd7\x6e\xb9\x3e\x68\xd7\xb0\x1b\x9c\xa0\xde\x9b\xbd\xfc\x8d\xb8\x6e\x1c\x5a\x6e\x14\xf3\xd8\x65\xbf\x4f\x41\x4c\x3f\x18\xb7\x02\x90\xd6\x82\x16\x8c\x99\xae\x96\x7d\x9c\x39\xc5\xc0\x69\xc2\x0e\x89\xfa\x96\xd2\x58\x95\x4c\x8d\xa3\x45\x81\xe3\x3f\x85\xff\xaf\x89\xbe\x7e\xfa\xba\xec\xc8\x29\x9c\xa6\x23\xd9\xe7\xae\x5c\x44\x96\x6f\xe6\xf7\xd9\x6f\x29\x97\x52\xc7\x1f\xb3\x24\x09\x6d\x79\x4b\xf4\x03\x88\x30\x4a\xef\xf4\xf1\xe7\x3e\x3f\x21\xa4\x09\x2c\x1e\x53\xd8\x2c\xf4\x96\xc8\x0e\xf0\xd3\x69\xd3\xff\xf2\xdd\x5a\x72\x3e\x29\x81\xa2\xf6\x19\x1e\x41\x09\xb3\x2d\xc0\x5f\xb8\x9c\x1a\xa5\x9f\xbc\x6c\x93\x21\x5a\x71\x73\xde\x81\xd4\xca\xd3\xec\x87\xbe\x4e\x2a\xaa\xa1\xbf\x24\x35\x09\x3e\x26\x96\x4f\x19\x67\x29\x17\x26\x22\x5a\x6a\xcc\xba\x11\x87\xc5\x73\xb5\x04\x12\xc6\xff\xe5\x14\xc1\xc8\xf7\xad\xac\x08\x4a\x8c\xed\xef\xb7\xbd\xf9\x1a\x81\x13\xba\xd2\xfe\x2a\x3a\x85\x5c\xa0\xe6\x57\xa2\xaa\x55\x2f\xa0\x8c\x83\x3d\x7d\x98\xfd\xe8\x22\x7a\x83\xdb\xc9\x72\xf3\x99\xeb\x4e\xc3\x18\x14\x65\x3c\x29\xc4\x3c\x7b\x6f\xaa\x79\xca\xee\xb0\x46\xa3\xff\x6f\x8c\xe1\xfe\xf8\x65\x17\x64\xbc\x65\xf8\x70\x8f\x13\xed\x64\x8f\x56\x21\xf6\xa5\x04\x8d\xd3\xb1\x65\x70\x11\x7b\x0a\x0a\x59\x1e\x46\x36\x44\x88\x19\x35\x27\xaf\xb4\xdf\x12\x71\x0a\x5a\xbb\x27\xbf\x79\x5c\xf6\x61\x4a\x86\x99\x5a\x09\xba\x6e\xaa\x9c\x17\x0b\xee\xfd\x71\x0a\x83\x38\xfd\x27\xdd\x7f\x04\x1b\x04\xd1\x64\x19\x0f\x70\x11\x87\x70\x88\x16\xbf\x8c\xb8\x6c\x1c\x94\xf1\x4a\x61\x59\x05\x08\xb1\xe3\xbc\x08\x29\x2f\x6d\x39\x89\x1d\x86\x91\xd8\xc4\x9d\xa1\x19\x25\x8f\xcb\x06\x14\x67\xa7\xdf\x7c\xe2\x7d\x8d\xcd\xae\x50\x9b\x61\x09\x2d\xe2\x10\x2d\xba\x40\x55\x2b\xdd\x35\x9f\xcf\x71\xf9\x35\x76\xa0\xfc\x81\x85\x20\xfd\x85\x7d\xf9\x26\x90\xb5\x63\xef\x19\xbc\xac\xc5\x5a\x02\x12\x39\x1a\xab\x28\x85\xec\x42\x58\x66\x78\xd2\xdc\x36\x10\x3e\x3b\x46\xf3\x97\xdb\xb2\x4c\xb9\xb6\xc7\x1a\x4e\x00\x54\x69\x47\x44\x56\x11\x7c\xb8\x4a\x6e\x17\xe3\xa7\xbe\xea\x3f\xc9\x87\x27\x0e\x42\x99\x9d\x3d\x53\x06\x6d\x8c\x71\x1a\x81\x6f\xe9\x71\x87\x90\xc9\xcf\x70\xfa\x08\xc7\x03\x3d\x5e\x2a\xe7\x8f\x2a\x3c\xb1\x55\xe7\xf6\x30\x03\x0a\xb2\xff\x5d\x3f\x12\x74\x5c\x76\x14\x1e\x49\x97\x25\xb3\x9b\x0c\x1a\xbb\x5e\xf8\x32\xdf\x3c\x10\x00\xdb\xc6\xb8\xce\x0f\x3e\x99\xd8\x15\x6e\x09\x35\xd5\x12\xb8\xd1\x99\xa0\xf0\xcf\xb1\xac\xd1\x71\xfe\x26\xb2\xa5\xf2\xe2\xba\x6c\x42\x2a\x68\x1a\x77\xf1\x4d\xcd\x1d\x86\xa9\xd9\x06\xec\x43\x3d\x78\x65\x35\x50\x12\x40\x0c\xd7\xc3\x7c\x70\xc5\xcd\xb7\x21\xdf\xe8\xdc\x65\x59\x41\x6b\x8b\x94\xdf\x0f\xb4\xa3\xe2\x9a\x62\x05\xe1\xe6\x25\x03\x19\x7d\x06\x15\xac\xf2\x53\xfa\xfe\xb5\x69\x90\xc5\x2e\x57\xe5\x99\x62\xed\x9b\x1b\x16\xea\x62\x7d\xad\x46\xed\xfe\x32\x26\x56\x41\x32\xa2\xb0\x10\x80\x04\xd2\x14\xce\xe8\x5c\xad\x67\x76\xfe\xb3\x57\x78\xdb\x2f\x7a\xfa\xd3\x53\xa5\xe3\x77\xae\x0e\xda\xcd\x9f\xdf\x78\x88\xc2\xf9\x14\xe7\xb6\xe5\x14\x7d\x25\xab\x92\x1c\xf1\xae\x45\xf1\xcb\x26\xd1\x92\x1c\x37\xb2\xd8\xbb\xf1\x4e\xff\x7c\x77\xd2\xd4\xa3\x4d\x03\xac\xe7\xab\x79\x37\xdd\x72\xd9\x87\x4c\xba\x9b\xec\x1f\x1e\xe0\xe8\x33\x80\xfe\x36\x18\x73\xf2\xca\x59\x07\x81\x61\x78\x25\x61\x1e\x73\x20\xac\x9d\x8c\xb9\x5b\xb7\x6c\xa3\xc0\x99\x7e\xcc\xb0\xee\xeb\x98\xb1\xff\xe4\x97\x24\x33\xa4\x18\xa9\x1c\x45\x0d\xac\x9b\x2c\x5c\x6a\xd5\x8d\xb3\xdc\x77\xcc\xc5\xba\x95\x41\xd4\x52\x70\xbd\x4c\x3a\x0e\x8b\x79\x8a\x7b\x8d\x5e\x3e\x8b\x20\xf0\xea\xe0\x4f\x7c\x21\xaa\x0b\xf1\x7c\xc2\x53\x8d\xd2\x90\xe6\x1e\x73\xa4\x94\xff\x9b\x07\x12\xb8\x76\x5d\xd7\xb5\xba\xd0\x04\x23\x44\x87\xd3\x84\xbf\xf1\x37\x1c\xf0\x48\x1b\xcd\xf4\x91\x44\xe5\x02\x84\xe5\x5d\xc6\x6a\x02\xb0\xe1\xd8\xa1\x31\x00\x68\x3d\x93\x96\xf7\xa1\xd3\x25\x66\x39\xa1\x5c\xca\xcd\xc4\xe1\x63\x87\x17\x11\xf1\xcb\x12\xc7\x0c\xda\xce\x46\xd3\x87\x0b\xf4\x78\x6b\x35\xe6\x26\xd9\x4a\x22\x28\xea\x21\xe9\x52\xd6\xfe\xcd\x2f\xb3\x2d\xfc\x95\xc9\xbb\xfe\x83\xb3\xbf\x78\xe3\x28\x8a\xe0\xc4\xdd\xda\x7a\x39\x4f\xfc\x25\x21\x6c\x5a\x4b\x71\x4a\x5d\xca\xfb\x58\x52\xee\xa9\xba\x51\x00\xbe\x8a\x57\x2a\x54\xbd\x42\xe0\x86\xfd\x8e\xef\x2d\x78\x03\xe2\x7d\x65\x27\x8b\x83\x53\xf3\x5b\xbd\xe7\x2d\xd0\x1f\x12\x46\x43\x30\x0f\x21\x08\x09\xe7\x80\x9e\x34\x3a\x31\xd8\xa4\x6d\xf5\xa1\x7b\x79\xb8\x1e\x81\xe4\x82\x13\xcc\x6b\x7f\x78\x69\x27\x24\x65\x30\xbb\xcf\xf7\xcc\x58\xf1\x87\x4b\x3d\xff\xf2\x3b\x47\xd9\xa2\x2d\x84\x49\xd2\xac\x9f\xe7\xcf\x72\x74\x5d\x68\x59\x71\x30\x06\xa7\xb1\xf1\x32\x97\xf5\x23\xdb\x72\xc2\x80\x11\x05\x92\xe4\x6d\xfb\xe6\x82\x9b\xe3\x2d\xa6\xe4\x45\x39\xb6\x12\x2d\x49\xb4\x44\x97\x03\x19\xf1\x4e\xaf\x1d\x98\xa8\x89\xb3\x31\xbc\xb0\xa1\xe2\x95\x16\x85\xd8\x35\x55\xc8\xcc\x03\xec\x38\x69\x64\x84\x33\x6d\xa4\xbb\x1e\xa3\x26\xc5\x2c\x3b\xb4\x65\xd8\xde\xfe\x37\xc7\xbd\x44\xdb\xda\x33\xfd\xdf\x33\xd9\x6f\x5f\x37\x3c\xee\x6e\x64\xdc\x0f\xb3\x7d\xbc\x5d\x35\x38\xb4\x63\x5a\x29\x70\x20\x90\x0f\x28\x7b\x0a\x9c\x8a\xaf\x44\x69\x93\x0c\x08\xd4\xd1\x9a\x40\x17\xe4\xd4\x56\x23\x35\x1d\x22\x78\xb1\xd4\xaf\xaf\xc1\x9e\xaf\x0b\xe9\xf8\xfd\x68\xf9\xee\x14\xfa\x7b\xbb\xe9\xa5\x06\xa7\xd5\x8b\xd8\xf6\xc4\x9a\xe2\x8f\x9e\xff\xe7\xbb\x79\x95\x28\xbf\xdd\x96\xbb\x5b\xb1\xfe\xe0\x22\x9b\x2e\xbf\x97\x0a\x15\x6c\xc0\x19\xe3\xfe\x83\x05\xfb\x37\xf1\xf1\xe2\x4a\x33\x36\x59\xfe\x96\x15\x67\xe8\xe2\x0a\x27\x59\xf9\x17\x40\xb4\x9e\x5d\xaa\xf0\x07\x1b\x22\xe5\x1a\xe9\xa8\x25\xa7\x02\xa2\x49\x17\x49\x47\x28\x93\x19\x8a\x24\x16\x34\xf2\x9e\x11\x0a\x0f\xd9\xeb\x26\x6b\x0d\x22\x6f\xe1\xed\xaa\x77\x04\xb1\x7d\x94\x1e\xc5\xa5\x09\x26\xe4\xd7\x92\x1c\xf1\xdf\x7c\x48\x8f\xd3\xed\x93\xbc\xe3\x5e\xd6\xfd\x9f\x58\xee\xf1\x86\x65\x48\x5d\xe0\xe5\x65\x63\x2f\xb4\x9d\x92\xbf\xcc\xa8\xa4\x81\x26\xa6\x00\x9a\xd6\x53\x5e\x38\x46\xa1\xab\xb8\xa2\x95\xb9\xe7\x0c\xb5\x37\x75\x45\xcd\x2c\x5c\x83\x48\x3f\x4d\x25\x7c\xff\x31\xb3\x54\x53\xbd\xda\x64\x57\xe9\xfa\xa6\x51\x1f\x9a\xdb\xcf\xf0\xf7\x0e\x42\x10\x96\xbc\x91\xd2\x42\x05\x48\xaf\x6b\x45\xe0\x2e\x19\x0e\xbb\x8f\x31\xa7\xdc\x7f\x48\x3c\xeb\x61\x08\xfe\x2a\x77\xcd\x30\x2a\x27\xbe\xfb\xa1\x05\x16\x51\xf3\x18\x2c\x61\x54\xa7\x7f\x85\x1b\x2f\x30\x33\x17\xa2\x90\xfe\xe1\x84\xc4\x80\x9c\x4e\xbc\x28\x66\x97\xc0\xae\x57\x20\x59\xba\x9d\xa4\x4f\x2d\xd6\x62\xab\x9e\x69\x42\x57\x7e\x89\xd4\x3d\x54\x47\xc1\x07\xb8\xfd\xc3\xc1\x5f\x26\x84\x55\x19\xe5\xcb\xe3\x77\xa3\x94\xdc\xb5\x32\xdd\x1f\x83\x21\xbd\xb3\xe9\xed\x22\x54\xf1\x4f\x91\xf7\xd6\x16\xa6\x99\x34\xea\x3f\x90\xc3\xaa\xae\x20\x06\x7f\xf4\x8c\x27\x60\x33\xac\xfc\xf9\x2f\xcb\x98\x17\xce\x2c\x59\xf7\x05\x16\x86\xb4\xfd\x3a\xbc\x53\xd5\xa7\x55\xba\x1d\x62\x7f\x40\x6e\x28\x3a\xad\x74\x5e\x07\x0e\xc3\x7d\x89\x1c\xbf\x90\xbc\x5c\xd4\xa5\xe1\xce\x48\xe7\x45\x0b\xc5\x95\x57\x85\x71\x7b\x0a\xdd\x17\x50\x05\x36\x39\x07\x62\x1a\xc2\x3e\x68\xb4\x83\xa2\x2e\x20\x7a\xaf\x94\x55\x75\x9f\xb4\x88\x49\x8b\x9e\x5b\x60\x5b\x38\xd6\x6e\xf9\xb3\xde\x3d\x32\x25\xc5\x21\x1c\x37\xa4\x40\x81\xf9\x63\x3b\xdc\x12\x78\xeb\x53\x30\x18\xc3\xe8\x6a\x10\x44\x12\x6b\x6f\x16\x11\x18\xbf\xa7\x0a\xf8\xe5\x93\x4b\x25\x9e\xe1\x2c\x1b\xda\xc8\x74\x27\x9b\x10\xba\x85\x02\xcf\x1f\x2a\x23\xd7\x52\xd9\x78\x65\x40\x87\x5e\xc8\xe8\x2b\x79\x3b\x14\x35\x0a\xa1\x93\xcb\x5f\x52\x70\xc8\x05\x5a\xa0\x39\xaa\x6a\xf5\x02\xf2\x24\x18\xc0\xa7\x09\x8d\x9e\xb9\xee\x07\x1b\x8b\x67\xdf\x7b\xf9\x12\x30\xe7\xf0\x04\x18\x85\x0b\x6d\xf7\xd6\x97\x4e\x21\x77\xbc\xde\x4c\x0d\xfd\xeb\xe7\xb2\xfe\x1a\x13\x32\x48\x7f\x7b\x15\xf3\xd2\xe4\x53\x91\x13\x32\xab\xc8\xc4\x16\x68\x3c\xe5\x61\x5e\x7a\xd2\xc9\xe8\x1b\x9c\xc8\x81\xee\xd4\x34\xd2\x84\xa7\xa4\x7f\x7d\xdd\x24\xa1\x56\x21\x9e\x28\x7b\x54\x4b\x3e\xda\x3d\x9c\x95\x3a\x3a\xae\xcc\xea\x36\x81\xa4\x63\x35\x0f\xbf\xbe\x28\x27\xd8\xda\x86\x7c\x98\x15\xac\x24\x1c\x2f\x7d\x07\x47\x63\x7d\x0b\x94\x1e\x1c\xba\x61\x4e\x5f\x4a\x5b\xee\x7a\x8e\x45\x64\x45\xdb\xff\xd1\xa4\x9e\x41\x28\x82\x67\xf6\x46\x33\xb5\x7f\x82\x00\xe2\xf5\xe8\x83\x13\x0b\xe9\xb5\xb2\xa7\x89\x8e\xa5\xa2\x16\x69\x4c\x7e\xe0\xba\x83\x51\xe5\xc7\x8f\x46\xfb\xe2\xba\x68\x26\xd2\x98\xe4\x18\xb4\x25\xd4\x26\xd8\x4b\x1b\x94\x76\xd7\x21\xc8\x3a\xb5\x6e\xdb\x3d\x98\xfa\x78\x41\x38\xc5\xf4\x48\xa9\x6b\xad\xf9\xed\xb4\x6c\x13\xfb\x32\xbd\x07\x67\x1d\x02\x4b\x45\xd3\xa9\x55\x2a\x0b\x49\x82\x75\x13\xf9\x63\x97\x0c\x16\xaa\x91\xe9\x2c\x6d\x99\x1f\xbc\xa2\xd4\x85\x35\xb5\xa6\x71\x59\x33\x90\x27\xaa\x0f\xa0\xaa\x4b\x3e\x30\xfa\x60\x67\x93\x03\x69\x3a\x8a\xf2\xdd\x29\x9d\x37\xf2\xfd\xa5\x07\xc1\xc2\x3a\xa2\xe6\xcf\xd9\xeb\xba\xff\xd8\xf2\xb4\xc1\x27\xa8\xc5\xdf\x68\x1d\xc9\x3e\x87\xcc\xcc\x2d\x1f\x6e\xaa\x70\x11\x63\xa3\xe9\xf6\xe6\xaf\x44\xf7\x59\xb4\x56\x5a\xc5\xb5\x53\xf7\xb0\xb5\xe0\x4b\x94\x65\x54\x5a\xa0\x2d\x35\x43\xe2\x74\xa2\xe0\x95\x2c\x49\xa4\xc9\xed\xe6\x9c\x96\x38\x0f\xa5\x26\xe2\x02\x6c\x3c\x9e\xf3\xa2\x69\x5b\x50\x7c\x35\x15\x9e\xcc\x1a\x74\x2d\x4f\x13\x65\x08\xf5\xe5\x33\x80\x6b\x25\x28\xbb\xa1\xec\xb4\x00\xeb\x86\x96\x97\x22\x8b\x7a\xd5\x9e\x8d\x1a\x79\x19\x90\x5f\x18\x8a\x05\x7f\x57\x0c\x2f\xee\x5e\xa2\xfe\xef\x8f\x35\x25\x9d\xe4\xe8\x29\x7d\x8e\x68\xf4\xfc\x0c\x87\xc5\x58\x11\x7e\x69\xee\x2f\x56\xea\x5a\xe4\xaf\xf9\xa6\x79\x3d\x10\x84\x51\xf1\xf3\xe8\x7c\x0d\x99\x40\xe4\xdb\x2f\xd7\x21\xc5\x4b\x15\x64\x25\x43\x5b\x85\x5e\x0b\x83\x88\x72\x3d\x05\x6c\xdb\x01\xfe\x08\x57\xd3\x5b\x07\x03\xd9\x48\x15\x8f\x35\x3a\x3e\xab\xa7\x14\xac\xa6\xd7\xce\x66\xce\xf9\xa5\x93\x81\xdf\x95\x84\xa6\xa4\x24\xcf\x08\xbd\xca\x4e\x78\x73\x68\xcc\x5c\x8a\xe2\x47\xec\x67\xe3\xcb\x95\x86\x0c\xe5\x1e\x23\xf6\x72\xfb\x39\x6c\xbf\x4a\xcf\x5c\x8a\x13\x4d\x7f\x24\xf6\x80\xc5\x11\xff\xcc\xa8\xf5\x65\x16\x2e\x9f\x94\x19\xff\xa0\xa7\xf3\xe8\x7f\xdb\x2d\x97\x39\x23\xff\xb5\xa1\xa8\x3c\xa9\x3d\xb3\xbe\xad\x58\x93\x60\x9d\x8c\xef\x74\xb1\x46\x20\xa6\xd0\xdb\xc8\xa3\xf6\xf7\x89\xf4\xcc\x54\x6e\xfd\x4b\xa2\xa3\xf6\x0d\x5e\xfd\x40\x0b\x7b\x2a\xbe\x1c\x7f\x7e\x14\x38\xd1\xbf\xa9\xfa\x60\x78\x47\x54\x74\x12\x16\xf7\x99\xd6\x1f\x94\xee\x04\x5c\x2c\xaf\x71\xc1\x08\xa9\xa3\xbd\x24\xff\x94\x1f\x65\x09\x3c\x47\x16\x2d\x80\x81\xe9\xef\x47\x9f\x74\xf6\x14\x9c\xe1\x7a\x64\x01\xc0\xef\x19\xbe\x0a\x73\xb3\xac\xa0\x80\x34\x30\x49\xf4\x9d\x30\x7f\x39\x69\xb1\xe8\x6a\x2a\xd9\x72\x67\xac\x25\x4c\x1c\xde\xea\xac\xef\x75\x71\xcf\x17\x6f\xe7\x79\x19\x52\xfd\x91\xb8\x0a\x61\x49\xd3\x49\x69\xa7\x8a\xe0\x41\x46\x70\xf9\xed\x44\x72\x60\xc1\x83\x4a\xe7\x86\x1e\xf5\x1f\x02\xec\xbc\x2b\x40\x0a\x3d\xf2\x2d\x5a\x1b\x72\xb5\x36\x89\x63\xa0\xac\xf9\x92\x5d\x2f\x46\x81\xb2\xcb\xd0\xbd\x0a\xc4\x12\xf3\xd8\x0b\x44\xd0\xa9\x2c\x4f\x04\xb6\x12\xbb\x3e\xbb\x6d\x9b\xf3\x2d\xb5\x49\xca\x82\xd5\x2c\x23\x08\xae\xe5\xef\xe4\x15\x83\x2f\xed\xae\x26\xab\xfd\x95\xa4\x67\x38\xa4\x41\xc6\xdb\xcb\x5e\x6a\x41\xd6\x39\x3f\x35\x4f\x94\x3a\xe4\xd6\x21\xec\xae\xc4\xc4\x81\xfe\xf8\xe9\xfb\x87\xdc\x2f\x1d\x26\xea\x0f\xf9\xcb\x8f\x58\x6d\xd0\xf7\x13\x2d\x9f\x62\x9d\xa3\x4c\xd8\xf1\x3f\x6b\x0b\x8c\x56\xe7\xea\x2b\x21\xa5\x26\xb2\x62\xb5\x2f\x33\x27\xd4\x03\x26\xfa\xa3\x85\x14\x45\x5e\xb3\xf1\xac\x4a\xfb\x8b\x41\x8f\x0e\x6b\x4a\x3a\x22\x1d\xcb\x1d\xc7\x52\x2c\x19\xcc\x4f\xb3\x02\xa8\xaa\xe4\xea\x5a\x13\x98\x9a\x61\xf6\x86\x55\x05\xd5\x98\xfc\x96\x57\x79\x0e\x90\x57\xda\x5e\xfe\x68\x9a\x4e\x06\x52\x07\xf1\xbe\xa8\xce\xd5\xa6\x18\x76\xef\x08\x89\x78\x5e\x5b\x9d\x4d\x3f\xdc\x04\x9b\x5c\xef\x4a\x38\xe7\x3f\x50\x66\x50\xe8\xe8\x7a\xfa\xba\xc0\x11\x6e\xe2\x35\x74\x96\x98\x49\x1a\xc4\x6f\xf4\x2e\xb8\x47\xed\xbd\xf7\xd7\x6e\x07\x5a\x5a\xe1\xf2\xf2\xe7\xc0\x6d\xce\x57\xdc\x94\xee\x36\x7a\xc8\xa6\x49\xfa\x18\x14\x17\x55\x12\x71\x06\xe5\x1d\x95\x79\x76\x77\x58\x45\xd3\xa0\xc3\xf6\xcd\x82\x26\x00\xb2\xfa\xfd\xf0\x58\xc1\xe7\x5a\x60\x18\x73\x92\x7e\x7c\x12\x8a\x4f\x38\x52\xcc\x0e\x49\x09\x62\x5d\xe2\x6d\x14\x1c\x90\xfa\xfc\xcf\x71\x1d\x73\xcf\x87\x23\xa5\xc7\x1c\x92\x2c\xb7\xc2\xa1\x81\x9f\x43\x8e\x5e\x11\x31\xa9\x68\xb2\x44\x4f\x12\x2e\xa7\xe3\x5a\xb6\x9f\xb3\xe3\x7e\xa7\xf3\xc1\xfe\x3e\x49\x24\xb6\x75\xd0\xd6\x0f\xd0\xa5\xc6\xd8\x69\xc6\x92\x32\x75\x53\x22\x32\xc2\xbc\xbe\x56\x3b\x86\x6c\x1f\x20\x69\x95\x8a\x23\xa1\xfe\xc2\x2a\xed\x18\xac\xd3\x09\x14\x23\xad\xc1\xd9\x51\x59\x5c\xc3\x12\x85\x31\xa5\x5b\x8a\x52\x18\xcb\x30\x3c\x21\xc9\x15\x10\xc9\xa3\xa4\x1f\x04\x14\xb5\x30\x72\xde\x30\x8f\xf2\xf9\x1e\x7f\x15\x4f\xb2\xc0\x39\x68\xc0\x7b\x40\xc1\x70\xc4\x10\x10\x23\xc0\xef\x8b\xed\x17\xa8\xbe\x13\x5f\x7e\xe5\x88\xae\x85\x7e\xc6\x15\xa1\x39\x79\x4a\x0c\x4d\xa6\xaf\xf7\xad\x0d\xd1\xfa\xe9\x2f\xec\x4f\x6f\x3e\x99\x5f\xfe\xf1\x5a\x6f\xc6\x57\x9e\x38\x8c\x22\x88\xd1\x06\xbf\xaa\x62\xf8\x7b\x7b\x9b\x55\x28\x86\xe1\x90\x66\x91\xd2\x38\xcc\x15\xbb\x04\x98\x40\x28\x1a\xfb\x9d\xef\xe7\x6a\x7d\xf0\x0e\x24\xf3\x2b\x6e\x4c\xfe\x02\x81\x64\x15\x13\x15\xfa\xe4\x06\x2b\xd9\x49\x22\x1d\x1b\x41\xcd\xa1\xf6\xb0\x09\xc3\x70\x8e\xa5\x0e\x86\x39\x92\x79\x19\x5f\x08\xb9\x9f\xbd\x08\x45\x5e\x2a\x11\x56\x9c\x81\x71\x82\x7e\xe4\x8c\x4c\xd9\x8f\xcf\xe0\x43\x7d\xad\x6b\x30\x9a\x01\xda\x9b\x98\xfd\xa7\x4e\x05\x88\x5f\xe0\x35\x10\x84\x9e\x32\x11\x3b\x6e\x52\x3c\x15\x2c\xa4\x4c\xb0\x44\x55\xc9\x3d\xe8\xf5\xf0\x78\x8b\x48\xa2\x56\x93\x0a\xa0\x1a\xcd\x2e\xf8\xbe\x22\xf2\x22\x25\x4d\x5b\x55\xa0\xd2\xae\xe2\x64\x5d\xf1\x29\xab\xe7\xda\x3f\x7e\x2f\x09\x96\xea\xee\x71\xa7\x7e\x28\xf8\x70\x96\xc2\xe4\x66\x5a\xc1\x0c\xf1\xb7\xef\xcb\xa3\x8f\x05\x46\x95\xd6\x3f\x79\x74\x76\x99\x7f\xed\xbc\xeb\x19\xa2\x4f\x1b\xfe\x0b\xd7\x2e\x2b\x56\x77\xc0\xcb\x25\x83\x45\x31\xf1\xb3\xd4\xb6\x90\x32\x10\x5d\x5f\x19\x0e\x6d\xc5\x45\x61\xa7\xcf\x5d\x85\xc0\x90\x36\xf1\xfd\x27\xeb\x3a\x5e\xa9\xac\x38\x1b\x7a\x3d\xb0\x15\x89\x2d\xe7\x2e\x39\xaf\x34\x8c\x91\x9b\x7e\x3e\x15\x1c\x58\x3c\x60\xa7\x86\x98\xf6\x84\x90\xe6\xc8\x16\x30\x3a\x0d\x5d\xc8\xcd\x03\xdb\x94\xaf\x6c\xad\x1b\xc3\x79\xc2\x07\x14\x5b\x36\x2e\x9c\x6c\x69\x0f\x7e\x5a\x76\xf0\x83\x8a\x7f\x52\x62\xda\xe8\xab\xa4\x62\xa8\xe3\x7d\x73\x87\xf7\x3e\x9d\x4a\xe5\x32\x1c\x45\xd2\x11\xae\x57\x98\x6d\xa1\x40\xf7\x48\x13\x58\x0d\x74\x1e\xc4\xaf\x6e\xf9\xe0\x84\x5f\x9e\xb6\x96\xfd\x27\xcd\x1a\xcb\x68\xb4\x89\x8c\x19\x79\xa2\x5f\xeb\xb7\x93\x42\x5c\x62\xbf\x94\xbf\xfe\xe9\x87\xcc\x78\xc6\x00\xed\x53\xfd\x98\x25\x47\xc6\x72\x85\x97\x33\xe4\x98\x9d\x86\x6f\xe0\x02\x2d\x2f\x20\xae\x4d\xec\xdf\x6b\x20\x56\x90\x66\xb8\xdc\xbe\x67\x7e\x2c\x1a\x2e\x9b\xa0\x5d\xf5\xf6\x9e\xbf\x23\x7d\x89\xd3\x76\x89\x2b\x50\x4e\xf5\x6e\x39\x55\x18\xc9\x87\x4d\x60\x84\x22\x76\x88\x85\xb4\xbc\x8a\xe1\xad\x16\x01\x49\x4f\xc9\x2b\x2a\x03\x8c\x64\x93\x4f\xf5\x02\xa9\x15\x35\x2b\xc7\xbd\x69\xb9\xc5\x6f\x7a\xb3\xe5\xb0\x89\xb0\x60\x02\x33\x8e\x35\x55\xb9\x47\xe6\x6f\x5d\x1a\xc7\xf1\xba\x4a\x31\x4a\x76\x26\x97\xd8\xb2\xff\xa6\x09\x95\x3e\x33\x34\xde\x4a\x3b\x6b\x24\x41\x74\xa5\xaf\x95\x67\xc6\x12\xc3\x8f\xc8\xd3\x60\x7b\x73\x08\xd4\x7d\xcf\xf0\xf1\x2c\x2a\x7b\x37\x63\xc0\x9e\xc1\x87\x80\x0a\x36\x7f\x53\x59\x35\xe0\x40\x5d\x67\x16\x19\xd8\xcc\xbd\xd1\x1f\x6e\xc7\x32\x13\x6f\x31\xde\x1a\xac\x7a\xbb\x18\x04\xd6\x9a\x72\x07\x6b\x0b\x1d\xb6\x1a\x23\x28\x7f\x74\x80\xd0\x7b\x1b\xe4\x31\x0a\xe5\x1f\x00\x28\x77\xc3\x00\x53\xed\xff\xf5\xc8\xce\x73\x29\x78\xcb\x31\x89\xdf\x54\x85\x46\xe2\x4b\x83\xc7\x6c\x56\xd7\x5d\xe9\x30\xeb\x82\x44\xdb\xbc\x8f\xdc\xe1\xce\xa8\xb2\xb4\x2d\xc9\x4b\xc6\x40\x19\x41\xeb\x57\x74\xae\xe8\xfc\xa1\xcb\xeb\x0e\xed\x11\xd6\x93\xc5\x78\x93\x1c\xe5\x4b\x32\xb4\xd0\xaa\x9b\x5c\x8f\x23\x34\x38\xd3\xc2\x5d\x1e\x8e\xc2\x73\x2a\xc3\xda\x7a\xc7\x30\x43\x63\x2c\x47\xa8\x2d\x4e\x20\x1a\x92\xf7\x04\xfb\xff\x0d\x8c\x53\x20\x6b\x84\x70\x8c\x2a\x7a\x98\x24\x7d\xd3\x82\x20\x7c\xac\xe0\xf6\xaa\x02\xaa\x6b\x5e\xd5\x1c\xd1\x78\xd4\xe6\xf6\x1b\xaf\x31\x16\x46\xfa\x39\xaf\x8f\x66\x78\x91\x0b\x62\x6d\x08\xbc\x29\xc3\xb7\xd1\xef\x74\x59\x08\x5c\x7f\xfa\xe4\x30\xd5\xc7\x05\xce\x66\x69\x20\x90\xc3\x59\x2c\x11\x92\x29\x03\x26\x25\x4f\x60\x3c\x95\xff\x1e\x1c\xb1\x15\xc3\xbd\x30\x2c\x31\xe5\x10\xbb\xfe\xcf\x46\x04\xcf\x94\x06\x2d\x76\x9d\xa1\x14\x9d\x41\xcc\x43\xad\x93\xa0\x65\x48\x3c\x7f\x14\xd3\xcf\xc9\x22\x35\x33\xaf\xb6\xf4\xc4\x33\xc7\xb6\x55\x7a\x34\x97\x51\xe8\x69\xa4\xfc\x5c\x0f\xaf\x54\x58\xbb\xa4\x12\x93\xe9\x37\x5a\xb4\x3e\x43\xcb\xef\x7b\x30\xd2\x25\x42\x36\x65\x4b\xe6\xf7\x2a\x14\xaf\x1a\xeb\x30\xc0\x88\xa4\x18\xde\xb5\x10\xc5\xf4\x24\x73\xd8\x32\xff\xdc\xdf\xd0\xea\x8c\x14\xb1\x56\x5d\x9a\x03\xfd\x71\xbf\x79\xd7\xb8\xc3\x6c\xc2\x96\x11\xd5\xbe\x4b\x37\x14\x77\xd0\x07\x15\x26\x9f\x0e\xa1\x42\xf6\xa1\x33\x04\x36\x38\x6b\x03\xaf\x76\x8e\x00\xe9\xa1\xf1\xd4\x5a\x67\x0e\x39\xa5\x82\x8b\x23\x9c\x0f\x05\xca\x82\x24\xaf\x99\xb9\x15\xfe\x70\xb6\x39\x27\x00\x0a\x1a\x9d\x57\x71\xc8\x27\x82\xb3\x47\xfc\xb7\xc5\x4f\x2d\x62\xeb\x10\x6d\x5c\x29\x0c\xd5\x26\x0c\x6e\x28\xe2\xe5\x6f\x24\x2c\x39\x3f\x5e\x03\x3f\xac\x05\x0e\x56\x80\x48\x05\x2b\x21\xb7\x9c\xa2\x53\x03\x18\x9d\xc4\xd3\x87\x97\x41\x3d\x82\x04\xb3\xf4\x2d\x27\x3f\x45\x8c\xdb\xd1\x67\x80\x18\x4d\x81\x61\xfa\x56\xd0\x1a\xc0\x98\x8a\xe2\x35\x2c\x2a\x3b\xb7\x95\x3e\xe1\xec\xa9\xda\x7f\x73\xe4\x74\xfb\xe7\xc7\xe1\x1f\x0e\x1d\x37\x3a\x04\x4b\x1a\x8b\xde\x0c\x03\xfd\xed\x9b\x13\x93\x6e\x51\x41\x7d\x82\x54\xc3\xd8\xd8\xbf\x62\x24\x25\x54\xff\x16\x77\x5e\xc2\x78\xb9\x8d\x9e\x7e\x06\x40\x6a\xb3\x52\x01\xd5\x3c\xe1\xa0\x7f\xb0\x5f\x3a\xcf\x2a\xcb\xce\xb0\xb2\x5c\xf7\x6b\x43\x4c\x38\xa7\x7f\x6a\xfd\xef\xa5\x1d\x7d\x15\xd9\x82\x6c\x9d\x8e\x3f\x08\xf1\xfe\xaa\x29\x5e\xc4\xee\x40\x24\x66\x9f\x5d\x6d\x29\xdc\xd5\x54\x0c\xaa\xd6\xb4\xf9\xb0\xae\x8a\xe3\x85\xce\xfb\xc3\x2d\x8a\x29\xd7\x5e\x22\x4c\x84\xab\xec\x4f\xa5\x4d\x49\x8c\x4f\x6e\xf7\x1e\x6a\x03\x76\x6a\xce\x09\x74\x1a\xa0\xf6\x31\xdd\x91\xa4\xe1\x27\x39\xbb\x46\xf8\xe7\x41\xbb\xfe\x7f\x76\x74\xb9\xad\x34\xfa\x38\xad\xf5\xa1\x8a\x87\xe5\x11\x73\x04\x48\x18\xfa\xd2\xbf\x99\xb1\x20\x53\x86\xe5\x0d\x9f\xa7\xf1\x9e\xfc\xcc\x94\x7d\x86\x6d\xa7\xc7\xc0\x5d\xa0\x9f\xe2\x62\x81\xeb\x06\x18\x45\xc0\x51\x0b\xaf\xc7\x75\xbe\x5e\x0b\x95\xa6\xcc\x49\x45\x8d\xb1\xd6\x82\x43\x58\xe2\x7e\x12\x67\xf1\xfb\x0f\x26\x04\x86\xe3\x5d\x94\x5e\xab\x12\x90\x71\x10\x9c\x58\x1a\x94\x42\x8d\xc5\xf2\x07\x45\xa0\x82\x9d\xfe\xdd\x6f\xde\xf5\x85\x5f\x07\x44\xb6\xec\x49\xa2\x4d\x4d\xea\xb7\x2d\xcf\x37\x7a\xc6\x75\x80\x79\xd9\x52\x61\x1e\x5a\x9d\xb0\x61\xec\xae\xa8\xb6\xca\x33\x3f\x3a\xaa\x00\x3d\x75\xfb\xef\x1c\xd4\xe1\xf3\x9d\x59\xf7\xd0\x88\xf8\x79\xee\xf8\xba\x6a\xd7\x1d\x20\xc9\x05\xf1\x87\xfb\x5c\xea\x61\x90\x1f\xd3\x1b\x52\x07\x98\xcc\x08\x06\x6b\x0f\x4f\x6d\x78\xe0\xe7\x75\xab\x8b\x56\x05\x5d\xe2\x24\x48\x6e\x54\xdb\xee\x7d\x84\xa5\x06\xd0\xe1\xd9\x31\x7f\x53\x99\xff\xeb\xf6\x9a\x66\xca\xe2\x58\x0e\xf8\xe9\xdf\x0d\x5c\x47\xf1\x4f\xc3\x95\xfe\xd3\xaf\x35\x8a\x39\xf2\xa2\x60\x2a\xeb\xb2\x6c\x3f\xc4\xce\x25\x51\x52\xb1\xc5\x4c\xc7\xb3\x37\x36\x86\xfa\x10\x87\x47\xea\x19\x08\x92\xae\x30\x45\x81\x3b\x6a\xd1\xc9\x9a\x8c\x43\x6b\xe7\xc3\x3b\xd1\xd3\x57\xe7\x2f\x26\x68\xc1\x65\x22\x96\xf9\xeb\x7b\xc2\xf0\x78\xf9\xe4\x5f\xe8\x31\xc2\xe9\x6a\x4f\x60\x67\xf6\x70\x51\x54\x55\x3c\x1b\x91\x1d\x40\xeb\x19\x69\x52\x70\xe8\x1e\x52\xfd\x0e\x44\xfb\xbf\xd9\x99\x32\x6d\x9c\xa3\xaa\xad\x62\x3a\xe3\xc5\x71\xe5\xda\x9d\xea\xd5\x15\xa6\x41\xbd\xa6\xed\x9a\x2e\x3b\x39\x5d\xd6\x24\x89\xb1\x46\xc6\xc4\x23\xe5\x9d\x54\x3e\xa3\x72\xea\x5c\x5d\x64\x53\x8e\x3a\xb4\xea\xab\x02\x52\x99\x17\xd7\x84\x9d\x2f\xe9\xed\xfd\x07\x77\xf6\xc7\x67\x38\xfe\x16\xd5\xa8\xd6\x7c\x8f\x00\xe3\xea\x2c\xd7\x95\x84\x1f\x38\x2c\xdd\x31\x84\xcb\x18\x05\x28\x9b\x65\x74\x36\x11\x19\xa7\x31\xfd\x13\x01\x2c\xdb\x1e\xd2\x8f\x58\xdc\x24\x7a\xf7\x55\xbb\x36\xb7\x03\x68\x82\x56\x4b\x50\x98\x04\x7b\x78\x9f\xd2\xb8\x4e\xcf\xfb\x38\xfd\xdf\xeb\xad\xec\x25\x95\x38\xee\x9a\x03\x23\x92\xe3\xfd\x7d\x79\xc0\x65\x7e\xe7\xd2\x68\x3c\xc9\xee\xf9\x33\x2d\x51\x08\x42\xb1\x6b\x7f\x11\x84\xa1\x26\x59\xf6\x20\xbf\x83\xaa\x42\xa6\xa9\xad\x41\x25\xa4\xe4\x30\x7a\xda\x5f\x94\x8a\x11\xaf\xfc\xdc\x50\xb0\x5c\x02\x6f\x38\xa9\x60\xf3\xf3\x45\x34\xa0\xc8\xe9\x3d\x8a\x87\x22\x0e\x17\x5c\xc5\x65\x9e\xc9\xf8\x3f\x9c\x3a\x67\x15\xc6\xb9\xad\x3f\x9a\x21\x34\xd5\xd9\x54\x17\xb6\xc4\xa1\xc9\x8f\xc3\xf0\x48\xba\xbf\xfc\x1f\xdf\x91\xaa\x02\x86\x61\xc0\xa0\xc4\xaa\xf4\x24\x84\x01\xf5\xc8\x11\xba\x04\x7f\x01\x5c\x04\xf8\x14\x90\xc6\xdf\x4b\x2d\xb6\xbe\x45\x84\x79\xed\x0a\x21\xd3\x47\xa7\x75\xce\x94\xbb\xc0\x9b\xd5\x3c\xaa\x61\x08\xc8\x2c\x99\xb4\xd1\x09\x55\x4b\x7f\x99\xae\xd1\x6e\x1b\x5b\xd0\x1e\x9f\xd1\x16\xba\xdd\xc5\x25\xd4\xa2\xb0\x9a\xb0\x55\x7f\x17\x9c\x55\x3d\x55\x83\xa2\x16\x32\xbb\x00\x71\x47\x64\x85\xa5\x21\x37\xd4\x5b\xe4\x0b\x6d\xe3\x5c\x78\x6c\xec\xe0\x5e\x41\xc9\x55\x6b\xe3\xb1\x91\xc1\xd6\xf1\x4a\xe7\xea\xe9\xc3\x7b\x66\x9f\x0d\xe7\xfe\xca\x52\x13\xee\x5a\x9f\xd0\x9d\xb2\x0b\xd9\x85\x54\x49\xb0\x53\x5f\x4f\x9b\x02\xc8\xd4\x05\x1a\x9f\x9a\xf1\xec\x45\x61\x18\x96\x17\xf6\x35\x08\xb1\x09\x33\x2a\xa0\x5c\xc9\x87\x11\xf6\x98\x77\xef\xb1\xac\x80\x14\x4e\xc6\x27\x10\xe6\x48\x57\xfb\xeb\x3a\xaf\x07\xec\xfe\x99\x07\x6b\xba\x1a\xeb\xc5\x31\x2a\x88\xd8\xc2\x89\x7f\xe2\x23\x42\x6f\xd9\x4a\x2c\xb6\x7a\xb9\x29\x2c\x6d\xe1\xa2\xf4\x7e\x3e\xd9\xbb\x51\xbd\x87\xbb\x42\xa7\xfe\x9e\xcb\x9a\xa1\x28\x10\xdf\xc9\x86\xbd\x3d\x0c\x5c\x3f\xe4\x98\xf9\xdb\x63\xd5\x7e\x4a\x76\xb9\xa7\xee\xe6\xe2\xc7\xfc\x04\x67\x20\x82\x7a\x2a\x87\xf0\xe5\xe5\x97\x4c\x8b\xae\xdf\x6a\x5c\xc2\xa3\xe6\x3e\xdd\xd6\xf0\xb7\xe7\xa5\xeb\xc0\xa4\xa5\xbf\xe2\x66\xe2\x5f\x13\xc5\x72\x87\x12\x70\x2a\x75\xcf\xa3\x12\xaf\x73\xa8\xfd\x61\x9c\xa3\xa6\x46\xeb\xc7\x86\x8c\x81\xa9\x2a\xfe\x47\x46\xd5\xd2\xdf\x19\xa4\x6e\xfa\xd4\x78\x91\x97\xeb\x60\x6d\x6f\xae\x24\x27\x11\x86\xd8\x4a\x3a\x32\x09\xbf\x43\x40\xdb\x3e\x94\x18\xff\xbc\x7f\x3a\xff\x68\x5d\xa0\xc2\x6c\x53\x03\xe1\xb7\x20\x03\xf1\xa9\x8d\x1b\x52\x04\xad\x6c\xbf\xbe\x64\x7c\xde\xd0\x82\xc1\x75\x33\x5d\xf2\xa1\x9f\x01\x47\xfd\x32\x2f\xe5\x82\x5b\x9d\x8e\xec\xad\x96\x78\xc4\xbe\xe0\x32\x6f\x7f\x23\x61\x39\x98\xe3\xb2\xef\x9d\xc6\xf2\x15\x26\x11\xb0\x0d\xdc\x2a\xa0\x4e\x00\x1b\xc1\x98\x96\x31\x86\x3a\x44\xd2\xb7\x16\x88\xe6\xba\xca\x0f\x23\xad\xd5\x1b\x0e\xbf\x25\x64\x92\x1c\x46\x61\x95\x44\x81\x2c\xd7\x72\xdb\xdf\x3b\x40\xc3\x93\xe8\xf2\x24\xcf\x6d\x11\x50\x8b\xa7\xd8\xca\x06\x01\x02\x16\xe7\xa4\xde\x55\xb6\xd4\x61\xe0\x2a\x76\x19\xa3\x9b\xfa\x9f\x0b\x31\xa0\x35\x55\x6a\x55\x2f\x3f\x38\x84\x20\xb9\x72\x54\x7d\xf1\x10\x7e\x10\x74\xe9\xdc\x83\x6d\x43\x6e\x52\x3f\x52\x09\x44\x7f\x4e\xd5\xbb\x8a\xf3\xec\x94\xee\xa9\x02\xec\x1e\xdc\x41\x15\x2c\x26\x89\xa4\x13\xa5\x70\x1b\x64\xae\xf3\xe4\x17\x66\x2b\x2d\xf4\x64\x77\x9b\x02\xe3\xb3\x82\x49\xb4\x90\x69\xed\x10\xbf\x39\xcc\xe3\x37\xe3\xa6\x3b\x3a\x18\x37\x53\xa6\x80\x47\x78\x9f\xda\xdb\x2f\xe6\x72\x18\x49\x7f\x87\x70\xf2\xea\x57\x17\x77\xf7\xd9\x67\x5d\xd5\xca\x9b\xa6\x73\xf5\x22\x74\x6f\x27\x86\x8c\x92\x28\x40\x2c\x30\x8a\x9a\x9c\xc2\xcf\xc2\xbc\x51\x74\xa1\xc4\x53\x05\xf4\xb8\xf4\xa1\x85\x3c\xf3\x0b\x0d\x37\xd2\x07\x84\xff\xe7\xf2\xd6\xe2\xf6\x94\xd7\xd3\x4e\x39\xc7\x1d\xd0\x86\x69\x0a\x08\x32\xbb\x53\x91\x22\x28\x42\xbc\x5a\x7c\xe3\xa0\xa8\x87\xf1\x28\xe8\x5f\x02\xb6\xb7\x7b\x3b\x64\xda\x7c\x2a\xe8\xb2\x84\xae\x3a\xed\xba\x02\x83\x5b\x02\xe0\xfc\x01\x02\xfa\x7b\x9c\xdb\x46\x5c\xe5\x37\xdf\x39\xe4\xf7\xb9\xe5\x0d\xb8\xe5\xca\x62\x1f\x25\x25\x82\x38\xb8\x5c\x0b\x5a\xe5\x04\x8d\x8d\xd7\xdc\x48\x05\x54\xdc\x9b\xec\x04\xa7\x59\x32\x78\xb3\xcb\x3e\x23\x3a\xe0\x7f\xb0\xfc\x8c\xbf\x1c\x28\xcb\x47\xe7\xae\xc8\xdc\xa1\x11\xc2\x7d\x55\xf8\x44\x9b\x51\x92\xbf\xb1\xe5\x27\x57\x14\x60\xcb\xda\xdb\xcf\xae\xf9\x35\x20\x78\x7d\xf3\x08\x85\xa2\x9b\x1a\xa3\xff\xa8\x0f\x80\x47\xe1\x90\x97\xb6\x9c\xdb\xcc\xdf\x1a\x12\x83\x4d\x89\x38\x22\xb2\xc2\x1a\x83\x49\xb8\xa0\x90\x57\xf0\x3f\xda\x77\xa1\xc9\x27\x0a\xf0\x36\x1b\xdc\x9b\x67\x0d\x2f\x96\x1a\x34\x4a\xcd\x42\x83\xc2\xf1\x62\xc2\x5c\xa6\x66\x9e\x87\x2e\x11\xd8\x6c\xa1\xc5\x81\x12\x9a\xec\xe4\xfd\x9a\x3b\xbf\x5d\x0e\xdb\x26\x55\x75\xa5\xd5\xf4\x9f\x13\xab\x10\x44\x67\x3a\x5a\x9d\x9b\x8b\x47\x01\x95\x08\x66\xad\xa3\xc0\x0f\x9f\x2e\x4f\xf0\x2e\x0f\x5b\x5b\x77\x86\x76\x90\x22\xc2\x10\xf7\x22\xd1\x28\xc1\x2a\x0d\xb5\xb2\x90\x44\x88\x96\x7c\x01\x61\xb1\x1f\x64\xfd\xc1\x74\x5d\xcf\x8e\x44\x3b\xf5\xa8\xec\x8e\xcf\x1d\x4e\x2c\x53\x25\x0c\x20\x6f\xc1\xa3\xfe\x99\xef\x93\x48\x2c\x7e\xfa\xbd\xaf\xce\xaf\x0e\xe4\x54\xda\x34\x3d\x99\x5e\x2e\x7a\x75\x16\xba\xe9\x4e\x0f\xfd\x06\x6b\xa4\xe0\x2c\x18\xee\xbe\xa7\x7a\xef\x90\x91\x14\x12\xf5\x8c\xc2\xdb\x12\xfd\x64\x25\x01\x3c\x6e\x7d\x79\xc8\x16\x46\xc1\x88\x4d\x06\x58\xbf\x7c\x97\x49\xa6\xb9\x2c\x7c\x80\x63\xae\x8d\xdb\x32\xc8\x42\x6f\x58\xca\x50\x62\x10\xa9\xd1\xb1\xf3\x0c\x6f\xa0\x2c\x34\xe1\x8c\x8d\xf3\xa5\x68\xf4\x91\xbf\xa4\xff\xc9\xfb\xc6\xf6\xb1\xd6\x78\x73\xe5\x50\xb7\x6d\xb4\x36\x83\x78\x70\xc2\x73\x58\xb1\x43\x99\xe0\x17\xd8\x9b\x45\xb1\xcb\x2f\x9f\xbb\x1d\x18\x3d\xbe\xba\x9b\xdf\x5c\x25\x5d\xf1\x66\x4d\x27\xb9\xff\xee\x7f\xcf\x86\x79\xfb\x45\x4f\xda\x16\xf4\x68\x1b\x6a\x6d\xed\x5d\x49\x8c\x4e\x81\x37\x09\x9c\xc7\x54\x91\x22\x0e\xbd\x65\x28\xc3\x71\x79\xa3\x3a\xa8\xf2\xfd\x9d\xb3\xa0\xa7\x15\x97\xe2\x84\x58\x0a\x4b\xb1\x13\x27\x0c\x5f\x6a\x58\x91\x85\x13\xca\x76\xb5\xe2\xcf\xc3\xf6\x34\x59\x96\xaa\xb9\xf3\xab\xa6\x2b\xf9\xd5\x53\x2d\x18\x89\x90\x41\xcd\x4b\xdd\x4a\xec\xa8\x81\xa3\xfa\x9c\x64\x92\x4d\xd3\xa2\x94\x0d\x73\xd0\x3e\x57\x8c\xab\xf6\xc8\xfc\xb5\xe0\x2f\x43\x48\xf4\xd6\x91\xef\x4a\xc9\xce\x2b\xda\xd8\x08\x35\x80\x92\x32\xb0\x73\xa3\x6d\xd2\x38\xe5\x5f\x59\x78\x0a\xd0\xd2\xe0\x05\xa2\x1d\x9c\xd5\x77\xf5\x0f\xdf\x7a\x5a\x50\xef\xbe\xc9\x20\xa9\xb9\xc2\x90\x65\xed\xbc\xfe\xd4\xaf\x98\x1f\xa6\xfb\xea\x3e\xbc\x52\xfb\x8d\x24\x7a\xcd\xd4\x9b\x97\x8d\xd0\xcc\x2b\xf8\x82\x8d\x64\x70\xc9\xc3\x68\xfe\x61\x25\x7b\x54\x42\xb8\x5b\x82\xc7\x2e\xb4\xfd\x9c\xc9\x55\xc7\xd6\x5e\x0b\xc5\x43\xa2\x1d\x20\x03\x43\x78\x9f\xfa\x0b\x2d\xc7\x1a\xb5\x70\xb6\xa9\x99\x7a\xc3\x18\xa5\xea\x29\x45\x65\xe5\x6a\xc6\x7d\xeb\x4d\xbe\x3a\xf4\x3b\xdc\x3f\x9e\xc3\xb6\x80\xeb\x4a\x1c\xc3\xbd\x48\xa1\x0d\x49\x93\xc6\x9a\x77\xaf\x63\xd7\x2d\xa4\x16\x4b\x38\x85\x54\x3e\x76\x12\x8c\x56\x70\xb0\x4a\xfc\xc3\x17\x55\xce\x5d\x7a\xa4\xa8\x0c\x4c\x10\x20\xd4\x4f\xa3\x60\x40\xc1\x09\x99\x8c\xd1\x57\xdb\x36\x6c\x1b\xff\xdc\x02\x62\xd2\x3d\xea\x82\xcb\x11\xa2\x22\x40\x53\x15\x8f\x83\x94\xfd\x9d\x63\x21\x41\x1c\x99\x4d\x01\x05\x4d\x0c\x82\x19\xa4\x89\x8b\x29\x1f\x69\xee\x14\x68\xbf\x94\xca\xb5\xe6\x92\x71\x05\x1a\x21\x74\x48\xbd\x68\xb1\x3d\x36\xd1\xad\x54\xd7\x17\x0c\x07\x00\x2d\x2d\x96\xeb\x98\x18\x0a\xa8\x80\xf7\xef\xfd\x4d\x5a\x37\xcc\x4f\x65\x2a\x96\x6a\xca\x87\xc4\x88\xe2\xea\x1c\xc5\x15\x50\x4b\x02\xcb\x4b\x91\x81\x17\xc9\xbe\x2f\xad\x71\x87\xf2\xa7\x75\x25\x56\x6b\xfa\xa3\x6a\x13\xf7\x9f\x73\xf8\x91\x4f\x70\xb8\xc6\x0b\x12\xc3\x21\x62\xf4\xae\xb3\xba\x71\x5a\xb2\x38\x00\xf0\xaf\x9a\xfc\x65\xbe\xe3\x35\x0c\xbc\x51\x92\xa5\x74\x3e\x75\x99\x21\x26\x87\x90\xda\xe8\x78\xda\x04\xae\x36\x16\x1f\x25\x67\xe5\x14\xe6\x6b\xf4\xb4\xfe\x7a\xde\xe9\x95\xa8\x15\xbc\xf6\x04\x51\x83\x04\x9f\xc7\x2d\xb7\x87\xcd\x71\xf0\xf6\x53\xf7\x0d\x1f\xdb\xc2\xaa\xfb\x1d\x5e\x1d\xcf\xd5\x76\x3f\xf5\xfd\xd3\xbf\x54\x54\x26\x38\xfa\xc1\xb1\xfe\x6c\xca\x7e\x5e\xa8\x87\x28\x2f\x8d\xce\x22\x94\x19\x99\xba\xc3\x5a\xed\x8e\xa2\xc0\xec\x31\x88\x29\xb5\xc3\x44\xd1\x95\x06\x9d\x14\x27\xc6\xd1\xef\xeb\x79\x5e\xe3\xea\xb0\xef\x93\x17\x36\x12\x7d\x91\x0a\x60\x21\x41\xa4\xc6\x28\x70\xae\x71\x77\xff\x8e\x8a\x44\x14\xba\x6c\x96\xfe\x8f\x0d\x98\xe3\x07\x1e\xa4\xf5\xed\x57\x68\x2d\x81\xea\xc5\x43\x9a\x45\xe2\x66\xec\x1a\x25\xd2\xe6\xd9\xc1\xd2\x16\x4b\x70\xc1\x27\x50\x21\xb8\x37\x4e\x6d\x4d\x34\xff\x68\x44\x30\x2a\xa2\x56\x26\x44\x53\xe1\x86\x6d\x9e\xcd\x63\x5d\xd3\x92\x6d\xea\x1a\xd0\x51\x13\x21\x5a\x44\x81\x75\xf4\xd2\x6b\x23\xf8\x71\x5b\x91\x02\xd4\x1b\x35\x77\x6d\x5d\x06\x93\x26\xc8\x7c\xfb\x25\xc2\x6b\xd3\x6a\x17\x67\xfa\xd5\x4f\x53\xe3\x53\xf7\x60\xef\x8d\x87\x34\x53\x5e\x2d\x0b\x4b\x86\xbe\x9d\xb4\x36\x8c\x28\x56\x6d\x3c\x30\x74\x04\x68\x12\xd0\xda\x7b\x9f\x3a\x7e\xaf\x8c\x7b\xae\xe5\xa1\x06\xf9\x85\x1b\x40\x99\x04\x91\x2e\xdc\xdc\xe2\xab\x23\xff\xf8\x13\x33\x6a\xa4\x0e\xad\x05\xaf\xe3\x4a\x42\xb3\xd3\x98\x3a\x2a\x62\xe6\xbf\x31\x43\x62\xef\x7c\x9b\x28\x6c\xe8\xe3\x35\x74\xb5\xba\x65\x0d\xf5\xb4\x20\x8e\x48\xf3\xa2\x88\xc2\x19\xca\xcc\x5e\x4a\x5f\x5b\x51\x1b\xc2\xd0\x38\x90\x51\x27\x70\x62\xb6\x7e\xb1\x04\xcc\x62\xcb\x96\x10\xa5\x1c\x73\x47\x40\xbb\x2c\x26\x49\xb6\x06\x04\x6a\xc5\x76\xdb\x09\xf8\xc3\x2d\x78\x2d\x97\xc3\x86\xd0\xc7\x16\x92\x0d\x03\x2a\x26\x70\x43\x5c\x2e\xc7\x3f\x3b\x03\xac\x38\x60\x1c\xf4\x16\x45\x2e\x1c\x9e\x7c\xe4\xce\x34\x2d\xcd\x69\x29\xc2\x75\x81\xde\xb2\x34\x23\x14\xc7\xb0\xc2\x80\xd7\x26\x60\x19\xa1\x2f\x41\x65\xfc\x54\x5c\x18\x93\xc0\xd1\xdf\xea\x74\x6a\xd6\x91\xd3\xec\x40\xd3\xa3\x40\x4b\xb4\x65\x77\x2a\x43\x2a\xcb\x6e\x92\x3d\xb6\x1b\xb0\x02\x57\x3f\x32\xa8\x84\x9b\xc3\xa8\xd2\x7d\x8a\xee\xae\xeb\x96\xea\xbf\xfd\xf7\x6f\x8b\x0d\xbc\x33\xde\x23\xdf\xe2\x6c\x1f\x1e\xfb\x77\x34\x8b\xe1\xbc\x60\xa4\x87\x88\x3d\x19\x0f\xaa\xea\x44\xc7\x6d\x34\x99\x6e\x79\x89\xf6\x9a\xf5\x68\xab\x3e\x1d\x4e\x6d\x2d\xc6\x0e\x4d\x18\xcc\x5d\xab\xb8\x9d\x94\xe9\xd5\x94\x5a\x69\xa0\xe3\x31\xa7\x12\x68\xf4\xfa\xf6\xb9\xfd\x7e\x24\x4e\xf9\x2e\x8a\xd4\x74\x97\xec\x99\x62\xbb\xa7\x4d\x2b\x5d\x88\x78\xba\xfb\xa7\x18\x74\x1a\xef\x81\xba\x4d\x02\x68\x72\x16\x2c\x55\x83\xb1\xd9\x5e\x45\xf8\x8b\xd2\x6f\x61\xa6\x7f\xd1\xea\xe6\x63\x42\x8d\xbd\xd2\xc8\xdf\x31\xc2\x56\xe7\x2a\xcf\x9e\x49\x97\xfd\xe6\xfd\x60\x68\x09\x87\x25\x15\x84\x39\x6a\x9a\x69\xe3\x02\xbe\x90\x40\xe4\x50\x46\x12\xcb\xba\x29\x48\x89\xbb\xf1\x1e\xce\x57\x12\xff\xe5\xc3\x0a\x63\x2c\x87\x38\x43\xed\x8e\xcb\xbd\xec\x17\x3a\xd6\x6d\x64\x3b\x3b\x1c\x11\xf3\xa5\x10\x57\x33\x50\x00\x68\x4e\xf9\x44\xee\x10\xf5\x8f\xd0\xf1\xf0\x9e\x3b\x1f\x22\x48\xad\x74\x89\x27\x6f\xfc\x8c\xf2\x1f\x08\xf8\x59\x0c\x58\x24\x3e\x60\x6d\xfa\x24\x0f\x30\x66\xbe\x49\xc2\x2b\xa1\x91\x5b\xd5\xfb\xc3\xc9\x2f\xc9\x3e\x27\x68\x54\xc2\x69\xc7\xdc\x3a\x2d\xda\x51\xda\xfb\x36\x2e\x6e\xc3\x5a\x60\x0d\xb3\xe5\xdd\x0f\x8d\xe4\xd3\xed\x6c\x7d\xf9\x42\xc7\xaf\x47\x3c\x40\xc1\xa8\xb6\x77\x31\x59\xb0\x0c\xb3\x71\x19\x26\xd5\xa4\xce\xc5\xa8\xd2\x8e\x97\xe0\x61\x20\x0b\x5a\xfa\x6f\xec\x89\xe9\x04\xbe\xf7\x85\x42\x0a\xad\xb3\x98\x20\x8d\xc2\xfa\xb8\x7f\x3c\x56\xe5\x53\x58\x5a\xe0\x3f\x58\xf6\x45\xd9\xb0\x1a\xb2\x97\x78\x29\xc0\xbc\x16\xf4\x54\xa6\xb0\x99\xbc\x07\x42\x84\xa7\x58\x1f\x55\x41\x0b\x29\x0f\x91\xd8\x81\x3e\x18\x43\xbf\x5b\x54\x52\xe0\x77\x2f\xd7\xc3\xf3\xac\x55\xc6\x37\x89\x8b\xdc\x07\x33\xa5\xe7\x9c\xc5\x93\xc9\xe0\xe0\x5c\x27\x3a\xed\xb3\xe2\x76\x20\xbf\xb7\x82\xdb\xa3\x98\x22\x08\x8e\x29\x40\x24\x35\xa9\xba\x37\x6f\x7d\xde\x4d\x12\xeb\xf1\xff\xe4\x9a\x15\x54\x88\xfd\x07\xf8\x76\x22\x87\xdc\xe4\x8c\x5a\xff\xcc\xe0\xf1\x2d\x99\x5e\xfa\xb7\xb0\xf9\x95\xfb\xd1\x2b\x96\x13\xde\xb4\x27\x58\x69\x29\x07\x1d\x41\xf8\x01\x52\xfc\x80\xfd\xae\x9b\x72\x89\x3f\x84\xc6\xb1\xe1\xad\xd3\x2d\x06\xde\x4f\x06\x7d\xdf\xce\xd9\xb0\xa9\xbb\x9f\x68\x18\x62\x7d\x3d\xaf\x98\x76\x28\x88\x14\x4c\xe5\xdf\x7b\xd1\x64\xe2\x94\x79\xfa\x4d\xbb\x08\xa7\xe9\x47\xc3\x8d\x14\x24\xd5\x50\xe7\xe2\x5e\xea\x0b\x89\xc1\xd5\x8c\xf3\x47\xaf\xa7\x9c\x54\x7d\x64\x01\xa0\xfe\xec\x9a\x68\x67\x7d\xcb\xe7\x3e\xf3\x5d\x18\xe8\x06\x65\xac\x54\x81\x3f\xa3\xb0\xe8\xe7\x34\xb1\xe4\x6f\x3d\x14\xa3\x6b\x6c\xcc\x25\x9b\xd6\xce\xb3\x2e\xf3\x5a\x2a\x23\xbf\x16\xd8\xf8\x13\x9c\x51\x9b\xbd\xcf\xe0\xac\x1b\xce\xc7\xd6\x34\x67\xc2\x66\x21\x7d\xea\x77\x4a\x94\x56\x50\xd5\xd9\x5e\x38\xc3\x9b\xfc\x2d\x28\x75\xc7\x49\xc7\xfd\xa2\x39\xf1\xe4\xab\x01\x76\x60\xf3\xc3\x8f\x97\xf5\xb8\x7e\xbf\x48\x03\xb5\xcd\x42\x81\x3a\x57\x60\x6b\x8d\x02\x49\x86\xa9\x5f\xe2\xa3\x4b\x05\xb5\xf1\xc7\x7c\x6a\xc8\x5e\x3e\x76\x38\xea\xac\xd1\x5f\x79\x2c\x63\x38\x63\xb5\xf3\x9f\xe2\xe5\x5e\x08\x21\xeb\x44\x14\xaa\xd3\x7e\xb0\xab\x16\xbf\x3d\x16\xb6\x27\x58\xfc\x8a\x35\xc5\xe4\xa0\xc8\x36\x34\x01\x83\x71\x40\x98\x19\x4d\xb6\xe3\xc7\x4f\x20\x90\x80\x69\x4e\x59\xc7\x68\x6c\xe1\x7d\xbc\x14\xa6\xb6\xab\xc1\xb1\x6b\xc2\xcf\x12\x68\xfa\xfb\xcc\x35\x21\x68\x27\x05\xd6\x57\xa2\xea\x97\x53\x0c\x6e\xf0\x74\xe2\xb8\x7b\x9b\x05\xea\x5e\x10\x6a\xad\xb6\xed\x9a\x57\x8c\x53\x47\x0e\xee\x9e\x75\xf6\xd1\x52\x0a\x9f\x73\xe0\x67\x41\xd1\x0a\x2b\x27\xc9\x53\x67\xac\x97\x29\x29\xbf\x7f\xeb\x0d\x58\x86\x6e\x59\x15\x1a\x09\x74\x48\xcb\x90\x88\x03\xa2\x6e\xd9\xde\xd9\x0c\xa2\x12\xbb\xdc\x55\xa4\x30\x26\x7e\xd3\x71\xa3\x9b\xfe\xa2\xb9\x57\x3f\x66\xd3\x53\x54\xbd\x83\x5d\xdc\x82\x57\x99\xf3\x5a\x18\x75\x1c\x4b\xfb\xcd\x8d\x2e\x40\xf9\x92\x28\xb0\x76\x75\xec\x90\xa7\x7c\x7f\xae\x55\x30\x95\xd1\x7b\x93\x32\xdd\x7f\xa2\x92\x89\x87\xc4\xc4\xb9\xb4\xdd\xda\xf9\x06\x6d\xbb\xe8\xdc\x3d\x53\xf9\x20\xc2\x70\xac\x2e\xf3\x38\x04\x98\x4d\x1c\x63\x23\x76\xc7\xd3\x87\xdf\x28\xea\x03\xee\x0b\x84\x61\x1c\xbf\x68\x6b\x6f\x5e\x69\x6f\x28\x2e\xe0\x1f\xf8\xb7\xd6\x52\xe1\x76\x05\xb7\x1e\xd6\x89\x71\xd5\x0b\xc5\x70\x5a\xe3\xc8\x8c\x52\x05\x0e\xf6\xd0\xd0\x1e\xd9\x22\xe9\x24\x06\x43\x11\x58\x43\xe7\x8a\x1d\x19\xa2\xac\x9d\x9e\xa5\x85\x4d\x55\x4a\x88\x9a\x94\x42\x29\xe2\xc2\x87\xa0\x6f\x39\x03\x14\xb7\x77\xda\x4b\x98\x69\xc3\x14\x84\x7f\xe9\xaf\x5e\xf1\x76\xd2\x38\x16\x23\xe9\x5b\x94\x89\x3e\x24\x55\x17\xfd\x19\xea\xcc\x40\xcc\x85\xe7\x09\xbf\xef\xe3\xbb\x10\x2a\x84\x27\xd4\x00\xe9\x70\x8b\xd5\x9c\xab\x0a\x55\xd9\x27\xf5\x48\x14\xff\xee\xed\x30\x68\x5b\xc8\xa5\x6f\xf7\xb6\x3f\xa1\xae\x47\xdf\xa8\x67\xe5\x74\x0c\x30\x09\xea\x64\x1b\xa4\xe0\xa9\x80\xca\x66\x64\x43\xf0\xe4\x21\xa4\x23\x71\xda\xa0\x4b\xc5\x7f\x5f\x7d\x95\x86\xbe\x4d\xcd\x1d\xe7\x20\x31\x0a\xc2\xd3\xc8\x44\x7e\x75\x71\x03\x50\x68\x8d\x75\x07\x5b\xa1\xa0\x99\x04\xe8\xd1\x81\xd7\xe3\x72\x3f\xff\xb1\x7f\xa5\x1e\x0b\x89\x8b\xd9\xaf\xc8\x93\x89\x0f\x6a\xf7\x3d\x33\x82\x53\xdb\x37\xe1\xb8\xbf\x95\x3c\xe9\xf2\x8a\x5e\xb0\x65\xc7\xa2\x32\x86\xf3\xea\x80\x20\xaf\x7a\xb1\xc1\x4a\x67\x09\x20\x3f\xef\x51\xa4\x22\x89\x73\x59\x73\xc1\xf9\x5b\xef\x2f\x30\x08\xb7\x05\x0e\xd8\x5a\xed\x4f\xe9\x27\xd8\x71\xd9\xc8\xee\x07\x63\x15\x9e\xa3\x45\xe6\x1b\x0f\x78\xd0\x2d\xd4\x46\x82\xa9\x27\x6f\xcb\x09\x48\x6f\xf2\xdd\xf8\x07\x6a\x9b\xe6\x65\x14\x77\xec\x62\x0a\x07\x22\xba\x7b\xb3\x9b\xa4\xf5\xa4\xad\x07\x9f\x83\x72\xf3\x92\xb7\xa6\xd3\x54\x59\x13\x63\xbf\x14\xcc\xaa\x24\x42\xae\xc4\xb1\x69\x81\x7a\x8b\xb5\xc0\x70\x73\x3c\x9c\x71\xd9\x42\x46\x2c\xc3\x89\x18\xce\xf2\x65\xe6\xa7\x2b\xe3\x4c\x81\xf4\x75\xd1\xca\x88\xdf\xe8\x75\x8b\x46\x05\x1e\x77\x1f\xe8\x6e\x71\xfb\x8e\xcb\xac\xe2\x68\xa8\xd6\x3f\x39\xe0\x7e\x49\xf0\xa3\xe1\x58\x2b\x77\x23\xcb\xd4\x4d\x61\xc5\xc3\x4a\xbe\x8c\x68\x30\x74\x75\xa7\x49\x5b\x58\x08\x0f\xd2\xc0\x03\x95\xcf\x40\xe0\xbb\x1f\x88\x95\x07\xaa\x2b\x14\xd9\x05\xc6\x32\xfa\x43\x6e\x51\xf6\x19\x70\x1a\xc6\x74\xb4\xef\x56\x65\x49\x25\x82\x60\x6e\x2d\xca\x08\x3c\x88\x8c\xca\xc7\xc6\x07\x1d\x3b\xd5\xa3\xd6\x9c\xc3\xf8\x2f\x76\xb3\x69\x6a\xf5\x9e\x91\x9c\x9b\xc8\x3a\x91\xbf\xcc\x94\x56\x26\xe0\x84\xc6\xcf\xf3\xf7\xcd\x7e\x9f\x8e\x7e\xf0\x1a\xfa\x4c\xf2\x70\xf5\xdf\xde\x1d\x8e\xf9\x5b\x90\xf6\x8a\x86\x69\x51\xb2\x9b\x44\xe3\xd1\x1d\x0a\xe4\x9e\xef\x3c\xf7\xb6\x18\x3d\x07\xe6\x34\x17\x1f\x01\x83\x39\xb6\x83\x42\xe6\x1e\x8d\x42\x9b\x42\x4c\x3c\x65\x0d\x9c\x2d\x58\x6d\xed\xd9\x44\x43\xb5\xc8\x9e\xd2\xe6\x92\xf8\xb5\x81\x2c\x9c\xb0\xa7\xab\x7c\xc3\x2e\x9c\x4e\xb2\x82\x54\x5f\xf5\xcc\xb8\x2c\x52\x33\x1c\x43\x86\x62\x1a\x4d\x5d\xdd\xa4\x83\x04\x4a\x7f\xb4\xd9\x6a\x2e\xe5\x41\x52\x80\xa7\x9f\x3e\x52\x4c\x38\xb9\xc2\xc4\xc7\xff\x13\xbc\x54\x16\x7e\xb4\x3d\xb8\x53\x81\x60\x40\x7a\x99\xd8\xd3\xe5\x3c\x98\xfe\x35\x99\x3c\x8d\xba\x7d\xc9\x46\x6d\x15\xcf\xcf\x34\x25\x53\x49\x83\x4c\x21\x69\xf8\x94\x69\x8e\x73\x84\x89\x7e\x4b\x0d\xb3\x71\xb2\xbf\x3b\xe1\x7a\x8e\x47\x1c\x7b\xdc\x01\x98\xbe\xae\xb2\x9b\x11\x18\x87\x15\x84\x9b\x13\x44\x8e\xf2\xbf\xaa\xbc\x16\x28\x87\x4e\x1d\x06\xae\x83\x38\xbf\x9d\x3c\xff\xfc\x6d\x27\x71\xce\x1a\xcb\x28\x8d\xbe\x7b\xa2\xd3\x7d\x76\x03\x29\xcd\x54\x53\x1f\x6f\x18\xb7\x29\xa0\x3e\x6f\x9c\x2f\xaf\x5d\xd1\x2a\x06\xff\x0c\x43\x6e\x97\xd0\xda\x50\x2b\xe5\x9d\xcc\xf7\xb2\x0f\xc9\xdf\x57\xd7\x14\x6d\x0f\x87\x68\x0f\x7d\x61\xcb\xe3\x7c\xf4\xed\xac\xa8\xec\xe9\xaa\x64\x82\x78\x3e\xb9\xfd\x85\xb1\x18\x9c\x51\x2c\xdb\x87\xe9\x36\x5b\xab\xa0\x32\x86\x0c\x88\x49\x96\xc8\x74\xa5\xd8\x25\x12\xf6\x42\x9c\xdb\x0b\x54\x28\x10\xa3\xc0\xb4\x60\xf5\x03\x0a\xd4\x07\x1b\xc1\xfb\x53\xf6\x9b\x64\xdf\x33\xb8\xc7\x9e\x34\xf6\x95\xce\x66\xde\xc9\x78\x28\x72\x5e\x29\x41\xdc\xea\xad\x03\xae\xff\xa7\xff\x4f\x7f\x9d\xdf\x8e\x1b\x0a\xac\xac\xb0\x11\x8f\x98\x56\x11\xbd\xe2\x59\x10\x8d\xa6\xde\xc2\x0c\x60\x50\x36\xe8\x26\xb3\x44\x2b\xd3\x3a\x07\x43\x51\xb5\x44\xbf\xab\x16\x78\xed\x9d\xb2\x9c\xfb\xa6\x84\xf5\x1b\xa9\xb9\x40\xc7\x35\xe9\x11\x6e\x49\xc7\x99\x5a\xd8\xd9\x4d\x1a\xf8\xf2\xd8\x10\xd7\x76\xbf\xa3\x96\x82\xc7\x80\x18\x02\x49\x8a\x98\x4d\x89\xa9\x53\x6a\xb3\x71\x59\xd6\x0c\xd9\x36\x02\xb8\x56\x02\xb8\x36\x02\x58\x7f\xe3\xb2\x58\x07\xe9\x41\x07\x99\xeb\x75\xcb\xb7\x3b\xd2\xc2\xd1\x72\x15\xf8\xc4\xf7\xd6\xf3\x5a\x93\x79\xe7\x0d\x65\xba\x91\xe8\x05\x13\x4e\xdb\xfd\xd8\xf4\xcc\x6c\x2f\xe4\x49\x96\xbb\x88\x79\x93\x3f\x76\x91\xf7\x46\xe3\xcf\x1c\xab\x9f\xba\xf4\x70\x43\x16\xa5\x7f\x63\x99\x29\x77\xf3\x9d\xd9\xee\xdc\xf1\x67\x41\xb9\xb0\x57\xac\xfc\xf2\x60\x53\x67\xae\xe9\x46\xfc\x9d\x40\x78\xad\xe3\xb3\x67\xe5\xb4\x90\xd8\x81\xdc\xef\x58\x69\x85\xbf\xe6\x1f\x8a\x4b\xd5\x84\x03\x55\x0c\x3f\x5e\x30\xa8\x9e\x73\x18\x50\xf2\x4f\x3f\xac\xf6\x8f\x4d\x6c\xda\xdf\xf1\x95\xcb\x96\x01\x5b\x0f\x06\xf9\x65\x9b\x1c\xf4\xcb\x76\xa1\x77\x66\xab\x17\xe5\xcd\x75\x91\xe6\xc2\xf6\xee\x5d\x5f\x23\x73\xae\xd0\xfe\x88\xf4\x5a\x88\x3a\xe7\xec\x58\x1b\xea\xf6\x97\x25\x00\x19\x66\xa7\x1b\x94\xd9\x98\x31\x3a\xeb\x0a\xda\xc8\xd4\xbd\xae\x62\xc4\x45\x0b\x25\x70\x5c\x1f\x80\x81\xe0\x41\x5d\x44\xbf\x0e\xd0\xb8\x7e\x48\x09\x23\x29\x26\x7d\xb7\x38\xd5\x3a\x77\xcf\x5a\xbb\x69\x5f\x8e\x0c\x9a\xe9\x16\x8c\xd1\x50\xaf\x02\xca\xad\x55\xe1\x18\x55\x5a\xb2\x4f\x23\xa0\xdd\x3d\x09\x55\x02\xd6\xf4\xa3\x00\x5b\x3e\xc9\xd1\xcd\x99\xe3\x97\x22\xc5\x94\x22\xe1\x00\xcf\xed\x46\xf8\x73\xc8\x05\xa1\x1b\x84\xe2\x12\x45\x83\x9a\x59\xe3\xcf\x18\x4d\xb1\x7b\x46\x86\x55\x40\xef\x29\x8f\x78\x75\x38\xa6\xc6\xea\x5f\x47\xe4\x77\xfa\x2b\xa5\xb6\xf1\xf4\xf1\xb9\x47\x6e\x15\xdb\x17\x37\x65\x59\xa6\x4a\xc5\x01\x01\x9e\x5e\x64\xbe\x79\x4f\x70\xe3\x1f\x0a\x30\xb9\xc6\xc1\xf2\x5f\xcc\xe1\x8f\x0f\x93\x48\x36\xfe\xd9\xae\x63\xb3\xc0\x4e\x14\x49\x14\x7d\xad\xf8\xed\x0f\xdd\x0b\x32\x53\xea\xdc\x1a\xa7\xb6\xef\x7b\x96\xcc\x96\x14\xf9\x6f\x55\x77\x6d\x49\xeb\x96\x8d\xcb\x9f\xc8\x8d\xed\xfe\x23\x50\x85\x2d\xf3\x34\xb2\xe9\x08\x7d\x55\x25\x28\xee\xb7\x26\x78\xfa\xf0\x50\xb1\x66\xdb\xe9\xf9\x18\xef\x05\x27\x3f\x94\xe7\x0f\x5b\xf9\x79\xdb\x8d\x87\x05\x6c\xf7\x49\x81\x0d\x4e\xb3\x5e\x1d\xe0\x65\xe5\x4b\xc2\x70\x3f\x41\xad\xcf\x35\x22\xe2\x0e\x9e\x60\xa1\x44\x82\xdb\xe7\x08\x53\x42\xb5\x01\xe0\xb1\x66\xe3\xb1\xa6\xe3\x07\x90\x05\x54\x80\xfd\x4b\x6d\xba\x3b\x63\x99\x19\xeb\xfd\xab\x4a\x9d\xbb\x44\xf1\x80\xd8\x0d\x47\x71\xf7\xa1\x7b\xd0\xa4\xdd\x40\x59\xa9\xfd\x51\x5c\xc7\x6f\x4a\xd0\x09\xc1\x17\x2b\x46\x89\x83\xa7\x1c\x8e\x49\xb8\x3a\xe0\x18\x1c\x1d\x53\x5f\x4b\x1d\x4d\x75\xb5\x25\x58\x8f\xe3\xb8\x0e\xcb\xef\xf1\x62\xdb\xe9\x0f\x10\x12\x23\x56\x85\x20\x14\x5d\xe8\x4a\x7c\xa0\x12\x1b\xca\xbe\xe8\xf8\x21\x29\x6a\xe7\x58\xb0\xba\x50\xd2\xa7\x5f\x40\xe7\x30\x24\x4f\x31\x96\xd1\xd8\x19\x2a\x6d\xb9\x83\x09\x53\xd6\xfc\xe5\x1c\x5b\x6c\xd5\x9e\x84\x2a\xac\x91\x6f\x9e\x77\x71\x16\x73\xdb\x8b\xe4\x2e\x74\xed\xf5\x83\x3f\xb1\x65\xd0\x06\x9f\xc3\x4e\x2d\xeb\x89\x42\x18\xaf\x0a\x5e\xe1\x82\x26\x6d\x92\xa4\x8b\xd9\x64\x1b\x48\x60\xfc\x86\x50\x85\xee\x44\x7f\x27\xb2\xc1\x24\x0d\x88\x7c\x03\xab\x30\xc4\x60\x52\x0d\xe5\x96\xfc\xe1\x2f\x20\xf3\xfd\x32\x10\xd7\xf4\xb9\x38\x75\x3a\x4b\x4f\xe4\x76\x21\x4d\xfb\xdf\xb6\x00\xc2\x20\x38\xa1\x6b\x4c\xe9\x66\x7c\xe8\xfe\xb7\x1e\x5f\x27\x44\x67\xb5\x75\x5d\x07\xab\x03\x81\x2b\x3c\x2d\xa3\xe6\xdd\x57\xab\x9b\x09\x56\x5e\x86\x4d\x5c\x11\x69\xef\x99\x5b\xe5\x64\xed\x1d\x5e\x4f\x61\xea\x34\xf7\x57\xb9\x7a\x4b\xe4\xa2\x73\x8d\x25\x67\x05\x37\xca\xc1\xe9\x64\x43\xbb\x79\x02\x52\x1c\x3b\xdb\xcd\x8a\xd2\xdc\xe4\xa2\x45\x61\x04\x59\xe2\x88\x79\xeb\x07\x6a\xb2\x56\x53\xc5\xda\x7d\x10\xfa\xd5\xb3\x68\xd9\x52\x87\x53\x50\x56\x68\xfd\x9b\xda\xf2\xd4\xe5\xd1\x19\x6b\x0c\xd8\xcd\xa4\x75\x53\xa5\x2d\x36\x38\x65\xec\x3c\x00\xe6\x95\x8d\x12\xd4\x4a\x5c\xdb\x64\x01\x6f\xc2\xf3\x33\x1d\xcf\x6a\xbd\xb6\xa7\x35\x1a\xf0\x2e\x64\x9d\xe4\x87\x04\x6d\xb6\x4f\x42\x14\x60\x06\xae\x18\x55\x1a\x3e\x30\xe3\x7c\x75\x7d\xf9\xba\xae\x6b\x31\x7e\xbf\x6b\xb2\xa7\x14\xa6\x72\x40\xd0\x05\x67\x1f\xd5\x1b\x34\x29\x38\x19\xd7\xb5\x31\xc3\xf7\xa3\x33\xbf\xe1\x04\x08\x18\x73\x63\x8a\xd7\xc3\x9a\xfc\xa5\x47\xaa\x6d\x70\x56\x23\x63\x53\xc2\x38\x79\x16\xdc\xf3\xb4\x54\x21\xf4\xf7\x6d\xae\xf9\x65\x20\x13\x7f\x20\xe8\xc9\x36\xb6\xc2\x47\xc0\xd4\xbb\xbc\x85\x6b\x73\x9c\x17\x2b\x77\xd3\x16\x70\x75\xce\x4e\x16\x9a\xee\x00\xe8\xfb\x64\x71\x22\xe5\x77\x97\x6b\x89\x94\x30\x70\xd1\xa9\x69\x8d\xaf\x14\xf8\xe1\x7a\xc0\xf8\x1e\x7d\xe9\x0e\x00\xa9\xad\x05\x6f\xd5\x10\xff\xa0\xa7\xcb\xca\x3c\x0d\x54\x56\x69\x7d\xe8\xef\x04\xb5\xef\x7d\xa9\xa5\x36\xf8\x36\xb0\xa9\xfe\x69\xd1\x34\x94\xb9\x18\x73\xcd\xd1\x72\x4c\x45\x70\x4a\x4f\x04\x7b\x41\x35\x3c\xdc\x09\x94\xdc\x16\xc0\xe6\x55\xd9\x81\xd7\x1f\x0a\x14\xd8\x0b\x9c\x53\x6a\x17\x90\x03\xb4\x54\xbc\x7e\xd4\xba\xe4\xae\xe9\x46\xbb\x93\x75\x24\x1e\xdd\x06\x84\x2c\x00\xa8\xe5\x04\xad\x09\xc4\xfb\xfe\x15\x8b\x68\xbc\x04\x91\x19\x89\xd1\x52\x11\xe7\x39\x7a\xaa\xb3\xb7\x15\xa2\x78\x0a\x14\xa3\x25\x17\x27\xfa\xf3\x0f\x00\xd4\x9b\x04\x46\x16\xb4\x88\xe3\x03\xfd\x99\x13\x89\x63\xf4\x8f\x44\xf1\xa5\xcf\xba\xd1\x4f\x69\x64\x7e\xd3\xfd\x25\x70\x5a\x55\x05\xd8\x78\x98\x6a\x7a\x18\xe0\x8f\x8d\x91\x2c\x70\x93\xa9\x6d\xa3\x11\x89\x46\x13\xed\x9c\x7f\x02\xfb\xb6\x12\x4b\x1a\x85\x3a\xb3\x5b\xe8\xf4\xe2\xca\x31\x7e\x6a\xfd\x64\x48\x7a\xfe\x46\xd2\x2b\x5a\x26\xe1\x8d\x6d\xc8\xf7\x77\x16\x59\x15\xa5\x7e\x8d\xa1\x6e\x17\x21\x75\x22\x99\x88\x38\xfd\xf9\xd1\x05\x5e\x41\x28\x14\x15\x12\xb6\x4f\x59\x5f\x0f\x26\xd6\xb3\x54\xd3\x27\xfa\x2b\x4e\x2c\xc9\x6d\xe4\x57\x9c\x43\x8e\xa2\x36\x26\x2e\x59\xd4\xce\x91\x4e\x0c\xc9\x25\x78\x17\x4c\x01\xb9\x19\x5d\x88\xfa\xb3\xc0\xa2\x94\x44\x4f\x75\xa6\xce\x63\x94\x3a\x60\x6a\x99\x21\x26\x12\xda\x6b\xcf\xd7\xf8\x12\xea\xc5\x9a\x92\xa0\x48\xcd\x6f\xc4\x2e\xf6\x66\x17\xe3\x59\xb9\xd3\xef\x67\x7a\x2b\x1d\x24\x31\xcb\x88\x1f\x68\x93\x34\x80\xfe\x40\x63\x1a\xb7\xf0\x44\x4c\x3e\x47\x79\xb0\xb2\x3b\x77\x61\xf3\x15\x50\x02\xe9\x14\x1c\x7a\xbb\xd1\xa5\x45\x67\x96\x5d\xbd\x40\x65\xb8\x58\x5b\x2a\x4d\x71\x29\x0f\x23\x82\x24\xb2\xd9\xb3\x69\x21\x1f\x8f\x9c\x53\xef\x1f\xa0\xc7\xbc\x79\x97\x99\x59\x3a\x22\x32\xdd\xd1\x9f\x26\xaa\xc6\xff\x47\xd2\x59\x2b\x49\xaf\x43\x41\xf8\x81\x1c\xc8\x0c\xe1\x18\x66\xcc\xcc\x99\x99\x99\xfd\xf4\xb7\xf6\xbf\xd1\xd6\x26\x2e\x59\x6a\x9d\xfe\x5a\x75\xc6\x1a\x6c\x09\xce\x0b\x53\x3c\xd1\x91\x3b\x47\xa3\xbe\x8c\x57\x8e\x60\xfc\x2c\xa9\xb9\xbc\x53\x4b\xf9\x5a\x8e\xf9\x60\x52\x06\x5e\x03\x2b\x0f\x4c\x65\x0f\x10\x51\x3b\xfa\x68\xea\xc5\x1a\xe3\x42\xee\x2b\x8e\x27\xfa\xef\xcd\xb7\xd2\xf8\x11\xc4\x43\x32\x94\xaa\xac\x2b\x85\x0c\xd7\x64\xc9\x53\x4d\xf5\xb8\xf0\xf8\x7d\xec\xa5\x08\x0a\xa2\x4d\x24\x18\x07\xde\xd5\x7a\x45\x61\x8f\x6b\xe0\x0c\x2a\x8d\xd1\xdd\x31\x70\x88\xdf\x2f\x4d\x53\x14\x75\x11\x19\x94\x17\xe6\x91\x29\x13\x23\x4c\x50\xad\x21\x07\x83\xa4\xfa\x00\xe2\x2d\xd0\xc5\xdc\xf7\xfd\x00\xd9\x53\x85\x75\x9c\x07\xf2\x7f\x13\xf5\x83\x57\xd1\x5d\x90\xcf\x3e\x84\xed\xa5\x8e\xf7\x28\x23\xfa\x18\x1f\xa1\xc8\xdb\xb5\x80\x15\xe6\x77\x13\xdc\xf9\xb5\x77\x7d\xd2\x45\x73\x78\xa7\x3e\xa3\x1a\x4e\xf1\xc8\xdc\xa0\xca\x9d\x1e\x91\xca\x8f\x04\x9e\xe4\x47\xe2\xce\xf4\x50\xe9\xed\x0d\x4b\xf9\x76\x9c\xfd\xc3\x21\x4a\x9f\xf4\x49\x22\xda\x42\xf5\xcb\x2d\xa6\x0d\x19\xe8\x7a\x8e\xe6\x9e\xe7\x45\xcd\x48\xeb\xe4\xce\x34\x04\xf2\xc1\x78\x29\x9c\x2c\x56\xe7\xaf\x34\xfc\x81\x01\xb5\x3c\x5b\xc4\x73\xc9\xc4\x8b\xf0\xd3\x39\xce\xec\x73\x0b\x12\x2c\xe8\x3b\x29\x1c\xbc\xab\x36\x6d\x9b\x03\x4c\xe6\xc6\xee\x0f\x3b\x79\x46\x73\xa5\xa9\xf5\xc8\x40\x04\xdf\x47\x85\x21\xbe\x4c\x11\xfa\xa1\x0f\xe7\x62\xcd\x80\x9d\x18\x37\xe8\xd3\x78\xa5\xbb\x7f\x95\x59\x67\x2b\x4d\x4e\x82\x7e\x4e\x82\x9e\x20\x10\x80\xcd\xce\xec\xbd\x1a\x95\xd8\xb8\xc6\x9e\xe5\x81\xfa\x26\x11\x07\xff\xee\xf9\x42\xfc\x38\x14\x71\x7a\x88\xe0\xe2\xe5\x63\x5e\xd9\xc3\x75\xfb\xd9\x48\x21\xc1\xb8\xc0\xb3\x4c\x0c\x9d\xbf\xd4\x9d\x3b\xac\x30\x38\x82\x84\xc9\x55\x80\xdc\x4a\xad\xab\x8a\x50\x10\xd5\xa9\x75\xb7\xcb\x0c\xf0\x63\x2c\x61\x64\xbf\x63\x9d\x7f\x98\xf9\x76\x1c\xfb\xd6\x8a\xf8\xc7\x66\x81\x22\x39\x6e\x74\xa0\x66\xb0\xb8\xdf\x89\x94\x69\xe1\xb6\x04\xc9\x57\x2f\x66\xf5\xc3\xf0\x86\x99\x78\x7b\xb3\x23\x34\xce\x81\x3f\xc5\x94\x8f\x5b\xb4\xab\x95\x00\x3d\xd7\x77\x46\x29\x69\xa5\xbf\x7f\x7e\xf4\xc7\x51\xbd\x49\x9c\x55\x4e\x43\x34\x7d\xf9\x19\x49\x5a\xc4\x4a\xed\x10\xf6\x96\x68\xeb\xaf\xfa\x08\x1e\x27\x51\x5d\xfc\xc4\x88\x52\xa5\xa4\x14\x2a\x9d\x6d\x97\x28\x6a\x7d\xdf\xa6\xed\x5f\xfb\x37\x34\x0e\x9a\x7e\x54\x58\xb7\x73\xb1\x61\x16\xa4\xd8\xc1\xd0\xc6\xdb\xac\x8d\x2e\x9a\x9a\x0b\x19\xcf\xc5\xb6\x7a\x4a\x9e\x67\x05\x04\xf7\x3d\x82\x2f\x4f\x3f\xcc\x7f\x93\x87\x00\x70\xbf\x77\xa8\xf6\x17\xf4\xd8\x52\xd3\x2c\xf2\xf0\xc6\x3b\xf1\x52\x14\x66\x54\x95\xac\x9d\x9c\x8b\x33\x57\x56\x02\x53\xfc\x9a\x78\x83\x5f\x71\x5e\x96\x41\xf8\x10\xda\xd8\x50\x87\x6b\x4f\x70\x01\x0a\xb0\xe5\xd2\x40\x5d\xdb\xb6\x9d\x25\x94\xc6\x18\x2a\xc2\x1a\xb2\x87\x3e\x53\x2c\xbd\x73\x84\xbe\xf3\xea\x8f\x61\xa2\x87\x29\xb6\x2b\xb1\x63\x98\xed\xbf\xc4\x56\x77\xdb\x66\x31\x0f\xf8\xb6\x37\x4a\x02\xc6\x4d\xee\xfd\x4c\x80\x0b\x18\xf4\xdd\x1f\x42\xa8\xde\x01\x69\x90\xd4\xc4\x5a\x00\x4a\x8c\x62\x86\xd0\xcc\x09\x5c\x16\x9e\x34\xcb\xf6\x63\xdf\x1e\x12\x0a\xcc\x85\x0a\xfa\xdd\xa5\x21\x9c\xa2\xc8\x3b\x3d\x1e\x22\x57\xcf\xcd\x92\xdc\xa3\xf2\xbe\x37\x74\xdb\x01\x86\x61\xbd\x18\x05\xdf\xfa\x6f\x8f\x91\xcb\xba\xe4\x0c\x01\x15\x8c\xf9\x6b\x3d\x63\xe3\x64\xf1\xe8\x58\x48\x2c\xd4\x36\xa7\x6a\xaf\x54\x7d\x08\xc9\x06\xbf\x8d\x50\x93\x0e\xb0\x13\x38\x3e\x73\xaf\x55\xad\x4a\x9f\x80\x95\x04\x3f\x59\x0f\xa4\xa1\xb0\x9f\x10\x4e\x2b\xb6\x70\x32\x75\xcc\x5b\x56\xe7\x5d\xc3\x26\x41\x7d\x23\x6e\xbd\x42\xaa\x69\xb1\x9c\x90\x28\xb9\xfa\x43\x56\xf9\x54\xab\x95\xa3\xb0\xeb\x1c\x5f\xf9\xdb\xa7\x70\xc6\x0b\x5a\xc6\xfc\xb4\x9f\xb5\x05\xea\x5c\xa1\xa5\x3b\x0d\x2e\xbd\xee\xa8\x4a\xb5\x67\x08\x18\x12\x18\x4c\xc1\x98\xc7\x8e\x7f\x04\x1a\xd2\xf2\xf0\x00\xca\xff\xf3\xf7\xfc\x41\xa3\xff\x70\x38\x41\x9f\xfa\x79\x00\x0c\x4d\x48\x88\xd2\x37\x72\x93\xf7\xc4\x14\xae\xcc\x10\xbf\x2d\x3d\x5e\x10\x96\xea\x78\xc6\x4d\xc1\x43\xa5\xe1\x6b\xaa\xcc\x4a\x90\x44\x6e\x60\x45\xfc\x16\xc9\xba\x52\xfd\x80\x9d\x37\x71\x84\x3d\xa1\x05\x60\x87\x49\x24\x1d\xb1\xf5\xd1\xa1\x3c\x3b\xef\xce\xa8\xa9\x7c\xc3\x56\xb9\x85\x70\x92\xa2\x28\x6c\x9c\xe7\xfd\xbc\xab\x5b\xdb\x7f\x9e\xef\xc0\x61\x16\x74\x5f\xb6\x2a\xfe\xef\x17\xb1\x27\x38\xd1\x83\x74\x43\x35\x43\xe4\xa7\x01\xb9\x1c\x34\xd5\xa9\x02\xd9\xe7\xf9\x82\x5b\x82\x47\xf2\xd4\x2b\x4d\x1e\x82\x6e\xe8\x04\x7b\x7b\x32\x68\xb9\x24\xef\x8b\xdf\x76\x26\x9e\xa0\x6d\x88\x14\xa2\x73\xcd\xd0\xf5\x87\xa4\xcb\xf9\x1b\x2c\x74\x80\xdf\x44\xcc\x40\x1a\xec\xba\x10\x55\xee\x0f\xad\x9e\xcc\x96\x19\x22\x5b\xe1\x9b\x23\x9f\x18\xf5\x34\xee\x33\x87\xab\xf9\xa5\xc1\x5d\x86\xd8\x4a\x60\x37\x43\x77\xf2\xb7\xd7\xaf\xc8\xe6\x3e\x76\xb0\xf6\xcd\xbf\x3e\xd7\x94\x5a\x09\x62\x06\x19\xc8\x4d\x4d\x51\x3a\x8f\x9b\x42\x88\x3e\x32\xa0\x82\xfe\xca\xbc\xe4\x10\xae\xcc\x42\x40\xba\xa3\x44\x4e\x1f\x62\x1b\xbe\x33\xdc\x9c\x3d\x33\x39\xf3\xbb\x77\x8a\xea\x6b\x8d\xa0\x03\x23\xc5\x77\x5a\x92\xc2\xd9\x0e\x3b\xeb\xb6\xed\x49\x0a\x1d\xb6\x9b\x1b\x5d\xfa\xf4\x6d\x9d\x58\x50\x10\xe3\x18\xec\xe6\x4e\x38\xdc\x97\x2b\x66\xfe\x86\xa6\x0c\xf9\x14\xa1\x51\x5c\xef\x17\x80\xf3\x5d\x89\x0d\xb8\x64\xe8\x44\x16\x3d\x86\xf0\xae\x3e\x27\xc5\x10\xc9\x06\x0e\xcc\x6a\xbe\x9c\x01\xe1\x12\x9c\x41\x85\x09\xf1\xae\xbd\x61\xcc\xe9\xc2\xce\x6f\x15\x43\x33\x44\xde\x17\xa3\x28\xf3\x04\xd0\x9e\x31\x26\x38\xe3\x55\xda\xc7\xbb\x24\xe5\x8e\xf2\x79\xe5\x6a\x39\x99\xd8\x50\x50\x9c\x79\x8e\x6d\x94\x10\x14\x2f\xb2\xa7\xc1\xce\x10\x34\x4d\xa0\x18\x46\xe0\x77\x06\x45\xfb\xce\xc0\x89\x75\xff\xca\x9c\x21\x48\x88\xa4\xcf\xf3\x7d\x61\x18\xfb\xd5\x9e\x51\x9b\x25\xa8\x5b\x0b\x36\xf9\xea\xa2\x99\xda\xac\xc6\x77\x12\x78\x96\xb6\xf3\x60\x3c\x73\x20\x76\x32\xba\x07\xdf\xe6\x4e\x94\x81\x05\xa3\xf1\xa3\x08\x9b\x3e\x00\xf4\x82\xf2\xba\x5f\x49\xfb\xd2\x85\x69\xb6\xc1\x80\x82\x1d\x55\x71\x66\x0d\xf6\x1f\x8f\x20\x69\xc0\x1c\xeb\x4a\xbd\x0f\xd3\xef\x67\xe8\xe6\x27\xb6\xa1\x18\xf6\x7b\x5e\xf4\x15\xc4\x7a\x21\x9f\xed\x54\x6a\xe8\x66\x24\x50\xfb\x00\x5e\xbf\x00\x00\x9c\x4a\xd7\x93\x61\x30\x06\xcf\x32\x55\x68\x7c\x35\xdd\x21\xea\xa0\xa6\xf2\x28\x21\xfe\x53\x59\x7a\x6c\xbc\x53\x76\x53\x18\xf5\xb6\xbb\xd8\xde\x37\x81\x5b\xf4\x39\x8f\x27\xc5\x48\xa4\xd1\x56\xe5\x71\x5c\xa0\x5c\x3e\xc2\xef\x7b\x5d\xbf\x3f\x6f\xa2\x0b\xda\x04\x3d\x92\x7a\x8f\x49\xde\x63\x77\x9f\x75\x84\xec\xb1\xdc\x30\xe5\xd8\x39\x8a\x46\xaa\x9a\x74\x57\x8e\xc4\x0d\x7c\xe7\x48\x51\xe3\x19\xb7\x24\xd5\x8d\x4d\xda\xf2\x8a\xc6\x3f\x6d\x1d\xec\xb3\x9c\xc5\x00\xf3\xac\x41\x0f\x70\x53\x65\x4a\x59\x55\x29\x0c\x7a\x31\xa6\x28\x18\x04\xd1\x19\x86\x74\x60\xc2\xe0\x8f\xd8\x81\xeb\x0b\xe4\xc7\x3d\x32\xcc\x9b\x62\x3b\x69\x78\x9a\x3b\x6f\x37\x4c\x81\x33\x3c\x4e\x90\x1e\xa8\x63\xf6\x63\xf2\xec\x6b\x88\x75\x78\x94\x8d\x6e\x4c\xd1\x97\xa4\x99\xbd\x44\x47\x42\xae\x8d\x6e\x9f\x42\xd2\x77\x78\x0a\x53\xe4\x20\x6b\x2b\x40\x11\x9c\xf4\xd7\x83\x82\xb6\xca\xb0\x75\xee\x1f\x9c\x01\x90\xa2\x95\xe5\x49\x8b\xc3\x0b\x88\xd8\xa8\xc1\xf1\xc7\xc1\x73\x5e\x16\xcd\xf0\x4b\x90\x10\xa2\xe9\x1f\xc0\x30\x6c\x14\x3d\x0b\xca\x32\x3b\x37\x35\xf2\x59\xd5\x26\x37\x12\x3d\xd7\x82\xc2\x38\x7e\xa1\xde\x3f\x48\xde\x9c\xb3\x3d\x14\xee\x7b\x86\xe7\x09\x15\x63\x6e\x82\x17\xe2\xa9\x98\x81\x86\x21\x90\xb5\x9c\x82\xc2\x07\x62\x18\x86\x4a\xe9\x1f\x0d\x65\x34\x60\x90\x3b\x4d\x9e\x6d\xb8\x10\x2e\x33\x44\xb1\x39\xc7\xf3\x78\x8b\xb4\x2b\x04\x3b\xf4\x99\x8c\x67\x18\x04\x30\x46\x6d\x3b\x05\xe2\x2b\xac\x4d\xd2\x26\x45\x6d\x6f\x47\x60\xc3\x79\x62\x2b\x0c\x4a\xa8\xad\xf7\x2f\xf1\x8a\xd6\xf5\xa3\xa8\x13\x8b\x41\xfd\xe3\x5d\x1e\x27\x40\x9d\xa6\x14\x4e\x50\xc4\xbc\x86\x58\x7b\x40\x9e\xd5\xfd\xe5\x67\x92\x8d\xda\x36\x7f\xe7\x2f\x8a\xce\x7b\xc7\x5d\x2c\x27\x72\x0c\xc6\x39\x38\xcf\x02\x59\x92\xc6\x3b\xe8\x45\x57\xea\xed\xfb\xbd\x1a\xe4\x7e\xa1\x9b\x9e\x71\xf2\xfe\xa0\xa3\x40\xfd\xbe\xd6\x0c\x9d\x00\x94\x22\xf6\x5c\x89\x49\x72\x33\x41\xd1\x6f\xd2\xbb\xf3\xcb\xe5\xdd\xc2\xdd\x53\x21\x16\x07\xc4\xb0\x59\x7b\x1b\xc3\x1b\x1f\xa7\x19\x0e\xc3\x0d\xe1\x14\x46\xca\x32\x9d\x53\x54\x79\xd2\x7f\xe4\x02\xe5\x58\x18\x8e\x1d\x52\x1f\xbb\xbb\x3d\x1b\x10\x2b\x52\xf4\xb1\x07\x2e\x75\x91\x66\x1d\x9a\x66\xb0\x87\x7f\xf0\x80\x30\xe7\xcf\xc9\xdf\x14\x4d\x38\x06\x38\xfe\x9e\xf5\x57\x33\xc7\xd7\x60\xdf\x82\xc2\x1c\x08\xa2\xcd\x23\x1a\xa1\xd3\x3f\x29\xc2\xf1\xfd\xe0\x3b\x70\x39\x67\xc3\xa5\xf8\xb7\x67\x9b\xb4\x65\xd1\x38\xcf\xa4\x01\x57\x0c\x62\xfe\xe3\xec\x65\x58\xf6\x2f\xf6\x63\x5d\x8f\xf9\xe3\xe8\xed\xe2\x5d\xf5\xf3\x45\x18\x9a\x8e\x0d\xaa\x1c\x5f\xcc\xc5\xc8\x44\x9d\x81\xc2\x65\xf2\x1d\x6a\x61\x23\x5b\xe7\xf0\x86\x60\xef\xfd\x82\x3a\xa8\xed\xd6\xac\xc8\xe6\x3f\x51\x09\x32\xef\x14\x92\xb0\x18\x51\x07\x14\x87\x15\x9a\x33\x63\x1a\xeb\x09\xf7\x2f\x00\x50\xb4\xf1\x21\xca\x4e\xd2\x99\x1e\x68\x69\x98\x27\x80\x99\xb2\x2c\x01\x4f\x31\x80\xce\xda\xfa\xba\x6b\xb1\x92\x04\xa8\x65\x08\x82\x84\x10\x02\x41\x5e\xea\xd9\x76\xe0\x06\x4d\x72\xef\x9b\x9f\xe2\xe4\xb9\xce\x1d\x9c\x78\x7e\x1a\x78\x92\x1b\xcd\x68\x39\xb7\x9c\xfa\xb7\x36\xfa\x57\x4d\x67\xff\x71\x37\x73\x7a\x99\xb1\x66\x28\xd9\xe8\x26\x62\xdf\x98\xc6\x3e\xdb\x51\xc8\x18\x20\x2e\x48\x5a\x16\xb9\xa9\x9f\x23\xb6\x2c\x5b\x22\xb0\xdd\x33\xdf\xac\xf0\xc5\x29\x5d\x14\x4d\x51\x80\xcd\x28\xdd\x51\xaa\x2c\xb3\xfc\xdc\x5b\x40\x3d\x3e\xe2\x8d\x70\x73\x97\x37\x26\x66\x3f\x12\x02\xe5\x56\xec\xfb\x85\x61\x1c\x3a\x05\x65\x4e\x6c\x81\x0a\xa0\xf9\xd8\xcf\xc2\x48\xe7\x99\x38\x92\xa1\xe5\xc3\x9a\x54\x17\x5b\xf7\xce\xf2\xa4\x24\x06\x22\xf1\x0c\xca\xc7\xf1\xc2\x9e\x4d\x05\x80\x2a\xc0\x4d\x70\x1f\xbc\x1d\xcf\x7e\x8e\x33\x9b\xf2\xec\xe8\x0c\x15\xff\xf8\xa0\x0f\xd1\xa0\xd1\xc8\x7c\xf2\x71\x65\xaa\x8f\x37\x28\x85\xa5\x80\xa8\xeb\xbe\x73\xf7\x4d\xfe\xcf\x4b\x26\x66\x62\x7c\xc8\x63\x64\x54\x97\x41\xcb\xde\x92\xc4\xea\x04\x0e\x4a\xef\x4b\x43\x09\x00\x24\xc0\x3c\x23\xc7\xa4\x1f\xc4\x40\x49\x0c\x1b\x5b\x2c\x59\x81\xde\xe2\xf7\x71\x9e\x0f\x69\x8f\x6e\x0f\x51\x7a\xdb\x00\xec\x91\xac\x68\x44\xdf\x7d\x3f\x67\x68\x20\xdb\xcc\x10\xf9\x06\x00\x92\x33\x34\x49\x60\x01\x1e\xb2\x78\x92\x85\x4e\x5d\x9a\xc3\x09\x5e\xc7\xb9\xe1\x5c\x8c\x7a\xe8\x38\x52\xb4\x10\x41\x58\x82\x4a\x4e\x98\x44\xed\x6b\x68\x64\x45\x71\x99\x26\xd7\x56\x61\xf8\xb1\x16\x7b\x6a\x63\x0c\xdf\xf8\x06\x40\x9f\x3b\xb1\x1c\x4e\x22\x18\xc8\xad\x51\x23\x3f\xa2\xdc\x98\x9d\x4f\x7d\x9f\x26\xbd\xcc\xc1\x9a\xf6\x35\x0c\x0a\xa8\x2c\x2f\x21\xac\x9b\x54\x7a\x0e\x6f\xb5\x95\x37\x1f\x06\xd8\xa0\x74\x00\xa6\x1b\xd0\xb4\x22\x52\xe2\xdb\xa2\x88\x5f\xce\xd0\xb3\x2c\x0b\xb9\x03\xc8\x84\xcb\xd3\x1c\xc9\x1f\x6d\xe2\x84\xb6\xfc\x60\x17\x21\x19\xa3\x31\xcb\x93\xe7\xef\x9b\x61\x78\x15\x0a\x22\x8c\xef\x1e\x59\xa4\x4a\x2c\x2d\xcf\xb0\x2c\x3d\x04\xf1\xb1\x92\x01\xa7\x4f\x9d\x37\xb9\x87\x37\xe8\x3c\x94\xca\xcf\x95\x3c\x56\x8b\xac\xbf\x3b\x66\xcf\xbf\xd1\x1d\x5a\x23\x86\x8d\x06\x8a\xf2\xe9\x27\xfd\x98\x97\x40\x83\x42\x6f\x23\x34\xe2\x8a\x51\x22\x81\x07\x01\xe6\x7e\x77\x86\x79\x48\x9c\xda\xd1\xfb\xa7\x6f\xb4\x2b\xe2\x60\x00\x26\xc0\x66\xa6\xdf\x0f\x33\x65\x81\x49\xaa\x76\xcd\x80\xbf\x32\x40\x89\xcf\xc7\x28\x9d\x17\x7a\xf1\xcc\x09\x7c\x1e\x10\xf5\x7e\xc6\xfd\x21\xcf\xa2\xd9\x18\x06\xc5\x30\x0c\x61\xde\x2f\x02\x68\x1c\xc6\x3c\x6d\xd2\x26\x15\x98\x26\x00\x74\xdb\xef\x67\x01\x51\x71\x0c\x43\xa5\x39\xa3\x59\x4c\xde\x7b\xdb\x9c\x75\xa1\x2c\xb2\xd1\x57\x7d\xb4\x30\x15\x9c\x27\x94\x23\xf2\x7a\xb6\xa7\x8b\x94\x20\x4d\xea\x4c\xd9\xf7\x28\xf8\x8a\x8c\xa4\xd6\x57\xf1\x6d\x5e\x0e\x54\x53\x7f\xfb\x14\xe6\x36\xa2\x06\x52\xbb\x79\x5c\x83\x41\xb4\xa6\x7f\xb9\x3b\x81\x68\x26\x4d\x03\x53\x6a\x8e\xb1\x2c\x4b\x3b\x67\x1b\xe1\xab\x3a\xf4\xe6\xb6\x2f\x80\xf0\x1b\xe4\x79\xc9\xa9\xae\xda\x5a\x1d\x64\xe0\x3e\xc2\x10\x44\x4e\x52\x14\xda\xaf\xc9\x7d\x2a\xf8\xab\xd1\x26\x43\x15\xd8\x49\x52\x33\x01\xa0\xf1\x3d\xc0\x70\x0f\xed\x00\xcb\x54\x7e\x40\x10\xc8\xe3\x74\xc4\xc0\x71\xb8\x24\x12\xf2\xf9\x8e\xb1\x36\x1f\xc4\x34\xc4\x0a\xdf\xe8\x44\xf1\xbc\x6a\x9e\x03\x94\x27\x8a\x44\x75\x82\x36\xf7\xfd\x37\xf5\xaa\xff\xc0\x8e\xe6\xec\x75\x66\xd6\xb3\xed\x47\xd6\x4c\x40\xca\x1c\x6d\x47\x48\xb1\xd7\xb4\x7e\x1d\x48\x02\xe7\xcf\x41\xc9\x63\x5d\x46\xe6\x45\x70\x86\x86\x18\xdb\x3a\xc4\xe9\x41\xf3\x6c\x0b\xfc\x6f\x3a\xbf\x10\xc0\x78\xf2\x78\x1d\x49\xc5\x4b\x95\xac\xfb\x1f\xa5\x5a\xc7\x19\xac\xde\x41\xd9\xa2\x2e\xda\x57\x6e\x44\x96\x0a\xc3\x79\x9a\x40\x7b\x73\x96\x63\x88\xb5\x18\xf3\xfc\x31\x5d\xcc\x53\x27\x5d\x2e\x38\x3c\x5e\xa7\x9f\xd5\x9b\xbd\x0b\x86\x15\x7c\xb9\x5d\xbe\x5a\x17\x9d\xee\xc5\x71\x9a\x9a\xbe\xdc\x04\x31\xb6\xe2\x9b\x7d\x9f\x9f\x27\x58\x36\x0b\x02\x47\xa2\x50\xb7\xdd\x10\x39\xaa\x04\xf9\xc4\x66\x50\x71\x6c\x0c\x4c\x06\xc8\xaa\xca\x20\xf4\x85\x63\x29\x1d\x76\xcb\xf8\x97\x7f\x98\xa4\x7a\xcc\xed\xca\xec\x17\x23\x8e\xfd\xc4\x54\xf6\x82\xd3\x05\x19\xe2\x24\x41\x29\x9d\x62\x20\x14\xc3\xda\xc4\xf3\x83\x20\x1e\x59\xa6\xa4\x73\xf1\xf9\xdd\xd1\x11\x9c\x94\x9d\x35\xb7\x2b\x1c\x65\xca\x65\x4c\xa8\x7e\xc9\xe7\xcf\x5f\x5a\x22\xda\x49\x0a\x79\x29\x82\xca\xf1\xee\x8d\xc3\x74\xb3\xa3\xf0\x27\x0f\x77\x3e\x04\x65\xb2\x2c\x24\x63\x5c\x03\x65\x0e\xfc\xe8\xa6\x6b\xa1\x16\xf7\xfd\x69\xdb\x40\x17\x79\x06\xa5\xc4\x1d\x2b\xcf\x92\x00\x20\xcf\x84\x85\x10\xde\xea\xe1\x24\xe5\x4e\x8e\x62\xf9\xd5\xd1\xd1\xb4\xf4\x1d\xa7\x07\x54\x9c\x56\xcb\x7d\x74\xda\xf0\x10\xc0\x02\x9a\x87\x3e\x6f\x35\x8c\x44\x18\xe2\x70\xff\xe8\x1d\xaa\xc1\xf9\x63\xc2\x96\x23\xed\xa3\xfa\x6d\xe6\xfd\x38\x44\xb1\xad\x27\x4c\x2e\xa1\x99\x97\x9f\xee\x40\xea\x60\x0a\x2e\xca\x42\x2f\xfc\x61\x27\x04\xbf\xfd\x50\x48\xc8\x69\xc6\xe7\xb9\x6f\xbe\xc6\x47\x65\xf9\xfb\xa9\xb8\xd2\x11\xfc\x4f\xe2\x4b\x15\xc7\x49\x91\x54\x03\x6a\x40\x15\x3c\x0c\x26\x00\xf0\xf9\x48\x65\x5f\xb0\x96\x07\xdd\xcf\xe4\x8f\xdb\x70\xc2\xf8\x95\x32\x84\x2a\x1d\xfd\xa0\x19\x9d\x8f\x9c\xa6\x5c\x94\xde\x40\x38\x14\xa5\xe9\xf8\x22\xbd\x5f\xd2\xe5\xc8\xfc\xce\x8d\x0f\x60\xb2\xfc\xc7\x19\xcd\x0b\x68\xfa\x7b\x95\xe1\x3c\x4c\x57\x11\x90\x04\x99\x63\x26\x30\x61\x98\x40\xf3\x31\x6e\x57\xfc\x58\x37\x4a\x7c\xd1\x21\x07\x0c\x21\xe4\x18\x92\xbb\x9e\xf0\xb1\x6f\x48\xfe\xe0\x62\x3c\x18\x22\x3f\x70\xa8\xb4\x12\x1a\x73\xae\x58\xf9\xca\xf1\xbf\x33\x0c\x71\x43\xad\x84\x97\xac\x9e\x72\xfb\x9f\x77\x7c\x4e\x1f\x65\xce\x54\x47\xb1\xac\xe6\xba\xba\x4c\xbe\x16\xa9\xfa\x61\x78\x62\xc5\x98\x33\xdf\x91\xca\xa2\x5c\xb4\x61\xd3\x3c\x35\xea\x26\x69\x70\x09\x9e\xe6\x58\xd2\xb4\x4e\x89\x19\xd3\x62\xd3\xdd\xc8\x73\x96\x35\xa1\xf5\x0b\xaf\x39\x9f\x2b\xe9\xa0\xc1\xc7\xa9\x51\x4c\x99\xa1\xfa\x38\x90\x20\x6e\x8c\x4b\xd1\xb8\xa0\x9b\x00\x62\x4e\x0f\x0b\x38\xec\xa6\xbb\x93\x7c\x8c\x38\xf7\x51\xfb\x2d\x89\xeb\xdc\x9f\xaa\xe1\x60\x65\xeb\xf3\xab\x51\x2c\x6d\xa2\xac\x08\x8b\x65\x56\xa0\xa7\x02\x6e\xd2\xe0\xbb\x51\x88\x53\x1b\xf2\xb2\x60\x5e\xb7\x23\x12\x08\x05\xf3\x0e\xf9\xa5\x37\x1f\xa4\x9e\x03\xaf\x16\x8b\x63\x08\x55\x37\x2f\xcb\x8a\xf3\x4e\x3a\xd8\x37\x6b\x0a\xfd\xa9\x94\xc9\xd3\xa3\x69\x70\x36\x3c\xc3\x40\x25\x6d\x07\xa6\x11\x51\x14\x28\xb5\xf3\xdf\xfb\x5c\xd1\x1c\x13\x0e\x0b\x95\x82\x89\x8d\x27\xe8\xe7\xfd\xc0\xd6\x7d\xe4\xa1\x98\xc4\x8f\xb7\x3c\x01\x40\x03\xf4\x4f\xe2\x3b\x10\xc8\x33\x4e\x9c\x8f\x95\x88\x09\x25\xf8\xcd\xbd\x7e\x9f\x7b\x5a\x8a\xd1\xa6\x2d\xfd\xed\x98\x2b\xa6\x89\x09\xa1\xd1\xf4\x7e\xd9\x26\x3c\xfa\x60\x0b\xab\x7b\x9e\x5c\x41\x74\x19\x94\xd2\xa8\x34\x1d\x41\xcb\xe4\xc5\xfd\xe5\x85\xc2\xa0\xe2\xf3\x84\x82\x61\x20\x7d\xcb\x7a\xcc\x2f\x06\x34\x3a\xec\x9e\xdf\x86\x4e\x65\x70\x0c\x8c\x2d\xd2\xea\x0d\x7f\xb4\xdb\xd0\x67\x97\xd2\xe2\x3e\xc0\x29\x5e\xe6\xa6\x10\x4e\x29\x66\x47\xd0\x87\xc4\x52\xf3\x84\xe1\x3d\x3d\xee\xb2\xa3\x37\x8c\x80\xca\xc2\xcb\x21\xb4\xdb\x6c\x96\x13\x5c\x32\xdf\xb1\x1a\x86\x60\xff\xb6\x3a\xfa\xfd\x51\xb2\xe6\x8b\xad\x2d\xaf\x1e\x2e\x14\xde\x6c\x35\x84\x49\x55\x3a\x7c\x26\x3b\x06\x64\xd3\x14\x49\xef\x6b\x76\x01\x05\x55\xcc\xfd\xf8\xa1\x59\x86\xeb\x42\x1e\x31\x01\x08\xcc\x85\xc1\x99\x1e\xf7\x64\x89\xaf\x1a\x24\x7b\x20\x45\x40\x37\xce\x60\x5d\xcf\x19\xaa\xb7\x67\x25\x79\x45\xe2\x89\x64\x3f\x5e\x68\x64\xb0\x91\x26\x30\xa6\x7a\x96\x96\x3e\xf4\x3d\x0d\x30\x0c\x0b\xcf\x73\x04\x14\x7e\xc3\x9f\xaa\x52\x87\x22\xe1\x61\xc6\x2c\x01\x7d\xbf\x8c\xb0\xca\x61\x5c\x2d\x46\xd4\xfc\x00\x35\x07\x4a\x91\x8f\x11\x39\xc6\xc6\xe8\x0a\x63\xf2\xce\xa7\x4e\x4c\xfb\xf8\xde\xf1\x5d\xfd\x65\x73\xbe\x8e\x5b\x3b\x50\xe1\x33\x3c\x50\x08\xd0\x2f\x56\x00\x1f\x87\x6f\x61\x32\x45\x1c\x8c\xbd\x44\x31\x38\xb9\x8d\x25\x6f\x3a\xf3\x78\x21\x52\xb7\xd9\x9a\xc1\x6d\x73\x2f\x6f\x2d\x17\xbd\xc6\xf5\x31\x85\x9a\x12\xf9\xcf\x6f\x1c\xff\x32\x6f\x66\x80\x9c\x79\x2d\x4c\x27\x73\xda\x65\xd2\x3d\x4a\x17\xb1\x08\x42\x3a\x40\xcf\x48\xb5\x4a\x68\x78\x94\xce\x16\x26\x8d\x15\x67\xc1\xa0\x29\xea\xf1\x64\x4d\x13\xc6\x79\xee\x12\x75\x77\x86\xd6\x3f\x9a\xbc\x78\xc5\xb6\xd0\xa4\xd0\xf8\x19\x50\x5a\x3e\x59\x51\x34\x27\xf1\x90\x30\xbc\xdf\x86\x79\x66\x67\x1d\xb8\xed\x29\x96\xe6\xb8\xef\xe7\x19\x60\x39\xba\x06\x51\xd6\x7e\x0d\x5e\x79\x70\x63\x2e\x82\x7e\x4e\x44\x11\x7b\xa7\x26\xcb\xca\x14\x05\xe6\xb1\x7a\x46\x81\xa5\x27\x38\x7f\x26\xd5\xae\xab\x9f\x17\x71\x77\x83\x12\xca\xfb\x71\x67\x10\xfa\x21\xc9\xfc\x78\xf9\x10\x46\xac\xb0\x39\x7e\x12\x61\x1a\x4c\x81\xee\x6b\x02\x87\x59\x24\x4a\x64\x06\x47\xee\x0e\x6f\xa3\x65\xb3\xea\xb7\x01\xec\x2d\x7f\xaa\x96\xce\x5f\x8c\xc2\xb0\xf3\x74\xc2\x13\xb7\x39\xc9\xb3\x79\x9b\x85\xce\xf0\xc4\x72\x03\xc2\xe9\xa2\x94\xbb\x7c\x25\xe8\x8a\xf9\x49\x46\xc8\x06\xc5\x88\x2d\x2b\x22\x9b\xee\x32\x1c\xba\x12\xba\x24\xc5\xf3\x9f\xdf\x20\x10\xa0\x1f\xcb\xf3\x84\x45\x04\xd0\x15\x6c\x3f\x9a\x8f\x40\xf4\x66\xea\x17\x59\x85\x5b\x80\x9b\x34\x34\x3d\x45\x01\x74\x81\x03\x9c\x39\x59\xb8\xb5\xd0\x41\x5a\xf6\x5e\xc5\xbd\xac\x2e\x1b\x9e\xb8\xf6\x93\x43\xc6\x8f\x6b\xfc\x30\xfc\x21\x4e\xf8\x90\x6a\x88\x86\xd0\x31\x2a\x22\x83\x60\x6c\x3f\xc6\x33\x4d\x37\x7d\x44\x48\x0b\x06\xcd\xfb\x04\x2f\x3a\x97\xa9\xb1\x3c\xf4\x18\xba\x6c\xce\x12\x9c\x9e\x47\xf4\x09\xff\x2e\x37\x86\xb5\x77\x1a\xea\x96\xf2\x12\x49\x79\x6a\xba\x4e\xa6\xf4\xb0\x64\x9e\x71\xa6\xfe\x1f\x30\xd1\x42\xb6\xab\x0e\xc2\x50\x1b\x24\x00\xb1\xc2\x45\x91\x9a\x5f\x8c\x21\x70\x95\xa2\xd0\xc7\xbe\x70\x97\x17\xc0\x28\xac\x49\x8b\x5a\xa9\x9a\xc0\xd1\x32\x48\x01\xaa\xc7\xcc\x31\xaf\x6b\x37\x3e\x0e\x51\xc1\x85\x2f\xdb\x5e\xfc\x93\x7e\xc8\xfb\xd2\x59\x81\xaf\x82\xbd\x30\x07\x48\xf3\x67\x37\x92\x26\xd6\x52\x0f\xd3\x19\x0a\x50\xa7\x85\xad\x08\x5a\xd6\xc9\x43\x1f\x4a\x16\x09\x86\x72\x34\xf8\x6e\x8b\xf3\x62\x79\x4f\x84\xb3\x5f\xdb\x19\x50\x6f\x95\xf1\x41\xd1\xe4\xc1\x39\x23\x9e\xc7\x69\x49\x33\x57\xbf\x81\xc2\xaf\x4c\x31\x45\x2a\x6e\x5b\x1a\x48\x41\xc8\xe8\x23\x66\x00\x23\x46\xec\xd0\x3e\x60\x9b\xb6\x24\x1f\xc5\x27\x42\x09\x1a\xa4\x74\x0e\xff\xa0\x93\x1a\xb7\x34\xa2\xd7\xe2\x56\x4a\x46\xb3\x33\x1a\x66\x84\xa9\xcf\x7e\x8e\xac\x33\xa7\x6b\xed\xb8\xbd\x43\x2c\x1a\x46\xe1\xc8\xcc\x51\xc3\x44\x40\x34\xe5\xed\xc8\x07\x94\x02\x85\x10\xc6\xf9\x4c\x94\x3f\x9a\x0a\x27\x4a\x2f\x95\xdc\xfb\x4b\xb4\xc2\xb2\xf9\xc4\x77\x5a\x90\xe4\x38\x0e\x33\x40\x71\x82\xc9\xad\xf7\xcd\xc4\xb6\x74\xf1\xf5\x0a\x20\x7e\x33\x59\xca\x94\x2e\x00\x80\x3c\x8c\x23\x44\x2d\xe4\xb6\x3e\x9e\xee\xfa\x48\x8e\x31\x38\x01\xc1\xe3\x3a\x28\xa6\x81\xbd\xf8\x1f\x6b\x97\x25\xa0\x54\xe2\xdf\x79\xe1\x2d\x48\x65\xc7\x4a\x91\x95\x0a\x46\xe1\x6f\x68\xfa\xb7\x8f\xe1\x71\x7d\xf5\x41\x3c\x84\x53\x3a\xa8\x85\x44\xc6\x97\xd6\x92\x44\xcc\xb9\xf7\x8f\xef\x28\x8a\xc2\xc5\xbd\x10\x9c\xe7\x28\x5f\xb3\xa4\xa6\x08\x00\xec\x7e\xc1\x6d\xca\x8c\xaf\x62\xaf\xd2\x2b\x5d\x04\x52\x5d\x8c\x8f\xc5\xeb\x0d\xc0\x1f\xa6\xd8\x06\x71\xfa\x0d\x4c\x67\xf4\x96\xfe\xd7\xde\x64\x1e\x9e\x1b\x5d\x94\x52\xd7\xf3\x06\x47\xe9\x6e\x8e\x85\x98\xe9\x62\x14\x89\x46\x78\xee\xed\xc7\x6d\x7d\x00\xf1\x30\x99\x07\x0e\xbe\x3a\xa9\x41\xca\x99\xe2\x6e\x01\x92\xc3\x49\x49\x66\xd8\x19\x02\xb4\x3c\x57\xc3\x68\x9e\x75\x03\xe5\x52\x88\x54\x45\xb0\x4e\xe7\x7f\x6d\xc1\x67\x79\xee\xde\x58\x57\xf8\x28\xe1\x19\x06\xa3\xa1\xef\xe9\x41\xf5\xa9\x3c\xdf\x05\xf5\xb9\x85\x8f\x67\xb3\x2c\x6b\x55\x5f\x76\xa8\x84\x7f\x1f\xc8\x6a\x5f\x26\x08\xed\xb2\x7e\xb5\x87\xd1\xa0\x92\x39\xcd\x34\x0e\xed\x08\xe4\x10\x35\x8e\x6b\x7f\x53\xe7\x50\xc0\x8c\x73\x6e\x70\x2d\x60\x22\xcc\x22\x3b\x17\xfb\x74\x41\x83\xb2\x6d\xe3\xe7\xf9\x74\x6f\x05\xff\x26\x8c\xc7\x83\x7a\x49\xe6\x2a\xfa\x51\xc1\xb5\xa5\xc9\xbd\xb7\xd6\xa3\x8d\x2f\xa5\xb7\x98\xf5\x42\xcc\x37\x3a\x94\x9d\xb8\x9e\x89\x4f\xba\x49\x08\x8f\x06\x0d\x7d\x3d\x10\x51\x7b\x3c\x8f\x93\x74\x2e\xdb\xf2\x6f\xf2\x36\xe5\x72\x7a\xeb\x6d\x2a\x14\x0e\xe4\x8f\x2f\xc5\x4f\x6c\x50\x15\x4f\x34\xcb\x6e\x66\xd3\xbe\x26\xae\xd3\x3b\x1b\x65\x60\x67\x03\x99\xe2\xf8\x12\x98\xf8\x98\xcf\x17\x22\x34\x43\xcc\x39\x81\xa2\xfa\x17\xa2\xd2\x70\xd1\x7f\x58\xca\x20\x9c\x42\x51\x17\x38\x31\x8a\xf4\x8d\x11\x39\x18\xc5\x39\x30\xba\xf8\xce\xc9\xb0\x42\x27\x46\x1a\x62\x20\x92\x92\x24\xd2\x6e\x0e\x45\x5b\xaa\x6c\x8a\xe3\x51\xc3\xaa\x41\x1f\xcb\xd2\xfc\x2f\x6b\x7d\xd8\x44\x6b\xa6\xf7\x43\x3f\x12\xfb\x91\xbe\xcd\x5b\x9c\xc1\xc0\xdb\xc7\xad\xc5\x77\x67\x88\x22\x0d\x99\xce\xec\x41\xc1\x62\x2f\x6c\xca\xa0\x94\xf2\x6c\x33\x4e\xaa\x10\xfb\x40\x21\x4a\xed\xba\x48\xd6\x0c\x6f\x79\x02\x9b\x6f\x8a\xf0\x1a\x7c\xb2\xdc\x05\x7f\x25\x7c\x10\x33\xa9\x07\x8f\x32\x9c\x6b\x76\x5b\xd3\x55\x6a\xb2\xc4\x49\x9c\x56\xec\x78\xbd\x4c\x98\x37\xbe\x14\x74\x0c\x53\xd1\xfc\x95\x4b\x60\x7c\x4c\x7c\x8a\x2a\x34\xb9\x73\xcc\xbf\xdd\x3f\x79\x77\xc0\x50\x06\xb9\xc2\xda\xee\x6e\x90\x8c\xcf\x31\x86\x50\xa4\x0f\x76\x62\x2f\xb1\x31\x09\x44\x6e\x26\x48\x0f\x6c\x0c\x09\x7c\x0b\xb4\x1d\x1a\xa3\xce\x63\x34\x8d\xad\xb4\x6f\xe0\xf7\xa1\x0f\xe7\xda\x6b\xba\x7d\x83\x6e\x6b\x02\x6f\xed\xe7\xd2\x11\x3d\xf4\x03\xee\x1a\x2c\xfb\x33\xb6\x04\x14\x69\x61\x98\xf4\x2f\xf5\xed\x6f\x88\x3f\x0b\x7b\xd0\xe0\xf0\xe4\xa0\x56\x5c\x5b\xbb\xd0\xb8\xb1\x3d\x49\x28\x15\xf1\x73\xd6\x09\xfc\x7e\x19\x64\x34\xbd\x7a\xf0\x7b\xd7\x55\xc4\xd5\x08\xd2\xef\x86\x26\x91\xfe\x83\x82\x9d\x50\x42\x3b\xd0\xf7\x68\x20\xf6\x96\x2b\x47\xe0\x21\x48\x7e\x86\x29\x32\xac\xc3\x4b\xa0\xbc\xda\x06\x0c\x3e\x00\x02\x7d\x12\xf5\x1b\xc2\x3b\xa2\xc4\x57\x79\x62\xe1\x4b\x4c\xee\x27\x0b\x07\xe2\x08\x6b\x4b\x28\xac\x55\xcb\x7f\xd6\xeb\x7b\x9d\x29\x0f\xaf\xd9\xcd\x8a\x33\x62\x14\x63\x69\x5e\x29\x1b\x09\x74\xaa\xbd\x83\x5f\x16\xe9\xcb\x71\xe0\xf6\x2d\x7a\x5a\xaf\x96\x7e\xa7\xda\xb1\x89\xee\x64\x3b\xeb\xe0\xf0\xf6\xa6\xc1\xb3\x8d\x50\xb6\xf6\xd9\x8b\x08\x2d\x9d\xd6\xa0\x02\x9b\xc4\x23\xbe\xef\x8d\x8e\xca\x9c\x26\x76\x91\x6a\x4b\xdd\x9a\x8b\x0d\x3a\xb3\x98\xad\xfc\xa1\x13\xf3\xa2\x0d\xf1\x61\x7d\xda\x1c\x81\xb1\xea\xbd\xac\x22\xa4\x05\x79\x06\x54\x6a\x59\xb4\xfb\xee\x8d\xb2\x7e\xe0\x15\x63\x29\x23\x07\x54\x09\xb5\x36\x93\x34\x75\x9f\xdf\x6c\x1a\x5b\x80\x44\x8c\x7a\xea\x60\xd4\x9f\xee\x95\xd8\x8f\x53\xa0\x12\x9e\x74\x73\x55\x60\xe2\x49\xe4\xd0\xfc\x12\xaa\x39\x12\xf4\x20\x4b\x4e\x69\xac\x3d\x8a\x24\xf3\xec\x3d\xc9\x19\xae\x22\x9d\x08\xad\xb4\xc6\x1b\xb6\xb5\xd2\xbb\xe5\x4d\x03\xe7\xfc\x9c\x73\x5e\x6f\x07\xc8\xae\xda\x7a\x2b\xa1\xdb\xfa\x20\xd1\x9e\x66\xaf\xe6\x9a\x3e\x9c\xfb\x8e\xd7\x17\x07\xf8\xd7\xa3\xe3\x63\x24\x42\xc8\x7b\x40\xe5\xd0\xee\x4e\x6d\x4b\x90\x81\x75\x95\x24\xff\xb1\x59\x41\x28\x8d\xcd\xd5\x80\xde\xc5\x96\xc2\x49\x4e\xd8\x9a\x1d\x41\xb0\xdf\x5a\x2a\x81\x3e\xf6\x8f\xe3\x75\xb2\x3d\x30\x3c\x6d\x86\x98\x7d\x9b\xd0\xd9\x48\x9d\x1c\x0e\x26\x1d\x2d\x7a\xe3\x09\x6b\xb9\xb5\xf9\x81\x95\xbc\xd5\x19\x00\xf0\x86\x3b\x9d\x9b\x55\x1e\x2b\x8c\x34\x48\x5a\x0b\x52\x2d\xbb\xe4\xde\x4c\x8b\x32\xcf\x49\xb0\xad\x8a\xd3\xcd\xca\xf3\xb7\x5c\xd3\x22\x35\x35\xbd\xd7\x9a\xdf\x69\xf2\x64\x7e\x63\x5d\x9c\x73\xe5\x6b\x29\xac\x25\x43\xe1\x0d\x85\x01\x9c\xb7\xff\xee\xe3\xa8\x7d\xdf\x0f\xfb\x38\x08\xfa\x38\xf0\xfb\x39\x09\x7b\xa2\x08\xf1\xa5\x66\x67\x4e\xa2\x4b\x33\x5b\xe5\xc7\x12\xbc\xde\xbc\xbb\xf7\x5c\x34\x9a\xbd\xd8\xe2\x26\xcd\x76\xba\x37\x2c\x9d\x90\x7b\x1a\x60\x45\x6b\xcd\xf1\xed\x19\xbb\x8b\x7f\xec\xd9\x01\x65\x36\x65\x44\x4f\x03\x64\xe7\x3d\xff\xab\xfb\xbe\xef\xbb\xbe\x1f\x07\xf1\x2a\x46\x2a\x9b\xae\x0e\x02\x49\xc7\x0a\xcd\x6b\xd2\x4c\x0a\x07\x9d\x0b\x57\x9d\x2a\xa0\xe8\x23\xe5\xaa\x4a\xbb\xf9\xaf\x4e\x32\xc5\x9b\x1d\x92\xc8\xbf\x48\x03\xef\xc1\x56\x7f\x15\x98\x06\x25\x00\x6a\xff\x50\x63\x35\xe3\xa6\x12\xa1\xc5\x79\x52\x82\x13\xeb\x12\x3d\xfc\xb6\x55\x81\x19\x7b\x7a\x24\xee\x03\x44\x1c\x28\x7e\x97\xe8\xa2\x97\xba\xd6\x93\x51\x46\x7a\x72\x96\x14\xd8\xeb\x15\x5d\x15\x3e\x98\x3b\xd9\x7a\x72\x7b\x43\x2e\xc0\x8c\xc0\x67\xbe\xa8\x3d\x4a\xc6\xad\x0c\xc9\xaf\xf9\x1b\x52\xa5\x24\xec\xa4\x38\xc7\xa4\x34\xfb\xc5\x56\x54\x9d\xa9\x73\x29\x47\xad\x10\xf1\x5c\xc2\x3b\xf6\x47\x08\xe9\x4f\xc8\x79\x1e\x57\x25\xdc\xb0\x2f\x49\x96\x23\xcb\x17\xa5\xeb\xba\xfa\x95\xed\x60\xf7\x04\xc3\x52\xa8\xf6\xe9\xd7\x73\xe2\xf0\x0e\x34\xbc\x2b\xf9\x1f\x49\xab\x69\xe6\xa1\xde\xf2\x36\xa5\x9f\xf5\xfc\xb6\x68\x90\x9b\x64\x98\xb7\xf4\x77\x4f\xf1\xef\xee\x52\xe1\x76\x72\x5c\xe8\x2e\x38\x69\xb3\xb8\xd1\xd2\x2e\x53\xa7\x52\xc5\x43\x89\xe0\xfa\xeb\xcb\x4f\x25\x33\x62\xd0\xb2\x2a\xf7\x46\x1d\x6f\xdc\x64\xb4\x7b\x62\x68\x77\x6c\x68\x42\x20\x1e\xff\xef\x4e\x32\x41\xb0\xf6\xf0\x4d\xba\xce\xc8\x2c\x8c\x09\x36\x8c\xbe\xf5\x38\xbc\x86\xf3\xab\xcf\xb7\x85\x0e\x24\xba\x4f\xa4\x31\xcc\x4b\xf2\x27\x99\x66\x5a\x9e\x6d\xd5\xd4\x7a\x53\x99\x9f\x81\x80\xcf\xf7\xaa\x04\xa0\x2e\xe4\xf0\x6f\x65\xd6\x87\x3e\x15\x85\x3e\xd5\x07\xde\x55\xc7\xc5\x83\xaf\xcf\x0e\x42\x7f\x56\xb4\x96\x7f\x40\x64\x9c\x68\x9a\xa1\x93\xbe\xb2\x02\x7d\x5a\x25\x6c\x32\x5a\x6a\x3c\xef\x0c\x83\x1e\x93\x0a\x0b\x37\x38\x1e\xba\x40\xb5\xd0\x4e\x99\x41\xed\xe7\x2a\x70\xa6\x68\xed\x15\x99\x1e\x07\x2a\xbf\xb9\x81\x45\x05\x6f\x6d\x2d\x6e\xe5\xae\xd7\x4b\x8f\xf6\x66\xaf\xde\x46\xb7\xe6\x0a\xb7\xd6\x46\xa8\xce\xab\x1e\xb2\xff\x69\x28\x1d\x32\xbe\xd6\x3b\xdb\x93\x58\x2d\xfc\xde\x9e\xff\xb5\x23\xef\xcb\xfe\xc9\xd4\xa6\x41\xa9\xbd\xc6\xbb\x51\xca\xab\xbd\xea\x43\x1b\xb4\x51\x2a\xe6\x70\x87\x8b\x0b\xa5\xb4\x3c\x95\xce\xdc\xc1\xe9\x65\x04\xab\x4f\x32\xd9\x58\x8a\xa2\x88\xb5\xa5\xca\x86\x45\x8c\xfa\xfa\xf0\x4e\xfb\x48\x58\xfd\x2b\xa4\xbf\xfb\x4f\xfd\x47\x3a\x10\x43\x3a\xc4\x4b\x32\xcc\xeb\x4c\x16\xfd\x9c\x04\x13\x66\xfd\xed\x2a\xa8\x6c\xef\x08\x89\x87\xf8\xdf\x2e\xf9\xfb\x3b\x27\xc5\x99\x52\x0c\xe4\xc4\xeb\x97\x87\xc9\xdc\xf0\x9a\x58\x0f\x56\x1f\x6b\x29\xe3\xda\x68\x20\xfe\x88\x50\x0d\xd7\xef\x46\x15\x99\x2a\x90\xc7\xbc\x00\x33\x9a\x95\x66\x39\x82\xb4\x08\x1e\x28\x70\x88\x47\xd7\xc7\xb7\x6b\x65\x27\x24\x90\x6c\x0f\x0b\xd1\x92\xaa\xa1\x5e\x63\x50\xa6\x14\xc5\xb8\x0c\x30\xcd\xb1\xdd\x46\xd3\x81\x77\xd9\xf1\xbe\xfc\xe3\x35\x34\xee\x7c\x6b\x99\x54\x9b\xc7\xac\x59\x44\xb7\x3c\xfe\x73\xeb\xae\xf7\x26\x68\xbc\x45\x83\x52\xa5\x28\x5b\x25\x0a\xf7\x17\xd3\xfa\x35\x41\x3b\x46\x3a\x7b\xcc\xa0\x21\x21\x0b\xc7\xdf\x29\xb0\xcd\xb6\xcf\x07\xa9\xfd\x69\xe5\xaa\xfc\x64\x34\xe1\x7b\xd0\x15\x5b\xde\x85\x4f\xf5\x68\xab\xf6\x6a\xab\x06\xcc\xc9\xfd\xda\x9e\xff\xb7\x1a\xd6\xa3\xb5\xa6\x8b\x30\x66\x88\x30\x9f\x4b\xe3\x73\x0b\xd6\x0b\xff\x80\x6d\xc5\xb4\xd1\xdf\x15\xd4\x34\x52\x67\x4c\x95\xf1\xf3\xa9\xe2\xa1\x42\x88\xfc\xca\x20\x38\xa5\xd7\xd4\x43\x0f\xae\x3e\x20\x67\x89\x2a\x77\x56\x68\x23\x9d\x86\x8b\x99\x11\x42\x12\xf9\xae\x0f\x44\x22\xc3\x8c\xe8\xd5\xe5\xb7\x53\x4b\x11\xdf\x09\x80\xd3\x07\x18\xaa\xcb\x46\x34\x57\x40\x34\xd7\x43\xf5\x36\x42\x90\x5c\xf4\x52\xd3\x75\xd6\x59\x71\xba\x4d\xf9\x54\xf2\x53\x8e\xa0\x3c\xb1\xc3\xed\x08\x8a\x21\xfa\x79\x45\x88\x0b\x32\x6f\x47\xac\x2f\x1a\x93\x5f\xf9\x72\x8c\x80\x62\xee\x0a\xc3\x28\x66\xac\x0d\xd0\x8e\xaa\x4f\xe2\x11\x71\x33\x56\xf0\xad\xa6\x91\xda\x4b\xff\xeb\xc0\xb9\xf9\x2d\x39\xab\x93\x7d\xbe\x5f\x9d\xf2\x37\x1f\x69\x82\xe6\x5b\x81\xa6\xf1\x81\xa5\x8b\x1f\x95\xfd\x55\x09\xdc\x9d\x6e\xa7\xab\x10\xd9\xd9\x15\x96\x82\xa5\x01\x96\xee\x0b\x9a\xef\x11\x8a\xec\x11\xaa\x77\xf1\xcf\x36\xd4\x94\x8b\x78\x16\xce\x45\x1b\xce\x45\x07\x5a\xca\xb3\xa5\xc1\x9f\x48\x86\x79\x45\xa0\xf1\xec\x08\xbd\x3c\xbd\x45\x77\x03\x5f\x19\x68\x48\x08\xbf\x56\xf8\xbd\x34\x03\xbd\xd9\x60\xd6\x08\x12\xd2\xa0\xa8\xb2\xab\x72\x7d\x86\xf9\x48\x33\x34\xad\x6e\xac\xc7\x23\xd5\x96\x06\x2a\x43\x53\xb2\x04\x6b\xd0\x55\xbf\x80\x7b\x82\x35\x41\x76\xe8\xc2\x8d\x34\x5f\xe0\x24\xf0\xd7\x85\x4c\x06\xb6\x51\xd6\xff\x3b\x91\x88\x02\xc0\x76\x1e\xf6\x64\xd1\xcd\xef\x43\x0f\xa1\x83\xc3\x85\x19\x3e\x51\xef\xa4\xc8\x1c\x8f\x3e\xc2\xa4\x6f\x9c\xdd\xd1\x19\xe4\x32\xb0\x44\x28\x6e\xdf\x29\xfd\x11\xbb\x1e\xbc\xa9\x39\xb8\x7e\xfa\xf6\x66\x17\x72\x04\x86\x43\xb1\xfe\xaf\xf1\xd4\x9c\xbd\x94\x8f\x29\x92\x8a\x77\x98\x8c\x0d\x37\x44\x73\xe5\x28\xc6\x9b\x48\xf6\x60\xc0\x8a\x63\x0a\x1d\x0d\x3e\x88\xd0\x20\xd1\xd1\xdd\x07\x77\x3e\x0c\x25\x94\x85\xbd\xeb\x35\x57\x7f\xb0\xfc\x61\x64\x73\x7a\x9c\x6e\x96\x77\x92\x49\xd0\x35\x40\xf7\xd5\x13\x4a\x6b\x0f\x48\xbd\xc1\xc1\x79\x08\xf8\x4c\x3d\x8a\x5d\x7f\x84\xd1\x22\x5d\x9c\x6f\xc1\x24\x7f\xc7\xbb\x54\x1f\x7a\x76\x3b\x42\x76\x3b\xc2\x9c\xb1\x32\x5c\x49\xa8\xd9\x83\x35\x77\x6d\x24\xf9\xd7\x78\xf5\x37\xbc\x75\x4d\x8e\x7d\x21\x4d\xc5\x39\x5d\xe0\xd4\xae\x15\x38\x17\x3a\xd0\x48\xb3\x31\xfd\xf6\x9d\x4e\xc6\x24\x56\xdc\x3e\x58\xc4\xd9\x96\x6d\x08\x01\x1d\x90\x67\x43\xd6\x73\x42\x70\x68\x30\x22\x87\x9b\x0e\x27\xf1\x59\x94\x86\x3c\x69\x10\x17\x77\xee\xb7\x1a\x33\xf9\x45\xc9\x0e\xfb\x33\xc0\x48\x26\x08\x9a\xa5\xfd\x68\xe8\xdc\x5f\x3e\x40\xfa\xb4\x04\xa8\xec\x70\x2e\xd9\x0d\xbd\x5c\xcc\x22\x4c\xe9\xa3\xdb\xaa\x59\x4c\x70\x3d\xa1\x38\xdb\x1f\x61\x21\xe8\x21\xf5\x25\xf0\xdf\x8c\xd6\x5e\x1a\x06\x16\x92\x87\xf9\x1e\x96\x26\xa3\x43\x23\x71\x94\xe3\xc3\x1c\x10\x86\x1f\x60\xc7\x54\x22\x3b\x25\xba\xcc\x33\x20\xf9\x7b\x12\xe4\x63\x82\xf6\x73\x14\xd4\x53\xfc\xb3\xbb\xe4\x97\x2c\xf3\xe2\x74\x8b\xd2\x4a\x11\xcf\x92\x26\x43\x0d\xb8\xc1\xc1\xbb\x59\x86\x08\x79\x65\x26\xb5\x64\xdd\x0c\xb7\x8f\xca\x22\x40\x07\x44\x6e\x57\x89\x6e\xea\xe0\x05\x2f\x29\xd2\x67\xa7\x02\xe4\xaa\x98\xf0\xb7\xba\x5c\xf2\xba\xf9\x81\xba\x1d\x61\x30\x07\xb6\x07\x54\xbc\xd8\x31\x51\x3b\xa3\x8f\xe4\xce\x28\x2b\x19\x54\x9a\xd8\x89\xe3\xda\x4f\xbd\xd9\xc2\x1b\x10\xf2\x89\x72\xf3\x97\xee\x28\x85\x63\x03\x0d\x47\x96\xc0\x42\x20\x3f\xad\xdc\xca\xf4\xa2\xc0\x6c\x98\xcc\x67\x9b\xf4\x3f\x74\xa2\xa9\x1f\x6f\xdd\xa0\x64\x49\xc6\x99\xcc\x2a\xa9\x65\x63\xb9\x9b\x97\xc4\x38\x31\x6c\x49\x82\x7e\x0e\x1c\xdc\x29\xd6\xe4\xcd\xc2\xef\x9d\x05\x50\x19\x9e\x32\xc2\xa8\x01\xa2\x5b\x74\x01\x56\xf8\x5f\x9b\x1b\x0a\x4a\xc5\xa9\xa6\x4e\x91\xcc\x9c\x9f\x19\x30\x49\xa0\xbe\xf0\xd4\xae\x59\x01\x9d\x37\x2c\xa2\x30\xf6\xa8\xc9\x33\x50\x3d\x27\x1f\xee\x0f\x4c\x8f\xca\x73\xce\x2b\x5c\x48\xd8\x12\x2a\x49\xad\x06\xe8\xde\x93\x68\xd4\xf9\x6f\x03\xa5\x1d\x10\x2b\x44\x77\x83\x54\x47\x61\xf2\x87\x1d\x3f\xeb\x2c\x9a\x4a\x67\xa7\x9d\xfb\xf2\x35\x4d\x16\x06\x5e\xea\xf1\x76\x7e\xa8\xdd\xf5\x10\xe3\x2d\x76\x67\x7b\x4c\x41\x39\xfa\xf6\xaf\xea\x2f\xc5\x89\x59\xb6\x0a\xdc\xc7\x12\xfc\xef\xed\x57\x27\x75\xd1\xa5\xd9\xb5\xb7\x46\xf1\x71\x6a\x9e\x28\x53\xc3\x54\x5e\xac\xd1\x12\x1b\xc8\x9e\xfa\x51\xb2\x28\xdf\xde\x73\x1a\xee\x11\xe9\x3b\x95\xe3\x31\x16\xe3\x5d\x86\x9c\xb1\x99\x3e\x1f\xee\xf3\x71\x3c\x9b\xf5\x45\x41\x6e\x6f\xcd\x11\x5b\x08\xf5\x55\x3c\xc1\xf5\xd4\xeb\x0a\xf6\x3b\xa7\x4e\xcd\xdd\x21\xf1\xd9\xaa\x9c\xff\x4c\x72\xba\x0f\x0b\xe2\x32\x2f\x87\x2b\xe4\xd1\x4e\xd0\x49\x92\x47\xdb\x03\x11\x00\x19\x2b\x7b\x38\x0f\x1f\xbe\xa2\x41\xc7\xd1\xfd\x13\x91\xa2\x45\x56\xf4\xb7\xd2\xea\x6e\x23\xe6\x12\x68\xfe\xb0\x01\x40\x8b\x59\x61\x35\x63\xcb\x50\xfa\x79\x98\xc1\x9f\x55\xb9\x80\x10\x2d\xd8\xf7\x72\x67\x71\x26\x6f\x50\x65\x15\x78\x82\x95\x9e\x47\x9b\x32\x16\xfa\xda\x4c\x8e\x33\x43\x1d\x09\x9b\xb9\x48\x8a\xb0\x1c\x56\x60\xcf\x49\xd0\xbb\xb7\x52\xdc\x3a\xc4\x64\x0f\x80\xc4\xae\x7f\xda\xd1\x22\xcb\x8c\xa4\x8f\x02\x2f\xc4\xb1\x86\x40\xdb\xf5\xb2\xe3\xad\x7d\x83\x82\xef\xcd\x98\x70\x06\x81\xec\x0c\x17\x73\xc4\x28\xdd\x7c\x31\xd6\x52\x59\xaa\x47\x29\xb7\xbe\x28\x77\x59\xa8\x04\xdd\xd2\x1f\x5d\x1a\xed\x44\x1a\xed\x98\xee\x68\x1b\x5c\x8a\xe2\xe0\x8b\xd1\x6e\x68\x6a\xda\x9d\x2f\x38\x03\x29\xf8\x1a\x47\x5a\xda\x39\xde\xe8\xbe\x26\x45\x68\x0e\xe6\x5a\x83\x10\x99\x4a\x4b\xf8\xb2\x93\x7f\x62\xe9\x8e\x50\x8c\xc8\x6f\x98\x39\x84\x3d\x39\xcb\xa3\xb1\x2e\x64\x55\x62\x14\x03\x41\xb9\x7b\x42\xd4\x8e\x3e\x5b\x2b\x2b\xe2\x4f\xd5\xda\x37\xb3\x19\x54\xe4\x3f\x59\xe9\x0f\x73\x13\xd5\x42\xfe\xed\x86\x1f\xb8\xcc\x6d\xa6\xf2\x87\x59\x50\x63\x74\xeb\xea\xea\x0e\x11\x21\x99\xd2\x2d\x09\x7a\xc1\x52\xc3\x9a\x97\x78\x30\xdf\x02\x2b\x4f\x2c\x7f\x74\x9d\x84\x30\x5f\x79\x96\x40\xed\x1f\x22\x3f\xb9\x66\xff\x15\x12\xfc\x1b\xb0\x60\xe4\x87\x42\x7a\x91\xde\x6c\x19\x43\x90\x6c\x49\x56\xe7\x0b\x9c\xaf\x8c\x3f\x65\x71\x8a\x5d\x6b\x22\x34\x93\xdc\x47\xea\x25\xba\xc8\xdb\x15\xde\x99\x8f\xfa\xf4\xd0\x38\x4b\x96\x50\x33\x0f\x51\xfa\x3b\x54\x34\xda\x33\x78\xef\xb8\xf6\x18\xf3\x01\x0f\x70\xf2\x54\xfa\xb0\xfd\xa9\xc1\x32\x6f\x0d\x44\x76\x22\x84\xeb\x3d\x9a\x59\xdf\xea\x8b\x03\x95\x1f\xf6\x60\x9d\x5d\x3f\x0f\xbf\x7d\x7c\x84\x87\x29\xee\x28\x99\x63\xe6\x86\x7d\x3b\x27\x05\xc5\xdb\xd7\x5c\x59\x2e\x81\x67\xeb\x43\xb1\x7d\xf0\x21\x11\xc1\x68\xc0\x2e\x31\xa5\x4e\x96\x7b\x18\xcd\x49\x65\x83\x4a\x65\x53\x7d\xe9\xac\x9c\xe9\x12\xbc\x1d\x37\xf9\xfc\x87\x00\xda\xf7\x53\x7d\xcb\xbf\xd8\x5d\x0b\x4a\x8d\x1b\x00\x70\x96\xc7\x55\x5e\x35\x09\xd3\x22\x58\xcb\xd7\x92\x59\x49\x06\x80\xa4\x1c\xce\x72\x84\xc8\x96\x64\x4e\x85\x7a\xf4\x63\x83\x02\x2a\x16\x40\x01\x18\xaa\xe0\xdf\x84\x18\x33\x00\x8c\x7e\x2f\xb9\xbd\x94\x2e\x69\xbd\xbf\x9e\x02\x53\x08\x28\x12\x6e\xa0\xf4\x09\xac\xeb\x27\xdd\x25\x15\x9d\x8e\xcd\xe2\x50\xc1\xb3\x80\x5a\x9f\xdf\xce\x26\xb1\xa1\x56\x68\xf6\xe3\xdb\x2f\x49\x83\x42\x0b\xa2\xa3\xd4\x44\xd5\x5f\x69\xec\x37\x8d\x7c\x82\xf6\x00\xbc\x83\x9d\x41\xa5\x26\xe3\xe3\x9a\x9a\xec\x43\x64\xe7\x8a\x40\x54\x7e\x86\xcf\xb7\x18\x83\x03\x7b\xe4\x99\x81\x46\xb7\xf4\x62\xe3\x8e\x4d\xb8\xa4\xf3\x14\x94\xa7\x78\xc1\x14\xd4\x58\x75\x15\x4a\xc8\x2f\x85\x3c\x11\x40\x56\x4f\xe5\xd7\x95\xa9\x24\x87\x36\x5d\x03\xc3\xea\xc0\x90\x0c\x04\xdc\x03\x66\xce\x0f\xac\x7e\xe6\x17\xfb\x89\x7c\xfd\x6a\x0f\xbd\xb9\x0c\x59\xee\xb0\x22\xf0\x7a\xa9\xb6\x26\x4b\x9c\xc8\x76\x81\xb1\x25\x08\xe9\xec\x75\xed\x6e\x34\xb5\x23\x8c\xf4\xc4\xf2\x50\x9d\x91\x04\x95\xd2\x2c\xe9\x2a\xe1\xd3\x1e\x18\xb5\x63\x74\xa6\x7e\x0f\xac\x3c\x3a\xd5\xf8\x22\x7d\x76\x99\x0c\x25\x04\x44\x17\xc3\x64\xc4\x73\x1d\x99\xeb\x1b\x26\xf6\xb7\x1b\xa2\xfb\x9b\x85\x02\x83\xf1\x34\xff\xd5\xdd\x3f\xd7\x28\x8e\x10\xcf\x6e\xe9\x12\x1e\xed\xd5\x46\x37\xae\x23\x65\xf1\x6e\x12\xb3\xc8\x33\xda\xdd\x2f\x96\x99\xed\x43\x18\x6e\x2d\x43\xfb\xaf\xaa\xac\x45\xfc\x77\xee\xe2\xd9\x82\xcd\x40\x20\xef\xe9\xa9\xc1\xc8\xd1\x9d\xdb\x1e\xcd\x67\x97\x00\x62\xcb\x54\xe2\x7d\x51\x18\x91\xa0\xf3\x81\x91\xc1\x1f\x45\x31\xa5\xef\x7b\xbd\x83\xd0\x98\xed\xf9\x5f\x0f\xd1\x5d\x0e\xde\x54\xe5\x39\xd7\xb7\x23\xf2\x57\x7b\xb5\xc5\x0c\x89\x07\x9e\x55\x1c\x32\xcf\x33\x5c\x09\xfa\xc0\xd2\x1d\xa2\x1f\x6d\x5b\x95\x67\xb0\x5b\xa2\x3c\x43\x98\xf8\xfd\xea\x29\x26\x68\x28\xd5\x07\xe2\xc0\xb6\xd5\x47\xb2\x51\x76\xd8\x60\x5d\x6d\x01\x5f\x94\x67\x2b\xff\x81\x88\xec\x78\x5d\x49\xa1\x54\x7e\x60\x77\x16\x7e\xb7\x7e\xf6\xda\xb3\xbf\x0d\x47\xb8\xb5\x50\x7c\x6a\xa9\x73\xca\x61\x1e\x34\xb6\xc9\x0f\xcc\x2a\xcc\x9f\x23\x65\x4c\x71\x08\x03\xc6\xfa\xb2\xae\xcb\x1f\x7a\xa8\x3f\x98\x5a\x60\xaa\xce\xc5\x47\xcb\x7e\xcd\x16\x60\xe0\x81\x1c\xc5\xd6\x92\x6d\x46\x49\xe8\x90\xa2\xe8\xf0\xb8\x65\xfd\x8c\x24\x01\x91\x27\x91\x95\x63\xc7\x2c\x48\xda\xdc\xd9\x91\x0c\xbc\xea\x57\x81\xa1\x88\xf7\xb7\x4f\xe3\x44\xa2\xe8\x70\xb2\xf3\xb8\x40\x15\xe8\x4d\x88\xcb\x90\x9f\x62\x5d\xc8\x96\x25\x0e\x0c\x97\x22\x7b\x2f\xa1\x27\x14\xcc\xb0\x79\xd9\x98\xd5\xfd\x78\x76\xba\x7f\xbe\x15\xea\x0f\xb1\x20\xc5\xe1\xf0\xa5\xae\x8d\x14\x57\x9b\x82\x2b\xa3\x3c\xac\x4f\x0e\x07\xcc\x17\x3f\x80\x30\x2b\xd9\x78\x6a\x3b\xf1\x97\x14\x02\xff\xeb\x58\xe6\x8d\x25\xb4\xf9\xe2\x98\xbb\x63\x7e\x73\xa7\xee\x94\x2e\x01\xeb\xf9\x7d\x89\xf3\x50\x45\xe7\xe6\xfe\x72\x57\x25\x0b\x1e\xf7\xb1\x46\x7e\x26\xe8\x8d\x83\x40\xa0\x32\xeb\xdc\x3b\x51\x8b\x8f\x23\x0d\x95\x3a\x5a\x1c\x84\x6c\xb6\xc1\xbe\x26\x16\x9e\xe9\xa2\x1b\x6f\x83\x42\x16\xe2\xe8\x9b\x1f\xeb\xfa\x4d\xe4\xa1\x3a\x48\x16\xf6\xf8\xa2\x34\xa3\x7e\x67\xa9\x68\x6b\x7f\xa1\x3c\xac\x87\x9e\xc7\x3e\x32\xa6\x19\x22\xff\x48\xb2\xba\x0f\xf1\xcf\xf5\x9e\x5c\xb0\x33\x03\x93\xc6\xfc\xc0\x4c\x0c\x23\x67\x05\xdd\xdb\x40\x68\xfd\x96\xa0\x21\x9e\xdf\x77\x06\xea\xbb\xfa\x0e\xbd\x5e\x4a\xb4\xe1\x9d\x38\x81\x31\xb5\x0c\x15\x2a\x49\x36\xe6\x77\xa3\xfe\x82\x97\x01\x95\x3d\x31\x25\x62\x4d\xe7\xbf\x1b\xae\xf0\x88\xda\x57\x82\x26\xe1\x9d\x77\x89\xc6\xeb\x5e\x8d\x32\xc9\x20\x30\x58\xeb\xcb\xfa\xbe\xef\xe7\x61\x8e\x5d\xa6\xf1\x22\x09\x93\xa3\xa9\xbe\x19\xbf\x4b\xa7\x78\xe8\x0d\x13\x5a\xde\xd9\x19\xf9\x79\x08\xeb\x01\x5d\x41\x5b\x46\x16\x6d\xc4\xd7\xd7\x12\xfa\x80\xd3\xa3\x70\xa0\xe3\xa7\xb6\x2a\x4f\x13\xa1\x0d\xbe\xe1\xa2\x85\x43\x70\x88\x51\x6f\x8d\xe9\xbf\xf3\x25\xab\xcc\x6f\xfe\x72\x5a\x17\x4c\xf8\x32\xd8\xc6\xd5\x22\x79\x18\x1e\xe4\x31\x52\x8c\xf3\x27\xec\xc0\xef\x65\x6f\xfc\x11\xf2\xa3\x36\xef\x81\x83\x8b\x2d\xe6\xf9\xf7\xdb\xd0\x91\x61\xbb\x71\xf0\x64\xc7\xef\xa3\x4c\xfb\xbd\xf3\xc2\xfc\x2a\x66\x71\x1f\x21\xeb\x2e\x09\x44\xbd\x80\x2d\x14\x00\x1d\xfc\xe5\x68\x75\x79\x78\xc8\xc1\x2f\x9b\xdd\x3e\x68\x72\x98\x98\x14\x3c\xef\x45\xf0\xad\x23\xfc\xa8\xfc\x54\xfb\xe9\xca\x94\xdf\x0a\x05\xcb\xba\x7c\x77\x33\x43\x62\x33\xf9\xd9\x64\x32\x8f\x49\x09\xe1\xe9\x2b\xdc\x9a\x3d\x1e\xb8\x4b\x4c\xb0\xc2\x01\xec\x86\xd4\x53\x1a\x39\x81\x76\xc6\x4c\x51\x49\xaa\x04\xa0\x1b\x24\xf5\x1a\x3f\xe4\x94\x27\xbc\x2c\x51\xf1\x8e\x32\x27\x46\x51\x8c\x48\xe9\x63\xe8\xd6\xc0\x6c\x25\x1a\xdf\x51\x2a\x47\x54\xe2\x27\x65\x86\x58\x5b\x12\x2b\x1b\x83\xab\x45\x11\xe8\x18\x98\x29\x9d\x5f\x41\x55\xa6\xcc\x3c\x00\x2c\xff\x7a\xc5\x97\xa5\x9a\x69\x2e\x31\x29\xf8\xf7\x73\x56\x53\xb3\x1a\xcf\x12\x99\x03\x36\xf9\x6a\x71\x8a\x75\x2d\xaf\x5d\x6e\x5a\x39\x0f\xff\x22\x53\x24\x6f\xa2\x56\x57\x9a\x8a\x32\xe7\xf7\x2e\xc2\x6f\xb6\x87\xb2\x8a\xe0\x52\x12\x99\x2e\x69\xda\x8f\x8c\x97\xdf\x6b\xf9\x36\x77\xb4\x95\xa6\x7b\x4d\x8e\x85\x25\xfb\xb2\x0d\x09\x54\xa6\x80\x66\x3f\x64\x0b\xed\xe6\xa8\x8f\x79\x32\xc1\x89\x2e\xb6\x36\xc5\xd0\xda\x8f\xdf\x74\xee\xaa\xb5\xc2\xa4\xcb\x6b\xd2\x6e\xcb\xff\xe6\x28\x93\x5d\xb9\xb5\x7d\x4f\x8c\xaa\xa7\xe4\x77\xb8\xf1\x65\xff\x0a\xe9\xe2\x5f\x1c\xbb\x20\xf3\x8d\x86\x78\x7f\x71\xda\xae\x08\x7c\x31\xb6\x5d\x74\x7f\xc8\x6f\x70\xc4\xbb\x38\xe6\x05\x87\xb2\xc3\x95\xba\x44\x17\x97\xa4\x99\x3c\xad\x3a\xac\xc7\x68\x7f\xae\x3e\xb2\x95\xf5\xfb\xab\xcd\xe4\xee\xca\x1d\x14\xf6\x84\xad\xa6\x8c\x12\xa8\x74\x7f\x12\xcf\xef\x73\xf9\x5f\xdb\x2b\x9b\xde\xb3\x27\x3c\xc9\x0b\x35\xca\x32\xfe\xf3\xad\x96\x2f\x42\x32\x05\x84\x9a\xa8\xca\xdf\x73\xf9\x81\xc2\x07\x45\x9a\x60\x1e\x4d\x02\x81\xa0\xfc\x33\xa2\x1e\x16\x6e\x88\x36\xdc\x19\x9a\xd1\xc6\x4a\x2b\x35\xad\xd5\xef\x33\x6b\x7a\xdc\x1d\x58\x57\x7e\x8e\x50\x25\x9a\xcd\x2d\xe4\xe4\x98\x97\x08\xbb\xe9\x7a\x22\x8a\xd9\x69\xa6\x45\x82\x19\xa6\xaf\xb8\x5e\x44\xba\xa6\x21\xa0\xdc\x34\xc9\xee\x89\xd2\xc7\x8b\x9e\x1d\x40\xa1\xf6\x73\x26\xfd\x27\xdd\x47\x3c\x3d\xcd\x3c\x5f\x76\x19\xfd\xc4\xc0\x21\xa0\x1f\xcf\xe2\x5b\xa8\x9e\xab\xaf\x1a\x3f\x44\xa6\x2f\x48\x8c\x2b\x86\x12\x69\x62\x47\x6a\x97\x01\x80\xa0\xe3\x64\x0f\xce\x91\x84\xca\x74\x42\x4b\xad\x14\x8b\xef\xa4\x0a\x6a\xd8\x33\x3c\x22\x17\x13\x24\xac\xb7\x56\xd5\x1f\x47\xe4\x0d\x2e\xf5\x6a\x8e\x24\x1c\xaf\x17\x62\xbc\x98\xa8\x8b\x51\x6f\x8a\xa0\x29\x1b\x56\xf9\xf1\x25\x18\x15\xb4\x9a\x20\xba\xe3\xbf\x7b\x41\x3e\x97\x76\x75\x23\xfd\xef\x17\x7b\x4a\xcc\x9c\x03\xfd\x8e\x2f\x01\x40\xb0\x56\x93\xe4\x7c\xd9\xa3\x86\xda\x0c\x2a\x8d\xb0\xc5\xa1\xd1\x7e\xbf\xa8\x96\x06\xb7\xee\xc2\x97\xf2\xe3\xeb\x8b\x2e\x8c\x51\xc5\x37\xbe\x2e\x4c\xb4\x5e\x12\xf9\xc3\x98\x14\x41\x12\xd9\x9c\xea\x28\xa3\xa4\xa2\x39\x10\x47\xda\xca\xd3\x7b\x22\xe9\x86\x41\xe5\x8e\xe8\xf5\x2a\xbe\x33\x9c\x1b\x58\x0e\x0d\xb1\x0d\x47\x26\xcd\x72\x29\x83\x5b\x9a\x2b\xa0\x79\xf5\x6e\x06\x4d\xd7\xd4\x66\xca\x8c\x67\x18\x63\xb9\x2f\x0b\x74\xf2\x6f\x13\x4b\x6e\x44\xca\xcd\xe7\xea\xe4\x8b\xd1\x51\xe7\xf3\xc7\x8c\x46\x6a\x8e\xa7\x08\x40\x38\x4b\xa9\xef\xb3\x16\x6d\xa6\x37\x6d\x53\xeb\x44\x72\x95\xf5\x15\xff\x7d\x3b\xf9\x86\xa1\x4c\xd3\xd2\x54\x79\xab\x49\x31\x5f\x2f\x89\x65\xec\x96\x65\x73\x10\x9e\x61\xc7\x81\xb9\x2f\x48\xfa\x71\xfd\x36\x42\x25\xee\xae\x82\x65\x21\x8f\xf6\x2c\xd8\xcc\x10\xb3\xe2\xe4\x8b\xa9\xc4\x3f\xe0\x37\x6d\x15\x3d\xe9\x92\xcc\x2f\x78\x49\xd1\x82\xbe\xb9\x7d\xb6\x22\xf4\x29\x62\xbf\xb6\xf1\xc5\x79\x8a\x7f\xba\xce\x18\x31\x07\xd7\xcd\x48\x79\xd9\x8c\xce\x76\x5d\x1b\x72\xe8\xd0\x25\xb8\x45\xd2\x9b\x84\x9b\x70\xab\xd8\xf5\x8f\xeb\x2a\x8d\xad\x39\x96\x2d\xac\x33\xb8\xbd\x01\x33\xbc\x10\x26\x0e\x7a\x40\x71\x88\x3c\xbd\xee\xd3\x3d\xd5\x02\xbe\x6b\x0a\xbb\x87\xcc\xcb\xc4\xee\xba\x29\xb2\x26\xae\xdc\x01\xa2\xc5\xad\xc4\x21\x98\x8a\xf4\x4d\xee\x6e\xa0\x95\xa9\x35\x57\x00\xe5\x8e\x96\xe7\x46\xfa\x9a\x9c\x62\x58\x89\xad\x48\xa6\x8e\x05\x8c\xdc\x8d\x16\x83\x91\xa4\x5b\x02\x9c\x63\xcb\x5e\x1d\x54\x9a\xdd\xb8\x27\xdd\xaf\x35\xc2\x72\x37\x46\x8a\x83\xd8\x68\x0f\xe0\x79\xc8\x20\x6d\x74\x57\x76\x4f\xd3\x7d\x7b\x72\xd5\x81\x7b\x39\xca\x42\x43\x25\x16\xdb\xe0\x21\x2c\xd9\x4a\x3d\xc3\xf8\x51\x4e\x85\x5d\x75\xd0\xb3\x18\x81\x61\x8e\xee\x6b\x1f\x30\x5d\xfe\x3c\xd2\x28\x49\x1f\x19\xde\xe8\xcf\xea\xb3\x33\x80\xce\x3e\xf6\xfc\xb1\x4f\x26\x77\xb8\x35\x5e\xe1\x92\x2d\xfd\xde\x35\x8e\xe7\x4e\x1a\xf0\x3a\x3b\xef\xbf\x5f\xab\x9c\x0b\x57\x7d\xd4\xb4\x11\x97\xd1\x6c\x86\x50\x0d\x1f\x6b\x70\x86\xfb\xfd\xcb\x85\xa8\xc9\xd7\x5d\xfe\xb5\xf1\x27\x37\xa6\x1f\xf1\x00\x6e\x57\x9c\x6e\x01\x2e\x01\x27\x62\xed\x11\x99\xfe\xa9\x8a\xb4\x8a\xbc\x88\xa8\xa9\x4d\xaf\x33\xa6\xa3\xc5\x03\x74\xb4\xad\x4f\x2a\x5f\x35\x9d\x53\x69\xc7\xaa\x2b\x24\x93\xec\xa2\x3b\xc3\xd6\x8f\xb6\x6d\x91\xc4\x33\x70\x18\xac\x4e\x61\x39\x04\x6c\x10\xda\x02\xa4\xd9\x72\x07\xd7\xde\xdd\xd5\xad\x10\xc4\x2b\x97\xec\x7c\x2d\xce\x66\xb5\xf4\x9c\xf0\xb1\xd9\xf8\x36\x15\xca\x6a\xdb\xc2\x73\x57\x07\x40\x89\x68\x42\x5c\x33\x98\xed\x7e\x8e\x8b\xe8\x62\x8f\x5c\x1d\xad\xbb\x29\x9d\xcc\x95\x26\x18\xf4\x60\xa2\xb7\xe7\x59\xe6\x29\x03\xf9\x53\xa4\x20\x32\x8b\x9d\x2d\x56\x4d\x1f\xde\x28\xe7\xab\xc9\x49\xa8\x60\xf6\x55\xee\xdd\x98\x83\x2a\x19\x80\x8e\xee\x9e\xec\xbf\xaa\xc6\x3d\xe4\xc4\xa8\x74\x77\x7f\xd7\x56\xaf\x2e\x9d\x19\xef\x04\x27\xbd\x5b\xce\x7a\x93\xed\x0f\xb1\x60\xba\xe5\x98\xdc\xa0\xc6\x5b\xdf\xdd\x2f\x70\xea\x6c\x9c\x21\xee\xf2\x3e\xbb\xca\x21\x6d\xcc\xd7\x30\xd9\xf1\x19\x28\x9b\x08\xfd\xae\x77\x4f\x7c\x98\x5a\x63\xeb\xf6\x54\xe1\x66\x5a\xcc\xcc\x74\xdf\x6e\x8d\x29\xef\xca\x84\x9a\xd1\x5b\xbb\x08\x81\x31\x23\xd1\xf9\x59\x2c\xe8\x8f\x1f\x21\xc0\xd7\x1f\x92\xaf\x36\x43\xe4\x9d\xb4\x49\x2d\x3c\x32\xea\x18\xd1\xbf\x6c\x67\x57\x99\xd0\xf2\x93\x62\xb2\x5f\x94\xc9\x3a\xbf\x19\xd0\xbd\x4f\xb0\xad\x33\x8c\xd6\xac\xad\x0d\xde\x53\xbb\x7b\xbc\x28\x17\x63\x14\xf4\x0d\x4e\x64\x46\x53\xcd\x89\xd7\xb3\x75\x30\xe3\xa2\x42\x4c\x74\xf6\x41\xa0\x58\xa8\xa5\x3c\xf4\xfb\xa4\xd9\x29\x3e\x3b\x44\xaa\x2d\xfd\x28\x58\x95\xe4\x3c\x5f\x3a\x69\x1e\xf6\xb9\x8b\xc1\x95\xe9\x60\x59\xc9\xe4\x38\x07\x8a\x87\x4e\x2f\xd5\x09\x19\xc6\xe6\x60\x11\xd0\xdf\x3d\x50\x2c\xe5\xa8\x36\xb0\xf7\x0a\x48\xe8\x63\x08\xd8\x0a\xb1\x82\x89\x9c\x20\x59\x8a\x47\x43\xef\x64\xeb\xfd\xc9\xbe\x6c\xbb\x7e\xbb\x23\xe4\xeb\x0b\x7a\x01\xd1\xfa\xb7\x7c\x58\x88\x59\x68\x77\x54\xe0\xe0\x93\x98\x51\x49\x09\x1a\x72\xc0\xb8\xf7\x60\xd4\x8e\x74\xe8\xb7\x15\xdf\x19\xe5\x2f\x58\x0a\x55\xd0\xab\x0e\x2e\x9b\x0a\xa7\xd8\x89\x66\x90\x4c\xc4\xe6\x8e\x2d\x3a\xd7\x61\xde\xdf\x06\x89\x36\xd1\xa4\xf8\x93\x37\x48\x0b\x13\x9e\x6d\x5e\x18\x06\x67\x06\x2a\x3f\xfa\x90\x1d\x00\xb7\xfd\xd8\x2a\x12\xf9\x1a\x79\x28\xe3\x92\xe4\xa4\x59\x96\x7d\xf5\xef\x28\xe8\xc8\xe2\x33\xba\x04\xb1\x05\x6a\x5e\x7c\xea\x7d\x81\x13\xf5\xdb\xc5\x7c\xf5\xe7\x61\x4f\xc7\xfb\x51\x61\x54\x70\xd0\x1e\x62\x8d\x8f\x17\x0c\x42\x91\x34\x04\xef\x53\xc5\xe3\x76\xc7\x22\x8c\xe8\xaf\x8d\x33\xc5\x25\x29\xe6\xb8\xe2\x0a\x97\x8d\x2c\xa4\x89\xfd\xba\x63\x54\xfd\x58\x0f\x2f\x77\x55\xf3\xf1\xbe\x76\x38\xbe\x33\x83\xc9\x7c\x2d\x05\x7d\xde\x73\x39\x37\xa4\xf9\x61\x4d\xe8\x0f\xb8\x25\x9c\xe7\x9b\x24\xc3\x9d\x45\xdb\x38\xe2\xf9\x7d\xf4\xfb\x2a\xcf\xb4\x7c\x2a\x90\xdb\x8b\x5e\x3b\xde\x26\x7f\xec\x60\x53\x87\x6f\x1d\x5c\xe0\xe5\x34\x89\xae\x10\xe2\x48\x7b\x73\x6c\x2f\x7b\xc4\x48\x91\xaf\xff\x02\x74\x65\x14\x18\xbd\xee\x4d\xfe\xe3\x3b\x01\x2e\x04\x34\x5d\xb6\x03\xb3\xde\x2d\xbd\x94\xc4\x1d\x95\xc7\x44\xcd\xde\x9a\x7a\xdb\xf3\xb5\x27\xd1\x52\x03\x3f\xd8\xb6\x12\x8a\xcf\x37\x03\x42\x9d\x0e\x08\xaf\x8d\x3e\xbc\xaf\x29\xef\xb6\x7d\x2c\xb5\xfd\x44\x1b\xfc\xb5\x08\xd5\x29\xa2\x90\xdc\xa6\x61\x4b\x83\x41\xfd\x36\x8f\x87\x6a\x95\x60\x73\x6b\x47\x18\x96\x00\x55\x79\x76\x60\xb3\xae\xf4\x67\x88\xe8\x76\xb6\xfd\xea\x9a\x54\x7f\xad\xd7\x33\xce\x92\x38\xdd\xfe\x0b\xd3\x7d\xfb\xf2\xf5\xc4\x4d\x45\xd9\xe3\x1b\xd3\x6f\x5a\x4f\x0a\xdb\x0e\x81\xf0\x65\xcf\x73\x6d\xcb\x9a\xff\x44\xed\x1f\xbb\xd7\x97\xcc\xa5\xc9\xbd\x65\xe2\x39\xc8\x49\x80\xec\x2b\x42\x12\xc9\x19\x4a\xbf\x2f\xa1\x3b\xcd\xa6\xf2\x57\x38\x5e\xf4\xc4\xf1\xb1\x3c\x9a\xc1\x8d\x1a\x02\x4b\x72\x89\xc3\x39\x4a\x3b\xbd\x9c\xf0\x51\x3b\x0b\xa1\x0a\x7a\x09\x55\x99\x37\x96\x83\x42\xf9\x8b\x12\xdc\xfb\x45\x7e\xad\xcc\x12\xfe\xdd\x69\xf5\x02\x95\x21\x5c\x47\x8b\x61\x85\x89\x23\x81\xc3\xde\xf8\x96\x42\x5d\x19\xa6\x3c\x44\x77\xaa\x1d\xf9\xd0\xc5\x59\x4d\xb2\xe3\x7d\xfd\xdd\x0c\xdf\xbb\xd0\x6d\x9b\x23\xf0\x63\xf5\x97\x47\xb1\x8f\xcf\x92\x00\x4b\xe3\xf2\x83\x8a\xd7\x04\xdd\xd5\xc8\xfc\xc1\x71\x23\x50\x0b\xbd\xef\xea\x0a\xbb\xfc\x79\x88\x63\x1c\x74\x4e\xc5\x55\x01\x0f\x61\xea\x78\x62\x2b\xca\x0b\xeb\x4b\xb4\x7c\xbf\x0f\xb0\x6c\x93\x1e\xed\x62\xaf\x95\xc0\xc1\xd5\x5f\x69\x60\x89\x04\xed\x7f\xed\x60\x7c\x89\xfa\xa6\x4d\xbe\x26\xea\xc8\x41\x8f\x53\x79\xb6\x35\xd6\x00\xfd\x11\xb9\xc4\xec\xa4\x15\x87\xcc\xea\x13\x52\x90\xb6\xa3\x74\x7f\xa2\x1d\x39\x16\x38\x74\x35\x1a\xad\x8c\xea\xb4\xfd\x84\xae\xc8\xc2\x6f\xc4\x7f\x02\x90\xfa\xf8\xb5\x38\xb2\x9b\x5b\xb7\xd6\xa6\x28\x73\x0a\x35\x27\xc9\x30\x54\xfe\x92\x61\x9e\x00\x41\xd3\x7f\x0f\x77\x49\x24\x85\x99\xd2\xc7\x28\x66\xa3\xca\x43\x12\x44\x9d\x0d\x47\x8c\x38\xd2\x2d\x37\xc4\x1f\xb3\xc6\x78\x1e\x78\x52\xf0\xc6\xa8\x4d\x6b\x43\xce\xa0\xfb\x98\x5e\x0c\x11\xdd\x5a\xf8\xd5\x03\xdc\xe2\x4b\x89\x29\x79\x02\xe0\x91\xf2\x25\x8a\xb0\xc7\x77\xdc\xea\xe8\x21\x33\x47\xf3\x37\x8e\x08\xc5\x5b\x97\x4e\x64\x79\xf1\x97\x47\xf9\x2b\x13\xa1\x72\xa4\xf0\x37\x50\x65\xe9\xbd\x99\x43\x7e\x8e\x88\xe3\x64\xc7\xeb\x61\x5f\xc4\xef\x8a\xd4\x60\x83\xad\x02\xe1\xcb\x5b\xb4\x01\x81\x72\xa9\x37\xab\x6a\x7c\xe4\xa1\x8a\xde\xd7\xf2\x57\x51\x7b\x70\x21\x50\x9a\xcd\x5b\x7f\x73\x0b\xb4\xab\x1b\x3b\x67\x99\xa2\x11\x9b\x7a\x62\xb7\xf3\x97\xc1\xeb\xa7\x1b\x5c\xe6\x18\x7d\x53\x98\xb8\xd0\x7e\x9c\x41\xa3\xee\x40\x91\x49\xf0\xde\x2e\x44\xab\xb0\x63\xe1\xdd\x85\xc1\xf5\xc4\xcf\x31\xbf\x23\x67\xbc\x57\x13\x95\xb7\x76\x15\x2a\x6c\xc7\x6d\x9d\xca\x55\xeb\xf0\xce\x73\x1e\x20\x87\x9a\x39\x44\x2b\xf2\x3d\x5d\x18\xe4\x86\xda\x32\x8e\x9f\x64\x41\x6c\x68\x4a\xbd\xfb\x15\xe9\x14\x0d\x79\xb3\xe2\x0c\xce\x1b\xe7\x2f\x4e\x5b\x5b\xa8\xa2\xd2\x33\x44\x18\x85\xff\xe5\xbe\xe1\x0c\xd7\xf2\x74\x1e\x22\x87\x5d\x66\x4a\x11\x94\xc1\x87\xbf\x57\x79\x84\xdc\xc0\x3c\xc5\xc0\xc8\x2d\x4c\x77\x14\xfa\x84\xd4\x95\xa1\xda\xb8\x93\xd0\x07\xec\x0c\x28\x91\x4b\xad\x5f\x42\x88\x7a\x61\x73\x7f\x96\xf4\xd6\x92\x21\x8f\xef\x0f\x65\xd5\xe7\xcf\xe3\x17\xa2\x38\xa2\x85\x65\x35\xf5\x18\xd3\xdd\xe9\x66\xf3\x7b\xda\x1e\xff\xc1\x4d\xa6\xbe\x08\xb2\x08\x4f\x75\xca\x34\x8d\x1d\x4c\x85\xa2\x98\x1d\x4b\x7f\xf9\xce\x6d\x34\xf1\x99\x91\xbc\x0c\xea\x0b\x4f\xd9\xa4\xc6\x55\xe3\x59\x76\x71\x92\x1e\xfb\x54\x56\x42\x72\x04\xf6\x5b\xeb\x22\x03\xdd\x90\x18\x29\x56\xe1\x28\xdd\xac\x38\x3a\xd9\x9f\xd7\xcf\x8f\x55\x3d\xf9\xb9\xf1\xf6\xe3\xe3\x14\xf9\x72\x5f\xbe\x77\xd9\x18\x51\xf8\x12\x61\xe7\xdf\xa0\x80\x51\x69\xea\x03\x53\x2f\x79\x93\xb5\x8d\x1e\x4d\xe3\xd6\x92\xa2\xb1\x45\x55\xd2\x4a\xc7\xd9\x17\x45\x50\x28\xd3\xd9\xc2\x6b\x20\x5f\x0c\x0a\x1d\xbb\xe1\xd8\x3f\x62\x6b\x6d\xa3\x25\x84\x34\x1d\x39\x09\x66\xb3\x63\x23\x2a\xfa\x17\xe9\xe2\xf8\x60\x27\xf6\xa7\x1d\x4d\x56\x39\x02\x21\x99\x72\x45\x20\x8a\xef\xf4\x3c\x5e\x9a\x65\x99\x27\x90\x43\x24\x5b\x96\x5b\xbf\x21\x09\x65\x0e\x17\x5a\x40\x6a\xe7\x04\xa2\xd8\x52\x01\x92\xc0\x7b\x52\xe2\x91\x26\xa6\xf3\x4d\x93\xf1\x8f\x30\x88\xbf\xf1\x2f\x7a\x70\x6c\x69\xf2\x00\xc0\x1d\x04\x75\x86\xed\x3b\x93\xba\x81\xed\xc1\x2a\x6f\x91\x11\xac\x1d\x33\xc3\xd4\x26\x9d\x92\x4b\xf2\x2e\x99\x02\x06\x9c\xe7\xb2\x07\xbb\xac\x0b\x52\x0e\xd9\x22\x46\xed\x98\x0a\x40\x65\x7b\xec\x87\xc6\x2c\xdd\x00\x97\xc0\x47\x9a\xf6\x28\xad\xe4\x7c\xc8\x71\x36\xc5\x15\x27\x0d\x47\x16\x20\xb5\x68\x66\xe3\xcd\x98\xf6\x8e\xa8\x04\xdd\x4f\x79\xdb\x13\xa3\x8d\xfe\xfe\x27\x91\x74\xa7\x93\xa9\x7b\xd7\x22\xc2\x90\xaa\xbe\xa2\xf0\x5b\x27\x0a\x74\xc7\x92\x5b\x35\x5f\xaa\x7d\x8e\x3f\x7f\x86\xe8\x6e\x63\x05\x11\x7a\x72\x6d\x74\x69\x2e\x5d\xde\x4f\xd4\x1a\xde\xea\xbf\x15\xf1\xc0\x45\xbd\x6b\xd1\xe7\x3a\x79\x6c\x7c\x89\x77\xab\xc6\xf6\x88\xdc\x78\x68\xe8\x98\x73\x12\xf7\x08\x44\x77\x6e\xe3\x1d\x45\xd5\xad\x89\xcf\x50\x71\x86\x54\x1f\x2e\x8f\x7c\xa2\x87\x3e\x9a\xd4\xc5\x14\x34\x14\x3f\xfb\x9e\xd6\x2a\xca\xd3\x63\xd0\xd3\x75\x6b\x64\xae\xfa\x85\xe1\x93\x44\x72\x94\xd4\xc6\x76\x3d\x51\xb2\x09\xd8\x34\x46\xd5\x86\xd6\x8f\x69\x95\x59\xbf\x8f\x83\x49\x06\x60\x8d\x0f\x4c\x56\xc1\xec\xaf\x09\x1a\x65\x85\xc9\x46\x78\x2a\x53\x42\x01\x4d\xe8\xd0\x10\xa6\x3b\x39\x86\xf8\x66\xaf\x56\x1e\x82\x11\x22\x3b\x75\x93\x64\xce\x38\x40\x91\xb5\xc5\x8c\xd1\x78\x68\x4e\x5f\x73\x93\xd2\x8d\x69\x28\xd6\xd0\xd3\x10\x95\xeb\x93\x54\xcd\x71\xfa\x97\x29\xf2\x64\x67\xd3\x44\x4c\x56\x35\x2b\x7c\x2c\xb6\xa0\xbf\xad\x36\x0f\x7c\x3d\xf3\x0c\xe4\x33\xb6\x97\xff\xf6\xf3\x3e\xaa\x48\x57\xd4\xef\xdb\x7e\x66\x69\xf0\xfa\x38\xd8\x03\x35\xd6\xca\x0f\x4c\x9e\xd0\xe7\xcd\x8f\x77\x58\xfd\xbd\xaa\x1f\xd9\xf9\xfe\x90\x9d\x4a\x61\x91\x59\x4f\x84\xc2\x99\xc0\x61\xf3\x3c\xcc\x61\xf6\x73\x95\x5c\x32\x25\xdf\xba\x1b\x20\xa5\x73\x51\xb1\xf9\x1e\xd8\x25\x43\x65\x5d\x31\x71\xf5\x1a\x8f\xe0\x59\x85\x63\xde\x85\xa3\xe0\xc4\xec\x96\xe5\xac\x6b\xe1\x74\x6d\x3f\xf3\x36\xf4\xef\x6e\x68\x22\x01\xd3\x64\x1a\xf4\x41\x15\xbb\x47\xf5\x45\x4c\x3a\xae\x69\x3d\xde\x50\x7c\x5f\x67\xcd\xa5\x30\x84\x4a\x8a\xa1\xa4\xa1\x44\x3d\x80\xf6\x6b\xbd\x48\xe5\x3e\x6f\x76\x0c\x06\x75\x4c\xd1\x60\x65\xa6\x41\x9f\xcc\xc7\xf1\xfa\xf9\x4d\x17\xe4\x84\xa1\x5c\x99\x7e\x02\x4e\xa4\xfa\x80\x40\x4c\x31\x05\x85\x47\x4c\x22\x03\x41\x3a\x7d\x01\xe9\xd5\x1e\x8f\x16\x93\xd8\x35\x12\xa1\xb1\x35\x53\x74\xc7\x6c\xfd\x76\xef\x32\xd6\x3d\xb6\xde\xc4\xa3\xff\x2e\x38\x30\x7f\xe0\x57\x9c\x5f\x27\x71\x49\xf7\xdb\xdc\x52\xef\xca\x10\x96\xee\x24\x00\x19\x25\x77\xcd\xe4\x73\x78\x34\xf7\x0f\xd6\xd1\xe3\xd9\x18\xd4\x2a\xf9\xcf\x8b\x88\x6d\x66\x9d\x81\x66\xdc\xbb\x6a\xd1\x5f\xd1\x15\xae\x5d\xe2\x56\xe7\x53\xb3\xe5\x48\xfc\xf1\xe7\xe7\x76\x37\x6c\xd1\x28\xb9\x20\x44\x2c\x11\x45\xbc\xf3\x5b\x2e\x1c\x5d\x54\xbd\x6f\x9c\xcc\xcd\x91\x76\xc6\x17\x55\xee\xbe\x21\x4a\x73\x0c\x49\xfd\xf7\x92\xbe\x0e\xb9\xb1\x73\x04\xe0\x25\x10\x65\x9c\x9a\x30\x7c\x19\x10\x70\x65\x1a\xca\x6f\xb6\x10\xd9\x39\xbd\x3f\x7d\x0a\xae\xee\xcb\x47\xf9\x75\x2d\x4a\x33\x15\x63\x63\x5a\xc1\xc7\xb1\x75\x46\x75\xab\x62\x1b\xff\x8a\x1b\x79\x68\x94\x7f\x10\x34\x62\x46\x5d\xd0\xd3\x4d\x6b\x64\x36\xb9\x90\x42\xd6\xee\xdc\x1b\x79\xd7\x20\x3c\x70\xd3\x08\x1b\x7f\xb3\xd9\x02\x31\x20\xf4\x72\x31\x66\x06\x85\x08\x6b\x4a\x7a\x89\x60\x45\x56\x44\x08\x5d\x86\x2e\xb3\x49\x69\x96\x23\x4c\x99\x03\x9e\x5d\xb9\x60\x6f\x70\xf5\x15\xc0\x50\x98\xda\x97\x63\x5e\xa2\x1e\x51\x30\x1f\xc9\x43\x7a\x0f\xfa\xdb\xf7\xa3\xe0\xe7\x11\xf9\x9b\x15\xd9\xdf\xd8\xba\x53\x17\x87\x6f\x1d\x8b\xd5\x64\x8a\xae\x5d\x9b\x47\x3e\x37\xfc\x94\xbd\x19\x13\x95\x32\x4c\x96\xf4\x99\xde\xff\xd1\x74\x16\x4b\xd6\x32\xcd\x16\xbe\x20\x06\xb8\x0d\xb1\x8d\xbb\x33\xc3\xdd\x9d\xab\x3f\xd1\xef\x77\xfe\x01\x11\x1d\x1d\x7b\x40\x15\x59\x2b\xd7\x93\x50\x59\x40\x46\x84\x93\x7e\x0d\xc5\xa4\x40\xd3\x1f\x27\x2d\x23\xb6\xa3\xd6\xf4\xc1\x46\x10\x54\xe8\xf8\xc3\xeb\x1e\x89\xd1\x7a\x56\xd9\x7e\xcf\xd0\x34\xde\xac\x84\xf8\x92\xbd\x57\x4a\x38\x53\xf9\x99\x30\xbb\x1d\xcd\x40\xb0\x7b\xfa\x2f\xda\x50\xe1\x87\x81\x3d\xd6\x7f\xbb\x18\xff\x18\x86\xab\xb1\xcc\x6a\x6e\xf7\x7c\xb1\x25\x0d\x86\xf0\x3b\xc9\x1f\x36\xd4\x8e\x07\x45\x1a\xfc\xe6\xe6\x04\x11\x45\x63\xac\x92\x56\x5c\x68\x86\x43\x54\xa2\x61\xb4\x12\xfa\x83\x91\x9e\x11\x0d\x2a\xbb\x63\xa4\x60\xae\x67\xe9\x03\x17\x53\xe0\x6f\xc1\xa8\x79\xe9\x38\x34\x89\xe8\xf9\x27\x44\x5f\x88\x4a\x33\xee\x8f\xbd\xad\x2f\x47\x69\x2d\x79\x7e\xa6\x37\x45\xe4\x73\x33\x41\xf2\x35\x6a\x3e\x45\x2d\x63\x3b\x0c\xae\xb0\x0f\x22\x2f\xe9\xbb\x5f\x12\xff\xc8\xdd\x08\xf7\xeb\xc0\x12\x56\xef\x95\x17\x66\x80\x52\x24\x7d\x0b\x4a\xd2\xe7\x81\x12\xa5\xf2\xe3\x05\xe5\xfe\xf6\xb4\x14\xa2\x52\x63\x1b\xa8\x98\x5c\x34\x3b\x86\x25\x09\x09\x2b\x03\xa1\xe9\x0f\xfd\x4c\xc9\xeb\xa9\x9c\xca\x74\x54\xb9\x73\x2a\x84\x06\xed\x2b\x50\x8a\x4a\x8d\xea\x85\x8b\x76\x8e\x3b\x3e\xfe\x99\x0b\x7a\xe0\x25\x04\xa4\x7a\x33\x22\x5d\xea\x0a\xba\x27\x3c\xa3\x97\x74\xc0\x66\x27\x10\x71\x6e\xeb\xbd\xab\xdc\xba\x6e\x2b\x39\xe4\xff\x5e\xc0\xaf\xeb\x4a\xec\xd4\x07\xae\x0e\x26\xe2\x3c\x82\xef\x88\x63\x63\xd5\xaf\xf0\x83\x51\x1f\xca\x23\x8c\x2d\x85\xf2\xd3\xee\xef\x67\x31\x5d\x9e\xc1\xa5\x15\x14\x5e\xec\x9c\x1c\x71\x3a\x29\x31\xfd\xd7\x93\xc5\xaa\xe8\x5c\xa3\x20\xee\x58\x04\x81\x13\x60\x56\x1f\x98\xab\xfa\xee\xa8\xc6\x9a\x9d\x6c\x54\x06\xef\xc3\x05\x00\x66\x2d\x35\x3d\x13\xc0\x87\x17\x08\x8e\x59\xb0\x3f\xa5\x5b\xfc\x40\xeb\xe6\x63\xfd\xec\xf4\x4e\x7e\xb3\x03\xa1\xda\x3c\x46\xba\xd3\x92\xba\xdd\x04\xb4\x3f\xcf\x93\x5a\x62\x27\x24\x9d\xe0\xdb\x26\x89\xb2\xaa\x0b\xcd\x0c\x9b\xc1\xd4\xc5\x87\xf0\x61\xf0\x31\x7b\x69\x19\x6c\x80\x60\x8e\xfa\x14\xb5\x5e\x3d\x6e\x3a\x3b\x9a\x29\xbf\x4d\x39\xe6\x6c\xfc\x3d\xa6\x59\xcb\xca\x9e\x67\xdd\x3c\x2e\x44\x29\xd6\x32\x99\x1e\x4f\x72\x2c\xa6\x53\xa0\xe4\xb1\x05\x2b\x50\x23\xd4\x02\xce\xc4\xb9\x9d\xa8\x66\x90\xc4\xe5\x2c\x83\x40\x98\x30\x54\xb0\x76\xfa\x4b\x76\x24\x3e\xc2\xcd\xbe\xf5\xcf\xf0\x02\xb8\x02\x3f\x54\xc1\x88\xb2\x92\x1a\x5f\x6b\xde\xd3\xdf\x9e\x9f\x07\x3c\x23\x73\xff\xad\x67\x74\x85\x49\x03\xfb\xe0\x65\xe5\xfa\x45\x73\x3a\x18\xc2\xf7\x43\x90\x4b\xec\x04\x4b\xcd\xad\x67\x86\xb5\x7b\x10\xf1\x4c\xe0\xf2\x56\xd4\x39\x91\x9f\xff\xf8\xac\x96\xc4\xa9\xfd\x91\x34\x80\x05\x11\x52\x06\x1a\x8c\x20\x21\xe9\xcc\xb5\x47\x82\x92\x50\x48\x0f\x01\x91\x47\x57\xb4\x61\x97\x73\x34\xd7\xc5\x92\x75\x97\xf2\x57\xcf\xa2\x0c\x1f\xac\x18\x0e\x4b\x26\x3c\x7a\xc6\xa5\x36\x16\x1b\x41\x50\x44\x0e\x42\x39\x8e\x81\xcd\x1a\x77\x0b\x81\x68\x7e\x88\xab\x53\x56\x21\x05\xcd\x6a\x4e\x0b\x5d\x4e\x19\x0c\x42\x8c\xc3\x39\xae\xe6\x50\x6f\xa0\x3e\xf4\x31\xcc\x30\x41\x16\x77\x6e\x4a\x85\xf4\x23\x10\x17\x68\xb7\x95\x00\x12\x1a\x00\xb4\x9e\x6c\xb7\x32\xc9\x2f\x34\x29\xfc\x40\x70\xce\x19\xa5\x58\xa5\x38\xd1\x18\x2b\x2d\x20\xab\x31\x8e\xb7\x94\xbe\x06\xad\x07\x4b\x84\x6a\x1a\x3f\x67\x7f\xda\x1c\xa4\x30\x8c\x02\xaa\xea\xa8\x37\x3e\x2f\x92\x30\x1a\xb6\xe2\x44\xd2\xf0\xd8\xe6\x27\xe8\x65\x2e\x26\xc4\x81\x33\x84\x45\xc7\x2f\x70\x62\x6a\x2c\x37\x19\xc7\xd1\x3d\x88\x06\xfb\xaa\xe6\x30\x60\x8d\x5c\x01\x36\x3a\xc7\xcb\xca\x3b\x28\xa2\x02\xa1\x59\x30\xf1\x52\xb6\x95\x0b\x4d\xfc\x76\xfa\x04\xf2\x3b\x37\x35\xdc\x0f\xc1\x5a\x60\x77\x59\x5e\xde\xbc\xb7\xa4\x3f\x0b\x88\x02\x01\x44\x14\xe6\x9f\x32\xdd\x30\xbe\x55\xd2\x43\x41\xbf\x5a\xe8\x7d\x53\xb5\x7f\x20\x58\x00\xa4\x8b\x57\xfb\xb8\x50\x9d\x25\xda\x0a\xb1\x62\xb4\xd0\x08\x79\xaf\xb8\xa1\xe2\xd1\xc0\xb3\x03\x16\x12\x79\xe7\x13\xa9\xc6\x93\xf3\x6d\xee\x05\x3b\x42\xa3\x0e\xfc\x2b\xa8\xf1\xdd\x37\xf5\x18\xbf\xb4\xf9\xc5\x1d\xf8\xa4\x6c\x0e\x64\x06\x9a\x35\x78\x4f\xac\xb1\x08\xa8\x9e\xf4\x4e\xd3\xf3\xd1\x20\x38\x3d\x35\xfa\x61\x4f\x1b\x53\xa9\xe5\xcc\x52\x5e\xab\xed\x4a\x94\x68\x76\xea\xe2\x18\x0c\xab\x1d\xa0\x2f\x05\x5a\x17\x4a\xee\x96\x2a\xb4\xc1\x9b\x7c\xb0\x58\x92\x27\xdf\xed\xbb\xdc\xc9\x2d\xd3\x5b\xdb\x40\xb7\x54\xee\x18\x3b\x0b\xbe\x17\x61\x76\x33\xc9\x23\x37\x4a\x79\x02\x2b\xc0\xa7\xa9\xa2\xd9\x61\x8c\x4f\xfa\xe4\xc0\xd0\xb7\xbf\x61\x85\xd3\x22\x52\xa0\xc6\xf0\x75\x6b\xba\x85\xae\x82\x86\x92\x7f\x4a\xc0\x9c\xbc\x5d\xd9\x68\xd4\x78\x6f\xbe\xc6\x59\x9c\xb5\xe2\x01\x81\x4c\xc9\xf9\x6c\x68\x00\x86\x29\x83\x68\xed\x00\xd8\x79\xe3\xee\xdc\x00\x4a\xab\xd4\x3c\x92\x4e\x69\x00\x48\x8f\xf0\xeb\x73\x7e\xd8\x8a\x94\xad\xf5\x67\x59\xe0\xf4\xce\x75\x89\xe3\x00\x2f\x78\xc9\xb2\x45\x01\x72\x40\x20\xf1\xea\x45\x0e\x3a\xb5\x59\x61\xec\xc8\xf4\x20\xd6\x9d\xa6\x07\x2d\x4e\x14\xc6\xcb\xa8\xc5\x4c\x3c\xc5\x4e\xad\x33\x26\x30\x16\x24\x51\xc9\xc2\x2d\x38\xac\xc9\xc3\x8c\x2a\x61\xce\xdd\x13\x1e\x7b\x15\x6c\x5f\x61\xd6\xfe\x9b\xb6\x18\x61\x6b\x48\x0f\x17\x8e\xe0\xeb\xae\xbc\x22\x17\x3a\x34\x3d\x9b\xd3\x57\x89\xb4\xe0\x66\xa5\xc5\x48\xa4\x20\x08\x60\x84\xc2\x0a\xa7\x4f\xc4\xd4\x52\x2f\x68\x5f\x11\x38\x4e\x0c\x91\x1e\x76\x63\x98\x9b\xd2\x96\xb9\xda\xbf\xe4\xe9\x83\xc9\xa1\x6d\xcb\x0d\x6f\x77\xa1\xd1\x03\x3e\xda\xcd\x85\xb6\x96\xea\xc2\x81\x94\x7b\xb9\x97\xcb\x61\xc3\x0b\x99\x74\x47\x32\x03\x2a\xb4\xea\xf1\xd3\xae\xc8\x4a\xa6\xa0\xb6\x5b\x63\x07\x08\xc8\xd4\xb7\x9f\x9f\x36\xaa\x4e\x68\x8c\x8c\x73\x8b\x62\xed\xc1\x7a\xfc\xa2\xd3\x73\x73\x50\xe9\x13\x10\x8b\x6e\xb1\xaa\x36\xad\x07\x32\xb7\x3e\x05\xb0\x92\xac\xa5\x26\xb6\xa1\x83\xe2\x34\xd8\x02\x4f\x90\x08\x31\xb2\x28\xaf\x08\xa6\x30\x0d\x4f\x9f\x52\xcd\x8c\xb1\x85\xab\xd3\x56\x90\x84\xcd\xde\x26\x10\x3b\x07\x36\xe6\x5e\xb5\x76\xd9\xb1\xd5\x8f\xf2\x64\x12\xf1\xcc\x0a\xff\x0c\x07\xbb\x99\x40\x3d\x8f\xcd\x83\x49\xbc\xbe\xc5\x90\x31\x69\x64\x83\xbf\xe5\x6b\xfd\x9f\x63\xfb\xc7\xf8\x65\xe9\x28\xb2\xf3\x8d\xa5\xad\x6f\x4a\x7c\x7b\x84\x5b\x68\xdf\xa2\xd8\xfe\x1a\xed\x77\xa1\x24\x71\x4c\x0e\xb2\x27\x17\xe7\xc8\xbc\x8b\xd4\x76\x2d\xd4\xff\xf4\xf4\xb7\x16\x27\xe8\xdc\x8f\x93\x59\x9c\x28\x4b\x0a\x1d\x30\x46\xe4\xc3\x1a\x63\x9e\x9d\x14\x1f\x1a\xc3\x06\xa2\xa5\x12\xcf\x36\x03\x60\x75\xa2\x59\x03\x44\xfe\xd7\x92\x0e\x94\xc3\x23\x98\xd7\xfa\xf0\xa8\x62\x0d\x21\x97\x1a\xa8\xf0\x4b\xb4\xe1\x81\xa1\x7b\x69\x49\x37\x55\x59\xb2\x0d\xc8\xb7\xc3\xaa\x5c\xbf\x6c\xc1\xfa\x95\x07\x51\x55\x88\xf2\x04\x11\xd2\x8f\x0e\x58\xed\xc8\x89\xba\x9c\xed\x3e\xb8\x54\xee\x62\xdf\x69\x9d\x1e\x49\x28\x75\x46\x32\xbf\x2d\x84\xf7\x43\xbd\x03\x8d\xb9\xbc\xf5\xc7\xfd\x4d\x50\x24\x9f\x94\x5b\xe7\x6d\x88\x65\x53\xb3\x9b\x3b\x89\x11\x7b\x45\x28\xad\x4e\xea\x1e\xb0\xd9\xa0\x04\x02\xfe\xdd\xc3\x89\xa6\xb1\x6e\x1a\x98\x5f\x5a\xd1\x65\x02\xa2\x3e\x02\x2d\x8b\xdf\xda\x69\x5b\x64\x03\x5a\x9f\x0f\xff\x62\xf8\xe0\xcc\xca\x9a\xe2\xb2\x08\x7d\xc8\x6e\x7e\x00\x63\x3d\xab\x26\x4b\xb2\x36\x10\x3b\xb3\x72\xb1\xcf\x15\x92\xeb\xd4\x7c\x96\xf6\xb4\xe3\x07\x82\x69\x39\xb6\xda\x78\x27\x4a\x3e\x9c\x57\xca\x7b\xa8\x79\xc9\x85\xc6\xca\xc2\x04\x2d\x60\xfc\x96\x05\x26\x88\x62\xb4\x1c\x6b\xfa\xe6\xa1\x3b\x73\xac\xf9\x2d\x31\x42\xb7\x82\xc4\x40\x1e\x81\xc8\xbf\xb6\x55\x61\x50\xea\x38\x8c\x2a\xad\x87\x37\x80\xf4\xf8\x55\x15\x3e\x26\x63\x29\x36\x3f\x87\x16\x9d\x3e\x2d\x65\x52\x7c\x4e\xd4\x95\xdb\xf9\xe6\x02\x51\x7f\x47\x5b\x97\x78\x42\x9d\x7f\x9e\x9d\x66\x49\x4d\x26\x62\x19\xa3\xca\x9b\x37\x37\x55\xc6\xf2\x47\x4f\xfa\xa6\xbe\x0b\x5f\x0b\x92\x30\x83\x5f\x06\xd3\x08\x59\x9c\x84\xc4\x7b\x61\xd5\xaf\x3f\xa1\x9c\xd5\x7d\xeb\xe5\xac\xc6\xcd\xa7\xcf\x6c\x23\x21\xdc\xd8\x6d\x33\x4e\xb8\x64\x51\x68\xe2\x8c\xe3\xba\x05\x29\xc6\xcf\x99\x6b\xff\x5f\x7d\xb2\xc5\x64\xee\x07\x73\xc7\xa9\xd6\xb1\x16\x42\x82\xb2\xa6\x63\x2d\xae\xe9\xb8\x2c\x2f\x21\xfe\xf6\x42\x78\x44\x67\x8e\xb1\xc1\x8a\x60\xda\x2b\x2e\x84\x58\xeb\x59\xe6\x58\xae\x26\xb4\xa7\x58\xb1\x24\xd2\x3f\x2a\x74\xa1\x74\x5c\x56\xfa\xfc\xd2\xc6\xcd\x34\x1d\xc0\x3a\x8b\xc1\x24\xc9\x13\x10\xa3\x8f\xb7\xab\x2f\x56\xa0\x92\x8a\x13\x4d\x35\x1b\xcd\xe6\x5d\x14\xcf\x2b\xf8\x9e\x53\x9e\xb3\x08\xa5\xc0\x8b\x7d\xd4\xa9\xa6\xf1\x32\x63\xaf\x21\x5b\x60\x12\x22\x97\x91\xf2\x1b\x1b\xab\x38\xad\x6e\xd5\x4e\xee\x04\xdd\xda\x71\x05\xc3\x0a\xed\x85\x16\x26\xc9\x0b\x53\x6c\xed\x8f\x6e\x9f\x94\xa3\xfc\x1d\xa8\x4c\xa2\xe0\x1e\x19\x9c\xeb\x38\x67\xb5\x57\x04\x8b\x4b\x19\x93\x31\x9e\x44\x70\xb9\x33\x98\x00\xc0\x8f\x5a\x39\xb8\xf2\x3e\x1e\x62\x3b\xc1\x77\x4b\x3f\x48\x42\x76\xf0\xb4\xd2\xda\xc3\xbf\x71\x2f\x6b\x3a\xfa\x26\xec\x1e\x99\x0b\xe1\x16\xef\x1c\xe9\xba\x12\x27\xc7\x32\x88\x46\xd4\xe3\x57\x5c\x3d\xac\xb9\xf7\xd9\x05\xc2\x3b\xaf\x6a\xb3\xa3\x59\x12\xd8\x90\xc1\x4b\xa6\x12\x69\x03\xad\xb8\x3e\x2e\xf6\x40\x68\x5f\xe8\xb9\x7e\x0a\x68\xf5\x47\x01\xf8\x20\xa0\x14\x96\xd6\xd1\x80\x76\xb5\xa5\x4e\xa6\x61\x32\x1a\xe3\x65\x66\xfc\x3b\x0b\x3d\x1b\x04\x51\x54\xcf\x82\x34\xd7\x98\xab\x74\xf1\xf4\xfb\xd3\x7f\x3f\x28\x22\x12\xe8\x55\xc0\xc3\x76\xf0\xc4\x0b\x4a\x88\x88\xbd\x77\x86\xa4\x0c\x97\xfe\xad\xd8\xe4\x4f\x10\xcb\x8a\x36\x1d\xf0\x68\xb2\x17\x82\x80\x7e\x0b\x08\xd0\x85\x8a\x1f\xab\xbe\xae\x92\xbe\x74\x84\x98\xc1\x66\xaf\xc2\x6d\xf0\x75\xdc\x55\x10\x3e\x17\xcc\x16\x0e\x2b\x9a\x1d\x68\x39\x7b\x50\xda\xbe\xfc\xdb\x69\x04\xcb\xa4\x7c\xfa\x17\x9b\x90\xa1\x88\xb7\xf9\xbb\xe7\xdf\xba\xdf\x1c\x79\xcf\xf5\x26\x75\x0f\xb6\x69\x73\x52\x9d\x10\x37\x41\x78\x79\x85\xe3\x68\xfa\x48\xf5\xeb\x54\xd1\xe9\x93\x5a\x9c\xb0\x45\x90\x3b\x29\x58\x5b\xa5\x7f\x8e\x2d\x35\xbb\x7a\xff\x49\xe7\x0a\xea\x15\xee\xb9\x4b\x66\x39\x73\xc8\xae\xa4\x92\xf0\x6a\xb4\x05\x2f\xcb\x67\x4c\xff\x9c\x5c\x63\xd3\x8c\xe0\xba\xb2\xcd\xe9\x44\x69\xd9\xfb\x9c\x8a\xce\x8e\xea\xa3\x43\xad\x46\x18\x57\x87\xcc\x31\x2e\x37\x8a\xdd\x6e\x5f\xc4\xd5\x28\x14\x11\x05\x78\xc9\xaf\xe7\xb2\xa8\x2e\x54\x5c\x10\x61\x49\x21\x3f\x13\x62\xb3\x47\x1a\xac\x2e\x6f\xac\x88\x3f\x0a\xac\xe0\x86\x75\xe9\xea\xbc\xbe\xe6\xbe\x73\x88\x3e\x68\x0c\x34\x1b\xc7\xed\x67\x75\x53\x13\x50\x66\x53\x4b\xbe\x9b\xd2\xfe\x7c\x06\x81\x7d\xd0\x8d\x6a\xce\xfc\x60\xb9\x9a\xf8\x13\x69\x02\xe1\x21\x44\xbe\x26\x9f\x44\x21\xd2\xf6\x37\xcb\x35\x53\xcb\xfc\x94\x20\x85\xee\xd5\x43\x2d\xa1\x24\x3d\x98\x93\xe7\x98\x52\xbe\x6b\xdd\xf3\x02\x5e\x7f\xb0\x0d\x10\x4a\xf5\x2c\x88\x52\x3d\x93\x0c\x3f\x85\xb6\x9b\xba\xb6\x04\xd1\xc0\x50\x7d\xd0\xeb\x18\x77\x18\x52\x95\x84\xdc\xa1\xea\x0f\x7b\x26\x3e\xf5\xf2\xea\xad\x05\x54\xc8\x16\x1c\xbf\x5b\xd1\xf1\x86\x5a\x19\x2d\x44\x0f\x64\x58\xd2\xb0\x96\xd5\x69\x1e\x95\x9f\x5d\x0b\xa2\x08\x56\x3e\x6c\x78\x39\xa8\x09\x5c\xc4\x27\x48\x64\x4d\xb7\x95\x46\x8e\x46\xba\xdf\x81\x01\x32\xcf\xd8\x55\xc2\xf4\x60\xf1\x11\x77\x80\x25\x40\xf4\x00\xa1\x50\xcb\xe2\x75\x5c\xb5\x4c\xf3\xa9\x88\x37\x50\x11\xfd\xd8\x18\xfe\x09\xba\x1d\x6b\x33\xc8\xe0\xa0\x69\x49\x1e\xa2\x0e\x5d\xcc\xf5\x7a\x0f\x19\xec\x7a\x04\x00\x58\x52\x63\x52\x38\x52\x8d\x95\x3f\x41\xb3\x1d\xae\x30\xd1\xb2\xd4\xc5\xbe\x75\xd6\x4c\x10\x4d\x08\x76\xfa\xcf\x29\x01\xef\x16\x32\x27\x92\x46\xee\x43\x2a\x3d\xd2\xac\x66\x23\x1c\x2d\x3e\x36\xf7\x6d\x1b\xef\xc5\x00\xb6\x1b\x98\x96\xd3\x79\xfd\x13\x3f\xfa\x61\x1a\xdc\xe4\x0a\xf3\xf1\xdf\x1c\xb2\x43\x8d\x81\x3b\xff\x1b\xf3\x87\xad\xef\x4a\x6b\x3a\xf3\x56\x4a\xb7\xb2\x26\x84\x28\x2a\x3d\x7c\x8e\x0b\x9d\xe4\x53\x53\x31\xe9\xb4\x0c\xe2\x28\xc1\x9c\x65\xee\xb2\x3d\x00\x8d\xb7\x3e\x86\x41\x9f\x47\x13\xea\x94\xc7\x4a\x5d\x43\x85\x1e\x24\xc7\x27\xff\xf3\x9e\xe5\xb5\xd3\x6a\x3e\x29\x5c\x4c\x55\x37\xb2\x11\x40\x75\x36\xbb\xdd\x72\x02\xe3\x39\xeb\xe0\x6f\xb6\x16\xc9\x14\xd3\xdd\xae\x3d\xbd\xff\x9e\x5f\x93\x86\xbf\x1e\xf2\x89\x72\x6b\xe3\x9a\x4f\x75\xb9\xa2\x60\xc3\xf3\x27\xfe\x36\x23\xda\x6d\xe7\x54\x7c\x12\xab\x7f\x79\x61\x57\x76\x84\x77\xec\x0e\xa2\xad\x88\x4f\x4a\x50\x7a\x36\x18\x00\x9d\xe9\x18\xc4\x0f\xa6\xc1\x0a\x92\xf8\xfb\x41\x25\x0c\x0f\x0d\x96\x55\x70\xaa\xfa\x28\xd0\xb8\xd0\xec\x56\xb4\xee\x40\xc1\xee\xdb\x75\x97\xc6\xc3\x2d\x59\xb9\x64\x08\x6f\x1e\x63\x40\x08\x2f\xb3\x93\xec\x1c\x9c\x4d\x18\x75\xb1\xf0\xf5\xb5\x10\x8c\x07\xdc\x7e\x51\x6b\x59\x71\x7a\xaf\x1d\xa8\xbb\x64\x50\xa4\xdc\x56\x62\xbf\x42\xcd\xb6\x3b\xc7\xdf\x78\x26\xe9\x88\x78\x1b\x42\x8e\xaa\x5d\x3b\xb6\xc4\x54\x3d\x36\x1b\x9a\xc3\xdf\x91\xb5\x58\x28\x59\xb7\x4b\x95\xc6\x67\xbf\x6a\x63\xa1\x24\x3e\x6b\xb2\x5c\xb3\x82\x08\x1d\xe1\xae\x95\x6f\x52\x9d\xa3\xbd\x4c\x14\x2d\xfd\xf9\x60\x35\x03\x69\x78\xb1\xc1\x6f\xb4\x5f\x05\x42\x12\x4d\x04\xc6\x29\x1e\x15\xb0\xfa\x70\x9d\xec\xf6\x7b\x0f\xb5\xc4\xcc\xf0\xde\x97\x67\xf5\xdd\xaf\x30\x23\x74\x6f\x2e\x2c\x54\x0e\x7f\x8d\xaa\xd2\x7a\x7f\x4f\x0e\x55\xd9\x33\x22\x1c\x76\x01\xc2\x6f\xf7\xba\xdf\x0c\x54\xb5\x83\xdd\x2e\xcb\x0a\x13\x89\xd3\x7f\x50\x7a\x8b\xfa\x52\x86\x4c\x26\x8a\xe3\x9c\x12\xdc\x00\x42\x89\xee\x31\x8f\x89\x5f\x37\xfa\x63\x6d\x1f\xb5\x36\x94\x7d\x1c\xaa\x5f\x38\xc6\xf0\xc8\x2a\xe7\x40\x00\xbd\x2e\x94\x44\x04\x78\x81\x88\x4a\x59\xd3\x87\x14\x1a\xfa\xd3\x51\xe3\x01\x37\x62\xae\x29\xb7\xa6\x82\xb6\xac\x06\x8c\x81\x29\x6e\x5e\x35\xcd\xed\x2f\x07\x01\x97\x3e\x09\xa3\xe2\xaa\x43\x0a\x1e\xab\x1d\xd1\xa4\xb6\xb4\x70\x41\x90\x5d\x15\xd1\x82\xed\x94\xa2\x81\xbd\x19\x46\x66\x58\xc5\x11\x7e\x3e\xfb\x9e\x71\xbf\xbc\x54\x71\xf9\xa9\x61\x25\xd1\x5f\x1c\x40\x8b\x47\x82\x96\xe0\x29\x3b\x8b\xc4\xab\x2d\x60\xa5\xd4\x60\xca\xca\xb3\x35\x8d\x10\x45\x6c\x30\xb0\xbc\x9a\x7c\x8d\x75\x6c\xb7\x70\x2e\x4e\x12\x40\x66\xdc\xbb\xc2\x1d\xbf\x0a\x99\x8d\xdf\xcc\xc4\x22\x8b\xa0\xd5\xe9\xff\x0c\xcf\xfe\x0a\x80\x8b\x7b\x80\xad\xdb\xdf\xbd\x19\xd3\xb7\xb3\x6b\xbe\x4d\x39\xe1\x19\x13\x26\x8b\x3e\xb7\xa7\x35\x10\xfd\x0c\x2d\xba\x0b\x30\xd4\x05\xa6\x97\x72\x31\xf9\x74\xc0\x33\xea\x90\x78\x65\x47\xd5\x66\x55\xf9\x5c\xc0\xa6\x5a\x19\xe3\xaf\x9d\x3e\xa1\xcc\xdd\x3f\x29\x22\xe5\x0e\x06\x98\x8b\x10\x1d\xa1\x9a\x6b\xbd\xb8\x69\x4b\xe4\x2f\xe7\x8f\xd4\x7b\x42\x4d\xa8\x39\x2c\xec\x5e\xe3\xe2\x80\xce\xd2\x77\xd8\x3c\x78\xe6\x14\xc2\x17\x18\x0f\x47\x69\xe4\xed\x13\x11\x3f\xbd\x71\xc7\xb7\x11\x3b\x39\x24\x33\x08\x13\xbd\xa8\x95\x73\xec\xeb\x40\xc8\xe2\x7a\x58\x2a\xd7\x27\x57\x96\x64\x3c\xaf\x2e\xef\x16\xa2\xb6\xe9\xb0\x54\x64\xd7\x24\x5f\xf4\xd3\x47\x51\xd2\x83\xe8\x52\x82\x4b\xef\x03\x8a\x9f\xe3\x97\xed\xd1\xa9\x62\x3b\x6f\xca\x43\x11\x89\xe2\xbf\x99\x97\xf2\x0e\x84\xc1\xa5\x93\x4a\x24\x15\x4d\x0f\x65\xfb\x02\xbb\x99\xd9\xac\x87\x06\x54\x48\xde\x6d\x0b\xf3\xcf\xf2\x20\x7a\x15\x23\x92\x67\x62\x7e\x40\x2e\x5a\x24\x8b\x13\x6d\xef\x53\xab\x63\x7f\x90\x51\x65\xb2\x82\x25\x3b\xa4\x1c\x3d\xb0\x92\xae\xc5\x71\x59\x63\x31\x06\x28\x4d\xfa\x70\xea\x94\xc0\xcb\x3a\xdd\x5f\x03\x11\x15\x0d\x14\x94\xf1\x4b\xda\xdd\x98\xf6\x30\x33\xa6\xd9\xfe\x8b\x8f\x6b\xe8\x9a\xf9\x13\x87\xf8\x03\x0d\x6f\x59\xd7\x79\xa5\xad\x58\x63\xab\x09\xff\xbd\x74\x5e\x1b\x7e\x8e\x7d\xbe\x68\x82\x7e\xc3\xfd\xd4\x4a\x5a\x31\xfa\xf6\x02\x6b\xfa\x5e\x38\xbf\x7a\x55\x62\x22\xd0\x45\x19\x6c\x12\x21\xf2\xa8\xa9\xc4\x3c\xdd\x28\xeb\x7c\x9e\xa9\xf5\x48\x1b\xb0\xbd\x41\x93\x5f\xab\xfe\xb0\xca\x4c\x77\x0b\x76\x82\xc0\x13\xfc\x25\x6e\xb9\x7a\xd7\xf2\x32\xb2\xd8\x24\x34\xbb\x18\x64\x21\x45\xd8\xa1\x8c\xc6\x28\x95\xb7\x05\x87\x82\x50\x71\x9e\xc6\x87\x02\x38\x78\x67\x5c\x56\x15\xc7\xad\x23\x43\x1e\x2f\x0d\xf7\x31\xba\x18\x31\xe7\xec\x53\x90\xd7\x82\xd0\xb9\x95\x1b\x14\xb8\x54\x68\xf4\x4c\x60\x6b\xf9\x61\xe1\xa2\x21\x09\x8a\x2b\x92\x7f\x7f\x73\x80\x53\xa4\x78\x17\xc9\x42\x37\xd4\x7d\xeb\x9b\xca\xcd\x48\xa0\xfc\xe0\x22\x62\x97\xa8\xc4\x7c\xa8\x5b\xc4\xce\xd9\x25\xd3\x71\xeb\x4b\xc3\x28\xbd\x83\xd8\xee\x42\x79\x0a\x91\xa4\xd8\xd8\xb0\x55\x6d\xb7\x53\x6a\xfe\xd3\x07\xba\x9c\x82\x93\x2c\xe2\x6c\xbd\x5a\x6c\x4d\x4c\xa0\x44\xbd\x05\x02\xe7\x5c\xb7\x9a\x9c\xaf\xb5\xdf\x4b\x97\x57\x94\x18\x36\xbd\x90\xc7\xf8\x05\xe9\x09\xb0\x60\xa4\xc5\xc5\x72\xd7\xad\xac\x72\xf5\xd5\x92\x05\x22\xc0\x64\x89\x1e\x00\x39\xe2\xb1\xc3\xb9\x58\x98\x95\x6f\xd1\x27\xc1\x66\xce\xab\x50\xe7\xd0\x2d\x38\x6b\xc1\x7b\x70\x15\xdc\x39\xcb\xfa\x75\x8f\x01\x7d\xf0\x00\x97\xba\xae\xc4\x2e\xd1\x00\xc9\xa5\x31\x8a\x4a\x77\x87\x83\xf2\x46\xab\xe5\x9d\x4b\x02\x8b\x66\xf0\x8a\x3a\x1f\x0b\xb8\x53\x82\xd2\x0a\x27\xb0\xfe\x8f\x0b\xff\xbd\xa7\x24\xc3\x48\x05\x1e\xc0\xf1\xb3\x7a\xd0\x09\xd0\x8c\xc0\x53\x52\x99\x74\xa4\x90\xd2\x94\x7a\xf7\x6c\x17\x7c\xe9\x89\xaa\x39\xaf\x5d\x91\xd3\x77\xdf\x34\x92\x33\x59\x8a\xc0\xa6\xee\x41\x7f\x05\x07\x09\x76\x92\x86\xc3\x1f\x67\xee\xca\xdc\x39\xd3\xbc\xaa\xed\xda\x1e\x77\xcb\xc1\x7a\xe5\x42\x9b\x0a\x97\x0a\x6e\x4f\x1d\x4c\xe2\x9d\x25\x12\xe0\x0a\xa7\x48\xf7\x6a\xb4\xb8\x15\x00\xe8\xf5\xce\x6f\x83\x57\x74\xc3\x81\x0c\x01\xdd\x6e\xc7\x77\x24\xeb\x9e\x99\x2e\x0f\x80\x05\x7d\xa1\xb9\xa3\x04\x29\x2e\x65\x81\xca\x40\x1b\x10\x5e\xab\xc3\x1e\x12\xa7\x24\x94\x6d\xd0\x4b\xfa\x67\xd2\xd9\xf6\x1e\x9b\xfc\x8a\x04\xa7\x5b\x6d\xa2\xf0\x16\x8a\x4a\xf2\x2d\xa5\xcb\xdd\xff\xb1\x9e\xdd\xa5\x19\x33\x18\x6d\x48\x1e\x2f\xc0\x57\x47\xbe\x10\xeb\xca\x1d\x07\x24\x8a\xbd\x10\x25\x6f\x61\x1b\xc9\x5d\x94\x9f\x2f\xe4\x28\x25\x67\x92\xa3\xbb\xaa\xc3\xfd\xd8\x9b\xb0\xd8\x46\x1f\x7b\xbf\xa6\x84\x58\x9f\x9c\x39\xff\x31\xf6\x20\xf2\xef\x0a\x97\xcb\x9a\xf6\x88\xd1\x25\xaf\x34\xff\xac\xe9\xfb\x8c\x97\xda\xf9\x9f\xe4\xa1\x94\xc1\x7b\x10\x65\x5e\xc7\xe9\x3e\x47\x16\xc0\x7f\x3a\x57\xa9\x76\x43\x8d\x80\x4e\x55\xb2\x6a\xa1\x61\xfa\x00\x06\xcb\x39\x71\xf4\xc3\x01\xa5\xad\xfc\xdc\x08\x34\xb3\xf3\x60\x9a\x98\x1c\xb8\xf0\xc2\x5a\x56\x2a\x4d\xf2\xe0\x91\x17\xe2\xbd\x6e\xf9\x0a\xfb\x86\x15\xd7\xcf\x48\xa3\xc2\x26\xfa\x29\xee\x7e\xf1\x16\x5b\xc0\x64\x61\xd1\x1d\x3d\x3e\x34\xa1\x65\x9c\x5e\xbf\x86\x33\x59\x07\x5e\x6e\xe9\x8b\xfb\x75\x6b\x69\x2f\xb5\xa8\xae\x30\xe0\xf0\x91\xac\xe9\xb8\xad\x22\xbb\xe2\x3f\xa5\xee\x5a\x61\x72\xcf\x1d\x01\xc0\xaa\x85\xb3\xc3\x57\x3a\x37\x56\xf1\xb3\x1a\xed\xd9\x37\x9a\x11\xcb\xaa\x0b\x2d\xaf\x4d\xbd\x75\x00\x28\xec\xdf\xe3\x07\x43\xe9\x6f\xc1\x37\xe3\x26\x21\x04\x9e\x5f\xbc\x74\x69\x45\x5b\xad\x82\xb2\x43\xe1\x69\xe3\x02\xd2\x22\x10\x92\x77\x20\xc1\xcf\x88\x32\x42\x95\xfb\x45\x76\xe9\xbe\x23\xe4\xe8\x06\x40\xf8\xc9\x25\x95\xab\xe7\x44\x74\x66\xc2\xec\x36\x63\x86\x51\x5d\x2f\xe8\x19\x26\x12\xc6\x41\xf4\x97\x3b\xa3\xad\xd7\x57\x3d\x69\xf7\xec\x93\x80\x95\xdb\xa0\x5d\xbe\x6e\x96\x36\x7a\xb6\xfd\x43\x1e\x10\xe6\x5e\x58\x76\x6e\xba\x1c\x3c\x13\x81\xbc\xb7\xd4\xbe\xfb\x5f\x45\x39\xce\x4d\xf1\x8e\x49\xef\x09\x58\x41\x19\x9b\x3f\xbf\x85\xd2\xf9\xc2\xa0\xda\x86\xaf\xa8\x33\xb5\x16\x4a\xd2\x70\x14\x06\xa3\x92\x5d\xd4\xbf\x9d\x8c\x4a\x1b\x8f\xc1\x91\x85\xe7\xc4\x7c\xbb\xdb\x18\xcf\x71\xea\x87\x66\x43\xb6\x20\x88\xf5\xf7\x6b\xa0\xde\x86\x86\xc1\x16\x3a\xe6\x14\xa4\xa4\x70\x03\x38\x97\xa6\x75\xe0\x15\x3d\x8d\x9a\xd3\x8c\x25\xb9\xe0\xec\x6b\x78\x28\x33\x5e\x25\x06\x9f\x16\xe3\x8d\x7c\x45\x60\x8d\x65\xa7\xe7\x7d\x08\x40\xf3\x2f\xcb\xdd\x26\x4b\xa1\xd4\xd4\x5c\x51\x86\x7e\x00\xc8\xf6\x10\xf7\xb1\x7e\x73\xa2\x2e\x44\x5b\x1b\x56\x3b\x78\x96\x35\x2f\x91\xa9\xb9\x45\x60\x72\x93\xcb\x19\x8c\x50\x0c\x77\x25\x5f\x4e\x99\xca\x3b\x68\x02\x7c\xc4\xe1\xda\xf6\x21\xd4\xb0\xd4\x33\xe3\x83\xde\x0a\x11\x71\x06\x20\x28\x75\x00\x2a\x0d\xf8\xd1\xd9\xa3\xba\xad\xd0\xc1\x3a\x76\xaf\x0f\x7d\x79\x1d\x58\x4c\xdc\x2d\x67\x29\xd7\x82\xb5\x4c\x1e\xff\x5a\xd4\x76\xad\xe7\xde\x89\x7c\xf4\xb0\x5e\x15\x24\xfa\xa4\x2e\xd5\x1d\xd8\x0f\xff\x89\x39\x38\xb9\x4a\xd0\xb1\xe8\x84\x12\x31\x47\x77\xfb\x2a\x6e\xeb\xbd\x03\x2e\xf0\xa9\x78\x7e\xcc\x1a\x1b\xb1\xcd\x69\xd5\x2e\x57\x83\xd3\xc5\x60\x73\x96\x22\xbf\x81\xbb\x3d\x1a\x00\xd6\xa1\xdb\x6d\x5c\x9b\x2a\x1a\x78\x3c\x7f\xc0\xd2\x70\x59\x81\x6b\x23\xe7\x18\x02\xbd\xda\x11\x18\x08\x1c\x25\xfe\xe9\x5b\xf1\x26\x8d\x5d\xf6\xf6\xb3\x70\x8b\x28\x82\x81\xac\xf9\xa8\xe6\x65\x3f\x1c\x03\x9a\x08\xe6\x6b\x2a\xea\xa0\x8e\xee\xba\x07\xd1\x94\xbe\x3b\x45\x3f\xb1\x36\x10\x60\x98\x8c\x4b\xe7\x5c\x62\x77\x01\x41\x55\xd9\x61\x64\xbe\x01\x48\xb6\xdd\x93\x8b\x62\x19\xd4\x7d\xb0\xc7\xe4\x64\x0b\x34\x77\x53\xe2\xf9\x18\xd1\x1f\x0d\x09\xf6\x4d\x7d\x65\x2c\x37\xf9\xa7\xc7\x52\x43\xe4\xd8\x4a\x7a\xa8\x8c\xfd\x20\x47\xc0\xb1\x9c\x28\x10\x8c\x5d\x0b\x7e\x2b\xfe\x3c\x6f\xe4\xfa\xcd\x75\xe1\xc0\x6e\xfa\x91\xf6\xc8\xde\x4b\x5d\x1a\x14\xd4\xaa\x9d\x56\x9e\x02\x02\x22\x9f\x57\xbf\x58\x7d\x7a\xe3\xb2\xee\xdb\x36\x62\xbb\x7c\x41\xd7\xc1\xfc\x1f\xeb\x86\x5b\xf0\x39\xa7\xa4\x43\x35\xf5\x8b\x2f\xd1\x55\xda\x79\x56\x91\xab\xa6\x91\x12\xac\x2c\x14\x7d\x7f\x3f\xde\x5e\x82\x1d\x1d\x93\x4f\x0f\x13\xd0\x8c\xb2\x39\xae\x33\x9c\xed\xe2\xd5\x27\xde\xb1\x38\x10\x9a\x45\xc7\x2a\x3b\x10\xfa\xca\x46\xc2\x8c\x10\x74\xc1\x4e\x6f\x4f\x44\xb6\xae\x79\x5c\xa6\x9a\x5e\x3c\x4e\xda\x2b\xa6\x0c\x81\xdd\x23\xc2\x0b\x4b\xa7\x80\xca\xfc\x3d\xb6\x7f\xf3\x78\xd1\x59\xd1\xcf\x80\x62\xb9\xbe\x3e\x09\xa2\xb6\x5e\x0d\xf4\x7e\x27\xd0\x14\x39\x96\x3f\x46\x35\xa6\x6b\x92\x6a\x09\x3f\x55\x3c\xbf\x2e\x74\x1b\xdc\x3e\xf8\xb1\x0e\xc6\x2d\xdc\x8f\x02\xad\xee\xc9\xaa\x25\xb3\x05\x49\xfa\x16\xf4\xb9\x16\x24\x17\xd9\x3a\x3e\x25\x6f\x63\xdb\x4e\xc6\x41\xbd\x42\x25\x80\x79\x06\xf9\x97\x84\xd1\xd0\x25\x3b\x0a\xd8\x55\x4d\xbc\x07\xa6\x28\x76\x55\xdd\x5c\x2a\x21\x60\xb2\xb7\xbe\xf9\xb9\x7a\xc0\xd7\x98\x59\xbd\x70\x41\xad\xfb\x92\x77\x6b\x61\x9d\xa0\x05\x14\xf5\x4e\x14\x80\xdc\xcd\x84\xa8\x39\x72\x8e\x77\x78\x2e\x4d\x77\xc6\x6f\x6b\x46\xd2\x04\x5d\x82\x19\xb4\x16\xb7\x88\x15\x08\x59\x40\x03\x99\x2a\xac\xa8\xa3\x5e\xac\xf3\x0e\x1b\x2f\x6d\x3c\x6a\x1d\x42\xd4\xe1\x26\xda\x32\xda\x2a\x4d\xda\xc8\xa1\x78\xd7\x1b\x52\x98\xf0\x82\xac\x77\xe2\xb4\x23\x27\xf3\xc0\x94\x91\x00\x30\xb9\x36\x79\x11\x65\xbf\x98\x4e\x8e\x6a\xd3\x8f\x7b\x4a\x9c\x2e\x7b\x32\x2e\x3e\x0c\xcd\x0e\xe4\xc9\x2b\x29\xc6\xe8\x17\xe7\x2a\xa1\xa6\x09\x48\xb8\xbd\xc6\x74\xb4\x4d\xc8\x27\xad\x55\xc4\xf2\x66\x68\xba\x00\x88\x7a\x85\x1d\x7c\xef\x6a\xbf\xd0\x5d\x3c\x85\x4b\xc8\x6e\x1e\x59\xee\x80\xb2\xc7\x4d\x6f\xc4\x75\x5e\x35\x1a\x10\x63\x18\x2a\x1f\xdd\x6e\xc2\xaf\x0c\xbd\x50\x92\x66\x57\xca\xfd\x0d\x86\x17\xa2\x1d\xde\x23\xf1\x72\xf5\x28\x71\x6e\xeb\x37\xff\x10\x7a\xe1\x8f\x7f\x75\x66\x4f\xe9\x39\xf3\x95\xa7\xb5\x93\x55\xab\xd7\xef\xab\x48\xc2\x98\x9b\xb2\xc6\x0f\x86\x84\x38\xb7\xab\x0b\x94\xda\xe4\x9b\xfa\x1d\x21\x60\x9a\x6b\xca\xbb\x39\x90\x9b\xa0\xb0\x65\xea\x73\x5a\x88\xa8\x38\x51\x3c\x46\x45\x84\xce\x2f\x10\x03\xd4\xfb\x08\x21\xba\xaa\x24\x40\xf7\xec\x84\x13\x75\x13\xb4\x80\x40\x4d\x86\xdd\x9b\x28\xdc\x28\x2f\xa6\xd6\xb8\x04\xa2\x29\x8c\x02\xb6\x0d\xa1\x9c\x99\x4e\xce\xe8\xc1\x01\x75\xf2\xb4\x47\xa9\x28\xa9\xa6\x2c\x8e\x94\x03\x80\x2c\xeb\xfc\xb5\xc4\x67\xcf\xe2\x47\xc8\xc6\xe8\x77\xe7\x32\x77\x90\x13\x7d\x83\x24\x99\x1f\x27\xd0\x09\x0a\x94\x4b\x31\x20\xb0\xca\x99\x8c\xa9\x10\xc4\xbd\xec\x7a\x54\x67\xd9\xd2\x21\xe8\xca\xa4\x5f\x17\x4a\x60\x89\xd0\xc9\x21\x9a\x1e\x35\x44\x56\xfb\x67\xa1\x30\xed\xf8\x95\x30\x5d\x54\x32\xee\x58\x6e\x48\x28\xf6\x82\xbc\x0b\xd0\xd5\x82\xcb\x2b\xe3\x17\x82\x6b\x65\x02\x38\x6e\x32\xb0\x8e\xc3\x7a\xa1\x1b\xc4\xb2\x21\x58\x32\x0a\xe1\xba\x8d\x5f\x5a\x28\xa6\xaf\x46\xda\x25\x10\x18\xc7\xe5\x21\xcf\xb4\x14\xc2\x5b\x72\x65\x18\x05\xb8\xcc\xa3\xb9\xd4\x79\x6a\x2d\x71\x8f\xbb\xf4\x06\x90\x5c\x8a\xcd\xcd\xa9\x74\x8b\xe7\x48\x91\x77\x72\x5d\xbb\x8c\xfe\x18\x5d\x1a\x86\x4a\x19\x54\x90\x3e\xff\xc4\x94\xaa\xa2\xfd\x24\x8f\x6f\xf4\x92\x7d\xec\x1a\xb0\x5a\xa1\xc2\xf2\xd0\xd2\x2a\x23\x6b\x24\x0f\x84\xc6\xc1\x17\xcf\xdf\x49\x79\x83\x20\x08\xa2\xb6\xc7\x59\xb3\xf1\x95\x0e\x03\xf9\xb1\x96\x8d\xb8\xeb\x17\x8a\x65\xee\x9c\x5b\x97\x30\x1c\xd6\x74\x5a\x52\x71\x4b\xc4\x54\x1f\xe8\x12\x91\x8a\xf3\x31\xb2\x5f\x1c\xfb\x4b\x2d\x42\xfd\xd5\xdf\x7c\x20\xf1\x33\xb6\xaa\xe7\x86\xe1\x42\xa7\x10\xeb\xba\x0e\x06\x00\x52\x68\xf6\x80\xd7\x89\x66\xbb\x45\x1e\xb4\xe5\x45\xb0\x17\xfd\x1c\xdf\x0f\x24\x16\x8b\x58\xa8\x90\xec\x7d\x4b\x6f\xa2\x38\xb7\x19\x59\xf7\x48\xda\x25\x50\xe1\x67\xb7\xec\xe4\x89\x56\x9e\x4d\x3f\xf5\xe7\x3e\x2d\x0e\xa8\x0c\x3b\x9d\x02\xb8\x08\x8b\x36\x06\xd1\x7e\xa3\xbe\x1b\xca\x0d\xa9\x16\x57\x1a\x00\x33\x96\xfc\x02\x9c\x30\x90\x89\xc4\x4d\x41\x01\x5a\xfe\xb1\x18\x8b\x97\xb9\x03\x90\x48\x98\x1a\x22\x0e\xa3\xf2\xc2\x9c\x52\x5f\xb8\xf5\xca\x42\x57\xbf\x5f\x64\x6e\x05\xfa\x08\x93\x01\xa7\x75\x59\xf9\x7e\xa6\x8e\x4c\x42\x9b\xe2\x3b\x20\xeb\x1e\xc5\x9a\x69\x46\xd6\xbb\x7f\xdb\x37\xbe\x0d\xa7\x09\x3a\x8b\x24\x62\xdd\xd6\x67\xff\xd7\x89\x60\xc4\xdb\x78\x64\xeb\x54\x74\xe6\x54\x3c\xb7\x85\x28\xa7\x99\xd8\x15\x93\x82\x2c\xf9\x59\x2e\x3f\xd0\x39\x54\xfe\xec\xf4\x4b\x61\xb0\x42\xdd\x00\xb7\x9c\x8f\x20\x0b\xf4\x7b\x48\x26\xcc\x48\x6b\x7a\x8b\x34\x0c\xce\x6e\x77\x5d\xe1\x0b\x33\xf0\x8c\x18\x96\x64\x77\x07\x97\x0b\x19\xeb\x37\x9c\xaa\x83\xbe\xda\x1e\xb2\x7b\x70\x0c\x11\x5a\x73\x5d\xb6\xb4\x96\x05\x9e\xb2\xaf\x3c\xe5\xe5\x4f\xc7\x29\xba\xbc\xe3\x99\x30\xd4\x63\x24\xd2\x70\xb8\xee\x18\xd1\x16\x43\x44\xf6\x6c\xfc\xca\x65\x0d\x38\x4e\x0f\x24\xe7\x9a\x70\x60\x67\x21\xf7\xd5\xe9\xef\xe4\x67\xdf\xf0\x42\xb8\x9b\x54\xef\x55\x75\x61\xdb\xe0\xdc\x20\xf0\x8a\x47\x1b\xad\xab\xee\x3c\x84\xaf\x8c\x6f\x20\x52\x99\xb9\xf3\xb5\x6b\x40\x68\x6d\x10\xa8\x04\x9b\x30\xb5\xc7\x18\xd1\x0c\xd9\x8a\xab\xc3\x45\x45\xd6\xeb\x6b\x0f\xbd\x44\x5f\xa8\x27\x9a\xc3\x5f\x93\x7a\x74\xc3\xf9\x83\xe2\xfa\x83\x92\xd2\xe5\xb5\x6e\xa0\xfd\xac\xc6\xb2\x8a\xcd\xfc\xdf\x5e\xe4\x69\xf9\x77\x10\x84\xb9\xcd\xc4\xdf\x64\x9d\xd3\x4a\x98\xc7\x96\x22\x1d\x05\x9a\xbf\xeb\xae\xe1\xec\x58\x2b\xdb\x49\xad\x3f\x70\x44\xf6\x4e\xe6\x7e\xd0\x60\x66\x7f\xd3\x9a\x1d\x48\x2d\x98\xef\xb4\x01\xa4\xd2\x4f\xc5\xef\xf8\x16\x73\x98\xd3\xf0\xbc\x50\x92\x03\x8a\x64\x47\x52\xd9\x17\x04\xe9\x00\x2e\x4d\x7d\xf5\x4e\xff\x04\x68\x35\x9c\xd5\x62\xbf\x73\xf9\x09\xac\xec\x0a\x8f\x6f\xa8\x5f\xa3\x83\x67\xdc\x96\xf3\x77\x87\xda\x41\xf0\x89\x97\x36\x37\x55\x91\x07\x42\xe2\xc0\xb7\x6b\x3c\x25\x26\x63\x30\x30\x51\x86\x11\xa5\x37\xb7\x0c\x72\xb9\x71\x98\x8e\xc3\xba\x05\x2b\x5c\x5e\xd3\xab\x04\x7d\xab\xd7\x92\xc8\xee\xd6\xf4\x34\xb2\x2b\x0c\xd0\xa0\x50\x13\x47\x4e\x8a\x9a\xf3\xe2\x5e\xd8\x0e\x0f\x84\xfc\x6b\xca\x42\xdb\x6d\x0b\x96\x1d\xc8\x5b\xea\xd3\xcf\x2d\x22\x1f\x6e\x3c\x02\x71\x39\x7b\xd5\x5a\xec\xd4\x5a\x1c\x00\xab\x0d\xa6\x41\x3a\x08\x83\x21\x09\xe0\x22\x0a\xa1\x42\x0a\xe0\x2a\xba\x75\x96\xf9\xff\x56\x02\x95\xf7\x77\x41\x94\x55\xac\xb2\x25\x77\x78\xad\x12\xe7\x2d\x2d\xc2\x5a\x98\x60\x29\x79\x0c\xc8\x1f\x67\xcb\x62\xbf\x16\x98\xbf\x65\x64\xdf\x48\x14\x35\xab\x23\xf2\x5e\xb9\x8d\x70\xfd\x0d\x49\xf8\x17\x93\x26\xdb\xd8\x88\x1b\x23\xc7\x92\xde\x06\x56\xb3\x82\x10\x8b\xcd\xa6\xbe\xa1\x67\x02\x97\xf3\xe5\xf4\x89\x57\x7e\xf1\x73\xec\xd0\x8f\x25\x47\x58\x7e\xdf\xf0\xc0\x54\x7f\xd5\xac\x4f\x00\xaa\x20\xa0\xb8\xec\x3c\xf9\xa4\x50\xaf\xe5\x3e\xb2\xc4\x62\x39\x92\x15\x73\xaf\xf8\xe2\xb9\x32\x3b\x20\x6c\xce\x42\x3c\x69\x72\xdc\x04\x55\x1a\x9f\x0b\x35\xf2\x34\x73\x8c\x0c\x75\x4d\x7a\x88\xed\x13\x1f\x91\x6a\x01\x95\xf1\xbb\x6b\x61\xdf\x7e\xd2\xcf\xf1\x83\xbf\x4b\x74\xfa\x04\x05\x3f\xca\xa5\x43\x7c\xda\x08\xa0\x4f\xfe\xfe\x23\x3a\x73\x22\x35\x03\x0a\xda\x10\x5d\x49\x73\x5d\xbe\x7d\xf5\xad\xbf\x94\x4b\xf7\xfb\x28\xe5\x75\x64\x73\xb8\x9a\xb2\xe0\x44\xed\x75\xa0\x81\xcb\x5d\x66\x95\x65\x02\x38\x8f\x3a\xd7\x0f\x0a\x7e\xe6\xbd\x84\x89\xe3\x1d\xb0\xfe\x22\x87\x21\x16\x98\x90\xed\x8d\x66\x85\x04\xff\xe3\x2e\x22\x1c\x96\x98\xe3\x6c\xc0\x19\xf5\xb1\xa0\xcf\xdf\x77\xfe\xad\x29\x6f\xa1\x08\xde\x0d\xb0\xbf\x1c\xdd\x3d\x14\x48\x9c\xd7\xf6\x62\x23\xab\xba\x93\x52\x8b\x6b\x61\x7e\x57\x1b\xe0\xc7\x6e\x4a\xd9\x52\x59\x3c\xc3\x54\x0e\xdb\x5f\xb5\xc4\xee\x1f\x10\x3f\x69\x1d\x4b\x0f\x55\xfd\x96\x74\x5c\xc2\x60\xb0\xdf\x6c\x58\xc2\x20\xc8\x00\x58\xab\x5b\x80\xea\x0a\x8b\xe9\x05\xdb\xfe\xbd\x44\x51\x1d\x1d\xbd\x7e\x86\xf8\x95\x8a\xc3\xc9\x09\xba\x23\x57\x50\xe6\xcb\x5b\x01\x98\x82\xd8\xef\xf8\x6f\x0f\x7f\x3c\x2a\x3b\x92\x1a\x9e\xfe\x18\x9e\xf0\xe9\x9f\x0e\x1b\x45\x14\x40\x94\xc5\xf4\x6c\x32\x2c\x69\xc8\x58\x11\xa5\xf3\x36\x6a\x7c\x39\xea\x04\xfe\x52\xc7\xe3\xb2\xc6\xa3\xea\x4e\x09\x64\x28\x49\x1b\x0e\x73\x86\xe7\xbe\x5b\x0a\xd1\x01\x80\x3f\x54\x34\x21\x0e\xe6\x1b\xe8\xb6\x30\x52\x36\x8d\x9f\xf3\xaf\x3e\x7c\xdf\x89\xbc\xd0\x26\x7f\x55\x37\xa3\xbf\x16\x87\x45\xdc\xa8\x76\xf3\x9b\xd1\x46\xef\x58\xa8\x3f\x01\x10\xb3\x95\xce\x81\x60\xa3\x32\x69\x01\xb8\x60\xeb\x21\x7e\x49\xbf\x5f\x03\x35\xd5\xd4\x21\x28\xad\x29\x55\x47\x3a\xc2\x07\x58\x66\x86\xf8\x36\x6c\xef\xd7\xbe\xd0\xb8\x54\xba\xc3\xab\xe8\xc5\x87\xc6\xd9\xfe\x31\x88\x40\x9f\xfd\x1e\xf2\x23\x68\xdd\x99\x1d\x56\xec\x55\xf9\xbb\x69\xc7\x55\xda\xf7\x8d\x13\x0f\x97\x40\x81\x27\xaa\x09\x3f\xbd\x1e\x3f\x3d\x0a\xe0\x01\x30\xa5\x40\x5c\x52\xf1\x65\x47\xd2\x31\x39\xb3\x10\x5e\xd2\x70\x58\x92\x70\x68\xe2\x58\x4f\xf2\x78\x75\x87\xc5\x16\xd7\xa2\xec\x62\xc6\x45\x06\x81\xc1\x0a\xb3\xe6\xc7\x87\xb6\x3c\xe8\x74\xd6\xdb\x73\xb9\x4a\xb6\x62\x0a\xb0\xaa\x8d\x0e\x56\x43\xb2\x09\x34\x25\x0a\xc9\xc1\x3e\x47\x4e\xf0\x01\x17\x1d\x80\xbf\x1d\x5f\xe3\xb6\x16\xbb\xf2\xa5\xcd\xfe\xe6\x32\x33\xbf\x9a\xaa\x2a\x59\x70\x2f\x56\xcf\xcc\x57\x70\x1d\x3d\xe1\x8d\xa1\xc2\x5a\xdb\x6d\x0b\x62\xbc\xb0\xc0\x4d\x91\x2b\xfa\x6d\x60\xaa\xc8\x1e\x1b\x6b\xce\x8e\x38\x2a\x12\xbb\xd1\x3b\x81\xf5\x0f\xe0\xe8\x74\x67\x59\x9b\xb2\x56\x38\xa5\xa7\x4b\xc1\xc7\x78\xdc\xd7\x3e\xb2\xfd\x1f\xeb\xe4\x57\x24\xf3\x01\xcd\xf6\xe4\xaf\xdb\x79\x99\xe9\xdc\x82\x7f\xa4\xb2\x91\x5b\x28\xc9\x8c\x11\xf0\x6f\xa7\xc2\x68\x8b\x25\x2f\x2f\xdc\xd6\x91\xf6\x7c\x17\x04\xc9\x36\x53\xdf\x7d\x0e\x07\x27\xde\x43\x2d\x38\xa1\xcc\x18\xdf\xc0\xdf\x3f\xfd\x33\x20\xd7\xff\x18\x7c\xaf\x32\xa4\x38\xbb\xc5\x71\xdb\x29\x42\xc8\x51\x6c\x6f\x28\x8c\x96\xb4\x1c\x66\xd5\xd5\x2c\x57\x65\x01\x89\xbb\x41\x74\x7d\x12\xfd\xf5\x07\xc5\x7b\xc6\x96\xb9\x3d\xc9\x86\xa8\x31\x32\x31\x50\x40\xc7\x4d\x06\x25\x8e\x01\x19\x50\x6a\x9e\xbc\x12\x0d\x82\x2e\x48\x1a\xe8\x3b\x8a\x24\x07\xfc\x8c\xb9\xa1\x09\xd1\x6c\xb6\xf0\x3c\xd1\xdc\x73\x84\xb2\x4f\xa6\x35\xd1\x28\xca\xcb\x7f\x33\x23\x3a\xab\xc1\xf6\x07\x95\xb5\x55\x1b\x53\xf8\x5f\x0b\xe2\xee\x9b\x1d\xe6\x44\x42\xa2\x02\x5a\xec\xe3\xf9\xf0\x11\x97\x86\x54\xdb\x4f\x2b\x72\x32\xc7\x62\x5d\xb3\x2e\x73\x3a\x3e\xf9\x35\xaa\xe3\x32\xa7\x85\xa9\x67\x7f\x7c\x2a\x2c\xd4\x54\xad\x28\xe9\x07\x8a\xbb\x6f\xe9\x93\x16\x27\x92\x79\x17\x59\x8c\xe8\x41\x5a\x5c\x23\x2d\x9c\x7e\x20\x14\x0b\x17\x2b\x9c\x62\x65\xe8\xd7\x5d\x4c\x3f\xc3\x65\x87\xba\x62\xbb\xad\x54\x5a\x56\x37\x7d\x34\xc8\x2e\xaf\x05\x53\x2b\xf2\x73\xb0\xdb\x91\xd3\x65\x4d\x47\x3c\x67\xf0\x57\x5f\xcb\x71\x59\xd3\xa6\x0f\x7e\x67\xb6\x92\x79\x38\x2e\x4b\x92\x86\xfb\xc6\x3c\xd8\x6f\x5e\xf5\x56\x71\x25\x50\x6a\xc2\xa4\x4d\xeb\x71\x0b\x0d\x23\x22\xc8\x37\x1e\xe1\xc3\x46\x52\x59\xfc\xcd\x86\xb2\x56\x17\x0d\xaa\xb8\xbb\x33\x86\x4b\x97\x27\xcf\xfe\x31\x33\x3d\x06\x97\x12\x0d\x49\x2a\x36\xbb\xc7\x10\x3b\xfe\x1c\xa7\xf6\x84\x4a\x23\x71\xb2\xcc\xf4\xd1\x65\x4d\x90\xce\x33\xe8\xf4\x25\xb8\x17\xfc\x5c\x21\xbb\x5e\xe1\xdd\x37\xf5\x5f\xaf\xe7\xe9\x22\x0c\xce\x8d\x67\xc3\x5a\x86\x21\x09\xe9\x2b\x43\xa6\xec\x80\xc8\x83\x7b\x64\x9c\x08\xc7\xbb\xab\x77\x9c\x48\xc7\x65\x6d\x7a\xe7\x97\xba\xad\x04\xd1\x55\x14\xc0\x45\xa0\xb9\xfd\xc2\xc0\x96\xd6\x9b\x22\xc0\xc8\xb2\x8b\x51\x80\x85\x4b\x1f\xc5\xad\xc7\x08\xa5\xb2\x20\xf1\xca\xaf\xd9\x06\x84\x0e\x07\xbc\xe4\xdb\x26\x8e\x7e\xdf\x4e\x94\x04\xfb\xd4\xda\x4b\x9a\x93\x57\x00\x60\xf9\x56\x9f\x3f\xb6\x2f\x86\x0d\x71\xda\x15\x29\x55\x46\xa6\x2e\x49\x4a\x1b\x87\x22\xab\xf4\x75\x79\x80\x24\xcd\x03\x18\x48\xb1\xd2\xc9\xce\x93\x85\x3f\x94\xc1\x27\x3b\x5d\x60\x84\x2e\x46\x11\x01\x9b\xd3\x4a\x8c\x0b\x63\xff\xf3\x90\xb9\x75\x71\x71\xcb\x31\xaa\xbe\xa5\xf0\xe1\x0b\xdd\x1d\x61\x7b\x74\x83\x89\x3c\x88\xa2\x60\x9f\x62\x94\xb4\xef\xe4\x2d\x64\x9f\x6f\x63\x21\xb1\x48\x71\x7e\x1b\x5a\x48\xff\xce\xc9\xf9\xe5\xcf\xc2\x46\x23\x56\x0e\x8a\x3b\x0c\x6e\x44\xb8\x5e\xff\xe7\x0d\x5d\xa9\xa3\xc4\xbe\xd4\x9e\x52\xa1\xc0\x8a\xce\x6c\x48\x60\x23\xa1\x1a\x84\x8b\x85\x62\x0b\xd3\xc6\x87\x42\xf5\x5c\x91\x5f\x79\x3f\x04\x07\x0a\x3b\xce\xb1\x31\x4f\x11\x1d\x7d\x03\x2c\x09\x94\x01\x5b\xe8\xff\x10\x73\x56\xb9\xa6\x46\x14\xce\x4b\xc6\xcc\x18\x85\x7b\x04\x5a\xb6\x11\x99\x57\xec\x00\x3a\x0e\x75\xe4\x4b\x28\xcc\xff\x3d\x95\xd6\xf7\x3b\x25\xb5\x20\x45\x8b\x43\xec\xe5\x80\x23\x83\x3f\xa8\xe1\x38\xd9\x34\xf8\x00\xa2\x4f\xb2\x42\x69\x26\xe6\x38\xd3\x40\x3a\x01\xa9\x48\x64\x0b\x8e\x2d\x20\xa8\x84\x30\x12\x10\x3c\x1e\xfc\x40\xc8\xb2\x11\x91\x4d\xa9\x74\x99\x95\x35\xee\xee\xe5\xd9\xf0\x0f\x4d\x25\x5d\x3f\x1f\x9a\xc4\x76\x30\xf8\xd6\x0b\x86\x55\x85\x7c\xd0\x57\x6b\xc4\xaf\x86\xf1\x8d\x7e\xc8\x8a\x0b\x7d\x53\xba\x94\x05\xa0\x57\xc0\x0f\xa7\x48\xad\x52\x2a\x85\x47\x87\xba\x70\xeb\x71\x69\xe3\x58\x27\xdc\xdf\x1d\x32\xb1\xc8\xb6\x35\x8f\x2b\xd3\x6b\x70\x4d\x78\x6c\xe9\x6e\x8d\x3f\x81\x2a\xcd\x17\x57\x7e\x7f\xbe\xef\x4f\x31\x6b\x59\x56\xb9\x7a\xed\x9c\x19\xe4\x10\x41\xb7\x9d\xdf\x6d\xc1\x91\x47\x2c\xdc\xe8\xd1\x0f\x19\x6b\xa0\xb9\xf1\x7a\x20\x44\x01\x5a\x6c\xc9\x8e\xe2\x14\x50\x18\x04\x57\x21\x58\x06\x13\xa4\x60\xe5\xb5\xbe\xbc\x3a\x25\x55\xaa\x51\xa3\xcd\xdb\x0d\xe8\xc6\x24\x7b\x0f\x54\x7a\xc3\xbb\x8f\x84\x5f\x89\xab\x05\x1e\x04\x5a\x0f\x78\xdf\x7e\x12\x05\x4f\x6e\x89\x9c\xba\x3d\x22\xff\x98\x42\x38\xaf\x6a\x8b\x15\x96\xd8\x66\x26\xd5\x61\xea\x90\x45\x0f\xe8\x6d\x84\x23\x4a\xa0\xd5\x41\x33\x6f\x24\x33\xf8\x88\xb5\xb9\x89\x8e\x9f\x70\xc5\xd9\xb8\xd8\xfc\x37\x5f\xdd\x83\x91\x6c\x5a\x63\x99\x35\x3c\x81\x67\xc3\x1d\x0f\x09\xf6\x1e\x2a\x53\xf2\x14\x08\x68\xb4\x42\xeb\x58\x49\xc6\xa7\x04\xe4\x75\xea\xbb\xaf\xad\xdc\xaa\xb4\x83\x01\x89\x3e\x4e\x2f\x1d\x5e\x11\xcb\xc8\x6c\x79\xc9\x9e\x35\xa1\x04\xab\x36\x63\x2a\x77\xc6\x43\x8c\xd2\x9c\x0a\xcd\xcc\x6e\x75\x5e\xdb\xc2\xec\x7c\xed\x17\x03\x51\xc5\x11\x6c\xbf\xa8\xf4\x1d\xe8\x32\xb5\x84\xe9\xb8\xcc\x1a\x4e\x01\x1d\x0f\xdb\x8d\xda\x6b\x62\x48\xdc\x8c\x31\x6e\x36\x4c\x57\x52\xcd\x09\x1f\x5b\x27\x58\xad\xba\xfc\x83\xd5\xce\x2e\xc3\xa1\xfa\xee\x9b\x87\x53\x94\xe2\x5c\xe3\xc4\xd3\xe8\xbf\xfd\x79\x3f\xce\x7e\x42\x05\x07\xa2\xa6\x83\x39\x41\x96\x6b\x31\xf6\xcc\x14\xe3\x4a\xc3\x6a\x12\xf0\xc4\x81\x54\x24\x83\x34\xbd\x37\x73\xf2\x9e\x0a\x38\x43\x1e\xeb\x55\xb1\x91\xdd\xdf\xdf\x3a\x98\x5f\x06\x60\xc5\xfd\xc3\x68\x04\x69\xe4\x24\x31\x7c\x06\x8c\xfb\x74\xbd\x57\x30\xb7\x9b\xdf\x2a\xd3\xf8\x52\x04\x75\x86\x90\x85\xe6\x3d\xe0\x8d\xc9\x9b\x91\x9f\xd1\x8b\xcf\xab\xcc\x55\x29\xa3\x6e\x30\x00\x7a\x13\x11\x74\x5a\x95\xf2\xfe\x2f\xe2\xe9\x8a\xee\xd9\xb9\x90\xbc\x87\x81\xfa\x1f\x6b\x87\x52\xaf\x9a\x2c\x22\x11\x85\x35\xc5\x72\x91\x72\xfd\x71\xf7\x0a\x1f\xdb\x11\xc9\x03\xed\x35\x13\x26\xef\xc7\x79\xdd\xea\xf6\xad\xf3\x4e\x7e\x4d\xca\xcf\xfd\xb5\x73\x4f\xea\x5f\xe7\x27\xbc\xfd\x2c\x86\xed\x4b\xec\x34\x20\x64\x73\x53\x49\x79\x7a\x37\x96\x6f\xaa\xdb\x79\xbd\x88\x70\xdf\x58\x34\x48\x87\x6d\x33\x51\xf6\xec\x34\xda\xff\x7c\x87\x0e\x68\x66\x87\xe9\x07\x5d\x44\xc1\x53\xfd\xbb\xe7\xbf\xb5\xda\x70\x85\xdd\xba\x53\x3a\x15\x4a\x1a\x0c\xb5\x7c\x26\x41\xc4\x37\x75\xd6\x3b\x3d\x54\xf0\x38\xef\x8b\x7c\x30\x1e\xaa\xda\xca\xe7\xc3\xef\xf5\x9b\x8f\x23\x59\x9e\x96\x00\xa8\xf7\x61\xf7\xfa\xaf\xee\xac\xe8\xbb\xd1\x86\x17\x04\xef\x0d\x7f\x43\x96\xd1\x23\x62\x94\x1f\xb6\x57\x18\xcf\x9e\x2c\x43\x72\x49\x89\x31\xe4\x8e\x7c\xf4\x4e\x29\x4c\xd7\xdc\xa0\x06\xb2\x6f\x1d\xa1\xbe\xe8\xf6\x4b\x12\x3a\x63\x37\xc8\xf3\x3d\xfa\xf7\xa0\xb8\xe1\xdd\x72\x1b\x0b\xf2\x75\x7b\x61\x35\x69\xc1\x98\x48\xd7\xaf\xe5\x3a\x89\xe0\xf4\x83\xe6\xa2\x17\x4c\x35\x11\x61\x73\xc8\x19\x6d\x7d\xab\x13\x30\x70\xdd\x22\x62\xf4\x45\xf0\xf3\xc1\x62\x61\xd2\x6b\x0b\x14\xc1\xf1\xa3\x1f\x9a\xeb\x7c\x70\x59\xd8\x5e\x9a\xf0\x91\x85\xfe\xd1\xfa\xbd\xca\x36\xe1\x2e\x54\xd6\xd4\xc6\xa3\xc9\xd5\xb1\xed\x70\x4b\x1c\x0e\xcb\x19\x79\xf8\xbe\xb6\x31\x21\xf3\x8c\xfd\xfb\x34\xa8\xf1\xd4\x97\xda\x2d\xd2\xb8\x2e\xa2\xc4\x1f\xac\xba\x7f\x85\xa9\x6b\x49\x1a\xd4\x80\x93\xe6\x50\xff\x2b\x18\x99\x2a\x62\x26\xb6\xfe\x97\xf7\x7e\x11\x8f\xcb\x4f\x10\xfc\xbc\x27\x6d\x85\x97\x7b\x4a\xc3\x6f\xf4\xaa\x9b\xe2\x53\xeb\xa9\xa1\x58\x6f\xef\xa0\xd4\x76\x5d\xe6\xcd\xb1\xc7\xc4\x0f\x2c\x86\x71\x1d\xfd\xca\x5e\xca\x6c\x6e\x7d\x0e\x2d\x6f\x81\xe8\xfe\x4b\x88\x66\x73\x75\xad\x7b\xde\x7e\x51\x63\x8e\x33\xd8\xcd\xf8\x68\xaa\x92\x6f\x98\x15\xd4\xb1\x5b\x89\x1c\x4d\xf3\xad\x47\xb4\xf6\x1b\xc9\xe2\x28\x4a\x34\x68\xa9\x6b\x98\xdb\xd2\x98\x09\xae\x8e\xad\xc9\x5d\x62\x09\x60\x5c\xc0\xeb\x0f\xc6\xb8\x95\xaa\x0d\x79\x83\x8d\x6c\xce\x8a\x42\xe8\xd8\x76\x9a\xc1\xd9\xea\xc1\xf7\x9c\xfd\xe8\x72\x05\x98\xd7\x7a\x39\x99\x92\x4e\xf0\x7d\xfc\x6b\x66\x9e\x50\xe9\xe6\x35\xfc\x92\x5a\x20\x03\x4a\x1f\xc1\x83\xbf\x75\x69\xca\x81\xb1\x5d\x53\x1f\x2e\xf5\xda\x0e\x75\xa4\x9b\x43\x91\xd1\x12\xb9\xf7\x84\xe6\xe6\xd4\xa7\xc6\x5f\xbc\xd8\x44\x64\xd7\x0b\xd9\x66\x39\x49\xdb\xbf\xb2\x20\xcf\x6f\xbf\xc4\xac\x40\xfa\x23\xda\x88\xa7\xb8\x08\x12\xac\x19\xf1\xde\xf1\x6d\x68\x00\x27\xda\xde\xd4\x9c\x48\x16\xa6\x9e\x18\xcf\xc8\xff\xea\xdd\x4a\x1a\xd6\xb3\xcc\x3e\x4d\x55\x7d\x45\x14\x50\x34\x6b\x3a\x28\xb2\x43\x41\x4e\x46\x92\xf4\x8a\x0e\xe2\x3a\x2f\x9e\x9f\x58\xe8\x98\xed\xa2\x06\x63\xd5\xf7\xb2\x2f\x21\xf4\xbc\x5b\xe3\x30\x74\x7b\x50\xc7\xea\xe8\x8a\x4f\xae\x88\x3d\xac\x89\x0f\x9a\xef\x99\x76\x59\xfc\x43\x01\x91\xb6\x60\x7d\xbc\x84\x97\x80\x2b\x65\xf5\xcd\x42\xfa\x8e\x11\xc6\x80\x4f\xd3\x72\x32\xe7\x0a\x37\x20\xfd\x51\x60\x71\x4e\x5f\xf2\xb8\x67\xc4\x3f\x10\x6e\x49\xd2\xab\x58\x17\x42\x56\xe2\x49\x24\xb9\xcd\xcd\xe1\x5f\xfe\x84\xc4\xd2\x0c\x46\xa5\x9e\x8f\x37\xf3\xe1\x59\x0a\x64\x40\xa6\xe5\x24\xba\x70\xea\x67\x4a\xd1\x8b\xf1\x2c\xc1\xf9\x0c\xf9\xe0\x7b\x85\x57\x3c\xa6\x5c\xa0\x2e\xdb\x0d\xde\x1f\x76\x92\x78\x73\xab\xf7\xba\xb0\x4c\xb6\x0c\xfc\xa9\xcb\xb4\x2d\x0a\x5f\xe3\x6d\xdf\x6d\x04\x70\x6d\x34\x6a\x3c\xb5\x91\x8b\xdb\xce\xf9\x3c\xa0\x97\x48\x8a\x54\xd1\x36\x40\x64\xc7\x0b\x82\xed\x77\xb4\x21\x10\xd3\x81\x90\x9e\x32\xf1\xf9\xa9\xa1\x24\x0d\x23\x78\x35\xa2\x28\xda\x21\xde\x02\x7d\x0b\x71\xaa\xed\x9c\x8a\x2c\xde\xb9\x02\x69\x7e\xbb\xea\xe8\x13\x59\xac\x8f\xff\xd6\xfe\x7b\x4a\x27\x83\xc4\x5f\xe8\xbf\x54\x9a\xe6\x6b\xa6\xd5\xd2\xd6\x6d\x7a\xf7\x5a\x2f\x28\xd6\x3b\x7a\xe9\x70\xa4\x10\xbf\x37\xf4\x6a\xc8\x57\xfa\xce\xf0\x7c\x58\xf1\xfa\xc4\x72\xd9\xf3\x78\x81\x22\x3d\xe7\x55\x68\x34\x17\x3a\xc3\xa2\xde\x10\x22\x56\xcc\x05\x31\xf3\xde\x5a\x9f\x49\x96\xa2\xe0\x9c\x3a\x1c\xa0\x51\xac\x7a\xf0\x5b\xa5\xcb\x60\xcc\xc6\xbf\x9c\x10\x49\x17\x3c\x2f\x8c\x42\x92\xe6\xbf\x6f\xbf\xb9\xf4\x5a\x5a\x1c\x95\x04\xdb\x6d\x7e\xbf\xfb\x84\x89\x1f\xcf\x62\xb9\x29\x65\x24\x95\x22\xf8\x99\xf5\xcb\x9b\x1f\x6b\x76\xf0\xc5\x85\x6e\x0f\x4e\x11\xd9\x0c\xbd\x25\x44\x18\xe0\x19\xc5\x80\xd8\xb8\xfe\xa4\x10\x74\x79\x42\x59\x89\xb6\xbb\xdc\xb8\x2a\xa5\x40\xce\x9c\x33\x74\xce\x6c\x03\xf5\x61\x76\x1d\x3d\x6c\x57\x35\x2f\x02\xba\xfe\x18\x3a\x7c\x22\xdf\xa9\xf6\xbc\xbd\x39\x51\x80\xd5\xc5\xbd\x22\xf1\x85\xb9\xac\x98\x3a\x33\xd1\x2f\x94\x0d\x26\xbf\x18\xa6\xb7\x25\x2f\xd9\x61\xe2\xdc\x96\xf2\x44\xe7\xc0\xe7\x75\x4c\x55\x9a\x14\xa8\xc4\x1b\xe2\xf9\x78\x40\x8d\x30\x18\x32\xf3\xdb\xb1\x38\xb2\x5b\xce\x67\xf3\x4e\x7e\xf5\x4e\x26\xac\xb2\xaa\x16\x0a\x28\x2a\x6b\xfa\x80\xe9\xf2\x07\x92\x7e\xb1\x4e\x7d\xaf\x2d\xca\x53\xb2\x78\xfa\x44\x71\xfd\x81\x30\x94\x68\xea\x70\x1c\x3b\xf3\xaf\xd8\x11\xe2\x48\xd1\xec\x50\xc4\xea\xb2\x53\x2a\xa3\x0a\xd2\xde\xde\x4a\x21\x79\x83\x6f\xb5\xaa\xe5\x25\x42\xb4\x6f\xb1\xf3\x63\xaf\x0d\xd9\x32\xad\x34\xdc\xe4\x6a\xa6\x77\xc7\x75\x25\xf6\x2b\xa2\x34\x65\x52\xec\xc9\xe8\x36\xd1\x7a\x59\x66\x18\xc8\x5a\x77\x5a\x1b\xbe\xa3\x3d\xf6\x8b\x97\x62\x38\x87\xb5\x40\xa6\x36\xaf\x68\xeb\xa5\x42\x6f\x04\x81\x72\x63\x98\x0e\x48\xca\x72\x8b\x49\x81\xb6\xbd\xea\x7f\xec\x9d\xfb\xda\x0f\x61\xe0\x3d\xaa\x73\xdb\x61\x12\x1b\x32\xf8\x19\x37\xba\x05\x22\xcc\x29\x23\x81\x45\x7d\x77\xcd\x32\x8a\xa4\xc7\xcd\x62\xc0\xcf\x68\x4a\x90\xe2\xef\xef\x11\x37\xb7\xee\x9e\x3e\x7b\x57\xb9\x35\xd1\xc7\xed\xc1\xde\x00\xac\xbb\xfc\x90\x39\x7c\x37\x60\xb8\xed\x8e\x26\x05\x93\xa8\x06\x3b\x04\x46\x04\x69\x10\x2f\x11\x90\xfe\xbc\x1f\xac\xed\x7b\xa5\x00\xca\xcb\xb6\x91\x36\x10\xfb\xa6\x3e\x82\x44\x34\x66\x35\xe1\x00\x68\x20\xa4\x76\x20\x04\x16\xa1\x48\x07\x81\x05\x20\xae\x1e\x6a\x72\xf0\xe0\x3a\x94\x1a\xa5\x40\x09\xe6\xe7\x2c\x66\x76\xef\x1a\xfe\x1b\x03\x95\x29\xc5\xb9\xd1\xb8\x46\x17\xc3\x24\x0d\x8c\x46\x1e\xfb\x75\x2b\xbe\xdd\xba\x6e\x29\xbc\xe2\x47\x48\x9e\x08\x1d\xd1\x71\x18\x8c\xc9\x80\x9f\xd9\x84\x83\x20\x55\x5a\x12\xc8\xd1\x20\x80\x37\x55\xaf\x80\x20\x51\xe8\x53\xe9\xd6\xd8\x4a\x9c\x5b\x48\x26\x7d\x1a\xfe\x9a\x39\x07\xe3\xbd\x92\x6d\x06\x7a\xb1\xe7\x30\xe1\x52\xa0\xe5\x30\x9c\x1b\x82\xca\x9f\xbf\x9c\xaa\x3d\x9e\xda\x21\xa6\xcb\x26\xc2\x32\xaf\x66\x0b\x31\x5e\x22\xf3\x72\xeb\x2f\xd9\x8b\x41\x8b\xea\xce\xec\xfa\xaf\xd6\xc2\xfd\x7a\xb6\xa6\xec\xb2\x62\x2c\x5e\xe6\x8d\xee\x2d\xe9\xd2\x92\xa0\xb7\xb0\x10\xfe\x84\x95\xeb\x34\x86\x24\xf4\x1f\x28\xe7\x8b\x67\xcf\x08\xa0\x50\x66\x83\xb9\x57\x56\x90\x7a\xe1\x5f\x5d\xef\xd8\xd2\xf7\xd8\x08\x84\x06\xb4\x46\x55\xda\xf9\xd4\xb8\x7b\xd7\xac\xc7\x0f\x7f\x4d\x02\xa8\xd7\x06\xad\x19\x77\x53\x86\x39\xfd\xeb\x97\xd0\xf8\xe1\x4f\x22\x01\x90\x1d\x6e\x3e\x31\x20\x21\x1e\x84\x13\xcd\x76\xfc\x17\x7d\x4f\x0f\xe4\xb2\x65\x4a\x22\xc9\xa7\x07\xa1\x52\x92\x46\x01\x81\x86\x54\xcd\x77\x20\x1a\x1f\x67\xa0\xef\xf5\xbf\x4b\x1a\x1f\xb8\xdf\x83\x29\x80\x8d\xb8\xf1\x15\x8f\xe4\xe5\x4f\x13\x08\xdc\xf5\x61\xa3\x5c\x08\xd9\xd8\x29\xb3\x6b\x6e\xf2\xcb\x23\x41\xef\x64\x7a\x8a\x25\x3f\xb2\x41\xa9\x59\x5c\x77\x10\x39\xa5\x5f\xd4\xf7\xe0\x05\xa8\xe1\x88\x2f\x39\x24\x7e\xc6\x2c\x61\xc0\x98\xb5\x4e\x24\xd6\x11\xc0\xeb\xc1\x00\x75\xf2\x7c\xab\x54\x23\x9a\x77\x20\xa7\xc7\x52\x96\x15\x7f\xb2\x5c\xbb\x12\xfc\xc7\x79\xff\x1d\xec\xd9\x64\xce\xbc\x47\x28\x88\x47\x16\xfe\xe4\xe1\xcf\xb4\x23\xd0\x42\xa3\x85\x52\xac\x32\x1a\x70\xb3\x98\x92\x33\x1b\xf1\x3f\x89\x0a\x8c\xaf\xb2\xef\xdc\x82\xce\x16\xca\x4b\x4b\x7a\xc1\xa4\x09\x82\x24\x6c\x16\x8d\x2b\xae\xcc\x5f\x32\xdb\x27\x65\x41\x3b\x06\x59\xb5\xd3\xf6\xf7\x97\xb3\x23\x0e\x8b\x88\x63\x24\x37\xf6\xad\x30\x47\x4a\x64\x7b\xd5\x1e\xc4\x97\xe7\x80\x89\x25\x27\xa2\x01\xd2\x5d\xf6\x4d\x20\xff\xd8\xb8\x16\x97\x21\x49\xea\x6a\xc0\x2b\x32\x4d\xbd\x85\x65\x6c\xf1\x3e\x33\x49\xfa\x60\x6a\x54\xd4\x1c\xd5\x94\x40\xa5\xb5\x53\x9f\x41\xc9\x44\x51\xc2\x50\xdf\x71\x20\x73\x94\x54\x9e\x86\x15\x04\x1b\xf1\x29\x55\x57\x7a\xb1\x99\x63\xb1\x99\xb3\x0a\x24\x4a\x0e\xb4\xbe\x7d\x52\xde\xfc\x4f\xa3\x69\x7a\xba\xd0\x31\xec\x17\x22\x9a\x70\xa0\xf0\xe2\x35\x37\xc9\x0e\xa8\x37\xf5\xa6\xd2\xcb\x99\x45\x0f\xbf\xd3\x73\x59\x73\xbe\x3a\x46\x11\x64\x01\x74\xe0\x3c\x1f\x32\xfe\x9e\x17\x0d\xcb\x73\x30\xf9\x7f\xc3\xe5\xea\x5a\x8d\x29\xd4\x5f\xa6\x95\x72\xc4\x54\x5c\xd7\x73\x53\x97\xfc\x9a\xeb\xf7\x79\xe8\xfd\x4d\xdc\x40\x1f\x5f\x28\x11\x9b\x1d\x1e\xd5\xb7\x5f\x6c\x2f\x92\xb4\x17\x3b\x9f\x8b\xa9\x75\x2a\xf8\x95\x32\x2b\x3b\x72\x69\x4a\x21\x9c\x21\x24\x4e\x00\xf6\x62\xeb\x40\x23\x43\x72\x62\x88\xd0\x48\xbe\x9f\xe4\x40\x69\x58\xb3\xe1\xb1\xa6\xe3\xc6\x5b\xc5\xfd\x0c\x0d\x23\xd8\x29\x6f\xc3\x85\xe5\xc1\x85\xf1\xe5\x12\x8f\x01\x8b\xf5\xef\xd5\xe6\xa1\x79\xd0\x61\xb9\x7a\x27\x7f\x3e\x6c\xd8\xe8\x9a\x8e\x3d\x19\xbe\x40\x55\xee\x48\x15\xa1\x34\xd9\xc1\xc4\x6b\x6e\x0e\x93\x3f\x23\x75\x4d\xd4\x87\x53\x60\x8a\x34\x73\xac\x3f\x5e\x8b\xab\xae\xb0\x33\x97\x6c\x66\x92\x10\x0d\xe2\x65\xf4\x79\x10\x84\x77\x46\x57\xd3\x87\x83\x4f\xca\x89\xef\x7f\xda\xc5\x47\x7d\x6b\xf4\x27\x07\xe0\xc5\x15\xac\xd6\x97\xa3\x48\x51\x17\xbc\x0d\x19\xab\xf5\x61\xcd\x4d\x55\x3a\xff\xc9\x9f\x5e\x5a\x12\x2d\x08\xfe\x29\x54\x02\xcf\xa2\x74\xf3\x30\xb7\x77\xa2\x19\x52\x52\x5f\xd8\x9c\x50\xf2\x0a\xe6\xbb\xdb\x9c\x80\xe5\xe6\x4d\x6c\x84\x37\xbc\x8a\x52\x69\x8f\xcf\x72\x02\x63\x3b\xd2\x3b\xaf\xea\x95\x1d\x08\x7d\xa2\x20\x79\x80\x01\x02\x1f\x64\x79\xfa\xf0\x4b\x57\xca\x06\x13\x40\xa5\x0c\x50\x7f\xb8\x41\x92\x6b\x4d\xae\x0e\xd5\x0b\xe1\x42\xf3\xe8\xdf\x79\xd4\x10\x26\x19\xc9\x99\x0d\x78\xf8\x03\x26\x49\xeb\xf1\x32\x61\x9d\xc5\x26\xf0\x3d\x77\x80\xd8\x3f\x83\x29\x08\x82\x8c\x85\x81\x6b\xc2\x78\x19\x94\xb9\xee\xe7\x40\x61\xcb\x91\xac\x10\x88\x6e\xff\x01\x84\xda\xad\xf7\x81\x12\x3b\x29\x21\x1c\xf3\x49\xa0\xf0\x63\xf7\xe1\x26\x8a\xcc\x80\x0e\xd9\xf5\x7f\x4c\x2f\xcc\xbe\xc0\xe2\xbf\x2f\x79\x81\xdc\xba\x81\xcc\x19\x7e\x7e\xc0\xde\x78\xd9\x38\xa2\x10\xcb\x75\xcb\x39\xcd\x4e\x0f\x07\x59\x2c\x44\x19\x9d\x57\xb4\xed\x88\x71\xe2\x7b\x66\x7c\xc9\xe3\x5f\x00\x71\x9c\xd7\x46\xae\x84\xd9\xf4\x80\x34\x83\x12\x80\x5a\xa5\xa5\x76\x2a\x4f\xaa\xcd\x9c\xf6\xca\x6a\xc5\x8d\x76\x83\xdd\x18\x29\x14\xc0\xb0\x38\xcc\x7b\x3e\x65\xfb\x8a\xbc\x01\xb2\xf9\x51\x26\x7d\xc5\x4a\x4a\xdf\x36\x52\xf2\xc1\x0a\xff\xcb\xdb\xac\x84\xb8\xd6\x63\x96\x4a\x46\x03\xc0\x10\xc3\xb4\xee\xf1\x76\x83\x6b\xea\x4b\xa1\xbf\xbf\x71\x94\x55\x5d\x3b\x3c\x49\x31\xb5\x52\xb3\x29\x5d\x9e\xc9\xa2\xbd\x23\xdd\x86\x62\x1d\x6f\x26\x6f\x63\xb9\xe1\x07\x81\xff\x34\xec\x5f\x8c\xb9\xf2\xb4\x90\xe5\xac\x8b\x7c\x40\x3c\x69\x51\x49\x2a\x5e\x70\x9d\x83\x02\x95\x79\x44\x25\xba\xe0\xe6\x02\x5d\x8f\x4c\xc2\x20\x88\x92\x03\xd5\xf8\x2f\x91\xa5\xc0\xd5\x11\x75\x78\x65\x64\xc6\x3c\xf5\xbb\x88\x05\x1f\x4d\x3e\xcd\xa0\x10\x14\x28\x42\xd6\xfc\xae\xea\x09\x0e\x29\x84\xe6\xb5\xd4\x5a\x6c\xfb\x1b\x7f\xaa\x35\x79\xae\xcf\x9e\x7b\x3f\xa5\xa1\x2b\x87\x15\x23\x6c\x53\x64\x9e\x8d\x9b\xde\xc8\x80\xc5\x1f\xf3\x6a\xd3\xb7\x50\x13\x43\xc6\xb1\xc8\x36\x9c\xfb\x97\x5c\xe6\x45\x90\x9b\xd5\x68\xf6\x9f\x68\xff\xd1\xf7\xc4\x84\xc2\x3d\x2d\x68\x5a\xa1\x75\x84\x92\x8c\x42\x23\x2c\xa3\xb0\xae\xc4\xdf\x77\x1f\x6a\xae\x16\x66\x06\x02\xe6\xaf\xbe\xe9\x2c\xeb\xf4\x7b\xd0\x95\x56\x87\xc5\xd6\xdd\x72\xb2\xe9\xb1\xc8\x9e\xa5\xc8\x9e\x10\x9b\x42\x5f\x79\x20\x39\x5f\xb2\xa3\x1b\x0c\x90\xe0\xf9\x2d\x3e\xf6\x63\x64\x25\xd4\xbc\xde\xc1\x00\xa6\xb1\xbc\x67\xf8\x42\x61\x50\xfe\x14\x9a\x0f\x67\x2a\x46\x17\x42\xac\xe3\x03\xf7\x1b\xcb\xbd\x0b\x5f\xff\xec\xd7\xee\x77\xe7\xf4\x43\x0a\x88\x04\xda\xf2\xa0\x59\x4d\x7f\xf6\xa8\x84\x01\x9b\x5d\xb3\x28\x08\xbd\x27\x06\x03\x9e\x44\x5a\xaf\xe8\x78\x14\x9d\xf8\x36\xb4\x30\x37\xc3\x87\x21\xef\xa1\xa6\x3d\x08\xed\xae\x3e\xb2\xfb\xda\x8f\x48\xcc\x89\x48\xeb\x59\x60\xe1\x10\x7a\x74\x2f\xe5\xfa\x92\x7f\xca\x6c\xc4\xce\x6b\xf7\x1b\x05\x01\x3d\x94\x90\x15\x45\x76\xc4\x19\x9c\x08\x20\x85\x44\x2b\x2b\x2a\x53\x2a\x00\x50\xb6\x95\x73\xe2\x8e\x1e\x5f\x4c\x57\x62\xe4\xcd\xe4\x98\xda\xfe\x63\x34\xff\xa9\xfe\x74\xc4\x6f\xe5\x65\x49\xc3\x13\x2b\xa5\x13\xab\xa4\x01\xef\xe9\x3c\xac\x3a\x7f\x51\x3d\xa5\xba\x13\xfa\xfc\x52\xb2\x78\xe1\x15\x13\xd9\x3a\x7e\xf0\x14\x61\x6b\x46\xf1\x2b\x0f\x3d\x79\x20\x92\xd6\x3e\xc1\xc4\xe2\xf0\xe6\x82\xdf\xf6\xf6\x5f\x9d\x21\x6b\xa3\xb2\x16\x00\x00\x55\x4b\xe5\x64\xd9\xfb\x6d\x0c\xb6\x32\x27\xa0\x7a\x4a\x99\xe3\x6c\x2c\xb7\x1c\xb8\xcc\xea\x6b\x97\x79\x88\x83\xdf\x7d\x53\xdb\x27\x3f\xdf\x99\x39\x92\x31\x19\x6b\x71\xb9\x20\x5a\x7f\xa0\xbd\x56\xa4\x3f\x34\x1b\x79\xdb\xe6\x51\xdb\x24\xda\x3f\x8f\xd8\xc5\x7e\xa5\xec\x98\xae\x74\x0f\xc8\x27\x7d\x1c\xf3\x7a\x12\x5b\x30\xa0\x4b\x8c\xc3\x0a\x8a\xda\x6d\x2b\x79\xea\xa1\x22\xf8\x42\x77\xef\x89\xa5\xfb\xd4\xac\x32\x0c\x53\x33\xc2\x20\xd8\x81\x3d\xa1\x42\x81\xa9\xdc\xbc\xba\xe3\xe7\x05\x41\x10\xa4\x70\x79\xf5\x1e\xac\x31\xf6\x01\xe4\xa8\xf2\xae\xeb\xba\xea\xc2\xbc\xb0\x32\x28\x31\xf0\xf3\xac\xaa\xb9\xbd\x08\x73\x43\xbf\xe0\xbf\xd8\x1d\x6e\xcb\xe4\x01\x73\x08\x31\xf9\x88\x7f\xc7\x36\x2a\x6b\x7a\x6e\x35\x26\x73\xa7\x51\xfb\x12\x7b\x57\x5e\xb2\x43\xff\xce\xac\x90\x47\x8f\xf9\x1d\xc6\xf8\xd9\x0c\x39\x6f\x0f\x05\x38\x72\xd7\x25\x5f\x3d\xbb\xc2\xc1\x33\x19\xcf\x92\x4b\xe0\x8a\x8f\xee\x09\x83\xc2\xf9\x03\x22\x68\x0f\x86\x6a\x41\xa4\xc1\xef\x54\xb7\x8c\x6c\xb7\xc2\xae\x71\xdf\xf8\x25\x34\x48\x5f\x2f\xbe\x16\xe6\xe4\x86\x0f\x0e\x11\xa6\xc4\x53\x40\x65\xbe\x74\xe7\x2d\x6b\x32\x42\x3f\x85\x8b\x23\x6e\x51\xed\x9e\x17\xb0\x15\xcd\xef\x49\xb1\x05\x44\xe3\xe5\x2f\xc5\xd2\x50\xbe\x54\xfd\x2f\xff\xb2\x75\x2c\xd6\xc2\x18\xc2\x6f\xbf\x94\x3a\x63\xbb\x03\x40\x43\xbd\xb8\x19\x71\x6e\x4a\x58\x7a\x1a\x0d\x8c\x16\x68\xc1\x1c\x99\x0b\x1d\x4a\xe5\x5f\x04\xec\x07\x3f\x5b\xd0\x84\x40\x71\xa7\x97\x8d\xfd\xc4\xec\x07\xf2\xef\xfe\x2f\x1b\x8b\x0d\xb8\xf0\x7c\x96\xf5\x7a\x2a\xaa\xa7\xae\x81\xa6\x9b\x20\x68\xaf\x1f\x70\xd0\xac\x9d\x99\xe3\x0c\xe7\xb2\x60\x9a\x32\x63\xdb\x61\x84\xd9\x79\x54\xb7\x9f\x81\x98\x2a\xc4\x09\x1b\x8b\x0b\xe1\xd8\x84\x9d\x49\xd2\x38\xbf\x85\x48\x47\x67\x89\xa9\x43\x73\x21\x66\x70\x48\xf0\xbc\x93\xa6\x0d\x7f\xae\xf4\x96\xae\xb1\xc4\x76\xc3\xab\x72\x41\x52\xa6\x52\x69\x6c\xf6\x99\x71\xea\x67\xf6\x38\xb6\x33\x21\x33\x70\x50\xef\xf0\xce\xb2\x35\xcd\x07\x4b\x67\xdc\x14\xc7\xfc\xe3\x7b\x91\xed\x1d\xd5\x36\x91\x43\x6c\x1a\xe6\x0d\x83\x7e\x91\x39\x93\xb1\x83\xda\x95\x41\x8b\x04\xea\x99\x61\x69\x99\x83\x72\x7e\x2c\xf5\xe1\x29\xf7\x64\x74\x04\x47\x0c\x86\xa5\x70\x50\x3e\x7b\xb0\x4b\x3e\xbd\x1e\xf7\x03\xeb\xf8\xd7\xaf\xc4\xfe\xd9\x29\xaf\x17\x0f\x5d\x0a\x0e\x04\x5b\x6e\xa2\xc3\x8e\x1f\xe8\x2e\xb1\xc5\x2a\x57\x0f\xfa\xe4\x51\xab\x5b\xc2\x59\x38\x5b\xd3\xb3\xe0\x75\xb5\x3c\x9a\x35\x75\xd8\x2f\xd0\x2c\xe1\x7c\x07\xe1\x5a\x45\xad\xbc\x2d\x43\x4b\x16\xde\x0d\x02\x3f\xd0\x1e\x92\xbe\x09\x4b\xf4\x95\xdf\x9f\xdf\xd9\x06\x84\x66\xdb\x2e\x9e\x91\xc2\x2a\xa2\x00\x36\xb4\x6c\x59\xd5\x76\xa6\x4d\xd2\x13\x61\xfe\x06\xb6\x60\x4b\x7c\x96\xcf\x57\x57\xf6\xe2\x3d\xf4\x7f\x32\x6c\x78\xfe\xb5\xcb\x6e\x5e\xe9\x4c\x48\x71\x5a\x7b\xeb\xc6\xc7\x8a\x6f\x3a\xab\x6a\x2b\x5f\x9f\x9f\x96\xd3\x09\x5b\xe7\xbe\xfd\x76\x34\xa3\x94\x15\xa8\x23\x2c\x26\xed\xfa\x6f\x3c\x92\x9b\x7a\x44\x19\x1d\x92\x83\x05\x48\x04\x32\x8c\xf6\x3b\x55\xde\xc6\xfe\xd8\xc3\x13\x13\x4a\xff\x84\xc7\x0f\x58\xbb\xfe\x29\x9a\xdb\xaf\xeb\xaa\x76\x4c\xaa\xda\xc2\xdf\x9a\x69\xe3\xb1\xa6\x4b\x23\x1c\xce\x7a\x95\x77\x40\xb6\x3c\xfa\xcc\x0e\x2c\xf7\x19\xb4\x4a\x5e\xd9\xc7\x73\x19\xc7\xf4\x31\xbf\x49\x0e\xe7\x9a\x8f\xb7\x83\x73\xff\x6f\x7f\x00\x4c\x0e\xe7\x5a\x1e\xe2\xe4\xb1\x03\x7f\x80\x1b\x4c\x8a\x62\xd2\x33\x37\xa5\x02\xc1\xcf\x0f\x2c\x3b\x37\x1c\x25\xa4\x00\x57\x11\x48\x26\x9a\x61\x6a\xd0\x78\x47\x57\x59\x9b\xe3\xb6\x64\x83\x29\xd2\xfc\x6a\xa2\x63\x7d\xc1\x76\xf8\xc4\x0e\xe0\xa2\x3a\xa7\x2f\x81\x4f\x34\x3b\x34\x17\x7e\x32\x57\x69\xe7\x55\x5d\xf5\x46\x0e\x3d\xcd\x40\xf6\x38\x75\xe7\xcd\xfa\xd7\x3c\xe0\x01\xbb\x9e\x95\xa9\xca\xe2\xea\x6d\xc5\x4c\x77\x46\x79\x2c\x69\xb3\x91\x30\xb7\x96\x7f\xf8\xa5\x5a\x9e\xba\xe5\x4f\x94\x2a\x3d\xc3\x57\x94\x58\x39\xb7\x51\x69\x63\x53\xf2\xe6\x5a\xc5\x39\x28\x5b\x0c\x91\x6e\x61\x20\xe3\xf8\x50\x0d\x38\x15\x3e\x32\x65\xd1\x95\xe2\xdc\xc4\x80\xfb\x14\x81\x59\x7f\xdd\x83\xb7\xa0\x57\xff\x44\x1e\x26\xfe\xd5\xf0\x56\xb6\x76\xfd\x51\xf9\x09\xb4\xcd\xda\xfe\xef\xbf\xef\xa7\x23\x01\x9b\x84\x7f\x03\x98\xb1\xd3\x83\x40\xd1\x53\xbe\x19\x37\xe7\x45\xb1\x3e\x99\x62\x26\x6e\x9d\x0b\xf7\x49\xe9\xdc\xf4\x4d\xf4\x9c\x8a\x3d\xae\x13\xaf\x26\x17\x84\xec\x05\x1a\xdc\x82\x99\xb5\x2e\xa8\xe1\x58\xdf\x29\x51\x82\x72\xe2\x33\xac\xc5\xc5\x12\x1a\xa5\x27\xfc\x55\x7c\x99\xfe\x12\x06\xba\x4f\x44\x9b\xe1\x4e\xa5\xf7\x26\x3e\xb7\xbc\x9b\x81\x33\xf5\xdb\x1f\x0a\xa8\x84\x66\xb1\xbf\x3a\xef\x6a\x38\xe7\x40\x0d\xa2\x2d\x2f\x47\x7f\xb7\xae\x83\xda\x4d\xeb\xa3\x47\x5d\xca\x4b\xcb\x12\xb5\xaa\xeb\xc2\x47\x7a\xc5\xaf\x07\x4e\x9a\x8d\x93\xc6\x90\x60\x4a\xd2\x6e\x8a\x5c\x23\x40\x82\x0d\x77\x31\x12\x25\x6f\xae\x0b\x98\xcd\x0a\xbf\x9e\xff\x7c\xf8\x28\x21\xb2\x40\x3b\xbc\x94\x0f\xfe\xd2\xfe\xf8\x68\x0b\xd6\x4f\xeb\x7e\xe1\x03\x80\x3a\x79\x98\x9f\x8c\xdc\x83\x3d\xfe\x13\x4c\x04\x8e\x61\x8a\x2c\xa5\x01\xfe\xe1\xec\xf7\xd0\x70\xb1\x64\x2b\xb1\x6f\xcc\x3b\x04\xc3\x90\x70\xde\xc9\x31\x82\xd0\x33\x56\xd3\x7f\xbd\xc8\xb3\x84\xb9\xed\x96\xb7\x91\x77\x92\x2d\xec\xf0\x03\xdd\xb1\x90\xbc\x03\x61\x06\x97\xcc\xaf\xfe\x6d\x9a\x01\x3f\xe5\x57\xaa\xbf\x05\x03\xc0\xf6\x46\xc2\x2f\x5e\x04\x2e\x37\xa4\x85\x19\x92\x30\x78\x7c\x9b\x1f\x08\x92\x04\xaa\xa3\x69\x38\x46\xae\xf7\x7a\x35\xd8\xe5\x00\xe6\x3b\xd9\x81\x4c\x5f\x8e\xdf\x4c\x31\xf4\xdc\x07\xc2\x1b\xe3\x6e\x31\x39\x48\xc1\x2f\x59\xbc\xa6\xeb\xca\x2c\x94\x5f\xcf\xec\x47\x53\x58\x81\x08\xe4\x53\x9c\xc8\x1d\x3e\x50\x4b\x62\x35\x6d\x41\x44\x07\x05\x5b\x82\xd4\xb2\x1a\x6d\xf0\xfb\xb3\xa9\xcc\x6e\x25\xf5\xdd\xd7\x33\xc2\xcc\xfc\x33\x46\xda\xb9\x81\xfc\x63\x46\x73\x5e\x95\xf6\xcf\x2b\xdb\xba\x84\x9d\x68\xfe\xc7\x94\x0b\xf9\x7f\x2c\x9d\xb5\xd6\xb4\xcc\x12\x85\x2f\x88\x00\xb7\x10\x67\x70\xb7\x0c\x77\x77\xae\xfe\xac\xf7\xfb\xcf\x24\x93\x0c\x2c\x56\x4f\x57\xed\x67\x37\xd5\xd5\xfe\x20\x3b\xd4\x6b\xbd\x6f\xcc\xd5\x25\x3f\xd2\xce\x35\x33\x70\x64\x43\xc7\x2f\x35\x18\x0f\x9b\xc2\x66\x76\xb9\x66\x17\x40\x4e\x12\x64\x72\x2d\xe4\x00\x36\x52\xae\x5e\xd3\x71\x49\x09\xba\x94\x38\xe1\x0f\x34\xdf\x2f\x6f\x9c\x19\xc9\xac\xc9\xd6\xcf\x11\x6f\xe3\x50\x74\x7c\x85\xdd\x43\xd5\xdd\xb7\x10\x5e\x38\x6f\x48\xa9\xdc\xc2\x38\xb6\x21\x95\x3a\x84\xe3\x07\xb1\x5f\x84\x74\x8e\x96\xc0\xda\xbc\xc6\x0b\xe6\x38\x99\xa9\x32\x10\x8c\x8a\x8d\x4c\x93\x38\xff\xd7\x7d\x38\x45\xb2\xdb\xc0\xf3\x6f\xf2\xb4\xcc\x94\xa8\x0a\x0e\x5a\x1d\x86\x98\x73\x66\x37\x59\x71\x22\x6c\xfa\x2e\x15\x7e\x01\x46\xe7\xc3\x62\x6e\xea\xbc\xf1\x6f\xbd\x6a\xdf\x98\x87\x9e\x59\xb6\xab\x22\xb8\x31\x21\x6d\xc4\xcb\xa4\xbc\x26\x47\xe9\xb7\x8b\xc1\x40\xd1\x9c\x3e\xcc\x58\x81\xa9\x33\xe1\x38\x17\x63\xff\x57\xb7\xec\x90\x84\x21\x9a\x1d\x18\x75\x5a\x20\xb3\x36\xfe\x36\xbc\x4f\x79\xc9\xe4\x71\x5e\x30\x49\xc3\x08\x95\xab\x62\x1c\x1c\xea\x32\x48\xa6\xb0\x20\x05\x13\x73\xdc\xbe\x0c\xcc\xfc\xef\x37\xfb\x13\xb3\xc6\x71\x90\xa6\xc4\xb3\x0f\xf8\x52\x1d\x7f\xbb\xc2\xd1\xc4\xa1\x4c\xa1\x51\xc3\xdc\x5e\x72\x20\x6d\xbd\xa8\xa9\xf4\xb4\xca\xdd\xb5\xd5\x83\x85\x34\x17\x48\xab\x3f\x28\x36\x55\x5a\x3a\xd3\x35\x30\x23\x22\xc2\x30\x2b\x6d\x3c\xca\xde\x82\x38\x62\x25\xd6\x59\x68\x1c\x21\xbc\xbd\xba\xff\x6f\x5f\xf5\x20\x13\xc9\x83\xa8\x4f\xac\xe7\xed\x5b\xfc\x88\xa0\x9f\x3d\xaf\x42\xf1\xbd\x52\xa5\x3a\x16\x59\x14\xc5\xe9\xd8\x0b\xf8\x1a\xd2\xfb\xb2\x1d\xf5\xae\xc5\x0e\xd5\x16\x7c\xd8\x88\x02\xd9\x63\xef\x9f\x1e\x4b\x75\xcb\xdd\x96\x0c\x02\x95\x49\xee\xa6\x6d\x11\x67\x8e\x54\x26\x00\xde\xb3\x6f\x3c\x09\x45\x97\xd7\x64\xe3\x66\x3b\xaf\x84\xde\x3a\x89\x7f\x86\xfc\x79\x83\x3f\x83\x01\x31\x2b\x3e\x26\x11\x9b\x59\x37\x31\xc6\xe2\xc5\xdd\xa7\x88\xbd\xa2\x86\xaf\x43\x1d\x56\xe8\x88\x6c\x3e\x6c\x7c\xb6\x76\xe4\x59\x74\x1c\xf8\x8f\x97\x8d\x26\xa1\x7a\xac\xa6\x62\xab\x1e\x18\xdf\x2d\x3d\x99\x2c\xd1\xc3\x74\x6e\x73\xe6\xf8\x60\xfd\x7e\x8e\x99\x6d\x4a\x75\xc5\xbb\xfe\xe9\x9e\x2f\xf3\xb3\xce\xdd\xa5\xf8\x9a\xb7\xff\xcd\x1a\x77\x5f\x17\xaa\x66\x88\x80\x3b\x9a\xf1\x14\xcc\x91\x9f\x91\x36\x04\x41\x10\x4a\xb1\x9b\x54\x39\x6a\x7c\x72\xf7\x10\x0d\x8f\x7b\x3c\x4c\x53\xd5\xae\xf9\xb3\xed\x30\x89\xe4\xf4\x2e\xf1\x62\xab\xc0\x34\xa6\xcc\xef\xe6\x0a\x4c\x03\x69\xc3\x99\x8f\x51\x75\xab\x3c\x5e\x18\x4c\x38\x4c\x68\x62\xff\x16\xfa\x25\x5b\x24\xbd\x51\xc3\xd4\xdb\xad\x5f\xa9\x5b\x00\x5a\xe3\xc7\x4c\x37\x45\x81\xe6\xd7\x67\x9e\xa2\xbf\x6e\xe2\x5f\x01\x6c\xd8\x0c\x1b\x50\xa3\x52\x44\x21\xbc\xaf\x92\x99\xa2\xd9\x21\x0a\x3c\x99\xb3\x38\xbd\xdf\x89\x3c\x03\xb2\xef\x17\xdc\xbf\x16\x1c\xac\xd1\x7e\x03\xf4\x58\x18\x56\x0b\xfb\x68\xed\xf4\xb0\x97\x34\xdb\x9c\x56\xd5\x62\xc4\x54\x22\x6c\xe9\x08\x08\xbf\x19\x62\xbf\xc3\x3b\xcf\xd6\x34\x1b\x50\x85\x44\x7a\x0f\x15\x88\x4e\xc0\xdc\x6e\xab\x06\xd0\x4b\x9e\x5a\xcd\x24\x2b\xb7\xae\xeb\x66\x3e\xba\xd3\x8e\xc2\x18\xf9\x6f\x61\xb5\xbd\xdd\xd2\x3f\xf1\x1d\x95\x31\xa1\xcb\x2e\x11\xe0\xf8\x23\x2c\xc6\x79\xa3\x0f\xe3\x80\xca\xc2\x81\x6a\x62\xee\x75\x5d\xd3\xdd\xca\x1f\xc0\xf4\x63\xa1\xe6\x58\x07\x3f\xb3\x09\x88\x51\x28\xb3\xda\x7d\x50\xbc\x1e\xbf\x8d\xea\xa2\x57\x38\x4b\x15\xa8\x87\x0a\xcf\x9f\x2c\x8d\xcc\x30\x8e\xfb\xd3\xfe\x37\xa5\xcb\x37\x8e\x71\x83\xdd\x0c\x2e\xf3\x44\x77\xf8\x0b\x0f\x5b\x18\x16\xce\xeb\x33\x63\xfa\x9a\x7f\xc7\x85\xa8\x52\x33\x27\x63\x72\x66\x33\x29\xfc\xec\xa5\xd2\x93\x91\x89\x6c\x50\xfe\xe3\xaf\x39\x52\x4b\xab\x57\x90\x17\x3a\x7e\x19\xfc\x4a\x24\x32\x45\x1b\x3a\xc0\xbc\x7d\x9b\x86\xe8\x50\x39\x5f\x17\xc8\x5d\x91\x9d\x83\x51\x73\x14\x10\xfd\xba\xc6\x12\x42\x81\xd3\x63\xc9\x9d\x29\xb0\x5c\xbb\xb8\xe1\x70\xfe\x36\xee\xdc\x5a\xf9\x61\x18\x04\x21\x49\xba\xbc\x22\xfe\x8d\xdc\xdd\xc4\xe7\x94\x6d\x77\x4c\x6f\x9c\x1f\x08\x5c\x57\xb5\xeb\xed\xab\x24\xd8\xed\x03\xfa\xfd\x34\x31\xd3\x72\x4c\xab\xba\xf3\xdd\xfb\x62\x7e\x3b\xc2\xdb\x72\x82\xc3\x88\x9d\x74\x99\x66\x59\xee\x27\x11\xc3\x0a\x74\xcf\xf3\x8f\x3b\x4d\x57\x5f\xd7\x1f\xa7\xd6\x5c\xe3\xb0\xae\x6d\xf1\xb2\x5c\x57\x27\x9b\x93\x30\x8e\x16\x4e\xb0\x95\xdb\x42\x82\x1b\x65\xe1\xdf\x64\x99\x41\x57\x80\x41\x62\x14\x68\x00\x07\x19\xb4\xaa\xed\x32\x0b\x35\xcb\xac\x7b\x0e\x14\x95\xea\x4f\x00\x72\x0f\x89\xeb\x6b\xe2\x7a\xf7\x02\x94\x15\x3c\xcf\xfd\xf8\x1c\xfd\x21\x46\x57\xd7\x91\xf4\xec\xe9\xab\x74\x2d\x3d\x45\xa7\xa7\x55\x2c\x74\x73\xe3\x9b\x66\x5e\x0d\x43\x7d\x2f\x9c\x4a\x86\x5b\xd1\xda\x85\xdf\xc4\xb0\xb7\x59\x94\x56\x27\xdb\xc3\x25\x36\x09\x04\xd6\x5a\x08\xdc\xbc\x11\xd9\x04\xe8\xc9\x99\x22\x77\xca\xe7\xef\x6c\x47\xb0\x1c\xf7\x83\x39\xf8\xc8\x02\x1d\xc4\x1b\xf9\x58\xcf\x62\x4a\x60\xc3\x38\x7a\x02\x54\x3c\x66\x07\xaa\x9b\x90\xec\x53\x45\xf6\x0d\x1b\xce\x4b\xee\x8e\x37\x30\xd6\xa9\xaa\x2a\x53\xce\x34\xb2\x53\xc7\x75\xad\xb1\x4a\xb7\xb5\x83\xb1\xd9\x5f\x98\x19\xc4\x97\x17\xc4\xe2\xaa\xbe\xcb\xb9\x5b\x40\xe0\xaa\xd7\xe3\x12\xcf\x4d\x3c\x06\x0a\x94\xe5\x41\x8a\xb8\xb7\x29\x50\xea\x39\xbf\x97\x8b\x7d\xe7\xc7\x3c\x9c\x3b\x6e\x46\x43\x1c\xc4\x2d\x1a\xbb\x72\x13\x06\x43\x92\x08\xc7\x0e\x83\x20\x58\xd7\x3b\xf3\x2b\x5f\x2a\x12\x3c\xe1\x31\x5f\xf7\x4b\xd5\x76\x9e\xcf\xdf\xae\xc7\x90\x78\xfc\x38\xbd\x1f\xd3\xb1\x99\x11\x15\xa7\x4b\xc8\x09\x90\xf9\x35\xba\x12\x51\xc8\xba\x80\x4d\xf7\xcd\x21\x6f\xcf\xe8\xb3\x4b\x7a\xe0\xa6\x3e\xd7\x94\x3b\x84\x51\x4f\xff\xf6\xc5\xa7\xac\x4c\x74\x0f\xf3\x90\x81\x2c\x94\x06\xf7\x3a\x04\x4a\x4b\x68\x95\x36\x91\xd6\xb3\xa0\xb0\xab\x56\xf6\x3a\x24\x4a\xb4\xb5\x51\xbb\xd6\x18\xd3\x4b\x66\xac\x91\x2f\xfc\x77\x2c\xdb\x4b\x55\x16\x9a\x16\x76\xdd\x0d\xd5\x06\x11\xd0\x7e\x1f\xf0\x20\x39\x6d\xb2\xfd\x56\xb3\x9e\x0d\x3e\x43\x92\x61\x1f\xfd\xd2\x92\x39\x68\x51\x7d\x69\x9b\xb1\xe9\xa5\x2e\x95\x07\x6e\xc0\xd6\x0a\x8b\xbb\x77\x2d\x47\xd9\xf7\x61\x4b\xd6\x36\x3a\xd2\xc4\x22\xee\x87\x12\x8f\xc5\xda\x4e\x7d\xd9\xa0\x0d\x5f\xc6\xf4\xfd\x39\xee\xba\x0e\x5b\xfd\xcd\x07\x4e\xca\x96\xcc\x9c\x57\xb3\x1b\xbb\xe4\xd2\xbb\x38\x4d\xc7\x61\x45\xc9\x03\x52\xc4\xab\x6e\x74\xdc\x5a\x10\xf2\xf7\xc1\x86\xd0\x39\x20\x27\xdd\xa8\x7b\x90\xe2\x0a\x67\x87\x29\x65\xca\xe0\x4e\xfe\xaf\x94\x9d\x40\x2c\xc6\xb5\xec\x17\xd5\x85\xdf\xe6\x3a\x18\x9b\xf9\x99\x11\xb6\x07\x00\xcd\x52\x29\x58\x4d\x28\x88\x4e\xb0\xd0\xef\xeb\xb9\xfa\x56\x76\xac\x8e\x0a\x80\x5d\xc3\xe0\x27\x07\x11\x34\x68\x91\x3f\x51\x6c\xfc\x50\xee\x06\x4a\x52\x11\x53\xe9\x89\x82\xd7\x3b\xe3\x73\xa3\x22\xe9\x58\x5c\x36\x59\x70\x65\xf7\x8a\x84\x02\xc2\x22\x3e\x6b\xfa\x28\x79\xea\x10\x59\xad\x1d\xe2\xb7\xed\x71\x97\x83\xd3\x79\x63\x69\xab\x36\xee\x0c\x55\x96\x3c\x7a\x68\x69\xd3\x63\x29\xab\x59\x9d\x7a\x19\xba\x09\x9d\x43\x6d\xea\x7b\xf0\xee\xaa\xfc\xf1\x0b\x0c\xc9\xfd\x18\x22\x3a\x1f\xa1\x18\xbd\xd7\x31\xd5\xfd\x1e\xdd\x15\x56\x07\x3a\xf6\x42\xc9\x70\x01\xbf\xf5\x40\x74\xa0\x5c\xfe\x6c\x86\x69\xf5\x4e\xff\x7e\xaf\xf1\xcb\x78\x9a\xd6\x7d\x5b\x93\xce\x71\x10\x8c\x8c\x85\x15\x71\x48\xca\x48\x78\xe8\x7b\x50\x85\x50\x0b\xce\x74\x4c\x46\x47\xab\x2c\xea\xcc\x39\x9d\x96\x5d\xc8\x5c\x26\xed\xcd\x7b\xc5\x14\x7a\x6c\xb6\xcf\xea\x03\xc0\x4b\xaf\xb9\x87\x4d\x1b\x1e\xad\x5a\xac\x8d\x47\xe5\xb4\xa3\xa6\x71\xf6\xa9\x6b\xa8\xa8\xf5\xdd\xd9\x49\xb9\xec\xde\x35\xee\x44\xab\x53\xe0\xde\x3b\x44\x8b\x1e\x5f\x6d\x93\x4a\x29\x67\x83\x09\xba\x5c\x4e\xff\x31\x5e\xe6\x90\xd0\x68\x1b\x27\x6f\xa9\x6d\xed\xd3\x2f\xcd\x44\xbd\xfa\x27\xce\xe9\x10\x25\x27\x4a\xc9\x73\x15\x91\x35\x07\x15\xb2\x43\x1f\xe3\x97\xb7\x61\x59\x7d\xb3\x1e\x8e\x79\xba\xab\x99\x01\x8b\xd6\xf4\xfc\x76\x5f\x10\xd9\x3b\xac\xf4\x54\xb3\x59\x86\x63\x06\xec\x14\xf9\xdf\x19\x08\x56\x84\xa8\x49\x0e\xfb\xfb\x96\x22\xca\xd0\xa4\xd5\x80\x01\x23\xf6\xfb\x0a\xab\xbe\xf7\x3a\x08\x83\x20\x38\x50\x8d\x61\x37\x9f\x1c\x8f\x91\x2c\xed\xe9\xe5\xfc\x2a\x2f\x2d\x8f\x3f\x18\x93\xd1\xe4\xc5\x97\x73\xd4\x1f\x2c\x66\x70\x14\xf6\x57\x00\xb2\x0e\xa6\x8d\x3c\x2b\xdd\xbd\x6f\xea\xba\xb6\x23\xc7\xd6\x34\x5a\x08\x81\xbf\x96\x51\x83\x51\x72\xdd\x67\x18\xcd\x8a\x98\x1a\xcb\x0e\xd7\x96\x14\x7e\x9b\xca\xf3\x25\x14\x00\x54\x60\x5e\x6a\x31\x94\x76\xaf\xde\x91\xf4\x0b\x74\x5e\x7b\x37\x0d\xb8\xa8\xa5\x87\x92\x07\x36\x8c\x90\xfa\xf1\x97\xac\x60\x24\x4c\xd0\xc8\xe6\x2e\x4c\x9f\x32\x0c\x67\x0b\x4d\x9e\xb9\x84\x9b\xaf\xeb\xbc\x12\x2e\x2a\xd4\x11\xd5\x02\xef\x3d\xab\x48\x15\xcc\x7b\x06\x30\x77\xfc\x6b\x7c\xf5\x4d\x3c\x42\xab\x9a\xb8\x14\xe7\x54\x52\x20\x03\x25\xe9\x17\xaf\x00\xaa\xa4\x42\x55\xee\x9c\xd6\x44\x18\x85\xb2\xcb\x09\x3b\x7f\xe7\xf6\x6f\x1d\xf8\xe8\xdf\x1a\x33\x39\xa1\xd1\x3d\x3f\x91\xf5\x20\x58\x52\xb5\x49\xb5\x30\x4a\x9c\x01\xfa\x9d\xfd\x79\x73\xbf\x4e\x9f\x70\x67\xce\x24\xcd\x41\x0b\xce\x89\x31\x2d\xdc\x02\xe8\xd0\x5c\xbc\xcf\x04\xa3\x60\x19\x6a\x18\x89\xf4\x3d\xb7\x83\x78\x53\xc7\x48\xa5\xda\x5f\xd5\x76\x45\xb2\x62\x54\x4d\x8d\x55\x60\x84\x2c\xbe\x5f\x33\xfa\xeb\xba\xac\xae\x00\x34\xde\x4d\x6b\x25\x5a\xa2\xd9\x2e\x70\x80\xf3\x9e\xa9\x41\x57\x81\x4c\x32\x02\x63\xdf\x3e\x08\x8f\x4e\x9f\xb4\x5c\x31\x48\x63\xb3\x09\xef\x7b\x74\x22\x72\xcd\xb5\xca\xc6\x3f\x6e\xe3\x40\xb1\x05\xe9\x0e\x2f\x21\xdc\xe4\x8f\xb5\xf4\x58\x3b\x12\x43\xb4\xb8\x7e\x01\xb6\x07\x49\x18\x4c\x09\x52\xd4\xf5\x75\xb3\xa5\xdf\xcd\xf4\x96\x4a\x1b\x42\x18\x23\x9f\x29\xbd\xdb\x86\xde\xf7\xcc\x08\x7c\x64\xe1\xec\xde\x99\xf2\xed\x18\x50\x9d\x5f\xbc\x58\x82\x77\x4e\xd5\x82\xac\x07\xd9\xe1\x64\x71\x4e\xd5\x01\xcb\x13\xd6\xab\x52\x66\x8c\x2f\x55\x80\xc5\xe9\xf9\x90\x31\x13\xd4\xf9\xc7\x6c\x35\x52\x47\x48\x88\xdc\x12\x3d\xeb\xb4\xf7\x4a\xa5\xc2\xef\x65\x52\x06\x60\x14\x0d\xdc\x64\x76\x73\x4a\x9c\x64\xb7\xda\x14\xa3\xd6\xe2\x4b\x97\x13\x7f\x90\x62\x0b\x1b\xc8\x95\x9d\xe8\x62\xb2\x03\x9a\x85\x54\x15\x7d\x4a\x70\xfd\xeb\xd5\x63\xa1\x28\xe5\x6a\x3c\xd3\xbf\x85\xd9\x4f\x48\x5a\x00\x9b\xff\xe6\x1a\xc7\x0c\xbe\xc5\x30\xce\x1f\x14\x38\x6a\xbf\xf8\x1d\x0f\x81\x6b\x6a\xee\x9b\xf0\xde\x87\xa5\xbd\xf9\x92\x89\x09\xe0\xfd\xfa\xe8\x06\x26\xe4\x4d\x9e\x3c\x12\x57\xb8\x3c\xed\xe3\xf4\xda\x28\xd8\x60\x68\xe8\x06\xf0\x75\xa2\x85\xf8\x69\x39\x5f\x51\x6e\x0d\x4c\xc7\x51\x53\xc7\x21\x5c\x32\x09\x03\x83\xc3\x30\xe6\xea\x0a\x91\xfa\xee\x78\x7e\x45\xde\xd2\xef\xd6\x09\x58\xd1\xd1\xc5\xa3\x0a\x14\x42\xbe\xaa\xef\xe5\x41\xb4\xc1\xd7\xb3\x1e\x7d\xca\x0e\x66\x7a\x67\xef\x22\x23\x69\x00\xa3\x72\x6e\x9a\xcc\x73\x65\xe1\x8f\x5e\x0d\x98\x5d\x41\xd9\xa0\x89\x30\x5c\x44\xf1\x4f\x64\xeb\x5c\xd4\xbf\xb9\x9e\x0e\xbc\x4c\xac\x32\xc7\x22\x06\x03\xc0\x6c\x77\xf2\x5f\xb5\x46\xdb\x03\x5a\x13\x7e\x0b\xbc\x50\x47\x30\x61\x7e\x7b\x26\x35\xb3\xab\x69\x1c\x71\x5e\x5b\xdf\x3a\x66\xef\x5e\x17\x05\x54\x56\x70\x81\x58\x5b\x52\x43\xe7\xca\x94\xcb\x30\x0c\x1e\xc0\x41\xe0\x44\xcc\x17\x81\xa9\xb1\x17\x4a\x52\x44\x3e\x7c\x17\x0a\x66\x31\x61\xf8\xe4\x65\xed\x26\x3a\x50\x55\xbb\xad\x7d\x31\xa1\xd6\x6b\xa7\x1d\xb6\x76\x45\xae\x42\xfe\x54\xca\xec\x21\x9d\xaf\x2e\x98\xc4\xc0\x9b\xb9\x1e\xb0\xbb\x4d\xb5\xa3\x2b\x69\x8e\x91\x60\x70\xa2\x27\xae\x41\xea\xf4\xa8\x41\xb1\xa3\xc0\x0d\x4b\xf8\xc8\x22\xb9\x7b\xa0\xcc\x9a\xbc\x98\x0e\xaf\xe8\xa2\x81\x09\x48\xb8\xe4\x0c\x49\x63\xac\xa3\x0f\x5f\x42\x7f\xe0\xf9\x53\xaf\x77\x95\xdb\x6b\xe0\xd6\x16\x84\x20\x12\xa3\x60\xfa\x06\x94\xd9\x6a\x2c\x73\xa4\xe4\x79\x96\x39\x00\xb0\x7c\x72\x4f\xa0\xac\xbc\xe6\x9d\x05\x9a\x3d\x8c\x59\xf9\x97\xba\xb4\xe1\xc5\x53\xaf\xca\x47\x56\x83\xec\x16\x4a\xe7\x40\xc5\x47\xe0\x57\x97\x40\x11\xeb\xed\xb4\xf6\xaf\xc5\xbd\x39\x6c\xbe\x3d\x74\x4b\xd3\xcb\x65\x4d\x6a\x20\xa3\x97\x1f\xe1\x16\xf0\xd7\x5f\xbc\x20\xf1\x9b\xbe\x3a\xad\x10\xf6\x11\x59\xfb\xa8\x8f\xfb\xbc\xbe\xe7\xad\xf5\x29\x50\xc9\xa0\x88\x6b\xce\x6d\x26\x34\x50\x5e\x99\x24\x14\x27\x22\xcb\xa0\x8c\x90\xc5\x75\x84\x64\xa1\xcc\x80\xfd\x5c\xa3\xd9\x43\xfe\x8f\x19\x2d\x44\x72\x2a\xa8\x71\x30\xa8\xf4\xb2\x4f\x7f\xf7\x4d\x15\xf3\x33\xec\x51\x28\x61\x30\x55\x6d\xe7\x75\xf4\x92\x91\xc8\x28\xb0\x94\x71\x3a\xcb\x4b\xf0\xbc\x22\x11\x00\xf7\x40\x74\xf2\x97\x80\x2e\xde\xd6\x35\x95\xaf\xf2\x4e\x57\x7d\x93\x67\xb7\xd3\x89\x92\x3b\x16\x76\x6f\xd7\x14\x04\x00\x2f\x3c\xd7\x96\x62\x1f\x43\xb0\xc5\x50\xb0\xda\x1d\xd3\xf0\x9c\x25\xdc\x82\x46\xc9\x4d\x1f\x83\x7e\x88\xb6\xbe\x57\x62\xb8\x44\x30\x24\x81\x80\xcf\x7e\x20\x3e\x45\xc5\x33\x7d\x53\x92\x62\x57\xe9\x65\xfd\xd4\x12\xb3\xb1\xab\xd2\x48\xec\xd2\xc4\xa1\xc8\x71\xc3\xf0\x4a\x58\xae\xc0\x8c\xb3\x73\xb4\xe0\xec\x99\x74\x45\x1b\xaa\x0c\xf8\x5e\x44\x11\xdc\xcf\xa1\x46\x5d\xd6\x0b\x31\xf5\xf2\x63\x55\x45\xdc\xf1\xea\xf7\x43\x60\xf5\x5f\x3d\x3a\x71\x6e\x73\x7d\xdf\x62\xd1\xeb\x3c\x59\x22\xe4\x88\xd6\xb1\xc0\x52\xa1\xea\x09\x8d\x39\xf4\x99\xcf\xb8\xa2\x63\xf4\x2b\x68\x11\x7f\x41\xaf\x80\x74\x43\x8c\xcb\x1a\x19\xe3\x97\x12\xfb\x26\x79\xf6\x13\x10\x94\xcb\xff\xbe\x05\x92\x3c\xe5\x84\x8a\x3e\x19\xbc\xa4\x99\xe1\xf4\x70\x97\xfc\x2d\x39\xb6\x20\x80\x22\xb9\x9c\x0d\x02\xc2\x61\x49\x8a\x13\xf5\x87\xe8\xfc\xf0\x5b\xe7\xb3\x03\x21\x9a\x2b\x11\x82\xdc\xd2\xfa\xfb\xce\x2d\x81\xc9\x43\x0c\xb4\x70\xb4\x23\x3a\x8e\x07\xb9\xba\x37\x00\x30\xb3\x20\x20\x67\x99\x7a\xd8\xc3\x9c\xaf\xf3\xf4\x39\xb6\xe5\xc6\x0a\xdf\xd4\x19\x5b\x2a\x2b\x6b\x82\x39\x81\xeb\x3e\xe2\xf0\xb7\x7a\x0d\x16\x82\x64\xbf\xb5\x24\x31\xae\x34\x15\x12\xd2\x4c\x2c\x62\xdf\x1c\xd5\x23\x2d\x78\x7f\x70\x02\xba\xc1\x70\x64\x27\xa2\x25\x54\x0d\x24\x63\xf1\x9b\x2b\xf3\xc5\x76\x7b\x56\xb9\xba\x7e\xff\x3f\x0e\x26\x06\x4a\x94\x33\x0d\xda\x0c\x38\xff\xf6\xb5\x9f\xd1\x2d\x0e\xfe\xbc\x09\x36\x55\x79\xcb\x7c\xcf\x05\x5e\x3c\x4b\x7e\x45\x0f\x46\x96\x8b\xbd\x88\xe0\x05\xbd\x81\xf9\x7e\x1f\xdb\xe3\x8b\x8d\x77\xaf\xc8\x73\x4a\x12\x06\x81\x1f\x14\xed\xe8\x43\xb6\x90\x18\x88\xc4\x19\x46\xd6\x6e\x01\x42\xe3\x27\x9a\x1d\x48\x73\x2d\xfc\x6b\x76\xc6\x8b\x26\x2f\xd8\xde\xf2\xca\xa3\x05\x94\x19\x52\xc3\xec\x3a\xf7\xee\xdb\xef\x4b\x28\x92\x72\xeb\x3e\x10\x9d\x90\xc5\xef\xe6\x2a\x3d\x50\x82\x9f\x02\xe6\x6d\x06\xa2\x5f\x0c\x97\x7c\xa9\xde\x16\xf0\x53\x15\xa5\x4e\x63\x28\x35\x42\x65\x18\x7e\xaf\xde\xe5\xd3\x29\x56\x83\x98\x09\xdf\x3e\x0e\xe1\x06\xd9\xc4\x90\x5e\x57\x98\xc5\x54\xfb\x5b\x1d\x67\xdf\x46\x11\xc8\x59\xb6\x7e\xd8\xa6\x96\x01\xf7\x4b\x12\x3e\x9b\x75\x99\x00\xa6\xcd\x25\xac\xde\x73\x76\xa4\xb7\x90\x92\xd7\xc0\x16\x35\xc6\x8f\x02\x2a\x53\xc0\x2e\xf1\x82\xb5\x1f\x11\xb3\x1e\x52\x4c\x49\xa7\x75\x65\x2f\x71\x2e\xe7\x74\x78\x65\xe1\x4c\x62\xa6\xbe\xe1\xe7\x93\x82\xe9\xa3\xe7\xd7\x88\x70\x68\x19\x3f\xf0\x3a\x74\xa8\xef\xf1\x59\x38\x9c\x2c\xed\x1e\x75\x27\xc9\x0f\xf1\xe6\x0f\x42\x3a\x6e\x2b\xb4\x07\x9a\x22\xb8\x51\x67\xeb\xb4\xea\xee\x5b\x07\x7a\xaf\x22\x5e\x63\x93\xf3\xdf\x92\x86\x03\x5d\x91\x93\x08\x19\x5c\x3b\xb7\x67\xdf\x09\xaf\x71\x92\xce\xfe\x56\xab\x54\xb3\x33\x79\x59\xd3\x07\x3d\x78\x1c\x4a\xc4\x64\x3e\x7b\x3d\x1c\x75\x8a\x0c\xcb\xdf\x7d\xf6\x2f\x08\xb1\xb7\x30\x05\x66\x15\xa1\xb6\xc3\x91\x23\xdc\x00\xb0\xa2\xdb\x22\x9e\x95\xb4\xb0\x26\x6f\xae\x24\xae\x1d\xee\xb5\xb2\x46\x41\xa4\x6e\xe8\x66\x8a\x85\x37\x00\xad\x6d\xe7\x53\xfb\x9b\x3b\x83\x1f\x29\xa2\x93\x47\x94\x19\x99\xcf\x2d\xa0\x63\x3a\x2e\xeb\x1f\x17\xed\xa3\x95\xd1\x03\x55\xcd\x6f\x7f\x69\x24\xf8\x6b\x38\x59\x04\xb5\x97\x62\xc1\xea\x12\xde\xf7\x76\xe9\xf2\x44\xba\x99\x48\x85\xfd\xc5\x21\x1c\xe2\xc0\xf6\x5f\x4f\x41\x6b\xda\x04\xe2\xc7\xea\x23\xef\x28\xd2\xba\xc3\x3b\x69\xbe\xf8\x4e\x24\x2d\xe8\x84\x17\x3a\x77\xef\x0e\x54\x56\xa4\x87\x02\xae\x67\x36\x08\xe9\xb2\x97\xea\xa4\x7a\x5e\x2e\x67\xab\xe7\xc4\x35\xd5\x45\x87\xbf\x45\xca\xf9\xae\x11\xe9\x5a\xa1\x9d\x19\x94\xc2\xe7\x66\x74\x46\xf3\x4c\xb4\xd1\x85\xc8\x6e\x5a\x89\x3f\xf3\x40\xff\xf4\x27\x93\xdd\xfe\xd0\x5a\xb4\x46\xc8\x17\x30\xe5\x6e\x78\xad\x8b\xa1\xa4\xd6\x79\x60\x02\x2f\xd1\x0a\x95\xb5\xb6\x0f\xc8\xc3\x6d\x6a\xc2\xf4\x04\xec\xa7\x53\x2a\xdd\x0f\x9b\x16\x3e\x45\x14\x78\xfc\x62\xcd\xe0\x47\x81\x46\xff\x25\x4d\x1c\x89\x84\x81\x24\x69\x88\xad\x52\x87\x74\x4a\x1f\x7d\x8d\x41\x46\x07\x01\x16\x18\x08\x04\x0f\x94\x4a\xfd\x8c\xe9\x44\x2e\xeb\x93\xe5\xde\x3d\x87\xda\xf1\xaa\xb6\xa3\x4b\xd2\xf1\x6d\xb6\xaa\xd4\x60\x09\xd7\xd8\x44\xe0\xe4\xd7\xb7\xc1\xf7\x35\x7e\x79\x25\xe0\xe8\xbc\x69\x2e\x52\x98\x11\x2a\x3d\x37\x55\x09\xcc\x86\xcf\x69\x3a\x1a\xe3\x87\xe5\x9a\x32\x4c\x1d\x4c\x2f\x13\x5e\xad\x2b\x09\xd0\x4e\x95\x10\x89\x41\x94\xd3\xcc\x47\x4c\x5a\x0f\xb5\xc4\x08\x29\x49\x17\x4e\xc0\xf6\x7c\xea\xb8\xac\xa3\x1b\x06\x42\x4b\xe9\x25\x3f\x5f\x9f\x77\x4b\x89\x1e\xb8\xf4\xec\x89\xad\xa2\x24\x0e\x13\x40\x74\xe7\xbc\xa3\xd5\x27\x59\x9e\x99\x31\xc2\xe1\xca\x45\x18\x0f\x78\x83\xe8\xe4\x45\x9a\x23\x76\xfd\xde\x5a\xf5\xcb\xe4\x37\x7f\x81\xc0\x1c\xbb\x27\x71\xe7\x70\x5a\x54\x4f\x1f\x3b\x89\xcf\xe4\x79\x06\x04\xf1\xc2\x4e\x43\xee\x40\x05\x07\xad\xfa\xb9\x3d\xad\x52\x32\xa0\x03\xef\xd2\x82\x7e\x67\xc4\x29\xc9\x18\x4b\x7c\x4d\x98\xed\x0f\xef\x6d\x39\x1c\x96\x14\x8d\x2e\xe8\x27\x36\x35\xae\x1a\xb2\x27\x02\xac\x89\x66\x94\xc9\x40\x06\x1f\x8e\x3e\xc8\xd7\x6f\x7e\x46\xaf\x18\x36\x30\x1d\xb0\x49\xe8\x0d\x28\x7c\xbe\xfd\x23\xb8\x82\x7d\x10\x3a\x6d\xfd\x7c\x8e\xb1\x05\x8e\xfa\xac\x8f\xa4\xfd\x0d\xfe\x3c\x05\x03\xaa\x9f\xf5\x84\x16\x35\x67\x40\xaa\x33\x35\x37\xb4\xf1\xa8\x95\x4a\xeb\x37\xfc\xa0\xc0\xb8\xc1\x36\xbd\xdf\x08\xbb\xce\x8f\x5a\xb2\x7e\x26\xf2\xa7\x59\xb3\x26\xb6\x88\x0f\xf5\xeb\x8e\x1c\x5b\xfa\xa7\xe1\x68\xf6\x3c\xcc\x8b\x78\xb0\x70\xb5\x7b\x1b\x68\x4b\x52\x91\xc5\xef\xbd\x36\x52\xf6\xad\x25\x66\x76\x86\xb5\x9a\xbd\x3a\x91\x15\xd9\x66\xdc\x84\x9c\x9a\xad\x2e\x74\xa6\x13\x3a\xdb\xdf\x7d\x51\x61\x5e\x0a\xec\x59\xe1\x95\x99\xa8\x7a\x25\x0c\x9c\xec\xeb\x2f\xe3\xc9\xcd\x01\xc4\x30\xaa\xfb\x75\x0f\x05\x0a\xed\x73\x0b\xbc\xf2\x41\xf3\x24\x0b\x0c\xc0\x2d\x7e\xdf\xf7\xf3\xc5\x7e\x06\x21\x46\x82\xc1\xc7\xf8\x03\xd1\x7b\xd7\xe6\x7c\x8d\x6e\x03\x5d\x9d\xe8\x6c\x84\x07\x6c\xad\xe9\xbb\x4f\x3c\x3d\x91\xf3\x1e\x69\x0f\xa3\x9a\xa9\xbb\xac\xde\x14\x4f\x15\x4b\xcc\xb0\xce\x2e\x28\x8e\x28\x79\x49\x9f\x68\xe1\xf9\xb0\xae\x4c\xb3\x19\x0e\x4d\xf6\x10\xf7\x8f\xe9\x15\x32\x45\x8e\x99\x07\x6e\xaa\xe6\x0f\xd5\x1b\x94\x46\xa8\x44\x6b\x84\x57\x38\xdb\x3f\xfc\xe4\x6b\xcc\x64\xe0\x27\x5f\x44\x17\x73\x38\x25\xd9\xc3\x0f\x8f\xe0\x0a\xb0\xaf\x8b\x72\x6c\xf0\x44\x61\xea\xce\x50\x3c\x08\x92\xd0\x7f\xbb\xfc\xd1\x2b\x19\xa6\x21\x33\x67\x32\x82\x57\xe8\x8b\xff\x70\x08\x8c\xa0\x41\x71\xfd\x55\xb4\x50\x10\xc9\xac\x4c\x0f\xcb\x68\xc0\xd3\x66\xe4\xe6\x4e\xc4\x06\x7f\x0b\x46\x32\xdd\x05\x51\x45\x5f\x5b\x6d\xcb\x8c\xfc\xb5\x84\x40\xc8\xcc\x34\x51\x54\xd5\xa8\x9e\x5b\x18\x2a\xe1\x39\xbb\x27\x3c\x26\xc7\xc6\xa9\xd4\x74\x0a\x2d\xe2\x52\x73\x63\x49\x12\x06\x87\xb6\x56\xfc\xbd\x6b\xcc\xdf\x23\x47\xf0\x91\xb6\x64\x85\xfc\xfe\x38\xa4\x8c\xac\xb1\x17\x11\x98\xa1\xbe\xd6\xc8\xd7\x2c\x93\xa8\xd5\x7c\xaf\xcd\xbd\xba\x61\x02\xe7\xe9\xc1\xa8\x42\x41\x0f\xe7\x86\x4a\x33\x96\x65\xd3\x60\xd8\x7a\xb1\x2b\x94\xc4\x0d\xc3\xb9\x9d\x2a\x10\x1d\x7f\x13\x5b\xa4\x33\x3f\x3f\xec\x60\x1a\xcc\x63\x89\xbd\x7e\xf6\xe5\xf4\x5f\xf2\x39\x33\x24\xb0\x6a\xe3\xef\x7d\xdf\x85\x5b\x70\x04\x17\xee\x4c\xfe\x19\x4d\xdd\xb3\xfe\x44\x8e\xf0\xd1\x33\xb1\x34\xdc\xc5\xf3\x4b\xa8\x53\x29\xb5\x19\x44\xf0\x24\x0c\x30\x8c\xf1\xcb\x60\xb9\x0b\xd4\xf2\x0c\x64\x07\x0a\x8c\xe9\x5b\x8f\x43\xb3\x7d\xc3\x85\x03\xdd\x13\x9e\xf9\x7b\x69\x70\x5b\x5e\x27\x5a\x65\x5f\xd4\x3d\xe8\xca\xde\x1c\x35\xbe\xdf\x83\x01\xca\x5f\x6c\xbc\x78\xd1\x2b\xa3\x97\x1d\xaf\xe2\xb5\xb2\xf5\x52\x08\x5d\x80\xf9\xb9\x3f\x54\x69\x19\x24\xd5\xd8\x07\x66\x49\x3d\xed\x70\x84\xdc\x10\x74\x7e\xd5\x0a\xd9\x57\xd4\xb4\x07\x35\x55\x52\x99\xfe\x2f\x26\x58\xef\xdd\x44\xa9\x73\x76\x77\x6a\x16\x08\xab\xae\x4f\xbe\x60\x81\x6e\x31\xc2\xac\x40\x24\x25\x04\xb3\x02\x35\x72\x65\x18\xc6\x0f\x35\x1a\x89\x5c\x82\x1e\x48\xe8\x85\xcd\xd4\x90\x60\xc3\xf5\xf7\x36\x44\xd2\x40\x13\xbf\x51\x99\xe6\x74\xc4\xd7\xdf\xd0\x12\x41\x54\xf5\xb0\xf1\xe5\x19\x2c\x41\x58\x6e\x61\x84\x14\xd6\x54\x63\xe7\xc2\x36\xb4\x48\x84\x6e\xff\xf5\xc9\x78\xf4\xd6\xa1\x27\xf5\x0e\x18\xad\x16\x41\xb1\xaf\xea\x14\x00\x27\x4c\xf2\x92\xe5\xb7\x81\x2f\x86\x18\xf5\xd2\xa3\xa4\xf6\x51\x07\x9f\xf8\x07\xff\xc7\x64\x64\x47\x23\x5e\x82\x61\x6d\xf9\x9d\xbf\x01\x6c\xf2\x6d\x22\xba\x2a\x58\x24\xcc\xbd\x5d\xcc\xfe\x72\x72\xee\xf4\xb7\xa2\x4f\xad\x25\xd6\xb5\x9d\x05\xee\xbe\x09\xfd\x27\x2e\x7b\xd9\x3b\xf1\x1e\x92\x0d\x56\x42\xed\x05\xfe\xe9\x1a\x05\x64\xfa\x16\x00\xa5\xcd\x0f\x8e\x2f\x32\x77\x59\xaa\x3d\x61\x36\x73\xc3\x28\x52\xf7\x0c\x46\x31\x2c\xb6\xd3\x67\x52\x57\xee\xe0\xb9\xea\x33\x95\x4f\xdd\xdf\xf5\xc4\xb9\xad\xab\x18\x33\xb1\xa9\x76\x65\x49\xec\x48\xd0\xb1\x9e\x91\x2e\xf5\x8f\xd7\x2c\x72\x5c\x09\xbf\x80\x08\x1a\x37\xaa\x51\x8b\x8f\x60\x47\xd7\x90\xac\xc3\xe0\xc8\x4e\xb4\x42\xa7\x1d\xca\x0c\x68\x5e\x8e\xd7\xc9\xc8\x62\xa4\x4b\xda\x92\xba\x40\x2d\x84\xd1\x39\x63\x0f\x1f\x90\xc1\x15\xa4\x93\x01\xdf\x08\xa7\x22\x71\x48\xca\x6a\x54\xf1\x42\xcd\x1a\xbd\x6b\x72\xf6\xe7\x0a\xd7\x43\x83\x81\x56\x5e\x50\x41\xf7\x4f\x04\x9a\x07\x19\x25\xa8\xc7\xbc\x89\xe5\x56\xf5\x9a\x8e\x4a\xf3\x53\x9d\xbe\xee\x53\x8c\x41\x8a\xa0\x67\xeb\x58\xea\x7a\xdc\x4c\x45\x18\xfa\x3d\xb6\x5a\x7e\x3b\x29\xbc\xdf\x0d\x64\xd6\x94\x86\xc3\xe2\x31\xa0\x06\x9b\x93\x27\x75\xc5\xa9\x69\xe8\x2b\x43\x81\x00\xf2\xc9\xe3\x0f\xa2\x23\x04\x5b\xfd\xe7\x2d\x29\x49\xe6\x10\x59\x50\x38\xbb\xff\xb1\x11\x83\xc9\x3f\x7d\xf4\xf2\xae\x9c\xbf\x3a\xff\xe6\xa1\x7b\x50\x62\x1e\xc0\x68\xfc\x0a\x7d\x52\xc4\xfc\x56\xb9\x7e\x29\xa3\x85\x9c\x7d\x8c\xad\x55\xc1\x15\x1a\x35\xd4\x06\x82\xf3\x7d\xc5\xdd\x06\x80\x3c\xae\xd3\x8a\x72\x57\x83\x0b\xd9\x49\x4b\xab\xfe\x89\xa5\x33\xf1\x01\x79\xac\x52\x33\x07\xb6\x25\x38\xb7\x6f\x49\xa0\x29\x6b\x62\xdc\xc9\x19\x39\xbd\xf3\xaa\x2e\xf1\x19\xf5\x3f\xea\x00\x7b\x10\x80\xdd\x0d\x26\xf0\x20\x10\x1d\xe1\x66\x64\x40\xc0\x28\x53\x41\xe4\xea\xbc\xfc\xdf\x87\x8b\xae\xe5\x3b\x7f\xc3\x8d\xed\xa5\x59\xc6\xf2\x11\xda\xfd\xa2\xb9\x5f\x71\x21\x9d\x67\xa2\x1f\x85\x9b\xc9\xc8\xdd\x68\x74\x21\xb1\x89\xcc\x71\x43\x89\x42\x8f\xc8\x40\x5f\x1b\x88\x37\x2e\xdc\xf8\x86\xc4\xe7\xc3\x47\x2c\x45\x77\xd3\x96\xfd\x2d\x30\xbb\xdc\x2e\xfe\x89\x45\x2a\x09\xf1\x8d\x0c\x02\x9d\x0f\xe4\x16\xee\x65\xd2\xb7\x87\x3c\x08\x76\xbf\x5b\x6f\x18\x15\x90\x4c\x6b\x72\xd1\x14\xb1\x23\xe5\xa5\x66\x7a\x5f\xe4\x93\xa3\xd5\xb3\x20\x20\x36\x92\xc3\xfb\x65\x6b\x56\xa7\x2f\x9e\xad\x89\x50\x1b\x10\x2e\x3b\x45\x1a\xc5\xc1\xec\x80\xdd\x23\x72\x5d\x7d\xfa\x6c\x26\x12\x6f\x5f\x64\xb3\x5e\x5d\x7a\xa6\x0e\xb5\x00\xe9\x32\x57\x76\x5b\xbd\x74\xae\xd6\xa2\x7c\x78\x02\x3b\xbb\x5e\xab\x0d\x22\x0a\x0b\xdb\x4b\xe3\x44\xb7\xba\x21\x6d\xc3\x18\xbd\x2c\x40\x8d\x3b\x67\xec\x0a\x13\xbc\x37\x9d\xf4\xaa\x57\x03\x43\xf7\x7c\x64\x28\xe7\xd6\xed\x17\x2d\xd1\x91\xbc\x00\x49\x59\xf1\x2d\xa6\x80\x09\xba\x90\x3f\x1c\x0a\x2d\x4e\xfc\x49\xeb\xe8\x54\x3c\x0e\xfe\x04\x9e\xa5\x7f\x88\xd4\xca\xec\x1d\xdb\x17\x5c\x23\x89\x19\x8e\x6b\x59\x59\x63\xc2\x1b\x6e\xb4\x0d\xd4\x68\x87\x59\x43\x3a\x1b\x8a\x92\x31\x25\x89\xae\x95\xbb\xf2\xa7\x3f\x0f\x38\x5a\x0a\x79\x69\x56\x2a\x49\x4d\x1c\x18\xe0\x08\x3f\xb6\xff\x63\xed\xdb\x00\x92\x71\x59\x10\xd2\x4f\xb0\xb5\x6a\x9f\x19\x2a\x41\xf0\xce\x13\xa2\x1c\x50\x92\xbe\x9b\x52\xb0\x45\x36\x0e\x1c\xab\x23\x66\xcf\x66\xeb\xf3\x38\xd1\xac\x45\xf2\xeb\xe6\xb3\xc7\x82\xd3\x00\x9c\xd4\x7f\x3a\x9b\x09\x97\x8e\x57\x9a\xec\xba\x11\x09\x7f\xc6\xf8\x95\x95\x1e\x9e\xe3\xf1\x03\xdc\x71\xd9\x56\x12\x38\xe5\x48\x8b\x2a\xe1\x8a\xa0\xb5\x04\x67\xdd\x1f\x95\xb6\xf8\x01\xbe\x44\x4f\xf8\x23\x74\xce\xab\xd5\x0c\x0f\xfc\xb4\xd3\xea\xfe\xbd\xfb\xa7\xcb\xd3\x0f\x92\x70\x38\x17\x47\x61\x35\xe5\xea\x60\x52\xa4\xde\xac\xc3\xde\x82\xae\xf4\xd1\xba\x08\xb4\x4d\xcc\x50\x83\x91\xd4\x41\xe4\x74\xcc\x48\x1a\xe8\x17\xb8\x01\x97\xaa\x4f\x4c\x8f\x7a\xeb\xb6\x1e\x39\x76\xf2\x16\xf4\x59\x6d\xdc\xbc\xf4\xda\x9c\x83\x5c\x61\x95\xe2\x42\xd3\x82\x0d\xa5\xc4\x9c\x10\x62\x4c\xc6\x24\x60\x68\x27\x1c\x66\x22\xa3\xc8\x9c\x01\x2f\xd4\x45\x74\x4e\x88\x0d\xff\xdf\xba\xe1\xe6\x2c\x68\x32\xc3\x41\x10\x04\x00\x8f\x72\x16\x38\x11\x00\x2e\x1c\x94\x15\x6e\x30\x2c\x5a\x13\x4a\x4e\x3c\x44\x94\xa6\x20\x23\x31\x3a\x5c\x09\x52\xa5\xd6\x65\xb3\x8c\x4c\xaa\x35\x78\xa1\x0a\x76\x67\x03\x6e\x7a\x35\xcc\xfb\x36\xc5\x2b\xfd\x5f\x62\x4b\x14\x17\xda\x15\x73\xf2\x66\xd8\xf0\x54\xf7\xa3\x18\x53\xf6\xd2\x3d\x02\x41\x00\xea\x70\xd5\xf5\x27\x05\xd4\xa6\xaf\x3a\x80\xc7\x27\x96\x45\x79\xc6\x69\x59\xb3\xf1\xb6\x48\x5a\x27\x2a\x4b\xe5\xe6\x7d\xb0\xd2\xe7\xe3\x50\x7d\x78\xf1\xaa\x59\x6a\x1e\xe4\xeb\xb2\xf2\x49\x11\xda\x97\xf5\xdb\x5e\x5c\x64\xbf\x19\x3d\x10\x12\x6d\x75\x7a\xfa\x68\xb2\x3b\x37\x30\x77\x28\xb0\x12\x5b\xa2\xfc\x8d\xe0\x46\x03\x1a\x8e\x7b\x92\xe7\xd6\x3e\xd8\x25\x03\x37\xa2\xbc\x30\xc5\xcb\x60\x7e\x9c\x1b\x7a\xe3\xa2\x8d\x00\x58\xad\xcb\x9a\xf6\x8e\xc6\x33\x98\xfa\xab\xc5\x38\x10\x5d\x7f\x98\x07\xd0\x06\x72\xc3\xf3\x61\xe7\xc6\x8a\xa9\x5b\xf0\xfd\xf8\xc6\x10\x24\x31\x2c\x37\x30\x90\x14\x76\x44\x89\xe5\x45\xaf\xa4\x67\x4f\x95\x82\x49\x35\x12\xba\x1b\x10\xfc\x70\x0a\xa6\x23\xb0\x55\x30\x8d\x23\x22\x93\x5e\x50\xde\x9c\x1d\x46\xac\x3b\xdd\x95\x9d\x0c\xfb\xae\x1d\xa9\x2c\xe1\x37\x57\x0a\x2e\xfe\xe0\x95\xce\x0e\xf0\xb4\xa2\x42\xcd\x44\x4f\x5c\x3f\xa9\xc1\xbb\x8b\x6b\x95\x78\x3f\x34\xee\xed\xab\xc4\xfb\xe3\xa1\x6f\x81\x00\x8b\xae\x2c\xcd\x15\x68\x79\x05\x92\xdb\x14\x87\x24\x4c\xf4\xd1\xe3\x9f\x97\xe0\x19\xd1\x7c\x29\xa5\xc9\x15\x23\x24\xd3\x79\x55\xeb\x9a\x64\x18\xb0\xeb\xcb\x6d\x7f\xa6\x1e\x3f\xb3\x96\xe8\x35\xe3\x0a\xa7\x15\xd7\x47\x12\xa4\x9b\x20\x0c\x46\xc5\xb9\x58\xfa\x5f\x9d\x34\x59\x5d\x12\x3f\x50\x8f\x0e\x65\x06\xd1\x56\xa7\x37\xd0\xf8\xfc\x4a\xbc\x73\xb9\xfa\xa7\xc2\x47\x16\x36\x73\x2a\x08\x1c\xf2\xe5\xa7\x26\x7a\xcd\x8d\xcf\xf9\x64\x8f\x02\xd3\x11\xf4\x49\xcb\xbb\xce\xa0\x54\x25\x28\x19\x4d\xdc\x3f\x5e\x0d\x87\x25\xf3\x2b\x93\xa5\xc4\x0b\xde\x07\xa5\x42\xc1\xe8\x42\x71\x15\x3d\xa2\x6c\xa0\xca\xca\x9e\x65\xc4\xeb\x1a\x0b\xec\x4d\x3a\xad\x80\x1f\x78\x26\xc1\x97\x5f\x20\x5e\x2d\x10\x50\xfc\xb6\xd3\x9f\x03\x6b\xfa\x8e\x7a\x10\x6e\x3e\xa6\x3b\x35\x18\xbf\xe3\xa0\x16\xfb\x8f\x17\x3b\x13\xfc\x55\x7d\x72\x66\x26\x32\x71\x8f\xc1\x69\x03\xe1\xa0\x2d\x1f\x9b\xfc\x95\x21\xf4\xf5\xcb\x13\x29\x18\x70\xf7\xcf\x9b\x0f\x5b\x0a\x1b\xf7\xa6\xbb\x82\xc3\x82\x97\xff\xe7\x19\x13\xed\x33\x52\xa6\xb9\x5d\xa9\xb3\x34\xb4\x8d\x47\x7d\x31\xd9\xb4\xfa\x60\x80\xac\x16\x04\xca\x49\x81\xdb\x19\xc0\xca\xda\x1c\xaa\x00\x91\xe3\x3a\x7c\xcc\xbb\x36\x1f\x97\x35\xad\x15\x7d\xba\xfc\x82\xb0\xe6\xd3\x74\xba\x0b\x0b\xe0\x21\x09\x83\x1d\xcd\x40\xf1\x96\xd0\x0f\xf9\xd8\x31\xa9\x84\xe6\x26\x0f\x53\xfe\xf6\x7e\xfd\xd3\xaf\x84\xd3\xbf\x05\xfc\x1e\x89\x57\x85\xec\x27\xef\xa3\xa0\x99\x73\xc5\xf0\x09\x8a\x03\xe0\xf5\xe2\x14\x9c\x1e\xa1\x38\xb8\x7e\xfb\xb3\xbc\x94\xb8\x77\x99\x67\x2f\x6b\xdc\x02\x82\x70\x7b\xe0\x14\x23\xc4\xb9\x32\x08\xa4\x8e\x8a\xae\x16\x9c\x89\xc4\xa7\xa8\xb8\x6d\xf8\xd1\x3d\x07\x54\x1b\x31\xdb\x36\x5b\x4f\xf8\x9a\x8e\x8b\x25\x7b\xd8\x9d\xe0\x95\x79\x7c\x18\x6c\x2b\xef\xaf\xbd\xf7\x4a\x0b\x89\xc5\xc1\x26\x15\x87\x88\xc4\xb2\x89\x3a\x33\x10\x82\x2a\xaa\x03\x49\xcf\x38\x1a\xf0\x32\x02\x49\xf9\xa3\x41\x19\x88\xff\xf8\xe9\xb4\x6f\x98\xa5\xc0\x4a\xe9\x08\x04\x70\x0c\xe9\x4b\x6c\x78\x31\xab\x03\x61\x80\xe4\x80\x58\x98\xb1\x8e\x67\x2f\x83\x21\x09\x51\xf2\x68\xcc\x2f\x2f\x74\x7e\x2e\xbd\x3e\x11\x9e\xa2\x52\x7d\x23\x3d\xc2\x17\x40\x38\x30\x02\x82\x7e\x51\xdf\xe4\x08\xd7\xb9\xc4\x4a\x91\x22\xaa\x01\x0e\x42\xa9\x38\xc6\x2f\x6c\x81\x38\x48\x7e\x82\x29\xeb\xd3\x4f\x97\x62\xf4\xcd\x19\xf7\xde\x35\x71\x45\x32\x61\xbc\x6f\xf3\x8a\xb6\xcd\x18\x51\xd9\x62\xe7\x3e\x44\x8e\x2d\xf3\x65\xf3\xbc\x54\xb8\x90\xf8\xe6\x32\xbb\x1a\xcd\xaf\x57\xa7\x34\xe9\xeb\x77\x53\x46\xc9\x83\x14\xbd\x9b\x06\x64\x4b\x2c\x5e\x96\x16\x2d\x79\xcd\x06\xcb\x0b\x40\xb4\x06\x74\x91\xd9\xc5\x46\xa7\xdc\x66\x97\x9b\x27\x11\x48\x02\x63\x18\xcd\x75\x27\xe5\xa6\xe2\xe2\xc3\xfe\x3c\x94\xd8\xf8\xc1\xcf\x59\x2a\xd5\xa5\x2e\x94\x5c\xf0\x97\x7e\x92\x9d\x08\x8b\xea\x78\xf1\x8e\x34\x8e\x1d\x89\x7f\xe6\xaf\xe2\xd3\x22\xa5\x90\x74\x86\x57\xb4\xa7\xda\x3e\x15\xa2\x3f\xd5\x2f\xad\xe1\xaa\x4e\x2b\x0a\x6d\x92\x47\x9d\xd0\x0f\xc4\x27\xb6\x68\xe0\x7b\x84\x6e\x7e\xc7\xbc\xf7\x26\x09\xa6\x8b\x83\x92\x18\x28\xc3\x58\x02\x33\xe4\x7b\xb2\x3c\x98\xce\x8a\x1d\x85\xb2\x24\xe9\xc7\xbf\xb8\x8a\x6e\xca\x94\xcb\xfa\xc6\x8b\xd3\x9d\x27\x29\x8f\x07\xa8\xee\x0b\x84\xac\xfe\xf2\x4d\x7b\x94\xbf\x3e\xa9\x78\x8d\xda\xef\x31\x4e\x9f\x36\x9f\x90\xc9\x3b\xfb\x2b\x41\x9f\x8d\xea\x94\x6f\x26\xf4\x8e\x73\xe2\x58\xad\xcc\x29\xe1\x92\xfe\x9d\xf2\xd6\xc7\x1a\xed\xa5\xae\x0b\xd5\x70\xbd\xdb\xdb\x99\x70\xfb\x43\x9a\x36\x71\x5f\xd2\x7c\xc4\x4f\xf2\x52\x07\x97\x28\xcc\x69\x51\xcb\x61\xcf\xd4\x03\x68\x15\x8c\x2a\xaf\x28\x43\x46\xdf\x9a\x95\xea\xc7\x0e\x13\xbf\x40\xbb\x26\x3d\xbf\xe2\xf0\xcc\x29\x83\x10\xb1\xbc\xaa\x9f\x3c\x31\xf5\x08\x42\xa1\xfc\x9a\x0c\x77\x47\x21\x7c\x64\x65\x3b\xf8\x0c\x80\xde\x71\x6e\xc9\x13\x57\x5a\x37\xc3\x30\x1c\xc3\xb8\xbe\xc3\x06\xdc\xbc\xa9\x90\xc1\x10\xdd\x43\x53\x87\x97\x41\xc0\xc5\x01\x95\xe5\xa2\xb3\xc2\xab\xac\x67\x8e\xbc\xaf\x31\x15\xd0\x86\x60\x75\x42\x48\x65\xce\xe6\x73\xc3\x45\x14\x30\x6e\x61\xf1\x0d\xf5\xd2\xfa\x36\xbc\xc4\x57\x65\x67\x24\xd1\xce\xc5\x37\x37\x46\xe6\x67\x7d\x0f\xbe\xa1\x57\xd5\x05\x83\x21\xaa\x26\xbc\xb3\xd7\xd6\xd6\x40\x95\x09\x8d\x5d\x71\x5d\xd3\x37\x70\x2d\x11\xb9\x74\xef\x3c\xa1\xf6\x4c\xe0\x85\xf0\x95\x1e\xe7\xa7\x4c\x95\x99\x9a\xa5\x9e\xc2\x79\x53\x86\x60\xb1\x29\xa3\x4c\x89\x6b\xc1\x7a\xeb\xfc\xbc\xba\x5b\x6a\xad\x44\x62\x8c\x00\x59\x9e\x44\xc1\xd6\x77\x02\x75\x47\x3b\xb4\x78\xf5\x23\x5b\x01\x43\x58\x24\x31\x9d\xb1\x3b\x50\xe3\xe2\x6d\xc8\xa8\xeb\xf0\x55\x4b\xb3\xdd\x56\xf2\x5c\x5a\x24\x5b\xf3\x5b\x12\x1e\x28\xc0\xbd\xc8\xcd\x81\x6b\xd4\x0a\xb5\xcc\x05\x37\x41\x8d\x2f\xff\x9b\x67\x5d\x33\x0d\xc2\xb3\x7b\x2d\x4e\x65\x30\x03\x3e\x6a\xe9\xa0\xd9\x01\x02\x00\x56\xce\xed\x2b\x34\x8e\xef\x82\xa8\xd1\xc5\x08\x5f\x13\xe6\xaa\xb5\x8c\xc0\x94\x83\x92\x86\x72\xf7\xdc\xb7\x6e\x1c\xb9\xce\x2b\x3d\x11\x0e\x4b\xf5\xcb\xdb\xf9\xd5\x3b\x6b\xf8\xf0\xbf\x41\xbb\x02\x3e\x69\x63\xb1\x01\x8f\xe3\x1d\x1d\xdd\xb5\x36\xd5\x15\x68\x0b\x44\xc5\x4e\x2d\xc9\x79\x1b\x08\xfc\x3d\x2e\x8f\x00\x09\x1a\x20\x6e\x3d\x2d\xdd\xce\x41\x0c\xaa\x52\xe2\x23\xf4\x15\x44\xa3\x33\x10\x56\x83\x0d\x06\xfc\x2d\x20\x14\x85\xa1\xed\xac\x23\x93\x09\xde\x8c\x68\x43\xfa\x6f\x19\x0c\x0a\x52\xde\x7c\x52\x91\xec\xb8\xef\x84\xe4\x48\xbe\xf2\xc3\x39\x10\x15\x37\x3f\xa7\xf6\x29\xa8\xd1\x9b\x7e\x99\x69\x76\x75\x6d\xeb\xb8\xe9\xf5\xaf\xf5\xfa\x99\x84\xef\x7c\x73\xff\x65\x37\xf7\xf7\x4d\xd2\xb6\xa6\xbd\xf2\xc3\xd7\xc4\x87\xe9\x4a\x46\x4f\x41\x8f\xff\x38\x50\xd5\xd6\xf7\x62\x99\xc1\xf0\x7c\x9c\x02\x4b\x8a\x48\x01\xcd\x99\x91\x48\xc3\xdf\x25\xf4\xb7\x22\xeb\x73\xbe\x0b\xe0\xc2\x8f\xbe\x85\xaa\x88\x13\x7f\x72\x8b\x62\x7b\xbf\x13\x50\x83\x09\xc4\x27\xa2\xcf\xa8\xaa\xf4\x1f\xd5\xcc\x49\xc1\xf5\xb9\xaf\x55\x7d\x84\xca\x1d\xaa\x7f\xfa\xf7\xb3\xae\xd6\x94\xbf\xa3\xa4\x69\x6a\x10\xf6\x69\xf1\x89\x4a\x99\x3a\x66\xec\x6e\x93\xb9\xb8\x7e\x56\x8d\x8e\x7e\x5e\x0c\x85\x31\x91\x2c\x4e\xd0\xfc\x72\x24\x38\xa8\x0b\xa4\x4c\x99\x47\x8e\x60\xb3\x7e\xa5\x35\x73\xdf\x52\x1e\x27\x92\xc5\xb9\x2e\xc7\xab\x44\x43\x94\xa7\xf4\x58\xae\x47\xbf\xfe\xb1\x0b\x1a\x04\xc8\x02\xd4\x86\xef\x01\x37\x7c\x0f\x47\xdf\xe2\x7e\x6d\xbc\xab\x18\x95\x19\xe3\x27\x3c\xba\xab\x7a\x18\x64\x42\x85\x5c\x14\x17\xaa\x72\xf5\xfc\xe3\x11\x5e\x64\xaf\x8a\x5f\xab\x49\x29\xd1\x83\x6c\xfc\xca\xec\x6a\x3b\x5e\xad\xf0\x2b\xd4\x6a\xe2\xc1\x3a\x97\x4f\xb2\x37\x25\xbe\x88\x02\x38\x0c\x92\x2d\x3e\x84\xb9\xcf\x1d\x21\x2a\x4e\x14\xed\x7d\xc1\x95\xbc\x47\xb9\x2a\x68\xc5\x69\x00\x82\x33\x63\x3d\xd7\x75\xdf\x56\x96\x9b\x57\x75\xdf\xd4\x77\xdf\x04\xec\x52\x55\x6e\x27\x50\x85\x96\xe5\x67\x4f\x5d\x30\xc9\x6a\xc2\x74\x7d\xb7\x73\x8a\x36\x5e\xd5\xb6\x67\x83\xc0\x65\x6c\x48\x1e\x2d\x69\xdc\xfc\xbf\xf4\x3f\x2c\x69\xd8\xe6\xc1\x80\x97\x3e\x8c\x33\x71\x1e\xd2\x23\x6c\x4e\x66\x8a\x5b\xbc\x8d\x78\xc6\x24\x75\x9e\x0d\xec\x58\x45\xb1\xb6\x1f\x88\x41\xf0\xaf\x96\x9a\xf9\xb1\x43\x78\x6c\xc4\x5a\x4c\x1b\x4e\x7a\x09\x45\xc6\x67\x04\xc9\x83\x9d\x1f\x9a\x0b\xd1\x95\xd9\xfd\xbb\xd6\xfa\xc5\x26\x55\x69\xc8\x72\xf5\xe9\xa0\x82\x3d\x5e\x86\x05\x57\xd7\x3f\xce\x5e\xc7\x52\x0b\xe1\x73\x9b\x89\xdb\xa5\x54\xb3\xe8\x71\xb5\x04\x2b\x98\xc8\xaf\x79\x6d\xe7\x75\x9d\x57\x81\x69\xfa\xd2\xa2\xa7\x89\x96\x80\x18\xfe\xbb\xbd\x74\xdf\xd2\x11\x6d\x37\x0e\x49\x84\xbb\xcc\x8e\x90\x48\xfe\x80\xb8\x8b\xfb\xb4\xfe\x68\x4d\x1d\xec\x24\xf1\x5d\x8b\xf3\xa5\xfd\x8d\x45\x3c\x09\x70\x0c\x17\x19\x3e\x61\xa3\xd1\x30\x4b\xef\x77\x6b\x41\x9b\x1d\xeb\xe2\x91\x13\x0c\xc9\xac\xfe\x77\xbc\xf8\xa2\xba\xc2\xd1\x42\xdb\xbf\x1e\x59\x18\x50\x99\xb2\xb5\x16\x4a\x79\x46\x76\x49\xf2\x68\x02\xe5\xa3\x46\x2b\x19\xa0\xb7\xdf\x41\x13\x97\x47\x97\x60\x39\x4f\xcc\xfa\xe7\x74\xf1\xf8\xf2\xd7\x43\x2b\xae\xd1\x0b\xa6\x62\x18\x13\xd3\x72\x5c\x55\x8f\xe4\xaa\x42\x57\xba\x7a\xf1\x1c\x83\x0d\x4f\x48\x0d\xe9\x08\xd1\xea\x03\x24\x74\xde\x7b\x61\x1f\x0d\x82\xce\x79\x6f\x79\x74\xaf\x27\xc2\xd7\x9e\x62\x84\x3e\x2e\x24\x4b\x02\x3f\x10\x1c\x2d\x19\xe8\x7c\x52\x5f\xa9\xf8\xbc\x58\x9c\xad\x46\xb8\xc0\x2e\xa1\x01\x94\x9c\x3e\xde\x1c\x16\xb7\x03\x1f\x68\x27\x27\x13\x8d\x66\x5d\xe6\xed\x5b\xc7\x8b\xb3\xe3\xe9\x1c\x7e\xc6\xe4\xcc\x78\xe0\xa6\x4a\x4b\xab\x2b\xe9\xd1\xb7\x9b\x44\xc5\x8b\x8a\x44\x38\x8c\x9c\xbe\x0d\x28\x6b\x8d\xaa\xec\xb7\x6a\x6d\xfb\xeb\x7e\x88\x51\x3e\xda\x43\xd2\x2f\x39\x80\xd1\x21\x7d\xdf\x47\x07\x90\xda\x40\xfa\x97\xff\x8b\x24\x9d\x2c\xaf\xd1\x9c\xba\x65\x4d\xc7\xf5\x01\x1b\xc3\x0b\xe1\x3d\x13\x1f\xdf\xa7\xcb\x64\xf5\x07\xc5\x7b\xc1\x0b\x95\xbb\x87\x4e\x8c\x1a\x88\x3e\x20\xcf\x24\xe7\xcf\x6d\x5c\x19\x62\xd4\x58\x51\x3e\x75\x1c\x8a\x2c\x02\xeb\xf4\x69\x81\x0c\xe6\x9b\x72\x22\x2b\xf3\xdf\x38\xe3\x1f\x69\xda\x58\x6e\xcc\x28\xa5\x2e\x43\x7e\x45\x38\x66\x59\x32\x48\xc2\x2d\xba\x1e\x60\xfc\x1a\xbc\x9b\xeb\xe1\x35\x5e\xfc\xf0\x11\x8e\x6e\x88\x8e\x1f\x08\x8f\xee\xf9\x9f\xf9\xe1\x2d\x92\x16\x40\x17\xef\xfe\xe8\x29\x67\x1d\xc2\xf0\x61\x78\x39\x6c\x77\xaf\x50\x59\xe8\x5b\x83\x44\x7f\x46\x19\xa9\x17\x25\xcb\x04\x6c\x4f\x2f\xa9\xdb\x3b\x3c\x4e\x88\x16\x45\x58\x6d\x34\x54\xd1\x92\x9e\xcd\x73\xda\x6d\x6d\x1d\x5a\x08\x7b\x39\xac\x7b\x3e\x6a\x20\x5d\x0b\xe5\x91\xf3\xfa\x83\xe1\xf5\x58\xb9\x69\x2d\xb6\x12\x87\x95\x8d\x21\x3e\x25\x21\x5b\x63\xa6\xb6\x22\x6b\x71\x4d\x44\x22\x39\xe7\xad\x01\x5a\xb8\xc1\xd0\xef\x8a\xa2\x8d\xa4\x5b\x34\xb0\x1f\x3c\x27\xd7\xf8\x18\xc9\x03\x21\xb0\xb8\x02\xc0\xaa\x9a\x8b\xf4\x8c\x26\x1d\xb7\xc4\x27\x54\x08\xae\x99\x4b\xb9\x25\xce\xed\xc4\x42\xbc\xcf\xf4\xd7\x9f\x65\x94\x00\x2c\xb1\x7d\xf5\xf0\x86\x0c\x9e\x02\xe5\x27\x99\x7c\x6b\x83\x57\x04\x25\x8b\x97\x55\xdd\xa4\x42\x43\xb4\x5c\x08\xb7\x5f\xd2\x38\x14\x9b\x34\x1c\xf0\x50\x7b\x4a\x75\x4d\xfb\x85\xd4\x5e\x91\xbd\xd3\xaf\x8a\x13\xca\x9f\xe2\xf8\xcf\xb2\x18\x5f\xfe\x19\xe1\x56\x9c\x64\xd9\xf5\x8a\x71\x86\x9f\x14\x08\x47\x88\x96\x27\x2f\x60\xaa\xd8\x22\x38\xcd\xd5\x76\x6c\x94\x57\x74\xa1\x84\x11\x7e\x5e\xb2\x23\xb4\x02\x50\x40\x45\x9f\x7c\x1e\x89\x50\x20\x3a\xbe\x0f\x74\x53\x87\xd3\xee\x8e\x20\xd9\x15\xd6\xab\x5a\x63\x31\x9d\xe9\x73\x6e\x4a\x7e\x34\xd9\x9d\xe5\x41\xf6\x9d\x5b\x6f\xe8\xe8\xee\x90\x61\x95\x4c\xa0\xe4\x81\x4a\x5d\x73\x5c\xc9\x48\x4a\x6f\x7d\xee\xab\x5a\xff\x2c\xf9\x3a\xef\xd9\xd7\x44\x13\x84\x95\xe1\x08\xe1\x23\x06\x66\x28\x27\x69\x54\x1a\x71\x60\x3a\x10\x2d\xa3\x51\x63\xfc\xf4\xee\x66\xd3\xe7\xda\x18\x17\x3b\xff\x34\x1e\xa2\x35\x77\x1e\x82\x9e\xab\x77\x6d\x83\x11\xba\xec\xfa\xdd\xe2\xfa\xc5\x75\xe3\x29\x96\x9e\x76\x1f\xab\x0a\x9d\x35\xaa\xfa\xe3\xfb\xcc\x39\xd0\x15\xdd\x49\x21\xc3\x01\xd9\x3b\xe0\x26\xa0\x1f\x74\x43\xbe\xd9\xe0\x8d\x11\x8d\x6d\xcb\xf4\x60\xc3\x8a\x78\x12\x8b\xeb\x26\x62\x0d\xd9\x23\xe1\x13\xf1\x14\x88\xa0\xda\x98\x96\x55\xd3\x55\xf7\x4d\x79\x37\x9a\xa0\x41\xbd\x34\xf4\xcf\x86\x12\xab\x0c\xa0\xc9\xa0\x40\xe6\xca\x92\x1d\x25\x68\x73\xf2\xb6\x68\x47\x19\x2c\x01\xd5\x16\x5b\xd5\x69\xc3\x30\x5d\x36\xa4\xaf\xec\xa6\x8e\x08\x60\xfb\x3e\x2c\x14\x04\xdb\x8c\x36\xee\x15\x24\x1d\xe4\x4b\x0e\x7e\x9a\xef\xda\x4f\xa6\x9a\x8b\x5e\x04\x4d\xd6\x21\x04\xc1\x0b\xfe\x13\xe4\xc3\x2e\xca\x25\xca\x03\xd1\xc9\x8a\x13\xcd\x70\x1c\x03\x57\x0d\x7f\xe9\x3f\xa0\xef\x4b\x2e\x31\xbd\x9e\xc8\x8e\x91\x64\xfb\x4b\x20\xf2\x4c\x7c\x82\x17\xaf\xaa\xe6\x4e\x46\x37\xb0\xe6\x5b\xdc\x7f\x0d\xf3\x9b\xac\x0b\xa1\x2a\xeb\x4b\x91\xa7\xfe\x29\x17\xc9\xc3\x3a\x90\x52\x0d\xd5\x9b\xbe\x96\x85\xe8\x91\x1d\x08\x69\xa2\xc1\x9d\x1e\xe7\x29\x7b\xc8\x14\x00\xde\x84\x93\x80\xde\x62\xa7\xd1\xc5\x30\x2e\x24\x66\xdc\x0b\xfc\xf7\x66\x06\x01\x5c\x73\x66\x8c\xf8\x0e\x2f\x2f\x61\x26\xc4\x1f\x9f\xca\xfc\x83\x11\xc5\x65\xcf\xbc\x5b\x39\x3e\xc4\xb2\x76\x2e\x6b\x08\x7a\xb9\xb8\x41\xc7\x46\x53\x3b\xc2\x63\x7e\xf9\x31\xbc\x67\x04\x85\xc8\x71\x65\x1b\x4c\x90\xce\x50\x58\x1d\x96\x4d\xc7\x84\x6e\xf0\xce\x7e\x75\xf6\xa3\xd9\x8f\xa8\x48\xa0\xeb\x11\x0d\x26\x3b\x0a\x2f\x4e\xaa\x41\x50\x3c\xe4\xea\x59\x95\xe9\x07\xcc\xaf\xe8\x9a\xde\x52\x9f\xf4\xed\x16\xc7\x64\x4d\xc9\x63\x44\x03\xf8\x90\x71\x04\x76\x85\x05\x95\x1f\x10\x8c\xe8\x12\xb4\xe3\x3c\x5c\x87\xfc\x4b\xf5\x5f\x3e\xae\xeb\xb9\xa1\x76\x89\x57\x15\x49\x8d\x39\x36\x99\xd1\x75\x4e\xa6\xd0\x39\x2b\xf7\xa6\x9c\x8f\x1a\x68\x35\x50\x4d\xf4\x97\x35\x7e\x4d\xf1\xb5\x14\x38\x01\x18\x95\x11\x40\xb5\x7f\xa9\x98\xd9\x1f\xa1\xe1\x80\x55\x47\xce\x9e\x49\x93\xb7\xc0\xf9\xb9\xc5\x77\x41\x96\x53\x3b\x76\x31\xab\x2a\xb8\x15\x6e\x30\x2d\x3b\x7e\x22\x38\x1d\x4c\x80\x55\x8b\x66\x4c\xee\x9a\x93\xb7\x1c\x28\xd9\xf3\x16\x30\x57\x0a\x7d\x0d\x00\x0a\x80\x1c\x19\x1c\x08\x99\x78\x38\x45\x14\x27\xea\x86\x70\xc8\x27\xc1\x87\xd3\xc0\xe5\xdd\xe0\x6c\xfe\x9a\x1b\xe8\x66\xc2\x5a\x74\x45\xb3\x67\xa4\xb2\x8e\xf2\x8a\xe2\x38\x66\x1b\xca\x50\x3c\xe1\xcb\xf7\x28\xc8\x3c\xe1\xd6\xed\x5d\xe0\xda\x79\x55\xb1\x37\xd5\xe5\x0f\x1e\x79\xcb\xa7\x05\x8e\xe0\x97\x0b\xbd\x10\xd2\x42\x01\x4d\xec\x0e\x73\xc6\x8c\x11\x74\x2e\x01\xca\x9a\x27\x3d\xc2\x2d\xd9\x91\x40\xf9\x43\xd3\x30\x81\x15\xd7\xbf\x7e\x88\xfa\x47\x58\xee\xd4\x78\xbe\x92\x47\xec\x73\xe0\xd8\x04\xfa\x40\x7e\x46\xc9\x9f\x86\x66\xc3\xa5\x13\xeb\xba\xce\x43\xfb\x24\xde\x50\x97\xd2\x71\xac\x48\x96\x1d\x03\xf0\xa5\xac\xad\x73\xe6\x7b\xf7\x16\x47\x9f\x58\x35\x1b\x54\x75\xf1\x98\x3d\x1c\x59\x09\x5e\xa6\xec\xa5\xc8\xd1\xd9\xd4\x01\xa0\xd9\x51\x87\xa5\xe5\x97\xb2\x0e\xc8\x4f\xa9\xc3\xd9\x21\xb3\x50\x21\x7d\xd9\x35\xa0\xda\xd0\x22\x0b\x11\xb0\xaa\xa2\xa8\x91\x06\x53\x40\x8b\x2d\x00\x70\x79\xca\x4b\xb6\xd1\x3e\xc1\x1a\x2e\x33\x98\xd8\xc4\xe1\x09\x56\xc7\x96\x5d\x8f\x3e\x2a\xd4\xa4\x5b\x0d\x61\x5e\x1b\x49\xaf\xe4\x82\x4c\xde\x72\xd6\x2f\xb8\xbe\xdf\x42\x81\x3b\x2a\xc8\x55\x6e\x0b\x87\x96\xc2\x1a\x16\x4a\x31\x0d\xd9\xdb\x9b\x4f\xca\x4e\x64\xd6\x6c\x0d\x93\x98\xb2\xd2\x01\x90\x05\x8c\xc0\xb1\x07\xca\x63\x83\x3b\xcd\x7b\x75\x18\x4a\x53\xb4\xe6\xde\x3b\x69\x7e\x07\x59\x7e\x47\x26\xc1\x47\xea\x29\x2d\x20\x04\x67\x36\x92\xdc\xf8\x55\x0f\x55\xc9\xcf\x06\x93\xf2\x93\x87\xca\x13\xfe\x88\x49\x09\x8d\x2e\x47\x00\x06\x3c\x12\x8a\x5a\xf8\x31\xd7\x65\xfe\x81\x88\x52\x61\x80\x1f\x14\x8e\xcb\x9a\x1d\xc8\x56\x6c\x68\x9a\x18\xd2\x9d\xcb\xed\x95\x6b\x9a\x3b\xaf\xe5\x45\xee\x48\x7c\x4d\x1f\x61\x76\xf3\x01\x7a\xa9\x73\xcc\x22\x5c\x45\x4a\x7e\x86\xd4\x54\x53\x86\x91\x6b\x38\x05\xfe\x59\x33\xfe\x9b\x73\x0e\x11\xf2\x71\x42\x01\xec\x33\xe6\x10\x07\xba\xe6\x07\x5e\x20\xa8\x98\x92\x42\x65\x43\x3e\x23\x7a\x97\x22\xc7\x96\xdf\x87\xf6\x5f\x05\xa9\xfe\xfd\xf9\xc7\x34\x82\xce\xd4\xbc\x77\x9e\xa1\x35\x0f\xa2\x2d\x17\xea\x2c\x57\x87\x8d\x32\x38\xa0\xe3\xb0\xa6\x0f\x7b\xb2\x69\xef\xfe\x64\x7a\xcc\x8c\x91\x8f\xec\xcc\xb1\xc4\x67\x78\x9f\xb4\x30\xff\xbc\xc9\x73\x9a\xec\x63\x96\x50\x25\x4f\x11\x48\x7d\xb3\x32\x11\x27\x9c\x1d\x78\x7c\x46\xad\xf6\xe9\x7e\x4e\x40\x86\xe7\x5b\x32\x8f\xf5\xbc\x70\xd0\xc0\x97\x5d\x00\x68\xcd\x50\x69\x42\xe6\xfa\xaf\x39\x64\xa6\xec\xf0\x8e\xc0\x63\x8a\x18\x5d\x8a\x0c\x03\x92\x39\x8b\x0f\x2b\x3c\xc3\xfb\xb0\x91\xf4\x7f\x3c\xa6\xb8\x95\xfc\x50\x21\xd8\xa2\xaf\x4b\x95\xbe\xf1\xc0\x3b\x7a\xa5\xc6\xf8\xe2\x59\x5c\x20\x24\xb0\x07\x48\xa4\x02\x7c\x2b\xdf\xb4\x1c\xc1\x1f\xfd\x92\x6a\x8b\x74\x35\x0e\x10\x1e\x30\x5c\xda\x97\x67\x25\x57\xcf\xbb\xc2\x95\x0b\x59\x2e\x06\x0d\x50\x60\x84\xda\x5f\xe4\x3c\x44\x69\xc9\x54\x45\x00\xf9\x71\xcb\x70\x58\x8f\x30\x41\x97\x04\xd2\x81\x5e\x62\xd0\xb9\x89\x51\x95\x74\xc1\x9c\x9f\xec\x1b\x07\xe9\x7c\x8e\x1a\x9f\x0d\x19\x52\xe7\x3e\x3a\xcf\xd4\xda\xcf\x02\xbf\x29\x41\x9c\x3e\xf9\x23\x14\x29\x1c\x97\xb4\x04\xcb\x2b\x3a\xa3\x49\x7c\x6c\x5f\xe0\x50\x81\xf7\x1f\x83\x7f\x30\x40\xe1\x90\xa3\x4b\x80\xd7\x0a\x6e\xd3\x7b\xa8\x9b\xdc\xe0\x82\x3d\x3e\x5c\x56\x71\x2f\x46\xf4\xbf\x79\xb4\x85\xc8\xbe\x85\xf0\xee\x09\xb0\xd1\x16\xc5\x15\x0d\x78\x99\xf6\x8b\x1a\x8f\x4a\x1b\xf7\x4a\x6b\xf7\x0a\x57\x0e\x73\xca\xfb\x45\xfa\xa7\x29\x93\xc7\x3e\xbf\x61\x5e\x1a\x4a\x57\x4c\x59\x7c\x69\x02\x2f\x5a\x46\xdf\xe8\x12\x8d\x0a\x3a\x4c\x8d\xc4\x2b\x63\xa7\x46\xb7\x7e\xb3\x4c\xd0\x07\x55\x77\x5e\x8d\x2e\xfe\x77\x00\x5a\x66\xb8\x73\xef\xe3\xbc\xfc\xe7\xbb\x1d\xa8\x90\x6d\xd8\xf0\xbc\x7f\x5b\x35\xe0\x22\x15\xed\xd5\x6a\xc0\xaa\x1c\xa6\xe0\x5f\x8b\xaa\xbf\x4f\x11\xb5\x54\xf4\xa7\x52\x2d\x76\x2a\x6d\xef\xd7\xbd\xb0\x44\x3d\x5e\x66\x23\x2e\x79\x53\x62\x56\xfe\x5f\x8e\x88\xa3\x85\x3f\x48\x13\x0d\x49\xf1\x55\xaa\x90\x24\x6c\x5f\x66\xff\x38\x81\xe9\xd1\xb1\xa5\x46\x4f\xd9\x66\x0b\x8d\xf7\x9d\x06\x7b\x0b\x85\x52\xbc\x1c\x82\x70\x58\x55\x64\x7d\xba\x38\x14\x1f\xd2\xb4\x95\xb2\x27\x61\x73\xba\x88\xcf\xa4\xc8\x82\xd6\x90\x39\xb7\x26\xea\x8f\x64\x92\x3d\x95\xbc\xe0\xdc\x54\xe0\x5f\x03\xde\x85\x06\xea\x3a\x49\xa5\x66\x4d\xa5\x65\x4f\x23\x13\xcd\x0a\x9a\x70\xd3\x71\x59\x89\x92\x0c\x67\xb2\xc1\x0e\xa1\xf1\x7d\xd1\x74\x7a\x1c\x70\xa8\x6f\x9f\x88\x41\x09\xc3\x61\x59\x9d\x69\x10\x93\xd0\x9f\xf8\x14\xf8\xc2\xab\xb8\xd6\x23\xbc\x40\x6b\x28\x23\xbb\xb4\x3a\x99\x21\xe5\x37\x1f\x16\x9c\xc0\x40\x8a\xb7\xc0\x30\x73\x8b\x90\xe0\xc6\x65\x8a\x17\x4b\xb8\x67\x51\x55\xcd\x54\x55\x91\x63\x4a\x29\x90\x6e\xa2\x0d\xc6\x1a\xd1\x62\xd1\x1c\xa8\xac\xf9\x6b\x34\x81\x0f\x63\xab\x23\x01\xef\xbb\x4b\x0f\xfe\x33\x5e\x74\x15\x11\x65\xd3\xfd\x3b\x14\x20\x45\xfe\x7d\xcf\xe9\xd8\xf4\x5c\xbd\xb6\x89\xef\xc3\x86\xe7\x3f\xfe\x2f\x60\x6c\xce\x5a\x80\x6b\x56\x59\x9b\xc6\xe9\x0a\x5c\x61\xe1\xb7\x0e\xa4\xf4\x42\x97\xf6\x52\x97\x46\x50\xf3\xf6\xd6\x8b\xea\x48\x41\x2b\x2c\xc2\x6f\x11\x7f\x81\xd8\xd8\xa1\xf8\xaf\xea\xcb\x9e\xf0\x3f\xc7\x13\x06\x43\x02\x54\x1e\xa8\x1b\x16\xdf\xe7\xdd\x42\x00\xe0\x02\x92\x20\xe1\x65\x9a\x7c\x8c\x6d\xb4\x11\x85\x21\x71\x8d\x67\x57\x15\xcb\xa8\x8d\x8f\x18\x1d\x73\x1b\xbc\x73\x2d\xc6\xb8\xc5\xbb\x24\xf3\xcd\x8c\x40\x87\x66\x43\x06\x1f\xf9\x7f\x8f\xdf\xf8\xbf\x21\x09\x03\xd1\xc9\xfd\xcb\xcb\x90\xb3\x0f\x8a\x30\xf8\x35\xaa\x7b\x6e\x04\x25\x04\xa2\x93\xd0\x9f\x75\x16\x7f\xe3\xab\x7c\xd7\x74\x63\xbe\x41\x84\xcd\x66\xa0\xef\x85\x57\x16\xd1\x2a\xf1\x51\x44\x22\xea\x58\x5d\x9f\x7f\xb3\x45\xd2\x40\x65\x4d\x71\xa1\x8f\xdc\x8b\x94\xe6\xe8\xda\x21\x7e\x0e\x2c\x62\xbe\x94\x27\x3d\xbf\x9a\xa4\x7d\x1a\x4e\xc2\x65\x4b\x81\xa8\x0f\x5e\xc8\xe6\xb8\x44\x9f\xf8\xce\x7d\x71\x8b\xb8\x62\x47\xf8\x2d\x92\x8c\x20\x9c\xe3\xfe\x5c\xf2\x63\xab\x3f\x8f\x3a\xd5\x98\x01\x15\x51\x98\x94\xf7\xa0\x89\x2f\x80\x97\xa5\x2e\xad\x97\x76\x25\x3b\x92\x58\xa1\xd6\xbb\xf2\x5a\x22\x18\xba\x19\x74\xba\x87\x7d\x64\xed\xa5\x5e\x95\xa3\xf3\x9e\xc1\x7d\x0e\x84\xa4\x89\x71\x6c\xc8\x1f\x4e\x92\xcb\x7b\x91\x1b\xaa\x4b\x0d\x38\xe5\x7c\x9b\x1d\x08\x2e\x9e\x3b\x51\x05\xc1\x92\x12\x67\x4c\xf4\xbf\x94\x56\x16\xea\x99\x89\x42\x9f\xe2\x59\x9d\x67\x50\xc3\x4a\x71\x0b\x56\x58\x92\x4d\x66\xfb\xb7\x07\x27\xc9\xcf\x3f\x96\xd8\x81\x97\x40\xf8\x1c\x88\x6a\x4a\xe5\xea\x15\x3e\xb2\x68\x0f\xb1\x70\x59\x89\x93\x24\x29\x1e\x50\xea\xc7\xca\xfc\x59\x26\x69\x82\x1e\x3f\xf8\x0b\xba\xec\xd3\xbf\xef\x29\xf9\x3b\x3c\x64\xb3\xf1\xb5\xa6\x81\xa8\x04\x21\x8b\xb3\x4b\xa2\x1f\x26\x6b\x62\x6c\x19\x5e\xc1\xbc\x57\x89\x08\xb0\xe7\xbe\xd7\x1f\x7c\x0e\xa5\x43\x25\x67\x16\x70\x27\x98\x1d\xf4\x43\x11\xab\x5a\x5e\x1f\x86\xad\x1b\x31\x2e\x7d\x62\xb1\x54\x4e\x14\x26\x4e\xd1\x32\xd0\x2d\xa4\x1b\x7a\x01\x0f\x34\xc3\x8b\x37\xb9\x75\x6f\xff\xfa\xf3\x52\x44\x95\x00\x24\x8e\x23\xce\x84\x92\x84\x88\x46\x2a\x50\x5c\x9b\x9f\x16\x5b\xe9\x2f\x1f\x69\x9a\x60\x7a\x42\xa5\x77\x2f\x36\x9f\xf0\x32\x24\x27\x9a\x86\xfb\x44\x61\x8d\xa8\x79\x69\xfd\xee\x6a\x06\xa2\x9e\x4c\x5f\x9d\x3a\xe8\x42\xb0\x91\xe5\x9d\x3d\x47\x36\xa9\x22\xc1\x90\xf8\xb4\xe5\xd1\xb6\xb9\x15\x4c\xf3\x73\x2e\xbb\x17\xea\x9e\xab\x29\xc3\x7e\x9e\xd8\x75\x55\x67\x97\xe8\xfb\x92\xe5\xee\x99\x2e\x00\xfd\x55\x6c\xee\x6a\xfa\x97\x23\xd6\xf4\x7d\xce\xb3\x4b\x2c\xe1\x54\x5c\x3d\x25\x67\x32\xe2\x00\xad\x3b\x0f\xff\xc3\xc1\xbc\x24\xf5\xd0\x7e\xcd\x1d\xc6\x9d\x38\x14\x31\x49\xf6\x69\x41\x4d\x4e\x2b\x78\xd0\x05\x4d\x66\x02\x63\xc2\xfb\xae\x09\xde\x39\x4f\x94\x6c\x1a\x02\x23\x8f\x72\x5a\x88\xbd\x5b\xe5\x91\xce\x9f\x17\x6f\x8e\x38\x1b\x3e\xfc\x26\x10\xb9\x02\x26\x52\x7d\x77\xc4\x68\x62\xe4\x2f\xa9\x24\x68\x01\x85\x86\xfc\xa7\xf1\xbe\x68\xf9\x02\xb3\x8a\x23\x99\xec\x52\x19\x75\x37\x46\x6a\x6d\x8c\x28\x4e\xb1\x31\xe5\xc5\x43\xf4\xa0\x38\x7e\x2a\x07\x6a\xd6\xeb\x85\x1e\x9c\xd4\xe6\xba\xd3\x92\x86\x93\xf2\xea\xa6\xce\x81\xe7\x14\x7d\xca\xfc\x63\x3a\x89\x1d\xb3\x89\xbc\x5f\x49\xe8\x69\x2e\xf9\xb9\xd0\xb1\xc1\x38\x59\x1c\x22\x92\xab\x6d\x41\xd0\xe7\x02\x03\x66\xed\x18\xe6\x0b\x9e\xa8\xf7\xfc\xe6\x5f\xcd\x23\x64\x39\xab\x98\x7c\x9f\xbc\x5f\x89\x4b\x1a\x6e\x17\x42\xb2\xd3\x80\x51\x26\xc7\x45\xc2\xfe\x9c\xd5\xd7\xdc\x7f\xa2\xdb\x35\x95\x4e\x97\x57\xe8\x60\xd2\x19\x0d\xf8\x9f\x58\xa4\xad\x59\x81\x1b\x46\x85\x86\xe9\xd5\x38\xef\x7d\x18\xa2\x34\x31\x0c\xa8\x74\x3b\x6d\x40\x4d\x01\x7d\x62\x48\xc3\x0b\x18\x9d\x83\xee\xa4\xb9\x72\xc3\xa2\x7f\x3e\x6c\x45\xda\xae\xea\x3b\xa2\xfc\x46\xa3\xf5\x65\x03\x5e\x2d\x0d\xe7\x13\x4c\x57\x51\x82\xed\xf0\x1d\x08\x33\x7e\x1e\xa8\x50\x5e\xa7\xdb\x0b\xc1\xf2\x92\xe4\x13\x1d\xbb\xea\x1e\x03\xa0\x9b\x36\xcc\x3d\xaf\x70\xab\xf2\xca\x32\xb8\x3b\xf6\x4d\xa1\x6e\x6f\x91\x8d\x83\x24\x47\xd2\x2b\xd2\x60\xf5\xc7\x32\xb5\x74\x38\xe8\x98\x26\xe6\x48\x26\x00\x76\xc7\x02\x08\xd0\xae\x3f\xa8\xef\xa8\x81\x07\x0f\x3e\x36\xff\xda\xc0\xb5\xae\x6b\xbb\x2c\x9d\x9e\x1d\xd9\x6d\x5a\xcf\xd2\x13\xd5\x31\x92\x3c\xdb\x3a\xe8\xbc\x96\x48\x56\x9c\x25\xc7\xb4\xb1\x8e\x50\x67\xe2\xec\x52\xe5\x1f\x63\xd2\xc6\xa3\x34\xd1\x9a\xd3\xc7\x92\x4d\x51\x54\x4f\x8a\x93\x76\x41\x84\x97\x56\xb8\xe4\xce\x9b\x4a\xd0\xc5\xf5\x67\x5d\xb4\xa1\xca\x1b\x9b\xcf\x33\x98\xa0\xbf\xe5\x05\x95\xd6\xd9\x3d\x59\xdb\xda\x9d\xb6\x1c\x24\x08\x6f\xb0\xb4\x56\x6b\xa6\x50\x6b\x23\xcb\x57\x9f\xa4\x11\x2a\x51\xb6\xc7\x16\x41\x45\x5f\xd7\x71\x79\x9c\x06\x76\xf7\x6d\xff\xb8\xb8\xd7\x8c\x7d\x9e\xb6\xfb\x27\x91\x34\x00\x0f\x28\x94\xe1\xb4\x21\x5d\x15\x48\x79\x8c\x5b\x1e\x59\x7a\x3b\xdc\x3e\xc7\x12\xdb\x51\x65\xc8\x83\xab\x21\xc5\xfe\xc5\xc1\x05\xdc\x3d\x4a\x57\xae\x2b\xb1\x83\x95\xd5\x30\x5f\x26\xc7\x94\x31\x52\x09\x01\x94\x4c\x58\x98\x08\x7d\x65\x33\x30\xd9\x0e\x60\x49\x9d\x57\xec\xc8\xd6\x90\x28\x8c\x7d\xf9\xa7\x13\x93\x40\x29\x45\x43\x82\xc6\x20\x3e\x7a\x60\x59\xb2\x11\x11\x7f\xfe\xfa\xfb\x75\xfa\xce\xca\xfc\x1f\x6a\xc0\xba\x67\x0b\x62\x20\x0d\x7f\x5a\x3d\xbf\x89\x4e\x17\x47\x6c\x16\xba\x00\x7e\x37\x01\x15\x51\x40\x96\xe0\x7b\x33\xc4\xc4\x8c\xd1\xfb\xa0\x9d\x79\xc7\xb0\xdd\x55\xb3\x1a\x4b\x14\x1a\x9d\xc1\x5f\xb2\x1f\x92\xc0\xd9\xdf\xb7\x9e\x55\xe6\x2e\xaa\x15\x5a\xf2\x33\x52\xdd\x7a\xfe\xb1\x8b\x0b\x17\xde\x8f\xb0\x78\x67\xc6\xf1\x32\x1a\x3a\xd6\xbb\xe5\xc9\x9a\x60\x73\xea\xc8\x60\x1e\x03\xad\x31\xd5\x6a\xb7\x74\x0c\x58\x3b\xf7\x56\x94\x21\xa9\x36\x02\xb8\x76\x93\x54\xa8\x3b\x75\xd5\xea\x83\xaa\xad\x77\x61\x43\x4b\xd1\x45\x47\x72\x81\x1d\xd0\x19\xca\xf4\x69\xcb\x16\x63\x55\x96\x2b\x2e\x89\x8b\x3d\x22\xb5\xee\x56\x78\xcf\x7c\xc3\x94\x11\x35\xe8\x76\x50\x57\x90\xe4\xac\x46\x27\x86\x72\xfa\xca\xe0\x18\x21\xef\x80\x52\xb9\x6b\xf9\x24\xe0\x9a\x5c\x2c\x8b\xb2\x05\x39\x22\xff\x63\xbe\xc0\xce\x68\x59\x9d\xf0\x84\xb2\x60\x52\xbb\x77\x32\x8a\xa1\xd4\xf0\x35\x43\x5f\x10\xe4\xb8\xe2\xea\x44\x4b\xe3\x5e\xf0\x42\xd4\xf0\xe1\x53\x6a\x38\xa7\xaa\xcb\x44\x03\xb8\x70\x04\x43\x75\x04\xb5\xc9\x8f\x68\x1b\xda\x2f\x5b\x51\x3d\x00\x04\x1e\x52\x4d\xcb\x1d\x04\xab\xe1\xd1\x6c\x9b\x24\x3c\xb2\x80\x27\xbe\xa9\xdc\x1c\x9d\x33\x8e\x31\x49\x61\x75\xae\xce\x59\x10\x35\xba\xba\x7d\xc5\x12\x3d\x70\x08\xf9\x74\x16\xa0\xb9\x47\xef\x6a\x82\x4f\xe4\x8c\x74\x4e\x27\x0e\xbc\xd0\xc4\x44\x66\x97\x3a\x05\x1b\x21\xf2\x38\x75\x98\x2e\xca\xaa\x7e\x0d\xa9\xeb\x1e\x04\xdb\xda\x61\x70\xc2\x6c\xfc\x0a\x00\xb0\xa2\x60\x11\x46\x0f\xdd\x09\x3a\x89\xb0\x74\xfe\x44\x5c\x66\x28\x33\xe6\xd8\x50\x39\x3c\xf1\xf8\xd6\x71\x27\x4b\xd4\x42\x85\xf5\x56\xc5\x23\xc4\x5c\x2e\xee\xb1\xc2\x5c\x6e\xc5\x32\x73\xa4\xe4\x99\xb1\x6f\xac\xe8\xf4\xcf\x48\xc7\xe4\x89\xdd\x5a\xec\xc7\x7a\xd5\x9c\x86\x43\xe3\xf2\x3f\xdf\x01\x82\xb5\x16\xb6\x63\xf5\x87\x7f\xef\xa4\xe2\x91\xa9\x99\xd1\x53\x46\x45\x36\xdd\x75\x59\xd5\x06\x2b\xa7\x5e\x6c\x6c\xc7\x1a\xf9\xd6\x99\x1a\x0a\x97\x9e\x3d\x8e\xf9\x92\xa8\x88\x70\x5e\xf5\x2e\x2f\x6e\x43\x73\xdf\xcb\xc7\x34\xe0\x3d\xc6\xac\xfc\x66\xae\x30\xa7\x1c\x28\x3f\xd2\x46\x73\x9d\x07\xcb\x8f\x80\x0a\x2b\x42\xc9\x60\xa2\x89\x1b\xdf\xe1\x09\x04\x34\xf3\xbd\xf7\x34\xa2\xbd\x4a\x82\x21\x00\xb1\x48\xe9\x2f\xa6\x91\xd4\x10\x38\xd1\x17\x79\x71\x89\x43\x8e\x51\xa8\x96\x48\x43\xb1\xbd\xa6\x76\x4b\x56\x38\x5e\x7e\x66\xb6\x12\xe7\x1e\x8f\xca\x58\x4f\x81\xa9\x7d\x40\x46\x1b\x63\xf6\x5d\xb7\x4c\xea\xf5\xf2\x0b\xfe\x3c\x8a\xe3\xef\x21\x49\xaf\x1f\x72\x33\x8a\x93\x77\x45\x1a\x94\x47\x98\xc1\x30\xf0\x65\xba\x54\x2d\x56\x72\xa6\xb1\xc8\xed\xd7\xc1\x75\x7b\x9d\x31\x77\xf6\xcf\x18\x68\x20\xa2\x09\x93\x87\xd3\x2b\x9a\xcd\xb0\xb4\x98\x10\x67\xbb\x9c\xef\x61\xc0\x2f\x95\xa2\x64\x7f\x53\xb7\x32\x70\xc5\xc7\x0a\x73\xe5\x00\x70\x1f\x81\x22\xbc\x46\x72\x43\x67\x58\x17\x14\xa3\xaa\xaf\x03\xf5\xcb\x0f\x97\x92\x3e\x10\x3d\x1f\x3e\xef\xd4\x94\x2a\xf6\xa6\xe3\x70\x58\x5b\x79\x02\x57\x31\x92\xfc\x8e\x02\x70\x0a\x13\x0f\x84\x0c\x3a\x30\x0f\xd7\x95\x38\xd1\x7d\x3c\x45\xf7\x02\x44\xf8\x1e\xbf\xed\x40\x88\xf7\x62\x04\xe7\xba\x88\xb9\xc9\xe6\x35\x46\x78\x06\x4c\xda\x66\x04\x91\x53\xb9\xf3\x30\x1a\x0a\xd9\x5b\x60\x45\x54\x4c\x1a\xc7\x68\x6f\xa1\x68\x1d\x45\x47\x5e\xf8\xe4\xb9\x5c\x92\x64\x22\x31\xc4\x10\x9e\x6b\x23\xe2\x80\x13\xbf\xac\x38\x61\xf3\x31\xb0\x6f\x02\xf3\x90\x7f\xd8\xea\x92\xe1\x2f\x44\x6f\x4c\x67\x34\x1c\xbc\x10\x02\x2b\x66\x90\xa9\x35\xee\x3e\xf7\x12\xd7\x3d\xd9\xee\xe9\x35\x02\xe7\x81\xea\xc2\x1f\x3b\x67\x12\x40\x91\xbb\x0c\x1e\xc0\x14\x61\x53\xdb\x0f\xe3\xb2\xa6\xd5\x45\x02\x22\x65\x70\x0b\x44\x54\xf0\xca\xb2\x0c\xb8\x56\x94\xc4\x58\x05\xed\xa5\x16\x39\x90\x25\xcf\x63\x5b\x9a\x74\x0e\x75\x27\x40\x52\xc8\xae\x5e\x9a\x9d\x42\xf6\x49\x58\x4c\xc5\xf7\xd5\xb8\xf9\xe2\xf9\x9f\x87\x12\xb9\x0c\x7c\xa0\xb3\x24\x77\x8f\xb1\x45\x6f\x81\x68\xcf\x0f\x24\xa7\x01\x0e\x38\x8f\x02\x71\x5e\xc4\x0a\x37\xaf\x49\x21\x0e\x1e\xa1\xb7\xf4\x98\x8a\xbd\x7b\xd7\x5a\x81\x83\x00\x4e\x08\xba\x6c\x05\x93\x52\x29\x89\x6f\x36\xe1\x3d\xcf\x77\xd7\xb8\xfb\x68\xa5\x5b\x59\x87\x0d\x26\x30\x95\xab\xff\x15\xfc\xb2\xbf\x5c\xe4\x9b\x1b\xe5\x73\x68\x21\xfe\xbc\xe6\xd2\xbf\x45\x79\x29\x3e\xc3\x5a\x91\xbb\xa9\xc1\xbe\x69\x6f\xf3\xeb\xbd\x0f\xbf\x49\x84\x0c\x32\x03\x72\x3b\x79\xd8\x12\xc4\x81\xe8\x3c\xfa\x9c\x7e\x0f\xff\xfc\xc4\xef\x99\xa9\x0c\xfb\xcd\x47\x6a\x7a\x5c\x2c\x57\x2b\xbb\x3e\x18\xc9\xe0\x43\x86\x54\x53\xfe\x54\xa6\x87\xf7\x44\xe0\xd6\xfe\x3c\x4a\x4e\x3c\x3a\xbd\x21\x83\x4d\x7d\xf0\x1a\xe6\x18\xe0\x48\xb9\xf5\x48\xb6\x7c\x0d\x59\x7f\x7f\x9f\x5d\x45\x60\xb4\x0f\xe1\x36\x6d\x30\xa1\x5f\x15\x25\x3a\xb6\xff\xcc\x58\xd6\xa0\x1b\xa5\xb6\xb1\xa7\xf4\x70\x0b\x0c\xd1\x5d\x6a\x5f\xf3\x83\x62\x21\xb2\xbf\x87\xb6\xd4\x36\xfc\x7e\x3c\x70\xb0\x0b\x22\xf3\x0b\x35\x46\x24\xff\x60\x90\x8e\x97\x11\x19\xe8\xb0\xc1\x7b\x12\x60\x8d\x2d\x31\x01\x4e\x96\x19\x23\xe9\xc0\x83\xfe\xf8\x3e\xec\x17\x1f\x78\x5a\x12\xb6\xc4\x1a\x48\x7b\xd2\x1d\xcb\x22\x81\x5b\x12\x68\xa9\xad\xd8\xec\xd9\xf8\x82\x0f\x54\xf0\xfe\xc4\x1f\x20\xba\x0c\x5f\xf2\x37\x2f\xa8\xaa\xa3\x0a\x16\x7b\xcd\x2d\xdd\x8a\x33\xc9\x91\x82\x7e\xe6\x27\x8c\xff\xc7\xde\x75\xb4\xde\x8f\x73\xe7\xfd\xfb\x29\xc2\x64\x15\x0c\x71\x6f\x33\x24\x60\xdf\xeb\x5e\xaf\xbb\x4d\x36\xee\xbd\x77\x87\xf7\xbb\x87\xfb\x1b\x08\xff\xc9\x2e\xfb\x11\x78\x61\x21\x74\x2c\xe9\x41\xe7\x3c\xb2\xa4\x47\x30\x10\x5f\x09\x9f\x58\x97\x5b\x8a\x0e\xb7\x03\x00\x89\x93\x1a\x15\x01\x79\x03\xb3\x16\xeb\x02\x41\xa7\x47\xbe\x30\x63\x68\x62\x68\xa7\x99\xc1\x46\xe6\x82\xe1\x3b\x15\xbd\x02\x9d\xbb\x8b\xbc\x17\xef\x81\x36\xec\xe5\x6b\x1c\x15\xbd\x89\x90\x13\x8a\x49\x2d\xa9\x52\x59\xb1\xdb\x79\x5e\x66\x5a\x94\x88\xb1\x50\xf1\x24\x42\x33\xf9\xbc\x62\x3a\x49\x81\x42\x5f\xfb\xc7\x6b\xb0\xf5\x96\xbc\x21\x42\xb0\x98\xaf\xbe\x6c\x74\xe6\x20\xa3\x22\x8c\x76\x52\xad\x0d\x00\x43\x01\x29\xa1\xb0\xb0\x7c\xe4\xf1\xaf\xe2\x10\x1b\x80\xc8\xb5\xc1\x13\xca\x2c\x78\x00\xf0\x38\x50\x62\xdd\xf5\xb8\x93\x7d\x6f\x70\x46\x8c\xce\xc1\xe2\x20\x2c\x8e\x36\xc9\x0c\xa0\x97\xd8\xdf\xac\x43\x8c\xf9\x0f\xf1\xa6\x11\x52\x5f\x60\x02\x1f\xe1\x18\x8c\x55\x2b\x0f\x06\x3c\x74\x39\xf6\x31\xbb\x73\x2f\x8c\x01\xa1\x87\x04\x4b\x05\xca\x38\x20\xba\x70\x8f\x0a\xcb\x9c\x82\x67\x1c\x0e\x37\x70\x0a\x48\x1b\x40\xb4\xfb\x39\x1e\x64\x1c\x34\x9a\xa1\x0d\x2b\xde\x7c\xf1\xdf\x66\x6d\x13\x44\xfa\xef\x7b\x81\x32\x47\x53\x5f\xd8\x4e\xae\x86\xf8\x06\x03\x12\x47\x4f\xa0\xa0\x11\x81\x0e\x26\x22\xef\x40\xba\x13\x17\x88\xd4\x45\x75\x0f\xb2\x2f\xa1\x9b\xe3\x7a\x24\x34\x15\xd8\xf3\xf0\xe8\x63\x3a\xde\xa8\xab\xa5\x85\xe6\x08\x21\xf9\xae\xc6\x58\x24\x39\x86\x6a\x42\x40\x47\xef\xb4\xe3\x2d\xd7\x95\x6e\xb5\x18\x09\xa3\xd2\x86\x46\xee\x80\x78\xf6\xbc\xaa\x8c\x96\x1b\x60\x3f\xca\xdb\xfb\x18\x07\x0b\x7e\x52\x89\x0d\x8f\x22\x4f\x8a\x0d\xe5\xf8\xae\x6c\x8d\x3d\x78\x23\xe7\xeb\x1c\x15\x67\xc2\x30\x2e\x38\xab\x59\xbd\x29\x51\x41\xb7\x89\x26\x82\x80\x89\x89\xbc\x3c\xa3\xb0\xaf\xc6\xdb\xb4\x96\xdc\x0a\x33\x33\x38\xfa\x45\x9a\x95\x57\xd3\x1f\x10\xb9\xe4\x85\x5a\xec\xa8\xd7\x9d\xaa\xeb\xf1\x56\x6e\xd2\x17\x11\x0f\x13\x60\x0c\xc8\x02\x8b\xcd\x89\x24\xfa\x22\xdf\x0a\x15\xbb\x9d\x6c\xbd\xd9\x93\xcc\xf7\x00\x21\xa7\x39\x12\x86\x79\x0b\x6d\xb7\x9b\x6e\xfd\xf5\xa3\x4f\x36\x49\xe1\x8c\xd6\x61\x07\x04\xb5\x19\xae\x36\x0c\x60\x67\x6e\xfa\x41\xec\x99\x8f\x66\x47\xed\x99\x0c\x57\x9a\xbc\x6e\xcf\x82\x6f\x20\x5d\x5d\x86\x27\x6e\x2e\x0a\x19\xef\xc6\xa3\x62\x47\x47\x2f\x0d\x5f\x04\xb9\x2b\xfd\xe2\xad\xc4\x1a\xa0\x74\xe4\xe1\x39\xda\x94\x20\x08\x01\x05\xd1\x98\x51\xb8\x12\x54\x9e\x1a\xc2\x1b\x3c\x0c\x91\xb0\x87\x29\x82\xf0\x22\x4f\x14\x3c\xdd\x30\x80\x28\x7f\x48\x64\x80\xd2\xa0\x55\xd3\x58\xe7\x52\x76\x6d\x7f\x28\xd5\x78\xb0\x2f\x4f\x24\xc0\xe3\xaa\x63\x08\xda\x92\x0f\x75\x38\x97\x98\x0f\x8b\x72\x67\xb1\x04\x2d\x11\x4d\xd0\x09\x93\x62\x82\xc4\x80\xfb\x38\x2b\xcd\x0a\x1a\x3a\x9a\x23\xb3\x63\x0f\x6a\x47\x49\x3a\x52\x0c\x24\x50\x15\xe6\x50\xde\x14\xc7\x5b\xa1\x3f\x6e\x1d\xcd\x62\xa0\x18\xd3\xfb\x3e\x84\xfb\x62\x63\x40\x6e\x46\xbe\xdb\xf1\xd5\x13\x58\x9c\xc5\xa5\xab\xaf\x5e\x82\x7a\x05\x72\xb2\x42\x93\x62\xb7\xbb\xaf\xfa\x9e\x43\x8f\x20\x05\x9a\x27\xbe\x22\x31\x58\x87\x40\x80\x5f\xc0\x4a\x50\x2f\xb6\xc6\xc3\x35\x3a\xf2\x17\x44\xda\xd0\xc6\x9a\x62\xd3\x21\x64\xde\x42\x86\x77\x2a\xd3\xac\x94\x5a\x5a\x1d\x2d\x99\x9b\x0f\x6c\xdb\x70\x40\xd9\x2e\x15\xf0\x66\x42\x50\x91\x86\x14\xf5\xee\x3e\x9f\x11\xab\xc4\xf5\x6e\xb5\x39\x21\x80\x62\x7b\xf3\x9c\x72\x4b\x11\xf6\xb3\x47\x6c\xeb\x9f\x90\x67\x4f\xb7\xe1\x45\xd9\x50\x58\x7b\x0f\x96\xdd\xbf\x97\x2b\xd4\x26\xdb\x6a\x1d\x9e\xbe\x37\xbb\x10\x6a\x75\xa0\x82\xea\xc1\x57\x28\xd3\x06\x67\x6c\xc0\xeb\xfa\xb8\x22\x0b\xa4\x6f\xa6\x55\xde\x65\x39\x4a\x2f\x5d\x81\x0a\x58\x91\xf9\x17\x4c\x83\x07\x85\x67\x7b\xcd\xb8\x0f\xef\x39\x2e\x6a\x3e\xd7\x0a\x3b\x8c\x9d\x3a\xdc\x25\x59\xef\x00\xa6\x0b\x97\x3e\x16\x4a\xdc\xc9\xb5\xea\xec\x2d\xc9\xcd\x60\x33\xc4\x06\x60\x3b\x67\x5a\xc7\x39\xee\xbf\x3c\x20\x9f\x53\x43\xb4\x4b\x40\xed\xb2\xbd\x87\x79\xde\x4a\x7d\xef\x86\x0b\x63\x70\x7a\xa7\x9f\x66\x85\x3e\x52\x4f\x7b\x8c\x07\x2c\x35\x81\x66\x8f\xcf\x01\x0b\x8d\xb5\x3f\x2b\xab\xe4\x43\x42\xcf\xa7\xe6\x8c\x84\x5f\x62\xcb\x86\xfb\x19\x9a\xca\x7c\x4d\xd7\x68\x98\xf0\x9c\xd4\x74\x10\x66\xbc\x27\x97\x28\xda\x54\x9c\x8d\x66\x24\x8d\x4e\x18\x1c\x76\x29\xb5\x56\x36\x97\x27\x25\x0d\x73\x28\x90\xc4\x68\x78\xfb\x76\x3b\xb9\x90\xcf\x23\x5b\x62\xa4\x35\xc4\xf7\xb5\x12\x89\x5c\x42\xdc\x94\xd8\x05\x7a\xa5\x01\x4c\x83\xf4\x76\xe2\xb7\x59\xb6\xef\x58\x17\x01\xfb\xd3\xb9\x87\x0d\x00\x13\xed\xa8\x12\xbf\x27\x1b\x81\x51\x69\x61\xa0\xa8\x7e\xa7\x15\xa3\x00\xb9\xd3\xe2\xaa\x55\x42\xa9\x2a\xb0\x65\x72\xa7\x54\xcf\x57\xa1\xb7\x78\x33\xa2\xe4\x6c\x73\x49\x28\xbd\x46\x82\x0d\x45\x66\x7b\x1b\xe4\x5e\x20\xa0\xac\x4a\x93\x98\xee\x01\x44\xca\xef\x06\x03\x12\x73\x10\xb4\x05\xe7\x5b\x8f\xbf\xbe\xfe\xb1\x84\x0a\x23\x96\x71\x0a\x88\x25\xb6\x5f\xa9\xa2\x50\xa1\xc7\x18\x1c\xe7\xc2\xc0\x6e\x05\xbc\x51\x8d\x91\xad\x36\x68\x53\x46\x49\x9a\xe3\x63\xa6\xee\xe5\xdc\xac\xce\x9b\x48\xf4\x6f\xf4\xff\x62\x3c\x42\x52\x81\x57\x8d\x14\xcf\x8a\x14\xe6\xa7\xa6\xf3\x7d\x38\x86\x77\x17\xd3\x7d\xd4\x47\x74\xfe\x78\x33\x94\x1f\xc3\x9e\xf4\xf8\x20\xdb\xb4\xcd\xb3\x67\x48\xd5\xd2\x6e\x55\xea\xd2\x2b\xf5\x38\x39\xd5\x49\xee\x9f\xe7\x4c\xa3\xc8\xf6\x1b\x6b\x2e\x4c\x94\x32\xde\xe5\x4c\xa4\x39\x4c\x44\x7d\xd8\x13\xc0\xee\xde\x40\x10\x23\xfa\x4c\xec\xea\x8c\xbd\xab\x73\xac\xce\x03\xb2\xdb\x4d\x5d\x30\xab\x78\x2f\xd3\x59\xa6\x41\x61\x28\xf0\xb6\xbc\x11\xe1\xcd\x0e\x25\x56\x2b\x74\x23\xf6\x90\x68\xd1\x81\xcb\xb3\x23\x94\x28\xfc\x0c\x1c\x4c\x51\x9a\x84\x84\x08\x65\xa7\xdf\x40\x16\x1c\xd7\x39\xba\xae\xc8\x55\x89\xff\xac\x2d\xcd\xca\xbd\xfd\xf0\x06\xea\xd9\xf6\x8d\xf0\x15\x55\x88\x57\xba\x10\x68\x57\x9c\x9f\xd7\xe8\x67\xc6\x90\x21\x22\x20\x57\x09\x42\x1d\xc3\x25\x60\x19\x58\xec\x50\xaa\x8b\x5c\x25\xd9\xc7\xe1\x8a\xc0\xb1\x10\xe8\xac\x0b\xf9\xe7\xcc\xa8\x7a\x55\xc3\x46\xba\xb5\x9a\x10\x2b\x0f\x20\xf3\xc5\x03\x7a\x72\x3e\xbb\x48\xb8\xa8\xcf\x2b\x60\x42\x33\x45\x55\x1b\xde\x2c\x4e\xf7\x8e\x05\xa2\x72\x93\x6f\xa5\xed\x3b\x5f\xe3\x40\x31\xdc\xa9\x0a\xbd\xca\x98\x35\x51\xf2\xdb\x37\xd7\x9a\x08\xd7\x07\xa0\x65\xdf\xf3\x02\x18\xc6\xdd\x25\x8c\xb2\x57\x40\xd2\x40\xe3\x62\x2a\x47\xf4\xcb\x8c\x16\x13\xb2\x06\xd9\x49\xe8\xdd\x0c\xc7\xb7\x51\xe6\x5a\x03\xd2\x66\xec\x0f\xd3\x16\x6f\xc1\xb7\x9f\x8a\x03\x25\x36\xef\xe1\x2b\xad\x68\x10\x27\x7e\xc8\xec\xc6\x6d\x8c\xce\x4d\x17\xd6\x1c\xc3\x79\x9c\x6a\x2c\x44\x90\xda\x8d\xa2\xcb\xa8\xe5\x30\x87\x07\x50\xaf\x5c\xb9\xb5\x46\x74\x32\xa2\x0a\xdc\x4e\xf6\x5d\x58\x77\x3c\x2f\xf0\xa0\x8c\xbb\xb6\xe7\x85\x6e\xaa\x72\x6f\x89\xd7\x41\x77\x88\x83\x77\xfb\x68\x8f\x36\x69\x85\x48\xef\xe0\x8f\x1e\x6c\x27\x4d\x02\xb6\x28\x37\xb5\x70\x97\x2d\x21\xe2\xce\xdb\xc3\xc9\xf3\x96\xe7\x65\x3e\x17\xb7\x4a\x05\xe9\x8e\xfb\x68\xaa\x7d\x2e\x51\xa4\x5d\x50\x26\x66\x37\x1d\x3c\x17\x28\x0e\xe3\x44\x6b\xe4\x86\x10\x97\xac\xbe\x38\xf7\x75\x1c\x30\xf9\x80\xd2\x93\xa2\x0a\xd2\x2e\xf1\x05\x4d\xaa\x4d\xe8\x7d\x65\x3a\x24\x6f\xf6\x0a\xd3\x7d\xbd\xbd\xcf\x6e\x4b\x6c\x7c\xa1\xd6\x27\x3d\x9e\x38\x7a\x82\x1b\xaf\xfa\x94\xae\x09\x42\xe5\x27\x25\x3c\xba\xd3\x84\x37\x1a\xe6\xba\x20\xe1\xa3\x06\x67\xec\xc7\xe5\xa9\x42\x7c\x6e\x84\x4c\x27\x12\xd6\xb9\xb1\x57\xae\x9d\x3b\x57\xb5\x0d\x84\x9c\x48\x9a\x74\x69\x14\x65\x1d\x5f\x65\x3c\xc7\xfd\x3c\x03\x45\xaf\x7d\xf9\xb5\x6a\x43\xdf\x21\x39\xd6\x92\x72\xaa\x54\x57\x1d\xa8\x96\x1a\xe9\x32\x73\x99\x75\xda\x9f\x3b\x81\xeb\x71\x52\x90\x6d\x89\xe1\x2d\xf6\x97\x68\x87\x88\x58\xff\x5c\xfb\x8b\xc5\x66\xb9\x4e\x06\x04\xa6\x83\x64\x43\xa8\xe0\x2e\x04\x64\xa0\x97\x18\xd9\x60\x92\x1e\xd8\x2b\x4b\x7d\x2e\x75\x3a\x2b\xf0\x60\x1a\x07\xe3\x2c\x86\xf3\xc3\x1c\x09\x2d\x32\xfc\xa6\xd2\x8e\x6e\xeb\x1f\x6f\xee\x40\xb0\x18\x50\x92\x8e\xb5\x7b\xb3\x59\x8a\x48\x6c\xaa\x38\xdc\x19\x0f\x60\xc5\xef\xa6\xf8\xe3\x0a\x80\xcf\x5f\xbe\x5c\x45\x81\xe7\xa5\x95\x76\x38\x6b\xe9\x7c\x2e\xfd\xfd\x79\x34\xd2\x38\x57\xf5\x75\x6f\x53\x82\x33\xe5\xae\x35\x28\xb5\xc9\xcf\x41\x7e\x19\xcd\x86\x90\x79\x61\x06\x33\x1f\xee\xef\x91\x10\x2a\x28\x23\xad\xd5\x33\x87\xa7\x82\xc8\xcc\xb7\x2e\x7b\x18\x99\x96\xd5\xeb\xb5\x68\xfc\xc7\x5b\xd1\xa5\xa3\x41\xbe\x82\xb6\xd6\x79\xdf\x1f\xac\xae\xc7\x5e\xfd\xd2\xb3\x14\x00\x9d\x09\x4e\xd6\x20\xda\xc6\x17\xc3\xbc\xa5\xfa\x47\x6b\xb7\xc6\x76\xa9\x40\x45\xfa\x06\x33\x88\x06\xb8\x95\x5c\x88\xbc\x83\x49\x5a\x68\x72\x0c\xdc\xe9\x9f\x73\x56\x0a\x6a\x9a\xf7\x80\xcd\x4a\xed\x93\xd9\x1e\x90\x34\xa2\x3a\x61\x5f\x55\x90\x53\xd4\xd0\xa6\x16\x07\x44\xe6\xc7\xd7\x13\x03\x47\x43\xce\x3c\xc6\x5e\xda\x9b\x04\x1c\xa7\xc5\x0d\x8b\x33\xa5\x0b\x17\xad\x86\x50\x9b\x3e\x11\xd5\x25\x7b\x8d\xd9\x0b\xc8\xf2\x15\x79\xf7\x68\xbc\xf5\xb0\x78\x26\x16\xc7\x30\xef\xf9\x1b\x47\xa3\x2a\xfc\xd0\x20\x41\xe7\x14\x50\x8f\xf7\xba\x28\x40\x07\x9e\xa5\xc2\x8e\x82\x31\x7c\x7d\x63\x96\x1f\xe9\xf4\x39\xfa\x9e\x61\x18\x46\xab\x1f\x5a\xb5\x21\x19\x03\x0a\x8b\xf3\x78\x33\x00\x91\x46\x84\x71\xaf\xb3\x5c\xcf\x78\x36\x32\x5b\x49\x23\x48\x46\x48\x13\x7f\xd6\x14\xde\x1e\x4d\x90\xb8\x60\x8a\x0d\xa2\xe4\xe6\x07\xd3\x26\xf9\x7a\x22\xd2\xc4\xe9\x9f\xc3\xbb\x5d\x8c\xe7\x7b\x90\x1c\x8a\x97\x62\x02\x63\x26\x2c\x60\x56\x60\x0b\x95\x6d\x9a\x08\x17\xe4\x89\xd6\x17\x59\x0b\x0c\xd0\x4a\xbd\x2e\x21\x35\x47\x14\x5a\x52\xdc\x65\x38\xd1\x8a\x24\x3a\x02\x5a\x63\x1b\xa8\x3f\x4b\xf9\x47\x89\xbd\x4f\xf6\x1e\x97\x9b\x02\x8d\xde\x91\x21\xa0\x30\x45\xf4\x06\x44\x5e\xb0\xca\x78\x7b\x5a\x98\xfd\xa4\xe2\x17\x86\xec\x99\x0a\xd5\xe2\x6a\x09\x7b\x16\x1a\x5f\xa6\x0c\x23\xbd\xc0\x99\xe8\xa7\x3a\x04\xcc\x06\xdb\xf5\xa2\x40\x67\x38\xdd\xb1\x8e\xba\xf4\x6e\xde\xa7\xc9\xf7\x86\x88\x2e\x94\x65\xfa\x91\x1e\xd2\x17\x1b\x29\x1e\xa8\xe8\xce\x25\x93\x64\x59\x0d\x7b\xbd\x19\x1e\x9c\xa0\x73\x53\xa4\xe0\x74\x0b\x36\x0d\x32\x2f\xc0\xbc\x1e\x0d\xd5\x7d\x32\x9b\xd0\x64\xd2\x7b\x30\x36\x9a\xa9\x29\x99\x95\x31\x04\x16\x04\x09\xef\x40\x10\x32\x3b\x02\x2a\x11\xae\xb4\x10\xe5\xdb\xed\xa6\xd9\xef\x21\x7f\x31\x55\xd6\xf5\x78\x4f\xfb\xf3\xe0\x3c\xb4\x2e\xf6\xb9\xa9\x36\xb4\xa9\x36\x7d\xaf\xcc\xe7\x75\xaf\x8b\xfc\x35\x65\x51\x80\xca\xdf\x64\x8d\xc1\xba\xe5\xf6\xf6\x53\x79\xbc\xee\xac\xdf\x98\x46\x40\xfd\x45\x20\x51\x77\xe6\x3f\xb5\x38\xb2\x0c\xf3\x62\x44\x5c\x70\x86\x02\x25\xe8\x7c\x47\x13\x9a\xea\x65\x3b\xec\x0e\x14\x49\x86\x08\xd6\x1f\x32\xc3\xd4\x29\x5f\x66\x62\x5b\xe2\x3e\xea\x63\x64\x5b\x22\x1f\xee\x42\xc4\x78\x0b\x89\xf7\x31\x61\xcf\xf3\x62\x3a\x3f\xc6\x5b\xad\xa1\x4d\xf9\x06\x1e\xb6\xf9\x60\x58\xa8\xaf\x08\x79\xf7\xdd\x14\x6f\x4d\x88\xc0\x8d\x8b\xa8\x5d\x8d\xae\x3e\x99\x09\x7d\x75\x32\xf4\x2a\x62\x80\x02\xe6\x5b\x06\xd0\x39\x5e\x50\x74\x0f\xc7\x7e\x37\xf5\x56\x1f\xf5\x3f\xbf\xff\xea\x10\xe6\xa8\xf3\x3b\x8b\xc2\xb1\xa0\x7b\x6c\xc9\x30\x2c\x87\xcb\x16\xc7\xbb\x59\x10\xc0\xb4\x69\xc7\x42\xd5\xc2\xba\x3f\xcd\xb1\xde\xb8\xb7\x5e\x4a\x02\x0c\xb1\x8c\x78\x15\x79\xd0\xe1\x9f\x56\x7d\x21\x94\xdd\xe2\xc6\x17\xf4\x36\x1a\xc7\xdd\x04\x75\x8d\xf4\x25\x01\x88\xde\x30\xa3\xd0\x39\x9f\x4b\x73\x5c\xe4\x8b\xa2\x35\x89\x6f\xbd\x09\xcf\x4f\xf1\x85\x71\xd1\xc1\xb2\xed\x76\xb3\xdd\x4e\x82\xd5\x47\x82\x35\x4c\x84\x3f\x4c\xdf\xef\xfa\xd6\xc6\x7e\x3e\x82\xb7\x80\x11\x65\x76\x74\xe0\x91\xf9\xf5\xc9\x4d\xa1\xf9\x40\xb1\x8e\xe0\x2b\xa2\x3b\x1f\x44\x73\x38\x44\xaf\x42\x89\x7d\x95\xe5\xf8\xc2\xb0\x5d\xad\x27\xcd\xe1\x32\x00\xcc\x7f\x94\xd8\xe2\xbc\x8b\x08\x7b\xc0\x01\xa7\xb5\x15\x90\x9d\x89\x7d\x11\xae\x36\xf9\x51\xf0\xbb\xd6\xa4\xc7\xeb\xd8\xe7\xb7\x04\x83\x56\x93\x31\xb6\xaa\x90\x6f\x0a\x54\x6f\x6a\xd0\x80\x22\x7d\x68\x10\x3c\x4e\x5c\x7f\xa8\x43\x7d\x52\xd4\xbb\x3f\x76\x57\xe0\xe6\x8f\x74\xa4\xeb\xe1\x79\x11\x14\xe9\xbb\x4c\xc5\x11\x18\x46\xe5\x55\xfe\x08\x57\x2b\x8d\x84\x83\xba\xc7\x32\xb2\x57\xba\xaf\xf2\x67\xdf\x9e\x52\xcf\xb3\xdf\xcd\x71\x93\x7c\x92\x8d\x65\x66\x4c\xe8\xbb\x2e\x7e\xb3\xdd\xac\x67\xe2\xb7\x7f\x9d\x0f\x75\x32\x8c\xc4\x49\x2d\xd7\x7b\x7d\x24\x3e\x04\xfd\x6a\x07\xe3\x4e\x49\xf9\x59\x41\x95\x04\xc6\x55\x7d\x9d\x2b\xcf\xba\x6e\x27\xf5\xfc\x94\x7b\xdd\x8f\xc3\x5b\xdb\x76\x9a\x63\xa1\x26\x82\x99\xb0\x5b\x4f\xcc\x9b\x3f\x17\x40\x65\x1b\xda\xde\x2e\xa4\xff\x09\x57\x68\x73\xbe\x8f\x0b\xeb\x89\xaf\xf9\x55\x0d\xe9\xce\xc7\xe5\x33\xf3\x8d\x71\xfc\x77\x0c\xee\xce\xf2\xbc\x3c\x68\x71\xc1\xea\xa2\xef\x80\x56\xae\xf7\x0d\xe0\xe0\xc0\x1b\x5e\xed\xc6\x49\x03\x1f\xf9\x51\x17\x06\x66\x5e\x7c\xab\xcf\x2c\x24\xd9\x17\x5c\x47\x13\x60\xcb\xaf\xcd\x73\xf9\x77\x49\x81\x83\xa2\x0c\xbe\xeb\x79\x96\xfb\x6d\xfb\xcf\xdd\x2a\x1e\x9b\x05\x1e\x9c\xcd\x2f\x7c\x85\x14\x96\x3d\xa1\x58\xcf\x44\x0b\x12\x1a\x6f\xfe\x3a\xa2\x26\x86\xc8\x4f\x98\x28\x37\xb5\x3f\xeb\xa2\xce\x56\x07\xdf\xe9\x22\x3f\x26\x90\xfa\xbc\xe5\x2b\xd6\xcb\xed\xa4\x4e\xcc\x28\x6e\xeb\xa2\xd8\xe3\xa4\xb9\xff\x73\x83\xe2\xbc\x2c\xd7\x61\xe2\xe0\x8b\x7e\xab\xdf\xd7\x56\x85\x8d\x56\x86\xb3\x10\x11\xde\xd6\x8a\x40\x3d\xea\xae\xbc\xd0\x58\x25\x94\x10\xf9\xb0\xc4\xfe\x34\x4b\xab\xc4\x50\x65\xd2\x60\x27\xf3\xbf\xe9\xe4\x14\x78\x4b\x02\x6c\x60\x34\x06\xc5\x8a\x2b\xfd\x30\xbf\xa4\xd7\xc7\x7a\x6e\x8e\xf9\x4b\x7a\xb7\x9c\x96\x88\xcc\xaf\xe5\x38\x26\x0f\x83\x33\xfd\x4b\x31\xe3\x63\x5d\x6b\xca\xfe\x9a\xf5\x61\xf1\xaa\x60\xcf\xbf\x14\xc3\x59\x51\xb8\xce\x5f\x4d\xb0\x8c\xd8\xf3\x94\xf8\x7f\x6d\xa6\x7f\xdb\xfc\xdb\xe6\xff\xc3\xe6\x01\x15\x0b\x50\x75\x81\xb1\x89\x3d\xd2\xfe\xe4\xda\xae\x67\x58\x0a\xfe\x0a\x25\xe9\x3f\x7e\xfb\xb7\x3f\xfe\xf1\xcf\x7f\xfc\x7b\xb2\xe4\x71\x96\x2e\x7b\x9f\xfc\x67\x57\x03\x5d\xfd\x7b\x92\x17\xe3\x92\xff\x77\x3a\x0e\x5b\x3e\x6c\xbf\xff\x06\xfe\x17\x04\xc5\xd0\x6f\x7f\x4c\x71\x96\xd5\x43\xf9\x3b\xf4\x2f\xf8\x74\xfd\x91\x8e\xdd\xb8\xfc\xfe\xaf\x69\x9a\xfe\xf1\xcf\xff\x09\x00\x00\xff\xff\xaf\xa5\x1a\xb1\x3d\x07\x02\x00") func cmdInternalPagesAssetsStylesContainersCssBytes() ([]byte, error) { return bindataRead( _cmdInternalPagesAssetsStylesContainersCss, "cmd/internal/pages/assets/styles/containers.css", ) } func cmdInternalPagesAssetsStylesContainersCss() (*asset, error) { bytes, err := cmdInternalPagesAssetsStylesContainersCssBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "cmd/internal/pages/assets/styles/containers.css", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd3, 0x13, 0xf3, 0xbc, 0xc8, 0x9f, 0x4b, 0x4, 0x81, 0x1c, 0xf9, 0x9c, 0x51, 0x4d, 0xa2, 0x2f, 0x8d, 0x89, 0x5a, 0xfd, 0xd6, 0x57, 0x22, 0xa, 0xa3, 0x25, 0xa3, 0x40, 0x28, 0x64, 0xd2, 0xf}} return a, nil } // Asset loads and returns the asset for the given name. // It returns an error if the asset could not be found or // could not be loaded. func Asset(name string) ([]byte, error) { canonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) } return a.bytes, nil } return nil, fmt.Errorf("Asset %s not found", name) } // AssetString returns the asset contents as a string (instead of a []byte). func AssetString(name string) (string, error) { data, err := Asset(name) return string(data), err } // MustAsset is like Asset but panics when Asset would return an error. // It simplifies safe initialization of global variables. func MustAsset(name string) []byte { a, err := Asset(name) if err != nil { panic("asset: Asset(" + name + "): " + err.Error()) } return a } // MustAssetString is like AssetString but panics when Asset would return an // error. It simplifies safe initialization of global variables. func MustAssetString(name string) string { return string(MustAsset(name)) } // AssetInfo loads and returns the asset info for the given name. // It returns an error if the asset could not be found or // could not be loaded. func AssetInfo(name string) (os.FileInfo, error) { canonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) } return a.info, nil } return nil, fmt.Errorf("AssetInfo %s not found", name) } // AssetDigest returns the digest of the file with the given name. It returns an // error if the asset could not be found or the digest could not be loaded. func AssetDigest(name string) ([sha256.Size]byte, error) { canonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err) } return a.digest, nil } return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name) } // Digests returns a map of all known files and their checksums. func Digests() (map[string][sha256.Size]byte, error) { mp := make(map[string][sha256.Size]byte, len(_bindata)) for name := range _bindata { a, err := _bindata[name]() if err != nil { return nil, err } mp[name] = a.digest } return mp, nil } // AssetNames returns the names of the assets. func AssetNames() []string { names := make([]string, 0, len(_bindata)) for name := range _bindata { names = append(names, name) } return names } // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ "cmd/internal/pages/assets/js/bootstrap-4.0.0-beta.2.min.js": cmdInternalPagesAssetsJsBootstrap400Beta2MinJs, "cmd/internal/pages/assets/js/containers.js": cmdInternalPagesAssetsJsContainersJs, "cmd/internal/pages/assets/js/jquery-3.5.1.min.js": cmdInternalPagesAssetsJsJquery351MinJs, "cmd/internal/pages/assets/js/loader.js": cmdInternalPagesAssetsJsLoaderJs, "cmd/internal/pages/assets/js/popper.min.js": cmdInternalPagesAssetsJsPopperMinJs, "cmd/internal/pages/assets/styles/bootstrap-4.0.0-beta.2.min.css": cmdInternalPagesAssetsStylesBootstrap400Beta2MinCss, "cmd/internal/pages/assets/styles/bootstrap-theme-3.1.1.min.css": cmdInternalPagesAssetsStylesBootstrapTheme311MinCss, "cmd/internal/pages/assets/styles/containers.css": cmdInternalPagesAssetsStylesContainersCss, } // AssetDebug is true if the assets were built with the debug flag enabled. const AssetDebug = false // AssetDir returns the file names below a certain // directory embedded in the file by go-bindata. // For example if you run go-bindata on data/... and data contains the // following hierarchy: // // data/ // foo.txt // img/ // a.png // b.png // // then AssetDir("data") would return []string{"foo.txt", "img"}, // AssetDir("data/img") would return []string{"a.png", "b.png"}, // AssetDir("foo.txt") and AssetDir("notexist") would return an error, and // AssetDir("") will return []string{"data"}. func AssetDir(name string) ([]string, error) { node := _bintree if len(name) != 0 { canonicalName := strings.Replace(name, "\\", "/", -1) pathList := strings.Split(canonicalName, "/") for _, p := range pathList { node = node.Children[p] if node == nil { return nil, fmt.Errorf("Asset %s not found", name) } } } if node.Func != nil { return nil, fmt.Errorf("Asset %s not found", name) } rv := make([]string, 0, len(node.Children)) for childName := range node.Children { rv = append(rv, childName) } return rv, nil } type bintree struct { Func func() (*asset, error) Children map[string]*bintree } var _bintree = &bintree{nil, map[string]*bintree{ "cmd": {nil, map[string]*bintree{ "internal": {nil, map[string]*bintree{ "pages": {nil, map[string]*bintree{ "assets": {nil, map[string]*bintree{ "js": {nil, map[string]*bintree{ "bootstrap-4.0.0-beta.2.min.js": {cmdInternalPagesAssetsJsBootstrap400Beta2MinJs, map[string]*bintree{}}, "containers.js": {cmdInternalPagesAssetsJsContainersJs, map[string]*bintree{}}, "jquery-3.5.1.min.js": {cmdInternalPagesAssetsJsJquery351MinJs, map[string]*bintree{}}, "loader.js": {cmdInternalPagesAssetsJsLoaderJs, map[string]*bintree{}}, "popper.min.js": {cmdInternalPagesAssetsJsPopperMinJs, map[string]*bintree{}}, }}, "styles": {nil, map[string]*bintree{ "bootstrap-4.0.0-beta.2.min.css": {cmdInternalPagesAssetsStylesBootstrap400Beta2MinCss, map[string]*bintree{}}, "bootstrap-theme-3.1.1.min.css": {cmdInternalPagesAssetsStylesBootstrapTheme311MinCss, map[string]*bintree{}}, "containers.css": {cmdInternalPagesAssetsStylesContainersCss, map[string]*bintree{}}, }}, }}, }}, }}, }}, }} // RestoreAsset restores an asset under the given directory. func RestoreAsset(dir, name string) error { data, err := Asset(name) if err != nil { return err } info, err := AssetInfo(name) if err != nil { return err } err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) if err != nil { return err } err = os.WriteFile(_filePath(dir, name), data, info.Mode()) if err != nil { return err } return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) } // RestoreAssets restores an asset under the given directory recursively. func RestoreAssets(dir, name string) error { children, err := AssetDir(name) // File if err != nil { return RestoreAsset(dir, name) } // Dir for _, child := range children { err = RestoreAssets(dir, filepath.Join(name, child)) if err != nil { return err } } return nil } func _filePath(dir, name string) string { canonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...) } ================================================ FILE: cmd/internal/pages/static/static.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Handler for /static content. package static import ( "fmt" "mime" "net/http" "net/url" "path" "k8s.io/klog/v2" ) const StaticResource = "/static/" var popper, _ = Asset("cmd/internal/pages/assets/js/popper.min.js") var bootstrapJS, _ = Asset("cmd/internal/pages/assets/js/bootstrap-4.0.0-beta.2.min.js") var containersJS, _ = Asset("cmd/internal/pages/assets/js/containers.js") var loaderJS, _ = Asset("cmd/internal/pages/assets/js/loader.js") var jqueryJS, _ = Asset("cmd/internal/pages/assets/js/jquery-3.5.1.min.js") var bootstrapCSS, _ = Asset("cmd/internal/pages/assets/styles/bootstrap-4.0.0-beta.2.min.css") var bootstrapThemeCSS, _ = Asset("cmd/internal/pages/assets/styles/bootstrap-theme-3.1.1.min.css") var containersCSS, _ = Asset("cmd/internal/pages/assets/styles/containers.css") var staticFiles = map[string][]byte{ "popper.min.js": popper, "bootstrap-4.0.0-beta.2.min.css": bootstrapCSS, "bootstrap-4.0.0-beta.2.min.js": bootstrapJS, "bootstrap-theme-3.1.1.min.css": bootstrapThemeCSS, "containers.css": containersCSS, "containers.js": containersJS, "loader.js": loaderJS, "jquery-3.5.1.min.js": jqueryJS, } func HandleRequest(w http.ResponseWriter, u *url.URL) { if len(u.Path) <= len(StaticResource) { http.Error(w, fmt.Sprintf("unknown static resource %q", u.Path), http.StatusNotFound) return } // Get the static content if it exists. resource := u.Path[len(StaticResource):] content, ok := staticFiles[resource] if !ok { http.Error(w, fmt.Sprintf("unknown static resource %q", u.Path), http.StatusNotFound) return } // Set Content-Type if we were able to detect it. contentType := mime.TypeByExtension(path.Ext(resource)) if contentType != "" { w.Header().Set("Content-Type", contentType) } if _, err := w.Write(content); err != nil { klog.Errorf("Failed to write response: %v", err) } } ================================================ FILE: cmd/internal/pages/templates.go ================================================ // Copyright 2023 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // generated by build/assets.sh; DO NOT EDIT // Code generated by go-bindata. DO NOT EDIT. // sources: // cmd/internal/pages/assets/html/containers.html (9.64kB) package pages import ( "bytes" "compress/gzip" "crypto/sha256" "fmt" "io" "os" "path/filepath" "strings" "time" ) func bindataRead(data []byte, name string) ([]byte, error) { gz, err := gzip.NewReader(bytes.NewBuffer(data)) if err != nil { return nil, fmt.Errorf("read %q: %w", name, err) } var buf bytes.Buffer _, err = io.Copy(&buf, gz) clErr := gz.Close() if err != nil { return nil, fmt.Errorf("read %q: %w", name, err) } if clErr != nil { return nil, err } return buf.Bytes(), nil } type asset struct { bytes []byte info os.FileInfo digest [sha256.Size]byte } type bindataFileInfo struct { name string size int64 mode os.FileMode modTime time.Time } func (fi bindataFileInfo) Name() string { return fi.name } func (fi bindataFileInfo) Size() int64 { return fi.size } func (fi bindataFileInfo) Mode() os.FileMode { return fi.mode } func (fi bindataFileInfo) ModTime() time.Time { return fi.modTime } func (fi bindataFileInfo) IsDir() bool { return false } func (fi bindataFileInfo) Sys() interface{} { return nil } var _cmdInternalPagesAssetsHtmlContainersHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x5a\x5f\x73\xe2\x38\x12\x7f\x86\x4f\xd1\xeb\xba\x87\xd9\xaa\xb1\x49\x26\xb9\x87\x9b\x23\x54\xb1\xcc\xcc\x2d\xb7\x99\x24\x15\x92\xdd\xda\x47\xd9\x6e\x6c\x4d\x84\xa5\x95\x64\x08\x97\xca\x77\xbf\x92\x64\x83\xff\x01\xf9\x57\x33\xcb\x0b\x20\xa9\xbb\x7f\xfd\x53\xb7\xd4\xb2\x3c\xfc\xc9\xf7\xfb\x00\x13\x2e\xd6\x92\x26\xa9\x86\x0f\x47\xc7\xa7\xf0\x1f\xce\x13\x86\x30\xcd\xa2\x00\xc6\x8c\xc1\xb5\xe9\x52\x70\x8d\x0a\xe5\x12\xe3\xa0\xdf\x07\x38\xa7\x11\x66\x0a\x63\xc8\xb3\x18\x25\xe8\x14\x61\x2c\x48\x94\x62\xd9\xf3\x1e\x7e\x47\xa9\x28\xcf\xe0\x43\x70\x04\xef\xcc\x00\xaf\xe8\xf2\x7e\xfe\x77\x1f\x60\xcd\x73\x58\x90\x35\x64\x5c\x43\xae\x10\x74\x4a\x15\xcc\x29\x43\xc0\xfb\x08\x85\x06\x9a\x41\xc4\x17\x82\x51\x92\x45\x08\x2b\xaa\x53\x6b\xa6\x50\x12\xf4\x01\xfe\x2c\x54\xf0\x50\x13\x9a\x01\x81\x88\x8b\x35\xf0\x79\x75\x1c\x10\x6d\xf0\x9a\x4f\xaa\xb5\xf8\x38\x18\xac\x56\xab\x80\x58\xac\x01\x97\xc9\x80\xb9\x71\x6a\x70\x3e\x9d\x7c\xbe\x98\x7d\xf6\x3f\x04\x47\x46\xe2\x36\x63\xa8\x14\x48\xfc\x2b\xa7\x12\x63\x08\xd7\x40\x84\x60\x34\x22\x21\x43\x60\x64\x05\x5c\x02\x49\x24\x62\x0c\x9a\x1b\xb4\x2b\x49\x35\xcd\x92\xf7\xa0\xf8\x5c\xaf\x88\xc4\x3e\x40\x4c\x95\x96\x34\xcc\x75\x8d\xaa\x12\x1b\x55\xb5\x01\x3c\x03\x92\x81\x37\x9e\xc1\x74\xe6\xc1\x2f\xe3\xd9\x74\xf6\xbe\x0f\xf0\xc7\xf4\xe6\xd7\xcb\xdb\x1b\xf8\x63\x7c\x7d\x3d\xbe\xb8\x99\x7e\x9e\xc1\xe5\x35\x4c\x2e\x2f\x3e\x4d\x6f\xa6\x97\x17\x33\xb8\xfc\x02\xe3\x8b\x3f\xe1\xb7\xe9\xc5\xa7\xf7\x80\x54\xa7\x28\x01\xef\x85\x34\xf8\xb9\x04\x6a\x48\x34\xf3\x06\x30\x43\xac\x01\x98\x73\x07\x48\x09\x8c\xe8\x9c\x46\xc0\x48\x96\xe4\x24\x41\x48\xf8\x12\x65\x46\xb3\x04\x04\xca\x05\x55\x66\x2a\x15\x90\x2c\xee\x03\x30\xba\xa0\x9a\x68\xdb\xd2\x72\x2a\xe8\xfb\xfe\xa8\xdf\x1f\xa6\x7a\xc1\x46\x7d\x80\x61\x8a\x24\x1e\xd9\x29\x18\x6a\xaa\x19\x8e\xa2\x71\xbc\xa4\x8a\x4b\xf0\xe1\xe1\x21\xf8\x44\x95\x60\x64\x7d\x41\x16\xf8\xf8\x38\x1c\xb8\x21\x6e\xb8\x8a\x24\x15\x1a\x94\x8c\xce\xbc\x87\x87\xe0\x9a\x73\xfd\xf8\xa8\x8c\xe5\x68\x20\xb8\x10\x28\x83\x05\xcd\x82\x6f\xca\x1b\x0d\x07\x6e\x70\x21\xf9\x93\xef\xc3\x39\xd1\xa8\xb4\x8d\x21\xca\x30\x36\xd8\x61\x41\x33\x3a\xa7\x18\xc3\x64\x36\x03\x83\xd3\x8e\x66\x34\xbb\x03\x89\xec\xcc\x53\x7a\xcd\x50\xa5\x88\xda\x83\x54\xe2\xbc\x6d\x37\xe4\x5c\x2b\x2d\x89\xf0\x4f\x83\xa3\xe0\xc8\x0f\x51\x93\xe0\x83\xc5\x11\x29\xe5\x8d\xfa\x5b\x00\x97\xc2\x50\x44\x98\x61\x67\x81\xaf\x35\x67\x95\xf8\x27\xc1\x71\x70\xdc\xb2\xf6\x1c\x8d\x11\xcf\x4c\xb6\xa0\x54\x2d\xc0\x7b\x19\xfb\x2f\x59\x92\x99\x9b\x90\x8d\x27\xfb\x26\xe8\xdb\x5f\x39\xca\xb5\x7f\x12\xfc\xb3\x00\xdc\x31\x4d\xfb\xe4\xf7\x10\xdd\xd6\xb4\xd5\xa5\xd7\x02\xcf\x3c\x8d\xf7\x7a\xf0\x8d\x2c\x89\x6b\xf5\xba\x4d\x30\x4e\x62\x94\x7b\x80\x3d\x47\x59\x85\xd7\xa6\xc2\xe1\xa0\xcc\x81\x61\xc8\xe3\x75\x61\x23\xa6\x4b\x88\x18\x51\xea\xcc\xdb\xc8\xba\x50\xf1\x55\xca\x57\x11\x51\xe8\xc1\xc6\x3d\xd2\x9c\x4e\x6f\x2b\xcc\x7c\xb5\xf0\x8f\x3f\x78\x40\xe3\x33\x8f\xf1\x84\x7b\x1b\xb1\x01\xd9\xfc\xac\xd9\x2b\x45\x46\xfd\x5e\xb5\x43\x90\x04\x7d\x03\x16\xa5\xe9\x32\xd9\x7b\x3c\x6a\x27\x69\x7a\x6c\xe4\x06\x31\x5d\x9a\x6f\xce\x4a\xf1\x50\x22\x89\x23\x99\x2f\x42\x27\xfd\xf0\x20\x49\x96\x20\xfc\x43\x10\x89\x99\x9e\x6c\xdc\xfc\x78\x06\xc1\x55\xbd\x4d\x3d\x3e\x5a\x83\x8c\x8e\x2a\xce\x36\x25\x83\x73\x9a\xdd\x3d\x3e\x7a\xa3\x8e\xae\x1b\xbc\xd7\x06\x1d\x19\x0d\x07\x8c\x16\x00\x30\x8b\x8d\xe2\xe1\x80\xb3\x2d\x29\x16\xb8\xfb\xf3\xf0\x40\xe7\x10\x4c\x95\x23\xf5\x00\x57\x50\x7c\x86\xe9\xe9\x16\x64\x10\x0c\x62\x1e\xdd\x19\xc6\x3e\xd9\x6f\xd8\xfa\xe4\xc0\xa4\xa7\x9d\xa6\x0f\x59\x69\xdb\x11\x3c\x5e\x90\xcc\x1b\x5d\xd9\xef\xa7\xda\x29\x49\xa8\x3a\x3c\xcb\xc3\xa8\xca\xfc\xeb\x62\xe4\x64\x54\xd3\x37\x1c\xa4\x27\xd5\x00\xa9\x08\x33\xaa\xb4\x9f\x48\x9e\x8b\x46\x84\xa8\x8a\x02\x1b\x1e\x4d\x84\xbd\x5a\x12\xd4\xc6\x97\x41\xd1\x36\xe2\x53\x8d\x0b\x1b\x2c\xb5\xf1\xdb\x48\x69\x04\x49\x75\x76\x76\x52\xe8\x18\x74\x73\x3d\xd3\x44\xe7\x6f\x41\xe0\x27\x49\x97\x28\xc1\xe9\x6b\x12\x98\xb3\x83\xfc\xb9\x10\x54\x56\xdc\xf2\xd7\xc0\xe7\x52\xcb\xa9\x81\x0e\x8a\x86\x4a\x90\xac\xb4\x62\xd4\xf8\x8c\x84\xc8\x2c\x77\x55\xdd\xc1\x6f\xb8\x36\xd4\x99\xe1\x23\x68\x76\xfe\x4e\x58\x6e\x57\x88\x66\xfe\xd5\x59\x73\xce\x6e\xb1\xf5\x5e\x06\x6d\xa6\xb9\x24\x09\x0e\x43\x39\x2a\x00\x19\x55\xbb\xc8\xea\x6d\xb9\xb2\xe6\x5b\x5c\xed\x46\xf5\x5c\xbe\x2a\xfa\xdb\x7c\x55\x3b\xeb\x7c\xf5\x36\x74\xf5\x86\x83\x9c\x59\x6f\x4a\x26\x8b\x86\x5d\xd1\xda\x95\xe3\xce\xab\xe9\x82\x24\x78\x38\x42\x2b\x8b\xce\xce\x50\x05\xa8\x2e\x4d\x27\x23\xa7\xda\x05\x6b\xa5\xa7\x8a\xcb\x69\x33\xfb\x92\x8b\x13\x9f\x5a\x19\xb3\x3f\xd6\x46\x99\x29\x0c\xe5\xf6\xff\x21\xdf\xae\x51\xf1\x5c\x46\xa8\xc6\x4b\x42\x99\x29\xc9\xdf\x20\x07\xa7\x8a\x33\x5b\xd6\x36\xf2\xcf\x99\x9c\x88\xbc\x6a\x6c\x67\xa0\x55\x98\xd8\x19\x3f\x40\x22\x4d\x97\xe6\x00\x50\x58\xf4\x6d\xdd\x0b\x82\x64\xc8\xdc\x6f\x6f\x34\xb9\xba\x75\xd3\xbf\xd5\x58\x2c\xde\x02\x23\x03\x27\x38\x37\x85\xf8\xc6\xf1\xfd\x26\xf7\xe5\x51\x4a\xa4\x99\xc7\x32\x46\x85\xa4\x99\x76\x8d\x6d\x63\x50\x53\x93\x67\x74\xa3\x46\x55\xd5\xb4\x91\x57\x27\xb1\xc3\x97\xaf\xe4\xfe\x8d\xdc\xf9\x4a\xee\xc1\xaa\x6a\x78\x34\xe1\x75\x87\xb6\x16\x77\xfb\x14\xf1\x57\xb9\xa4\xee\x5e\xef\xce\x98\x31\xbe\x32\x47\x16\xde\x9e\x24\x63\xa1\x61\x10\x82\xaf\x24\x4a\x69\x86\xd3\x6c\xce\x83\x8b\x7c\x61\xe5\xca\x35\xa6\x8d\xbe\x5c\x6a\x36\xff\x9d\x13\x5f\x71\xc1\xe5\xfa\xfb\x06\xbc\xb3\xb9\x27\xe6\xdd\x80\xc0\x3d\x89\xb0\x6a\x5e\x4f\x6f\x45\x59\x33\x03\xe8\xff\x70\x8f\xe1\xdd\x41\x53\xc8\xdf\x66\x54\xef\x91\x7f\x49\x54\x15\x7a\xde\x28\x51\xba\x92\xa4\xed\xf4\xc1\x1c\xd9\xe9\x6e\x21\xf9\x0a\x47\x67\x2b\x22\xde\x6a\x91\x5b\x11\xd1\xb9\x2c\xb4\x3d\xae\x58\x7d\x81\xd7\x15\xe9\x03\x9e\x37\x53\xaf\xf0\xee\x29\x67\x84\xc3\x9b\xd9\xad\x32\xa5\xd1\xee\x4a\xdc\x66\x5e\x91\x7f\x42\xd2\x05\x91\xeb\x3d\x65\x80\x19\x65\x2c\xd0\x2c\x69\x17\x02\xf5\x61\x45\x32\x5f\x2e\x51\x2e\x29\xae\xf6\x97\x07\xd5\x0a\x21\x37\x88\xfd\x84\xe4\x09\x7a\x75\x95\xe6\xd4\xbc\x29\x19\x7e\x88\x37\x57\x92\x47\xa8\xd4\xa1\x6a\xa7\xea\x8e\x28\x45\x7c\xcd\xc5\x93\x1c\xda\x51\x67\x7c\x47\x37\x6d\xc9\xf1\x14\x07\x3b\xbc\x69\x18\x38\x1d\xdd\x70\x4d\x18\x94\x71\x78\x6a\x23\xb3\xc2\x4f\x24\x72\x5f\x9b\x21\xbe\x9b\xf8\x28\x25\x52\x6f\x49\x81\xf2\xa9\x94\x51\x35\xb9\xba\x85\x73\x4e\x62\x18\x2f\x51\xee\xd1\xc7\x38\x89\xeb\x8a\x36\x0f\xab\xaa\xc8\x2c\x26\x10\xf6\xa8\x2e\x77\x2a\x13\x28\x7d\xb3\xff\x77\xe2\xeb\x56\xf9\x8b\x44\x72\x17\xf3\x55\xb6\x4b\xa7\x53\x15\x96\xc3\x76\x2a\x6d\x87\xc6\xc1\xdd\xf9\x3b\x86\x49\xb9\x51\x7f\xa7\x48\x59\x58\x73\x87\xa7\x21\x94\x83\x46\x4b\x05\x80\xe4\x2b\xe8\x3e\xf0\xec\x9d\xc2\xc6\xb0\xf6\x72\xfc\x2f\x7b\xb6\xac\xb9\x2a\x79\x22\xd1\x3e\x5b\x85\xd6\xa7\x6b\xa0\x1f\x12\x09\xd5\x3f\x7e\x6c\x0e\xaa\xd2\x2b\xd7\x11\xd7\x91\x72\xed\x3b\x2a\x3a\x35\x43\x7d\xaf\x52\xd2\xe7\x19\x5b\x7b\xa3\x5f\xb9\x86\x72\xc2\xdc\x21\xb9\x43\xb2\xcd\xe6\x73\xe0\xd2\x6c\xce\x1b\x60\x23\xce\xe2\x97\xa0\x9d\x70\x16\x3f\x15\x6e\xaf\xd7\x89\xbb\xbb\xb1\x3d\x73\x27\x5e\x35\xba\x34\xde\x37\x57\x9f\x67\x26\xe5\x05\xea\x15\x97\x77\xcf\xcc\xca\xde\xeb\xd3\xb1\x30\x5c\x6c\xf6\xcf\x49\xc4\x5e\xb3\x37\x96\x5c\x98\xe0\x6f\x27\x48\x98\x6b\xcd\x37\xf3\x15\xea\x0c\x42\x9d\xf9\x31\xce\x49\xce\x34\x94\x72\xbe\xe6\x49\xc2\xd0\x2b\x1e\x9d\x3b\x21\xc7\x73\xe6\x50\xfa\x0a\x19\x46\xf6\x08\xb0\x31\x06\x31\xd1\xa4\x10\xad\x60\x00\x22\x29\xf1\x53\xa2\x04\x17\xb9\x38\xf3\xb4\xcc\xb1\x68\xc4\x7b\x41\xb2\x18\xe3\x33\x6f\x4e\x98\xc2\x8e\x10\x73\xe1\xd5\x6d\xb8\x9c\xeb\xee\xf8\xaa\x05\x66\x44\x24\x56\xc6\xf6\xca\x48\x70\x9e\xb5\x58\xca\x59\xb7\x49\xaf\x49\xb0\xbf\xc0\x2c\xf7\x40\x72\xe3\xb1\xfb\x6d\x1d\xb3\xd5\x25\xc3\x38\x5c\xef\x65\xac\x1d\xf3\xc5\xe3\xa1\x3d\x61\xfb\x9c\x05\x39\x95\x3c\x4f\x52\x91\xeb\xf6\x2a\xb8\x59\x96\x4b\x78\xe1\x5a\xa3\x6a\x6f\xdf\x2f\x30\xfb\x59\x4a\x6e\x1f\x1f\xb7\xb6\x80\xd2\x16\xda\x11\xbb\x8d\x35\x9c\x6f\x64\xe8\x17\xf5\xc3\xb6\xcc\x2f\x94\xa1\x5a\x2b\x8d\x8b\xa7\x57\x90\xf3\x8d\x8c\xdb\xfb\x3a\x8b\xc8\xdd\x9a\x76\x2c\x53\x93\x5c\x69\xbe\xf8\x8a\x5a\xd2\xe8\xb9\x7c\x1c\x58\xac\x7a\xfb\x18\x18\xbb\xdb\x73\x13\xc7\x50\x58\x6f\xae\x58\xfb\x62\xa5\x51\x4b\x59\x27\xfc\x85\xd3\x73\x30\x1e\x7a\xcd\xc3\x66\xc7\x2d\xc8\x0f\x0b\x8d\x8e\xbb\x93\x43\xd1\xf1\xb4\xa2\x4a\x80\xa9\x9b\x6d\x59\xf3\xb1\xb9\x5e\xd0\x4c\xe4\xba\x56\xea\x56\x6f\x48\xfc\xd8\x5d\xf8\xf9\x11\xcf\x33\xed\x75\xee\xdf\x9b\xad\xbb\x4b\xce\xaa\xdf\x21\xb7\x24\x2c\xc7\xb3\xe3\xa3\x06\xe4\xdd\x0b\x4d\x27\xc2\x5a\x35\xd8\xd0\xd4\xbd\x00\xbe\x90\x43\x57\x8c\x1c\xa4\xb1\x28\x23\xfe\x9e\x4c\xd6\x4a\x2d\x67\x45\x72\xc6\x2a\x66\x42\xc6\xa3\x3b\xaf\xab\x7e\xde\xe7\xdc\xcb\x27\x61\xc7\x42\xdd\xd1\x59\xed\xaa\x74\xec\xbf\xa3\x2f\x85\x13\xfb\x2e\x53\x60\x11\xaa\x40\xa1\xbe\xcc\xcc\x39\x72\x42\x18\x0b\x49\x74\xf7\x4e\x69\x22\xf5\x15\x49\xf0\xdd\xc3\x43\xb0\xb9\x4f\x75\xf7\xdc\xef\xc1\xb4\xd5\x4e\xe3\xb6\xa9\x75\xf8\xb2\xad\xee\x02\xd9\xfe\x2c\x6f\x93\x7f\xb6\x2f\x3a\x99\x4f\x2c\xc9\xca\xdd\x96\x18\x3b\xf5\x8b\x99\x62\x50\xfd\x85\x01\xf7\x9e\xc0\x70\xe0\xde\xa2\xf9\x7f\x00\x00\x00\xff\xff\x19\x81\xf2\xde\xa8\x25\x00\x00") func cmdInternalPagesAssetsHtmlContainersHtmlBytes() ([]byte, error) { return bindataRead( _cmdInternalPagesAssetsHtmlContainersHtml, "cmd/internal/pages/assets/html/containers.html", ) } func cmdInternalPagesAssetsHtmlContainersHtml() (*asset, error) { bytes, err := cmdInternalPagesAssetsHtmlContainersHtmlBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "cmd/internal/pages/assets/html/containers.html", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3b, 0xb9, 0x8c, 0xe6, 0xbf, 0xf1, 0x9d, 0x7, 0xe7, 0xbc, 0xd5, 0xf1, 0xb1, 0xc2, 0x47, 0xe5, 0x2e, 0x76, 0xdf, 0x59, 0x12, 0x64, 0x50, 0x9d, 0x91, 0xb3, 0xaf, 0xb3, 0x1, 0x60, 0xd, 0x6c}} return a, nil } // Asset loads and returns the asset for the given name. // It returns an error if the asset could not be found or // could not be loaded. func Asset(name string) ([]byte, error) { canonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) } return a.bytes, nil } return nil, fmt.Errorf("Asset %s not found", name) } // AssetString returns the asset contents as a string (instead of a []byte). func AssetString(name string) (string, error) { data, err := Asset(name) return string(data), err } // MustAsset is like Asset but panics when Asset would return an error. // It simplifies safe initialization of global variables. func MustAsset(name string) []byte { a, err := Asset(name) if err != nil { panic("asset: Asset(" + name + "): " + err.Error()) } return a } // MustAssetString is like AssetString but panics when Asset would return an // error. It simplifies safe initialization of global variables. func MustAssetString(name string) string { return string(MustAsset(name)) } // AssetInfo loads and returns the asset info for the given name. // It returns an error if the asset could not be found or // could not be loaded. func AssetInfo(name string) (os.FileInfo, error) { canonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) } return a.info, nil } return nil, fmt.Errorf("AssetInfo %s not found", name) } // AssetDigest returns the digest of the file with the given name. It returns an // error if the asset could not be found or the digest could not be loaded. func AssetDigest(name string) ([sha256.Size]byte, error) { canonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err) } return a.digest, nil } return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name) } // Digests returns a map of all known files and their checksums. func Digests() (map[string][sha256.Size]byte, error) { mp := make(map[string][sha256.Size]byte, len(_bindata)) for name := range _bindata { a, err := _bindata[name]() if err != nil { return nil, err } mp[name] = a.digest } return mp, nil } // AssetNames returns the names of the assets. func AssetNames() []string { names := make([]string, 0, len(_bindata)) for name := range _bindata { names = append(names, name) } return names } // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ "cmd/internal/pages/assets/html/containers.html": cmdInternalPagesAssetsHtmlContainersHtml, } // AssetDebug is true if the assets were built with the debug flag enabled. const AssetDebug = false // AssetDir returns the file names below a certain // directory embedded in the file by go-bindata. // For example if you run go-bindata on data/... and data contains the // following hierarchy: // // data/ // foo.txt // img/ // a.png // b.png // // then AssetDir("data") would return []string{"foo.txt", "img"}, // AssetDir("data/img") would return []string{"a.png", "b.png"}, // AssetDir("foo.txt") and AssetDir("notexist") would return an error, and // AssetDir("") will return []string{"data"}. func AssetDir(name string) ([]string, error) { node := _bintree if len(name) != 0 { canonicalName := strings.Replace(name, "\\", "/", -1) pathList := strings.Split(canonicalName, "/") for _, p := range pathList { node = node.Children[p] if node == nil { return nil, fmt.Errorf("Asset %s not found", name) } } } if node.Func != nil { return nil, fmt.Errorf("Asset %s not found", name) } rv := make([]string, 0, len(node.Children)) for childName := range node.Children { rv = append(rv, childName) } return rv, nil } type bintree struct { Func func() (*asset, error) Children map[string]*bintree } var _bintree = &bintree{nil, map[string]*bintree{ "cmd": {nil, map[string]*bintree{ "internal": {nil, map[string]*bintree{ "pages": {nil, map[string]*bintree{ "assets": {nil, map[string]*bintree{ "html": {nil, map[string]*bintree{ "containers.html": {cmdInternalPagesAssetsHtmlContainersHtml, map[string]*bintree{}}, }}, }}, }}, }}, }}, }} // RestoreAsset restores an asset under the given directory. func RestoreAsset(dir, name string) error { data, err := Asset(name) if err != nil { return err } info, err := AssetInfo(name) if err != nil { return err } err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) if err != nil { return err } err = os.WriteFile(_filePath(dir, name), data, info.Mode()) if err != nil { return err } return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) } // RestoreAssets restores an asset under the given directory recursively. func RestoreAssets(dir, name string) error { children, err := AssetDir(name) // File if err != nil { return RestoreAsset(dir, name) } // Dir for _, child := range children { err = RestoreAssets(dir, filepath.Join(name, child)) if err != nil { return err } } return nil } func _filePath(dir, name string) string { canonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...) } ================================================ FILE: cmd/internal/storage/bigquery/README.md ================================================ BigQuery Storage Driver ======= [EXPERIMENTAL] Support for BigQuery backend as cAdvisor storage driver. The current implementation takes bunch of BigQuery specific flags for authentication. These will be merged into a single backend config. To run the current version, following flags need to be specified: ``` # Storage driver to use. -storage_driver=bigquery # Information about server-to-server Oauth token. # These can be obtained by creating a Service Account client id under `Google Developer API` # service client id -bq_id="XYZ.apps.googleusercontent.com" # service email address -bq_account="ABC@developer.gserviceaccount.com" # path to pem key (converted from p12 file) -bq_credentials_file="/path/to/key.pem" # project id to use for storing datasets. -bq_project_id="awesome_project" ``` See [Service account Authentication](https://developers.google.com/accounts/docs/OAuth2) for Oauth related details. ================================================ FILE: cmd/internal/storage/bigquery/bigquery.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package bigquery import ( "os" "github.com/google/cadvisor/cmd/internal/storage/bigquery/client" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/storage" bigquery "google.golang.org/api/bigquery/v2" ) func init() { storage.RegisterStorageDriver("bigquery", new) } type bigqueryStorage struct { client *client.Client machineName string } const ( // Bigquery schema types typeTimestamp string = "TIMESTAMP" typeString string = "STRING" typeInteger string = "INTEGER" colTimestamp string = "timestamp" colMachineName string = "machine" colContainerName string = "container_name" colCPUCumulativeUsage string = "cpu_cumulative_usage" // Cumulative CPU usage in system and user mode colCPUCumulativeUsageSystem string = "cpu_cumulative_usage_system" colCPUCumulativeUsageUser string = "cpu_cumulative_usage_user" // Memory usage colMemoryUsage string = "memory_usage" // Working set size colMemoryWorkingSet string = "memory_working_set" // Total active file size colMemoryTotalActiveFile string = "memory_total_active_file" // Total inactive file size colMemoryTotalInactiveFile string = "memory_total_inactive_file" // Container page fault colMemoryContainerPgfault string = "memory_container_pgfault" // Constainer major page fault colMemoryContainerPgmajfault string = "memory_container_pgmajfault" // Hierarchical page fault colMemoryHierarchicalPgfault string = "memory_hierarchical_pgfault" // Hierarchical major page fault colMemoryHierarchicalPgmajfault string = "memory_hierarchical_pgmajfault" // Cumulative count of bytes received. colRxBytes string = "rx_bytes" // Cumulative count of receive errors encountered. colRxErrors string = "rx_errors" // Cumulative count of bytes transmitted. colTxBytes string = "tx_bytes" // Cumulative count of transmit errors encountered. colTxErrors string = "tx_errors" // Filesystem device. colFsDevice = "fs_device" // Filesystem limit. colFsLimit = "fs_limit" // Filesystem available space. colFsUsage = "fs_usage" ) func new() (storage.StorageDriver, error) { hostname, err := os.Hostname() if err != nil { return nil, err } return newStorage( hostname, *storage.ArgDbTable, *storage.ArgDbName, ) } // TODO(jnagal): Infer schema through reflection. (See bigquery/client/example) func (s *bigqueryStorage) GetSchema() *bigquery.TableSchema { fields := make([]*bigquery.TableFieldSchema, 19) i := 0 fields[i] = &bigquery.TableFieldSchema{ Type: typeTimestamp, Name: colTimestamp, Mode: "REQUIRED", } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeString, Name: colMachineName, Mode: "REQUIRED", } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeString, Name: colContainerName, Mode: "REQUIRED", } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colCPUCumulativeUsage, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colCPUCumulativeUsageSystem, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colCPUCumulativeUsageUser, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colMemoryUsage, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colMemoryWorkingSet, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colMemoryTotalActiveFile, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colMemoryTotalInactiveFile, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colMemoryContainerPgfault, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colMemoryContainerPgmajfault, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colMemoryHierarchicalPgfault, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colMemoryHierarchicalPgmajfault, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colRxBytes, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colRxErrors, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colTxBytes, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colTxErrors, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeString, Name: colFsDevice, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colFsLimit, } i++ fields[i] = &bigquery.TableFieldSchema{ Type: typeInteger, Name: colFsUsage, } return &bigquery.TableSchema{ Fields: fields, } } func (s *bigqueryStorage) containerStatsToRows( cInfo *info.ContainerInfo, stats *info.ContainerStats, ) (row map[string]interface{}) { row = make(map[string]interface{}) // Timestamp row[colTimestamp] = stats.Timestamp // Machine name row[colMachineName] = s.machineName // Container name name := cInfo.ContainerReference.Name if len(cInfo.ContainerReference.Aliases) > 0 { name = cInfo.ContainerReference.Aliases[0] } row[colContainerName] = name // Cumulative Cpu Usage row[colCPUCumulativeUsage] = stats.Cpu.Usage.Total // Cumulative Cpu Usage in system mode row[colCPUCumulativeUsageSystem] = stats.Cpu.Usage.System // Cumulative Cpu Usage in user mode row[colCPUCumulativeUsageUser] = stats.Cpu.Usage.User // Memory Usage row[colMemoryUsage] = stats.Memory.Usage // Working set size row[colMemoryWorkingSet] = stats.Memory.WorkingSet // Total active file size row[colMemoryTotalActiveFile] = stats.Memory.TotalActiveFile // Total inactive file size row[colMemoryTotalInactiveFile] = stats.Memory.TotalInactiveFile // container page fault row[colMemoryContainerPgfault] = stats.Memory.ContainerData.Pgfault // container major page fault row[colMemoryContainerPgmajfault] = stats.Memory.ContainerData.Pgmajfault // hierarchical page fault row[colMemoryHierarchicalPgfault] = stats.Memory.HierarchicalData.Pgfault // hierarchical major page fault row[colMemoryHierarchicalPgmajfault] = stats.Memory.HierarchicalData.Pgmajfault // Network stats. row[colRxBytes] = stats.Network.RxBytes row[colRxErrors] = stats.Network.RxErrors row[colTxBytes] = stats.Network.TxBytes row[colTxErrors] = stats.Network.TxErrors // TODO(jnagal): Handle per-cpu stats. return } func (s *bigqueryStorage) containerFilesystemStatsToRows( cInfo *info.ContainerInfo, stats *info.ContainerStats, ) (rows []map[string]interface{}) { for _, fsStat := range stats.Filesystem { row := make(map[string]interface{}) row[colFsDevice] = fsStat.Device row[colFsLimit] = fsStat.Limit row[colFsUsage] = fsStat.Usage rows = append(rows, row) } return rows } func (s *bigqueryStorage) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error { if stats == nil { return nil } rows := make([]map[string]interface{}, 0) rows = append(rows, s.containerStatsToRows(cInfo, stats)) rows = append(rows, s.containerFilesystemStatsToRows(cInfo, stats)...) for _, row := range rows { err := s.client.InsertRow(row) if err != nil { return err } } return nil } func (s *bigqueryStorage) Close() error { s.client.Close() s.client = nil return nil } // Create a new bigquery storage driver. // machineName: A unique identifier to identify the host that current cAdvisor // instance is running on. // tableName: BigQuery table used for storing stats. func newStorage(machineName, datasetID, tableName string) (storage.StorageDriver, error) { bqClient, err := client.NewClient() if err != nil { return nil, err } err = bqClient.CreateDataset(datasetID) if err != nil { return nil, err } ret := &bigqueryStorage{ client: bqClient, machineName: machineName, } schema := ret.GetSchema() err = bqClient.CreateTable(tableName, schema) if err != nil { return nil, err } return ret, nil } ================================================ FILE: cmd/internal/storage/bigquery/client/client.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package client import ( "context" "errors" "flag" "fmt" "os" "strings" "golang.org/x/oauth2" "golang.org/x/oauth2/jwt" bigquery "google.golang.org/api/bigquery/v2" "google.golang.org/api/option" ) var ( // TODO(jnagal): Condense all flags to an identity file and a pem key file. clientID = flag.String("bq_id", "", "Client ID") clientSecret = flag.String("bq_secret", "notasecret", "Client Secret") projectID = flag.String("bq_project_id", "", "Bigquery project ID") serviceAccount = flag.String("bq_account", "", "Service account email") pemFile = flag.String("bq_credentials_file", "", "Credential Key file (pem)") ) const ( errAlreadyExists string = "Error 409: Already Exists" ) type Client struct { service *bigquery.Service token *oauth2.Token datasetID string tableID string } // Helper method to create an authenticated connection. func connect() (*oauth2.Token, *bigquery.Service, error) { if *clientID == "" { return nil, nil, fmt.Errorf("no client id specified") } if *serviceAccount == "" { return nil, nil, fmt.Errorf("no service account specified") } if *projectID == "" { return nil, nil, fmt.Errorf("no project id specified") } authScope := bigquery.BigqueryScope if *pemFile == "" { return nil, nil, fmt.Errorf("no credentials specified") } pemBytes, err := os.ReadFile(*pemFile) if err != nil { return nil, nil, fmt.Errorf("could not access credential file %v - %v", pemFile, err) } jwtConfig := &jwt.Config{ Email: *serviceAccount, Scopes: []string{authScope}, PrivateKey: pemBytes, TokenURL: "https://accounts.google.com/o/oauth2/token", } token, err := jwtConfig.TokenSource(context.Background()).Token() if err != nil { return nil, nil, err } if !token.Valid() { return nil, nil, fmt.Errorf("invalid token for BigQuery oauth") } config := &oauth2.Config{ ClientID: *clientID, ClientSecret: *clientSecret, Scopes: []string{authScope}, Endpoint: oauth2.Endpoint{ AuthURL: "https://accounts.google.com/o/oauth2/auth", TokenURL: "https://accounts.google.com/o/oauth2/token", }, } client := config.Client(context.Background(), token) service, err := bigquery.NewService(context.Background(), option.WithHTTPClient(client)) if err != nil { fmt.Printf("Failed to create new service: %v\n", err) return nil, nil, err } return token, service, nil } // Creates a new client instance with an authenticated connection to bigquery. func NewClient() (*Client, error) { token, service, err := connect() if err != nil { return nil, err } c := &Client{ token: token, service: service, } return c, nil } func (c *Client) Close() error { c.service = nil return nil } // Helper method to return the bigquery service connection. // Expired connection is refreshed. func (c *Client) getService() (*bigquery.Service, error) { if c.token == nil || c.service == nil { return nil, fmt.Errorf("service not initialized") } // Refresh expired token. if !c.token.Valid() { token, service, err := connect() if err != nil { return nil, err } c.token = token c.service = service return service, nil } return c.service, nil } func (c *Client) PrintDatasets() error { datasetList, err := c.service.Datasets.List(*projectID).Do() if err != nil { fmt.Printf("Failed to get list of datasets\n") return err } fmt.Printf("Successfully retrieved datasets. Retrieved: %d\n", len(datasetList.Datasets)) for _, d := range datasetList.Datasets { fmt.Printf("%s %s\n", d.Id, d.FriendlyName) } return nil } func (c *Client) CreateDataset(datasetID string) error { if c.service == nil { return fmt.Errorf("no service created") } _, err := c.service.Datasets.Insert(*projectID, &bigquery.Dataset{ DatasetReference: &bigquery.DatasetReference{ DatasetId: datasetID, ProjectId: *projectID, }, }).Do() // TODO(jnagal): Do a Get() to verify dataset already exists. if err != nil && !strings.Contains(err.Error(), errAlreadyExists) { return err } c.datasetID = datasetID return nil } // Create a table with provided table ID and schema. // Schema is currently not updated if the table already exists. func (c *Client) CreateTable(tableID string, schema *bigquery.TableSchema) error { if c.service == nil || c.datasetID == "" { return fmt.Errorf("no dataset created") } _, err := c.service.Tables.Get(*projectID, c.datasetID, tableID).Do() if err != nil { // Create a new table. _, err := c.service.Tables.Insert(*projectID, c.datasetID, &bigquery.Table{ Schema: schema, TableReference: &bigquery.TableReference{ DatasetId: c.datasetID, ProjectId: *projectID, TableId: tableID, }, }).Do() if err != nil { return err } } // TODO(jnagal): Update schema if it has changed. We can only extend existing schema. c.tableID = tableID return nil } // Add a row to the connected table. func (c *Client) InsertRow(rowData map[string]interface{}) error { service, _ := c.getService() if service == nil || c.datasetID == "" || c.tableID == "" { return fmt.Errorf("table not setup to add rows") } jsonRows := make(map[string]bigquery.JsonValue) for key, value := range rowData { jsonRows[key] = bigquery.JsonValue(value) } rows := []*bigquery.TableDataInsertAllRequestRows{ { Json: jsonRows, }, } // TODO(jnagal): Batch insert requests. insertRequest := &bigquery.TableDataInsertAllRequest{Rows: rows} result, err := service.Tabledata.InsertAll(*projectID, c.datasetID, c.tableID, insertRequest).Do() if err != nil { return fmt.Errorf("error inserting row: %v", err) } if len(result.InsertErrors) > 0 { errstr := fmt.Sprintf("Insertion for %d rows failed\n", len(result.InsertErrors)) for _, errors := range result.InsertErrors { for _, errorproto := range errors.Errors { errstr += fmt.Sprintf("Error inserting row %d: %+v\n", errors.Index, errorproto) } } return errors.New(errstr) } return nil } ================================================ FILE: cmd/internal/storage/bigquery/client/example/example.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "flag" "fmt" "time" "github.com/SeanDolphin/bqschema" "github.com/google/cadvisor/cmd/internal/storage/bigquery/client" ) type container struct { Name string `json:"name"` CpuUsage uint64 `json:"cpuusage,omitempty"` MemoryUsage uint64 `json:"memoryusage,omitempty"` NetworkUsage uint64 `json:"networkusage,omitempty"` Timestamp time.Time `json:"timestamp"` } func main() { flag.Parse() c, err := client.NewClient() if err != nil { fmt.Printf("Failed to connect to bigquery\n") panic(err) } err = c.PrintDatasets() if err != nil { panic(err) } // Create a new dataset. err = c.CreateDataset("sampledataset") if err != nil { fmt.Printf("Failed to create dataset %v\n", err) panic(err) } // Create a new table containerData := container{ Name: "test_container", CpuUsage: 123456, MemoryUsage: 1024, NetworkUsage: 9046, Timestamp: time.Now(), } schema, err := bqschema.ToSchema(containerData) if err != nil { fmt.Printf("Failed to create schema") panic(err) } err = c.CreateTable("sampletable", schema) if err != nil { fmt.Printf("Failed to create table") panic(err) } // Add Data m := make(map[string]interface{}) t := time.Now() for i := 0; i < 10; i++ { m["Name"] = containerData.Name m["CpuUsage"] = containerData.CpuUsage + uint64(i*100) m["MemoryUsage"] = containerData.MemoryUsage - uint64(i*10) m["NetworkUsage"] = containerData.NetworkUsage + uint64(i*10) m["Timestamp"] = t.Add(time.Duration(i) * time.Second) err = c.InsertRow(m) if err != nil { fmt.Printf("Failed to insert row") panic(err) } } } ================================================ FILE: cmd/internal/storage/elasticsearch/elasticsearch.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package elasticsearch import ( "flag" "fmt" "os" "sync" "time" info "github.com/google/cadvisor/info/v1" storage "github.com/google/cadvisor/storage" "gopkg.in/olivere/elastic.v2" ) func init() { storage.RegisterStorageDriver("elasticsearch", new) } type elasticStorage struct { client *elastic.Client machineName string indexName string typeName string lock sync.Mutex } type detailSpec struct { Timestamp int64 `json:"timestamp"` MachineName string `json:"machine_name,omitempty"` ContainerName string `json:"container_Name,omitempty"` ContainerStats *info.ContainerStats `json:"container_stats,omitempty"` } var ( argElasticHost = flag.String("storage_driver_es_host", "http://localhost:9200", "ElasticSearch host:port") argIndexName = flag.String("storage_driver_es_index", "cadvisor", "ElasticSearch index name") argTypeName = flag.String("storage_driver_es_type", "stats", "ElasticSearch type name") argEnableSniffer = flag.Bool("storage_driver_es_enable_sniffer", false, "ElasticSearch uses a sniffing process to find all nodes of your cluster by default, automatically") ) func new() (storage.StorageDriver, error) { hostname, err := os.Hostname() if err != nil { return nil, err } return newStorage( hostname, *argIndexName, *argTypeName, *argElasticHost, *argEnableSniffer, ) } func (s *elasticStorage) containerStatsAndDefaultValues( cInfo *info.ContainerInfo, stats *info.ContainerStats) *detailSpec { timestamp := stats.Timestamp.UnixNano() / 1e3 var containerName string if len(cInfo.ContainerReference.Aliases) > 0 { containerName = cInfo.ContainerReference.Aliases[0] } else { containerName = cInfo.ContainerReference.Name } detail := &detailSpec{ Timestamp: timestamp, MachineName: s.machineName, ContainerName: containerName, ContainerStats: stats, } return detail } func (s *elasticStorage) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error { if stats == nil { return nil } func() { // AddStats will be invoked simultaneously from multiple threads and only one of them will perform a write. s.lock.Lock() defer s.lock.Unlock() // Add some default params based on ContainerStats detail := s.containerStatsAndDefaultValues(cInfo, stats) // Index a cadvisor (using JSON serialization) _, err := s.client.Index(). Index(s.indexName). Type(s.typeName). BodyJson(detail). Do() if err != nil { // Handle error fmt.Printf("failed to write stats to ElasticSearch - %s", err) return } }() return nil } func (s *elasticStorage) Close() error { s.client = nil return nil } // machineName: A unique identifier to identify the host that current cAdvisor // instance is running on. // ElasticHost: The host which runs ElasticSearch. func newStorage( machineName, indexName, typeName, elasticHost string, enableSniffer bool, ) (storage.StorageDriver, error) { // Obtain a client and connect to the default Elasticsearch installation // on 127.0.0.1:9200. Of course you can configure your client to connect // to other hosts and configure it in various other ways. client, err := elastic.NewClient( elastic.SetHealthcheck(true), elastic.SetSniff(enableSniffer), elastic.SetHealthcheckInterval(30*time.Second), elastic.SetURL(elasticHost), ) if err != nil { // Handle error return nil, fmt.Errorf("failed to create the elasticsearch client - %s", err) } // Ping the Elasticsearch server to get e.g. the version number info, code, err := client.Ping().URL(elasticHost).Do() if err != nil { // Handle error return nil, fmt.Errorf("failed to ping the elasticsearch - %s", err) } fmt.Printf("Elasticsearch returned with code %d and version %s", code, info.Version.Number) ret := &elasticStorage{ client: client, machineName: machineName, indexName: indexName, typeName: typeName, } return ret, nil } ================================================ FILE: cmd/internal/storage/influxdb/influxdb.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package influxdb import ( "flag" "fmt" "net/url" "os" "sync" "time" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/storage" "github.com/google/cadvisor/version" influxdb "github.com/influxdb/influxdb/client" ) func init() { storage.RegisterStorageDriver("influxdb", new) } var argDbRetentionPolicy = flag.String("storage_driver_influxdb_retention_policy", "", "retention policy") type influxdbStorage struct { client *influxdb.Client machineName string database string retentionPolicy string bufferDuration time.Duration lastWrite time.Time points []*influxdb.Point lock sync.Mutex readyToFlush func() bool } // Series names const ( // Cumulative CPU usage serCPUUsageTotal string = "cpu_usage_total" serCPUUsageSystem string = "cpu_usage_system" serCPUUsageUser string = "cpu_usage_user" serCPUUsagePerCPU string = "cpu_usage_per_cpu" // Smoothed average of number of runnable threads x 1000. serLoadAverage string = "load_average" // Memory Usage serMemoryUsage string = "memory_usage" // Maximum memory usage recorded serMemoryMaxUsage string = "memory_max_usage" // //Number of bytes of page cache memory serMemoryCache string = "memory_cache" // Size of RSS serMemoryRss string = "memory_rss" // Container swap usage serMemorySwap string = "memory_swap" // Size of memory mapped files in bytes serMemoryMappedFile string = "memory_mapped_file" // Working set size serMemoryWorkingSet string = "memory_working_set" // Total active file size serMemoryTotalActiveFile string = "memory_total_active_file" // Total inactive file size serMemoryTotalInactiveFile string = "memory_total_inactive_file" // Number of memory usage hits limits serMemoryFailcnt string = "memory_failcnt" // Cumulative count of memory allocation failures serMemoryFailure string = "memory_failure" // Cumulative count of bytes received. serRxBytes string = "rx_bytes" // Cumulative count of receive errors encountered. serRxErrors string = "rx_errors" // Cumulative count of bytes transmitted. serTxBytes string = "tx_bytes" // Cumulative count of transmit errors encountered. serTxErrors string = "tx_errors" // Filesystem limit. serFsLimit string = "fs_limit" // Filesystem usage. serFsUsage string = "fs_usage" // Hugetlb stat - current res_counter usage for hugetlb setHugetlbUsage = "hugetlb_usage" // Hugetlb stat - maximum usage ever recorded setHugetlbMaxUsage = "hugetlb_max_usage" // Hugetlb stat - number of times hugetlb usage allocation failure setHugetlbFailcnt = "hugetlb_failcnt" // Perf statistics serPerfStat = "perf_stat" // Referenced memory serReferencedMemory = "referenced_memory" // Resctrl - Total memory bandwidth serResctrlMemoryBandwidthTotal = "resctrl_memory_bandwidth_total" // Resctrl - Local memory bandwidth serResctrlMemoryBandwidthLocal = "resctrl_memory_bandwidth_local" // Resctrl - Last level cache usage serResctrlLLCOccupancy = "resctrl_llc_occupancy" ) func new() (storage.StorageDriver, error) { hostname, err := os.Hostname() if err != nil { return nil, err } return newStorage( hostname, *storage.ArgDbTable, *storage.ArgDbName, *argDbRetentionPolicy, *storage.ArgDbUsername, *storage.ArgDbPassword, *storage.ArgDbHost, *storage.ArgDbIsSecure, *storage.ArgDbBufferDuration, ) } // Field names const ( fieldValue string = "value" fieldType string = "type" fieldDevice string = "device" ) // Tag names const ( tagMachineName string = "machine" tagContainerName string = "container_name" ) func (s *influxdbStorage) containerFilesystemStatsToPoints( cInfo *info.ContainerInfo, stats *info.ContainerStats) (points []*influxdb.Point) { if len(stats.Filesystem) == 0 { return points } for _, fsStat := range stats.Filesystem { tagsFsUsage := map[string]string{ fieldDevice: fsStat.Device, fieldType: "usage", } fieldsFsUsage := map[string]interface{}{ fieldValue: int64(fsStat.Usage), } pointFsUsage := &influxdb.Point{ Measurement: serFsUsage, Tags: tagsFsUsage, Fields: fieldsFsUsage, } tagsFsLimit := map[string]string{ fieldDevice: fsStat.Device, fieldType: "limit", } fieldsFsLimit := map[string]interface{}{ fieldValue: int64(fsStat.Limit), } pointFsLimit := &influxdb.Point{ Measurement: serFsLimit, Tags: tagsFsLimit, Fields: fieldsFsLimit, } points = append(points, pointFsUsage, pointFsLimit) } s.tagPoints(cInfo, stats, points) return points } // Set tags and timestamp for all points of the batch. // Points should inherit the tags that are set for BatchPoints, but that does not seem to work. func (s *influxdbStorage) tagPoints(cInfo *info.ContainerInfo, stats *info.ContainerStats, points []*influxdb.Point) { // Use container alias if possible var containerName string if len(cInfo.ContainerReference.Aliases) > 0 { containerName = cInfo.ContainerReference.Aliases[0] } else { containerName = cInfo.ContainerReference.Name } commonTags := map[string]string{ tagMachineName: s.machineName, tagContainerName: containerName, } for i := 0; i < len(points); i++ { // merge with existing tags if any addTagsToPoint(points[i], commonTags) addTagsToPoint(points[i], cInfo.Spec.Labels) points[i].Time = stats.Timestamp } } func (s *influxdbStorage) containerStatsToPoints( cInfo *info.ContainerInfo, stats *info.ContainerStats, ) (points []*influxdb.Point) { // CPU usage: Total usage in nanoseconds points = append(points, makePoint(serCPUUsageTotal, stats.Cpu.Usage.Total)) // CPU usage: Time spend in system space (in nanoseconds) points = append(points, makePoint(serCPUUsageSystem, stats.Cpu.Usage.System)) // CPU usage: Time spent in user space (in nanoseconds) points = append(points, makePoint(serCPUUsageUser, stats.Cpu.Usage.User)) // CPU usage per CPU for i := 0; i < len(stats.Cpu.Usage.PerCpu); i++ { point := makePoint(serCPUUsagePerCPU, stats.Cpu.Usage.PerCpu[i]) tags := map[string]string{"instance": fmt.Sprintf("%v", i)} addTagsToPoint(point, tags) points = append(points, point) } // Load Average points = append(points, makePoint(serLoadAverage, stats.Cpu.LoadAverage)) // Network Stats points = append(points, makePoint(serRxBytes, stats.Network.RxBytes)) points = append(points, makePoint(serRxErrors, stats.Network.RxErrors)) points = append(points, makePoint(serTxBytes, stats.Network.TxBytes)) points = append(points, makePoint(serTxErrors, stats.Network.TxErrors)) // Referenced Memory points = append(points, makePoint(serReferencedMemory, stats.ReferencedMemory)) s.tagPoints(cInfo, stats, points) return points } func (s *influxdbStorage) memoryStatsToPoints( cInfo *info.ContainerInfo, stats *info.ContainerStats, ) (points []*influxdb.Point) { // Memory Usage points = append(points, makePoint(serMemoryUsage, stats.Memory.Usage)) // Maximum memory usage recorded points = append(points, makePoint(serMemoryMaxUsage, stats.Memory.MaxUsage)) //Number of bytes of page cache memory points = append(points, makePoint(serMemoryCache, stats.Memory.Cache)) // Size of RSS points = append(points, makePoint(serMemoryRss, stats.Memory.RSS)) // Container swap usage points = append(points, makePoint(serMemorySwap, stats.Memory.Swap)) // Size of memory mapped files in bytes points = append(points, makePoint(serMemoryMappedFile, stats.Memory.MappedFile)) // Working Set Size points = append(points, makePoint(serMemoryWorkingSet, stats.Memory.WorkingSet)) // Total Active File Size points = append(points, makePoint(serMemoryTotalActiveFile, stats.Memory.TotalActiveFile)) // Total Inactive File Size points = append(points, makePoint(serMemoryTotalInactiveFile, stats.Memory.TotalInactiveFile)) // Number of memory usage hits limits points = append(points, makePoint(serMemoryFailcnt, stats.Memory.Failcnt)) // Cumulative count of memory allocation failures memoryFailuresTags := map[string]string{ "failure_type": "pgfault", "scope": "container", } memoryFailurePoint := makePoint(serMemoryFailure, stats.Memory.ContainerData.Pgfault) addTagsToPoint(memoryFailurePoint, memoryFailuresTags) points = append(points, memoryFailurePoint) memoryFailuresTags["failure_type"] = "pgmajfault" memoryFailurePoint = makePoint(serMemoryFailure, stats.Memory.ContainerData.Pgmajfault) addTagsToPoint(memoryFailurePoint, memoryFailuresTags) points = append(points, memoryFailurePoint) memoryFailuresTags["failure_type"] = "pgfault" memoryFailuresTags["scope"] = "hierarchical" memoryFailurePoint = makePoint(serMemoryFailure, stats.Memory.HierarchicalData.Pgfault) addTagsToPoint(memoryFailurePoint, memoryFailuresTags) points = append(points, memoryFailurePoint) memoryFailuresTags["failure_type"] = "pgmajfault" memoryFailurePoint = makePoint(serMemoryFailure, stats.Memory.HierarchicalData.Pgmajfault) addTagsToPoint(memoryFailurePoint, memoryFailuresTags) points = append(points, memoryFailurePoint) s.tagPoints(cInfo, stats, points) return points } func (s *influxdbStorage) hugetlbStatsToPoints( cInfo *info.ContainerInfo, stats *info.ContainerStats, ) (points []*influxdb.Point) { for pageSize, hugetlbStat := range stats.Hugetlb { tags := map[string]string{ "page_size": pageSize, } // Hugepage usage point := makePoint(setHugetlbUsage, hugetlbStat.Usage) addTagsToPoint(point, tags) points = append(points, point) //Maximum hugepage usage recorded point = makePoint(setHugetlbMaxUsage, hugetlbStat.MaxUsage) addTagsToPoint(point, tags) points = append(points, point) // Number of hugepage usage hits limits point = makePoint(setHugetlbFailcnt, hugetlbStat.Failcnt) addTagsToPoint(point, tags) points = append(points, point) } s.tagPoints(cInfo, stats, points) return points } func (s *influxdbStorage) perfStatsToPoints( cInfo *info.ContainerInfo, stats *info.ContainerStats, ) (points []*influxdb.Point) { for _, perfStat := range stats.PerfStats { point := makePoint(serPerfStat, perfStat.Value) tags := map[string]string{ "cpu": fmt.Sprintf("%v", perfStat.Cpu), "name": perfStat.Name, "scaling_ratio": fmt.Sprintf("%v", perfStat.ScalingRatio), } addTagsToPoint(point, tags) points = append(points, point) } s.tagPoints(cInfo, stats, points) return points } func (s *influxdbStorage) resctrlStatsToPoints( cInfo *info.ContainerInfo, stats *info.ContainerStats, ) (points []*influxdb.Point) { // Memory bandwidth for nodeID, rdtMemoryBandwidth := range stats.Resctrl.MemoryBandwidth { tags := map[string]string{ "node_id": fmt.Sprintf("%v", nodeID), } point := makePoint(serResctrlMemoryBandwidthTotal, rdtMemoryBandwidth.TotalBytes) addTagsToPoint(point, tags) points = append(points, point) point = makePoint(serResctrlMemoryBandwidthLocal, rdtMemoryBandwidth.LocalBytes) addTagsToPoint(point, tags) points = append(points, point) } // Cache for nodeID, rdtCache := range stats.Resctrl.Cache { tags := map[string]string{ "node_id": fmt.Sprintf("%v", nodeID), } point := makePoint(serResctrlLLCOccupancy, rdtCache.LLCOccupancy) addTagsToPoint(point, tags) points = append(points, point) } s.tagPoints(cInfo, stats, points) return points } func (s *influxdbStorage) OverrideReadyToFlush(readyToFlush func() bool) { s.readyToFlush = readyToFlush } func (s *influxdbStorage) defaultReadyToFlush() bool { return time.Since(s.lastWrite) >= s.bufferDuration } func (s *influxdbStorage) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error { if stats == nil { return nil } var pointsToFlush []*influxdb.Point func() { // AddStats will be invoked simultaneously from multiple threads and only one of them will perform a write. s.lock.Lock() defer s.lock.Unlock() s.points = append(s.points, s.containerStatsToPoints(cInfo, stats)...) s.points = append(s.points, s.memoryStatsToPoints(cInfo, stats)...) s.points = append(s.points, s.hugetlbStatsToPoints(cInfo, stats)...) s.points = append(s.points, s.perfStatsToPoints(cInfo, stats)...) s.points = append(s.points, s.resctrlStatsToPoints(cInfo, stats)...) s.points = append(s.points, s.containerFilesystemStatsToPoints(cInfo, stats)...) if s.readyToFlush() { pointsToFlush = s.points s.points = make([]*influxdb.Point, 0) s.lastWrite = time.Now() } }() if len(pointsToFlush) > 0 { points := make([]influxdb.Point, len(pointsToFlush)) for i, p := range pointsToFlush { points[i] = *p } batchTags := map[string]string{tagMachineName: s.machineName} bp := influxdb.BatchPoints{ Points: points, Database: s.database, RetentionPolicy: s.retentionPolicy, Tags: batchTags, Time: stats.Timestamp, } response, err := s.client.Write(bp) if err != nil || checkResponseForErrors(response) != nil { return fmt.Errorf("failed to write stats to influxDb - %s", err) } } return nil } func (s *influxdbStorage) Close() error { s.client = nil return nil } // machineName: A unique identifier to identify the host that current cAdvisor // instance is running on. // influxdbHost: The host which runs influxdb (host:port) func newStorage( machineName, tablename, database, retentionPolicy, username, password, influxdbHost string, isSecure bool, bufferDuration time.Duration, ) (*influxdbStorage, error) { url := &url.URL{ Scheme: "http", Host: influxdbHost, } if isSecure { url.Scheme = "https" } config := &influxdb.Config{ URL: *url, Username: username, Password: password, UserAgent: fmt.Sprintf("%v/%v", "cAdvisor", version.Info["version"]), } client, err := influxdb.NewClient(*config) if err != nil { return nil, err } ret := &influxdbStorage{ client: client, machineName: machineName, database: database, retentionPolicy: retentionPolicy, bufferDuration: bufferDuration, lastWrite: time.Now(), points: make([]*influxdb.Point, 0), } ret.readyToFlush = ret.defaultReadyToFlush return ret, nil } // Creates a measurement point with a single value field func makePoint(name string, value interface{}) *influxdb.Point { fields := map[string]interface{}{ fieldValue: toSignedIfUnsigned(value), } return &influxdb.Point{ Measurement: name, Fields: fields, } } // Adds additional tags to the existing tags of a point func addTagsToPoint(point *influxdb.Point, tags map[string]string) { if point.Tags == nil { point.Tags = tags } else { for k, v := range tags { point.Tags[k] = v } } } // Checks response for possible errors func checkResponseForErrors(response *influxdb.Response) error { const msg = "failed to write stats to influxDb - %s" if response != nil && response.Err != nil { return fmt.Errorf(msg, response.Err) } if response != nil && response.Results != nil { for _, result := range response.Results { if result.Err != nil { return fmt.Errorf(msg, result.Err) } } } return nil } // Some stats have type unsigned integer, but the InfluxDB client accepts only signed integers. func toSignedIfUnsigned(value interface{}) interface{} { switch v := value.(type) { case uint64: return int64(v) case uint32: return int32(v) case uint16: return int16(v) case uint8: return int8(v) case uint: return int(v) } return value } ================================================ FILE: cmd/internal/storage/influxdb/influxdb_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build influxdb_test // To run unit test: go test -tags influxdb_test package influxdb import ( "fmt" "math/rand" "net/url" "reflect" "testing" "time" "github.com/google/cadvisor/cmd/internal/storage/test" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/storage" influxdb "github.com/influxdb/influxdb/client" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // The duration in seconds for which stats will be buffered in the influxdb driver. const kCacheDuration = 1 type influxDbTestStorageDriver struct { count int buffer int base storage.StorageDriver } func (self *influxDbTestStorageDriver) readyToFlush() bool { return self.count >= self.buffer } func (self *influxDbTestStorageDriver) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error { self.count++ return self.base.AddStats(cInfo, stats) } func (self *influxDbTestStorageDriver) Close() error { return self.base.Close() } func (self *influxDbTestStorageDriver) StatsEq(a, b *info.ContainerStats) bool { if !test.TimeEq(a.Timestamp, b.Timestamp, 10*time.Millisecond) { return false } // Check only the stats populated in influxdb. if !reflect.DeepEqual(a.Cpu.Usage, b.Cpu.Usage) { return false } if a.Memory.Usage != b.Memory.Usage { return false } if a.Memory.WorkingSet != b.Memory.WorkingSet { return false } if a.Memory.TotalActiveFile != b.Memory.TotalActiveFile { return false } if a.Memory.TotalInactiveFile != b.Memory.TotalInactiveFile { return false } if !reflect.DeepEqual(a.Network, b.Network) { return false } if !reflect.DeepEqual(a.Filesystem, b.Filesystem) { return false } return true } func runStorageTest(f func(test.TestStorageDriver, *testing.T), t *testing.T, bufferCount int) { machineName := "machineA" table := "cadvisor_table" database := "cadvisor_test" username := "root" password := "root" hostname := "localhost:8086" retentionPolicy := "cadvisor_test_rp" // percentilesDuration := 10 * time.Minute config := influxdb.Config{ URL: url.URL{Scheme: "http", Host: hostname}, Username: username, Password: password, } client, err := influxdb.NewClient(config) if err != nil { t.Fatal(err) } // Re-create the database first. if err := prepareDatabase(client, database, retentionPolicy); err != nil { t.Fatal(err) } // Delete all data by the end of the call. // defer client.Query(influxdb.Query{Command: fmt.Sprintf("drop database \"%v\"", database)}) driver, err := newStorage(machineName, table, database, retentionPolicy, username, password, hostname, false, time.Duration(bufferCount)) if err != nil { t.Fatal(err) } defer driver.Close() testDriver := &influxDbTestStorageDriver{buffer: bufferCount} driver.OverrideReadyToFlush(testDriver.readyToFlush) testDriver.base = driver // Generate another container's data on same machine. test.StorageDriverFillRandomStatsFunc("containerOnSameMachine", 100, testDriver, t) // Generate another container's data on another machine. driverForAnotherMachine, err := newStorage("machineB", table, database, retentionPolicy, username, password, hostname, false, time.Duration(bufferCount)) if err != nil { t.Fatal(err) } defer driverForAnotherMachine.Close() testDriverOtherMachine := &influxDbTestStorageDriver{buffer: bufferCount} driverForAnotherMachine.OverrideReadyToFlush(testDriverOtherMachine.readyToFlush) testDriverOtherMachine.base = driverForAnotherMachine test.StorageDriverFillRandomStatsFunc("containerOnAnotherMachine", 100, testDriverOtherMachine, t) f(testDriver, t) } func prepareDatabase(client *influxdb.Client, database string, retentionPolicy string) error { dropDbQuery := influxdb.Query{ Command: fmt.Sprintf("drop database \"%v\"", database), } createDbQuery := influxdb.Query{ Command: fmt.Sprintf("create database \"%v\"", database), } // A default retention policy must always be present. // Depending on the InfluxDB configuration it may be created automatically with the database or not. // TODO create ret. policy only if not present createPolicyQuery := influxdb.Query{ Command: fmt.Sprintf("create retention policy \"%v\" on \"%v\" duration 1h replication 1 default", retentionPolicy, database), } _, err := client.Query(dropDbQuery) if err != nil { return err } _, err = client.Query(createDbQuery) if err != nil { return err } _, err = client.Query(createPolicyQuery) return err } func TestContainerFileSystemStatsToPoints(t *testing.T) { assert := assert.New(t) machineName := "testMachine" table := "cadvisor_table" database := "cadvisor_test" retentionPolicy := "cadvisor_test_rp" username := "root" password := "root" influxdbHost := "localhost:8086" storage, err := newStorage(machineName, table, database, retentionPolicy, username, password, influxdbHost, false, 2*time.Minute) assert.Nil(err) cInfo := &info.ContainerInfo{ ContainerReference: info.ContainerReference{ Name: "containerName", }, } stats := &info.ContainerStats{} points := storage.containerFilesystemStatsToPoints(cInfo, stats) // stats.Filesystem is always nil, not sure why assert.Nil(points) } func TestContainerStatsToPoints(t *testing.T) { // Given storage, err := createTestStorage() require.Nil(t, err) require.NotNil(t, storage) cInfo, stats := createTestStats() require.Nil(t, err) require.NotNil(t, stats) // When points := storage.containerStatsToPoints(cInfo, stats) points = append(points, storage.memoryStatsToPoints(cInfo, stats)...) points = append(points, storage.hugetlbStatsToPoints(cInfo, stats)...) points = append(points, storage.perfStatsToPoints(cInfo, stats)...) points = append(points, storage.resctrlStatsToPoints(cInfo, stats)...) // Then assert.NotEmpty(t, points) assert.Len(t, points, 34+len(stats.Cpu.Usage.PerCpu)) // CPU stats assertContainsPointWithValue(t, points, serCpuUsageTotal, stats.Cpu.Usage.Total) assertContainsPointWithValue(t, points, serCpuUsageSystem, stats.Cpu.Usage.System) assertContainsPointWithValue(t, points, serCpuUsageUser, stats.Cpu.Usage.User) assertContainsPointWithValue(t, points, serLoadAverage, stats.Cpu.LoadAverage) for _, cpu_usage := range stats.Cpu.Usage.PerCpu { assertContainsPointWithValue(t, points, serCpuUsagePerCpu, cpu_usage) } // Memory stats assertContainsPointWithValue(t, points, serMemoryUsage, stats.Memory.Usage) assertContainsPointWithValue(t, points, serMemoryMaxUsage, stats.Memory.MaxUsage) assertContainsPointWithValue(t, points, serMemoryCache, stats.Memory.Cache) assertContainsPointWithValue(t, points, serMemoryRss, stats.Memory.RSS) assertContainsPointWithValue(t, points, serMemorySwap, stats.Memory.Swap) assertContainsPointWithValue(t, points, serMemoryMappedFile, stats.Memory.MappedFile) assertContainsPointWithValue(t, points, serMemoryUsage, stats.Memory.Usage) assertContainsPointWithValue(t, points, serMemoryWorkingSet, stats.Memory.WorkingSet) assertContainsPointWithValue(t, points, serMemoryTotalActiveFile, stats.Memory.TotalActiveFile) assertContainsPointWithValue(t, points, serMemoryTotalInactiveFile, stats.Memory.TotalInactiveFile) assertContainsPointWithValue(t, points, serMemoryFailcnt, stats.Memory.Failcnt) assertContainsPointWithValue(t, points, serMemoryFailure, stats.Memory.ContainerData.Pgfault) assertContainsPointWithValue(t, points, serMemoryFailure, stats.Memory.ContainerData.Pgmajfault) assertContainsPointWithValue(t, points, serMemoryFailure, stats.Memory.HierarchicalData.Pgfault) assertContainsPointWithValue(t, points, serMemoryFailure, stats.Memory.HierarchicalData.Pgmajfault) // Hugetlb stats for _, hugetlbStat := range stats.Hugetlb { assertContainsPointWithValue(t, points, setHugetlbUsage, hugetlbStat.Usage) assertContainsPointWithValue(t, points, setHugetlbMaxUsage, hugetlbStat.MaxUsage) assertContainsPointWithValue(t, points, setHugetlbFailcnt, hugetlbStat.Failcnt) } // Network stats assertContainsPointWithValue(t, points, serRxBytes, stats.Network.RxBytes) assertContainsPointWithValue(t, points, serRxErrors, stats.Network.RxErrors) assertContainsPointWithValue(t, points, serTxBytes, stats.Network.TxBytes) assertContainsPointWithValue(t, points, serTxBytes, stats.Network.TxErrors) // Perf stats for _, perfStat := range stats.PerfStats { assertContainsPointWithValue(t, points, serPerfStat, perfStat.Value) } // Reference memory assertContainsPointWithValue(t, points, serReferencedMemory, stats.ReferencedMemory) // Resource Control stats - memory bandwidth for _, rdtMemoryBandwidth := range stats.Resctrl.MemoryBandwidth { assertContainsPointWithValue(t, points, serResctrlMemoryBandwidthTotal, rdtMemoryBandwidth.TotalBytes) assertContainsPointWithValue(t, points, serResctrlMemoryBandwidthLocal, rdtMemoryBandwidth.LocalBytes) } // Resource Control stats - cache for _, rdtCache := range stats.Resctrl.Cache { assertContainsPointWithValue(t, points, serResctrlLLCOccupancy, rdtCache.LLCOccupancy) } } func assertContainsPointWithValue(t *testing.T, points []*influxdb.Point, name string, value interface{}) bool { found := false for _, point := range points { if point.Measurement == name && point.Fields[fieldValue] == toSignedIfUnsigned(value) { found = true break } } return assert.True(t, found, "no point found with name='%v' and value=%v", name, value) } func createTestStorage() (*influxdbStorage, error) { machineName := "testMachine" table := "cadvisor_table" database := "cadvisor_test" retentionPolicy := "cadvisor_test_rp" username := "root" password := "root" influxdbHost := "localhost:8086" storage, err := newStorage(machineName, table, database, retentionPolicy, username, password, influxdbHost, false, 2*time.Minute) return storage, err } func createTestStats() (*info.ContainerInfo, *info.ContainerStats) { cInfo := &info.ContainerInfo{ ContainerReference: info.ContainerReference{ Name: "testContainername", Aliases: []string{"testContainerAlias1", "testContainerAlias2"}, }, } cpuUsage := info.CpuUsage{ Total: uint64(rand.Intn(10000)), PerCpu: []uint64{uint64(rand.Intn(1000)), uint64(rand.Intn(1000)), uint64(rand.Intn(1000))}, User: uint64(rand.Intn(10000)), System: uint64(rand.Intn(10000)), } stats := &info.ContainerStats{ Timestamp: time.Now(), Cpu: info.CpuStats{ Usage: cpuUsage, LoadAverage: int32(rand.Intn(1000)), }, Memory: info.MemoryStats{ Usage: 26767396864, MaxUsage: 30429605888, Cache: 7837376512, RSS: 18930020352, Swap: 1024, MappedFile: 1025327104, WorkingSet: 23630012416, TotalActiveFile: 29459246253, TotalInactiveFile: 28364536434, Failcnt: 1, ContainerData: info.MemoryStatsMemoryData{Pgfault: 100328455, Pgmajfault: 97}, HierarchicalData: info.MemoryStatsMemoryData{Pgfault: 100328454, Pgmajfault: 96}, }, Hugetlb: map[string]info.HugetlbStats{ "1GB": {Usage: 1234, MaxUsage: 5678, Failcnt: 9}, "2GB": {Usage: 9876, MaxUsage: 5432, Failcnt: 1}, }, ReferencedMemory: 12345, PerfStats: []info.PerfStat{{Cpu: 1, PerfValue: info.PerfValue{Name: "cycles", ScalingRatio: 1.5, Value: 4589}}}, Resctrl: info.ResctrlStats{ MemoryBandwidth: []info.MemoryBandwidthStats{ {TotalBytes: 11234, LocalBytes: 4567}, {TotalBytes: 55678, LocalBytes: 9876}, }, Cache: []info.CacheStats{ {LLCOccupancy: 3}, {LLCOccupancy: 5}, }, }, } return cInfo, stats } ================================================ FILE: cmd/internal/storage/kafka/kafka.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package kafka import ( "crypto/tls" "crypto/x509" "encoding/json" "flag" "log" "os" "strings" "time" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/storage" "github.com/google/cadvisor/utils/container" kafka "github.com/Shopify/sarama" "k8s.io/klog/v2" ) func init() { storage.RegisterStorageDriver("kafka", new) kafka.Logger = log.New(os.Stderr, "[kafka]", log.LstdFlags) } var ( brokers = flag.String("storage_driver_kafka_broker_list", "localhost:9092", "kafka broker(s) csv") topic = flag.String("storage_driver_kafka_topic", "stats", "kafka topic") certFile = flag.String("storage_driver_kafka_ssl_cert", "", "optional certificate file for TLS client authentication") keyFile = flag.String("storage_driver_kafka_ssl_key", "", "optional key file for TLS client authentication") caFile = flag.String("storage_driver_kafka_ssl_ca", "", "optional certificate authority file for TLS client authentication") verifySSL = flag.Bool("storage_driver_kafka_ssl_verify", true, "verify ssl certificate chain") ) type kafkaStorage struct { producer kafka.AsyncProducer topic string machineName string } type detailSpec struct { Timestamp time.Time `json:"timestamp"` MachineName string `json:"machine_name,omitempty"` ContainerName string `json:"container_Name,omitempty"` ContainerID string `json:"container_Id,omitempty"` ContainerLabels map[string]string `json:"container_labels,omitempty"` ContainerStats *info.ContainerStats `json:"container_stats,omitempty"` } func (s *kafkaStorage) infoToDetailSpec(cInfo *info.ContainerInfo, stats *info.ContainerStats) *detailSpec { timestamp := time.Now() containerID := cInfo.ContainerReference.Id containerLabels := cInfo.Spec.Labels containerName := container.GetPreferredName(cInfo.ContainerReference) detail := &detailSpec{ Timestamp: timestamp, MachineName: s.machineName, ContainerName: containerName, ContainerID: containerID, ContainerLabels: containerLabels, ContainerStats: stats, } return detail } func (s *kafkaStorage) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error { detail := s.infoToDetailSpec(cInfo, stats) b, err := json.Marshal(detail) s.producer.Input() <- &kafka.ProducerMessage{ Topic: s.topic, Value: kafka.StringEncoder(b), } return err } func (s *kafkaStorage) Close() error { return s.producer.Close() } func new() (storage.StorageDriver, error) { machineName, err := os.Hostname() if err != nil { return nil, err } return newStorage(machineName) } func generateTLSConfig() (*tls.Config, error) { if *certFile != "" && *keyFile != "" && *caFile != "" { cert, err := tls.LoadX509KeyPair(*certFile, *keyFile) if err != nil { return nil, err } caCert, err := os.ReadFile(*caFile) if err != nil { return nil, err } caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) return &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: caCertPool, InsecureSkipVerify: *verifySSL, }, nil } return nil, nil } func newStorage(machineName string) (storage.StorageDriver, error) { config := kafka.NewConfig() tlsConfig, err := generateTLSConfig() if err != nil { return nil, err } if tlsConfig != nil { config.Net.TLS.Enable = true config.Net.TLS.Config = tlsConfig } config.Producer.RequiredAcks = kafka.WaitForAll brokerList := strings.Split(*brokers, ",") klog.V(4).Infof("Kafka brokers:%q", *brokers) producer, err := kafka.NewAsyncProducer(brokerList, config) if err != nil { return nil, err } ret := &kafkaStorage{ producer: producer, topic: *topic, machineName: machineName, } return ret, nil } ================================================ FILE: cmd/internal/storage/redis/redis.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package redis import ( "encoding/json" "os" "sync" "time" info "github.com/google/cadvisor/info/v1" storage "github.com/google/cadvisor/storage" redis "github.com/gomodule/redigo/redis" ) func init() { storage.RegisterStorageDriver("redis", new) } type redisStorage struct { conn redis.Conn machineName string redisKey string bufferDuration time.Duration lastWrite time.Time lock sync.Mutex readyToFlush func() bool } type detailSpec struct { Timestamp int64 `json:"timestamp"` MachineName string `json:"machine_name,omitempty"` ContainerName string `json:"container_Name,omitempty"` ContainerStats *info.ContainerStats `json:"container_stats,omitempty"` } func new() (storage.StorageDriver, error) { hostname, err := os.Hostname() if err != nil { return nil, err } return newStorage( hostname, *storage.ArgDbName, *storage.ArgDbHost, *storage.ArgDbBufferDuration, ) } func (s *redisStorage) defaultReadyToFlush() bool { return time.Since(s.lastWrite) >= s.bufferDuration } // We must add some default params (for example: MachineName,ContainerName...)because containerStats do not include them func (s *redisStorage) containerStatsAndDefaultValues(cInfo *info.ContainerInfo, stats *info.ContainerStats) *detailSpec { timestamp := stats.Timestamp.UnixNano() / 1e3 var containerName string if len(cInfo.ContainerReference.Aliases) > 0 { containerName = cInfo.ContainerReference.Aliases[0] } else { containerName = cInfo.ContainerReference.Name } detail := &detailSpec{ Timestamp: timestamp, MachineName: s.machineName, ContainerName: containerName, ContainerStats: stats, } return detail } // Push the data into redis func (s *redisStorage) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error { if stats == nil { return nil } var seriesToFlush []byte func() { // AddStats will be invoked simultaneously from multiple threads and only one of them will perform a write. s.lock.Lock() defer s.lock.Unlock() // Add some default params based on containerStats detail := s.containerStatsAndDefaultValues(cInfo, stats) // To json b, _ := json.Marshal(detail) if s.readyToFlush() { seriesToFlush = b s.lastWrite = time.Now() } }() if len(seriesToFlush) == 0 { return nil } // We use redis's "LPUSH" to push the data to the redis return s.conn.Send("LPUSH", s.redisKey, seriesToFlush) } func (s *redisStorage) Close() error { return s.conn.Close() } // Create a new redis storage driver. // machineName: A unique identifier to identify the host that runs the current cAdvisor // instance is running on. // redisHost: The host which runs redis. // redisKey: The key for the Data that stored in the redis func newStorage( machineName, redisKey, redisHost string, bufferDuration time.Duration, ) (storage.StorageDriver, error) { conn, err := redis.Dial("tcp", redisHost) if err != nil { return nil, err } ret := &redisStorage{ conn: conn, machineName: machineName, redisKey: redisKey, bufferDuration: bufferDuration, lastWrite: time.Now(), } ret.readyToFlush = ret.defaultReadyToFlush return ret, nil } ================================================ FILE: cmd/internal/storage/statsd/client/client.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package client import ( "fmt" "net" "k8s.io/klog/v2" ) type Client struct { HostPort string Namespace string conn net.Conn } func (c *Client) Open() error { conn, err := net.Dial("udp", c.HostPort) if err != nil { klog.Errorf("failed to open udp connection to %q: %v", c.HostPort, err) return err } c.conn = conn return nil } func (c *Client) Close() error { c.conn.Close() c.conn = nil return nil } // Simple send to statsd daemon without sampling. func (c *Client) Send(namespace, containerName, key string, value uint64) error { // only send counter value formatted := fmt.Sprintf("%s.%s.%s:%d|g", namespace, containerName, key, value) _, err := fmt.Fprint(c.conn, formatted) if err != nil { return fmt.Errorf("failed to send data %q: %v", formatted, err) } return nil } func New(hostPort string) (*Client, error) { Client := Client{HostPort: hostPort} if err := Client.Open(); err != nil { return nil, err } return &Client, nil } ================================================ FILE: cmd/internal/storage/statsd/statsd.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package statsd import ( "strconv" client "github.com/google/cadvisor/cmd/internal/storage/statsd/client" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/storage" ) func init() { storage.RegisterStorageDriver("statsd", new) } type statsdStorage struct { client *client.Client Namespace string } const ( // Cumulative CPU usage // To be deprecated in 0.39 // https://github.com/google/cadvisor/issues/2637 colCPUCumulativeUsage string = "cpu_cumulative_usage" // Cumulative CPU usage serCPUUsageTotal string = "cpu_usage_total" serCPUUsageSystem string = "cpu_usage_system" serCPUUsageUser string = "cpu_usage_user" serCPUUsagePerCPU string = "cpu_usage_per_cpu" // Smoothed average of number of runnable threads x 1000. serLoadAverage string = "cpu_load_average" // Memory Usage serMemoryUsage string = "memory_usage" // Maximum memory usage recorded serMemoryMaxUsage string = "memory_max_usage" // Number of bytes of page cache memory serMemoryCache string = "memory_cache" // Size of RSS serMemoryRss string = "memory_rss" // Container swap usage serMemorySwap string = "memory_swap" // Size of memory mapped files in bytes serMemoryMappedFile string = "memory_mapped_file" // Working set size serMemoryWorkingSet string = "memory_working_set" // Total active file size serMemoryTotalActiveFile string = "memory_total_active_file" // Total inactive file size serMemoryTotalInactiveFile string = "memory_total_inactive_file" // Number of memory usage hits limits serMemoryFailcnt string = "memory_failcnt" // Cumulative count of memory allocation failures serMemoryFailure string = "memory_failure" // Cumulative count of bytes received. serRxBytes string = "rx_bytes" // Cumulative count of receive errors encountered. serRxErrors string = "rx_errors" // Cumulative count of bytes transmitted. serTxBytes string = "tx_bytes" // Cumulative count of transmit errors encountered. serTxErrors string = "tx_errors" // Filesystem summary serFsSummary string = "fs_summary" // Filesystem limit. serFsLimit string = "fs_limit" // Filesystem usage. serFsUsage string = "fs_usage" // Hugetlb stat - current res_counter usage for hugetlb setHugetlbUsage string = "hugetlb_usage" // Hugetlb stat - maximum usage ever recorded setHugetlbMaxUsage string = "hugetlb_max_usage" // Hugetlb stat - number of times hugetlb usage allocation failure setHugetlbFailcnt string = "hugetlb_failcnt" // Perf statistics serPerfStat string = "perf_stat" // Referenced memory serReferencedMemory string = "referenced_memory" // Resctrl - Total memory bandwidth serResctrlMemoryBandwidthTotal string = "resctrl_memory_bandwidth_total" // Resctrl - Local memory bandwidth serResctrlMemoryBandwidthLocal string = "resctrl_memory_bandwidth_local" // Resctrl - Last level cache usage serResctrlLLCOccupancy string = "resctrl_llc_occupancy" ) func new() (storage.StorageDriver, error) { return newStorage(*storage.ArgDbName, *storage.ArgDbHost) } func (s *statsdStorage) containerStatsToValues(stats *info.ContainerStats) (series map[string]uint64) { series = make(map[string]uint64) // Total usage in nanoseconds series[serCPUUsageTotal] = stats.Cpu.Usage.Total // To be deprecated in 0.39 series[colCPUCumulativeUsage] = series[serCPUUsageTotal] // CPU usage: Time spend in system space (in nanoseconds) series[serCPUUsageSystem] = stats.Cpu.Usage.System // CPU usage: Time spent in user space (in nanoseconds) series[serCPUUsageUser] = stats.Cpu.Usage.User // CPU usage per CPU for i := 0; i < len(stats.Cpu.Usage.PerCpu); i++ { series[serCPUUsagePerCPU+"."+strconv.Itoa(i)] = stats.Cpu.Usage.PerCpu[i] } // Load Average series[serLoadAverage] = uint64(stats.Cpu.LoadAverage) // Network stats. series[serRxBytes] = stats.Network.RxBytes series[serRxErrors] = stats.Network.RxErrors series[serTxBytes] = stats.Network.TxBytes series[serTxErrors] = stats.Network.TxErrors // Referenced Memory series[serReferencedMemory] = stats.ReferencedMemory return series } func (s *statsdStorage) containerFsStatsToValues(series *map[string]uint64, stats *info.ContainerStats) { for _, fsStat := range stats.Filesystem { // Summary stats. (*series)[serFsSummary+"."+serFsLimit] += fsStat.Limit (*series)[serFsSummary+"."+serFsUsage] += fsStat.Usage // Per device stats. (*series)[fsStat.Device+"."+serFsLimit] = fsStat.Limit (*series)[fsStat.Device+"."+serFsUsage] = fsStat.Usage } } func (s *statsdStorage) memoryStatsToValues(series *map[string]uint64, stats *info.ContainerStats) { // Memory Usage (*series)[serMemoryUsage] = stats.Memory.Usage // Maximum memory usage recorded (*series)[serMemoryMaxUsage] = stats.Memory.MaxUsage //Number of bytes of page cache memory (*series)[serMemoryCache] = stats.Memory.Cache // Size of RSS (*series)[serMemoryRss] = stats.Memory.RSS // Container swap usage (*series)[serMemorySwap] = stats.Memory.Swap // Size of memory mapped files in bytes (*series)[serMemoryMappedFile] = stats.Memory.MappedFile // Working Set Size (*series)[serMemoryWorkingSet] = stats.Memory.WorkingSet // Total Active File Size (*series)[serMemoryTotalActiveFile] = stats.Memory.TotalActiveFile // Total Inactive File Size (*series)[serMemoryTotalInactiveFile] = stats.Memory.TotalInactiveFile // Number of memory usage hits limits (*series)[serMemoryFailcnt] = stats.Memory.Failcnt // Cumulative count of memory allocation failures (*series)[serMemoryFailure+".container.pgfault"] = stats.Memory.ContainerData.Pgfault (*series)[serMemoryFailure+".container.pgmajfault"] = stats.Memory.ContainerData.Pgmajfault (*series)[serMemoryFailure+".hierarchical.pgfault"] = stats.Memory.HierarchicalData.Pgfault (*series)[serMemoryFailure+".hierarchical.pgmajfault"] = stats.Memory.HierarchicalData.Pgmajfault } func (s *statsdStorage) hugetlbStatsToValues(series *map[string]uint64, stats *info.ContainerStats) { for pageSize, hugetlbStat := range stats.Hugetlb { (*series)[setHugetlbUsage+"."+pageSize] = hugetlbStat.Usage (*series)[setHugetlbMaxUsage+"."+pageSize] = hugetlbStat.MaxUsage (*series)[setHugetlbFailcnt+"."+pageSize] = hugetlbStat.Failcnt } } func (s *statsdStorage) perfStatsToValues(series *map[string]uint64, stats *info.ContainerStats) { for _, perfStat := range stats.PerfStats { (*series)[serPerfStat+"."+perfStat.Name+"."+strconv.Itoa(perfStat.Cpu)] = perfStat.Value } } func (s *statsdStorage) resctrlStatsToValues(series *map[string]uint64, stats *info.ContainerStats) { for nodeID, rdtMemoryBandwidth := range stats.Resctrl.MemoryBandwidth { (*series)[serResctrlMemoryBandwidthTotal+"."+strconv.Itoa(nodeID)] = rdtMemoryBandwidth.TotalBytes (*series)[serResctrlMemoryBandwidthLocal+"."+strconv.Itoa(nodeID)] = rdtMemoryBandwidth.LocalBytes } for nodeID, rdtCache := range stats.Resctrl.Cache { (*series)[serResctrlLLCOccupancy+"."+strconv.Itoa(nodeID)] = rdtCache.LLCOccupancy } } // Push the data via the statsd client func (s *statsdStorage) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error { if stats == nil { return nil } series := s.containerStatsToValues(stats) s.containerFsStatsToValues(&series, stats) s.memoryStatsToValues(&series, stats) s.hugetlbStatsToValues(&series, stats) s.perfStatsToValues(&series, stats) s.resctrlStatsToValues(&series, stats) var containerName string if len(cInfo.ContainerReference.Aliases) > 0 { containerName = cInfo.ContainerReference.Aliases[0] } else { containerName = cInfo.ContainerReference.Name } for key, value := range series { err := s.client.Send(s.Namespace, containerName, key, value) if err != nil { return err } } return nil } func (s *statsdStorage) Close() error { s.client.Close() s.client = nil return nil } func newStorage(namespace, hostPort string) (*statsdStorage, error) { statsdClient, err := client.New(hostPort) if err != nil { return nil, err } statsdStorage := &statsdStorage{ client: statsdClient, Namespace: namespace, } return statsdStorage, nil } ================================================ FILE: cmd/internal/storage/stdout/stdout.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package stdout import ( "bytes" "fmt" "strconv" "time" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/storage" ) func init() { storage.RegisterStorageDriver("stdout", new) } type stdoutStorage struct { Namespace string } const ( serTimestamp string = "timestamp" // Cumulative CPU usage // To be deprecated in 0.39 // https://github.com/google/cadvisor/issues/2637 colCPUCumulativeUsage string = "cpu_cumulative_usage" // Cumulative CPU usage serCPUUsageTotal string = "cpu_usage_total" serCPUUsageSystem string = "cpu_usage_system" serCPUUsageUser string = "cpu_usage_user" serCPUUsagePerCPU string = "cpu_usage_per_cpu" // Smoothed average of number of runnable threads x 1000. serLoadAverage string = "load_average" // Memory Usage serMemoryUsage string = "memory_usage" // Maximum memory usage recorded serMemoryMaxUsage string = "memory_max_usage" // Number of bytes of page cache memory serMemoryCache string = "memory_cache" // Size of RSS serMemoryRss string = "memory_rss" // Container swap usage serMemorySwap string = "memory_swap" // Size of memory mapped files in bytes serMemoryMappedFile string = "memory_mapped_file" // Working set size serMemoryWorkingSet string = "memory_working_set" // Total active file serMemoryTotalActiveFile string = "memory_total_active_file" // Total inactive file serMemoryTotalInactiveFile string = "memory_total_inactive_file" // Number of memory usage hits limits serMemoryFailcnt string = "memory_failcnt" // Cumulative count of memory allocation failures serMemoryFailure string = "memory_failure" // Cumulative count of bytes received. serRxBytes string = "rx_bytes" // Cumulative count of receive errors encountered. serRxErrors string = "rx_errors" // Cumulative count of bytes transmitted. serTxBytes string = "tx_bytes" // Cumulative count of transmit errors encountered. serTxErrors string = "tx_errors" // Filesystem summary serFsSummary string = "fs_summary" // Filesystem limit. serFsLimit string = "fs_limit" // Filesystem usage. serFsUsage string = "fs_usage" // Hugetlb stat - current res_counter usage for hugetlb setHugetlbUsage string = "hugetlb_usage" // Hugetlb stat - maximum usage ever recorded setHugetlbMaxUsage string = "hugetlb_max_usage" // Hugetlb stat - number of times hugetlb usage allocation failure setHugetlbFailcnt string = "hugetlb_failcnt" // Perf statistics serPerfStat string = "perf_stat" // Referenced memory serReferencedMemory string = "referenced_memory" // Resctrl - Total memory bandwidth serResctrlMemoryBandwidthTotal string = "resctrl_memory_bandwidth_total" // Resctrl - Local memory bandwidth serResctrlMemoryBandwidthLocal string = "resctrl_memory_bandwidth_local" // Resctrl - Last level cache usage serResctrlLLCOccupancy string = "resctrl_llc_occupancy" ) func new() (storage.StorageDriver, error) { return newStorage(*storage.ArgDbHost) } func (driver *stdoutStorage) containerStatsToValues(stats *info.ContainerStats) (series map[string]uint64) { series = make(map[string]uint64) // Unix Timestamp series[serTimestamp] = uint64(time.Now().UnixNano()) // Total usage in nanoseconds series[serCPUUsageTotal] = stats.Cpu.Usage.Total // To be deprecated in 0.39 series[colCPUCumulativeUsage] = series[serCPUUsageTotal] // CPU usage: Time spend in system space (in nanoseconds) series[serCPUUsageSystem] = stats.Cpu.Usage.System // CPU usage: Time spent in user space (in nanoseconds) series[serCPUUsageUser] = stats.Cpu.Usage.User // CPU usage per CPU for i := 0; i < len(stats.Cpu.Usage.PerCpu); i++ { series[serCPUUsagePerCPU+"."+strconv.Itoa(i)] = stats.Cpu.Usage.PerCpu[i] } // Load Average series[serLoadAverage] = uint64(stats.Cpu.LoadAverage) // Network stats. series[serRxBytes] = stats.Network.RxBytes series[serRxErrors] = stats.Network.RxErrors series[serTxBytes] = stats.Network.TxBytes series[serTxErrors] = stats.Network.TxErrors // Referenced Memory series[serReferencedMemory] = stats.ReferencedMemory return series } func (driver *stdoutStorage) containerFsStatsToValues(series *map[string]uint64, stats *info.ContainerStats) { for _, fsStat := range stats.Filesystem { // Summary stats. (*series)[serFsSummary+"."+serFsLimit] += fsStat.Limit (*series)[serFsSummary+"."+serFsUsage] += fsStat.Usage // Per device stats. (*series)[fsStat.Device+"."+serFsLimit] = fsStat.Limit (*series)[fsStat.Device+"."+serFsUsage] = fsStat.Usage } } func (driver *stdoutStorage) memoryStatsToValues(series *map[string]uint64, stats *info.ContainerStats) { // Memory Usage (*series)[serMemoryUsage] = stats.Memory.Usage // Maximum memory usage recorded (*series)[serMemoryMaxUsage] = stats.Memory.MaxUsage //Number of bytes of page cache memory (*series)[serMemoryCache] = stats.Memory.Cache // Size of RSS (*series)[serMemoryRss] = stats.Memory.RSS // Container swap usage (*series)[serMemorySwap] = stats.Memory.Swap // Size of memory mapped files in bytes (*series)[serMemoryMappedFile] = stats.Memory.MappedFile // Working Set Size (*series)[serMemoryWorkingSet] = stats.Memory.WorkingSet // Total Active File (*series)[serMemoryTotalActiveFile] = stats.Memory.TotalActiveFile // Total Inactive File (*series)[serMemoryTotalInactiveFile] = stats.Memory.TotalInactiveFile // Number of memory usage hits limits (*series)[serMemoryFailcnt] = stats.Memory.Failcnt // Cumulative count of memory allocation failures (*series)[serMemoryFailure+".container.pgfault"] = stats.Memory.ContainerData.Pgfault (*series)[serMemoryFailure+".container.pgmajfault"] = stats.Memory.ContainerData.Pgmajfault (*series)[serMemoryFailure+".hierarchical.pgfault"] = stats.Memory.HierarchicalData.Pgfault (*series)[serMemoryFailure+".hierarchical.pgmajfault"] = stats.Memory.HierarchicalData.Pgmajfault } func (driver *stdoutStorage) hugetlbStatsToValues(series *map[string]uint64, stats *info.ContainerStats) { for pageSize, hugetlbStat := range stats.Hugetlb { (*series)[setHugetlbUsage+"."+pageSize] = hugetlbStat.Usage (*series)[setHugetlbMaxUsage+"."+pageSize] = hugetlbStat.MaxUsage (*series)[setHugetlbFailcnt+"."+pageSize] = hugetlbStat.Failcnt } } func (driver *stdoutStorage) perfStatsToValues(series *map[string]uint64, stats *info.ContainerStats) { for _, perfStat := range stats.PerfStats { (*series)[serPerfStat+"."+perfStat.Name+"."+strconv.Itoa(perfStat.Cpu)] = perfStat.Value } } func (driver *stdoutStorage) resctrlStatsToValues(series *map[string]uint64, stats *info.ContainerStats) { for nodeID, rdtMemoryBandwidth := range stats.Resctrl.MemoryBandwidth { (*series)[serResctrlMemoryBandwidthTotal+"."+strconv.Itoa(nodeID)] = rdtMemoryBandwidth.TotalBytes (*series)[serResctrlMemoryBandwidthLocal+"."+strconv.Itoa(nodeID)] = rdtMemoryBandwidth.LocalBytes } for nodeID, rdtCache := range stats.Resctrl.Cache { (*series)[serResctrlLLCOccupancy+"."+strconv.Itoa(nodeID)] = rdtCache.LLCOccupancy } } func (driver *stdoutStorage) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error { if stats == nil { return nil } containerName := cInfo.ContainerReference.Name if len(cInfo.ContainerReference.Aliases) > 0 { containerName = cInfo.ContainerReference.Aliases[0] } var buffer bytes.Buffer buffer.WriteString(fmt.Sprintf("cName=%s host=%s", containerName, driver.Namespace)) series := driver.containerStatsToValues(stats) driver.containerFsStatsToValues(&series, stats) driver.memoryStatsToValues(&series, stats) driver.hugetlbStatsToValues(&series, stats) driver.perfStatsToValues(&series, stats) driver.resctrlStatsToValues(&series, stats) for key, value := range series { buffer.WriteString(fmt.Sprintf(" %s=%v", key, value)) } _, err := fmt.Println(buffer.String()) return err } func (driver *stdoutStorage) Close() error { return nil } func newStorage(namespace string) (*stdoutStorage, error) { stdoutStorage := &stdoutStorage{ Namespace: namespace, } return stdoutStorage, nil } ================================================ FILE: cmd/internal/storage/test/mock.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( info "github.com/google/cadvisor/info/v1" "github.com/stretchr/testify/mock" ) type MockStorageDriver struct { mock.Mock MockCloseMethod bool } func (d *MockStorageDriver) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error { args := d.Called(cInfo.ContainerReference, stats) return args.Error(0) } func (d *MockStorageDriver) Close() error { if d.MockCloseMethod { args := d.Called() return args.Error(0) } return nil } ================================================ FILE: cmd/internal/storage/test/storagetests.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "math/rand" "testing" "time" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/storage" ) type TestStorageDriver interface { StatsEq(a *info.ContainerStats, b *info.ContainerStats) bool storage.StorageDriver } func buildTrace(cpu, mem []uint64, duration time.Duration) []*info.ContainerStats { if len(cpu) != len(mem) { panic("len(cpu) != len(mem)") } ret := make([]*info.ContainerStats, len(cpu)) currentTime := time.Now() var cpuTotalUsage uint64 = 0 for i, cpuUsage := range cpu { cpuTotalUsage += cpuUsage stats := new(info.ContainerStats) stats.Timestamp = currentTime currentTime = currentTime.Add(duration) stats.Cpu.Usage.Total = cpuTotalUsage stats.Cpu.Usage.User = stats.Cpu.Usage.Total stats.Cpu.Usage.System = 0 stats.Cpu.Usage.PerCpu = []uint64{cpuTotalUsage} stats.Memory.Usage = mem[i] stats.Network.RxBytes = uint64(rand.Intn(10000)) stats.Network.RxErrors = uint64(rand.Intn(1000)) stats.Network.TxBytes = uint64(rand.Intn(100000)) stats.Network.TxErrors = uint64(rand.Intn(1000)) stats.Filesystem = make([]info.FsStats, 1) stats.Filesystem[0].Device = "/dev/sda1" stats.Filesystem[0].Limit = 1024000000 stats.Filesystem[0].Usage = 1024000 ret[i] = stats } return ret } func TimeEq(t1, t2 time.Time, tolerance time.Duration) bool { // t1 should not be later than t2 if t1.After(t2) { t1, t2 = t2, t1 } diff := t2.Sub(t1) return diff <= tolerance } // This function will generate random stats and write // them into the storage. The function will not close the driver func StorageDriverFillRandomStatsFunc( containerName string, N int, driver TestStorageDriver, t *testing.T, ) { cpuTrace := make([]uint64, 0, N) memTrace := make([]uint64, 0, N) // We need N+1 observations to get N samples for i := 0; i < N+1; i++ { cpuTrace = append(cpuTrace, uint64(rand.Intn(1000))) memTrace = append(memTrace, uint64(rand.Intn(1000))) } samplePeriod := 1 * time.Second cInfo := info.ContainerInfo{ ContainerReference: info.ContainerReference{ Name: containerName, }, } trace := buildTrace(cpuTrace, memTrace, samplePeriod) for _, stats := range trace { err := driver.AddStats(&cInfo, stats) if err != nil { t.Fatalf("unable to add stats: %v", err) } } } ================================================ FILE: cmd/storagedriver.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "flag" "fmt" "strings" "time" "github.com/google/cadvisor/cache/memory" _ "github.com/google/cadvisor/cmd/internal/storage/bigquery" _ "github.com/google/cadvisor/cmd/internal/storage/elasticsearch" _ "github.com/google/cadvisor/cmd/internal/storage/influxdb" _ "github.com/google/cadvisor/cmd/internal/storage/kafka" _ "github.com/google/cadvisor/cmd/internal/storage/redis" _ "github.com/google/cadvisor/cmd/internal/storage/statsd" _ "github.com/google/cadvisor/cmd/internal/storage/stdout" "github.com/google/cadvisor/storage" "k8s.io/klog/v2" ) var ( storageDriver = flag.String("storage_driver", "", fmt.Sprintf("Storage `driver` to use. Data is always cached shortly in memory, this controls where data is pushed besides the local cache. Empty means none, multiple separated by commas. Options are: , %s", strings.Join(storage.ListDrivers(), ", "))) storageDuration = flag.Duration("storage_duration", 2*time.Minute, "How long to keep data stored (Default: 2min).") ) // NewMemoryStorage creates a memory storage with an optional backend storage option. func NewMemoryStorage() (*memory.InMemoryCache, error) { backendStorages := []storage.StorageDriver{} for _, driver := range strings.Split(*storageDriver, ",") { if driver == "" { continue } storage, err := storage.New(driver) if err != nil { return nil, err } backendStorages = append(backendStorages, storage) klog.V(1).Infof("Using backend storage type %q", driver) } klog.V(1).Infof("Caching stats in memory for %v", *storageDuration) return memory.New(*storageDuration, backendStorages), nil } ================================================ FILE: collector/collector_manager.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package collector import ( "fmt" "strings" "time" v1 "github.com/google/cadvisor/info/v1" ) const metricLabelPrefix = "io.cadvisor.metric." type GenericCollectorManager struct { Collectors []*collectorData NextCollectionTime time.Time } type collectorData struct { collector Collector nextCollectionTime time.Time } // Returns a new CollectorManager that is thread-compatible. func NewCollectorManager() (CollectorManager, error) { return &GenericCollectorManager{ Collectors: []*collectorData{}, NextCollectionTime: time.Now(), }, nil } func GetCollectorConfigs(labels map[string]string) map[string]string { configs := map[string]string{} for k, v := range labels { if strings.HasPrefix(k, metricLabelPrefix) { name := strings.TrimPrefix(k, metricLabelPrefix) configs[name] = v } } return configs } func (cm *GenericCollectorManager) RegisterCollector(collector Collector) error { cm.Collectors = append(cm.Collectors, &collectorData{ collector: collector, nextCollectionTime: time.Now(), }) return nil } func (cm *GenericCollectorManager) GetSpec() ([]v1.MetricSpec, error) { metricSpec := []v1.MetricSpec{} for _, c := range cm.Collectors { specs := c.collector.GetSpec() metricSpec = append(metricSpec, specs...) } return metricSpec, nil } func (cm *GenericCollectorManager) Collect() (time.Time, map[string][]v1.MetricVal, error) { var errors []error // Collect from all collectors that are ready. var next time.Time metrics := map[string][]v1.MetricVal{} for _, c := range cm.Collectors { if c.nextCollectionTime.Before(time.Now()) { var err error c.nextCollectionTime, metrics, err = c.collector.Collect(metrics) if err != nil { errors = append(errors, err) } } // Keep track of the next collector that will be ready. if next.IsZero() || next.After(c.nextCollectionTime) { next = c.nextCollectionTime } } cm.NextCollectionTime = next return next, metrics, compileErrors(errors) } // Make an error slice into a single error. func compileErrors(errors []error) error { if len(errors) == 0 { return nil } res := make([]string, len(errors)) for i := range errors { res[i] = fmt.Sprintf("Error %d: %v", i, errors[i].Error()) } return fmt.Errorf("%s", strings.Join(res, ",")) } ================================================ FILE: collector/collector_manager_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package collector import ( "testing" "time" "github.com/stretchr/testify/assert" v1 "github.com/google/cadvisor/info/v1" ) type fakeCollector struct { nextCollectionTime time.Time err error collectedFrom int } func (fc *fakeCollector) Collect(metric map[string][]v1.MetricVal) (time.Time, map[string][]v1.MetricVal, error) { fc.collectedFrom++ return fc.nextCollectionTime, metric, fc.err } func (fc *fakeCollector) Name() string { return "fake-collector" } func (fc *fakeCollector) GetSpec() []v1.MetricSpec { return []v1.MetricSpec{} } func TestCollect(t *testing.T) { cm := &GenericCollectorManager{} firstTime := time.Now().Add(-time.Hour) secondTime := time.Now().Add(time.Hour) f1 := &fakeCollector{ nextCollectionTime: firstTime, } f2 := &fakeCollector{ nextCollectionTime: secondTime, } assert := assert.New(t) assert.NoError(cm.RegisterCollector(f1)) assert.NoError(cm.RegisterCollector(f2)) // First collection, everyone gets collected from. nextTime, _, err := cm.Collect() assert.Equal(firstTime, nextTime) assert.NoError(err) assert.Equal(1, f1.collectedFrom) assert.Equal(1, f2.collectedFrom) f1.nextCollectionTime = time.Now().Add(2 * time.Hour) // Second collection, only the one that is ready gets collected from. nextTime, _, err = cm.Collect() assert.Equal(secondTime, nextTime) assert.NoError(err) assert.Equal(2, f1.collectedFrom) assert.Equal(1, f2.collectedFrom) } ================================================ FILE: collector/config/sample_config.json ================================================ { "endpoint" : "http://localhost:8000/nginx_status", "metrics_config" : [ { "name" : "activeConnections", "metric_type" : "gauge", "units" : "number of active connections", "data_type" : "int", "polling_frequency" : 10, "regex" : "Active connections: ([0-9]+)" }, { "name" : "reading", "metric_type" : "gauge", "units" : "number of reading connections", "data_type" : "int", "polling_frequency" : 10, "regex" : "Reading: ([0-9]+) .*" }, { "name" : "writing", "metric_type" : "gauge", "data_type" : "int", "units" : "number of writing connections", "polling_frequency" : 10, "regex" : ".*Writing: ([0-9]+).*" }, { "name" : "waiting", "metric_type" : "gauge", "units" : "number of waiting connections", "data_type" : "int", "polling_frequency" : 10, "regex" : ".*Waiting: ([0-9]+)" } ] } ================================================ FILE: collector/config/sample_config_endpoint_config.json ================================================ { "endpoint" : { "protocol": "https", "port": 8000, "path": "/nginx_status" }, "metrics_config" : [ { "name" : "activeConnections", "metric_type" : "gauge", "units" : "number of active connections", "data_type" : "int", "polling_frequency" : 10, "regex" : "Active connections: ([0-9]+)" }, { "name" : "reading", "metric_type" : "gauge", "units" : "number of reading connections", "data_type" : "int", "polling_frequency" : 10, "regex" : "Reading: ([0-9]+) .*" }, { "name" : "writing", "metric_type" : "gauge", "data_type" : "int", "units" : "number of writing connections", "polling_frequency" : 10, "regex" : ".*Writing: ([0-9]+).*" }, { "name" : "waiting", "metric_type" : "gauge", "units" : "number of waiting connections", "data_type" : "int", "polling_frequency" : 10, "regex" : ".*Waiting: ([0-9]+)" } ] } ================================================ FILE: collector/config/sample_config_prometheus.json ================================================ { "endpoint" : "http://localhost:8080/metrics", "polling_frequency" : 10, "metrics_config" : [ ] } ================================================ FILE: collector/config/sample_config_prometheus_endpoint_config.json ================================================ { "endpoint" : { "protocol": "http", "port": 8081, "path": "/METRICS" }, "polling_frequency" : 10, "metrics_config" : [ ] } ================================================ FILE: collector/config/sample_config_prometheus_filtered.json ================================================ { "endpoint" : "http://localhost:8080/metrics", "polling_frequency" : 10, "metrics_config" : [ "go_goroutines", "qps" ] } ================================================ FILE: collector/config.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package collector import ( "time" "encoding/json" v1 "github.com/google/cadvisor/info/v1" ) type Config struct { // the endpoint to hit to scrape metrics Endpoint EndpointConfig `json:"endpoint"` // holds information about different metrics that can be collected MetricsConfig []MetricConfig `json:"metrics_config"` } // metricConfig holds information extracted from the config file about a metric type MetricConfig struct { // the name of the metric Name string `json:"name"` // enum type for the metric type MetricType v1.MetricType `json:"metric_type"` // metric units to display on UI and in storage (eg: MB, cores) // this is only used for display. Units string `json:"units"` // data type of the metric (eg: int, float) DataType v1.DataType `json:"data_type"` // the frequency at which the metric should be collected PollingFrequency time.Duration `json:"polling_frequency"` // the regular expression that can be used to extract the metric Regex string `json:"regex"` } type Prometheus struct { // the endpoint to hit to scrape metrics Endpoint EndpointConfig `json:"endpoint"` // the frequency at which metrics should be collected PollingFrequency time.Duration `json:"polling_frequency"` // holds names of different metrics that can be collected MetricsConfig []string `json:"metrics_config"` } type EndpointConfig struct { // The full URL of the endpoint to reach URL string // A configuration in which an actual URL is constructed from, using the container's ip address URLConfig URLConfig } type URLConfig struct { // the protocol to use for connecting to the endpoint. Eg 'http' or 'https' Protocol string `json:"protocol"` // the port to use for connecting to the endpoint. Eg '8778' Port json.Number `json:"port"` // the path to use for the endpoint. Eg '/metrics' Path string `json:"path"` } func (ec *EndpointConfig) UnmarshalJSON(b []byte) error { url := "" config := URLConfig{ Protocol: "http", Port: "8000", } if err := json.Unmarshal(b, &url); err == nil { ec.URL = url return nil } err := json.Unmarshal(b, &config) if err == nil { ec.URLConfig = config return nil } return err } ================================================ FILE: collector/fakes.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package collector import ( "time" v1 "github.com/google/cadvisor/info/v1" ) type FakeCollectorManager struct { } func (fkm *FakeCollectorManager) RegisterCollector(collector Collector) error { return nil } func (fkm *FakeCollectorManager) GetSpec() ([]v1.MetricSpec, error) { return []v1.MetricSpec{}, nil } func (fkm *FakeCollectorManager) Collect(metric map[string][]v1.MetricVal) (time.Time, map[string][]v1.MetricVal, error) { var zero time.Time return zero, metric, nil } ================================================ FILE: collector/generic_collector.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package collector import ( "encoding/json" "fmt" "io" "net/http" "regexp" "strconv" "strings" "time" "github.com/google/cadvisor/container" v1 "github.com/google/cadvisor/info/v1" ) type GenericCollector struct { // name of the collector name string // holds information extracted from the config file for a collector configFile Config // holds information necessary to extract metrics info *collectorInfo // The Http client to use when connecting to metric endpoints httpClient *http.Client } type collectorInfo struct { // minimum polling frequency among all metrics minPollingFrequency time.Duration // regular expresssions for all metrics regexps []*regexp.Regexp // Limit for the number of srcaped metrics. If the count is higher, // no metrics will be returned. metricCountLimit int } // Returns a new collector using the information extracted from the configfile func NewCollector(collectorName string, configFile []byte, metricCountLimit int, containerHandler container.ContainerHandler, httpClient *http.Client) (*GenericCollector, error) { var configInJSON Config err := json.Unmarshal(configFile, &configInJSON) if err != nil { return nil, err } configInJSON.Endpoint.configure(containerHandler) // TODO : Add checks for validity of config file (eg : Accurate JSON fields) if len(configInJSON.MetricsConfig) == 0 { return nil, fmt.Errorf("no metrics provided in config") } minPollFrequency := time.Duration(0) regexprs := make([]*regexp.Regexp, len(configInJSON.MetricsConfig)) for ind, metricConfig := range configInJSON.MetricsConfig { // Find the minimum specified polling frequency in metric config. if metricConfig.PollingFrequency != 0 { if minPollFrequency == 0 || metricConfig.PollingFrequency < minPollFrequency { minPollFrequency = metricConfig.PollingFrequency } } regexprs[ind], err = regexp.Compile(metricConfig.Regex) if err != nil { return nil, fmt.Errorf("invalid regexp %v for metric %v", metricConfig.Regex, metricConfig.Name) } } // Minimum supported polling frequency is 1s. minSupportedFrequency := 1 * time.Second if minPollFrequency < minSupportedFrequency { minPollFrequency = minSupportedFrequency } if len(configInJSON.MetricsConfig) > metricCountLimit { return nil, fmt.Errorf("too many metrics defined: %d limit: %d", len(configInJSON.MetricsConfig), metricCountLimit) } return &GenericCollector{ name: collectorName, configFile: configInJSON, info: &collectorInfo{ minPollingFrequency: minPollFrequency, regexps: regexprs, metricCountLimit: metricCountLimit, }, httpClient: httpClient, }, nil } // Returns name of the collector func (collector *GenericCollector) Name() string { return collector.name } func (collector *GenericCollector) configToSpec(config MetricConfig) v1.MetricSpec { return v1.MetricSpec{ Name: config.Name, Type: config.MetricType, Format: config.DataType, Units: config.Units, } } func (collector *GenericCollector) GetSpec() []v1.MetricSpec { specs := []v1.MetricSpec{} for _, metricConfig := range collector.configFile.MetricsConfig { spec := collector.configToSpec(metricConfig) specs = append(specs, spec) } return specs } // Returns collected metrics and the next collection time of the collector func (collector *GenericCollector) Collect(metrics map[string][]v1.MetricVal) (time.Time, map[string][]v1.MetricVal, error) { currentTime := time.Now() nextCollectionTime := currentTime.Add(time.Duration(collector.info.minPollingFrequency)) uri := collector.configFile.Endpoint.URL response, err := collector.httpClient.Get(uri) if err != nil { return nextCollectionTime, nil, err } defer response.Body.Close() pageContent, err := io.ReadAll(response.Body) if err != nil { return nextCollectionTime, nil, err } var errorSlice []error for ind, metricConfig := range collector.configFile.MetricsConfig { matchString := collector.info.regexps[ind].FindStringSubmatch(string(pageContent)) if matchString != nil { if metricConfig.DataType == v1.FloatType { regVal, err := strconv.ParseFloat(strings.TrimSpace(matchString[1]), 64) if err != nil { errorSlice = append(errorSlice, err) } metrics[metricConfig.Name] = []v1.MetricVal{ {FloatValue: regVal, Timestamp: currentTime}, } } else if metricConfig.DataType == v1.IntType { regVal, err := strconv.ParseInt(strings.TrimSpace(matchString[1]), 10, 64) if err != nil { errorSlice = append(errorSlice, err) } metrics[metricConfig.Name] = []v1.MetricVal{ {IntValue: regVal, Timestamp: currentTime}, } } else { errorSlice = append(errorSlice, fmt.Errorf("unexpected value of 'data_type' for metric '%v' in config ", metricConfig.Name)) } } else { errorSlice = append(errorSlice, fmt.Errorf("no match found for regexp: %v for metric '%v' in config", metricConfig.Regex, metricConfig.Name)) } } return nextCollectionTime, metrics, compileErrors(errorSlice) } ================================================ FILE: collector/generic_collector_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package collector import ( "fmt" "net/http" "net/http/httptest" "os" "testing" "github.com/stretchr/testify/assert" containertest "github.com/google/cadvisor/container/testing" v1 "github.com/google/cadvisor/info/v1" ) func TestEmptyConfig(t *testing.T) { assert := assert.New(t) emptyConfig := ` { "endpoint" : "http://localhost:8000/nginx_status", "metrics_config" : [ ] } ` // Create a temporary config file 'temp.json' with invalid json format assert.NoError(os.WriteFile("temp.json", []byte(emptyConfig), 0777)) configFile, err := os.ReadFile("temp.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") _, err = NewCollector("tempCollector", configFile, 100, containerHandler, http.DefaultClient) assert.Error(err) assert.NoError(os.Remove("temp.json")) } func TestConfigWithErrors(t *testing.T) { assert := assert.New(t) // Syntax error: Missed '"' after activeConnections invalid := ` { "endpoint" : "http://localhost:8000/nginx_status", "metrics_config" : [ { "name" : "activeConnections, "metric_type" : "gauge", "data_type" : "int", "polling_frequency" : 10, "regex" : "Active connections: ([0-9]+)" } ] } ` // Create a temporary config file 'temp.json' with invalid json format assert.NoError(os.WriteFile("temp.json", []byte(invalid), 0777)) configFile, err := os.ReadFile("temp.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") _, err = NewCollector("tempCollector", configFile, 100, containerHandler, http.DefaultClient) assert.Error(err) assert.NoError(os.Remove("temp.json")) } func TestConfigWithRegexErrors(t *testing.T) { assert := assert.New(t) // Error: Missed operand for '+' in activeConnections regex invalid := ` { "endpoint" : "host:port/nginx_status", "metrics_config" : [ { "name" : "activeConnections", "metric_type" : "gauge", "data_type" : "int", "polling_frequency" : 10, "regex" : "Active connections: (+)" }, { "name" : "reading", "metric_type" : "gauge", "data_type" : "int", "polling_frequency" : 10, "regex" : "Reading: ([0-9]+) .*" } ] } ` // Create a temporary config file 'temp.json' assert.NoError(os.WriteFile("temp.json", []byte(invalid), 0777)) configFile, err := os.ReadFile("temp.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") _, err = NewCollector("tempCollector", configFile, 100, containerHandler, http.DefaultClient) assert.Error(err) assert.NoError(os.Remove("temp.json")) } func TestConfig(t *testing.T) { assert := assert.New(t) // Create an nginx collector using the config file 'sample_config.json' configFile, err := os.ReadFile("config/sample_config.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") collector, err := NewCollector("nginx", configFile, 100, containerHandler, http.DefaultClient) assert.NoError(err) assert.Equal(collector.name, "nginx") assert.Equal(collector.configFile.Endpoint.URL, "http://localhost:8000/nginx_status") assert.Equal(collector.configFile.MetricsConfig[0].Name, "activeConnections") } func TestEndpointConfig(t *testing.T) { assert := assert.New(t) configFile, err := os.ReadFile("config/sample_config_endpoint_config.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") containerHandler.On("GetContainerIPAddress").Return( "111.111.111.111", ) collector, err := NewCollector("nginx", configFile, 100, containerHandler, http.DefaultClient) assert.NoError(err) assert.Equal(collector.name, "nginx") assert.Equal(collector.configFile.Endpoint.URL, "https://111.111.111.111:8000/nginx_status") assert.Equal(collector.configFile.MetricsConfig[0].Name, "activeConnections") } func TestMetricCollection(t *testing.T) { assert := assert.New(t) // Collect nginx metrics from a fake nginx endpoint configFile, err := os.ReadFile("config/sample_config.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") fakeCollector, err := NewCollector("nginx", configFile, 100, containerHandler, http.DefaultClient) assert.NoError(err) tempServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Active connections: 3\nserver accepts handled requests") fmt.Fprintln(w, "5 5 32\nReading: 0 Writing: 1 Waiting: 2") })) defer tempServer.Close() fakeCollector.configFile.Endpoint.URL = tempServer.URL metrics := map[string][]v1.MetricVal{} _, metrics, errMetric := fakeCollector.Collect(metrics) assert.NoError(errMetric) metricNames := []string{"activeConnections", "reading", "writing", "waiting"} // activeConnections = 3 assert.Equal(metrics[metricNames[0]][0].IntValue, int64(3)) assert.Equal(metrics[metricNames[0]][0].FloatValue, float64(0)) // reading = 0 assert.Equal(metrics[metricNames[1]][0].IntValue, int64(0)) assert.Equal(metrics[metricNames[1]][0].FloatValue, float64(0)) // writing = 1 assert.Equal(metrics[metricNames[2]][0].IntValue, int64(1)) assert.Equal(metrics[metricNames[2]][0].FloatValue, float64(0)) // waiting = 2 assert.Equal(metrics[metricNames[3]][0].IntValue, int64(2)) assert.Equal(metrics[metricNames[3]][0].FloatValue, float64(0)) } func TestMetricCollectionLimit(t *testing.T) { assert := assert.New(t) // Collect nginx metrics from a fake nginx endpoint configFile, err := os.ReadFile("config/sample_config.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") _, err = NewCollector("nginx", configFile, 1, containerHandler, http.DefaultClient) assert.Error(err) } ================================================ FILE: collector/prometheus_collector.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package collector import ( "bytes" "encoding/json" "fmt" "io" "net/http" "sort" "time" rawmodel "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "github.com/prometheus/common/model" "github.com/google/cadvisor/container" v1 "github.com/google/cadvisor/info/v1" ) type PrometheusCollector struct { // name of the collector name string // rate at which metrics are collected pollingFrequency time.Duration // holds information extracted from the config file for a collector configFile Prometheus // the metrics to gather (uses a map as a set) metricsSet map[string]bool // Limit for the number of scaped metrics. If the count is higher, // no metrics will be returned. metricCountLimit int // The Http client to use when connecting to metric endpoints httpClient *http.Client } // Returns a new collector using the information extracted from the configfile func NewPrometheusCollector(collectorName string, configFile []byte, metricCountLimit int, containerHandler container.ContainerHandler, httpClient *http.Client) (*PrometheusCollector, error) { var configInJSON Prometheus err := json.Unmarshal(configFile, &configInJSON) if err != nil { return nil, err } configInJSON.Endpoint.configure(containerHandler) minPollingFrequency := configInJSON.PollingFrequency // Minimum supported frequency is 1s minSupportedFrequency := 1 * time.Second if minPollingFrequency < minSupportedFrequency { minPollingFrequency = minSupportedFrequency } if metricCountLimit < 0 { return nil, fmt.Errorf("metric count limit must be greater than or equal to 0") } var metricsSet map[string]bool if len(configInJSON.MetricsConfig) > 0 { metricsSet = make(map[string]bool, len(configInJSON.MetricsConfig)) for _, name := range configInJSON.MetricsConfig { metricsSet[name] = true } } if len(configInJSON.MetricsConfig) > metricCountLimit { return nil, fmt.Errorf("too many metrics defined: %d limit %d", len(configInJSON.MetricsConfig), metricCountLimit) } // TODO : Add checks for validity of config file (eg : Accurate JSON fields) return &PrometheusCollector{ name: collectorName, pollingFrequency: minPollingFrequency, configFile: configInJSON, metricsSet: metricsSet, metricCountLimit: metricCountLimit, httpClient: httpClient, }, nil } // Returns name of the collector func (collector *PrometheusCollector) Name() string { return collector.name } func (collector *PrometheusCollector) GetSpec() []v1.MetricSpec { response, err := collector.httpClient.Get(collector.configFile.Endpoint.URL) if err != nil { return nil } defer response.Body.Close() if response.StatusCode != http.StatusOK { return nil } dec := expfmt.NewDecoder(response.Body, expfmt.ResponseFormat(response.Header)) var specs []v1.MetricSpec for { d := rawmodel.MetricFamily{} if err = dec.Decode(&d); err != nil { break } name := d.GetName() if len(name) == 0 { continue } // If metrics to collect is specified, skip any metrics not in the list to collect. if _, ok := collector.metricsSet[name]; collector.metricsSet != nil && !ok { continue } spec := v1.MetricSpec{ Name: name, Type: metricType(d.GetType()), Format: v1.FloatType, } specs = append(specs, spec) } if err != nil && err != io.EOF { return nil } return specs } // metricType converts Prometheus metric type to cadvisor metric type. // If there is no mapping then just return the name of the Prometheus metric type. func metricType(t rawmodel.MetricType) v1.MetricType { switch t { case rawmodel.MetricType_COUNTER: return v1.MetricCumulative case rawmodel.MetricType_GAUGE: return v1.MetricGauge default: return v1.MetricType(t.String()) } } type prometheusLabels []*rawmodel.LabelPair func labelSetToLabelPairs(labels model.Metric) prometheusLabels { var promLabels prometheusLabels for k, v := range labels { name := string(k) value := string(v) promLabels = append(promLabels, &rawmodel.LabelPair{Name: &name, Value: &value}) } return promLabels } func (s prometheusLabels) Len() int { return len(s) } func (s prometheusLabels) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // ByName implements sort.Interface by providing Less and using the Len and // Swap methods of the embedded PrometheusLabels value. type byName struct{ prometheusLabels } func (s byName) Less(i, j int) bool { return s.prometheusLabels[i].GetName() < s.prometheusLabels[j].GetName() } func prometheusLabelSetToCadvisorLabels(promLabels model.Metric) map[string]string { labels := make(map[string]string) for k, v := range promLabels { if string(k) == "__name__" { continue } labels[string(k)] = string(v) } return labels } func prometheusLabelSetToCadvisorLabel(promLabels model.Metric) string { labels := labelSetToLabelPairs(promLabels) sort.Sort(byName{labels}) var b bytes.Buffer for i, l := range labels { if i > 0 { b.WriteString("\xff") } b.WriteString(l.GetName()) b.WriteString("=") b.WriteString(l.GetValue()) } return b.String() } // Returns collected metrics and the next collection time of the collector func (collector *PrometheusCollector) Collect(metrics map[string][]v1.MetricVal) (time.Time, map[string][]v1.MetricVal, error) { currentTime := time.Now() nextCollectionTime := currentTime.Add(time.Duration(collector.pollingFrequency)) uri := collector.configFile.Endpoint.URL response, err := collector.httpClient.Get(uri) if err != nil { return nextCollectionTime, nil, err } defer response.Body.Close() if response.StatusCode != http.StatusOK { return nextCollectionTime, nil, fmt.Errorf("server returned HTTP status %s", response.Status) } sdec := expfmt.SampleDecoder{ Dec: expfmt.NewDecoder(response.Body, expfmt.ResponseFormat(response.Header)), Opts: &expfmt.DecodeOptions{ Timestamp: model.TimeFromUnixNano(currentTime.UnixNano()), }, } var ( // 50 is chosen as a reasonable guesstimate at a number of metrics we can // expect from virtually any endpoint to try to save allocations. decSamples = make(model.Vector, 0, 50) newMetrics = make(map[string][]v1.MetricVal) ) for { if err = sdec.Decode(&decSamples); err != nil { break } for _, sample := range decSamples { metName := string(sample.Metric[model.MetricNameLabel]) if len(metName) == 0 { continue } // If metrics to collect is specified, skip any metrics not in the list to collect. if _, ok := collector.metricsSet[metName]; collector.metricsSet != nil && !ok { continue } // TODO Handle multiple labels nicer. Prometheus metrics can have multiple // labels, cadvisor only accepts a single string for the metric label. label := prometheusLabelSetToCadvisorLabel(sample.Metric) labels := prometheusLabelSetToCadvisorLabels(sample.Metric) metric := v1.MetricVal{ FloatValue: float64(sample.Value), Timestamp: sample.Timestamp.Time(), Label: label, Labels: labels, } newMetrics[metName] = append(newMetrics[metName], metric) if len(newMetrics) > collector.metricCountLimit { return nextCollectionTime, nil, fmt.Errorf("too many metrics to collect") } } decSamples = decSamples[:0] } if err != nil && err != io.EOF { return nextCollectionTime, nil, err } for key, val := range newMetrics { metrics[key] = append(metrics[key], val...) } return nextCollectionTime, metrics, nil } ================================================ FILE: collector/prometheus_collector_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package collector import ( "fmt" "net/http" "net/http/httptest" "os" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" containertest "github.com/google/cadvisor/container/testing" v1 "github.com/google/cadvisor/info/v1" ) func TestPrometheus(t *testing.T) { assert := assert.New(t) // Create a prometheus collector using the config file 'sample_config_prometheus.json' configFile, err := os.ReadFile("config/sample_config_prometheus.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") collector, err := NewPrometheusCollector("Prometheus", configFile, 100, containerHandler, http.DefaultClient) assert.NoError(err) assert.Equal("Prometheus", collector.name) assert.Equal("http://localhost:8080/metrics", collector.configFile.Endpoint.URL) tempServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { text := `# HELP go_gc_duration_seconds A summary of the GC invocation durations. # TYPE go_gc_duration_seconds summary go_gc_duration_seconds{quantile="0"} 5.8348000000000004e-05 go_gc_duration_seconds{quantile="1"} 0.000499764 go_gc_duration_seconds_sum 1.7560473e+07 go_gc_duration_seconds_count 2693 # HELP go_goroutines Number of goroutines that currently exist. # TYPE go_goroutines gauge go_goroutines 16 # HELP empty_metric A metric without any values # TYPE empty_metric counter # HELP metric_with_spaces_in_label A metric with spaces in a label. # TYPE metric_with_spaces_in_label gauge metric_with_spaces_in_label{name="Network Agent"} 72 # HELP metric_with_multiple_labels A metric with multiple labels. # TYPE metric_with_multiple_labels gauge metric_with_multiple_labels{label1="One", label2="Two", label3="Three"} 81 ` fmt.Fprintln(w, text) })) defer tempServer.Close() collector.configFile.Endpoint.URL = tempServer.URL var spec []v1.MetricSpec require.NotPanics(t, func() { spec = collector.GetSpec() }) assert.Len(spec, 4) specNames := make(map[string]struct{}, 3) for _, s := range spec { specNames[s.Name] = struct{}{} } expectedSpecNames := map[string]struct{}{ "go_gc_duration_seconds": {}, "go_goroutines": {}, "metric_with_spaces_in_label": {}, "metric_with_multiple_labels": {}, } assert.Equal(expectedSpecNames, specNames) metrics := map[string][]v1.MetricVal{} _, metrics, errMetric := collector.Collect(metrics) assert.NoError(errMetric) gcDuration := metrics["go_gc_duration_seconds"] assert.Equal(5.8348000000000004e-05, gcDuration[0].FloatValue) assert.Equal("__name__=go_gc_duration_seconds\xffquantile=0", gcDuration[0].Label) assert.Equal(0.000499764, gcDuration[1].FloatValue) assert.Equal("__name__=go_gc_duration_seconds\xffquantile=1", gcDuration[1].Label) gcDurationSum := metrics["go_gc_duration_seconds_sum"] assert.Equal(1.7560473e+07, gcDurationSum[0].FloatValue) assert.Equal("__name__=go_gc_duration_seconds_sum", gcDurationSum[0].Label) gcDurationCount := metrics["go_gc_duration_seconds_count"] assert.Equal(float64(2693), gcDurationCount[0].FloatValue) assert.Equal("__name__=go_gc_duration_seconds_count", gcDurationCount[0].Label) goRoutines := metrics["go_goroutines"] assert.Equal(float64(16), goRoutines[0].FloatValue) assert.Equal("__name__=go_goroutines", goRoutines[0].Label) metricWithSpaces := metrics["metric_with_spaces_in_label"] assert.Equal(float64(72), metricWithSpaces[0].FloatValue) assert.Equal("__name__=metric_with_spaces_in_label\xffname=Network Agent", metricWithSpaces[0].Label) metricWithMultipleLabels := metrics["metric_with_multiple_labels"] assert.Equal(float64(81), metricWithMultipleLabels[0].FloatValue) assert.Equal("__name__=metric_with_multiple_labels\xfflabel1=One\xfflabel2=Two\xfflabel3=Three", metricWithMultipleLabels[0].Label) } func TestPrometheusEndpointConfig(t *testing.T) { assert := assert.New(t) //Create a prometheus collector using the config file 'sample_config_prometheus.json' configFile, err := os.ReadFile("config/sample_config_prometheus_endpoint_config.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") containerHandler.On("GetContainerIPAddress").Return( "222.222.222.222", ) collector, err := NewPrometheusCollector("Prometheus", configFile, 100, containerHandler, http.DefaultClient) assert.NoError(err) assert.Equal(collector.name, "Prometheus") assert.Equal(collector.configFile.Endpoint.URL, "http://222.222.222.222:8081/METRICS") } func TestPrometheusShortResponse(t *testing.T) { assert := assert.New(t) // Create a prometheus collector using the config file 'sample_config_prometheus.json' configFile, err := os.ReadFile("config/sample_config_prometheus.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") collector, err := NewPrometheusCollector("Prometheus", configFile, 100, containerHandler, http.DefaultClient) assert.NoError(err) assert.Equal(collector.name, "Prometheus") assert.Equal(collector.configFile.Endpoint.URL, "http://localhost:8080/metrics") tempServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { text := "# HELP empty_metric A metric without any values" fmt.Fprint(w, text) })) defer tempServer.Close() collector.configFile.Endpoint.URL = tempServer.URL assert.NotPanics(func() { collector.GetSpec() }) } func TestPrometheusMetricCountLimit(t *testing.T) { assert := assert.New(t) // Create a prometheus collector using the config file 'sample_config_prometheus.json' configFile, err := os.ReadFile("config/sample_config_prometheus.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") collector, err := NewPrometheusCollector("Prometheus", configFile, 10, containerHandler, http.DefaultClient) assert.NoError(err) assert.Equal(collector.name, "Prometheus") assert.Equal(collector.configFile.Endpoint.URL, "http://localhost:8080/metrics") tempServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { for i := 0; i < 30; i++ { fmt.Fprintf(w, "# HELP m%d Number of goroutines that currently exist.\n", i) fmt.Fprintf(w, "# TYPE m%d gauge\n", i) fmt.Fprintf(w, "m%d %d", i, i) } })) defer tempServer.Close() collector.configFile.Endpoint.URL = tempServer.URL metrics := map[string][]v1.MetricVal{} _, result, errMetric := collector.Collect(metrics) assert.Error(errMetric) assert.Equal(len(metrics), 0) assert.Nil(result) } func TestPrometheusFiltersMetrics(t *testing.T) { assert := assert.New(t) // Create a prometheus collector using the config file 'sample_config_prometheus_filtered.json' configFile, err := os.ReadFile("config/sample_config_prometheus_filtered.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") collector, err := NewPrometheusCollector("Prometheus", configFile, 100, containerHandler, http.DefaultClient) assert.NoError(err) assert.Equal(collector.name, "Prometheus") assert.Equal(collector.configFile.Endpoint.URL, "http://localhost:8080/metrics") tempServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { text := `# HELP go_gc_duration_seconds A summary of the GC invocation durations. # TYPE go_gc_duration_seconds summary go_gc_duration_seconds{quantile="0"} 5.8348000000000004e-05 go_gc_duration_seconds{quantile="1"} 0.000499764 go_gc_duration_seconds_sum 1.7560473e+07 go_gc_duration_seconds_count 2693 # HELP go_goroutines Number of goroutines that currently exist. # TYPE go_goroutines gauge go_goroutines 16 ` fmt.Fprintln(w, text) })) defer tempServer.Close() collector.configFile.Endpoint.URL = tempServer.URL metrics := map[string][]v1.MetricVal{} _, metrics, errMetric := collector.Collect(metrics) assert.NoError(errMetric) assert.Len(metrics, 1) goRoutines := metrics["go_goroutines"] assert.Equal(goRoutines[0].FloatValue, float64(16)) } func TestPrometheusFiltersMetricsCountLimit(t *testing.T) { assert := assert.New(t) // Create a prometheus collector using the config file 'sample_config_prometheus_filtered.json' configFile, err := os.ReadFile("config/sample_config_prometheus_filtered.json") assert.NoError(err) containerHandler := containertest.NewMockContainerHandler("mockContainer") _, err = NewPrometheusCollector("Prometheus", configFile, 1, containerHandler, http.DefaultClient) assert.Error(err) } ================================================ FILE: collector/types.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package collector import ( "time" v1 "github.com/google/cadvisor/info/v1" ) // TODO(vmarmol): Export to a custom metrics type when that is available. // Metric collector. type Collector interface { // Collect metrics from this collector. // Returns the next time this collector should be collected from. // Next collection time is always returned, even when an error occurs. // A collection time of zero means no more collection. Collect(map[string][]v1.MetricVal) (time.Time, map[string][]v1.MetricVal, error) // Return spec for all metrics associated with this collector GetSpec() []v1.MetricSpec // Name of this collector. Name() string } // Manages and runs collectors. type CollectorManager interface { // Register a collector. RegisterCollector(collector Collector) error // Collect from collectors that are ready and return the next time // at which a collector will be ready to collect from. // Next collection time is always returned, even when an error occurs. // A collection time of zero means no more collection. Collect() (time.Time, map[string][]v1.MetricVal, error) // Get metric spec from all registered collectors. GetSpec() ([]v1.MetricSpec, error) } ================================================ FILE: collector/util.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package collector import "github.com/google/cadvisor/container" func (ec *EndpointConfig) configure(containerHandler container.ContainerHandler) { // If the exact URL was not specified, generate it based on the ip address of the container. if ec.URL == "" { ipAddress := containerHandler.GetContainerIPAddress() ec.URL = ec.URLConfig.Protocol + "://" + ipAddress + ":" + ec.URLConfig.Port.String() + ec.URLConfig.Path } } ================================================ FILE: container/common/container_hints.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Unmarshal's a Containers description json file. The json file contains // an array of ContainerHint structs, each with a container's id and networkInterface // This allows collecting stats about network interfaces configured outside docker // and lxc package common import ( "encoding/json" "flag" "os" ) var ArgContainerHints = flag.String("container_hints", "/etc/cadvisor/container_hints.json", "location of the container hints file") type ContainerHints struct { AllHosts []containerHint `json:"all_hosts,omitempty"` } type containerHint struct { FullName string `json:"full_path,omitempty"` NetworkInterface *networkInterface `json:"network_interface,omitempty"` Mounts []Mount `json:"mounts,omitempty"` } type Mount struct { HostDir string `json:"host_dir,omitempty"` ContainerDir string `json:"container_dir,omitempty"` } type networkInterface struct { VethHost string `json:"veth_host,omitempty"` VethChild string `json:"veth_child,omitempty"` } func GetContainerHintsFromFile(containerHintsFile string) (ContainerHints, error) { dat, err := os.ReadFile(containerHintsFile) if os.IsNotExist(err) { return ContainerHints{}, nil } var cHints ContainerHints if err == nil { err = json.Unmarshal(dat, &cHints) } return cHints, err } ================================================ FILE: container/common/container_hints_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package common import ( "testing" ) func TestGetContainerHintsFromFile(t *testing.T) { cHints, err := GetContainerHintsFromFile("test_resources/container_hints.json") if err != nil { t.Fatalf("Error in unmarshalling: %s", err) } if cHints.AllHosts[0].NetworkInterface.VethHost != "veth24031eth1" && cHints.AllHosts[0].NetworkInterface.VethChild != "eth1" { t.Errorf("Cannot find network interface in %+v", cHints) } correctMountDirs := [...]string{ "/var/run/nm-sdc1", "/var/run/nm-sdb3", "/var/run/nm-sda3", "/var/run/netns/root", "/var/run/openvswitch/db.sock", } if len(cHints.AllHosts[0].Mounts) == 0 { t.Errorf("Cannot find any mounts") } for i, mountDir := range cHints.AllHosts[0].Mounts { if correctMountDirs[i] != mountDir.HostDir { t.Errorf("Cannot find mount %s in %+v", mountDir.HostDir, cHints) } } } func TestFileNotExist(t *testing.T) { _, err := GetContainerHintsFromFile("/file_does_not_exist.json") if err != nil { t.Fatalf("GetContainerHintsFromFile must not error for blank file: %s", err) } } ================================================ FILE: container/common/fsHandler.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Handler for Docker containers. package common import ( "fmt" "sync" "time" "github.com/google/cadvisor/fs" "k8s.io/klog/v2" ) type FsHandler interface { Start() Usage() FsUsage Stop() } type FsUsage struct { BaseUsageBytes uint64 TotalUsageBytes uint64 InodeUsage uint64 } type realFsHandler struct { sync.RWMutex lastUpdate time.Time usage FsUsage period time.Duration minPeriod time.Duration rootfs string extraDir string fsInfo fs.FsInfo // Tells the container to stop. stopChan chan struct{} } const ( maxBackoffFactor = 20 ) const DefaultPeriod = time.Minute var _ FsHandler = &realFsHandler{} func NewFsHandler(period time.Duration, rootfs, extraDir string, fsInfo fs.FsInfo) FsHandler { return &realFsHandler{ lastUpdate: time.Time{}, usage: FsUsage{}, period: period, minPeriod: period, rootfs: rootfs, extraDir: extraDir, fsInfo: fsInfo, stopChan: make(chan struct{}, 1), } } func (fh *realFsHandler) update() error { var ( rootUsage, extraUsage fs.UsageInfo rootErr, extraErr error ) // TODO(vishh): Add support for external mounts. if fh.rootfs != "" { rootUsage, rootErr = fh.fsInfo.GetDirUsage(fh.rootfs) } if fh.extraDir != "" { extraUsage, extraErr = fh.fsInfo.GetDirUsage(fh.extraDir) } // Wait to handle errors until after all operartions are run. // An error in one will not cause an early return, skipping others fh.Lock() defer fh.Unlock() fh.lastUpdate = time.Now() if fh.rootfs != "" && rootErr == nil { fh.usage.InodeUsage = rootUsage.Inodes fh.usage.BaseUsageBytes = rootUsage.Bytes fh.usage.TotalUsageBytes = rootUsage.Bytes } if fh.extraDir != "" && extraErr == nil { if fh.rootfs != "" { fh.usage.TotalUsageBytes += extraUsage.Bytes } else { // rootfs is empty, totalUsageBytes use extra usage bytes fh.usage.TotalUsageBytes = extraUsage.Bytes } } // Combine errors into a single error to return if rootErr != nil || extraErr != nil { return fmt.Errorf("rootDiskErr: %v, extraDiskErr: %v", rootErr, extraErr) } return nil } func (fh *realFsHandler) trackUsage() { longOp := time.Second for { start := time.Now() if err := fh.update(); err != nil { klog.Errorf("failed to collect filesystem stats - %v", err) fh.period = fh.period * 2 if fh.period > maxBackoffFactor*fh.minPeriod { fh.period = maxBackoffFactor * fh.minPeriod } } else { fh.period = fh.minPeriod } duration := time.Since(start) if duration > longOp { // adapt longOp time so that message doesn't continue to print // if the long duration is persistent either because of slow // disk or lots of containers. longOp = longOp + time.Second klog.V(2).Infof("fs: disk usage and inodes count on following dirs took %v: %v; will not log again for this container unless duration exceeds %v", duration, []string{fh.rootfs, fh.extraDir}, longOp) } select { case <-fh.stopChan: return case <-time.After(fh.period): } } } func (fh *realFsHandler) Start() { go fh.trackUsage() } func (fh *realFsHandler) Stop() { close(fh.stopChan) } func (fh *realFsHandler) Usage() FsUsage { fh.RLock() defer fh.RUnlock() return fh.usage } ================================================ FILE: container/common/helpers.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package common import ( "errors" "fmt" "io/fs" "math" "os" "path" "strconv" "strings" "time" "github.com/opencontainers/cgroups" "golang.org/x/sys/unix" "github.com/google/cadvisor/container" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/utils" "k8s.io/klog/v2" ) func DebugInfo(watches map[string][]string) map[string][]string { out := make(map[string][]string) lines := make([]string, 0, len(watches)) for containerName, cgroupWatches := range watches { lines = append(lines, fmt.Sprintf("%s:", containerName)) for _, cg := range cgroupWatches { lines = append(lines, fmt.Sprintf("\t%s", cg)) } } out["Inotify watches"] = lines return out } var bootTime = func() time.Time { now := time.Now() var sysinfo unix.Sysinfo_t if err := unix.Sysinfo(&sysinfo); err != nil { return now } sinceBoot := time.Duration(sysinfo.Uptime) * time.Second return now.Add(-1 * sinceBoot).Truncate(time.Minute) }() func GetSpec(cgroupPaths map[string]string, machineInfoFactory info.MachineInfoFactory, hasNetwork, hasFilesystem bool) (info.ContainerSpec, error) { return getSpecInternal(cgroupPaths, machineInfoFactory, hasNetwork, hasFilesystem, cgroups.IsCgroup2UnifiedMode()) } func getSpecInternal(cgroupPaths map[string]string, machineInfoFactory info.MachineInfoFactory, hasNetwork, hasFilesystem, cgroup2UnifiedMode bool) (info.ContainerSpec, error) { var spec info.ContainerSpec // Assume unified hierarchy containers. // Get the lowest creation time from all hierarchies as the container creation time. now := time.Now() lowestTime := now for _, cgroupPathDir := range cgroupPaths { dir, err := os.Stat(cgroupPathDir) if err == nil && dir.ModTime().Before(lowestTime) { lowestTime = dir.ModTime() } else if os.IsNotExist(err) { // Directory does not exist, skip checking for files within. continue } // The modified time of the cgroup directory sometimes changes whenever a subcontainer is created. // eg. /docker will have creation time matching the creation of latest docker container. // Use clone_children/events as a workaround as it isn't usually modified. It is only likely changed // immediately after creating a container. If the directory modified time is lower, we use that. cgroupPathFile := path.Join(cgroupPathDir, "cgroup.clone_children") if cgroup2UnifiedMode { cgroupPathFile = path.Join(cgroupPathDir, "cgroup.events") } fi, err := os.Stat(cgroupPathFile) if err == nil && fi.ModTime().Before(lowestTime) { lowestTime = fi.ModTime() } } if lowestTime.Before(bootTime) { lowestTime = bootTime } if lowestTime != now { spec.CreationTime = lowestTime } // Get machine info. mi, err := machineInfoFactory.GetMachineInfo() if err != nil { return spec, err } // CPU. cpuRoot, ok := GetControllerPath(cgroupPaths, "cpu", cgroup2UnifiedMode) if ok { if utils.FileExists(cpuRoot) { if cgroup2UnifiedMode { spec.HasCpu = true weight := readUInt64(cpuRoot, "cpu.weight") if weight > 0 { limit, err := convertCPUWeightToCPULimit(weight) if err != nil { klog.Errorf("GetSpec: Failed to read CPULimit from %q: %s", path.Join(cpuRoot, "cpu.weight"), err) } else { spec.Cpu.Limit = limit } } max := readString(cpuRoot, "cpu.max") if max != "" { splits := strings.SplitN(max, " ", 2) if len(splits) != 2 { klog.Errorf("GetSpec: Failed to parse CPUmax from %q", path.Join(cpuRoot, "cpu.max")) } else { if splits[0] != "max" { spec.Cpu.Quota = parseUint64String(splits[0]) } spec.Cpu.Period = parseUint64String(splits[1]) } } } else { spec.HasCpu = true spec.Cpu.Limit = readUInt64(cpuRoot, "cpu.shares") spec.Cpu.Period = readUInt64(cpuRoot, "cpu.cfs_period_us") quota := readString(cpuRoot, "cpu.cfs_quota_us") if quota != "" && quota != "-1" { val, err := strconv.ParseUint(quota, 10, 64) if err != nil { klog.Errorf("GetSpec: Failed to parse CPUQuota from %q: %s", path.Join(cpuRoot, "cpu.cfs_quota_us"), err) } else { spec.Cpu.Quota = val } } } } } // Cpu Mask. // This will fail for non-unified hierarchies. We'll return the whole machine mask in that case. cpusetRoot, ok := GetControllerPath(cgroupPaths, "cpuset", cgroup2UnifiedMode) if ok { if utils.FileExists(cpusetRoot) { spec.HasCpu = true mask := "" if cgroup2UnifiedMode { mask = readString(cpusetRoot, "cpuset.cpus.effective") } else { mask = readString(cpusetRoot, "cpuset.cpus") } spec.Cpu.Mask = utils.FixCpuMask(mask, mi.NumCores) } } // Memory memoryRoot, ok := GetControllerPath(cgroupPaths, "memory", cgroup2UnifiedMode) if ok { if cgroup2UnifiedMode { if utils.FileExists(path.Join(memoryRoot, "memory.max")) { spec.HasMemory = true spec.Memory.Reservation = readUInt64(memoryRoot, "memory.min") spec.Memory.Limit = readUInt64(memoryRoot, "memory.max") spec.Memory.SwapLimit = readUInt64(memoryRoot, "memory.swap.max") } } else { if utils.FileExists(memoryRoot) { spec.HasMemory = true spec.Memory.Limit = readUInt64(memoryRoot, "memory.limit_in_bytes") spec.Memory.SwapLimit = readUInt64(memoryRoot, "memory.memsw.limit_in_bytes") spec.Memory.Reservation = readUInt64(memoryRoot, "memory.soft_limit_in_bytes") } } } // Hugepage hugepageRoot, ok := cgroupPaths["hugetlb"] if ok { if utils.FileExists(hugepageRoot) { spec.HasHugetlb = true } } // Processes, read it's value from pids path directly pidsRoot, ok := GetControllerPath(cgroupPaths, "pids", cgroup2UnifiedMode) if ok { if utils.FileExists(pidsRoot) { spec.HasProcesses = true spec.Processes.Limit = readUInt64(pidsRoot, "pids.max") } } spec.HasNetwork = hasNetwork spec.HasFilesystem = hasFilesystem ioControllerName := "blkio" if cgroup2UnifiedMode { ioControllerName = "io" } if blkioRoot, ok := GetControllerPath(cgroupPaths, ioControllerName, cgroup2UnifiedMode); ok && utils.FileExists(blkioRoot) { spec.HasDiskIo = true } return spec, nil } func GetControllerPath(cgroupPaths map[string]string, controllerName string, cgroup2UnifiedMode bool) (string, bool) { ok := false path := "" if cgroup2UnifiedMode { path, ok = cgroupPaths[""] } else { path, ok = cgroupPaths[controllerName] } return path, ok } func readString(dirpath string, file string) string { cgroupFile := path.Join(dirpath, file) // Read out, err := os.ReadFile(cgroupFile) if err != nil { // Ignore non-existent files if !os.IsNotExist(err) { klog.Warningf("readString: Failed to read %q: %s", cgroupFile, err) } return "" } return strings.TrimSpace(string(out)) } // Convert from [1-10000] to [2-262144] func convertCPUWeightToCPULimit(weight uint64) (uint64, error) { const ( // minWeight is the lowest value possible for cpu.weight minWeight = 1 // maxWeight is the highest value possible for cpu.weight maxWeight = 10000 ) if weight < minWeight || weight > maxWeight { return 0, fmt.Errorf("convertCPUWeightToCPULimit: invalid cpu weight: %v", weight) } return 2 + ((weight-1)*262142)/9999, nil } func parseUint64String(strValue string) uint64 { if strValue == "max" { return math.MaxUint64 } if strValue == "" { return 0 } val, err := strconv.ParseUint(strValue, 10, 64) if err != nil { klog.Errorf("parseUint64String: Failed to parse int %q: %s", strValue, err) return 0 } return val } func readUInt64(dirpath string, file string) uint64 { out := readString(dirpath, file) if out == "max" { return math.MaxUint64 } if out == "" { return 0 } val, err := strconv.ParseUint(out, 10, 64) if err != nil { klog.Errorf("readUInt64: Failed to parse int %q from file %q: %s", out, path.Join(dirpath, file), err) return 0 } return val } // Lists all directories under "path" and outputs the results as children of "parent". func ListDirectories(dirpath string, parent string, recursive bool, output map[string]struct{}) error { dirents, err := os.ReadDir(dirpath) if err != nil { // Ignore if this hierarchy does not exist. if errors.Is(err, fs.ErrNotExist) { return nil } return err } for _, dirent := range dirents { // We only grab directories. if !dirent.IsDir() { continue } dirname := dirent.Name() name := path.Join(parent, dirname) output[name] = struct{}{} // List subcontainers if asked to. if recursive { if err := ListDirectories(path.Join(dirpath, dirname), name, true, output); err != nil { return err } } } return nil } func MakeCgroupPaths(mountPoints map[string]string, name string) map[string]string { cgroupPaths := make(map[string]string, len(mountPoints)) for key, val := range mountPoints { cgroupPaths[key] = path.Join(val, name) } return cgroupPaths } func CgroupExists(cgroupPaths map[string]string) bool { // If any cgroup exists, the container is still alive. for _, cgroupPath := range cgroupPaths { if utils.FileExists(cgroupPath) { return true } } return false } func ListContainers(name string, cgroupPaths map[string]string, listType container.ListType) ([]info.ContainerReference, error) { containers := make(map[string]struct{}) for _, cgroupPath := range cgroupPaths { err := ListDirectories(cgroupPath, name, listType == container.ListRecursive, containers) if err != nil { return nil, err } } // Make into container references. ret := make([]info.ContainerReference, 0, len(containers)) for cont := range containers { ret = append(ret, info.ContainerReference{ Name: cont, }) } return ret, nil } // AssignDeviceNamesToDiskStats assigns the Device field on the provided DiskIoStats by looking up // the device major and minor identifiers in the provided device namer. func AssignDeviceNamesToDiskStats(namer DeviceNamer, stats *info.DiskIoStats) { assignDeviceNamesToPerDiskStats( namer, stats.IoMerged, stats.IoQueued, stats.IoServiceBytes, stats.IoServiceTime, stats.IoServiced, stats.IoTime, stats.IoWaitTime, stats.Sectors, stats.IoCostUsage, stats.IoCostWait, stats.IoCostIndebt, stats.IoCostIndelay, ) } // assignDeviceNamesToPerDiskStats looks up device names for the provided stats, caching names // if necessary. func assignDeviceNamesToPerDiskStats(namer DeviceNamer, diskStats ...[]info.PerDiskStats) { devices := make(deviceIdentifierMap) for _, stats := range diskStats { for i, stat := range stats { stats[i].Device = devices.Find(stat.Major, stat.Minor, namer) } } } // DeviceNamer returns string names for devices by their major and minor id. type DeviceNamer interface { // DeviceName returns the name of the device by its major and minor ids, or false if no // such device is recognized. DeviceName(major, minor uint64) (string, bool) } type MachineInfoNamer info.MachineInfo func (n *MachineInfoNamer) DeviceName(major, minor uint64) (string, bool) { for _, info := range n.DiskMap { if info.Major == major && info.Minor == minor { return "/dev/" + info.Name, true } } for _, info := range n.Filesystems { if info.DeviceMajor == major && info.DeviceMinor == minor { return info.Device, true } } return "", false } type deviceIdentifier struct { major uint64 minor uint64 } type deviceIdentifierMap map[deviceIdentifier]string // Find locates the device name by device identifier out of from, caching the result as necessary. func (m deviceIdentifierMap) Find(major, minor uint64, namer DeviceNamer) string { d := deviceIdentifier{major, minor} if s, ok := m[d]; ok { return s } s, _ := namer.DeviceName(major, minor) m[d] = s return s } // RemoveNetMetrics is used to remove any network metrics from the given MetricSet. // It returns the original set as is if remove is false, or if there are no metrics // to remove. func RemoveNetMetrics(metrics container.MetricSet, remove bool) container.MetricSet { if !remove { return metrics } // Check if there is anything we can remove, to avoid useless copying. if !metrics.HasAny(container.AllNetworkMetrics) { return metrics } // A copy of all metrics except for network ones. return metrics.Difference(container.AllNetworkMetrics) } ================================================ FILE: container/common/helpers_test.go ================================================ // Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package common import ( "errors" "fmt" "math" "os" "path/filepath" "reflect" "testing" "github.com/stretchr/testify/assert" "github.com/google/cadvisor/container" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" ) func BenchmarkListDirectories(b *testing.B) { for i := 0; i < b.N; i++ { output := make(map[string]struct{}) if err := ListDirectories("/sys/fs/cgroup", "", true, output); err != nil { b.Fatal(err) } } } func TestConvertCpuWeightToCpuLimit(t *testing.T) { limit, err := convertCPUWeightToCPULimit(1) if err != nil { t.Fatalf("Error in convertCPUWeightToCPULimit: %s", err) } if limit != 2 { t.Fatalf("convertCPUWeightToCPULimit(1) != 2") } limit, err = convertCPUWeightToCPULimit(10000) if err != nil { t.Fatalf("Error in convertCPUWeightToCPULimit: %s", err) } if limit != 262144 { t.Fatalf("convertCPUWeightToCPULimit(10000) != 262144") } _, err = convertCPUWeightToCPULimit(0) if err == nil { t.Fatalf("convertCPUWeightToCPULimit(0) must raise an error") } _, err = convertCPUWeightToCPULimit(10001) if err == nil { t.Fatalf("convertCPUWeightToCPULimit(10001) must raise an error") } } func TestParseUint64String(t *testing.T) { if parseUint64String("1000") != 1000 { t.Fatalf("parseUint64String(\"1000\") != 1000") } if parseUint64String("-1") != 0 { t.Fatalf("parseUint64String(\"-1\") != 0") } if parseUint64String("0") != 0 { t.Fatalf("parseUint64String(\"0\") != 0") } if parseUint64String("not-a-number") != 0 { t.Fatalf("parseUint64String(\"not-a-number\") != 0") } if parseUint64String(" 1000 ") != 0 { t.Fatalf("parseUint64String(\" 1000 \") != 0") } if parseUint64String("18446744073709551615") != 18446744073709551615 { t.Fatalf("parseUint64String(\"18446744073709551615\") != 18446744073709551615") } } type mockInfoProvider struct { options v2.RequestOptions } func (m *mockInfoProvider) GetRequestedContainersInfo(containerName string, options v2.RequestOptions) (map[string]*info.ContainerInfo, error) { m.options = options return map[string]*info.ContainerInfo{}, nil } func (m *mockInfoProvider) GetVersionInfo() (*info.VersionInfo, error) { return nil, errors.New("not supported") } func (m *mockInfoProvider) GetMachineInfo() (*info.MachineInfo, error) { return &info.MachineInfo{ NumCores: 7, }, nil } func TestGetSpecCgroupV1(t *testing.T) { root, err := os.Getwd() if err != nil { t.Fatalf("getwd: %s", err) } cgroupPaths := map[string]string{ "memory": filepath.Join(root, "test_resources/cgroup_v1/test1/memory"), "cpu": filepath.Join(root, "test_resources/cgroup_v1/test1/cpu"), "cpuset": filepath.Join(root, "test_resources/cgroup_v1/test1/cpuset"), "pids": filepath.Join(root, "test_resources/cgroup_v1/test1/pids"), } spec, err := getSpecInternal(cgroupPaths, &mockInfoProvider{}, false, false, false) assert.Nil(t, err) assert.True(t, spec.HasMemory) assert.EqualValues(t, spec.Memory.Limit, 123456789) assert.EqualValues(t, spec.Memory.SwapLimit, 13579) assert.EqualValues(t, spec.Memory.Reservation, 24680) assert.True(t, spec.HasCpu) assert.EqualValues(t, spec.Cpu.Limit, 1025) assert.EqualValues(t, spec.Cpu.Period, 100010) assert.EqualValues(t, spec.Cpu.Quota, 20000) assert.EqualValues(t, spec.Cpu.Mask, "0-5") assert.True(t, spec.HasProcesses) assert.EqualValues(t, spec.Processes.Limit, 1027) assert.False(t, spec.HasHugetlb) assert.False(t, spec.HasDiskIo) } func TestGetSpecCgroupV2(t *testing.T) { root, err := os.Getwd() if err != nil { t.Fatalf("getwd: %s", err) } cgroupPaths := map[string]string{ "": filepath.Join(root, "test_resources/cgroup_v2/test1"), } spec, err := getSpecInternal(cgroupPaths, &mockInfoProvider{}, false, false, true) assert.Nil(t, err) assert.True(t, spec.HasMemory) assert.EqualValues(t, spec.Memory.Limit, 123456789) assert.EqualValues(t, spec.Memory.SwapLimit, 13579) assert.EqualValues(t, spec.Memory.Reservation, 24680) assert.True(t, spec.HasCpu) assert.EqualValues(t, spec.Cpu.Limit, 1286) assert.EqualValues(t, spec.Cpu.Period, 100010) assert.EqualValues(t, spec.Cpu.Quota, 20000) assert.EqualValues(t, spec.Cpu.Mask, "0-5") assert.True(t, spec.HasProcesses) assert.EqualValues(t, spec.Processes.Limit, 1027) assert.False(t, spec.HasHugetlb) assert.True(t, spec.HasDiskIo) } func TestGetSpecCgroupV2Max(t *testing.T) { root, err := os.Getwd() assert.Nil(t, err) cgroupPaths := map[string]string{ "": filepath.Join(root, "test_resources/cgroup_v2/test2"), } spec, err := getSpecInternal(cgroupPaths, &mockInfoProvider{}, false, false, true) assert.Nil(t, err) max := uint64(math.MaxUint64) assert.True(t, spec.HasMemory) assert.EqualValues(t, spec.Memory.Limit, max) assert.EqualValues(t, spec.Memory.SwapLimit, max) assert.EqualValues(t, spec.Memory.Reservation, max) assert.True(t, spec.HasCpu) assert.EqualValues(t, spec.Cpu.Limit, 1286) assert.EqualValues(t, spec.Cpu.Period, 100010) assert.EqualValues(t, spec.Cpu.Quota, 0) assert.EqualValues(t, spec.Processes.Limit, max) } func TestRemoveNetMetrics(t *testing.T) { for _, ts := range []struct { desc string in, out container.MetricSet }{ { desc: "nil set", in: nil, }, { desc: "empty set", in: container.MetricSet{}, }, { desc: "nothing to remove", in: container.MetricSet{container.MemoryUsageMetrics: struct{}{}, container.PerfMetrics: struct{}{}}, }, { desc: "also nothing to remove", in: container.AllMetrics.Difference(container.AllNetworkMetrics), }, { desc: "remove net from all", in: container.AllMetrics, out: container.AllMetrics.Difference(container.AllNetworkMetrics), }, { desc: "remove net from some", in: container.MetricSet{container.MemoryUsageMetrics: struct{}{}, container.NetworkTcpUsageMetrics: struct{}{}}, out: container.MetricSet{container.MemoryUsageMetrics: struct{}{}}, }, } { for _, remove := range []bool{true, false} { ts, remove := ts, remove desc := fmt.Sprintf("%s, remove: %v", ts.desc, remove) t.Run(desc, func(t *testing.T) { out := RemoveNetMetrics(ts.in, remove) if !remove || ts.out == nil { // Compare the actual underlying pointers. Can't use assert.Same // because it checks for pointer type, and these are maps. if reflect.ValueOf(ts.in) != reflect.ValueOf(out) { t.Errorf("expected original map %p, got %p", ts.in, out) } } else { assert.Equal(t, ts.out, out) } }) } } } func BenchmarkGetSpecCgroupV2(b *testing.B) { root, err := os.Getwd() if err != nil { b.Fatalf("getwd: %s", err) } cgroupPaths := map[string]string{ "": filepath.Join(root, "test_resources/cgroup_v2/test1"), } for i := 0; i < b.N; i++ { _, err := getSpecInternal(cgroupPaths, &mockInfoProvider{}, false, false, true) assert.Nil(b, err) } } func BenchmarkGetSpecCgroupV1(b *testing.B) { root, err := os.Getwd() if err != nil { b.Fatalf("getwd: %s", err) } cgroupPaths := map[string]string{ "memory": filepath.Join(root, "test_resources/cgroup_v1/test1/memory"), "cpu": filepath.Join(root, "test_resources/cgroup_v1/test1/cpu"), "cpuset": filepath.Join(root, "test_resources/cgroup_v1/test1/cpuset"), "pids": filepath.Join(root, "test_resources/cgroup_v1/test1/pids"), } for i := 0; i < b.N; i++ { _, err := getSpecInternal(cgroupPaths, &mockInfoProvider{}, false, false, false) assert.Nil(b, err) } } ================================================ FILE: container/common/inotify_watcher.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package common import ( "sync" inotify "k8s.io/utils/inotify" ) // Watcher for container-related inotify events in the cgroup hierarchy. // // Implementation is thread-safe. type InotifyWatcher struct { // Underlying inotify watcher. watcher *inotify.Watcher // Map of containers being watched to cgroup paths watched for that container. containersWatched map[string]map[string]bool // Lock for all datastructure access. lock sync.Mutex } func NewInotifyWatcher() (*InotifyWatcher, error) { w, err := inotify.NewWatcher() if err != nil { return nil, err } return &InotifyWatcher{ watcher: w, containersWatched: make(map[string]map[string]bool), }, nil } // Add a watch to the specified directory. Returns if the container was already being watched. func (iw *InotifyWatcher) AddWatch(containerName, dir string) (bool, error) { iw.lock.Lock() defer iw.lock.Unlock() cgroupsWatched, alreadyWatched := iw.containersWatched[containerName] // Register an inotify notification. if !cgroupsWatched[dir] { err := iw.watcher.AddWatch(dir, inotify.InCreate|inotify.InDelete|inotify.InMove) if err != nil { return alreadyWatched, err } if cgroupsWatched == nil { cgroupsWatched = make(map[string]bool) } cgroupsWatched[dir] = true } // Record our watching of the container. if !alreadyWatched { iw.containersWatched[containerName] = cgroupsWatched } return alreadyWatched, nil } // Remove watch from the specified directory. Returns if this was the last watch on the specified container. func (iw *InotifyWatcher) RemoveWatch(containerName, dir string) (bool, error) { iw.lock.Lock() defer iw.lock.Unlock() // If we don't have a watch registered for this, just return. cgroupsWatched, ok := iw.containersWatched[containerName] if !ok { return false, nil } // Remove the inotify watch if it exists. if cgroupsWatched[dir] { err := iw.watcher.RemoveWatch(dir) if err != nil { return false, nil } delete(cgroupsWatched, dir) } // Remove the record if this is the last watch. if len(cgroupsWatched) == 0 { delete(iw.containersWatched, containerName) return true, nil } return false, nil } // Errors are returned on this channel. func (iw *InotifyWatcher) Error() chan error { return iw.watcher.Error } // Events are returned on this channel. func (iw *InotifyWatcher) Event() chan *inotify.Event { return iw.watcher.Event } // Closes the inotify watcher. func (iw *InotifyWatcher) Close() error { return iw.watcher.Close() } // Returns a map of containers to the cgroup paths being watched. func (iw *InotifyWatcher) GetWatches() map[string][]string { out := make(map[string][]string, len(iw.containersWatched)) for k, v := range iw.containersWatched { out[k] = mapToSlice(v) } return out } func mapToSlice(m map[string]bool) []string { out := make([]string, 0, len(m)) for k := range m { out = append(out, k) } return out } ================================================ FILE: container/common/test_resources/cgroup_v1/test1/cpu/cpu.cfs_period_us ================================================ 100010 ================================================ FILE: container/common/test_resources/cgroup_v1/test1/cpu/cpu.cfs_quota_us ================================================ 20000 ================================================ FILE: container/common/test_resources/cgroup_v1/test1/cpu/cpu.shares ================================================ 1025 ================================================ FILE: container/common/test_resources/cgroup_v1/test1/cpuset/cpuset.cpus ================================================ 0-5 ================================================ FILE: container/common/test_resources/cgroup_v1/test1/memory/memory.limit_in_bytes ================================================ 123456789 ================================================ FILE: container/common/test_resources/cgroup_v1/test1/memory/memory.memsw.limit_in_bytes ================================================ 13579 ================================================ FILE: container/common/test_resources/cgroup_v1/test1/memory/memory.soft_limit_in_bytes ================================================ 24680 ================================================ FILE: container/common/test_resources/cgroup_v1/test1/pids/pids.max ================================================ 1027 ================================================ FILE: container/common/test_resources/cgroup_v2/test1/cpu.max ================================================ 20000 100010 ================================================ FILE: container/common/test_resources/cgroup_v2/test1/cpu.weight ================================================ 50 ================================================ FILE: container/common/test_resources/cgroup_v2/test1/cpuset.cpus.effective ================================================ 0-5 ================================================ FILE: container/common/test_resources/cgroup_v2/test1/memory.max ================================================ 123456789 ================================================ FILE: container/common/test_resources/cgroup_v2/test1/memory.min ================================================ 24680 ================================================ FILE: container/common/test_resources/cgroup_v2/test1/memory.swap.max ================================================ 13579 ================================================ FILE: container/common/test_resources/cgroup_v2/test1/pids.max ================================================ 1027 ================================================ FILE: container/common/test_resources/cgroup_v2/test2/cpu.max ================================================ max 100010 ================================================ FILE: container/common/test_resources/cgroup_v2/test2/cpu.weight ================================================ 50 ================================================ FILE: container/common/test_resources/cgroup_v2/test2/memory.max ================================================ max ================================================ FILE: container/common/test_resources/cgroup_v2/test2/memory.min ================================================ max ================================================ FILE: container/common/test_resources/cgroup_v2/test2/memory.swap.max ================================================ max ================================================ FILE: container/common/test_resources/cgroup_v2/test2/pids.max ================================================ max ================================================ FILE: container/common/test_resources/container_hints.json ================================================ { "name": "Container Hints", "description": "Container hints file", "all_hosts": [ { "network_interface": { "veth_child": "eth1", "veth_host": "veth24031eth1" }, "mounts": [ { "host_dir": "/var/run/nm-sdc1", "container_dir": "/var/run/nm-sdc1", "permission": "rw" }, { "host_dir": "/var/run/nm-sdb3", "container_dir": "/var/run/nm-sdb3", "permission": "rw" }, { "host_dir": "/var/run/nm-sda3", "container_dir": "/var/run/nm-sda3", "permission": "rw" }, { "host_dir": "/var/run/netns/root", "container_dir": "/var/run/netns/root", "permission": "ro" }, { "host_dir": "/var/run/openvswitch/db.sock", "container_dir": "/var/run/openvswitch/db.sock", "permission": "rw" } ], "full_path": "18a4585950db428e4d5a65c216a5d708d241254709626f4cb300ee963fb4b144" } ] } ================================================ FILE: container/container.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package container defines types for sub-container events and also // defines an interface for container operation handlers. package container import info "github.com/google/cadvisor/info/v1" // ListType describes whether listing should be just for a // specific container or performed recursively. type ListType int const ( ListSelf ListType = iota ListRecursive ) type ContainerType int const ( ContainerTypeRaw ContainerType = iota ContainerTypeDocker ContainerTypeCrio ContainerTypeContainerd ContainerTypePodman ) // Interface for container operation handlers. type ContainerHandler interface { // Returns the ContainerReference ContainerReference() (info.ContainerReference, error) // Returns container's isolation spec. GetSpec() (info.ContainerSpec, error) // Returns the current stats values of the container. GetStats() (*info.ContainerStats, error) // Returns the subcontainers of this container. ListContainers(listType ListType) ([]info.ContainerReference, error) // Returns the processes inside this container. ListProcesses(listType ListType) ([]int, error) // Returns absolute cgroup path for the requested resource. GetCgroupPath(resource string) (string, error) // Returns container labels, if available. GetContainerLabels() map[string]string // Returns the container's ip address, if available GetContainerIPAddress() string // GetExitCode returns the container's exit code if available. // Returns an error if the container has not exited, exit codes are not supported // for this handler type, or the container information is unavailable. GetExitCode() (int, error) // Returns whether the container still exists. Exists() bool // Cleanup frees up any resources being held like fds or go routines, etc. Cleanup() // Start starts any necessary background goroutines - must be cleaned up in Cleanup(). // It is expected that most implementations will be a no-op. Start() // Type of handler Type() ContainerType } ================================================ FILE: container/containerd/client.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package containerd import ( "context" "errors" "fmt" "net" "sync" "time" containersapi "github.com/containerd/containerd/api/services/containers/v1" tasksapi "github.com/containerd/containerd/api/services/tasks/v1" versionapi "github.com/containerd/containerd/api/services/version/v1" tasktypes "github.com/containerd/containerd/api/types/task" "github.com/containerd/errdefs/pkg/errgrpc" "google.golang.org/grpc" "google.golang.org/grpc/backoff" "google.golang.org/grpc/credentials/insecure" emptypb "google.golang.org/protobuf/types/known/emptypb" "github.com/google/cadvisor/container/containerd/containers" "github.com/google/cadvisor/container/containerd/pkg/dialer" ) type client struct { containerService containersapi.ContainersClient taskService tasksapi.TasksClient versionService versionapi.VersionClient } type ContainerdClient interface { LoadContainer(ctx context.Context, id string) (*containers.Container, error) TaskPid(ctx context.Context, id string) (uint32, error) LoadTaskProcess(ctx context.Context, id string) (*tasktypes.Process, error) TaskExitStatus(ctx context.Context, id string) (uint32, error) Version(ctx context.Context) (string, error) } var ( ErrTaskIsInUnknownState = errors.New("containerd task is in unknown state") // used when process reported in containerd task is in Unknown State ) var once sync.Once var ctrdClient ContainerdClient = nil var ctrdClientErr error = nil const ( maxBackoffDelay = 3 * time.Second baseBackoffDelay = 100 * time.Millisecond connectionTimeout = 2 * time.Second maxMsgSize = 16 * 1024 * 1024 // 16MB ) // Client creates a containerd client func Client(address, namespace string) (ContainerdClient, error) { once.Do(func() { tryConn, err := net.DialTimeout("unix", address, connectionTimeout) if err != nil { ctrdClientErr = fmt.Errorf("containerd: cannot unix dial containerd api service: %v", err) return } tryConn.Close() connParams := grpc.ConnectParams{ Backoff: backoff.DefaultConfig, } connParams.Backoff.BaseDelay = baseBackoffDelay connParams.Backoff.MaxDelay = maxBackoffDelay //nolint:staticcheck // SA1019 gopts := []grpc.DialOption{ grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(dialer.ContextDialer), grpc.WithBlock(), grpc.WithConnectParams(connParams), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize)), } unary, stream := newNSInterceptors(namespace) gopts = append(gopts, grpc.WithUnaryInterceptor(unary), grpc.WithStreamInterceptor(stream), ) ctx, cancel := context.WithTimeout(context.Background(), connectionTimeout) defer cancel() //nolint:staticcheck // SA1019 conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...) if err != nil { ctrdClientErr = err return } ctrdClient = &client{ containerService: containersapi.NewContainersClient(conn), taskService: tasksapi.NewTasksClient(conn), versionService: versionapi.NewVersionClient(conn), } }) return ctrdClient, ctrdClientErr } func (c *client) LoadContainer(ctx context.Context, id string) (*containers.Container, error) { r, err := c.containerService.Get(ctx, &containersapi.GetContainerRequest{ ID: id, }) if err != nil { return nil, errgrpc.ToNative(err) } return containerFromProto(r.Container), nil } func (c *client) TaskPid(ctx context.Context, id string) (uint32, error) { response, err := c.taskService.Get(ctx, &tasksapi.GetRequest{ ContainerID: id, }) if err != nil { return 0, errgrpc.ToNative(err) } if response.Process.Status == tasktypes.Status_UNKNOWN { return 0, ErrTaskIsInUnknownState } return response.Process.Pid, nil } func (c *client) LoadTaskProcess(ctx context.Context, id string) (*tasktypes.Process, error) { response, err := c.taskService.Get(ctx, &tasksapi.GetRequest{ ContainerID: id, }) if err != nil { return nil, errgrpc.ToNative(err) } return response.Process, nil } func (c *client) TaskExitStatus(ctx context.Context, id string) (uint32, error) { response, err := c.taskService.Get(ctx, &tasksapi.GetRequest{ ContainerID: id, }) if err != nil { return 0, errgrpc.ToNative(err) } if response.Process.Status != tasktypes.Status_STOPPED { return 0, fmt.Errorf("container %s has not exited (status: %v)", id, response.Process.Status) } return response.Process.ExitStatus, nil } func (c *client) Version(ctx context.Context) (string, error) { response, err := c.versionService.Version(ctx, &emptypb.Empty{}) if err != nil { return "", errgrpc.ToNative(err) } return response.Version, nil } func containerFromProto(containerpb *containersapi.Container) *containers.Container { var runtime containers.RuntimeInfo var createdAt time.Time // TODO: is nil check required for containerpb if containerpb.Runtime != nil { runtime = containers.RuntimeInfo{ Name: containerpb.Runtime.Name, Options: containerpb.Runtime.Options, } } if containerpb.GetCreatedAt() != nil { createdAt = containerpb.GetCreatedAt().AsTime() } return &containers.Container{ ID: containerpb.ID, Labels: containerpb.Labels, Image: containerpb.Image, Runtime: runtime, Spec: containerpb.Spec, Snapshotter: containerpb.Snapshotter, SnapshotKey: containerpb.SnapshotKey, Extensions: containerpb.Extensions, CreatedAt: createdAt, } } ================================================ FILE: container/containerd/client_test.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package containerd import ( "context" "fmt" "github.com/containerd/containerd/api/types/task" "github.com/google/cadvisor/container/containerd/containers" ) type containerdClientMock struct { cntrs map[string]*containers.Container returnErr error tasks map[string]*task.Process exitStatus uint32 } func (c *containerdClientMock) LoadContainer(ctx context.Context, id string) (*containers.Container, error) { if c.returnErr != nil { return nil, c.returnErr } cntr, ok := c.cntrs[id] if !ok { return nil, fmt.Errorf("unable to find container %q", id) } return cntr, nil } func (c *containerdClientMock) Version(ctx context.Context) (string, error) { return "test-v0.0.0", nil } func (c *containerdClientMock) TaskPid(ctx context.Context, id string) (uint32, error) { return 2389, nil } func (c *containerdClientMock) LoadTaskProcess(ctx context.Context, id string) (*task.Process, error) { if c.returnErr != nil { return nil, c.returnErr } task, ok := c.tasks[id] if !ok { return nil, fmt.Errorf("unable to find task for container %q", id) } return task, nil } func (c *containerdClientMock) TaskExitStatus(ctx context.Context, id string) (uint32, error) { if c.returnErr != nil { return 0, c.returnErr } return c.exitStatus, nil } func mockcontainerdClient(cntrs map[string]*containers.Container, returnErr error) ContainerdClient { tasks := make(map[string]*task.Process) for _, cntr := range cntrs { tasks[cntr.ID] = &task.Process{} } return &containerdClientMock{ cntrs: cntrs, returnErr: returnErr, tasks: tasks, } } ================================================ FILE: container/containerd/containers/containers.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package containers import ( "context" "time" "google.golang.org/protobuf/types/known/anypb" ) // Container represents the set of data pinned by a container. Unless otherwise // noted, the resources here are considered in use by the container. // // The resources specified in this object are used to create tasks from the container. type Container struct { // ID uniquely identifies the container in a namespace. // // This property is required and cannot be changed after creation. ID string // Labels provide metadata extension for a container. // // These are optional and fully mutable. Labels map[string]string // Image specifies the image reference used for a container. // // This property is optional and mutable. Image string // Runtime specifies which runtime should be used when launching container // tasks. // // This property is required and immutable. Runtime RuntimeInfo // Spec should carry the runtime specification used to implement the // container. // // This field is required but mutable. Spec *anypb.Any // SnapshotKey specifies the snapshot key to use for the container's root // filesystem. When starting a task from this container, a caller should // look up the mounts from the snapshot service and include those on the // task create request. // // This field is not required but mutable. SnapshotKey string // Snapshotter specifies the snapshotter name used for rootfs // // This field is not required but immutable. Snapshotter string // CreatedAt is the time at which the container was created. CreatedAt time.Time // UpdatedAt is the time at which the container was updated. UpdatedAt time.Time // Extensions stores client-specified metadata Extensions map[string]*anypb.Any } // RuntimeInfo holds runtime specific information type RuntimeInfo struct { Name string Options *anypb.Any } // Store interacts with the underlying container storage type Store interface { // Get a container using the id. // // Container object is returned on success. If the id is not known to the // store, an error will be returned. Get(ctx context.Context, id string) (Container, error) // List returns containers that match one or more of the provided filters. List(ctx context.Context, filters ...string) ([]Container, error) // Create a container in the store from the provided container. Create(ctx context.Context, container Container) (Container, error) // Update the container with the provided container object. ID must be set. // // If one or more fieldpaths are provided, only the field corresponding to // the fieldpaths will be mutated. Update(ctx context.Context, container Container, fieldpaths ...string) (Container, error) // Delete a container using the id. // // nil will be returned on success. If the container is not known to the // store, ErrNotFound will be returned. Delete(ctx context.Context, id string) error } ================================================ FILE: container/containerd/factory.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package containerd import ( "context" "flag" "fmt" "path" "regexp" "strings" "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/watcher" ) var ArgContainerdEndpoint = flag.String("containerd", "/run/containerd/containerd.sock", "containerd endpoint") var ArgContainerdNamespace = flag.String("containerd-namespace", "k8s.io", "containerd namespace") var containerdEnvMetadataWhiteList = flag.String("containerd_env_metadata_whitelist", "", "DEPRECATED: this flag will be removed, please use `env_metadata_whitelist`. A comma-separated list of environment variable keys matched with specified prefix that needs to be collected for containerd containers") // The namespace under which containerd aliases are unique. const k8sContainerdNamespace = "containerd" // Regexp that identifies containerd cgroups, containers started with // --cgroup-parent have another prefix than 'containerd' var containerdCgroupRegexp = regexp.MustCompile(`([a-z0-9]{64})`) type containerdFactory struct { machineInfoFactory info.MachineInfoFactory client ContainerdClient version string // Information about the mounted cgroup subsystems. cgroupSubsystems map[string]string // Information about mounted filesystems. fsInfo fs.FsInfo includedMetrics container.MetricSet } func (f *containerdFactory) String() string { return k8sContainerdNamespace } func (f *containerdFactory) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (handler container.ContainerHandler, err error) { client, err := Client(*ArgContainerdEndpoint, *ArgContainerdNamespace) if err != nil { return } containerdMetadataEnvAllowList := strings.Split(*containerdEnvMetadataWhiteList, ",") // prefer using the unified metadataEnvAllowList if len(metadataEnvAllowList) != 0 { containerdMetadataEnvAllowList = metadataEnvAllowList } return newContainerdContainerHandler( client, name, f.machineInfoFactory, f.fsInfo, f.cgroupSubsystems, inHostNamespace, containerdMetadataEnvAllowList, f.includedMetrics, ) } // Returns the containerd ID from the full container name. func ContainerNameToContainerdID(name string) string { id := path.Base(name) if matches := containerdCgroupRegexp.FindStringSubmatch(id); matches != nil { return matches[1] } return id } // isContainerName returns true if the cgroup with associated name // corresponds to a containerd container. func isContainerName(name string) bool { // TODO: May be check with HasPrefix ContainerdNamespace if strings.HasSuffix(name, ".mount") { return false } return containerdCgroupRegexp.MatchString(path.Base(name)) } // Containerd can handle and accept all containerd created containers func (f *containerdFactory) CanHandleAndAccept(name string) (bool, bool, error) { // if the container is not associated with containerd, we can't handle it or accept it. if !isContainerName(name) { return false, false, nil } // Check if the container is known to containerd and it is running. id := ContainerNameToContainerdID(name) // If container and task lookup in containerd fails then we assume // that the container state is not known to containerd ctx, cancel := context.WithTimeout(context.Background(), connectionTimeout) defer cancel() _, err := f.client.LoadContainer(ctx, id) if err != nil { return false, false, fmt.Errorf("failed to load container: %v", err) } return true, true, nil } func (f *containerdFactory) DebugInfo() map[string][]string { return map[string][]string{} } // Register root container before running this function! func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error { client, err := Client(*ArgContainerdEndpoint, *ArgContainerdNamespace) if err != nil { return fmt.Errorf("unable to create containerd client: %v", err) } containerdVersion, err := client.Version(context.Background()) if err != nil { return fmt.Errorf("failed to fetch containerd client version: %v", err) } cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics) if err != nil { return fmt.Errorf("failed to get cgroup subsystems: %v", err) } klog.V(1).Infof("Registering containerd factory") f := &containerdFactory{ cgroupSubsystems: cgroupSubsystems, client: client, fsInfo: fsInfo, machineInfoFactory: factory, version: containerdVersion, includedMetrics: includedMetrics, } container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw}) return nil } ================================================ FILE: container/containerd/factory_test.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package containerd import ( "testing" "github.com/containerd/typeurl/v2" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/stretchr/testify/assert" "github.com/google/cadvisor/container/containerd/containers" ) func TestIsContainerName(t *testing.T) { tests := []struct { name string expected bool }{ { name: "/system.slice/run-containerd-io.containerd.runtime.v1.linux-k8s.io-14ae50f1d3ada102aec3ab00168fdafb2dc0986d79ca9e8d5b75581fa89e9fea-rootfs.mount", expected: false, }, { name: "/kubepods/besteffort/podd76e26fba3bf2bfd215eb29011d55250/40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", expected: true, }, } for _, test := range tests { if actual := isContainerName(test.name); actual != test.expected { t.Errorf("%s: expected: %v, actual: %v", test.name, test.expected, actual) } } } func TestCanHandleAndAccept(t *testing.T) { as := assert.New(t) testContainers := make(map[string]*containers.Container) testContainer := &containers.Container{ ID: "40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", Labels: map[string]string{"io.cri-containerd.kind": "sandbox"}, } spec := &specs.Spec{Root: &specs.Root{Path: "/test/"}, Process: &specs.Process{}} testContainer.Spec, _ = typeurl.MarshalAnyToProto(spec) testContainers["40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9"] = testContainer f := &containerdFactory{ client: mockcontainerdClient(testContainers, nil), cgroupSubsystems: nil, fsInfo: nil, machineInfoFactory: nil, includedMetrics: nil, } for k, v := range map[string]bool{ "/kubepods/besteffort/podd76e26fba3bf2bfd215eb29011d55250/40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9": true, "/system.slice/run-containerd-io.containerd.runtime.v1.linux-k8s.io-14ae50f1d3ada102aec3ab00168fdafb2dc0986d79ca9e8d5b75581fa89e9fea-rootfs.mount": false, } { b1, b2, err := f.CanHandleAndAccept(k) as.Nil(err) as.Equal(b1, v) as.Equal(b2, v) } } ================================================ FILE: container/containerd/grpc.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // This code has been taken from containerd repo to avoid large library import package containerd import ( "context" "google.golang.org/grpc" "github.com/google/cadvisor/container/containerd/namespaces" ) type namespaceInterceptor struct { namespace string } func (ni namespaceInterceptor) unary(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { _, ok := namespaces.Namespace(ctx) if !ok { ctx = namespaces.WithNamespace(ctx, ni.namespace) } return invoker(ctx, method, req, reply, cc, opts...) } func (ni namespaceInterceptor) stream(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { _, ok := namespaces.Namespace(ctx) if !ok { ctx = namespaces.WithNamespace(ctx, ni.namespace) } return streamer(ctx, desc, cc, method, opts...) } func newNSInterceptors(ns string) (grpc.UnaryClientInterceptor, grpc.StreamClientInterceptor) { ni := namespaceInterceptor{ namespace: ns, } return grpc.UnaryClientInterceptor(ni.unary), grpc.StreamClientInterceptor(ni.stream) } ================================================ FILE: container/containerd/handler.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Handler for containerd containers. package containerd import ( "context" "encoding/json" "errors" "fmt" "strings" "time" "github.com/containerd/errdefs" "github.com/opencontainers/cgroups" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/common" containerlibcontainer "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" ) type containerdContainerHandler struct { machineInfoFactory info.MachineInfoFactory // Absolute path to the cgroup hierarchies of this container. // (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test") cgroupPaths map[string]string fsInfo fs.FsInfo // Metadata associated with the container. reference info.ContainerReference envs map[string]string labels map[string]string // Time at which this container was created. creationTime time.Time // Image name used for this container. image string // Filesystem handler. includedMetrics container.MetricSet libcontainerHandler *containerlibcontainer.Handler client ContainerdClient } var _ container.ContainerHandler = &containerdContainerHandler{} // newContainerdContainerHandler returns a new container.ContainerHandler func newContainerdContainerHandler( client ContainerdClient, name string, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, cgroupSubsystems map[string]string, inHostNamespace bool, metadataEnvAllowList []string, includedMetrics container.MetricSet, ) (container.ContainerHandler, error) { // Create the cgroup paths. cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems, name) // Generate the equivalent cgroup manager for this container. cgroupManager, err := containerlibcontainer.NewCgroupManager(name, cgroupPaths) if err != nil { return nil, err } id := ContainerNameToContainerdID(name) // We assume that if load fails then the container is not known to containerd. ctx := context.Background() cntr, err := client.LoadContainer(ctx, id) if err != nil { return nil, err } var spec specs.Spec if err := json.Unmarshal(cntr.Spec.Value, &spec); err != nil { return nil, err } // Cgroup is created during task creation. When cadvisor sees the cgroup, // task may not be fully created yet. Use a retry+backoff to tolerant the // race condition. // TODO(random-liu): Use cri-containerd client to talk with cri-containerd // instead. cri-containerd has some internal synchronization to make sure // `ContainerStatus` only returns result after `StartContainer` finishes. var taskPid uint32 backoff := 100 * time.Millisecond retry := 5 for { taskPid, err = client.TaskPid(ctx, id) if err == nil { break } // Retry when task is not created yet or task is in unknown state (likely in process of initializing) isRetriableError := errdefs.IsNotFound(err) || errors.Is(err, ErrTaskIsInUnknownState) if !isRetriableError || retry == 0 { return nil, err } retry-- time.Sleep(backoff) backoff *= 2 } rootfs := "/" if !inHostNamespace { rootfs = "/rootfs" } containerReference := info.ContainerReference{ Id: id, Name: name, Namespace: k8sContainerdNamespace, Aliases: []string{id, name}, } // Containers that don't have their own network -- this includes // containers running in Kubernetes pods that use the network of the // infrastructure container -- does not need their stats to be // reported. This stops metrics being reported multiple times for each // container in a pod. metrics := common.RemoveNetMetrics(includedMetrics, cntr.Labels["io.cri-containerd.kind"] != "sandbox") libcontainerHandler := containerlibcontainer.NewHandler(cgroupManager, rootfs, int(taskPid), metrics) handler := &containerdContainerHandler{ machineInfoFactory: machineInfoFactory, cgroupPaths: cgroupPaths, fsInfo: fsInfo, envs: make(map[string]string), labels: cntr.Labels, includedMetrics: metrics, reference: containerReference, libcontainerHandler: libcontainerHandler, client: client, } if !cntr.CreatedAt.IsZero() && !cntr.CreatedAt.Before(time.Unix(0, 0)) { handler.creationTime = cntr.CreatedAt } // Add the name and bare ID as aliases of the container. handler.image = cntr.Image for _, exposedEnv := range metadataEnvAllowList { if exposedEnv == "" { // if no containerdEnvWhitelist provided, len(metadataEnvAllowList) == 1, metadataEnvAllowList[0] == "" continue } for _, envVar := range spec.Process.Env { if envVar != "" { splits := strings.SplitN(envVar, "=", 2) if len(splits) == 2 && strings.HasPrefix(splits[0], exposedEnv) { handler.envs[splits[0]] = splits[1] } } } } return handler, nil } func (h *containerdContainerHandler) ContainerReference() (info.ContainerReference, error) { return h.reference, nil } func (h *containerdContainerHandler) GetSpec() (info.ContainerSpec, error) { // TODO: Since we dont collect disk usage stats for containerd, we set hasFilesystem // to false. Revisit when we support disk usage stats for containerd hasFilesystem := false hasNet := h.includedMetrics.Has(container.NetworkUsageMetrics) spec, err := common.GetSpec(h.cgroupPaths, h.machineInfoFactory, hasNet, hasFilesystem) spec.Labels = h.labels spec.Envs = h.envs spec.Image = h.image startTime := spec.CreationTime if !h.creationTime.IsZero() { spec.CreationTime = h.creationTime } if !startTime.IsZero() { spec.StartTime = startTime } return spec, err } func (h *containerdContainerHandler) getFsStats(stats *info.ContainerStats) error { mi, err := h.machineInfoFactory.GetMachineInfo() if err != nil { return err } if h.includedMetrics.Has(container.DiskIOMetrics) { common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo) } return nil } func (h *containerdContainerHandler) GetStats() (*info.ContainerStats, error) { stats, err := h.libcontainerHandler.GetStats() if err != nil { return stats, err } // Get filesystem stats. err = h.getFsStats(stats) return stats, err } func (h *containerdContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { return []info.ContainerReference{}, nil } func (h *containerdContainerHandler) GetCgroupPath(resource string) (string, error) { var res string if !cgroups.IsCgroup2UnifiedMode() { res = resource } path, ok := h.cgroupPaths[res] if !ok { return "", fmt.Errorf("could not find path for resource %q for container %q", resource, h.reference.Name) } return path, nil } func (h *containerdContainerHandler) GetContainerLabels() map[string]string { return h.labels } func (h *containerdContainerHandler) ListProcesses(listType container.ListType) ([]int, error) { return h.libcontainerHandler.GetProcesses() } func (h *containerdContainerHandler) Exists() bool { return common.CgroupExists(h.cgroupPaths) } func (h *containerdContainerHandler) Type() container.ContainerType { return container.ContainerTypeContainerd } func (h *containerdContainerHandler) Start() { } func (h *containerdContainerHandler) Cleanup() { } func (h *containerdContainerHandler) GetContainerIPAddress() string { // containerd doesnt take care of networking.So it doesnt maintain networking states return "" } func (h *containerdContainerHandler) GetExitCode() (int, error) { ctx := context.Background() exitStatus, err := h.client.TaskExitStatus(ctx, h.reference.Id) if err != nil { return -1, err } return int(exitStatus), nil } ================================================ FILE: container/containerd/handler_test.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Handler for containerd containers. package containerd import ( "testing" "github.com/containerd/typeurl/v2" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/stretchr/testify/assert" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/containerd/containers" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" ) func init() { typeurl.Register(&specs.Spec{}, "types.contianerd.io/opencontainers/runtime-spec", "v1", "Spec") } type mockedMachineInfo struct{} func (m *mockedMachineInfo) GetMachineInfo() (*info.MachineInfo, error) { return &info.MachineInfo{}, nil } func (m *mockedMachineInfo) GetVersionInfo() (*info.VersionInfo, error) { return &info.VersionInfo{}, nil } func TestHandler(t *testing.T) { as := assert.New(t) type testCase struct { client ContainerdClient name string machineInfoFactory info.MachineInfoFactory fsInfo fs.FsInfo cgroupSubsystems map[string]string inHostNamespace bool metadataEnvAllowList []string includedMetrics container.MetricSet hasErr bool errContains string checkReference *info.ContainerReference checkEnvVars map[string]string } testContainers := make(map[string]*containers.Container) testContainer := &containers.Container{ ID: "40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", Labels: map[string]string{"io.cri-containerd.kind": "sandbox"}, } spec := &specs.Spec{Root: &specs.Root{Path: "/test/"}, Process: &specs.Process{Env: []string{"TEST_REGION=FRA", "TEST_ZONE=A", "HELLO=WORLD"}}} testContainer.Spec, _ = typeurl.MarshalAnyToProto(spec) testContainers["40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9"] = testContainer for _, ts := range []testCase{ { mockcontainerdClient(nil, nil), "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", nil, nil, nil, false, nil, nil, true, "unable to find container \"40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9\"", nil, nil, }, { mockcontainerdClient(testContainers, nil), "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", &mockedMachineInfo{}, nil, nil, false, nil, nil, false, "", &info.ContainerReference{ Id: "40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", Name: "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", Aliases: []string{"40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9"}, Namespace: k8sContainerdNamespace, }, map[string]string{}, }, { mockcontainerdClient(testContainers, nil), "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", &mockedMachineInfo{}, nil, nil, false, []string{"TEST"}, nil, false, "", &info.ContainerReference{ Id: "40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", Name: "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", Aliases: []string{"40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9", "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/40af7cdcbe507acad47a5a62025743ad3ddc6ab93b77b21363aa1c1d641047c9"}, Namespace: k8sContainerdNamespace, }, map[string]string{"TEST_REGION": "FRA", "TEST_ZONE": "A"}, }, } { handler, err := newContainerdContainerHandler(ts.client, ts.name, ts.machineInfoFactory, ts.fsInfo, ts.cgroupSubsystems, ts.inHostNamespace, ts.metadataEnvAllowList, ts.includedMetrics) if ts.hasErr { as.NotNil(err) if ts.errContains != "" { as.Contains(err.Error(), ts.errContains) } } if ts.checkReference != nil { cr, err := handler.ContainerReference() as.Nil(err) as.Equal(*ts.checkReference, cr) } if ts.checkEnvVars != nil { sp, err := handler.GetSpec() as.Nil(err) as.Equal(ts.checkEnvVars, sp.Envs) } } } func TestGetExitCode(t *testing.T) { tests := []struct { name string exitStatus uint32 returnErr error expectErr bool errContains string expectedCode int }{ { name: "successful exit code 0", exitStatus: 0, returnErr: nil, expectErr: false, expectedCode: 0, }, { name: "successful exit code 1", exitStatus: 1, returnErr: nil, expectErr: false, expectedCode: 1, }, { name: "task not stopped", exitStatus: 0, returnErr: assert.AnError, expectErr: true, expectedCode: -1, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { as := assert.New(t) mockClient := &containerdClientMock{ returnErr: tt.returnErr, exitStatus: tt.exitStatus, } h := &containerdContainerHandler{ client: mockClient, reference: info.ContainerReference{ Id: "test-container-id", }, } code, err := h.GetExitCode() if tt.expectErr { as.Error(err) as.Equal(tt.expectedCode, code) } else { as.NoError(err) as.Equal(tt.expectedCode, code) } }) } } ================================================ FILE: container/containerd/identifiers/validate.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // Package identifiers provides common validation for identifiers and keys // across containerd. // // Identifiers in containerd must be a alphanumeric, allowing limited // underscores, dashes and dots. // // While the character set may be expanded in the future, identifiers // are guaranteed to be safely used as filesystem path components. package identifiers import ( "fmt" "regexp" "github.com/containerd/errdefs" ) const ( maxLength = 76 alphanum = `[A-Za-z0-9]+` separators = `[._-]` ) var ( // identifierRe defines the pattern for valid identifiers. identifierRe = regexp.MustCompile(reAnchor(alphanum + reGroup(separators+reGroup(alphanum)) + "*")) ) // Validate returns nil if the string s is a valid identifier. // // identifiers are similar to the domain name rules according to RFC 1035, section 2.3.1. However // rules in this package are relaxed to allow numerals to follow period (".") and mixed case is // allowed. // // In general identifiers that pass this validation should be safe for use as filesystem path components. func Validate(s string) error { if len(s) == 0 { return fmt.Errorf("identifier must not be empty: %w", errdefs.ErrInvalidArgument) } if len(s) > maxLength { return fmt.Errorf("identifier %q greater than maximum length (%d characters): %w", s, maxLength, errdefs.ErrInvalidArgument) } if !identifierRe.MatchString(s) { return fmt.Errorf("identifier %q must match %v: %w", s, identifierRe, errdefs.ErrInvalidArgument) } return nil } func reGroup(s string) string { return `(?:` + s + `)` } func reAnchor(s string) string { return `^` + s + `$` } ================================================ FILE: container/containerd/identifiers/validate_test.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package identifiers import ( "strings" "testing" "github.com/containerd/errdefs" ) func TestValidIdentifiers(t *testing.T) { for _, input := range []string{ "default", "Default", t.Name(), "default-default", "containerd.io", "foo.boo", "swarmkit.docker.io", "0912341234", "task.0.0123456789", "container.system-75-f19a.00", "underscores_are_allowed", strings.Repeat("a", maxLength), } { t.Run(input, func(t *testing.T) { if err := Validate(input); err != nil { t.Fatalf("unexpected error: %v != nil", err) } }) } } func TestInvalidIdentifiers(t *testing.T) { for _, input := range []string{ "", ".foo..foo", "foo/foo", "foo/..", "foo..foo", "foo.-boo", "-foo.boo", "foo.boo-", "but__only_tasteful_underscores", "zn--e9.org", // or something like it! "default--default", strings.Repeat("a", maxLength+1), } { t.Run(input, func(t *testing.T) { if err := Validate(input); err == nil { t.Fatal("expected invalid error") } else if !errdefs.IsInvalidArgument(err) { t.Fatal("error should be an invalid identifier error") } }) } } ================================================ FILE: container/containerd/install/install.go ================================================ // Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // The install package registers containerd.NewPlugin() as the "containerd" container provider when imported package install import ( "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/containerd" ) func init() { err := container.RegisterPlugin("containerd", containerd.NewPlugin()) if err != nil { klog.Fatalf("Failed to register containerd plugin: %v", err) } } ================================================ FILE: container/containerd/namespaces/context.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package namespaces import ( "context" "fmt" "os" "github.com/containerd/errdefs" "github.com/google/cadvisor/container/containerd/identifiers" ) const ( // NamespaceEnvVar is the environment variable key name NamespaceEnvVar = "CONTAINERD_NAMESPACE" // Default is the name of the default namespace Default = "default" ) type namespaceKey struct{} // WithNamespace sets a given namespace on the context func WithNamespace(ctx context.Context, namespace string) context.Context { ctx = context.WithValue(ctx, namespaceKey{}, namespace) // set our key for namespace // also store on the grpc and ttrpc headers so it gets picked up by any clients that // are using this. return withTTRPCNamespaceHeader(withGRPCNamespaceHeader(ctx, namespace), namespace) } // NamespaceFromEnv uses the namespace defined in CONTAINERD_NAMESPACE or // default func NamespaceFromEnv(ctx context.Context) context.Context { namespace := os.Getenv(NamespaceEnvVar) if namespace == "" { namespace = Default } return WithNamespace(ctx, namespace) } // Namespace returns the namespace from the context. // // The namespace is not guaranteed to be valid. func Namespace(ctx context.Context) (string, bool) { namespace, ok := ctx.Value(namespaceKey{}).(string) if !ok { if namespace, ok = fromGRPCHeader(ctx); !ok { return fromTTRPCHeader(ctx) } } return namespace, ok } // NamespaceRequired returns the valid namespace from the context or an error. func NamespaceRequired(ctx context.Context) (string, error) { namespace, ok := Namespace(ctx) if !ok || namespace == "" { return "", fmt.Errorf("namespace is required: %w", errdefs.ErrFailedPrecondition) } if err := identifiers.Validate(namespace); err != nil { return "", fmt.Errorf("namespace validation: %w", err) } return namespace, nil } ================================================ FILE: container/containerd/namespaces/context_test.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package namespaces import ( "context" "os" "testing" ) func TestContext(t *testing.T) { ctx := context.Background() namespace, ok := Namespace(ctx) if ok { t.Fatal("namespace should not be present") } if namespace != "" { t.Fatalf("namespace should not be defined: got %q", namespace) } expected := "test" nctx := WithNamespace(ctx, expected) namespace, ok = Namespace(nctx) if !ok { t.Fatal("expected to find a namespace") } if namespace != expected { t.Fatalf("unexpected namespace: %q != %q", namespace, expected) } } func TestNamespaceFromEnv(t *testing.T) { oldenv := os.Getenv(NamespaceEnvVar) defer os.Setenv(NamespaceEnvVar, oldenv) // restore old env var ctx := context.Background() namespace, ok := Namespace(ctx) if ok { t.Fatal("namespace should not be present") } if namespace != "" { t.Fatalf("namespace should not be defined: got %q", namespace) } expected := "test-namespace" os.Setenv(NamespaceEnvVar, expected) nctx := NamespaceFromEnv(ctx) namespace, ok = Namespace(nctx) if !ok { t.Fatal("expected to find a namespace") } if namespace != expected { t.Fatalf("unexpected namespace: %q != %q", namespace, expected) } } ================================================ FILE: container/containerd/namespaces/grpc.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package namespaces import ( "context" "google.golang.org/grpc/metadata" ) const ( // GRPCHeader defines the header name for specifying a containerd namespace. GRPCHeader = "containerd-namespace" ) // NOTE(stevvooe): We can stub this file out if we don't want a grpc dependency here. func withGRPCNamespaceHeader(ctx context.Context, namespace string) context.Context { // also store on the grpc headers so it gets picked up by any clients that // are using this. nsheader := metadata.Pairs(GRPCHeader, namespace) md, ok := metadata.FromOutgoingContext(ctx) // merge with outgoing context. if !ok { md = nsheader } else { // order ensures the latest is first in this list. md = metadata.Join(nsheader, md) } return metadata.NewOutgoingContext(ctx, md) } func fromGRPCHeader(ctx context.Context) (string, bool) { // try to extract for use in grpc servers. md, ok := metadata.FromIncomingContext(ctx) if !ok { // TODO(stevvooe): Check outgoing context? return "", false } values := md[GRPCHeader] if len(values) == 0 { return "", false } return values[0], true } ================================================ FILE: container/containerd/namespaces/store.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package namespaces import "context" // Store provides introspection about namespaces. // // Note that these are slightly different than other objects, which are record // oriented. A namespace is really just a name and a set of labels. Objects // that belong to a namespace are returned when the namespace is assigned to a // given context. type Store interface { Create(ctx context.Context, namespace string, labels map[string]string) error Labels(ctx context.Context, namespace string) (map[string]string, error) SetLabel(ctx context.Context, namespace, key, value string) error List(ctx context.Context) ([]string, error) // Delete removes the namespace. The namespace must be empty to be deleted. Delete(ctx context.Context, namespace string, opts ...DeleteOpts) error } // DeleteInfo specifies information for the deletion of a namespace type DeleteInfo struct { // Name of the namespace Name string } // DeleteOpts allows the caller to set options for namespace deletion type DeleteOpts func(context.Context, *DeleteInfo) error ================================================ FILE: container/containerd/namespaces/ttrpc.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package namespaces import ( "context" "github.com/containerd/ttrpc" ) const ( // TTRPCHeader defines the header name for specifying a containerd namespace TTRPCHeader = "containerd-namespace-ttrpc" ) func copyMetadata(src ttrpc.MD) ttrpc.MD { md := ttrpc.MD{} for k, v := range src { md[k] = append(md[k], v...) } return md } func withTTRPCNamespaceHeader(ctx context.Context, namespace string) context.Context { md, ok := ttrpc.GetMetadata(ctx) if !ok { md = ttrpc.MD{} } else { md = copyMetadata(md) } md.Set(TTRPCHeader, namespace) return ttrpc.WithMetadata(ctx, md) } func fromTTRPCHeader(ctx context.Context) (string, bool) { return ttrpc.GetMetadataValue(ctx, TTRPCHeader) } ================================================ FILE: container/containerd/namespaces/ttrpc_test.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package namespaces import ( "context" "reflect" "testing" "github.com/containerd/ttrpc" ) func TestCopyTTRPCMetadata(t *testing.T) { src := ttrpc.MD{} src.Set("key", "a", "b", "c", "d") md := copyMetadata(src) if !reflect.DeepEqual(src, md) { t.Fatalf("metadata is copied incorrectly") } slice, _ := src.Get("key") slice[0] = "z" if reflect.DeepEqual(src, md) { t.Fatalf("metadata is copied incorrectly") } } func TestTTRPCNamespaceHeader(t *testing.T) { ctx := context.Background() namespace := "test-namespace" ctx = withTTRPCNamespaceHeader(ctx, namespace) header, ok := fromTTRPCHeader(ctx) if !ok || header != namespace { t.Fatalf("ttrp namespace header is set incorrectly") } } ================================================ FILE: container/containerd/pkg/dialer/dialer.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package dialer import ( "context" "fmt" "net" "time" ) type dialResult struct { c net.Conn err error } // ContextDialer returns a GRPC net.Conn connected to the provided address func ContextDialer(ctx context.Context, address string) (net.Conn, error) { if deadline, ok := ctx.Deadline(); ok { return timeoutDialer(address, time.Until(deadline)) } return timeoutDialer(address, 0) } // Dialer returns a GRPC net.Conn connected to the provided address // Deprecated: use ContextDialer and grpc.WithContextDialer. var Dialer = timeoutDialer func timeoutDialer(address string, timeout time.Duration) (net.Conn, error) { var ( stopC = make(chan struct{}) synC = make(chan *dialResult) ) go func() { defer close(synC) for { select { case <-stopC: return default: c, err := dialer(address, timeout) if isNoent(err) { <-time.After(10 * time.Millisecond) continue } synC <- &dialResult{c, err} return } } }() select { case dr := <-synC: return dr.c, dr.err case <-time.After(timeout): close(stopC) go func() { dr := <-synC if dr != nil && dr.c != nil { dr.c.Close() } }() return nil, fmt.Errorf("dial %s: timeout", address) } } ================================================ FILE: container/containerd/pkg/dialer/dialer_unix.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build !windows /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package dialer import ( "fmt" "net" "os" "strings" "syscall" "time" ) // DialAddress returns the address with unix:// prepended to the // provided address func DialAddress(address string) string { return fmt.Sprintf("unix://%s", address) } func isNoent(err error) bool { if err != nil { if nerr, ok := err.(*net.OpError); ok { if serr, ok := nerr.Err.(*os.SyscallError); ok { if serr.Err == syscall.ENOENT { return true } } } } return false } func dialer(address string, timeout time.Duration) (net.Conn, error) { address = strings.TrimPrefix(address, "unix://") return net.DialTimeout("unix", address, timeout) } ================================================ FILE: container/containerd/pkg/dialer/dialer_windows.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package dialer import ( "net" "os" "time" winio "github.com/Microsoft/go-winio" ) func isNoent(err error) bool { return os.IsNotExist(err) } func dialer(address string, timeout time.Duration) (net.Conn, error) { return winio.DialPipe(address, &timeout) } // DialAddress returns the dial address func DialAddress(address string) string { return address } ================================================ FILE: container/containerd/plugin.go ================================================ // Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package containerd import ( "github.com/google/cadvisor/container" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/watcher" ) // NewPlugin returns an implementation of container.Plugin suitable for passing to container.RegisterPlugin() func NewPlugin() container.Plugin { return &plugin{} } type plugin struct{} func (p *plugin) InitializeFSContext(context *fs.Context) error { return nil } func (p *plugin) Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) (watcher.ContainerWatcher, error) { err := Register(factory, fsInfo, includedMetrics) return nil, err } ================================================ FILE: container/crio/client.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package crio import ( "context" "encoding/json" "flag" "fmt" "io" "net" "net/http" "sync" "syscall" "time" ) var crioClientTimeout = flag.Duration("crio_client_timeout", time.Duration(0), "CRI-O client timeout. Default is no timeout.") const ( CrioSocket = "/var/run/crio/crio.sock" maxUnixSocketPathSize = len(syscall.RawSockaddrUnix{}.Path) ) var ( theClient CrioClient clientErr error crioClientOnce sync.Once ) // Info represents CRI-O information as sent by the CRI-O server type Info struct { StorageDriver string `json:"storage_driver"` StorageRoot string `json:"storage_root"` StorageImage string `json:"storage_image"` CgroupDriver string `json:"cgroup_driver"` } // ContainerInfo represents a given container information type ContainerInfo struct { Name string `json:"name"` Pid int `json:"pid"` Image string `json:"image"` CreatedTime int64 `json:"created_time"` Labels map[string]string `json:"labels"` Annotations map[string]string `json:"annotations"` LogPath string `json:"log_path"` Root string `json:"root"` IP string `json:"ip_address"` IPs []string `json:"ip_addresses"` } type CrioClient interface { Info() (Info, error) ContainerInfo(string) (*ContainerInfo, error) } type crioClientImpl struct { client *http.Client } func configureUnixTransport(tr *http.Transport, proto, addr string) error { if len(addr) > maxUnixSocketPathSize { return fmt.Errorf("unix socket path %q is too long", addr) } // No need for compression in local communications. tr.DisableCompression = true tr.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) { return net.DialTimeout(proto, addr, 32*time.Second) } return nil } // Client returns a new configured CRI-O client func Client() (CrioClient, error) { crioClientOnce.Do(func() { tr := new(http.Transport) theClient = nil if clientErr = configureUnixTransport(tr, "unix", CrioSocket); clientErr != nil { return } theClient = &crioClientImpl{ client: &http.Client{ Transport: tr, Timeout: *crioClientTimeout, }, } }) return theClient, clientErr } func getRequest(path string) (*http.Request, error) { req, err := http.NewRequest("GET", path, nil) if err != nil { return nil, err } // For local communications over a unix socket, it doesn't matter what // the host is. We just need a valid and meaningful host name. req.Host = "crio" req.URL.Host = CrioSocket req.URL.Scheme = "http" return req, nil } // Info returns generic info from the CRI-O server func (c *crioClientImpl) Info() (Info, error) { info := Info{} req, err := getRequest("/info") if err != nil { return info, err } resp, err := c.client.Do(req) if err != nil { return info, err } defer resp.Body.Close() if err := json.NewDecoder(resp.Body).Decode(&info); err != nil { return info, err } return info, nil } // ContainerInfo returns information about a given container func (c *crioClientImpl) ContainerInfo(id string) (*ContainerInfo, error) { req, err := getRequest("/containers/" + id) if err != nil { return nil, err } cInfo := ContainerInfo{} resp, err := c.client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() // golang's http.Do doesn't return an error if non 200 response code is returned // handle this case here, rather than failing to decode the body if resp.StatusCode != http.StatusOK { respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("error finding container %s: status %d", id, resp.StatusCode) } return nil, fmt.Errorf("error finding container %s: status %d returned error %s", id, resp.StatusCode, string(respBody)) } if err := json.NewDecoder(resp.Body).Decode(&cInfo); err != nil { return nil, err } if len(cInfo.IP) > 0 { return &cInfo, nil } if len(cInfo.IPs) > 0 { cInfo.IP = cInfo.IPs[0] } return &cInfo, nil } ================================================ FILE: container/crio/client_test.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package crio import "fmt" type crioClientMock struct { info Info containersInfo map[string]*ContainerInfo err error } func (c *crioClientMock) Info() (Info, error) { if c.err != nil { return Info{}, c.err } return c.info, nil } func (c *crioClientMock) ContainerInfo(id string) (*ContainerInfo, error) { if c.err != nil { return nil, c.err } cInfo, ok := c.containersInfo[id] if !ok { return nil, fmt.Errorf("no container with id %s", id) } return cInfo, nil } func mockCrioClient(info Info, containersInfo map[string]*ContainerInfo, err error) CrioClient { return &crioClientMock{ err: err, info: info, containersInfo: containersInfo, } } ================================================ FILE: container/crio/factory.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package crio import ( "fmt" "path" "regexp" "strings" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/watcher" "k8s.io/klog/v2" ) // The namespace under which crio aliases are unique. const CrioNamespace = "crio" // The namespace suffix under which crio aliases are unique when using systemd. const CrioNamespaceSuffix = ".scope" // The namespace systemd runs components under. const SystemdNamespace = "system-systemd" // Regexp that identifies CRI-O cgroups var crioCgroupRegexp = regexp.MustCompile(`([a-z0-9]{64})`) type storageDriver string const ( // TODO add full set of supported drivers in future.. overlayStorageDriver storageDriver = "overlay" overlay2StorageDriver storageDriver = "overlay2" ) type crioFactory struct { machineInfoFactory info.MachineInfoFactory storageDriver storageDriver storageDir string // Information about the mounted cgroup subsystems. cgroupSubsystems map[string]string // Information about mounted filesystems. fsInfo fs.FsInfo includedMetrics container.MetricSet client CrioClient cgroupDriver string } func (f *crioFactory) String() string { return CrioNamespace } func (f *crioFactory) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (handler container.ContainerHandler, err error) { client, err := Client() if err != nil { return } handler, err = newCrioContainerHandler( client, name, f.machineInfoFactory, f.fsInfo, f.storageDriver, f.storageDir, f.cgroupSubsystems, inHostNamespace, metadataEnvAllowList, f.includedMetrics, ) return } // Returns the CRIO ID from the full container name. func ContainerNameToCrioId(name string) string { id := path.Base(name) if matches := crioCgroupRegexp.FindStringSubmatch(id); matches != nil { return matches[1] } return id } // isContainerName returns true if the cgroup with associated name // corresponds to a crio container. func isContainerName(name string) bool { // always ignore .mount cgroup even if associated with crio and delegate to systemd if strings.HasSuffix(name, ".mount") { return false } return crioCgroupRegexp.MatchString(path.Base(name)) } // crio handles all containers under /crio func (f *crioFactory) CanHandleAndAccept(name string) (bool, bool, error) { if strings.HasPrefix(path.Base(name), "crio-conmon") { // TODO(runcom): should we include crio-conmon cgroups? return false, false, nil } if strings.HasPrefix(path.Base(name), SystemdNamespace) { return true, false, nil } if !strings.HasPrefix(path.Base(name), CrioNamespace) { return false, false, nil } // if the container is not associated with CRI-O, we can't handle it or accept it. if !isContainerName(name) { return false, false, nil } // When using systemd as the cgroup driver, sandbox containers don't have // the .scope suffix. Filter them out to prevent cadvisor from trying to // query cri-o for containers that don't exist in the runtime, which causes // 404 errors and can lead to deadlocks during kubelet restart. // See: https://github.com/cri-o/cri-o/issues/8748 // See: https://github.com/google/cadvisor/pull/3457 if f.cgroupDriver == "systemd" { if !strings.HasSuffix(path.Base(name), CrioNamespaceSuffix) { // This is a sandbox container when using systemd return true, false, nil } } return true, true, nil } func (f *crioFactory) DebugInfo() map[string][]string { return map[string][]string{} } // Register root container before running this function! func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error { client, err := Client() if err != nil { return err } info, err := client.Info() if err != nil { return err } // TODO determine crio version so we can work differently w/ future versions if needed cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics) if err != nil { return fmt.Errorf("failed to get cgroup subsystems: %v", err) } klog.V(1).Infof("Registering CRI-O factory") f := &crioFactory{ client: client, cgroupSubsystems: cgroupSubsystems, fsInfo: fsInfo, machineInfoFactory: factory, storageDriver: storageDriver(info.StorageDriver), storageDir: info.StorageRoot, includedMetrics: includedMetrics, cgroupDriver: info.CgroupDriver, } container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw}) return nil } ================================================ FILE: container/crio/factory_test.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package crio import ( "testing" "github.com/stretchr/testify/assert" ) func TestCanHandleAndAccept(t *testing.T) { tests := []struct { name string cgroupDriver string path string wantCanHandle bool wantCanAccept bool }{ // Systemd behavior - sandbox containers (without .scope) are filtered { name: "systemd: sandbox container without .scope", cgroupDriver: "systemd", path: "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f", wantCanHandle: true, wantCanAccept: false, }, { name: "systemd: regular container with .scope", cgroupDriver: "systemd", path: "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f.scope", wantCanHandle: true, wantCanAccept: true, }, // Non-systemd (cgroupfs) behavior - all valid containers accepted { name: "cgroupfs: container without .scope", cgroupDriver: "cgroupfs", path: "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f", wantCanHandle: true, wantCanAccept: true, }, { name: "cgroupfs: container with .scope", cgroupDriver: "cgroupfs", path: "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f.scope", wantCanHandle: true, wantCanAccept: true, }, // Common cases (same behavior for both systemd and cgroupfs) { name: "system-systemd component", cgroupDriver: "systemd", path: "/system.slice/system-systemd\\x2dcoredump.slice", wantCanHandle: true, wantCanAccept: false, }, { name: "mount cgroup", cgroupDriver: "systemd", path: "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f.mount", wantCanHandle: false, wantCanAccept: false, }, { name: "crio-conmon container", cgroupDriver: "systemd", path: "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-conmon-81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f", wantCanHandle: false, wantCanAccept: false, }, { name: "invalid container ID", cgroupDriver: "systemd", path: "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75", wantCanHandle: false, wantCanAccept: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { f := &crioFactory{ cgroupDriver: tt.cgroupDriver, } canHandle, canAccept, err := f.CanHandleAndAccept(tt.path) assert.NoError(t, err) assert.Equal(t, tt.wantCanHandle, canHandle, "canHandle mismatch") assert.Equal(t, tt.wantCanAccept, canAccept, "canAccept mismatch") }) } } ================================================ FILE: container/crio/handler.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Handler for CRI-O containers. package crio import ( "fmt" "path/filepath" "strconv" "strings" "github.com/opencontainers/cgroups" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/common" containerlibcontainer "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" ) type crioContainerHandler struct { client CrioClient name string machineInfoFactory info.MachineInfoFactory // Absolute path to the cgroup hierarchies of this container. // (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test") cgroupPaths map[string]string // the CRI-O storage driver storageDriver storageDriver fsInfo fs.FsInfo rootfsStorageDir string // Metadata associated with the container. envs map[string]string labels map[string]string // TODO // crio version handling... // Image name used for this container. image string // The network mode of the container // TODO // Filesystem handler. fsHandler common.FsHandler // The IP address of the container ipAddress string includedMetrics container.MetricSet reference info.ContainerReference libcontainerHandler *containerlibcontainer.Handler cgroupManager cgroups.Manager rootFs string pidKnown bool } var _ container.ContainerHandler = &crioContainerHandler{} // newCrioContainerHandler returns a new container.ContainerHandler func newCrioContainerHandler( client CrioClient, name string, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, storageDriver storageDriver, storageDir string, cgroupSubsystems map[string]string, inHostNamespace bool, metadataEnvAllowList []string, includedMetrics container.MetricSet, ) (container.ContainerHandler, error) { // Create the cgroup paths. cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems, name) // Generate the equivalent cgroup manager for this container. cgroupManager, err := containerlibcontainer.NewCgroupManager(name, cgroupPaths) if err != nil { return nil, err } rootFs := "/" if !inHostNamespace { rootFs = "/rootfs" } id := ContainerNameToCrioId(name) pidKnown := true cInfo, err := client.ContainerInfo(id) if err != nil { return nil, err } if cInfo.Pid == 0 { // If pid is not known yet, network related stats can not be retrieved by the // libcontainer handler GetStats(). In this case, the crio handler GetStats() // will reattempt to get the pid and, if now known, will construct the libcontainer // handler. This libcontainer handler is then cached and reused without additional // calls to crio. pidKnown = false } // passed to fs handler below ... // XXX: this is using the full container logpath, as constructed by the CRI // /var/log/pods//container_instance.log // It's not actually a log dir, as the CRI doesn't have per-container dirs // under /var/log/pods// // We can't use /var/log/pods// to count per-container log usage. // We use the container log file directly. storageLogDir := cInfo.LogPath // Determine the rootfs storage dir rootfsStorageDir := cInfo.Root // TODO(runcom): CRI-O doesn't strip /merged but we need to in order to // get device ID from root, otherwise, it's going to error out as overlay // mounts doesn't have fixed dev ids. rootfsStorageDir = strings.TrimSuffix(rootfsStorageDir, "/merged") switch storageDriver { case overlayStorageDriver, overlay2StorageDriver: // overlay and overlay2 driver are the same "overlay2" driver so treat // them the same. rootfsStorageDir = filepath.Join(rootfsStorageDir, "diff") } containerReference := info.ContainerReference{ Id: id, Name: name, Aliases: []string{cInfo.Name, id}, Namespace: CrioNamespace, } // Find out if we need network metrics reported for this container. // Containers that don't have their own network -- this includes // containers running in Kubernetes pods that use the network of the // infrastructure container -- does not need their stats to be // reported. This stops metrics being reported multiple times for each // container in a pod. metrics := common.RemoveNetMetrics(includedMetrics, cInfo.Labels["io.kubernetes.container.name"] != "POD") libcontainerHandler := containerlibcontainer.NewHandler(cgroupManager, rootFs, cInfo.Pid, metrics) // TODO: extract object mother method handler := &crioContainerHandler{ client: client, name: name, machineInfoFactory: machineInfoFactory, cgroupPaths: cgroupPaths, storageDriver: storageDriver, fsInfo: fsInfo, rootfsStorageDir: rootfsStorageDir, envs: make(map[string]string), labels: cInfo.Labels, includedMetrics: metrics, reference: containerReference, libcontainerHandler: libcontainerHandler, cgroupManager: cgroupManager, rootFs: rootFs, pidKnown: pidKnown, } handler.image = cInfo.Image // TODO: we wantd to know graph driver DeviceId (dont think this is needed now) // ignore err and get zero as default, this happens with sandboxes, not sure why... // kube isn't sending restart count in labels for sandboxes. restartCount, _ := strconv.Atoi(cInfo.Annotations["io.kubernetes.container.restartCount"]) // Only adds restartcount label if it's greater than 0 if restartCount > 0 { handler.labels["restartcount"] = strconv.Itoa(restartCount) } handler.ipAddress = cInfo.IP // we optionally collect disk usage metrics if includedMetrics.Has(container.DiskUsageMetrics) { handler.fsHandler = common.NewFsHandler(common.DefaultPeriod, rootfsStorageDir, storageLogDir, fsInfo) } // TODO for env vars we wanted to show from container.Config.Env from whitelist //for _, exposedEnv := range metadataEnvAllowList { //klog.V(4).Infof("TODO env whitelist: %v", exposedEnv) //} return handler, nil } func (h *crioContainerHandler) Start() { if h.fsHandler != nil { h.fsHandler.Start() } } func (h *crioContainerHandler) Cleanup() { if h.fsHandler != nil { h.fsHandler.Stop() } } func (h *crioContainerHandler) ContainerReference() (info.ContainerReference, error) { return h.reference, nil } func (h *crioContainerHandler) GetSpec() (info.ContainerSpec, error) { hasFilesystem := h.includedMetrics.Has(container.DiskUsageMetrics) hasNet := h.includedMetrics.Has(container.NetworkUsageMetrics) spec, err := common.GetSpec(h.cgroupPaths, h.machineInfoFactory, hasNet, hasFilesystem) spec.Labels = h.labels spec.Envs = h.envs spec.Image = h.image return spec, err } func (h *crioContainerHandler) getFsStats(stats *info.ContainerStats) error { mi, err := h.machineInfoFactory.GetMachineInfo() if err != nil { return err } if h.includedMetrics.Has(container.DiskIOMetrics) { common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo) } if !h.includedMetrics.Has(container.DiskUsageMetrics) { return nil } var device string switch h.storageDriver { case overlay2StorageDriver, overlayStorageDriver: deviceInfo, err := h.fsInfo.GetDirFsDevice(h.rootfsStorageDir) if err != nil { return fmt.Errorf("unable to determine device info for dir: %v: %v", h.rootfsStorageDir, err) } device = deviceInfo.Device default: return nil } var ( limit uint64 fsType string ) // crio does not impose any filesystem limits for containers. So use capacity as limit. for _, fs := range mi.Filesystems { if fs.Device == device { limit = fs.Capacity fsType = fs.Type break } } if fsType == "" { return fmt.Errorf("unable to determine fs type for device: %v", device) } fsStat := info.FsStats{Device: device, Type: fsType, Limit: limit} usage := h.fsHandler.Usage() fsStat.BaseUsage = usage.BaseUsageBytes fsStat.Usage = usage.TotalUsageBytes fsStat.Inodes = usage.InodeUsage stats.Filesystem = append(stats.Filesystem, fsStat) return nil } func (h *crioContainerHandler) getLibcontainerHandler() *containerlibcontainer.Handler { if h.pidKnown { return h.libcontainerHandler } id := ContainerNameToCrioId(h.name) cInfo, err := h.client.ContainerInfo(id) if err != nil || cInfo.Pid == 0 { return h.libcontainerHandler } h.pidKnown = true h.libcontainerHandler = containerlibcontainer.NewHandler(h.cgroupManager, h.rootFs, cInfo.Pid, h.includedMetrics) return h.libcontainerHandler } func (h *crioContainerHandler) GetStats() (*info.ContainerStats, error) { libcontainerHandler := h.getLibcontainerHandler() stats, err := libcontainerHandler.GetStats() if err != nil { return stats, err } if h.includedMetrics.Has(container.NetworkUsageMetrics) && len(stats.Network.Interfaces) == 0 { // No network related information indicates that the pid of the // container is not longer valid and we need to ask crio to // provide the pid of another container from that pod h.pidKnown = false return stats, nil } // Get filesystem stats. err = h.getFsStats(stats) if err != nil { return stats, err } return stats, nil } func (h *crioContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { // No-op for Docker driver. return []info.ContainerReference{}, nil } func (h *crioContainerHandler) GetCgroupPath(resource string) (string, error) { var res string if !cgroups.IsCgroup2UnifiedMode() { res = resource } path, ok := h.cgroupPaths[res] if !ok { return "", fmt.Errorf("could not find path for resource %q for container %q", resource, h.reference.Name) } return path, nil } func (h *crioContainerHandler) GetContainerLabels() map[string]string { return h.labels } func (h *crioContainerHandler) GetContainerIPAddress() string { return h.ipAddress } func (h *crioContainerHandler) ListProcesses(listType container.ListType) ([]int, error) { return h.libcontainerHandler.GetProcesses() } func (h *crioContainerHandler) Exists() bool { return common.CgroupExists(h.cgroupPaths) } func (h *crioContainerHandler) Type() container.ContainerType { return container.ContainerTypeCrio } func (h *crioContainerHandler) GetExitCode() (int, error) { return -1, fmt.Errorf("exit code not available from CRI-O API") } ================================================ FILE: container/crio/handler_test.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package crio import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/google/cadvisor/container" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" ) func TestHandler(t *testing.T) { as := assert.New(t) type testCase struct { client CrioClient name string machineInfoFactory info.MachineInfoFactory fsInfo fs.FsInfo storageDriver storageDriver storageDir string cgroupSubsystems map[string]string inHostNamespace bool metadataEnvAllowList []string includedMetrics container.MetricSet hasErr bool errContains string checkReference *info.ContainerReference } for _, ts := range []testCase{ { mockCrioClient(Info{}, nil, fmt.Errorf("no client returned")), "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f", nil, nil, "", "", nil, false, nil, nil, true, "no client returned", nil, }, { mockCrioClient(Info{}, nil, nil), "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f", nil, nil, "", "", nil, false, nil, nil, true, "no container with id 81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f", nil, }, { mockCrioClient( Info{}, map[string]*ContainerInfo{"81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f": {Name: "test", Labels: map[string]string{"io.kubernetes.container.name": "POD"}}}, nil, ), "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f", nil, nil, "", "", nil, false, nil, nil, false, "", &info.ContainerReference{ Id: "81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f", Name: "/kubepods/pod068e8fa0-9213-11e7-a01f-507b9d4141fa/crio-81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f", Aliases: []string{"test", "81e5c2990803c383229c9680ce964738d5e566d97f5bd436ac34808d2ec75d5f"}, Namespace: CrioNamespace, }, }, } { handler, err := newCrioContainerHandler(ts.client, ts.name, ts.machineInfoFactory, ts.fsInfo, ts.storageDriver, ts.storageDir, ts.cgroupSubsystems, ts.inHostNamespace, ts.metadataEnvAllowList, ts.includedMetrics) if ts.hasErr { as.NotNil(err) if ts.errContains != "" { as.Contains(err.Error(), ts.errContains) } } if ts.checkReference != nil { cr, err := handler.ContainerReference() as.Nil(err) as.Equal(*ts.checkReference, cr) } } } ================================================ FILE: container/crio/install/install.go ================================================ // Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // The install package registers crio.NewPlugin() as the "crio" container provider when imported package install import ( "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/crio" ) func init() { err := container.RegisterPlugin("crio", crio.NewPlugin()) if err != nil { klog.Fatalf("Failed to register crio plugin: %v", err) } } ================================================ FILE: container/crio/plugin.go ================================================ // Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package crio import ( "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/watcher" ) // NewPlugin returns an implementation of container.Plugin suitable for passing to container.RegisterPlugin() func NewPlugin() container.Plugin { return &plugin{} } type plugin struct{} func (p *plugin) InitializeFSContext(context *fs.Context) error { crioClient, err := Client() if err != nil { return err } crioInfo, err := crioClient.Info() if err != nil { klog.V(5).Infof("CRI-O not connected: %v", err) } else { context.Crio = fs.CrioContext{Root: crioInfo.StorageRoot, ImageStore: crioInfo.StorageImage, Driver: crioInfo.StorageDriver} } return nil } func (p *plugin) Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) (watcher.ContainerWatcher, error) { err := Register(factory, fsInfo, includedMetrics) return nil, err } ================================================ FILE: container/docker/client.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Handler for /validate content. // Validates cadvisor dependencies - kernel, os, docker setup. package docker import ( "net/http" "sync" "github.com/docker/go-connections/tlsconfig" dclient "github.com/moby/moby/client" ) var ( dockerClient *dclient.Client dockerClientErr error dockerClientOnce sync.Once ) // Client creates a Docker API client based on the given Docker flags func Client() (*dclient.Client, error) { dockerClientOnce.Do(func() { var client *http.Client if *ArgDockerTLS { client = &http.Client{} options := tlsconfig.Options{ CAFile: *ArgDockerCA, CertFile: *ArgDockerCert, KeyFile: *ArgDockerKey, InsecureSkipVerify: false, } tlsc, err := tlsconfig.Client(options) if err != nil { dockerClientErr = err return } client.Transport = &http.Transport{ TLSClientConfig: tlsc, } } dockerClient, dockerClientErr = dclient.New( dclient.WithHost(*ArgDockerEndpoint), dclient.WithHTTPClient(client), ) }) return dockerClient, dockerClientErr } ================================================ FILE: container/docker/docker.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Provides global docker information. package docker import ( "context" "fmt" "regexp" "strconv" "time" dockersystem "github.com/moby/moby/api/types/system" dclient "github.com/moby/moby/client" "github.com/google/cadvisor/container/docker/utils" v1 "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/machine" ) var dockerTimeout = 10 * time.Second func SetTimeout(timeout time.Duration) { dockerTimeout = timeout } func Status() (v1.DockerStatus, error) { ctx, cancel := context.WithTimeout(context.Background(), dockerTimeout) defer cancel() return StatusWithContext(ctx) } func StatusWithContext(ctx context.Context) (v1.DockerStatus, error) { client, err := Client() if err != nil { return v1.DockerStatus{}, fmt.Errorf("unable to communicate with docker daemon: %v", err) } res, err := client.Info(ctx, dclient.InfoOptions{}) if err != nil { return v1.DockerStatus{}, err } return StatusFromDockerInfo(res.Info) } func StatusFromDockerInfo(dockerInfo dockersystem.Info) (v1.DockerStatus, error) { out := v1.DockerStatus{} out.KernelVersion = machine.KernelVersion() out.OS = dockerInfo.OperatingSystem out.Hostname = dockerInfo.Name out.RootDir = dockerInfo.DockerRootDir out.Driver = dockerInfo.Driver out.NumImages = dockerInfo.Images out.NumContainers = dockerInfo.Containers out.DriverStatus = make(map[string]string, len(dockerInfo.DriverStatus)) for _, v := range dockerInfo.DriverStatus { out.DriverStatus[v[0]] = v[1] } var err error ver, err := VersionString() if err != nil { return out, err } out.Version = ver ver, err = APIVersionString() if err != nil { return out, err } out.APIVersion = ver return out, nil } func Images() ([]v1.DockerImage, error) { client, err := Client() if err != nil { return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err) } ctx, cancel := context.WithTimeout(context.Background(), dockerTimeout) defer cancel() summaries, err := client.ImageList(ctx, dclient.ImageListOptions{All: false}) if err != nil { return nil, err } return utils.SummariesToImages(summaries.Items) } // ValidateInfo checks whether the dockerInfo reflects a valid docker setup, and returns it if it does, or an // error otherwise. func ValidateInfo(GetInfo func() (*dockersystem.Info, error), ServerVersion func() (string, error)) (*dockersystem.Info, error) { info, err := GetInfo() if err != nil { return nil, err } // Fall back to version API if ServerVersion is not set in info. if info.ServerVersion == "" { var err error info.ServerVersion, err = ServerVersion() if err != nil { return nil, fmt.Errorf("unable to get runtime version: %v", err) } } version, err := ParseVersion(info.ServerVersion, VersionRe, 3) if err != nil { return nil, err } if version[0] < 1 { return nil, fmt.Errorf("cAdvisor requires runtime version %v or above but we have found version %v reported as %q", []int{1, 0, 0}, version, info.ServerVersion) } if info.Driver == "" { return nil, fmt.Errorf("failed to find runtime storage driver") } return info, nil } func Info() (*dockersystem.Info, error) { client, err := Client() if err != nil { return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err) } ctx, cancel := context.WithTimeout(context.Background(), dockerTimeout) defer cancel() res, err := client.Info(ctx, dclient.InfoOptions{}) if err != nil { return nil, fmt.Errorf("failed to detect Docker info: %v", err) } return &res.Info, nil } func APIVersion() ([]int, error) { ver, err := APIVersionString() if err != nil { return nil, err } return ParseVersion(ver, apiVersionRe, 2) } func VersionString() (string, error) { dockerVersion := "Unknown" client, err := Client() if err == nil { ctx, cancel := context.WithTimeout(context.Background(), dockerTimeout) defer cancel() version, err := client.ServerVersion(ctx, dclient.ServerVersionOptions{}) if err == nil { dockerVersion = version.Version } } return dockerVersion, err } func APIVersionString() (string, error) { apiVersion := "Unknown" client, err := Client() if err == nil { ctx, cancel := context.WithTimeout(context.Background(), dockerTimeout) defer cancel() version, err := client.Ping(ctx, dclient.PingOptions{NegotiateAPIVersion: true}) if err == nil { apiVersion = version.APIVersion } } return apiVersion, err } func ParseVersion(versionString string, regex *regexp.Regexp, length int) ([]int, error) { matches := regex.FindAllStringSubmatch(versionString, -1) if len(matches) != 1 { return nil, fmt.Errorf("version string \"%v\" doesn't match expected regular expression: \"%v\"", versionString, regex.String()) } versionStringArray := matches[0][1:] versionArray := make([]int, length) for index, versionStr := range versionStringArray { version, err := strconv.Atoi(versionStr) if err != nil { return nil, fmt.Errorf("error while parsing \"%v\" in \"%v\"", versionStr, versionString) } versionArray[index] = version } return versionArray, nil } ================================================ FILE: container/docker/docker_test.go ================================================ // Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package docker import ( "reflect" "regexp" "testing" ) func TestParseDockerAPIVersion(t *testing.T) { tests := []struct { version string regex *regexp.Regexp length int expected []int expectedError string }{ {"17.03.0", VersionRe, 3, []int{17, 03, 0}, ""}, {"17.a3.0", VersionRe, 3, []int{}, `version string "17.a3.0" doesn't match expected regular expression: "(\d+)\.(\d+)\.(\d+)"`}, {"1.20", apiVersionRe, 2, []int{1, 20}, ""}, {"1.a", apiVersionRe, 2, []int{}, `version string "1.a" doesn't match expected regular expression: "(\d+)\.(\d+)"`}, } for _, test := range tests { actual, err := ParseVersion(test.version, test.regex, test.length) if err != nil { if len(test.expectedError) == 0 { t.Errorf("%s: expected no error, got %v", test.version, err) } else if err.Error() != test.expectedError { t.Errorf("%s: expected error %v, got %v", test.version, test.expectedError, err) } } else { if !reflect.DeepEqual(actual, test.expected) { t.Errorf("%s: expected array %v, got %v", test.version, test.expected, actual) } } } } ================================================ FILE: container/docker/factory.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package docker import ( "context" "flag" "fmt" "regexp" "strconv" "strings" "sync" "time" "github.com/blang/semver/v4" dockersystem "github.com/moby/moby/api/types/system" dclient "github.com/moby/moby/client" "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/containerd" dockerutil "github.com/google/cadvisor/container/docker/utils" "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/devicemapper" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/machine" "github.com/google/cadvisor/watcher" "github.com/google/cadvisor/zfs" ) var ArgDockerEndpoint = flag.String("docker", "unix:///var/run/docker.sock", "docker endpoint") var ArgDockerTLS = flag.Bool("docker-tls", false, "use TLS to connect to docker") var ArgDockerCert = flag.String("docker-tls-cert", "cert.pem", "path to client certificate") var ArgDockerKey = flag.String("docker-tls-key", "key.pem", "path to private key") var ArgDockerCA = flag.String("docker-tls-ca", "ca.pem", "path to trusted CA") var dockerEnvMetadataWhiteList = flag.String("docker_env_metadata_whitelist", "", "DEPRECATED: this flag will be removed, please use `env_metadata_whitelist`. A comma-separated list of environment variable keys matched with specified prefix that needs to be collected for docker containers") // The namespace under which Docker aliases are unique. const DockerNamespace = "docker" // The retry times for getting docker root dir const rootDirRetries = 5 // The retry period for getting docker root dir, Millisecond const rootDirRetryPeriod time.Duration = 1000 * time.Millisecond var ( // Basepath to all container specific information that libcontainer stores. dockerRootDir string dockerRootDirFlag = flag.String("docker_root", "/var/lib/docker", "DEPRECATED: docker root is read from docker info (this is a fallback, default: /var/lib/docker)") dockerRootDirOnce sync.Once // flag that controls globally disabling thin_ls pending future enhancements. // in production, it has been found that thin_ls makes excessive use of iops. // in an iops restricted environment, usage of thin_ls must be controlled via blkio. // pending that enhancement, disable its usage. disableThinLs = true ) func RootDir() string { dockerRootDirOnce.Do(func() { for i := 0; i < rootDirRetries; i++ { status, err := Status() if err == nil && status.RootDir != "" { dockerRootDir = status.RootDir break } else { time.Sleep(rootDirRetryPeriod) } } if dockerRootDir == "" { dockerRootDir = *dockerRootDirFlag } }) return dockerRootDir } type StorageDriver string const ( DevicemapperStorageDriver StorageDriver = "devicemapper" AufsStorageDriver StorageDriver = "aufs" OverlayStorageDriver StorageDriver = "overlay" Overlay2StorageDriver StorageDriver = "overlay2" ContainerdSnapshotterStorageDriver StorageDriver = "overlayfs" ZfsStorageDriver StorageDriver = "zfs" VfsStorageDriver StorageDriver = "vfs" ) type dockerFactory struct { machineInfoFactory info.MachineInfoFactory storageDriver StorageDriver storageDir string client *dclient.Client containerdClient containerd.ContainerdClient // Information about the mounted cgroup subsystems. cgroupSubsystems map[string]string // Information about mounted filesystems. fsInfo fs.FsInfo dockerVersion []int dockerAPIVersion []int includedMetrics container.MetricSet thinPoolName string thinPoolWatcher *devicemapper.ThinPoolWatcher zfsWatcher *zfs.ZfsWatcher } func (f *dockerFactory) String() string { return DockerNamespace } func (f *dockerFactory) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (handler container.ContainerHandler, err error) { client, err := Client() if err != nil { return } dockerMetadataEnvAllowList := strings.Split(*dockerEnvMetadataWhiteList, ",") // prefer using the unified metadataEnvAllowList if len(metadataEnvAllowList) != 0 { dockerMetadataEnvAllowList = metadataEnvAllowList } handler, err = newContainerHandler( client, f.containerdClient, name, f.machineInfoFactory, f.fsInfo, f.storageDriver, f.storageDir, f.cgroupSubsystems, inHostNamespace, dockerMetadataEnvAllowList, f.dockerVersion, f.includedMetrics, f.thinPoolName, f.thinPoolWatcher, f.zfsWatcher, ) return } // Docker handles all containers under /docker func (f *dockerFactory) CanHandleAndAccept(name string) (bool, bool, error) { // if the container is not associated with docker, we can't handle it or accept it. if !dockerutil.IsContainerName(name) { return false, false, nil } // Check if the container is known to docker and it is active. id := dockerutil.ContainerNameToId(name) // We assume that if Inspect fails then the container is not known to docker. res, err := f.client.ContainerInspect(context.Background(), id, dclient.ContainerInspectOptions{}) if err != nil || !res.Container.State.Running { return false, true, fmt.Errorf("error inspecting container: %v", err) } return true, true, nil } func (f *dockerFactory) DebugInfo() map[string][]string { return map[string][]string{} } var ( versionRegexpString = `(\d+)\.(\d+)\.(\d+)` VersionRe = regexp.MustCompile(versionRegexpString) apiVersionRegexpString = `(\d+)\.(\d+)` apiVersionRe = regexp.MustCompile(apiVersionRegexpString) ) func StartThinPoolWatcher(dockerInfo *dockersystem.Info) (*devicemapper.ThinPoolWatcher, error) { _, err := devicemapper.ThinLsBinaryPresent() if err != nil { return nil, err } if err := ensureThinLsKernelVersion(machine.KernelVersion()); err != nil { return nil, err } if disableThinLs { return nil, fmt.Errorf("usage of thin_ls is disabled to preserve iops") } dockerThinPoolName, err := dockerutil.DockerThinPoolName(*dockerInfo) if err != nil { return nil, err } dockerMetadataDevice, err := dockerutil.DockerMetadataDevice(*dockerInfo) if err != nil { return nil, err } thinPoolWatcher, err := devicemapper.NewThinPoolWatcher(dockerThinPoolName, dockerMetadataDevice) if err != nil { return nil, err } go thinPoolWatcher.Start() return thinPoolWatcher, nil } func StartZfsWatcher(dockerInfo *dockersystem.Info) (*zfs.ZfsWatcher, error) { filesystem, err := dockerutil.DockerZfsFilesystem(*dockerInfo) if err != nil { return nil, err } zfsWatcher, err := zfs.NewZfsWatcher(filesystem) if err != nil { return nil, err } go zfsWatcher.Start() return zfsWatcher, nil } func ensureThinLsKernelVersion(kernelVersion string) error { // kernel 4.4.0 has the proper bug fixes to allow thin_ls to work without corrupting the thin pool minKernelVersion := semver.MustParse("4.4.0") // RHEL 7 kernel 3.10.0 release >= 366 has the proper bug fixes backported from 4.4.0 to allow // thin_ls to work without corrupting the thin pool minRhel7KernelVersion := semver.MustParse("3.10.0") matches := VersionRe.FindStringSubmatch(kernelVersion) if len(matches) < 4 { return fmt.Errorf("error parsing kernel version: %q is not a semver", kernelVersion) } sem, err := semver.Make(matches[0]) if err != nil { return err } if sem.GTE(minKernelVersion) { // kernel 4.4+ - good return nil } // Certain RHEL/Centos 7.x kernels have a backport to fix the corruption bug if !strings.Contains(kernelVersion, ".el7") { // not a RHEL 7.x kernel - won't work return fmt.Errorf("kernel version 4.4.0 or later is required to use thin_ls - you have %q", kernelVersion) } // RHEL/Centos 7.x from here on if sem.Major != 3 { // only 3.x kernels *may* work correctly return fmt.Errorf("RHEL/Centos 7.x kernel version 3.10.0-366 or later is required to use thin_ls - you have %q", kernelVersion) } if sem.GT(minRhel7KernelVersion) { // 3.10.1+ - good return nil } if sem.EQ(minRhel7KernelVersion) { // need to check release releaseRE := regexp.MustCompile(`^[^-]+-([0-9]+)\.`) releaseMatches := releaseRE.FindStringSubmatch(kernelVersion) if len(releaseMatches) != 2 { return fmt.Errorf("unable to determine RHEL/Centos 7.x kernel release from %q", kernelVersion) } release, err := strconv.Atoi(releaseMatches[1]) if err != nil { return fmt.Errorf("error parsing release %q: %v", releaseMatches[1], err) } if release >= 366 { return nil } } return fmt.Errorf("RHEL/Centos 7.x kernel version 3.10.0-366 or later is required to use thin_ls - you have %q", kernelVersion) } // Register root container before running this function! func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error { client, err := Client() if err != nil { return fmt.Errorf("unable to communicate with docker daemon: %v", err) } dockerInfo, err := ValidateInfo(Info, VersionString) if err != nil { return fmt.Errorf("failed to validate Docker info: %v", err) } // Version already validated above, assume no error here. dockerVersion, _ := ParseVersion(dockerInfo.ServerVersion, VersionRe, 3) dockerAPIVersion, _ := APIVersion() cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics) if err != nil { return fmt.Errorf("failed to get cgroup subsystems: %v", err) } var ( thinPoolWatcher *devicemapper.ThinPoolWatcher thinPoolName string zfsWatcher *zfs.ZfsWatcher containerdClient containerd.ContainerdClient ) if includedMetrics.Has(container.DiskUsageMetrics) { if StorageDriver(dockerInfo.Driver) == DevicemapperStorageDriver { thinPoolWatcher, err = StartThinPoolWatcher(dockerInfo) if err != nil { klog.Errorf("devicemapper filesystem stats will not be reported: %v", err) } // Safe to ignore error - driver status should always be populated. status, _ := StatusFromDockerInfo(*dockerInfo) thinPoolName = status.DriverStatus[dockerutil.DriverStatusPoolName] } if StorageDriver(dockerInfo.Driver) == ZfsStorageDriver { zfsWatcher, err = StartZfsWatcher(dockerInfo) if err != nil { klog.Errorf("zfs filesystem stats will not be reported: %v", err) } } } if StorageDriver(dockerInfo.Driver) == ContainerdSnapshotterStorageDriver { containerdClient, err = containerd.Client(*containerd.ArgContainerdEndpoint, "moby") if err != nil { return fmt.Errorf("unable to create containerd client: %v", err) } } klog.V(1).Infof("Registering Docker factory") f := &dockerFactory{ cgroupSubsystems: cgroupSubsystems, client: client, containerdClient: containerdClient, dockerVersion: dockerVersion, dockerAPIVersion: dockerAPIVersion, fsInfo: fsInfo, machineInfoFactory: factory, storageDriver: StorageDriver(dockerInfo.Driver), storageDir: RootDir(), includedMetrics: includedMetrics, thinPoolName: thinPoolName, thinPoolWatcher: thinPoolWatcher, zfsWatcher: zfsWatcher, } container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw}) return nil } ================================================ FILE: container/docker/factory_test.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package docker import "testing" func TestEnsureThinLsKernelVersion(t *testing.T) { tests := []struct { version string expectedError string }{ {"4.4.0-31-generic", ""}, {"4.4.1", ""}, {"4.6.4-301.fc24.x86_64", ""}, {"3.10.0-327.22.2.el7.x86_64", `RHEL/Centos 7.x kernel version 3.10.0-366 or later is required to use thin_ls - you have "3.10.0-327.22.2.el7.x86_64"`}, {"3.10.0-366.el7.x86_64", ""}, {"3.10.0-366.el7_3.x86_64", ""}, {"3.10.0.el7.abc", `unable to determine RHEL/Centos 7.x kernel release from "3.10.0.el7.abc"`}, {"3.10.0-abc.el7.blarg", `unable to determine RHEL/Centos 7.x kernel release from "3.10.0-abc.el7.blarg"`}, {"3.10.0-367.el7.x86_64", ""}, {"3.10.0-366.x86_64", `kernel version 4.4.0 or later is required to use thin_ls - you have "3.10.0-366.x86_64"`}, {"3.10.1-1.el7.x86_64", ""}, {"2.0.36", `kernel version 4.4.0 or later is required to use thin_ls - you have "2.0.36"`}, {"2.1", `error parsing kernel version: "2.1" is not a semver`}, } for _, test := range tests { err := ensureThinLsKernelVersion(test.version) if err != nil { if len(test.expectedError) == 0 { t.Errorf("%s: expected no error, got %v", test.version, err) } else if err.Error() != test.expectedError { t.Errorf("%s: expected error %v, got %v", test.version, test.expectedError, err) } } else if err == nil && len(test.expectedError) > 0 { t.Errorf("%s: expected error %v", test.version, test.expectedError) } } } ================================================ FILE: container/docker/fs.go ================================================ // Copyright 2022 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package docker import ( "fmt" "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/common" "github.com/google/cadvisor/devicemapper" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/zfs" ) func FsStats( stats *info.ContainerStats, machineInfoFactory info.MachineInfoFactory, metrics container.MetricSet, storageDriver StorageDriver, fsHandler common.FsHandler, globalFsInfo fs.FsInfo, poolName string, rootfsStorageDir string, zfsParent string, ) error { mi, err := machineInfoFactory.GetMachineInfo() if err != nil { return err } if metrics.Has(container.DiskIOMetrics) { common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo) } if metrics.Has(container.DiskUsageMetrics) { var device string switch storageDriver { case DevicemapperStorageDriver: device = poolName case AufsStorageDriver, OverlayStorageDriver, Overlay2StorageDriver, VfsStorageDriver: deviceInfo, err := globalFsInfo.GetDirFsDevice(rootfsStorageDir) if err != nil { return fmt.Errorf("unable to determine device info for dir: %v: %v", rootfsStorageDir, err) } device = deviceInfo.Device case ZfsStorageDriver: device = zfsParent default: return nil } for _, fs := range mi.Filesystems { if fs.Device == device { usage := fsHandler.Usage() fsStat := info.FsStats{ Device: device, Type: fs.Type, Limit: fs.Capacity, BaseUsage: usage.BaseUsageBytes, Usage: usage.TotalUsageBytes, Inodes: usage.InodeUsage, } fileSystems, err := globalFsInfo.GetGlobalFsInfo() if err != nil { return fmt.Errorf("unable to obtain diskstats for filesystem %s: %v", fsStat.Device, err) } addDiskStats(fileSystems, &fs, &fsStat) stats.Filesystem = append(stats.Filesystem, fsStat) break } } } return nil } func addDiskStats(fileSystems []fs.Fs, fsInfo *info.FsInfo, fsStats *info.FsStats) { if fsInfo == nil { return } for _, fileSys := range fileSystems { if fsInfo.DeviceMajor == fileSys.DiskStats.Major && fsInfo.DeviceMinor == fileSys.DiskStats.Minor { fsStats.ReadsCompleted = fileSys.DiskStats.ReadsCompleted fsStats.ReadsMerged = fileSys.DiskStats.ReadsMerged fsStats.SectorsRead = fileSys.DiskStats.SectorsRead fsStats.ReadTime = fileSys.DiskStats.ReadTime fsStats.WritesCompleted = fileSys.DiskStats.WritesCompleted fsStats.WritesMerged = fileSys.DiskStats.WritesMerged fsStats.SectorsWritten = fileSys.DiskStats.SectorsWritten fsStats.WriteTime = fileSys.DiskStats.WriteTime fsStats.IoInProgress = fileSys.DiskStats.IoInProgress fsStats.IoTime = fileSys.DiskStats.IoTime fsStats.WeightedIoTime = fileSys.DiskStats.WeightedIoTime break } } } // FsHandler is a composite FsHandler implementation the incorporates // the common fs handler, a devicemapper ThinPoolWatcher, and a zfsWatcher type FsHandler struct { FsHandler common.FsHandler // thinPoolWatcher is the devicemapper thin pool watcher ThinPoolWatcher *devicemapper.ThinPoolWatcher // deviceID is the id of the container's fs device DeviceID string // zfsWatcher is the zfs filesystem watcher ZfsWatcher *zfs.ZfsWatcher // zfsFilesystem is the docker zfs filesystem ZfsFilesystem string } var _ common.FsHandler = &FsHandler{} func (h *FsHandler) Start() { h.FsHandler.Start() } func (h *FsHandler) Stop() { h.FsHandler.Stop() } func (h *FsHandler) Usage() common.FsUsage { usage := h.FsHandler.Usage() // When devicemapper is the storage driver, the base usage of the container comes from the thin pool. // We still need the result of the fsHandler for any extra storage associated with the container. // To correctly factor in the thin pool usage, we should: // * Usage the thin pool usage as the base usage // * Calculate the overall usage by adding the overall usage from the fs handler to the thin pool usage if h.ThinPoolWatcher != nil { thinPoolUsage, err := h.ThinPoolWatcher.GetUsage(h.DeviceID) if err != nil { // TODO: ideally we should keep track of how many times we failed to get the usage for this // device vs how many refreshes of the cache there have been, and display an error e.g. if we've // had at least 1 refresh and we still can't find the device. klog.V(5).Infof("unable to get fs usage from thin pool for device %s: %v", h.DeviceID, err) } else { usage.BaseUsageBytes = thinPoolUsage usage.TotalUsageBytes += thinPoolUsage } } if h.ZfsWatcher != nil { zfsUsage, err := h.ZfsWatcher.GetUsage(h.ZfsFilesystem) if err != nil { klog.V(5).Infof("unable to get fs usage from zfs for filesystem %s: %v", h.ZfsFilesystem, err) } else { usage.BaseUsageBytes = zfsUsage usage.TotalUsageBytes += zfsUsage } } return usage } ================================================ FILE: container/docker/handler.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Package docker implements a handler for Docker containers. package docker import ( "context" "encoding/json" "fmt" "os" "path" "strconv" "strings" "time" dclient "github.com/moby/moby/client" "github.com/opencontainers/cgroups" "github.com/opencontainers/runtime-spec/specs-go" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/common" "github.com/google/cadvisor/container/containerd" "github.com/google/cadvisor/container/containerd/namespaces" dockerutil "github.com/google/cadvisor/container/docker/utils" containerlibcontainer "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/devicemapper" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/zfs" "k8s.io/klog/v2" ) const ( // The read write layers exist here. aufsRWLayer = "diff" overlayRWLayer = "upper" overlay2RWLayer = "diff" // Path to the directory where docker stores log files if the json logging driver is enabled. pathToContainersDir = "containers" ) type containerHandler struct { // machineInfoFactory provides info.MachineInfo machineInfoFactory info.MachineInfoFactory // Absolute path to the cgroup hierarchies of this container. // (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test") cgroupPaths map[string]string // the docker storage driver storageDriver StorageDriver fsInfo fs.FsInfo rootfsStorageDir string // Time at which this container was created. creationTime time.Time // Time at which this container was started. startTime time.Time // Metadata associated with the container. envs map[string]string labels map[string]string // Image name used for this container. image string // Filesystem handler. fsHandler common.FsHandler // The IP address of the container ipAddress string metrics container.MetricSet // the devicemapper poolname thinPoolName string // zfsParent is the parent for docker zfs zfsParent string // Reference to the container reference info.ContainerReference libcontainerHandler *containerlibcontainer.Handler // the docker client is needed to inspect the container and get the health status client dclient.APIClient } var _ container.ContainerHandler = &containerHandler{} func getRwLayerID(containerID, storageDir string, sd StorageDriver, dockerVersion []int) (string, error) { const ( // Docker version >=1.10.0 have a randomized ID for the root fs of a container. randomizedRWLayerMinorVersion = 10 rwLayerIDFile = "mount-id" ) if (dockerVersion[0] <= 1) && (dockerVersion[1] < randomizedRWLayerMinorVersion) { return containerID, nil } bytes, err := os.ReadFile(path.Join(storageDir, "image", string(sd), "layerdb", "mounts", containerID, rwLayerIDFile)) if err != nil { return "", fmt.Errorf("failed to identify the read-write layer ID for container %q. - %v", containerID, err) } return string(bytes), err } // newContainerHandler returns a new container.ContainerHandler func newContainerHandler( client *dclient.Client, containerdClient containerd.ContainerdClient, name string, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, storageDriver StorageDriver, storageDir string, cgroupSubsystems map[string]string, inHostNamespace bool, metadataEnvAllowList []string, dockerVersion []int, metrics container.MetricSet, thinPoolName string, thinPoolWatcher *devicemapper.ThinPoolWatcher, zfsWatcher *zfs.ZfsWatcher, ) (container.ContainerHandler, error) { // Create the cgroup paths. cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems, name) // Generate the equivalent cgroup manager for this container. cgroupManager, err := containerlibcontainer.NewCgroupManager(name, cgroupPaths) if err != nil { return nil, err } rootFs := "/" if !inHostNamespace { rootFs = "/rootfs" storageDir = path.Join(rootFs, storageDir) } id := dockerutil.ContainerNameToId(name) // Add the Containers dir where the log files are stored. // FIXME: Give `otherStorageDir` a more descriptive name. otherStorageDir := path.Join(storageDir, pathToContainersDir, id) var rootfsStorageDir, zfsFilesystem, zfsParent string if storageDriver == ContainerdSnapshotterStorageDriver { ctx := namespaces.WithNamespace(context.Background(), "moby") cntr, err := containerdClient.LoadContainer(ctx, id) if err != nil { return nil, err } var spec specs.Spec if err := json.Unmarshal(cntr.Spec.Value, &spec); err != nil { return nil, err } rootfsStorageDir = spec.Root.Path } else { rwLayerID, err := getRwLayerID(id, storageDir, storageDriver, dockerVersion) if err != nil { return nil, err } // Determine the rootfs storage dir OR the pool name to determine the device. // For devicemapper, we only need the thin pool name, and that is passed in to this call rootfsStorageDir, zfsFilesystem, zfsParent, err = DetermineDeviceStorage(storageDriver, storageDir, rwLayerID) if err != nil { return nil, fmt.Errorf("unable to determine device storage: %v", err) } } // We assume that if Inspect fails then the container is not known to docker. res, err := client.ContainerInspect(context.Background(), id, dclient.ContainerInspectOptions{}) if err != nil { return nil, fmt.Errorf("failed to inspect container %q: %v", id, err) } ctnr := res.Container // Obtain the IP address for the container. var ipAddress string if ctnr.NetworkSettings != nil && ctnr.HostConfig != nil { c := ctnr if ctnr.HostConfig.NetworkMode.IsContainer() { // If the NetworkMode starts with 'container:' then we need to use the IP address of the container specified. // This happens in cases such as kubernetes where the containers doesn't have an IP address itself and we need to use the pod's address containerID := ctnr.HostConfig.NetworkMode.ConnectedContainer() res, err := client.ContainerInspect(context.Background(), containerID, dclient.ContainerInspectOptions{}) if err != nil { return nil, fmt.Errorf("failed to inspect container %q: %v", containerID, err) } c = res.Container } if nw, ok := c.NetworkSettings.Networks[c.HostConfig.NetworkMode.NetworkName()]; ok { if nw.IPAddress.IsValid() { ipAddress = nw.IPAddress.String() } } } // Do not report network metrics for containers that share netns with another container. includedMetrics := common.RemoveNetMetrics(metrics, ctnr.HostConfig.NetworkMode.IsContainer()) handler := &containerHandler{ machineInfoFactory: machineInfoFactory, cgroupPaths: cgroupPaths, storageDriver: storageDriver, fsInfo: fsInfo, rootfsStorageDir: rootfsStorageDir, ipAddress: ipAddress, envs: make(map[string]string), labels: ctnr.Config.Labels, image: ctnr.Config.Image, metrics: includedMetrics, thinPoolName: thinPoolName, zfsParent: zfsParent, client: client, reference: info.ContainerReference{ // Add the name and bare ID as aliases of the container. Id: id, Name: name, Aliases: []string{strings.TrimPrefix(ctnr.Name, "/"), id}, Namespace: DockerNamespace, }, libcontainerHandler: containerlibcontainer.NewHandler(cgroupManager, rootFs, ctnr.State.Pid, metrics), } // Timestamp returned by Docker is in time.RFC3339Nano format. handler.creationTime, err = time.Parse(time.RFC3339Nano, ctnr.Created) if err != nil { return nil, fmt.Errorf("failed to parse the create timestamp %q for container %q: %v", ctnr.Created, id, err) } // StartedAt may be unset for containers that never started. if startedAt := ctnr.State.StartedAt; startedAt != "" { if t, err := time.Parse(time.RFC3339Nano, startedAt); err == nil && !t.Before(time.Unix(0, 0)) { handler.startTime = t } } if ctnr.RestartCount > 0 { handler.labels["restartcount"] = strconv.Itoa(ctnr.RestartCount) } if includedMetrics.Has(container.DiskUsageMetrics) { var deviceID string if ctnr.GraphDriver != nil { deviceID = ctnr.GraphDriver.Data["DeviceId"] } else { klog.V(4).Infof("GraphDriver not found for container %q", id) } handler.fsHandler = &FsHandler{ FsHandler: common.NewFsHandler(common.DefaultPeriod, rootfsStorageDir, otherStorageDir, fsInfo), ThinPoolWatcher: thinPoolWatcher, ZfsWatcher: zfsWatcher, DeviceID: deviceID, ZfsFilesystem: zfsFilesystem, } } // Split env vars to get metadata map. for _, exposedEnv := range metadataEnvAllowList { if exposedEnv == "" { // if no dockerEnvWhitelist provided, len(metadataEnvAllowList) == 1, metadataEnvAllowList[0] == "" continue } for _, envVar := range ctnr.Config.Env { if envVar != "" { splits := strings.SplitN(envVar, "=", 2) if len(splits) == 2 && strings.HasPrefix(splits[0], exposedEnv) { handler.envs[strings.ToLower(splits[0])] = splits[1] } } } } return handler, nil } func DetermineDeviceStorage(storageDriver StorageDriver, storageDir string, rwLayerID string) ( rootfsStorageDir string, zfsFilesystem string, zfsParent string, err error) { switch storageDriver { case AufsStorageDriver: rootfsStorageDir = path.Join(storageDir, string(AufsStorageDriver), aufsRWLayer, rwLayerID) case OverlayStorageDriver: rootfsStorageDir = path.Join(storageDir, string(storageDriver), rwLayerID, overlayRWLayer) case Overlay2StorageDriver: rootfsStorageDir = path.Join(storageDir, string(storageDriver), rwLayerID, overlay2RWLayer) case VfsStorageDriver: rootfsStorageDir = path.Join(storageDir) case ZfsStorageDriver: var status info.DockerStatus status, err = Status() if err != nil { return } zfsParent = status.DriverStatus[dockerutil.DriverStatusParentDataset] zfsFilesystem = path.Join(zfsParent, rwLayerID) } return } func (h *containerHandler) ContainerReference() (info.ContainerReference, error) { return h.reference, nil } func (h *containerHandler) GetSpec() (info.ContainerSpec, error) { hasFilesystem := h.metrics.Has(container.DiskUsageMetrics) hasNetwork := h.metrics.Has(container.NetworkUsageMetrics) spec, err := common.GetSpec(h.cgroupPaths, h.machineInfoFactory, hasNetwork, hasFilesystem) if err != nil { return info.ContainerSpec{}, err } spec.Labels = h.labels spec.Envs = h.envs spec.Image = h.image spec.CreationTime = h.creationTime spec.StartTime = h.startTime return spec, nil } func (h *containerHandler) GetStats() (*info.ContainerStats, error) { // TODO(vmarmol): Get from libcontainer API instead of cgroup manager when we don't have to support older Dockers. stats, err := h.libcontainerHandler.GetStats() if err != nil { return stats, err } // We assume that if Inspect fails then the container is not known to docker. res, err := h.client.ContainerInspect(context.Background(), h.reference.Id, dclient.ContainerInspectOptions{}) if err != nil { return nil, fmt.Errorf("failed to inspect container %q: %v", h.reference.Id, err) } ctnr := res.Container if ctnr.State.Health != nil { stats.Health.Status = string(ctnr.State.Health.Status) } // Get filesystem stats. err = FsStats(stats, h.machineInfoFactory, h.metrics, h.storageDriver, h.fsHandler, h.fsInfo, h.thinPoolName, h.rootfsStorageDir, h.zfsParent) if err != nil { return stats, err } return stats, nil } func (h *containerHandler) ListContainers(container.ListType) ([]info.ContainerReference, error) { return []info.ContainerReference{}, nil } func (h *containerHandler) ListProcesses(container.ListType) ([]int, error) { return h.libcontainerHandler.GetProcesses() } func (h *containerHandler) GetCgroupPath(resource string) (string, error) { var res string if !cgroups.IsCgroup2UnifiedMode() { res = resource } cgroupPath, ok := h.cgroupPaths[res] if !ok { return "", fmt.Errorf("could not find path for resource %q for container %q", resource, h.reference.Name) } return cgroupPath, nil } func (h *containerHandler) GetContainerLabels() map[string]string { return h.labels } func (h *containerHandler) GetContainerIPAddress() string { return h.ipAddress } func (h *containerHandler) Exists() bool { return common.CgroupExists(h.cgroupPaths) } func (h *containerHandler) Cleanup() { if h.fsHandler != nil { h.fsHandler.Stop() } } func (h *containerHandler) Start() { if h.fsHandler != nil { h.fsHandler.Start() } } func (h *containerHandler) Type() container.ContainerType { return container.ContainerTypeDocker } func (h *containerHandler) GetExitCode() (int, error) { res, err := h.client.ContainerInspect(context.Background(), h.reference.Id, dclient.ContainerInspectOptions{}) if err != nil { return -1, fmt.Errorf("failed to inspect container %s: %w", h.reference.Id, err) } ctnr := res.Container if ctnr.State.Running { return -1, fmt.Errorf("container %s is still running", h.reference.Id) } return ctnr.State.ExitCode, nil } ================================================ FILE: container/docker/handler_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Handler for Docker containers. package docker import ( "context" "os" "path" "strings" "testing" "github.com/moby/moby/api/types/container" dclient "github.com/moby/moby/client" "github.com/stretchr/testify/assert" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" ) type mockDockerClientForExitCode struct { dclient.APIClient inspectResp dclient.ContainerInspectResult inspectErr error } func (m *mockDockerClientForExitCode) ContainerInspect(ctx context.Context, containerID string, options dclient.ContainerInspectOptions) (dclient.ContainerInspectResult, error) { return m.inspectResp, m.inspectErr } func TestStorageDirDetectionWithOldVersions(t *testing.T) { as := assert.New(t) rwLayer, err := getRwLayerID("abcd", "/", AufsStorageDriver, []int{1, 9, 0}) as.Nil(err) as.Equal(rwLayer, "abcd") } func TestStorageDirDetectionWithNewVersions(t *testing.T) { as := assert.New(t) testDir := t.TempDir() containerID := "abcd" randomizedID := "xyz" randomIDPath := path.Join(testDir, "image/aufs/layerdb/mounts/", containerID) as.Nil(os.MkdirAll(randomIDPath, os.ModePerm)) as.Nil(os.WriteFile(path.Join(randomIDPath, "mount-id"), []byte(randomizedID), os.ModePerm)) rwLayer, err := getRwLayerID(containerID, testDir, "aufs", []int{1, 10, 0}) as.Nil(err) as.Equal(rwLayer, randomizedID) rwLayer, err = getRwLayerID(containerID, testDir, "aufs", []int{1, 10, 0}) as.Nil(err) as.Equal(rwLayer, randomizedID) } func rawMetadataEnvMatch(dockerEnvWhiteList string, cntConfig container.Config) map[string]string { metadataEnvAllowList := strings.Split(dockerEnvWhiteList, ",") handlerEnvs := make(map[string]string) // split env vars to get metadata map. for _, exposedEnv := range metadataEnvAllowList { for _, envVar := range cntConfig.Env { if envVar != "" { splits := strings.SplitN(envVar, "=", 2) if len(splits) == 2 && splits[0] == exposedEnv { handlerEnvs[strings.ToLower(exposedEnv)] = splits[1] } } } } return handlerEnvs } func newMetadataEnvMatch(dockerEnvWhiteList string, cntConfig container.Config) map[string]string { metadataEnvAllowList := strings.Split(dockerEnvWhiteList, ",") handlerEnvs := make(map[string]string) // split env vars to get metadata map. for _, exposedEnv := range metadataEnvAllowList { if exposedEnv == "" { // if no dockerEnvWhitelist provided, len(metadataEnvAllowList) == 1, metadataEnvAllowList[0] == "" continue } for _, envVar := range cntConfig.Env { if envVar != "" { splits := strings.SplitN(envVar, "=", 2) if len(splits) == 2 && strings.HasPrefix(splits[0], exposedEnv) { handlerEnvs[strings.ToLower(splits[0])] = splits[1] } } } } return handlerEnvs } func TestDockerEnvWhitelist(t *testing.T) { as := assert.New(t) envTotalMatch := "TEST_REGION,TEST_ZONE" envMatchWithPrefix := "TEST_" envMatchWithPrefixEmpty := "" rawCntConfig := container.Config{Env: []string{"TEST_REGION=FRA", "TEST_ZONE=A", "HELLO=WORLD"}} newCntConfig := container.Config{Env: []string{"TEST_REGION=FRA", "TEST_ZONE=A", "TEST_POOL=TOOLING", "HELLO=WORLD"}} rawExpected := map[string]string{ "test_region": "FRA", "test_zone": "A", } newExpected := map[string]string{ "test_region": "FRA", "test_zone": "A", "test_pool": "TOOLING", } emptyExpected := map[string]string{} rawEnvsTotalMatch := rawMetadataEnvMatch(envTotalMatch, rawCntConfig) newEnvsTotalMatch := newMetadataEnvMatch(envTotalMatch, rawCntConfig) // make sure total match does not change as.Equal(rawEnvsTotalMatch, newEnvsTotalMatch) as.Equal(rawEnvsTotalMatch, rawExpected) rawEnvsTotalMatch2 := rawMetadataEnvMatch(envTotalMatch, newCntConfig) newEnvsTotalMatch2 := newMetadataEnvMatch(envTotalMatch, newCntConfig) // make sure total match does not change with more envs exposed as.Equal(rawEnvsTotalMatch2, newEnvsTotalMatch2) as.Equal(rawEnvsTotalMatch2, rawExpected) newEnvsMatchWithPrefix := newMetadataEnvMatch(envMatchWithPrefix, rawCntConfig) newEnvsMatchWithPrefix2 := newMetadataEnvMatch(envMatchWithPrefix, newCntConfig) // make sure new method can return envs with prefix specified as.Equal(newEnvsMatchWithPrefix, rawExpected) as.Equal(newEnvsMatchWithPrefix2, newExpected) newEnvsMatchWithEmptyPrefix := newMetadataEnvMatch(envMatchWithPrefixEmpty, newCntConfig) rawEnvsMatchWithEmptyWhitelist := rawMetadataEnvMatch(envMatchWithPrefixEmpty, newCntConfig) // make sure empty whitelist returns nothing as.Equal(newEnvsMatchWithEmptyPrefix, emptyExpected) as.Equal(rawEnvsMatchWithEmptyWhitelist, emptyExpected) } func TestAddDiskStatsCheck(t *testing.T) { var readsCompleted, readsMerged, sectorsRead, readTime, writesCompleted, writesMerged, sectorsWritten, writeTime, ioInProgress, ioTime, weightedIoTime uint64 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 fileSystem := fs.Fs{ DiskStats: fs.DiskStats{ ReadsCompleted: readsCompleted, ReadsMerged: readsMerged, SectorsRead: sectorsRead, ReadTime: readTime, WritesCompleted: writesCompleted, WritesMerged: writesMerged, SectorsWritten: sectorsWritten, WriteTime: writeTime, IoInProgress: ioInProgress, IoTime: ioTime, WeightedIoTime: weightedIoTime, }, } fileSystems := []fs.Fs{fileSystem} var fsStats info.FsStats addDiskStats(fileSystems, nil, &fsStats) } func TestAddDiskStats(t *testing.T) { // Arrange as := assert.New(t) var readsCompleted, readsMerged, sectorsRead, readTime, writesCompleted, writesMerged, sectorsWritten, writeTime, ioInProgress, ioTime, weightedIoTime uint64 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 var fsStats info.FsStats fsInfo := info.FsInfo{ DeviceMajor: 4, DeviceMinor: 64, } fileSystem := fs.Fs{ DiskStats: fs.DiskStats{ ReadsCompleted: readsCompleted, ReadsMerged: readsMerged, SectorsRead: sectorsRead, ReadTime: readTime, WritesCompleted: writesCompleted, WritesMerged: writesMerged, SectorsWritten: sectorsWritten, WriteTime: writeTime, IoInProgress: ioInProgress, IoTime: ioTime, WeightedIoTime: weightedIoTime, }, } fileSystems := []fs.Fs{fileSystem} // Act addDiskStats(fileSystems, &fsInfo, &fsStats) // Assert as.Equal(readsCompleted, fileSystem.DiskStats.ReadsCompleted, "ReadsCompleted metric should be %d but was %d", readsCompleted, fileSystem.DiskStats.ReadsCompleted) as.Equal(readsMerged, fileSystem.DiskStats.ReadsMerged, "ReadsMerged metric should be %d but was %d", readsMerged, fileSystem.DiskStats.ReadsMerged) as.Equal(sectorsRead, fileSystem.DiskStats.SectorsRead, "SectorsRead metric should be %d but was %d", sectorsRead, fileSystem.DiskStats.SectorsRead) as.Equal(readTime, fileSystem.DiskStats.ReadTime, "ReadTime metric should be %d but was %d", readTime, fileSystem.DiskStats.ReadTime) as.Equal(writesCompleted, fileSystem.DiskStats.WritesCompleted, "WritesCompleted metric should be %d but was %d", writesCompleted, fileSystem.DiskStats.WritesCompleted) as.Equal(writesMerged, fileSystem.DiskStats.WritesMerged, "WritesMerged metric should be %d but was %d", writesMerged, fileSystem.DiskStats.WritesMerged) as.Equal(sectorsWritten, fileSystem.DiskStats.SectorsWritten, "SectorsWritten metric should be %d but was %d", sectorsWritten, fileSystem.DiskStats.SectorsWritten) as.Equal(writeTime, fileSystem.DiskStats.WriteTime, "WriteTime metric should be %d but was %d", writeTime, fileSystem.DiskStats.WriteTime) as.Equal(ioInProgress, fileSystem.DiskStats.IoInProgress, "IoInProgress metric should be %d but was %d", ioInProgress, fileSystem.DiskStats.IoInProgress) as.Equal(ioTime, fileSystem.DiskStats.IoTime, "IoTime metric should be %d but was %d", ioTime, fileSystem.DiskStats.IoTime) as.Equal(weightedIoTime, fileSystem.DiskStats.WeightedIoTime, "WeightedIoTime metric should be %d but was %d", weightedIoTime, fileSystem.DiskStats.WeightedIoTime) } func TestGetExitCode(t *testing.T) { tests := []struct { name string running bool exitCode int inspectErr error expectErr bool errContains string expectedCode int }{ { name: "successful exit code 0", running: false, exitCode: 0, inspectErr: nil, expectErr: false, expectedCode: 0, }, { name: "successful exit code 1", running: false, exitCode: 1, inspectErr: nil, expectErr: false, expectedCode: 1, }, { name: "container still running", running: true, exitCode: 0, inspectErr: nil, expectErr: true, errContains: "still running", expectedCode: -1, }, { name: "inspect fails", running: false, exitCode: 0, inspectErr: assert.AnError, expectErr: true, errContains: "failed to inspect", expectedCode: -1, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { as := assert.New(t) mockClient := &mockDockerClientForExitCode{ inspectResp: dclient.ContainerInspectResult{ Container: container.InspectResponse{ State: &container.State{ Running: tt.running, ExitCode: tt.exitCode, }, }, }, inspectErr: tt.inspectErr, } h := &containerHandler{ client: mockClient, reference: info.ContainerReference{ Id: "test-container-id", }, } code, err := h.GetExitCode() if tt.expectErr { as.Error(err) if tt.errContains != "" { as.Contains(err.Error(), tt.errContains) } as.Equal(tt.expectedCode, code) } else { as.NoError(err) as.Equal(tt.expectedCode, code) } }) } } ================================================ FILE: container/docker/install/install.go ================================================ // Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // The install package registers docker.NewPlugin() as the "docker" container provider when imported package install import ( "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/docker" ) func init() { err := container.RegisterPlugin("docker", docker.NewPlugin()) if err != nil { klog.Fatalf("Failed to register docker plugin: %v", err) } } ================================================ FILE: container/docker/plugin.go ================================================ // Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package docker import ( "context" "time" "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/watcher" ) const dockerClientTimeout = 10 * time.Second // NewPlugin returns an implementation of container.Plugin suitable for passing to container.RegisterPlugin() func NewPlugin() container.Plugin { return &plugin{} } type plugin struct{} func (p *plugin) InitializeFSContext(context *fs.Context) error { SetTimeout(dockerClientTimeout) // Try to connect to docker indefinitely on startup. dockerStatus := retryDockerStatus() context.Docker = fs.DockerContext{ Root: RootDir(), Driver: dockerStatus.Driver, DriverStatus: dockerStatus.DriverStatus, } return nil } func (p *plugin) Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) (watcher.ContainerWatcher, error) { err := Register(factory, fsInfo, includedMetrics) return nil, err } func retryDockerStatus() info.DockerStatus { startupTimeout := dockerClientTimeout maxTimeout := 4 * startupTimeout for { ctx, cancel := context.WithTimeout(context.Background(), startupTimeout) defer cancel() dockerStatus, err := StatusWithContext(ctx) if err == nil { return dockerStatus } switch err { case context.DeadlineExceeded: klog.Warningf("Timeout trying to communicate with docker during initialization, will retry") default: klog.V(5).Infof("Docker not connected: %v", err) return info.DockerStatus{} } startupTimeout = 2 * startupTimeout if startupTimeout > maxTimeout { startupTimeout = maxTimeout } } } ================================================ FILE: container/docker/utils/docker.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils import ( "fmt" "os" "path" "regexp" "strings" dockerimage "github.com/moby/moby/api/types/image" dockersystem "github.com/moby/moby/api/types/system" v1 "github.com/google/cadvisor/info/v1" ) const ( DriverStatusPoolName = "Pool Name" DriverStatusMetadataFile = "Metadata file" DriverStatusParentDataset = "Parent Dataset" ) // Regexp that identifies docker cgroups, containers started with // --cgroup-parent have another prefix than 'docker' var cgroupRegexp = regexp.MustCompile(`([a-z0-9]{64})`) func DriverStatusValue(status [][2]string, target string) string { for _, v := range status { if strings.EqualFold(v[0], target) { return v[1] } } return "" } func DockerThinPoolName(info dockersystem.Info) (string, error) { poolName := DriverStatusValue(info.DriverStatus, DriverStatusPoolName) if len(poolName) == 0 { return "", fmt.Errorf("could not get devicemapper pool name") } return poolName, nil } func DockerMetadataDevice(info dockersystem.Info) (string, error) { metadataDevice := DriverStatusValue(info.DriverStatus, DriverStatusMetadataFile) if len(metadataDevice) != 0 { return metadataDevice, nil } poolName, err := DockerThinPoolName(info) if err != nil { return "", err } metadataDevice = fmt.Sprintf("/dev/mapper/%s_tmeta", poolName) if _, err := os.Stat(metadataDevice); err != nil { return "", err } return metadataDevice, nil } func DockerZfsFilesystem(info dockersystem.Info) (string, error) { filesystem := DriverStatusValue(info.DriverStatus, DriverStatusParentDataset) if len(filesystem) == 0 { return "", fmt.Errorf("could not get zfs filesystem") } return filesystem, nil } func SummariesToImages(summaries []dockerimage.Summary) ([]v1.DockerImage, error) { var out []v1.DockerImage const unknownTag = ":" for _, summary := range summaries { if len(summary.RepoTags) == 1 && summary.RepoTags[0] == unknownTag { // images with repo or tags are uninteresting. continue } di := v1.DockerImage{ ID: summary.ID, RepoTags: summary.RepoTags, Created: summary.Created, VirtualSize: summary.Size, Size: summary.Size, } out = append(out, di) } return out, nil } // ContainerNameToId returns the ID from the full container name. func ContainerNameToId(name string) string { id := path.Base(name) if matches := cgroupRegexp.FindStringSubmatch(id); matches != nil { return matches[1] } return id } // IsContainerName returns true if the cgroup with associated name // corresponds to a container. func IsContainerName(name string) bool { // always ignore .mount cgroup even if associated with docker and delegate to systemd if strings.HasSuffix(name, ".mount") { return false } return cgroupRegexp.MatchString(path.Base(name)) } ================================================ FILE: container/docker/utils/docker_test.go ================================================ // Copyright 2022 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils import "testing" func TestIsContainerName(t *testing.T) { tests := []struct { name string expected bool }{ { name: "/system.slice/var-lib-docker-overlay-9f086b233ab7c786bf8b40b164680b658a8f00e94323868e288d6ce20bc92193-merged.mount", expected: false, }, { name: "/system.slice/docker-72e5a5ff5eef3c4222a6551b992b9360a99122f77d2229783f0ee0946dfd800e.scope", expected: true, }, } for _, test := range tests { if actual := IsContainerName(test.name); actual != test.expected { t.Errorf("%s: expected: %v, actual: %v", test.name, test.expected, actual) } } } ================================================ FILE: container/factory.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package container import ( "fmt" "sort" "strings" "sync" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/watcher" "k8s.io/klog/v2" ) type ContainerHandlerFactory interface { // Create a new ContainerHandler using this factory. CanHandleAndAccept() must have returned true. NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (c ContainerHandler, err error) // Returns whether this factory can handle and accept the specified container. CanHandleAndAccept(name string) (handle bool, accept bool, err error) // Name of the factory. String() string // Returns debugging information. Map of lines per category. DebugInfo() map[string][]string } // MetricKind represents the kind of metrics that cAdvisor exposes. type MetricKind string const ( CpuUsageMetrics MetricKind = "cpu" ProcessSchedulerMetrics MetricKind = "sched" PerCpuUsageMetrics MetricKind = "percpu" MemoryUsageMetrics MetricKind = "memory" MemoryNumaMetrics MetricKind = "memory_numa" CpuLoadMetrics MetricKind = "cpuLoad" DiskIOMetrics MetricKind = "diskIO" DiskUsageMetrics MetricKind = "disk" NetworkUsageMetrics MetricKind = "network" NetworkTcpUsageMetrics MetricKind = "tcp" NetworkAdvancedTcpUsageMetrics MetricKind = "advtcp" NetworkUdpUsageMetrics MetricKind = "udp" AppMetrics MetricKind = "app" ProcessMetrics MetricKind = "process" HugetlbUsageMetrics MetricKind = "hugetlb" PerfMetrics MetricKind = "perf_event" ReferencedMemoryMetrics MetricKind = "referenced_memory" CPUTopologyMetrics MetricKind = "cpu_topology" ResctrlMetrics MetricKind = "resctrl" CPUSetMetrics MetricKind = "cpuset" OOMMetrics MetricKind = "oom_event" PressureMetrics MetricKind = "pressure" ) // AllMetrics represents all kinds of metrics that cAdvisor supported. var AllMetrics = MetricSet{ CpuUsageMetrics: struct{}{}, ProcessSchedulerMetrics: struct{}{}, PerCpuUsageMetrics: struct{}{}, MemoryUsageMetrics: struct{}{}, MemoryNumaMetrics: struct{}{}, CpuLoadMetrics: struct{}{}, DiskIOMetrics: struct{}{}, DiskUsageMetrics: struct{}{}, NetworkUsageMetrics: struct{}{}, NetworkTcpUsageMetrics: struct{}{}, NetworkAdvancedTcpUsageMetrics: struct{}{}, NetworkUdpUsageMetrics: struct{}{}, ProcessMetrics: struct{}{}, AppMetrics: struct{}{}, HugetlbUsageMetrics: struct{}{}, PerfMetrics: struct{}{}, ReferencedMemoryMetrics: struct{}{}, CPUTopologyMetrics: struct{}{}, ResctrlMetrics: struct{}{}, CPUSetMetrics: struct{}{}, OOMMetrics: struct{}{}, PressureMetrics: struct{}{}, } // AllNetworkMetrics represents all network metrics that cAdvisor supports. var AllNetworkMetrics = MetricSet{ NetworkUsageMetrics: struct{}{}, NetworkTcpUsageMetrics: struct{}{}, NetworkAdvancedTcpUsageMetrics: struct{}{}, NetworkUdpUsageMetrics: struct{}{}, } func (mk MetricKind) String() string { return string(mk) } type MetricSet map[MetricKind]struct{} func (ms MetricSet) Has(mk MetricKind) bool { _, exists := ms[mk] return exists } func (ms MetricSet) HasAny(ms1 MetricSet) bool { for m := range ms1 { if _, ok := ms[m]; ok { return true } } return false } func (ms MetricSet) add(mk MetricKind) { ms[mk] = struct{}{} } func (ms MetricSet) String() string { values := make([]string, 0, len(ms)) for metric := range ms { values = append(values, string(metric)) } sort.Strings(values) return strings.Join(values, ",") } // Not thread-safe, exported only for https://pkg.go.dev/flag#Value func (ms *MetricSet) Set(value string) error { *ms = MetricSet{} if value == "" { return nil } for _, metric := range strings.Split(value, ",") { if AllMetrics.Has(MetricKind(metric)) { (*ms).add(MetricKind(metric)) } else { return fmt.Errorf("unsupported metric %q specified", metric) } } return nil } func (ms MetricSet) Difference(ms1 MetricSet) MetricSet { result := MetricSet{} for kind := range ms { if !ms1.Has(kind) { result.add(kind) } } return result } func (ms MetricSet) Append(ms1 MetricSet) MetricSet { result := ms for kind := range ms1 { if !ms.Has(kind) { result.add(kind) } } return result } // All registered auth provider plugins. var pluginsLock sync.Mutex var plugins = make(map[string]Plugin) type Plugin interface { // InitializeFSContext is invoked when populating an fs.Context object for a new manager. // A returned error here is fatal. InitializeFSContext(context *fs.Context) error // Register is invoked when starting a manager. It can optionally return a container watcher. // A returned error is logged, but is not fatal. Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics MetricSet) (watcher.ContainerWatcher, error) } func RegisterPlugin(name string, plugin Plugin) error { pluginsLock.Lock() defer pluginsLock.Unlock() if _, found := plugins[name]; found { return fmt.Errorf("Plugin %q was registered twice", name) } plugins[name] = plugin return nil } func InitializeFSContext(context *fs.Context) error { pluginsLock.Lock() defer pluginsLock.Unlock() for name, plugin := range plugins { err := plugin.InitializeFSContext(context) if err != nil { klog.V(5).Infof("Initialization of the %s context failed: %v", name, err) return err } } return nil } func InitializePlugins(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics MetricSet) []watcher.ContainerWatcher { pluginsLock.Lock() defer pluginsLock.Unlock() containerWatchers := []watcher.ContainerWatcher{} for name, plugin := range plugins { watcher, err := plugin.Register(factory, fsInfo, includedMetrics) if err != nil { klog.Infof("Registration of the %s container factory failed: %v", name, err) } else { klog.Infof("Registration of the %s container factory successfully", name) } if watcher != nil { containerWatchers = append(containerWatchers, watcher) } } return containerWatchers } // TODO(vmarmol): Consider not making this global. // Global list of factories. var ( factories = map[watcher.ContainerWatchSource][]ContainerHandlerFactory{} factoriesLock sync.RWMutex ) // Register a ContainerHandlerFactory. These should be registered from least general to most general // as they will be asked in order whether they can handle a particular container. func RegisterContainerHandlerFactory(factory ContainerHandlerFactory, watchTypes []watcher.ContainerWatchSource) { factoriesLock.Lock() defer factoriesLock.Unlock() for _, watchType := range watchTypes { factories[watchType] = append(factories[watchType], factory) } } // Returns whether there are any container handler factories registered. func HasFactories() bool { factoriesLock.Lock() defer factoriesLock.Unlock() return len(factories) != 0 } // Create a new ContainerHandler for the specified container. func NewContainerHandler(name string, watchType watcher.ContainerWatchSource, metadataEnvAllowList []string, inHostNamespace bool) (ContainerHandler, bool, error) { factoriesLock.RLock() defer factoriesLock.RUnlock() // Create the ContainerHandler with the first factory that supports it. // Note that since RawContainerHandler can support a wide range of paths, // it's evaluated last just to make sure if any other ContainerHandler // can support it. for _, factory := range GetReorderedFactoryList(watchType) { canHandle, canAccept, err := factory.CanHandleAndAccept(name) if err != nil { klog.V(4).Infof("Error trying to work out if we can handle %s: %v", name, err) } if canHandle { if !canAccept { klog.V(3).Infof("Factory %q can handle container %q, but ignoring.", factory, name) return nil, false, nil } klog.V(3).Infof("Using factory %q for container %q", factory, name) handle, err := factory.NewContainerHandler(name, metadataEnvAllowList, inHostNamespace) return handle, canAccept, err } klog.V(4).Infof("Factory %q was unable to handle container %q", factory, name) } return nil, false, fmt.Errorf("no known factory can handle creation of container") } // Clear the known factories. func ClearContainerHandlerFactories() { factoriesLock.Lock() defer factoriesLock.Unlock() factories = map[watcher.ContainerWatchSource][]ContainerHandlerFactory{} } func DebugInfo() map[string][]string { factoriesLock.RLock() defer factoriesLock.RUnlock() // Get debug information for all factories. out := make(map[string][]string) for _, factoriesSlice := range factories { for _, factory := range factoriesSlice { for k, v := range factory.DebugInfo() { out[k] = v } } } return out } // GetReorderedFactoryList returns the list of ContainerHandlerFactory where the // RawContainerHandler is always the last element. func GetReorderedFactoryList(watchType watcher.ContainerWatchSource) []ContainerHandlerFactory { ContainerHandlerFactoryList := make([]ContainerHandlerFactory, 0, len(factories)) var rawFactory ContainerHandlerFactory for _, v := range factories[watchType] { if v != nil { if v.String() == "raw" { rawFactory = v continue } ContainerHandlerFactoryList = append(ContainerHandlerFactoryList, v) } } if rawFactory != nil { ContainerHandlerFactoryList = append(ContainerHandlerFactoryList, rawFactory) } return ContainerHandlerFactoryList } ================================================ FILE: container/factory_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package container_test import ( "testing" "github.com/google/cadvisor/container" containertest "github.com/google/cadvisor/container/testing" "github.com/google/cadvisor/watcher" "github.com/stretchr/testify/mock" ) type mockContainerHandlerFactory struct { mock.Mock Name string CanHandleValue bool CanAcceptValue bool } func (f *mockContainerHandlerFactory) String() string { return f.Name } func (f *mockContainerHandlerFactory) DebugInfo() map[string][]string { return map[string][]string{} } func (f *mockContainerHandlerFactory) CanHandleAndAccept(name string) (bool, bool, error) { return f.CanHandleValue, f.CanAcceptValue, nil } func (f *mockContainerHandlerFactory) NewContainerHandler(name string, metadataEnvAllowList []string, isHostNamespace bool) (container.ContainerHandler, error) { args := f.Called(name) return args.Get(0).(container.ContainerHandler), args.Error(1) } const testContainerName = "/test" var testMetadataEnvAllowList = []string{} var mockFactory containertest.FactoryForMockContainerHandler func TestNewContainerHandler_FirstMatches(t *testing.T) { container.ClearContainerHandlerFactories() // Register one allways yes factory. allwaysYes := &mockContainerHandlerFactory{ Name: "yes", CanHandleValue: true, CanAcceptValue: true, } container.RegisterContainerHandlerFactory(allwaysYes, []watcher.ContainerWatchSource{watcher.Raw}) // The yes factory should be asked to create the ContainerHandler. mockContainer, err := mockFactory.NewContainerHandler(testContainerName, testMetadataEnvAllowList, true) if err != nil { t.Error(err) } allwaysYes.On("NewContainerHandler", testContainerName).Return(mockContainer, nil) cont, _, err := container.NewContainerHandler(testContainerName, watcher.Raw, testMetadataEnvAllowList, true) if err != nil { t.Error(err) } if cont == nil { t.Error("Expected container to not be nil") } } func TestNewContainerHandler_SecondMatches(t *testing.T) { container.ClearContainerHandlerFactories() // Register one allways no and one always yes factory. allwaysNo := &mockContainerHandlerFactory{ Name: "no", CanHandleValue: false, CanAcceptValue: true, } container.RegisterContainerHandlerFactory(allwaysNo, []watcher.ContainerWatchSource{watcher.Raw}) allwaysYes := &mockContainerHandlerFactory{ Name: "yes", CanHandleValue: true, CanAcceptValue: true, } container.RegisterContainerHandlerFactory(allwaysYes, []watcher.ContainerWatchSource{watcher.Raw}) // The yes factory should be asked to create the ContainerHandler. mockContainer, err := mockFactory.NewContainerHandler(testContainerName, testMetadataEnvAllowList, true) if err != nil { t.Error(err) } allwaysYes.On("NewContainerHandler", testContainerName).Return(mockContainer, nil) cont, _, err := container.NewContainerHandler(testContainerName, watcher.Raw, testMetadataEnvAllowList, true) if err != nil { t.Error(err) } if cont == nil { t.Error("Expected container to not be nil") } } func TestNewContainerHandler_NoneMatch(t *testing.T) { container.ClearContainerHandlerFactories() // Register two allways no factories. allwaysNo1 := &mockContainerHandlerFactory{ Name: "no", CanHandleValue: false, CanAcceptValue: true, } container.RegisterContainerHandlerFactory(allwaysNo1, []watcher.ContainerWatchSource{watcher.Raw}) allwaysNo2 := &mockContainerHandlerFactory{ Name: "no", CanHandleValue: false, CanAcceptValue: true, } container.RegisterContainerHandlerFactory(allwaysNo2, []watcher.ContainerWatchSource{watcher.Raw}) _, _, err := container.NewContainerHandler(testContainerName, watcher.Raw, testMetadataEnvAllowList, true) if err == nil { t.Error("Expected NewContainerHandler to fail") } } func TestNewContainerHandler_Accept(t *testing.T) { container.ClearContainerHandlerFactories() // Register handler that can handle the container, but can't accept it. cannotHandle := &mockContainerHandlerFactory{ Name: "no", CanHandleValue: false, CanAcceptValue: true, } container.RegisterContainerHandlerFactory(cannotHandle, []watcher.ContainerWatchSource{watcher.Raw}) cannotAccept := &mockContainerHandlerFactory{ Name: "no", CanHandleValue: true, CanAcceptValue: false, } container.RegisterContainerHandlerFactory(cannotAccept, []watcher.ContainerWatchSource{watcher.Raw}) _, accept, err := container.NewContainerHandler(testContainerName, watcher.Raw, testMetadataEnvAllowList, true) if err != nil { t.Error("Expected NewContainerHandler to succeed") } if accept == true { t.Error("Expected NewContainerHandler to ignore the container.") } } func TestRawContainerHandler_Last(t *testing.T) { chf1 := &mockContainerHandlerFactory{ Name: "raw", } container.RegisterContainerHandlerFactory(chf1, []watcher.ContainerWatchSource{watcher.Raw}) cfh2 := &mockContainerHandlerFactory{ Name: "crio", } container.RegisterContainerHandlerFactory(cfh2, []watcher.ContainerWatchSource{watcher.Raw}) cfh3 := &mockContainerHandlerFactory{ Name: "containerd", } container.RegisterContainerHandlerFactory(cfh3, []watcher.ContainerWatchSource{watcher.Raw}) list := container.GetReorderedFactoryList(watcher.Raw) if list[len(list)-1].String() != "raw" { t.Error("Expected raw container handler to be last in the list.") } } ================================================ FILE: container/libcontainer/handler.go ================================================ // Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package libcontainer import ( "bufio" "bytes" "encoding/json" "flag" "fmt" "io" "os" "path" "regexp" "strconv" "strings" "time" "github.com/opencontainers/cgroups" "github.com/opencontainers/cgroups/fs2" "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/common" info "github.com/google/cadvisor/info/v1" ) var ( referencedResetInterval = flag.Uint64("referenced_reset_interval", 0, "Reset interval for referenced bytes (container_referenced_bytes metric), number of measurement cycles after which referenced bytes are cleared, if set to 0 referenced bytes are never cleared (default: 0)") smapsFilePathPattern = "/proc/%d/smaps" clearRefsFilePathPattern = "/proc/%d/clear_refs" referencedRegexp = regexp.MustCompile(`Referenced:\s*([0-9]+)\s*kB`) ) type Handler struct { cgroupManager cgroups.Manager rootFs string pid int includedMetrics container.MetricSet // pidMetricsCache holds CPU scheduler stats for existing processes (map key is PID) between calls to schedulerStatsFromProcs. pidMetricsCache map[int]*info.CpuSchedstat // pidMetricsSaved holds accumulated CPU scheduler stats for processes that no longer exist. pidMetricsSaved info.CpuSchedstat cycles uint64 } func NewHandler(cgroupManager cgroups.Manager, rootFs string, pid int, includedMetrics container.MetricSet) *Handler { return &Handler{ cgroupManager: cgroupManager, rootFs: rootFs, pid: pid, includedMetrics: includedMetrics, pidMetricsCache: make(map[int]*info.CpuSchedstat), } } // Get cgroup and networking stats of the specified container func (h *Handler) GetStats() (*info.ContainerStats, error) { ignoreStatsError := false if cgroups.IsCgroup2UnifiedMode() { // On cgroup v2 the root cgroup stats have been introduced in recent kernel versions, // so not all kernel versions have all the data. This means that stat fetching can fail // due to lacking cgroup stat files, but that some data is provided. if h.cgroupManager.Path("") == fs2.UnifiedMountpoint { ignoreStatsError = true } } cgroupStats, err := h.cgroupManager.GetStats() if err != nil { if !ignoreStatsError { return nil, err } klog.V(4).Infof("Ignoring errors when gathering stats for root cgroup since some controllers don't have stats on the root cgroup: %v", err) } stats := newContainerStats(cgroupStats, h.includedMetrics) if h.includedMetrics.Has(container.ProcessSchedulerMetrics) { stats.Cpu.Schedstat, err = h.schedulerStatsFromProcs() if err != nil { klog.V(4).Infof("Unable to get Process Scheduler Stats: %v", err) } } if h.includedMetrics.Has(container.ReferencedMemoryMetrics) { h.cycles++ pids, err := h.cgroupManager.GetPids() if err != nil { klog.V(4).Infof("Could not get PIDs for container %d: %v", h.pid, err) } else { stats.ReferencedMemory, err = referencedBytesStat(pids, h.cycles, *referencedResetInterval) if err != nil { klog.V(4).Infof("Unable to get referenced bytes: %v", err) } } } // If we know the pid then get network stats from /proc//net/dev if h.pid > 0 { if h.includedMetrics.Has(container.NetworkUsageMetrics) { netStats, err := networkStatsFromProc(h.rootFs, h.pid) if err != nil { klog.V(4).Infof("Unable to get network stats from pid %d: %v", h.pid, err) } else { stats.Network.Interfaces = append(stats.Network.Interfaces, netStats...) } } if h.includedMetrics.Has(container.NetworkTcpUsageMetrics) { t, err := tcpStatsFromProc(h.rootFs, h.pid, "net/tcp") if err != nil { klog.V(4).Infof("Unable to get tcp stats from pid %d: %v", h.pid, err) } else { stats.Network.Tcp = t } t6, err := tcpStatsFromProc(h.rootFs, h.pid, "net/tcp6") if err != nil { klog.V(4).Infof("Unable to get tcp6 stats from pid %d: %v", h.pid, err) } else { stats.Network.Tcp6 = t6 } } if h.includedMetrics.Has(container.NetworkAdvancedTcpUsageMetrics) { ta, err := advancedTCPStatsFromProc(h.rootFs, h.pid, "net/netstat", "net/snmp") if err != nil { klog.V(4).Infof("Unable to get advanced tcp stats from pid %d: %v", h.pid, err) } else { stats.Network.TcpAdvanced = ta } } if h.includedMetrics.Has(container.NetworkUdpUsageMetrics) { u, err := udpStatsFromProc(h.rootFs, h.pid, "net/udp") if err != nil { klog.V(4).Infof("Unable to get udp stats from pid %d: %v", h.pid, err) } else { stats.Network.Udp = u } u6, err := udpStatsFromProc(h.rootFs, h.pid, "net/udp6") if err != nil { klog.V(4).Infof("Unable to get udp6 stats from pid %d: %v", h.pid, err) } else { stats.Network.Udp6 = u6 } } } // some process metrics are per container ( number of processes, number of // file descriptors etc.) and not required a proper container's // root PID (systemd services don't have the root PID atm) if h.includedMetrics.Has(container.ProcessMetrics) { path, ok := common.GetControllerPath(h.cgroupManager.GetPaths(), "cpu", cgroups.IsCgroup2UnifiedMode()) if !ok { klog.V(4).Infof("Could not find cgroups CPU for container %d", h.pid) } else { stats.Processes, err = processStatsFromProcs(h.rootFs, path, h.pid) if err != nil { klog.V(4).Infof("Unable to get Process Stats: %v", err) } } // if include processes metrics, just set threads metrics if exist, and has no relationship with cpu path setThreadsStats(cgroupStats, stats) } // For backwards compatibility. if len(stats.Network.Interfaces) > 0 { stats.Network.InterfaceStats = stats.Network.Interfaces[0] } return stats, nil } func parseUlimit(value string) (int64, error) { num, err := strconv.ParseInt(value, 10, 64) if err != nil { if strings.EqualFold(value, "unlimited") { // -1 implies unlimited except for priority and nice; man limits.conf num = -1 } else { // Value is not a number or "unlimited"; return an error return 0, fmt.Errorf("unable to parse limit: %s", value) } } return num, nil } func processLimitsFile(fileData string) []info.UlimitSpec { const maxOpenFilesLinePrefix = "Max open files" limits := strings.Split(fileData, "\n") ulimits := make([]info.UlimitSpec, 0, len(limits)) for _, lim := range limits { // Skip any headers/footers if strings.HasPrefix(lim, "Max open files") { // Remove line prefix ulimit, err := processMaxOpenFileLimitLine( "max_open_files", lim[len(maxOpenFilesLinePrefix):], ) if err == nil { ulimits = append(ulimits, ulimit) } } } return ulimits } // Any caller of processMaxOpenFileLimitLine must ensure that the name prefix is already removed from the limit line. // with the "Max open files" prefix. func processMaxOpenFileLimitLine(name, line string) (info.UlimitSpec, error) { // Remove any leading whitespace line = strings.TrimSpace(line) // Split on whitespace fields := strings.Fields(line) if len(fields) != 3 { return info.UlimitSpec{}, fmt.Errorf("unable to parse max open files line: %s", line) } // The first field is the soft limit, the second is the hard limit soft, err := parseUlimit(fields[0]) if err != nil { return info.UlimitSpec{}, err } hard, err := parseUlimit(fields[1]) if err != nil { return info.UlimitSpec{}, err } return info.UlimitSpec{ Name: name, SoftLimit: soft, HardLimit: hard, }, nil } func processRootProcUlimits(rootFs string, rootPid int) []info.UlimitSpec { filePath := path.Join(rootFs, "/proc", strconv.Itoa(rootPid), "limits") out, err := os.ReadFile(filePath) if err != nil { klog.V(4).Infof("error while listing directory %q to read ulimits: %v", filePath, err) return []info.UlimitSpec{} } return processLimitsFile(string(out)) } func processStatsFromProcs(rootFs string, cgroupPath string, rootPid int) (info.ProcessStats, error) { var fdCount, socketCount uint64 filePath := path.Join(cgroupPath, "cgroup.procs") out, err := os.ReadFile(filePath) if err != nil { return info.ProcessStats{}, fmt.Errorf("couldn't open cpu cgroup procs file %v : %v", filePath, err) } pids := strings.Split(string(out), "\n") // EOL is also treated as a new line while reading "cgroup.procs" file with os.ReadFile. // The last value is an empty string "". Ex: pids = ["22", "1223", ""] // Trim the last value if len(pids) != 0 && pids[len(pids)-1] == "" { pids = pids[:len(pids)-1] } for _, pid := range pids { dirPath := path.Join(rootFs, "/proc", pid, "fd") fds, err := os.ReadDir(dirPath) if err != nil { klog.V(4).Infof("error while listing directory %q to measure fd count: %v", dirPath, err) continue } fdCount += uint64(len(fds)) for _, fd := range fds { fdPath := path.Join(dirPath, fd.Name()) linkName, err := os.Readlink(fdPath) if err != nil { klog.V(4).Infof("error while reading %q link: %v", fdPath, err) continue } if strings.HasPrefix(linkName, "socket") { socketCount++ } } } processStats := info.ProcessStats{ ProcessCount: uint64(len(pids)), FdCount: fdCount, SocketCount: socketCount, } if rootPid > 0 { processStats.Ulimits = processRootProcUlimits(rootFs, rootPid) } return processStats, nil } func (h *Handler) schedulerStatsFromProcs() (info.CpuSchedstat, error) { pids, err := h.cgroupManager.GetAllPids() if err != nil { return info.CpuSchedstat{}, fmt.Errorf("could not get PIDs for container %d: %w", h.pid, err) } alivePids := make(map[int]struct{}, len(pids)) for _, pid := range pids { f, err := os.Open(path.Join(h.rootFs, "proc", strconv.Itoa(pid), "schedstat")) if err != nil { return info.CpuSchedstat{}, fmt.Errorf("couldn't open scheduler statistics for process %d: %v", pid, err) } defer f.Close() contents, err := io.ReadAll(f) if err != nil { return info.CpuSchedstat{}, fmt.Errorf("couldn't read scheduler statistics for process %d: %v", pid, err) } alivePids[pid] = struct{}{} rawMetrics := bytes.Split(bytes.TrimRight(contents, "\n"), []byte(" ")) if len(rawMetrics) != 3 { return info.CpuSchedstat{}, fmt.Errorf("unexpected number of metrics in schedstat file for process %d", pid) } cacheEntry, ok := h.pidMetricsCache[pid] if !ok { cacheEntry = &info.CpuSchedstat{} h.pidMetricsCache[pid] = cacheEntry } for i, rawMetric := range rawMetrics { metric, err := strconv.ParseUint(string(rawMetric), 10, 64) if err != nil { return info.CpuSchedstat{}, fmt.Errorf("parsing error while reading scheduler statistics for process: %d: %v", pid, err) } switch i { case 0: cacheEntry.RunTime = metric case 1: cacheEntry.RunqueueTime = metric case 2: cacheEntry.RunPeriods = metric } } } schedstats := h.pidMetricsSaved // copy for p, v := range h.pidMetricsCache { schedstats.RunPeriods += v.RunPeriods schedstats.RunqueueTime += v.RunqueueTime schedstats.RunTime += v.RunTime if _, alive := alivePids[p]; !alive { // PID p is gone: accumulate its stats ... h.pidMetricsSaved.RunPeriods += v.RunPeriods h.pidMetricsSaved.RunqueueTime += v.RunqueueTime h.pidMetricsSaved.RunTime += v.RunTime // ... and remove its cache entry, to prevent // pidMetricsCache from growing. delete(h.pidMetricsCache, p) } } return schedstats, nil } // referencedBytesStat gets and clears referenced bytes // see: https://github.com/brendangregg/wss#wsspl-referenced-page-flag func referencedBytesStat(pids []int, cycles uint64, resetInterval uint64) (uint64, error) { referencedKBytes, err := getReferencedKBytes(pids) if err != nil { return uint64(0), err } err = clearReferencedBytes(pids, cycles, resetInterval) if err != nil { return uint64(0), err } return referencedKBytes * 1024, nil } func getReferencedKBytes(pids []int) (uint64, error) { referencedKBytes := uint64(0) readSmapsContent := false foundMatch := false for _, pid := range pids { smapsFilePath := fmt.Sprintf(smapsFilePathPattern, pid) smapsContent, err := os.ReadFile(smapsFilePath) if err != nil { klog.V(5).Infof("Cannot read %s file, err: %s", smapsFilePath, err) if os.IsNotExist(err) { continue // smaps file does not exists for all PIDs } return 0, err } readSmapsContent = true allMatches := referencedRegexp.FindAllSubmatch(smapsContent, -1) if len(allMatches) == 0 { klog.V(5).Infof("Not found any information about referenced bytes in %s file", smapsFilePath) continue // referenced bytes may not exist in smaps file } for _, matches := range allMatches { if len(matches) != 2 { return 0, fmt.Errorf("failed to match regexp in output: %s", string(smapsContent)) } foundMatch = true referenced, err := strconv.ParseUint(string(matches[1]), 10, 64) if err != nil { return 0, err } referencedKBytes += referenced } } if len(pids) != 0 { if !readSmapsContent { klog.Warningf("Cannot read smaps files for any PID from %s", "CONTAINER") } else if !foundMatch { klog.Warningf("Not found any information about referenced bytes in smaps files for any PID from %s", "CONTAINER") } } return referencedKBytes, nil } func clearReferencedBytes(pids []int, cycles uint64, resetInterval uint64) error { if resetInterval == 0 { return nil } if cycles%resetInterval == 0 { for _, pid := range pids { clearRefsFilePath := fmt.Sprintf(clearRefsFilePathPattern, pid) clerRefsFile, err := os.OpenFile(clearRefsFilePath, os.O_WRONLY, 0o644) if err != nil { // clear_refs file may not exist for all PIDs continue } _, err = clerRefsFile.WriteString("1\n") if err != nil { return err } err = clerRefsFile.Close() if err != nil { return err } } } return nil } func networkStatsFromProc(rootFs string, pid int) ([]info.InterfaceStats, error) { netStatsFile := path.Join(rootFs, "proc", strconv.Itoa(pid), "/net/dev") ifaceStats, err := scanInterfaceStats(netStatsFile) if err != nil { return []info.InterfaceStats{}, fmt.Errorf("couldn't read network stats: %v", err) } return ifaceStats, nil } var ignoredDevicePrefixes = []string{"lo", "veth", "docker", "nerdctl"} func isIgnoredDevice(ifName string) bool { for _, prefix := range ignoredDevicePrefixes { if strings.HasPrefix(strings.ToLower(ifName), prefix) { return true } } return false } func scanInterfaceStats(netStatsFile string) ([]info.InterfaceStats, error) { file, err := os.Open(netStatsFile) if err != nil { return nil, fmt.Errorf("failure opening %s: %v", netStatsFile, err) } defer file.Close() scanner := bufio.NewScanner(file) // Discard header lines for i := 0; i < 2; i++ { if b := scanner.Scan(); !b { return nil, scanner.Err() } } stats := []info.InterfaceStats{} for scanner.Scan() { line := scanner.Text() line = strings.Replace(line, ":", "", -1) fields := strings.Fields(line) // If the format of the line is invalid then don't trust any of the stats // in this file. if len(fields) != 17 { return nil, fmt.Errorf("invalid interface stats line: %v", line) } devName := fields[0] if isIgnoredDevice(devName) { continue } i := info.InterfaceStats{ Name: devName, } statFields := append(fields[1:5], fields[9:13]...) statPointers := []*uint64{ &i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped, &i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped, } err := setInterfaceStatValues(statFields, statPointers) if err != nil { return nil, fmt.Errorf("cannot parse interface stats (%v): %v", err, line) } stats = append(stats, i) } return stats, nil } func setInterfaceStatValues(fields []string, pointers []*uint64) error { for i, v := range fields { val, err := strconv.ParseUint(v, 10, 64) if err != nil { return err } *pointers[i] = val } return nil } func tcpStatsFromProc(rootFs string, pid int, file string) (info.TcpStat, error) { tcpStatsFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file) tcpStats, err := scanTCPStats(tcpStatsFile) if err != nil { return tcpStats, fmt.Errorf("couldn't read tcp stats: %v", err) } return tcpStats, nil } func advancedTCPStatsFromProc(rootFs string, pid int, file1, file2 string) (info.TcpAdvancedStat, error) { var advancedStats info.TcpAdvancedStat var err error netstatFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file1) err = scanAdvancedTCPStats(&advancedStats, netstatFile) if err != nil { return advancedStats, err } snmpFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file2) err = scanAdvancedTCPStats(&advancedStats, snmpFile) if err != nil { return advancedStats, err } return advancedStats, nil } func scanAdvancedTCPStats(advancedStats *info.TcpAdvancedStat, advancedTCPStatsFile string) error { data, err := os.ReadFile(advancedTCPStatsFile) if err != nil { return fmt.Errorf("failure opening %s: %v", advancedTCPStatsFile, err) } reader := strings.NewReader(string(data)) scanner := bufio.NewScanner(reader) scanner.Split(bufio.ScanLines) advancedTCPStats := make(map[string]interface{}) for scanner.Scan() { nameParts := strings.Split(scanner.Text(), " ") scanner.Scan() valueParts := strings.Split(scanner.Text(), " ") // Remove trailing :. and ignore non-tcp protocol := nameParts[0][:len(nameParts[0])-1] if protocol != "TcpExt" && protocol != "Tcp" { continue } if len(nameParts) != len(valueParts) { return fmt.Errorf("mismatch field count mismatch in %s: %s", advancedTCPStatsFile, protocol) } for i := 1; i < len(nameParts); i++ { if strings.Contains(valueParts[i], "-") { vInt64, err := strconv.ParseInt(valueParts[i], 10, 64) if err != nil { return fmt.Errorf("decode value: %s to int64 error: %s", valueParts[i], err) } advancedTCPStats[nameParts[i]] = vInt64 } else { vUint64, err := strconv.ParseUint(valueParts[i], 10, 64) if err != nil { return fmt.Errorf("decode value: %s to uint64 error: %s", valueParts[i], err) } advancedTCPStats[nameParts[i]] = vUint64 } } } b, err := json.Marshal(advancedTCPStats) if err != nil { return err } err = json.Unmarshal(b, advancedStats) if err != nil { return err } return scanner.Err() } func scanTCPStats(tcpStatsFile string) (info.TcpStat, error) { var stats info.TcpStat data, err := os.ReadFile(tcpStatsFile) if err != nil { return stats, fmt.Errorf("failure opening %s: %v", tcpStatsFile, err) } tcpStateMap := map[string]uint64{ "01": 0, // ESTABLISHED "02": 0, // SYN_SENT "03": 0, // SYN_RECV "04": 0, // FIN_WAIT1 "05": 0, // FIN_WAIT2 "06": 0, // TIME_WAIT "07": 0, // CLOSE "08": 0, // CLOSE_WAIT "09": 0, // LAST_ACK "0A": 0, // LISTEN "0B": 0, // CLOSING } reader := strings.NewReader(string(data)) scanner := bufio.NewScanner(reader) scanner.Split(bufio.ScanLines) // Discard header line if b := scanner.Scan(); !b { return stats, scanner.Err() } for scanner.Scan() { line := scanner.Text() state := strings.Fields(line) // TCP state is the 4th field. // Format: sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode tcpState := state[3] _, ok := tcpStateMap[tcpState] if !ok { return stats, fmt.Errorf("invalid TCP stats line: %v", line) } tcpStateMap[tcpState]++ } stats = info.TcpStat{ Established: tcpStateMap["01"], SynSent: tcpStateMap["02"], SynRecv: tcpStateMap["03"], FinWait1: tcpStateMap["04"], FinWait2: tcpStateMap["05"], TimeWait: tcpStateMap["06"], Close: tcpStateMap["07"], CloseWait: tcpStateMap["08"], LastAck: tcpStateMap["09"], Listen: tcpStateMap["0A"], Closing: tcpStateMap["0B"], } return stats, nil } func udpStatsFromProc(rootFs string, pid int, file string) (info.UdpStat, error) { var err error var udpStats info.UdpStat udpStatsFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file) r, err := os.Open(udpStatsFile) if err != nil { return udpStats, fmt.Errorf("failure opening %s: %v", udpStatsFile, err) } udpStats, err = scanUDPStats(r) if err != nil { return udpStats, fmt.Errorf("couldn't read udp stats: %v", err) } return udpStats, nil } func scanUDPStats(r io.Reader) (info.UdpStat, error) { var stats info.UdpStat scanner := bufio.NewScanner(r) scanner.Split(bufio.ScanLines) // Discard header line if b := scanner.Scan(); !b { return stats, scanner.Err() } var listening, dropped, rxQueued, txQueued uint64 for scanner.Scan() { line := scanner.Text() // Format: sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops listening++ fs := strings.Fields(line) if len(fs) != 13 { continue } var rx, tx uint64 _, err := fmt.Sscanf(fs[4], "%X:%X", &rx, &tx) if err != nil { continue } rxQueued += rx txQueued += tx d, err := strconv.Atoi(string(fs[12])) if err != nil { continue } dropped += uint64(d) } stats = info.UdpStat{ Listen: listening, Dropped: dropped, RxQueued: rxQueued, TxQueued: txQueued, } return stats, nil } func (h *Handler) GetProcesses() ([]int, error) { pids, err := h.cgroupManager.GetPids() if err != nil { return nil, err } return pids, nil } // Convert libcontainer stats to info.ContainerStats. func setCPUStats(s *cgroups.Stats, ret *info.ContainerStats, withPerCPU bool) { ret.Cpu.Usage.User = s.CpuStats.CpuUsage.UsageInUsermode ret.Cpu.Usage.System = s.CpuStats.CpuUsage.UsageInKernelmode ret.Cpu.Usage.Total = s.CpuStats.CpuUsage.TotalUsage ret.Cpu.CFS.Periods = s.CpuStats.ThrottlingData.Periods ret.Cpu.CFS.ThrottledPeriods = s.CpuStats.ThrottlingData.ThrottledPeriods ret.Cpu.CFS.ThrottledTime = s.CpuStats.ThrottlingData.ThrottledTime ret.Cpu.CFS.BurstsPeriods = s.CpuStats.BurstData.BurstsPeriods ret.Cpu.CFS.BurstTime = s.CpuStats.BurstData.BurstTime setPSIStats(s.CpuStats.PSI, &ret.Cpu.PSI) if !withPerCPU { return } if len(s.CpuStats.CpuUsage.PercpuUsage) == 0 { // libcontainer's 'GetStats' can leave 'PercpuUsage' nil if it skipped the // cpuacct subsystem. return } ret.Cpu.Usage.PerCpu = s.CpuStats.CpuUsage.PercpuUsage } func setDiskIoStats(s *cgroups.Stats, ret *info.ContainerStats) { ret.DiskIo.IoServiceBytes = diskStatsCopy(s.BlkioStats.IoServiceBytesRecursive) ret.DiskIo.IoServiced = diskStatsCopy(s.BlkioStats.IoServicedRecursive) ret.DiskIo.IoQueued = diskStatsCopy(s.BlkioStats.IoQueuedRecursive) ret.DiskIo.Sectors = diskStatsCopy(s.BlkioStats.SectorsRecursive) ret.DiskIo.IoServiceTime = diskStatsCopy(s.BlkioStats.IoServiceTimeRecursive) ret.DiskIo.IoWaitTime = diskStatsCopy(s.BlkioStats.IoWaitTimeRecursive) ret.DiskIo.IoMerged = diskStatsCopy(s.BlkioStats.IoMergedRecursive) ret.DiskIo.IoTime = diskStatsCopy(s.BlkioStats.IoTimeRecursive) ret.DiskIo.IoCostUsage = diskStatsCopy(s.BlkioStats.IoCostUsage) ret.DiskIo.IoCostWait = diskStatsCopy(s.BlkioStats.IoCostWait) ret.DiskIo.IoCostIndebt = diskStatsCopy(s.BlkioStats.IoCostIndebt) ret.DiskIo.IoCostIndelay = diskStatsCopy(s.BlkioStats.IoCostIndelay) setPSIStats(s.BlkioStats.PSI, &ret.DiskIo.PSI) } func setMemoryStats(s *cgroups.Stats, ret *info.ContainerStats) { ret.Memory.Usage = s.MemoryStats.Usage.Usage ret.Memory.MaxUsage = s.MemoryStats.Usage.MaxUsage ret.Memory.Failcnt = s.MemoryStats.Usage.Failcnt ret.Memory.KernelUsage = s.MemoryStats.KernelUsage.Usage setPSIStats(s.MemoryStats.PSI, &ret.Memory.PSI) if cgroups.IsCgroup2UnifiedMode() { ret.Memory.Cache = s.MemoryStats.Stats["file"] ret.Memory.RSS = s.MemoryStats.Stats["anon"] ret.Memory.Swap = s.MemoryStats.SwapUsage.Usage - s.MemoryStats.Usage.Usage ret.Memory.MappedFile = s.MemoryStats.Stats["file_mapped"] } else if s.MemoryStats.UseHierarchy { ret.Memory.Cache = s.MemoryStats.Stats["total_cache"] ret.Memory.RSS = s.MemoryStats.Stats["total_rss"] ret.Memory.Swap = s.MemoryStats.Stats["total_swap"] ret.Memory.MappedFile = s.MemoryStats.Stats["total_mapped_file"] } else { ret.Memory.Cache = s.MemoryStats.Stats["cache"] ret.Memory.RSS = s.MemoryStats.Stats["rss"] ret.Memory.Swap = s.MemoryStats.Stats["swap"] ret.Memory.MappedFile = s.MemoryStats.Stats["mapped_file"] } if v, ok := s.MemoryStats.Stats["pgfault"]; ok { ret.Memory.ContainerData.Pgfault = v ret.Memory.HierarchicalData.Pgfault = v } if v, ok := s.MemoryStats.Stats["pgmajfault"]; ok { ret.Memory.ContainerData.Pgmajfault = v ret.Memory.HierarchicalData.Pgmajfault = v } inactiveFileKeyName := "total_inactive_file" if cgroups.IsCgroup2UnifiedMode() { inactiveFileKeyName = "inactive_file" } activeFileKeyName := "total_active_file" if cgroups.IsCgroup2UnifiedMode() { activeFileKeyName = "active_file" } if v, ok := s.MemoryStats.Stats[activeFileKeyName]; ok { ret.Memory.TotalActiveFile = v } workingSet := ret.Memory.Usage if v, ok := s.MemoryStats.Stats[inactiveFileKeyName]; ok { ret.Memory.TotalInactiveFile = v if workingSet < v { workingSet = 0 } else { workingSet -= v } } ret.Memory.WorkingSet = workingSet } func setCPUSetStats(s *cgroups.Stats, ret *info.ContainerStats) { ret.CpuSet.MemoryMigrate = s.CPUSetStats.MemoryMigrate } func getNumaStats(memoryStats map[uint8]uint64) map[uint8]uint64 { stats := make(map[uint8]uint64, len(memoryStats)) for node, usage := range memoryStats { stats[node] = usage } return stats } func setMemoryNumaStats(s *cgroups.Stats, ret *info.ContainerStats) { ret.Memory.ContainerData.NumaStats.File = getNumaStats(s.MemoryStats.PageUsageByNUMA.File.Nodes) ret.Memory.ContainerData.NumaStats.Anon = getNumaStats(s.MemoryStats.PageUsageByNUMA.Anon.Nodes) ret.Memory.ContainerData.NumaStats.Unevictable = getNumaStats(s.MemoryStats.PageUsageByNUMA.Unevictable.Nodes) ret.Memory.HierarchicalData.NumaStats.File = getNumaStats(s.MemoryStats.PageUsageByNUMA.Hierarchical.File.Nodes) ret.Memory.HierarchicalData.NumaStats.Anon = getNumaStats(s.MemoryStats.PageUsageByNUMA.Hierarchical.Anon.Nodes) ret.Memory.HierarchicalData.NumaStats.Unevictable = getNumaStats(s.MemoryStats.PageUsageByNUMA.Hierarchical.Unevictable.Nodes) } func setHugepageStats(s *cgroups.Stats, ret *info.ContainerStats) { ret.Hugetlb = make(map[string]info.HugetlbStats) for k, v := range s.HugetlbStats { ret.Hugetlb[k] = info.HugetlbStats{ Usage: v.Usage, MaxUsage: v.MaxUsage, Failcnt: v.Failcnt, } } } func setPSIData(d *cgroups.PSIData, ret *info.PSIData) { if d != nil { ret.Total = d.Total ret.Avg10 = d.Avg10 ret.Avg60 = d.Avg60 ret.Avg300 = d.Avg300 } } func setPSIStats(s *cgroups.PSIStats, ret *info.PSIStats) { if s != nil { setPSIData(&s.Full, &ret.Full) setPSIData(&s.Some, &ret.Some) } } // read from pids path not cpu func setThreadsStats(s *cgroups.Stats, ret *info.ContainerStats) { if s != nil { ret.Processes.ThreadsCurrent = s.PidsStats.Current ret.Processes.ThreadsMax = s.PidsStats.Limit } } func newContainerStats(cgroupStats *cgroups.Stats, includedMetrics container.MetricSet) *info.ContainerStats { ret := &info.ContainerStats{ Timestamp: time.Now(), } if s := cgroupStats; s != nil { setCPUStats(s, ret, includedMetrics.Has(container.PerCpuUsageMetrics)) if includedMetrics.Has(container.DiskIOMetrics) { setDiskIoStats(s, ret) } setMemoryStats(s, ret) if includedMetrics.Has(container.MemoryNumaMetrics) { setMemoryNumaStats(s, ret) } if includedMetrics.Has(container.HugetlbUsageMetrics) { setHugepageStats(s, ret) } if includedMetrics.Has(container.CPUSetMetrics) { setCPUSetStats(s, ret) } } return ret } ================================================ FILE: container/libcontainer/handler_test.go ================================================ // Copyright 2018 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package libcontainer import ( "os" "reflect" "testing" "github.com/opencontainers/cgroups" "github.com/stretchr/testify/assert" info "github.com/google/cadvisor/info/v1" ) func TestScanInterfaceStats(t *testing.T) { stats, err := scanInterfaceStats("testdata/procnetdev") if err != nil { t.Error(err) } netdevstats := []info.InterfaceStats{ { Name: "wlp4s0", RxBytes: 1, RxPackets: 2, RxErrors: 3, RxDropped: 4, TxBytes: 9, TxPackets: 10, TxErrors: 11, TxDropped: 12, }, { Name: "em1", RxBytes: 315849, RxPackets: 1172, RxErrors: 0, RxDropped: 0, TxBytes: 315850, TxPackets: 1173, TxErrors: 0, TxDropped: 0, }, } if len(stats) != len(netdevstats) { t.Errorf("Expected 2 net stats, got %d", len(stats)) } for i, v := range netdevstats { if v != stats[i] { t.Errorf("Expected %#v, got %#v", v, stats[i]) } } } func TestScanUDPStats(t *testing.T) { udpStatsFile := "testdata/procnetudp" r, err := os.Open(udpStatsFile) if err != nil { t.Errorf("failure opening %s: %v", udpStatsFile, err) } stats, err := scanUDPStats(r) if err != nil { t.Error(err) } udpstats := info.UdpStat{ Listen: 2, Dropped: 4, RxQueued: 10, TxQueued: 11, } if stats != udpstats { t.Errorf("Expected %#v, got %#v", udpstats, stats) } } // https://github.com/docker/libcontainer/blob/v2.2.1/cgroups/fs/cpuacct.go#L19 const nanosecondsInSeconds = 1000000000 // https://github.com/containerd/cgroups/pull/12 const clockTicks = 100 func TestSetCPUStats(t *testing.T) { perCPUUsage := make([]uint64, 31) for i := uint32(0); i < 31; i++ { perCPUUsage[i] = 8562955455524 } s := &cgroups.Stats{ CpuStats: cgroups.CpuStats{ CpuUsage: cgroups.CpuUsage{ PercpuUsage: perCPUUsage, TotalUsage: 33802947350272, UsageInKernelmode: 734746 * nanosecondsInSeconds / clockTicks, UsageInUsermode: 2767637 * nanosecondsInSeconds / clockTicks, }, PSI: &cgroups.PSIStats{ Full: cgroups.PSIData{ Avg10: 0.3, Avg60: 0.2, Avg300: 0.1, Total: 100, }, Some: cgroups.PSIData{ Avg10: 0.6, Avg60: 0.4, Avg300: 0.2, Total: 200, }, }, }, } var ret info.ContainerStats setCPUStats(s, &ret, true) expected := info.ContainerStats{ Cpu: info.CpuStats{ Usage: info.CpuUsage{ PerCpu: perCPUUsage, User: s.CpuStats.CpuUsage.UsageInUsermode, System: s.CpuStats.CpuUsage.UsageInKernelmode, Total: 33802947350272, }, PSI: info.PSIStats{ Full: info.PSIData{ Avg10: 0.3, Avg60: 0.2, Avg300: 0.1, Total: 100, }, Some: info.PSIData{ Avg10: 0.6, Avg60: 0.4, Avg300: 0.2, Total: 200, }, }, }, } if !ret.Eq(&expected) { t.Fatalf("expected %+v == %+v", ret, expected) } } func TestSetProcessesStats(t *testing.T) { ret := info.ContainerStats{ Processes: info.ProcessStats{ ProcessCount: 1, FdCount: 2, }, } s := &cgroups.Stats{ PidsStats: cgroups.PidsStats{ Current: 5, Limit: 100, }, } setThreadsStats(s, &ret) expected := info.ContainerStats{ Processes: info.ProcessStats{ ProcessCount: 1, FdCount: 2, ThreadsCurrent: s.PidsStats.Current, ThreadsMax: s.PidsStats.Limit, }, } if expected.Processes.ProcessCount != ret.Processes.ProcessCount { t.Fatalf("expected ProcessCount: %d == %d", ret.Processes.ProcessCount, expected.Processes.ProcessCount) } if expected.Processes.FdCount != ret.Processes.FdCount { t.Fatalf("expected FdCount: %d == %d", ret.Processes.FdCount, expected.Processes.FdCount) } if expected.Processes.ThreadsCurrent != ret.Processes.ThreadsCurrent { t.Fatalf("expected current threads: %d == %d", ret.Processes.ThreadsCurrent, expected.Processes.ThreadsCurrent) } if expected.Processes.ThreadsMax != ret.Processes.ThreadsMax { t.Fatalf("expected max threads: %d == %d", ret.Processes.ThreadsMax, expected.Processes.ThreadsMax) } } func TestParseLimitsFile(t *testing.T) { testData := []struct { limitLine string expected []info.UlimitSpec }{ { "Limit Soft Limit Hard Limit Units \n", []info.UlimitSpec{}, }, { "Max open files 8192 8192 files \n", []info.UlimitSpec{{Name: "max_open_files", SoftLimit: 8192, HardLimit: 8192}}, }, { "Max open files 85899345920 85899345920 files \n", []info.UlimitSpec{{Name: "max_open_files", SoftLimit: 85899345920, HardLimit: 85899345920}}, }, { "Max open files gibberish1 8192 files \n", []info.UlimitSpec{}, }, { "Max open files 8192 0xbaddata files \n", []info.UlimitSpec{}, }, { "Max stack size 8192 8192 files \n", []info.UlimitSpec{}, }, } for _, testItem := range testData { actual := processLimitsFile(testItem.limitLine) if reflect.DeepEqual(actual, testItem.expected) == false { t.Fatalf("Parsed ulimit doesn't match expected values for line: %s", testItem.limitLine) } } } func TestReferencedBytesStat(t *testing.T) { // overwrite package variables smapsFilePathPattern = "testdata/smaps%d" clearRefsFilePathPattern = "testdata/clear_refs%d" pids := []int{4, 6, 8} stat, err := referencedBytesStat(pids, 1, 3) assert.Nil(t, err) assert.Equal(t, uint64(416*1024), stat) clearRefsFiles := []string{ "testdata/clear_refs4", "testdata/clear_refs6", "testdata/clear_refs8", } // check if clear_refs files have proper values assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[0])) assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[1])) assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[2])) } func TestReferencedBytesStatWhenNeverCleared(t *testing.T) { // overwrite package variables smapsFilePathPattern = "testdata/smaps%d" clearRefsFilePathPattern = "testdata/clear_refs%d" pids := []int{4, 6, 8} stat, err := referencedBytesStat(pids, 1, 0) assert.Nil(t, err) assert.Equal(t, uint64(416*1024), stat) clearRefsFiles := []string{ "testdata/clear_refs4", "testdata/clear_refs6", "testdata/clear_refs8", } // check if clear_refs files have proper values assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[0])) assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[1])) assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[2])) } func TestReferencedBytesStatWhenResetIsNeeded(t *testing.T) { // overwrite package variables smapsFilePathPattern = "testdata/smaps%d" clearRefsFilePathPattern = "testdata/clear_refs%d" pids := []int{4, 6, 8} stat, err := referencedBytesStat(pids, 1, 1) assert.Nil(t, err) assert.Equal(t, uint64(416*1024), stat) clearRefsFiles := []string{ "testdata/clear_refs4", "testdata/clear_refs6", "testdata/clear_refs8", } // check if clear_refs files have proper values assert.Equal(t, "1\n", getFileContent(t, clearRefsFiles[0])) assert.Equal(t, "1\n", getFileContent(t, clearRefsFiles[1])) assert.Equal(t, "1\n", getFileContent(t, clearRefsFiles[2])) clearTestData(t, clearRefsFiles) } func TestGetReferencedKBytesWhenSmapsMissing(t *testing.T) { // overwrite package variable smapsFilePathPattern = "testdata/smaps%d" pids := []int{10} referenced, err := getReferencedKBytes(pids) assert.Nil(t, err) assert.Equal(t, uint64(0), referenced) } func TestClearReferencedBytesWhenClearRefsMissing(t *testing.T) { // overwrite package variable clearRefsFilePathPattern = "testdata/clear_refs%d" pids := []int{10} err := clearReferencedBytes(pids, 0, 1) assert.Nil(t, err) } var ulimits []info.UlimitSpec func BenchmarkProcessLimitsFile(b *testing.B) { content, err := os.ReadFile("testdata/limits") assert.Nil(b, err) b.ResetTimer() for i := 0; i < b.N; i++ { ulimits = processLimitsFile(string(content)) } // Ensure the compiler doesn't optimize away the benchmark _ = ulimits } func TestProcessMaxOpenFileLimitLine(t *testing.T) { line := " 1073741816 1073741816 files " ulimit, err := processMaxOpenFileLimitLine("max_open_files", line) assert.Nil(t, err) assert.Equal(t, "max_open_files", ulimit.Name) assert.Equal(t, int64(1073741816), ulimit.SoftLimit) assert.Equal(t, int64(1073741816), ulimit.HardLimit) } ================================================ FILE: container/libcontainer/helpers.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package libcontainer import ( "fmt" "github.com/google/cadvisor/container" info "github.com/google/cadvisor/info/v1" "github.com/opencontainers/cgroups" fs "github.com/opencontainers/cgroups/fs" fs2 "github.com/opencontainers/cgroups/fs2" "k8s.io/klog/v2" ) // GetCgroupSubsystems returns information about the cgroup subsystems that are // of interest as a map of cgroup controllers to their mount points. // For example, "cpu" -> "/sys/fs/cgroup/cpu". // // The incudeMetrics arguments specifies which metrics are requested, // and is used to filter out some cgroups and their mounts. If nil, // all supported cgroup subsystems are included. // // For cgroup v2, includedMetrics argument is unused, the only map key is "" // (empty string), and the value is the unified cgroup mount point. func GetCgroupSubsystems(includedMetrics container.MetricSet) (map[string]string, error) { if cgroups.IsCgroup2UnifiedMode() { return map[string]string{"": fs2.UnifiedMountpoint}, nil } // Get all cgroup mounts. allCgroups, err := cgroups.GetCgroupMounts(true) if err != nil { return nil, err } return getCgroupSubsystemsHelper(allCgroups, includedMetrics) } func getCgroupSubsystemsHelper(allCgroups []cgroups.Mount, includedMetrics container.MetricSet) (map[string]string, error) { if len(allCgroups) == 0 { return nil, fmt.Errorf("failed to find cgroup mounts") } // Trim the mounts to only the subsystems we care about. mountPoints := make(map[string]string, len(allCgroups)) for _, mount := range allCgroups { for _, subsystem := range mount.Subsystems { if !needSubsys(subsystem, includedMetrics) { continue } if _, ok := mountPoints[subsystem]; ok { // duplicate mount for this subsystem; use the first one we saw klog.V(5).Infof("skipping %s, already using mount at %s", mount.Mountpoint, mountPoints[subsystem]) continue } mountPoints[subsystem] = mount.Mountpoint } } return mountPoints, nil } // A map of cgroup subsystems we support listing (should be the minimal set // we need stats from) to a respective MetricKind. var supportedSubsystems = map[string]container.MetricKind{ "cpu": container.CpuUsageMetrics, "cpuacct": container.CpuUsageMetrics, "memory": container.MemoryUsageMetrics, "hugetlb": container.HugetlbUsageMetrics, "pids": container.ProcessMetrics, "cpuset": container.CPUSetMetrics, "blkio": container.DiskIOMetrics, "io": container.DiskIOMetrics, "devices": "", "perf_event": container.PerfMetrics, } // Check if this cgroup subsystem/controller is of use. func needSubsys(name string, metrics container.MetricSet) bool { // Check if supported. metric, supported := supportedSubsystems[name] if !supported { return false } // Check if needed. if metrics == nil || metric == "" { return true } return metrics.Has(metric) } func diskStatsCopy0(major, minor uint64) *info.PerDiskStats { disk := info.PerDiskStats{ Major: major, Minor: minor, } disk.Stats = make(map[string]uint64) return &disk } type diskKey struct { Major uint64 Minor uint64 } func diskStatsCopy1(diskStat map[diskKey]*info.PerDiskStats) []info.PerDiskStats { i := 0 stat := make([]info.PerDiskStats, len(diskStat)) for _, disk := range diskStat { stat[i] = *disk i++ } return stat } func diskStatsCopy(blkioStats []cgroups.BlkioStatEntry) (stat []info.PerDiskStats) { if len(blkioStats) == 0 { return } diskStat := make(map[diskKey]*info.PerDiskStats) for i := range blkioStats { major := blkioStats[i].Major minor := blkioStats[i].Minor key := diskKey{ Major: major, Minor: minor, } diskp, ok := diskStat[key] if !ok { diskp = diskStatsCopy0(major, minor) diskStat[key] = diskp } op := blkioStats[i].Op if op == "" { op = "Count" } diskp.Stats[op] = blkioStats[i].Value } return diskStatsCopy1(diskStat) } func NewCgroupManager(name string, paths map[string]string) (cgroups.Manager, error) { config := &cgroups.Cgroup{ Name: name, Resources: &cgroups.Resources{}, } if cgroups.IsCgroup2UnifiedMode() { path := paths[""] return fs2.NewManager(config, path) } return fs.NewManager(config, paths) } ================================================ FILE: container/libcontainer/helpers_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package libcontainer import ( "os" "path/filepath" "reflect" "strings" "testing" "github.com/opencontainers/cgroups" "github.com/stretchr/testify/assert" ) var defaultCgroupSubsystems = []string{ "systemd", "freezer", "memory", "blkio", "hugetlb", "net_cls,net_prio", "pids", "cpu,cpuacct", "devices", "cpuset", "perf_events", } func cgroupMountsAt(path string, subsystems []string) []cgroups.Mount { res := []cgroups.Mount{} for _, subsystem := range subsystems { res = append(res, cgroups.Mount{ Root: "/", Subsystems: strings.Split(subsystem, ","), Mountpoint: filepath.Join(path, subsystem), }) } return res } func TestGetCgroupSubsystems(t *testing.T) { testCases := []struct { mounts []cgroups.Mount expected map[string]string err bool }{ { mounts: []cgroups.Mount{}, err: true, }, { // normal case mounts: cgroupMountsAt("/sys/fs/cgroup", defaultCgroupSubsystems), expected: map[string]string{ "blkio": "/sys/fs/cgroup/blkio", "cpu": "/sys/fs/cgroup/cpu,cpuacct", "cpuacct": "/sys/fs/cgroup/cpu,cpuacct", "cpuset": "/sys/fs/cgroup/cpuset", "devices": "/sys/fs/cgroup/devices", "memory": "/sys/fs/cgroup/memory", "hugetlb": "/sys/fs/cgroup/hugetlb", "pids": "/sys/fs/cgroup/pids", }, }, { // multiple croup subsystems, should ignore second one mounts: append(cgroupMountsAt("/sys/fs/cgroup", defaultCgroupSubsystems), cgroupMountsAt("/var/lib/rkt/pods/run/ccdd4e36-2d4c-49fd-8b94-4fb06133913d/stage1/rootfs/opt/stage2/flannel/rootfs/sys/fs/cgroup", defaultCgroupSubsystems)...), expected: map[string]string{ "blkio": "/sys/fs/cgroup/blkio", "cpu": "/sys/fs/cgroup/cpu,cpuacct", "cpuacct": "/sys/fs/cgroup/cpu,cpuacct", "cpuset": "/sys/fs/cgroup/cpuset", "devices": "/sys/fs/cgroup/devices", "memory": "/sys/fs/cgroup/memory", "hugetlb": "/sys/fs/cgroup/hugetlb", "pids": "/sys/fs/cgroup/pids", }, }, { // most subsystems not mounted mounts: cgroupMountsAt("/sys/fs/cgroup", []string{"cpu"}), expected: map[string]string{ "cpu": "/sys/fs/cgroup/cpu", }, }, } for i, testCase := range testCases { subSystems, err := getCgroupSubsystemsHelper(testCase.mounts, nil) if testCase.err { if err == nil { t.Fatalf("[case %d] Expected error but didn't get one", i) } continue } if err != nil { t.Fatalf("[case %d] Expected no error, but got %v", i, err) } if !reflect.DeepEqual(testCase.expected, subSystems) { t.Fatalf("[case %d] Expected %v == %v", i, testCase.expected, subSystems) } } } func getFileContent(t *testing.T, filePath string) string { fileContent, err := os.ReadFile(filePath) assert.Nil(t, err) return string(fileContent) } func clearTestData(t *testing.T, clearRefsPaths []string) { for _, clearRefsPath := range clearRefsPaths { err := os.WriteFile(clearRefsPath, []byte("0\n"), 0o644) assert.Nil(t, err) } } ================================================ FILE: container/libcontainer/testdata/clear_refs4 ================================================ 0 ================================================ FILE: container/libcontainer/testdata/clear_refs6 ================================================ 0 ================================================ FILE: container/libcontainer/testdata/clear_refs8 ================================================ 0 ================================================ FILE: container/libcontainer/testdata/docker-v1.8.3/execdriver/native/1/state.json ================================================ {"id":"1","init_process_pid":66241,"init_process_start":"4507843","cgroup_paths":{"blkio":"/sys/fs/cgroup/blkio/docker/1","cpu":"/sys/fs/cgroup/cpu/docker/1","cpuacct":"/sys/fs/cgroup/cpuacct/docker/1","cpuset":"/sys/fs/cgroup/cpuset/docker/1","devices":"/sys/fs/cgroup/devices/docker/1","freezer":"/sys/fs/cgroup/freezer/docker/1","hugetlb":"/sys/fs/cgroup/hugetlb/docker/1","memory":"/sys/fs/cgroup/memory/docker/1","net_cls":"/sys/fs/cgroup/net_cls/docker/1","net_prio":"/sys/fs/cgroup/net_prio/docker/1","perf_event":"/sys/fs/cgroup/perf_event/docker/1"},"namespace_paths":{"NEWIPC":"/proc/66241/ns/ipc","NEWNET":"/var/run/docker/netns/e05ddb1777f3","NEWNS":"/proc/66241/ns/mnt","NEWPID":"/proc/66241/ns/pid","NEWUSER":"/proc/66241/ns/user","NEWUTS":"/proc/66241/ns/uts"},"config":{"no_pivot_root":false,"parent_death_signal":0,"pivot_dir":"","rootfs":"/var/lib/docker/devicemapper/mnt/1/rootfs","readonlyfs":false,"privatefs":true,"mounts":[{"source":"proc","destination":"/proc","device":"proc","flags":14,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"tmpfs","destination":"/dev","device":"tmpfs","flags":16777218,"data":"mode=755","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"devpts","destination":"/dev/pts","device":"devpts","flags":10,"data":"newinstance,ptmxmode=0666,mode=0620,gid=5","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"shm","destination":"/dev/shm","device":"tmpfs","flags":14,"data":"mode=1777,size=65536k","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"mqueue","destination":"/dev/mqueue","device":"mqueue","flags":14,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"sysfs","destination":"/sys","device":"sysfs","flags":15,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"cgroup","destination":"/sys/fs/cgroup","device":"cgroup","flags":15,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"/var/lib/docker/containers/1/resolv.conf","destination":"/etc/resolv.conf","device":"bind","flags":20480,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"/var/lib/docker/containers/1/hostname","destination":"/etc/hostname","device":"bind","flags":20480,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"/var/lib/docker/containers/1/hosts","destination":"/etc/hosts","device":"bind","flags":20480,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null}],"devices":[{"type":99,"path":"/dev/fuse","major":10,"minor":229,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"/dev/null","major":1,"minor":3,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/zero","major":1,"minor":5,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/full","major":1,"minor":7,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/tty","major":5,"minor":0,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/urandom","major":1,"minor":9,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/random","major":1,"minor":8,"permissions":"rwm","file_mode":438,"uid":0,"gid":0}],"mount_label":"","hostname":"1","namespaces":[{"type":"NEWNS","path":""},{"type":"NEWUTS","path":""},{"type":"NEWIPC","path":""},{"type":"NEWPID","path":""},{"type":"NEWNET","path":"/var/run/docker/netns/e05ddb1777f3"}],"capabilities":["CHOWN","DAC_OVERRIDE","FSETID","FOWNER","MKNOD","NET_RAW","SETGID","SETUID","SETFCAP","SETPCAP","NET_BIND_SERVICE","SYS_CHROOT","KILL","AUDIT_WRITE"],"networks":null,"routes":null,"cgroups":{"name":"1","parent":"docker","allow_all_devices":false,"allowed_devices":[{"type":99,"path":"","major":-1,"minor":-1,"permissions":"m","file_mode":0,"uid":0,"gid":0},{"type":98,"path":"","major":-1,"minor":-1,"permissions":"m","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"/dev/console","major":5,"minor":1,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"/dev/tty0","major":4,"minor":0,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"/dev/tty1","major":4,"minor":1,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"","major":136,"minor":-1,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"","major":5,"minor":2,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"","major":10,"minor":200,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"/dev/null","major":1,"minor":3,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/zero","major":1,"minor":5,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/full","major":1,"minor":7,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/tty","major":5,"minor":0,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/urandom","major":1,"minor":9,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/random","major":1,"minor":8,"permissions":"rwm","file_mode":438,"uid":0,"gid":0}],"denied_devices":null,"memory":0,"memory_reservation":0,"memory_swap":0,"kernel_memory":0,"cpu_shares":0,"cpuset_cpus":"","cpuset_mems":"","blkio_throttle_read_bps_device":"","blkio_throttle_write_bps_device":"","blkio_throttle_read_iops_device":"","blkio_throttle_write_iops_device":"","blkio_weight":0,"blkio_weight_device":"","freezer":"","hugetlb_limit":null,"slice":"","oom_kill_disable":false,"memory_swappiness":-1,"net_prio_ifpriomap":null,"net_cls_classid":""},"apparmor_profile":"docker-default","process_label":"","rlimits":null,"additional_groups":null,"uid_mappings":null,"gid_mappings":null,"mask_paths":["/proc/kcore","/proc/latency_stats","/proc/timer_stats"],"readonly_paths":["/proc/asound","/proc/bus","/proc/fs","/proc/irq","/proc/sys","/proc/sysrq-trigger"],"sysctl":null,"seccomp":null},"external_descriptors":["/dev/null","/dev/null","/dev/null"]} ================================================ FILE: container/libcontainer/testdata/docker-v1.9.1/execdriver/native/1/state.json ================================================ {"id":"1","init_process_pid":64076,"init_process_start":"3211353","cgroup_paths":{"blkio":"/sys/fs/cgroup/blkio/docker/1","cpu":"/sys/fs/cgroup/cpu/docker/1","cpuacct":"/sys/fs/cgroup/cpuacct/docker/1","cpuset":"/sys/fs/cgroup/cpuset/docker/1","devices":"/sys/fs/cgroup/devices/docker/1","freezer":"/sys/fs/cgroup/freezer/docker/1","hugetlb":"/sys/fs/cgroup/hugetlb/docker/1","memory":"/sys/fs/cgroup/memory/docker/1","net_cls":"/sys/fs/cgroup/net_cls/docker/1","net_prio":"/sys/fs/cgroup/net_prio/docker/1","perf_event":"/sys/fs/cgroup/perf_event/docker/1"},"namespace_paths":{"NEWIPC":"/proc/64076/ns/ipc","NEWNET":"/proc/64076/ns/net","NEWNS":"/proc/64076/ns/mnt","NEWPID":"/proc/64076/ns/pid","NEWUSER":"/proc/64076/ns/user","NEWUTS":"/proc/64076/ns/uts"},"config":{"no_pivot_root":false,"parent_death_signal":0,"pivot_dir":"","rootfs":"/var/lib/docker/devicemapper/mnt/1/rootfs","readonlyfs":false,"rootPropagation":278528,"mounts":[{"source":"proc","destination":"/proc","device":"proc","flags":14,"propagation_flags":null,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"tmpfs","destination":"/dev","device":"tmpfs","flags":16777218,"propagation_flags":null,"data":"mode=755","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"devpts","destination":"/dev/pts","device":"devpts","flags":10,"propagation_flags":null,"data":"newinstance,ptmxmode=0666,mode=0620,gid=5","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"sysfs","destination":"/sys","device":"sysfs","flags":15,"propagation_flags":null,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"cgroup","destination":"/sys/fs/cgroup","device":"cgroup","flags":15,"propagation_flags":null,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"/var/lib/docker/containers/1/resolv.conf","destination":"/etc/resolv.conf","device":"bind","flags":20480,"propagation_flags":null,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"/var/lib/docker/containers/1/hostname","destination":"/etc/hostname","device":"bind","flags":20480,"propagation_flags":null,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"/var/lib/docker/containers/1/hosts","destination":"/etc/hosts","device":"bind","flags":20480,"propagation_flags":null,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"/var/lib/docker/containers/1/shm","destination":"/dev/shm","device":"bind","flags":20480,"propagation_flags":null,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null},{"source":"/var/lib/docker/containers/1/mqueue","destination":"/dev/mqueue","device":"bind","flags":20480,"propagation_flags":null,"data":"","relabel":"","premount_cmds":null,"postmount_cmds":null}],"devices":[{"type":99,"path":"/dev/fuse","major":10,"minor":229,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"/dev/null","major":1,"minor":3,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/zero","major":1,"minor":5,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/full","major":1,"minor":7,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/tty","major":5,"minor":0,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/urandom","major":1,"minor":9,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/random","major":1,"minor":8,"permissions":"rwm","file_mode":438,"uid":0,"gid":0}],"mount_label":"","hostname":"1","namespaces":[{"type":"NEWNS","path":""},{"type":"NEWUTS","path":""},{"type":"NEWIPC","path":""},{"type":"NEWPID","path":""},{"type":"NEWNET","path":""}],"capabilities":["CAP_CHOWN","CAP_DAC_OVERRIDE","CAP_FSETID","CAP_FOWNER","CAP_MKNOD","CAP_NET_RAW","CAP_SETGID","CAP_SETUID","CAP_SETFCAP","CAP_SETPCAP","CAP_NET_BIND_SERVICE","CAP_SYS_CHROOT","CAP_KILL","CAP_AUDIT_WRITE"],"networks":null,"routes":null,"cgroups":{"name":"1","parent":"docker","allow_all_devices":false,"allowed_devices":[{"type":99,"path":"","major":-1,"minor":-1,"permissions":"m","file_mode":0,"uid":0,"gid":0},{"type":98,"path":"","major":-1,"minor":-1,"permissions":"m","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"/dev/console","major":5,"minor":1,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"/dev/tty0","major":4,"minor":0,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"/dev/tty1","major":4,"minor":1,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"","major":136,"minor":-1,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"","major":5,"minor":2,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"","major":10,"minor":200,"permissions":"rwm","file_mode":0,"uid":0,"gid":0},{"type":99,"path":"/dev/null","major":1,"minor":3,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/zero","major":1,"minor":5,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/full","major":1,"minor":7,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/tty","major":5,"minor":0,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/urandom","major":1,"minor":9,"permissions":"rwm","file_mode":438,"uid":0,"gid":0},{"type":99,"path":"/dev/random","major":1,"minor":8,"permissions":"rwm","file_mode":438,"uid":0,"gid":0}],"denied_devices":null,"memory":0,"memory_reservation":0,"memory_swap":0,"kernel_memory":0,"cpu_shares":0,"cpuset_cpus":"","cpuset_mems":"","blkio_weight":0,"blkio_leaf_weight":0,"blkio_weight_device":null,"blkio_throttle_read_bps_device":null,"blkio_throttle_write_bps_device":null,"blkio_throttle_read_iops_device":null,"blkio_throttle_write_iops_device":null,"freezer":"","hugetlb_limit":null,"slice":"","oom_kill_disable":false,"memory_swappiness":-1,"net_prio_ifpriomap":null,"net_cls_classid":""},"apparmor_profile":"docker-default","process_label":"","rlimits":null,"oom_score_adj":0,"additional_groups":null,"uid_mappings":null,"gid_mappings":null,"mask_paths":["/proc/kcore","/proc/latency_stats","/proc/timer_stats"],"readonly_paths":["/proc/asound","/proc/bus","/proc/fs","/proc/irq","/proc/sys","/proc/sysrq-trigger"],"sysctl":null,"seccomp":null,"version":""},"external_descriptors":["/dev/null","/dev/null","/dev/null"]} ================================================ FILE: container/libcontainer/testdata/limits ================================================ Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size unlimited unlimited bytes Max resident set unlimited unlimited bytes Max processes 119958 119958 processes Max open files 1073741816 1073741816 files Max locked memory 3932852224 3932852224 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 119958 119958 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us ================================================ FILE: container/libcontainer/testdata/procnetdev ================================================ Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed wlp4s0: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 docker0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 em1: 315849 1172 0 0 0 0 0 0 315850 1173 0 0 0 0 0 0 ================================================ FILE: container/libcontainer/testdata/procnetudp ================================================ sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops 1: 00000000:07D3 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 16583 2 ffff8800b4549400 0 21: 00000000:A841 00000000:0000 07 0000000A:0000000B 00:00000000 00000000 1000 0 114299623 2 ffff880338477800 4 ================================================ FILE: container/libcontainer/testdata/smaps4 ================================================ 55f523c9f000-55f523cc1000 r-xp 00000000 08:02 5505067 /sbin/cgmanager Size: 136 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Rss: 132 kB Pss: 132 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 132 kB Private_Dirty: 0 kB Referenced: 132 kB Anonymous: 0 kB LazyFree: 0 kB AnonHugePages: 0 kB ShmemPmdMapped: 0 kB Shared_Hugetlb: 0 kB Private_Hugetlb: 0 kB Swap: 0 kB SwapPss: 0 kB Locked: 0 kB VmFlags: rd ex mr mw me dw sd 55f523ec0000-55f523ec2000 r--p 00021000 08:02 5505067 /sbin/cgmanager Size: 8 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Rss: 8 kB Pss: 8 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 8 kB Referenced: 4 kB Anonymous: 8 kB LazyFree: 0 kB AnonHugePages: 0 kB ShmemPmdMapped: 0 kB Shared_Hugetlb: 0 kB Private_Hugetlb: 0 kB Swap: 0 kB SwapPss: 0 kB Locked: 0 kB VmFlags: rd mr mw me dw ac sd 55f523ec2000-55f523ec3000 rw-p 00023000 08:02 5505067 /sbin/cgmanager Size: 4 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Rss: 4 kB Pss: 4 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 4 kB Referenced: 0 kB Anonymous: 4 kB LazyFree: 0 kB AnonHugePages: 0 kB ShmemPmdMapped: 0 kB Shared_Hugetlb: 0 kB Private_Hugetlb: 0 kB Swap: 0 kB SwapPss: 0 kB Locked: 0 kB VmFlags: rd wr mr mw me dw ac sd 55f52478d000-55f5247ae000 rw-p 00000000 00:00 0 [heap] Size: 132 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Rss: 16 kB Pss: 16 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 16 kB Referenced: 16 kB Anonymous: 16 kB LazyFree: 0 kB AnonHugePages: 0 kB ShmemPmdMapped: 0 kB Shared_Hugetlb: 0 kB Private_Hugetlb: 0 kB Swap: 0 kB SwapPss: 0 kB Locked: 0 kB VmFlags: rd wr mr mw me ac sd ================================================ FILE: container/libcontainer/testdata/smaps6 ================================================ 55f523c9f000-55f523cc1000 r-xp 00000000 08:02 5505067 /sbin/cgmanager Size: 136 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Rss: 132 kB Pss: 132 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 132 kB Private_Dirty: 0 kB Referenced: 132 kB Anonymous: 0 kB LazyFree: 0 kB AnonHugePages: 0 kB ShmemPmdMapped: 0 kB Shared_Hugetlb: 0 kB Private_Hugetlb: 0 kB Swap: 0 kB SwapPss: 0 kB Locked: 0 kB VmFlags: rd ex mr mw me dw sd ================================================ FILE: container/libcontainer/testdata/smaps8 ================================================ 55f523c9f000-55f523cc1000 r-xp 00000000 08:02 5505067 /sbin/cgmanager Size: 136 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Rss: 132 kB Pss: 132 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 132 kB Private_Dirty: 0 kB Referenced: 132 kB Anonymous: 0 kB LazyFree: 0 kB AnonHugePages: 0 kB ShmemPmdMapped: 0 kB Shared_Hugetlb: 0 kB Private_Hugetlb: 0 kB Swap: 0 kB SwapPss: 0 kB Locked: 0 kB VmFlags: rd ex mr mw me dw sd ================================================ FILE: container/podman/client.go ================================================ // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package podman import ( "context" "fmt" "net" "net/http" urllib "net/url" ) type clientKey struct{} func (c clientKey) String() string { return "client" } type Connection struct { URI *urllib.URL Client *http.Client } func client(ctx *context.Context) (*Connection, error) { url, err := urllib.Parse(*endpointFlag) if err != nil { return nil, err } switch url.Scheme { case "unix": connection := Connection{URI: url} connection.Client = &http.Client{ Transport: &http.Transport{ DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { return (&net.Dialer{}).DialContext(ctx, "unix", url.Path) }, DisableCompression: true, }, } *ctx = context.WithValue(*ctx, clientKey{}, &connection) return &connection, nil } return nil, fmt.Errorf("couldn't get podman client") } ================================================ FILE: container/podman/factory.go ================================================ // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package podman import ( "flag" "fmt" "path" "sync" "time" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/docker" dockerutil "github.com/google/cadvisor/container/docker/utils" "github.com/google/cadvisor/devicemapper" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/zfs" ) const ( rootDirRetries = 5 rootDirRetryPeriod = time.Second containerBaseName = "container" ) var ( endpointFlag = flag.String("podman", "unix:///var/run/podman/podman.sock", "podman endpoint") ) var ( rootDir string rootDirOnce sync.Once ) func RootDir() string { rootDirOnce.Do(func() { for i := 0; i < rootDirRetries; i++ { status, err := Status() if err == nil && status.RootDir != "" { rootDir = status.RootDir break } else { time.Sleep(rootDirRetryPeriod) } } }) return rootDir } type podmanFactory struct { // Information about the mounted cgroup subsystems. machineInfoFactory info.MachineInfoFactory storageDriver docker.StorageDriver storageDir string cgroupSubsystem map[string]string fsInfo fs.FsInfo metrics container.MetricSet thinPoolName string thinPoolWatcher *devicemapper.ThinPoolWatcher zfsWatcher *zfs.ZfsWatcher } func (f *podmanFactory) CanHandleAndAccept(name string) (handle bool, accept bool, err error) { // Rootless if path.Base(name) == containerBaseName { name, _ = path.Split(name) } if !dockerutil.IsContainerName(name) { return false, false, nil } id := dockerutil.ContainerNameToId(name) ctnr, err := InspectContainer(id) if err != nil { return false, true, fmt.Errorf("error inspecting container: %v", err) } if ctnr.State == nil || !ctnr.State.Running { return false, true, fmt.Errorf("container not running") } return true, true, nil } func (f *podmanFactory) DebugInfo() map[string][]string { return map[string][]string{} } func (f *podmanFactory) String() string { return "podman" } func (f *podmanFactory) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (handler container.ContainerHandler, err error) { return newContainerHandler(name, f.machineInfoFactory, f.fsInfo, f.storageDriver, f.storageDir, f.cgroupSubsystem, inHostNamespace, metadataEnvAllowList, f.metrics, f.thinPoolName, f.thinPoolWatcher, f.zfsWatcher) } ================================================ FILE: container/podman/fs.go ================================================ // Copyright 2022 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package podman import ( "encoding/json" "fmt" "os" "path/filepath" "github.com/google/cadvisor/container/docker" ) var containersJsonFilnames = []string{ "containers.json", "volatile-containers.json", } type containersJSON struct { ID string `json:"id"` Layer string `json:"layer"` // rest in unnecessary } func rwLayerID(storageDriver docker.StorageDriver, storageDir string, containerID string) (string, error) { var containers []containersJSON fileExists := false for _, filename := range containersJsonFilnames { data, err := os.ReadFile(filepath.Join(storageDir, string(storageDriver)+"-containers", filename)) if err != nil && !os.IsNotExist(err) { return "", err } if data != nil { fileExists = true var buffer []containersJSON err = json.Unmarshal(data, &buffer) if err != nil { return "", err } containers = append(containers, buffer...) } } if !fileExists { return "", os.ErrNotExist } for _, c := range containers { if c.ID == containerID { return c.Layer, nil } } return "", fmt.Errorf("unable to determine %v rw layer id", containerID) } ================================================ FILE: container/podman/handler.go ================================================ // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Package podman implements a handler for Podman containers. package podman import ( "fmt" "path" "path/filepath" "strconv" "strings" "time" dockercontainer "github.com/moby/moby/api/types/container" "github.com/opencontainers/cgroups" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/common" "github.com/google/cadvisor/container/docker" dockerutil "github.com/google/cadvisor/container/docker/utils" containerlibcontainer "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/devicemapper" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/zfs" ) type containerHandler struct { // machineInfoFactory provides info.MachineInfo machineInfoFactory info.MachineInfoFactory // Absolute path to the cgroup hierarchies of this container. // (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test") cgroupPaths map[string]string // the docker storage driver storageDriver docker.StorageDriver fsInfo fs.FsInfo rootfsStorageDir string // Time at which this container was created. creationTime time.Time // Time at which this container was started. startTime time.Time // Metadata associated with the container. envs map[string]string labels map[string]string // Image name used for this container. image string networkMode dockercontainer.NetworkMode // Filesystem handler. fsHandler common.FsHandler // The IP address of the container ipAddress string metrics container.MetricSet // the devicemapper poolname thinPoolName string // zfsParent is the parent for docker zfs zfsParent string // Reference to the container reference info.ContainerReference libcontainerHandler *containerlibcontainer.Handler } func newContainerHandler( name string, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, storageDriver docker.StorageDriver, storageDir string, cgroupSubsystems map[string]string, inHostNamespace bool, metadataEnvAllowList []string, metrics container.MetricSet, thinPoolName string, thinPoolWatcher *devicemapper.ThinPoolWatcher, zfsWatcher *zfs.ZfsWatcher, ) (container.ContainerHandler, error) { // Create the cgroup paths. cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems, name) // Generate the equivalent cgroup manager for this container. cgroupManager, err := containerlibcontainer.NewCgroupManager(name, cgroupPaths) if err != nil { return nil, err } rootFs := "/" if !inHostNamespace { rootFs = "/rootfs" storageDir = path.Join(rootFs, storageDir) } rootless := path.Base(name) == containerBaseName if rootless { name, _ = path.Split(name) } id := dockerutil.ContainerNameToId(name) // We assume that if Inspect fails then the container is not known to Podman. ctnr, err := InspectContainer(id) if err != nil { return nil, err } // Obtain the IP address for the container. var ipAddress string if ctnr.NetworkSettings != nil && ctnr.HostConfig != nil { c := ctnr if ctnr.HostConfig.NetworkMode.IsContainer() { // If the NetworkMode starts with 'container:' then we need to use the IP address of the container specified. // This happens in cases such as kubernetes where the containers doesn't have an IP address itself and we need to use the pod's address containerID := ctnr.HostConfig.NetworkMode.ConnectedContainer() c, err = InspectContainer(containerID) if err != nil { return nil, fmt.Errorf("failed to inspect container %q: %v", containerID, err) } } if nw, ok := c.NetworkSettings.Networks[c.HostConfig.NetworkMode.NetworkName()]; ok { if nw.IPAddress.IsValid() { ipAddress = nw.IPAddress.String() } } } layerID, err := rwLayerID(storageDriver, storageDir, id) if err != nil { return nil, err } // Determine the rootfs storage dir OR the pool name to determine the device. // For devicemapper, we only need the thin pool name, and that is passed in to this call rootfsStorageDir, zfsFilesystem, zfsParent, err := determineDeviceStorage(storageDriver, storageDir, layerID) if err != nil { return nil, err } otherStorageDir := filepath.Join(storageDir, string(storageDriver)+"-containers", id) handler := &containerHandler{ machineInfoFactory: machineInfoFactory, cgroupPaths: cgroupPaths, storageDriver: storageDriver, fsInfo: fsInfo, rootfsStorageDir: rootfsStorageDir, ipAddress: ipAddress, envs: make(map[string]string), labels: ctnr.Config.Labels, image: ctnr.Config.Image, networkMode: ctnr.HostConfig.NetworkMode, fsHandler: common.NewFsHandler(common.DefaultPeriod, rootfsStorageDir, otherStorageDir, fsInfo), metrics: metrics, thinPoolName: thinPoolName, zfsParent: zfsParent, reference: info.ContainerReference{ // Add the name and bare ID as aliases of the container. Id: id, Name: name, Aliases: []string{strings.TrimPrefix(ctnr.Name, "/"), id}, Namespace: Namespace, }, libcontainerHandler: containerlibcontainer.NewHandler(cgroupManager, rootFs, ctnr.State.Pid, metrics), } handler.creationTime, err = time.Parse(time.RFC3339, ctnr.Created) if err != nil { return nil, fmt.Errorf("failed to parse the create timestamp %q for container %q: %v", ctnr.Created, id, err) } // StartedAt may be unset for containers that never started. if startedAt := ctnr.State.StartedAt; startedAt != "" { if t, err := time.Parse(time.RFC3339Nano, startedAt); err == nil && !t.Before(time.Unix(0, 0)) { handler.startTime = t } else if t, err := time.Parse(time.RFC3339, startedAt); err == nil && !t.Before(time.Unix(0, 0)) { handler.startTime = t } } if ctnr.RestartCount > 0 { handler.labels["restartcount"] = strconv.Itoa(ctnr.RestartCount) } if metrics.Has(container.DiskUsageMetrics) { handler.fsHandler = &docker.FsHandler{ FsHandler: common.NewFsHandler(common.DefaultPeriod, rootfsStorageDir, otherStorageDir, fsInfo), ThinPoolWatcher: thinPoolWatcher, ZfsWatcher: zfsWatcher, DeviceID: ctnr.GraphDriver.Data["DeviceId"], ZfsFilesystem: zfsFilesystem, } } // Split env vars to get metadata map. for _, exposedEnv := range metadataEnvAllowList { if exposedEnv == "" { continue } for _, envVar := range ctnr.Config.Env { if envVar != "" { splits := strings.SplitN(envVar, "=", 2) if len(splits) == 2 && strings.HasPrefix(splits[0], exposedEnv) { handler.envs[strings.ToLower(splits[0])] = splits[1] } } } } return handler, nil } func determineDeviceStorage(storageDriver docker.StorageDriver, storageDir string, rwLayerID string) ( rootfsStorageDir string, zfsFilesystem string, zfsParent string, err error) { switch storageDriver { // Podman aliased the driver names together. case docker.OverlayStorageDriver, docker.Overlay2StorageDriver: rootfsStorageDir = path.Join(storageDir, "overlay", rwLayerID, "diff") return default: return docker.DetermineDeviceStorage(storageDriver, storageDir, rwLayerID) } } func (h *containerHandler) ContainerReference() (info.ContainerReference, error) { return h.reference, nil } func (h *containerHandler) needNet() bool { if h.metrics.Has(container.NetworkUsageMetrics) { h.networkMode.IsContainer() return !h.networkMode.IsContainer() } return false } func (h *containerHandler) GetSpec() (info.ContainerSpec, error) { hasFilesystem := h.metrics.Has(container.DiskUsageMetrics) spec, err := common.GetSpec(h.cgroupPaths, h.machineInfoFactory, h.needNet(), hasFilesystem) if err != nil { return info.ContainerSpec{}, err } spec.Labels = h.labels spec.Envs = h.envs spec.Image = h.image spec.CreationTime = h.creationTime spec.StartTime = h.startTime return spec, nil } func (h *containerHandler) GetStats() (*info.ContainerStats, error) { stats, err := h.libcontainerHandler.GetStats() if err != nil { return stats, err } if !h.needNet() { stats.Network = info.NetworkStats{} } // Get filesystem stats. err = docker.FsStats(stats, h.machineInfoFactory, h.metrics, h.storageDriver, h.fsHandler, h.fsInfo, h.thinPoolName, h.rootfsStorageDir, h.zfsParent) if err != nil { return stats, err } return stats, nil } func (h *containerHandler) ListContainers(container.ListType) ([]info.ContainerReference, error) { return []info.ContainerReference{}, nil } func (h *containerHandler) ListProcesses(container.ListType) ([]int, error) { return h.libcontainerHandler.GetProcesses() } func (h *containerHandler) GetCgroupPath(resource string) (string, error) { var res string if !cgroups.IsCgroup2UnifiedMode() { res = resource } cgroupPath, ok := h.cgroupPaths[res] if !ok { return "", fmt.Errorf("could not find path for resource %q for container %q", resource, h.reference.Name) } return cgroupPath, nil } func (h *containerHandler) GetContainerLabels() map[string]string { return h.labels } func (h *containerHandler) GetContainerIPAddress() string { return h.ipAddress } func (h *containerHandler) Exists() bool { return common.CgroupExists(h.cgroupPaths) } func (h *containerHandler) Cleanup() { if h.fsHandler != nil { h.fsHandler.Stop() } } func (h *containerHandler) Start() { if h.fsHandler != nil { h.fsHandler.Start() } } func (h *containerHandler) Type() container.ContainerType { return container.ContainerTypePodman } func (h *containerHandler) GetExitCode() (int, error) { ctnr, err := InspectContainer(h.reference.Id) if err != nil { return -1, fmt.Errorf("failed to inspect container %s: %w", h.reference.Id, err) } if ctnr.State == nil { return -1, fmt.Errorf("container state not available for %s", h.reference.Id) } if ctnr.State.Running { return -1, fmt.Errorf("container %s is still running", h.reference.Id) } return ctnr.State.ExitCode, nil } ================================================ FILE: container/podman/install/install.go ================================================ // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package install import ( "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/podman" ) func init() { err := container.RegisterPlugin("podman", podman.NewPlugin()) if err != nil { klog.Fatalf("Failed to register podman plugin: %v", err) } } ================================================ FILE: container/podman/plugin.go ================================================ // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package podman import ( "fmt" "github.com/opencontainers/cgroups" "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/docker" dockerutil "github.com/google/cadvisor/container/docker/utils" "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/devicemapper" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/watcher" "github.com/google/cadvisor/zfs" ) func NewPlugin() container.Plugin { return &plugin{} } type plugin struct{} func (p *plugin) InitializeFSContext(context *fs.Context) error { context.Podman = fs.PodmanContext{ Root: "", Driver: "", DriverStatus: map[string]string{}, } return nil } func (p *plugin) Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) (watcher.ContainerWatcher, error) { return Register(factory, fsInfo, includedMetrics) } func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, metrics container.MetricSet) (watcher.ContainerWatcher, error) { cgroupSubsystem, err := libcontainer.GetCgroupSubsystems(metrics) if err != nil { return nil, fmt.Errorf("failed to get cgroup subsystems: %v", err) } validatedInfo, err := docker.ValidateInfo(GetInfo, VersionString) if err != nil { return nil, fmt.Errorf("failed to validate Podman info: %v", err) } var ( thinPoolName string thinPoolWatcher *devicemapper.ThinPoolWatcher zfsWatcher *zfs.ZfsWatcher ) if metrics.Has(container.DiskUsageMetrics) { switch docker.StorageDriver(validatedInfo.Driver) { case docker.DevicemapperStorageDriver: thinPoolWatcher, err = docker.StartThinPoolWatcher(validatedInfo) if err != nil { klog.Errorf("devicemapper filesystem stats will not be reported: %v", err) } status, _ := docker.StatusFromDockerInfo(*validatedInfo) thinPoolName = status.DriverStatus[dockerutil.DriverStatusPoolName] case docker.ZfsStorageDriver: zfsWatcher, err = docker.StartZfsWatcher(validatedInfo) if err != nil { klog.Errorf("zfs filesystem stats will not be reported: %v", err) } } } // Register Podman container handler factory. klog.V(1).Info("Registering Podman factory") f := &podmanFactory{ machineInfoFactory: factory, storageDriver: docker.StorageDriver(validatedInfo.Driver), storageDir: RootDir(), cgroupSubsystem: cgroupSubsystem, fsInfo: fsInfo, metrics: metrics, thinPoolName: thinPoolName, thinPoolWatcher: thinPoolWatcher, zfsWatcher: zfsWatcher, } container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw}) if !cgroups.IsCgroup2UnifiedMode() { klog.Warning("Podman rootless containers not working with cgroups v1!") } return nil, nil } ================================================ FILE: container/podman/podman.go ================================================ // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package podman import ( "context" "encoding/json" "fmt" "io" "net/http" "time" dockercontainer "github.com/moby/moby/api/types/container" dockerimage "github.com/moby/moby/api/types/image" dockersystem "github.com/moby/moby/api/types/system" "github.com/google/cadvisor/container/docker" "github.com/google/cadvisor/container/docker/utils" v1 "github.com/google/cadvisor/info/v1" ) const ( Namespace = "podman" ) var timeout = 10 * time.Second func validateResponse(gotError error, response *http.Response) error { var err error switch { case response == nil: err = fmt.Errorf("response not present") case response.StatusCode == http.StatusNotFound: err = fmt.Errorf("item not found") case response.StatusCode == http.StatusNotImplemented: err = fmt.Errorf("query not implemented") default: return gotError } if gotError != nil { err = fmt.Errorf("%s: %w", err.Error(), gotError) } return err } func apiGetRequest(url string, item interface{}) error { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() conn, err := client(&ctx) if err != nil { return err } req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return err } resp, err := conn.Client.Do(req) err = validateResponse(err, resp) if err != nil { return err } defer resp.Body.Close() data, err := io.ReadAll(resp.Body) if err != nil { return err } err = json.Unmarshal(data, item) if err != nil { return err } return ctx.Err() } func Images() ([]v1.DockerImage, error) { var summaries []dockerimage.Summary err := apiGetRequest("http://d/v1.0.0/images/json", &summaries) if err != nil { return nil, err } return utils.SummariesToImages(summaries) } func Status() (v1.DockerStatus, error) { podmanInfo, err := GetInfo() if err != nil { return v1.DockerStatus{}, err } status, err := docker.StatusFromDockerInfo(*podmanInfo) if err != nil { return v1.DockerStatus{}, err } podmanVersion, err := VersionString() if err != nil { // status.Version will be "Unknown" return status, err } status.Version = podmanVersion podmanAPIVersion, err := APIVersionString() if err != nil { // status.APIVersion will be "Unknown" return status, err } status.APIVersion = podmanAPIVersion return status, nil } func GetInfo() (*dockersystem.Info, error) { var info dockersystem.Info err := apiGetRequest("http://d/v1.0.0/info", &info) return &info, err } func VersionString() (string, error) { var version dockersystem.VersionResponse err := apiGetRequest("http://d/v1.0.0/version", &version) if err != nil { return "Unknown", err } return version.Version, nil } func APIVersionString() (string, error) { var version dockersystem.VersionResponse err := apiGetRequest("http://d/v1.0.0/version", &version) if err != nil { return "Unknown", err } return version.APIVersion, nil } func InspectContainer(id string) (dockercontainer.InspectResponse, error) { var data dockercontainer.InspectResponse err := apiGetRequest(fmt.Sprintf("http://d/v1.0.0/containers/%s/json", id), &data) return data, err } ================================================ FILE: container/podman/podman_test.go ================================================ // Copyright 2022 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package podman import ( "errors" "net/http" "testing" "github.com/stretchr/testify/assert" ) func TestValidateResponse(t *testing.T) { for _, tc := range []struct { response *http.Response err error expected string }{ { response: nil, err: nil, expected: "response not present", }, { response: &http.Response{ StatusCode: http.StatusNotFound, }, err: errors.New("some error"), expected: "item not found: some error", }, { response: &http.Response{ StatusCode: http.StatusNotImplemented, }, err: errors.New("some error"), expected: "query not implemented: some error", }, { response: &http.Response{ StatusCode: http.StatusOK, }, err: errors.New("some error"), expected: "some error", }, { response: &http.Response{ StatusCode: http.StatusOK, }, err: nil, expected: "", }, } { err := validateResponse(tc.err, tc.response) if tc.expected != "" { assert.EqualError(t, err, tc.expected) } else { assert.NoError(t, err) } } } ================================================ FILE: container/raw/factory.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package raw import ( "flag" "fmt" "strings" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/common" "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" watch "github.com/google/cadvisor/watcher" "k8s.io/klog/v2" ) var ( DockerOnly = flag.Bool("docker_only", false, "Only report docker containers in addition to root stats") disableRootCgroupStats = flag.Bool("disable_root_cgroup_stats", false, "Disable collecting root Cgroup stats") ) type rawFactory struct { // Factory for machine information. machineInfoFactory info.MachineInfoFactory // Information about the cgroup subsystems. cgroupSubsystems map[string]string // Information about mounted filesystems. fsInfo fs.FsInfo // Watcher for inotify events. watcher *common.InotifyWatcher // List of metrics to be included. includedMetrics map[container.MetricKind]struct{} // List of raw container cgroup path prefix whitelist. rawPrefixWhiteList []string } func (f *rawFactory) String() string { return "raw" } func (f *rawFactory) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (container.ContainerHandler, error) { rootFs := "/" if !inHostNamespace { rootFs = "/rootfs" } return newRawContainerHandler(name, f.cgroupSubsystems, f.machineInfoFactory, f.fsInfo, f.watcher, rootFs, f.includedMetrics) } // The raw factory can handle any container. If --docker_only is set to true, non-docker containers are ignored except for "/" and those whitelisted by raw_cgroup_prefix_whitelist flag. func (f *rawFactory) CanHandleAndAccept(name string) (bool, bool, error) { if name == "/" { return true, true, nil } if *DockerOnly && f.rawPrefixWhiteList[0] == "" { return true, false, nil } for _, prefix := range f.rawPrefixWhiteList { if strings.HasPrefix(name, prefix) { return true, true, nil } } return true, false, nil } func (f *rawFactory) DebugInfo() map[string][]string { return common.DebugInfo(f.watcher.GetWatches()) } func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics map[container.MetricKind]struct{}, rawPrefixWhiteList []string) error { cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics) if err != nil { return fmt.Errorf("failed to get cgroup subsystems: %v", err) } if len(cgroupSubsystems) == 0 { return fmt.Errorf("failed to find supported cgroup mounts for the raw factory") } watcher, err := common.NewInotifyWatcher() if err != nil { return err } klog.V(1).Infof("Registering Raw factory") factory := &rawFactory{ machineInfoFactory: machineInfoFactory, fsInfo: fsInfo, cgroupSubsystems: cgroupSubsystems, watcher: watcher, includedMetrics: includedMetrics, rawPrefixWhiteList: rawPrefixWhiteList, } container.RegisterContainerHandlerFactory(factory, []watch.ContainerWatchSource{watch.Raw}) return nil } ================================================ FILE: container/raw/handler.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Handler for "raw" containers. package raw import ( "fmt" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/common" "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/machine" "github.com/opencontainers/cgroups" "k8s.io/klog/v2" ) type rawContainerHandler struct { // Name of the container for this handler. name string machineInfoFactory info.MachineInfoFactory // Absolute path to the cgroup hierarchies of this container. // (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test") cgroupPaths map[string]string fsInfo fs.FsInfo externalMounts []common.Mount includedMetrics container.MetricSet libcontainerHandler *libcontainer.Handler } func isRootCgroup(name string) bool { return name == "/" } func newRawContainerHandler(name string, cgroupSubsystems map[string]string, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, watcher *common.InotifyWatcher, rootFs string, includedMetrics container.MetricSet) (container.ContainerHandler, error) { cHints, err := common.GetContainerHintsFromFile(*common.ArgContainerHints) if err != nil { return nil, err } cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems, name) cgroupManager, err := libcontainer.NewCgroupManager(name, cgroupPaths) if err != nil { return nil, err } var externalMounts []common.Mount for _, container := range cHints.AllHosts { if name == container.FullName { externalMounts = container.Mounts break } } pid := 0 if isRootCgroup(name) { pid = 1 // delete pids from cgroup paths because /sys/fs/cgroup/pids/pids.current not exist delete(cgroupPaths, "pids") } handler := libcontainer.NewHandler(cgroupManager, rootFs, pid, includedMetrics) return &rawContainerHandler{ name: name, machineInfoFactory: machineInfoFactory, cgroupPaths: cgroupPaths, fsInfo: fsInfo, externalMounts: externalMounts, includedMetrics: includedMetrics, libcontainerHandler: handler, }, nil } func (h *rawContainerHandler) ContainerReference() (info.ContainerReference, error) { // We only know the container by its one name. return info.ContainerReference{ Name: h.name, }, nil } func (h *rawContainerHandler) GetRootNetworkDevices() ([]info.NetInfo, error) { nd := []info.NetInfo{} if isRootCgroup(h.name) { mi, err := h.machineInfoFactory.GetMachineInfo() if err != nil { return nd, err } return mi.NetworkDevices, nil } return nd, nil } // Nothing to start up. func (h *rawContainerHandler) Start() {} // Nothing to clean up. func (h *rawContainerHandler) Cleanup() {} func (h *rawContainerHandler) GetSpec() (info.ContainerSpec, error) { const hasNetwork = false hasFilesystem := isRootCgroup(h.name) || len(h.externalMounts) > 0 spec, err := common.GetSpec(h.cgroupPaths, h.machineInfoFactory, hasNetwork, hasFilesystem) if err != nil { return spec, err } if isRootCgroup(h.name) { // Check physical network devices for root container. nd, err := h.GetRootNetworkDevices() if err != nil { return spec, err } spec.HasNetwork = spec.HasNetwork || len(nd) != 0 // Get memory and swap limits of the running machine memLimit, err := machine.GetMachineMemoryCapacity() if err != nil { klog.Warningf("failed to obtain memory limit for machine container") spec.HasMemory = false } else { spec.Memory.Limit = uint64(memLimit) // Spec is marked to have memory only if the memory limit is set spec.HasMemory = true } swapLimit, err := machine.GetMachineSwapCapacity() if err != nil { klog.Warningf("failed to obtain swap limit for machine container") } else { spec.Memory.SwapLimit = uint64(swapLimit) } } return spec, nil } func fsToFsStats(fs *fs.Fs) info.FsStats { inodes := uint64(0) inodesFree := uint64(0) hasInodes := fs.InodesFree != nil if hasInodes { inodes = *fs.Inodes inodesFree = *fs.InodesFree } return info.FsStats{ Device: fs.Device, Type: fs.Type.String(), Limit: fs.Capacity, Usage: fs.Capacity - fs.Free, HasInodes: hasInodes, Inodes: inodes, InodesFree: inodesFree, Available: fs.Available, ReadsCompleted: fs.DiskStats.ReadsCompleted, ReadsMerged: fs.DiskStats.ReadsMerged, SectorsRead: fs.DiskStats.SectorsRead, ReadTime: fs.DiskStats.ReadTime, WritesCompleted: fs.DiskStats.WritesCompleted, WritesMerged: fs.DiskStats.WritesMerged, SectorsWritten: fs.DiskStats.SectorsWritten, WriteTime: fs.DiskStats.WriteTime, IoInProgress: fs.DiskStats.IoInProgress, IoTime: fs.DiskStats.IoTime, WeightedIoTime: fs.DiskStats.WeightedIoTime, } } func (h *rawContainerHandler) getFsStats(stats *info.ContainerStats) error { var filesystems []fs.Fs var err error // Early exist if no disk metrics are to be collected. if !h.includedMetrics.Has(container.DiskUsageMetrics) && !h.includedMetrics.Has(container.DiskIOMetrics) { return nil } // Get Filesystem information only for the root cgroup. if isRootCgroup(h.name) { filesystems, err = h.fsInfo.GetGlobalFsInfo() if err != nil { return err } } else { if len(h.externalMounts) > 0 { mountSet := make(map[string]struct{}) for _, mount := range h.externalMounts { mountSet[mount.HostDir] = struct{}{} } filesystems, err = h.fsInfo.GetFsInfoForPath(mountSet) if err != nil { return err } } } if h.includedMetrics.Has(container.DiskUsageMetrics) { for i := range filesystems { fs := filesystems[i] stats.Filesystem = append(stats.Filesystem, fsToFsStats(&fs)) } } if h.includedMetrics.Has(container.DiskIOMetrics) { common.AssignDeviceNamesToDiskStats(&fsNamer{fs: filesystems, factory: h.machineInfoFactory}, &stats.DiskIo) } return nil } func (h *rawContainerHandler) GetStats() (*info.ContainerStats, error) { if *disableRootCgroupStats && isRootCgroup(h.name) { return nil, nil } stats, err := h.libcontainerHandler.GetStats() if err != nil { return stats, err } // Get filesystem stats. err = h.getFsStats(stats) if err != nil { return stats, err } return stats, nil } func (h *rawContainerHandler) GetCgroupPath(resource string) (string, error) { var res string if !cgroups.IsCgroup2UnifiedMode() { res = resource } path, ok := h.cgroupPaths[res] if !ok { return "", fmt.Errorf("could not find path for resource %q for container %q", resource, h.name) } return path, nil } func (h *rawContainerHandler) GetContainerLabels() map[string]string { return map[string]string{} } func (h *rawContainerHandler) GetContainerIPAddress() string { // the IP address for the raw container corresponds to the system ip address. return "127.0.0.1" } func (h *rawContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { return common.ListContainers(h.name, h.cgroupPaths, listType) } func (h *rawContainerHandler) ListProcesses(listType container.ListType) ([]int, error) { return h.libcontainerHandler.GetProcesses() } func (h *rawContainerHandler) Exists() bool { return common.CgroupExists(h.cgroupPaths) } func (h *rawContainerHandler) Type() container.ContainerType { return container.ContainerTypeRaw } func (h *rawContainerHandler) GetExitCode() (int, error) { return -1, fmt.Errorf("exit codes not applicable for raw cgroup containers") } type fsNamer struct { fs []fs.Fs factory info.MachineInfoFactory info common.DeviceNamer } func (n *fsNamer) DeviceName(major, minor uint64) (string, bool) { for _, info := range n.fs { if uint64(info.Major) == major && uint64(info.Minor) == minor { return info.Device, true } } if n.info == nil { mi, err := n.factory.GetMachineInfo() if err != nil { return "", false } n.info = (*common.MachineInfoNamer)(mi) } return n.info.DeviceName(major, minor) } ================================================ FILE: container/raw/handler_test.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Handler for "raw" containers. package raw import ( "reflect" "testing" "github.com/stretchr/testify/assert" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/common" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" ) func TestFsToFsStats(t *testing.T) { inodes := uint64(100) inodesFree := uint64(50) testCases := map[string]struct { fs *fs.Fs expected info.FsStats }{ "has_inodes": { fs: &fs.Fs{ DeviceInfo: fs.DeviceInfo{Device: "123"}, Type: fs.VFS, Capacity: uint64(1024 * 1024), Free: uint64(1024), Available: uint64(1024), Inodes: &inodes, InodesFree: &inodesFree, DiskStats: fs.DiskStats{ ReadsCompleted: uint64(100), ReadsMerged: uint64(100), SectorsRead: uint64(100), ReadTime: uint64(100), WritesCompleted: uint64(100), WritesMerged: uint64(100), SectorsWritten: uint64(100), WriteTime: uint64(100), IoInProgress: uint64(100), IoTime: uint64(100), WeightedIoTime: uint64(100), }, }, expected: info.FsStats{ Device: "123", Type: fs.VFS.String(), Limit: uint64(1024 * 1024), Usage: uint64(1024*1024) - uint64(1024), HasInodes: true, Inodes: inodes, InodesFree: inodesFree, Available: uint64(1024), ReadsCompleted: uint64(100), ReadsMerged: uint64(100), SectorsRead: uint64(100), ReadTime: uint64(100), WritesCompleted: uint64(100), WritesMerged: uint64(100), SectorsWritten: uint64(100), WriteTime: uint64(100), IoInProgress: uint64(100), IoTime: uint64(100), WeightedIoTime: uint64(100), }, }, "has_no_inodes": { fs: &fs.Fs{ DeviceInfo: fs.DeviceInfo{Device: "123"}, Type: fs.DeviceMapper, Capacity: uint64(1024 * 1024), Free: uint64(1024), Available: uint64(1024), DiskStats: fs.DiskStats{ ReadsCompleted: uint64(100), ReadsMerged: uint64(100), SectorsRead: uint64(100), ReadTime: uint64(100), WritesCompleted: uint64(100), WritesMerged: uint64(100), SectorsWritten: uint64(100), WriteTime: uint64(100), IoInProgress: uint64(100), IoTime: uint64(100), WeightedIoTime: uint64(100), }, }, expected: info.FsStats{ Device: "123", Type: fs.DeviceMapper.String(), Limit: uint64(1024 * 1024), Usage: uint64(1024*1024) - uint64(1024), HasInodes: false, Available: uint64(1024), ReadsCompleted: uint64(100), ReadsMerged: uint64(100), SectorsRead: uint64(100), ReadTime: uint64(100), WritesCompleted: uint64(100), WritesMerged: uint64(100), SectorsWritten: uint64(100), WriteTime: uint64(100), IoInProgress: uint64(100), IoTime: uint64(100), WeightedIoTime: uint64(100), }, }, } for testName, testCase := range testCases { actual := fsToFsStats(testCase.fs) if !reflect.DeepEqual(testCase.expected, actual) { t.Errorf("test case=%v, expected=%v, actual=%v", testName, testCase.expected, actual) } } } func TestGetFsStats(t *testing.T) { inodes := uint64(2000) inodesFree := uint64(1000) cases := map[string]struct { name string includedMetrics container.MetricSet externalMounts []common.Mount globalFsInfo func() ([]fs.Fs, error) getFsInfoForPath func(mountSet map[string]struct{}) ([]fs.Fs, error) diskIO info.DiskIoStats expectedFilesystems []info.FsStats expectedDiskIO info.DiskIoStats }{ "root with disk metrics enabled": { name: "/", includedMetrics: container.MetricSet{container.DiskUsageMetrics: struct{}{}, container.DiskIOMetrics: struct{}{}}, externalMounts: []common.Mount{}, globalFsInfo: func() ([]fs.Fs, error) { return []fs.Fs{{ DeviceInfo: fs.DeviceInfo{ Device: "123", Major: 1, Minor: 2, }, Type: "devicemapper", Capacity: 1000, Free: 500, Available: 450, Inodes: &inodes, InodesFree: &inodesFree, DiskStats: fs.DiskStats{ ReadsCompleted: 1, ReadsMerged: 2, SectorsRead: 3, ReadTime: 3, WritesCompleted: 4, WritesMerged: 6, SectorsWritten: 7, WriteTime: 8, IoInProgress: 9, IoTime: 10, WeightedIoTime: 11, }, }}, nil }, expectedFilesystems: []info.FsStats{ { Device: "123", Type: "devicemapper", Limit: 1000, Usage: 500, BaseUsage: 0, Available: 450, HasInodes: true, Inodes: 2000, InodesFree: 1000, ReadsCompleted: 1, ReadsMerged: 2, SectorsRead: 3, ReadTime: 3, WritesCompleted: 4, WritesMerged: 6, SectorsWritten: 7, WriteTime: 8, IoInProgress: 9, IoTime: 10, WeightedIoTime: 11, }, }, expectedDiskIO: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{ { Device: "123", Major: 1, Minor: 2, Stats: map[string]uint64{"a": 1}, }, }, }, diskIO: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{ { Device: "", Major: 1, Minor: 2, Stats: map[string]uint64{"a": 1}, }, }, }, }, "root with disk usage metrics enabled": { name: "/", includedMetrics: container.MetricSet{container.DiskUsageMetrics: struct{}{}}, externalMounts: []common.Mount{}, globalFsInfo: func() ([]fs.Fs, error) { return []fs.Fs{{ DeviceInfo: fs.DeviceInfo{ Device: "123", Major: 1, Minor: 2, }, Type: "devicemapper", Capacity: 1000, Free: 500, Available: 450, Inodes: &inodes, InodesFree: &inodesFree, DiskStats: fs.DiskStats{ ReadsCompleted: 1, ReadsMerged: 2, SectorsRead: 3, ReadTime: 3, WritesCompleted: 4, WritesMerged: 6, SectorsWritten: 7, WriteTime: 8, IoInProgress: 9, IoTime: 10, WeightedIoTime: 11, }, }}, nil }, expectedFilesystems: []info.FsStats{ { Device: "123", Type: "devicemapper", Limit: 1000, Usage: 500, BaseUsage: 0, Available: 450, HasInodes: true, Inodes: 2000, InodesFree: 1000, ReadsCompleted: 1, ReadsMerged: 2, SectorsRead: 3, ReadTime: 3, WritesCompleted: 4, WritesMerged: 6, SectorsWritten: 7, WriteTime: 8, IoInProgress: 9, IoTime: 10, WeightedIoTime: 11, }, }, // DiskIoStats must not be enriched with device name. // This is imperfect check but I can't find any other. expectedDiskIO: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{ { Device: "", Major: 1, Minor: 2, Stats: map[string]uint64{"a": 1}, }, }, }, diskIO: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{ { Device: "", Major: 1, Minor: 2, Stats: map[string]uint64{"a": 1}, }, }, }, }, "root with disk I/O metrics enabled": { name: "/", includedMetrics: container.MetricSet{container.DiskIOMetrics: struct{}{}}, externalMounts: []common.Mount{}, globalFsInfo: func() ([]fs.Fs, error) { return []fs.Fs{{ DeviceInfo: fs.DeviceInfo{ Device: "123", Major: 1, Minor: 2, }, Type: "devicemapper", Capacity: 1000, Free: 500, Available: 450, Inodes: &inodes, InodesFree: &inodesFree, DiskStats: fs.DiskStats{ ReadsCompleted: 1, ReadsMerged: 2, SectorsRead: 3, ReadTime: 3, WritesCompleted: 4, WritesMerged: 6, SectorsWritten: 7, WriteTime: 8, IoInProgress: 9, IoTime: 10, WeightedIoTime: 11, }, }}, nil }, expectedDiskIO: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{ { Device: "123", Major: 1, Minor: 2, Stats: map[string]uint64{"a": 1}, }, }, }, diskIO: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{ { Device: "", Major: 1, Minor: 2, Stats: map[string]uint64{"a": 1}, }, }, }, }, "root with disk metrics disabled": { name: "/", includedMetrics: container.MetricSet{}, externalMounts: []common.Mount{}, // DiskIoStats must not be enriched with device name. // This is imperfect check but I can't find any other. expectedDiskIO: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{ { Device: "", Major: 1, Minor: 2, Stats: map[string]uint64{"a": 1}, }, }, }, diskIO: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{ { Device: "", Major: 1, Minor: 2, Stats: map[string]uint64{"a": 1}, }, }, }, }, "random container with disk metrics enabled": { name: "/random/container", includedMetrics: container.MetricSet{container.DiskUsageMetrics: struct{}{}, container.DiskIOMetrics: struct{}{}}, externalMounts: []common.Mount{ {HostDir: "/", ContainerDir: "/"}, {HostDir: "/random", ContainerDir: "/completely/random"}, }, getFsInfoForPath: func(mountSet map[string]struct{}) ([]fs.Fs, error) { return []fs.Fs{ { DeviceInfo: fs.DeviceInfo{ Device: "123", Major: 1, Minor: 2, }, Type: "devicemapper", Capacity: 1000, Free: 500, Available: 450, Inodes: &inodes, InodesFree: &inodesFree, DiskStats: fs.DiskStats{ ReadsCompleted: 1, ReadsMerged: 2, SectorsRead: 3, ReadTime: 3, WritesCompleted: 4, WritesMerged: 6, SectorsWritten: 7, WriteTime: 8, IoInProgress: 9, IoTime: 10, WeightedIoTime: 11, }, }, { DeviceInfo: fs.DeviceInfo{ Device: "246", Major: 3, Minor: 4, }, Type: "devicemapper", Capacity: 2000, Free: 1000, Available: 900, Inodes: &inodes, InodesFree: &inodesFree, DiskStats: fs.DiskStats{ ReadsCompleted: 10, ReadsMerged: 20, SectorsRead: 25, ReadTime: 30, WritesCompleted: 40, WritesMerged: 60, SectorsWritten: 70, WriteTime: 80, IoInProgress: 90, IoTime: 100, WeightedIoTime: 110, }, }, }, nil }, expectedFilesystems: []info.FsStats{ { Device: "123", Type: "devicemapper", Limit: 1000, Usage: 500, BaseUsage: 0, Available: 450, HasInodes: true, Inodes: 2000, InodesFree: 1000, ReadsCompleted: 1, ReadsMerged: 2, SectorsRead: 3, ReadTime: 3, WritesCompleted: 4, WritesMerged: 6, SectorsWritten: 7, WriteTime: 8, IoInProgress: 9, IoTime: 10, WeightedIoTime: 11, }, { Device: "246", Type: "devicemapper", Limit: 2000, Usage: 1000, BaseUsage: 0, Available: 900, HasInodes: true, Inodes: 2000, InodesFree: 1000, ReadsCompleted: 10, ReadsMerged: 20, SectorsRead: 25, ReadTime: 30, WritesCompleted: 40, WritesMerged: 60, SectorsWritten: 70, WriteTime: 80, IoInProgress: 90, IoTime: 100, WeightedIoTime: 110, }, }, expectedDiskIO: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{ { Device: "123", Major: 1, Minor: 2, Stats: map[string]uint64{"a": 1}, }, { Device: "246", Major: 3, Minor: 4, Stats: map[string]uint64{"b": 2}, }, }, }, diskIO: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{ { Device: "", Major: 1, Minor: 2, Stats: map[string]uint64{"a": 1}, }, { Device: "", Major: 3, Minor: 4, Stats: map[string]uint64{"b": 2}, }, }, }, }, } for name, c := range cases { t.Run(name, func(t *testing.T) { handler := rawContainerHandler{ name: c.name, includedMetrics: c.includedMetrics, fsInfo: fsInfo{c.globalFsInfo, c.getFsInfoForPath}, externalMounts: c.externalMounts, machineInfoFactory: machineInfo{}, } stats := &info.ContainerStats{DiskIo: c.diskIO} err := handler.getFsStats(stats) assert.NoError(t, err) assert.Len(t, stats.Filesystem, len(c.expectedFilesystems)) assert.Equal(t, c.expectedFilesystems, stats.Filesystem) assert.Equal(t, c.expectedDiskIO, stats.DiskIo) }) } } type fsInfo struct { globalFsInfo func() ([]fs.Fs, error) getFsInfoForPath func(mountSet map[string]struct{}) ([]fs.Fs, error) } func (f fsInfo) GetGlobalFsInfo() ([]fs.Fs, error) { return f.globalFsInfo() } func (f fsInfo) GetFsInfoForPath(mountSet map[string]struct{}) ([]fs.Fs, error) { return f.getFsInfoForPath(mountSet) } func (f fsInfo) GetDirUsage(_ string) (fs.UsageInfo, error) { panic("unsupported") } func (f fsInfo) GetDeviceInfoByFsUUID(_ string) (*fs.DeviceInfo, error) { panic("unsupported") } func (f fsInfo) GetDirFsDevice(_ string) (*fs.DeviceInfo, error) { panic("unsupported") } func (f fsInfo) GetDeviceForLabel(_ string) (string, error) { panic("unsupported") } func (f fsInfo) GetLabelsForDevice(_ string) ([]string, error) { panic("unsupported") } func (f fsInfo) GetMountpointForDevice(_ string) (string, error) { panic("unsupported") } type machineInfo struct{} func (m machineInfo) GetMachineInfo() (*info.MachineInfo, error) { return &info.MachineInfo{ DiskMap: map[string]info.DiskInfo{ "1:2": { Name: "sda", Size: 1234, Scheduler: "none", }, "3:4": { Name: "sdb", Size: 5678, Scheduler: "none", }, }, }, nil } func (m machineInfo) GetVersionInfo() (*info.VersionInfo, error) { panic("unsupported") } ================================================ FILE: container/raw/watcher.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Package container defines types for sub-container events and also // defines an interface for container operation handlers. package raw import ( "fmt" "os" "path" "strings" inotify "k8s.io/utils/inotify" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/common" "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/watcher" "k8s.io/klog/v2" ) type rawContainerWatcher struct { // Absolute path to the root of the cgroup hierarchies cgroupPaths map[string]string // Inotify event watcher. watcher *common.InotifyWatcher // Signal for watcher thread to stop. stopWatcher chan error } func NewRawContainerWatcher(includedMetrics container.MetricSet) (watcher.ContainerWatcher, error) { cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics) if err != nil { return nil, fmt.Errorf("failed to get cgroup subsystems: %v", err) } if len(cgroupSubsystems) == 0 { return nil, fmt.Errorf("failed to find supported cgroup mounts for the raw factory") } watcher, err := common.NewInotifyWatcher() if err != nil { return nil, err } rawWatcher := &rawContainerWatcher{ cgroupPaths: cgroupSubsystems, watcher: watcher, stopWatcher: make(chan error), } return rawWatcher, nil } func (w *rawContainerWatcher) Start(events chan watcher.ContainerEvent) error { // Watch this container (all its cgroups) and all subdirectories. watched := make([]string, 0) for _, cgroupPath := range w.cgroupPaths { _, err := w.watchDirectory(events, cgroupPath, "/") if err != nil { for _, watchedCgroupPath := range watched { _, removeErr := w.watcher.RemoveWatch("/", watchedCgroupPath) if removeErr != nil { klog.Warningf("Failed to remove inotify watch for %q with error: %v", watchedCgroupPath, removeErr) } } return err } watched = append(watched, cgroupPath) } // Process the events received from the kernel. go func() { for { select { case event := <-w.watcher.Event(): err := w.processEvent(event, events) if err != nil { klog.Warningf("Error while processing event (%+v): %v", event, err) } case err := <-w.watcher.Error(): klog.Warningf("Error while watching %q: %v", "/", err) case <-w.stopWatcher: err := w.watcher.Close() if err == nil { w.stopWatcher <- err return } } } }() return nil } func (w *rawContainerWatcher) Stop() error { // Rendezvous with the watcher thread. w.stopWatcher <- nil return <-w.stopWatcher } // Watches the specified directory and all subdirectories. Returns whether the path was // already being watched and an error (if any). func (w *rawContainerWatcher) watchDirectory(events chan watcher.ContainerEvent, dir string, containerName string) (bool, error) { // Don't watch .mount cgroups because they never have containers as sub-cgroups. A single container // can have many .mount cgroups associated with it which can quickly exhaust the inotify watches on a node. if strings.HasSuffix(containerName, ".mount") { return false, nil } alreadyWatching, err := w.watcher.AddWatch(containerName, dir) if err != nil { return alreadyWatching, err } // Remove the watch if further operations failed. cleanup := true defer func() { if cleanup { _, err := w.watcher.RemoveWatch(containerName, dir) if err != nil { klog.Warningf("Failed to remove inotify watch for %q: %v", dir, err) } } }() // TODO(vmarmol): We should re-do this once we're done to ensure directories were not added in the meantime. // Watch subdirectories as well. entries, err := os.ReadDir(dir) if err != nil { return alreadyWatching, err } for _, entry := range entries { if entry.IsDir() { entryPath := path.Join(dir, entry.Name()) subcontainerName := path.Join(containerName, entry.Name()) alreadyWatchingSubDir, err := w.watchDirectory(events, entryPath, subcontainerName) if err != nil { klog.Errorf("Failed to watch directory %q: %v", entryPath, err) if os.IsNotExist(err) { // The directory may have been removed before watching. Try to watch the other // subdirectories. (https://github.com/kubernetes/kubernetes/issues/28997) continue } return alreadyWatching, err } // since we already missed the creation event for this directory, publish an event here. if !alreadyWatchingSubDir { go func() { events <- watcher.ContainerEvent{ EventType: watcher.ContainerAdd, Name: subcontainerName, WatchSource: watcher.Raw, } }() } } } cleanup = false return alreadyWatching, nil } func (w *rawContainerWatcher) processEvent(event *inotify.Event, events chan watcher.ContainerEvent) error { // Convert the inotify event type to a container create or delete. var eventType watcher.ContainerEventType switch { case (event.Mask & inotify.InCreate) > 0: eventType = watcher.ContainerAdd case (event.Mask & inotify.InDelete) > 0: eventType = watcher.ContainerDelete case (event.Mask & inotify.InMovedFrom) > 0: eventType = watcher.ContainerDelete case (event.Mask & inotify.InMovedTo) > 0: eventType = watcher.ContainerAdd default: // Ignore other events. return nil } // Derive the container name from the path name. var containerName string for _, mount := range w.cgroupPaths { mountLocation := path.Clean(mount) + "/" if strings.HasPrefix(event.Name, mountLocation) { containerName = event.Name[len(mountLocation)-1:] break } } if containerName == "" { return fmt.Errorf("unable to detect container from watch event on directory %q", event.Name) } // Maintain the watch for the new or deleted container. switch eventType { case watcher.ContainerAdd: // New container was created, watch it. alreadyWatched, err := w.watchDirectory(events, event.Name, containerName) if err != nil { return err } // Only report container creation once. if alreadyWatched { return nil } case watcher.ContainerDelete: // Container was deleted, stop watching for it. lastWatched, err := w.watcher.RemoveWatch(containerName, event.Name) if err != nil { return err } // Only report container deletion once. if !lastWatched { return nil } default: return fmt.Errorf("unknown event type %v", eventType) } // Deliver the event. events <- watcher.ContainerEvent{ EventType: eventType, Name: containerName, WatchSource: watcher.Raw, } return nil } ================================================ FILE: container/systemd/factory.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package systemd import ( "fmt" "strings" "github.com/google/cadvisor/container" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/watcher" "k8s.io/klog/v2" ) type systemdFactory struct{} func (f *systemdFactory) String() string { return "systemd" } func (f *systemdFactory) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (container.ContainerHandler, error) { return nil, fmt.Errorf("not yet supported") } func (f *systemdFactory) CanHandleAndAccept(name string) (bool, bool, error) { // on systemd using devicemapper each mount into the container has an associated cgroup that we ignore. // for details on .mount units: http://man7.org/linux/man-pages/man5/systemd.mount.5.html if strings.HasSuffix(name, ".mount") { return true, false, nil } klog.V(5).Infof("%s not handled by systemd handler", name) return false, false, nil } func (f *systemdFactory) DebugInfo() map[string][]string { return map[string][]string{} } // Register registers the systemd container factory. func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error { klog.V(1).Infof("Registering systemd factory") factory := &systemdFactory{} container.RegisterContainerHandlerFactory(factory, []watcher.ContainerWatchSource{watcher.Raw}) return nil } ================================================ FILE: container/systemd/install/install.go ================================================ // Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // The install package registers systemd.NewPlugin() as the "systemd" container provider when imported package install import ( "k8s.io/klog/v2" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/systemd" ) func init() { err := container.RegisterPlugin("systemd", systemd.NewPlugin()) if err != nil { klog.Fatalf("Failed to register systemd plugin: %v", err) } } ================================================ FILE: container/systemd/plugin.go ================================================ // Copyright 2019 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package systemd import ( "github.com/google/cadvisor/container" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/watcher" ) // NewPlugin returns an implementation of container.Plugin suitable for passing to container.RegisterPlugin() func NewPlugin() container.Plugin { return &plugin{} } type plugin struct{} func (p *plugin) InitializeFSContext(context *fs.Context) error { return nil } func (p *plugin) Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) (watcher.ContainerWatcher, error) { err := Register(factory, fsInfo, includedMetrics) return nil, err } ================================================ FILE: container/testing/mock_handler.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package testing import ( "github.com/google/cadvisor/container" info "github.com/google/cadvisor/info/v1" "github.com/stretchr/testify/mock" ) // This struct mocks a container handler. type MockContainerHandler struct { mock.Mock Name string Aliases []string } func NewMockContainerHandler(containerName string) *MockContainerHandler { return &MockContainerHandler{ Name: containerName, } } // If self.Name is not empty, then ContainerReference() will return self.Name and self.Aliases. // Otherwise, it will use the value provided by .On().Return(). func (h *MockContainerHandler) ContainerReference() (info.ContainerReference, error) { if len(h.Name) > 0 { var aliases []string if len(h.Aliases) > 0 { aliases = make([]string, len(h.Aliases)) copy(aliases, h.Aliases) } return info.ContainerReference{ Name: h.Name, Aliases: aliases, }, nil } args := h.Called() return args.Get(0).(info.ContainerReference), args.Error(1) } func (h *MockContainerHandler) Start() {} func (h *MockContainerHandler) Cleanup() {} func (h *MockContainerHandler) GetSpec() (info.ContainerSpec, error) { args := h.Called() return args.Get(0).(info.ContainerSpec), args.Error(1) } func (h *MockContainerHandler) GetStats() (*info.ContainerStats, error) { args := h.Called() return args.Get(0).(*info.ContainerStats), args.Error(1) } func (h *MockContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { args := h.Called(listType) return args.Get(0).([]info.ContainerReference), args.Error(1) } func (h *MockContainerHandler) ListProcesses(listType container.ListType) ([]int, error) { args := h.Called(listType) return args.Get(0).([]int), args.Error(1) } func (h *MockContainerHandler) Exists() bool { args := h.Called() return args.Get(0).(bool) } func (h *MockContainerHandler) GetCgroupPath(path string) (string, error) { args := h.Called(path) return args.Get(0).(string), args.Error(1) } func (h *MockContainerHandler) GetContainerLabels() map[string]string { args := h.Called() return args.Get(0).(map[string]string) } func (h *MockContainerHandler) Type() container.ContainerType { args := h.Called() return args.Get(0).(container.ContainerType) } func (h *MockContainerHandler) GetContainerIPAddress() string { args := h.Called() return args.Get(0).(string) } func (h *MockContainerHandler) GetExitCode() (int, error) { args := h.Called() return args.Int(0), args.Error(1) } type FactoryForMockContainerHandler struct { Name string PrepareContainerHandlerFunc func(name string, handler *MockContainerHandler) } func (h *FactoryForMockContainerHandler) String() string { return h.Name } func (h *FactoryForMockContainerHandler) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (container.ContainerHandler, error) { handler := &MockContainerHandler{} if h.PrepareContainerHandlerFunc != nil { h.PrepareContainerHandlerFunc(name, handler) } return handler, nil } func (h *FactoryForMockContainerHandler) CanHandle(name string) bool { return true } ================================================ FILE: deploy/Dockerfile ================================================ FROM registry.hub.docker.com/library/golang:1.25-alpine3.22 AS build # Install build depdencies for all supported arches RUN apk --no-cache add bash build-base cmake device-mapper findutils git \ libc6-compat linux-headers ndctl-dev pkgconfig python3 thin-provisioning-tools wget zfs && \ echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf && \ rm -rf /var/cache/apk/* RUN wget https://sourceforge.net/projects/perfmon2/files/libpfm4/libpfm-4.11.0.tar.gz && \ echo "112bced9a67d565ff0ce6c2bb90452516d1183e5 libpfm-4.11.0.tar.gz" | sha1sum -c && \ tar -xzf libpfm-4.11.0.tar.gz && \ rm libpfm-4.11.0.tar.gz RUN export DBG="-g -Wall" && \ make -e -C libpfm-4.11.0 && \ make install -C libpfm-4.11.0 # ipmctl only supports Intel x86_64 processors. # https://github.com/intel/ipmctl/issues/163 # Disable libipmctl due to https://github.com/google/cadvisor/issues/3482 #RUN if [ "$(uname --machine)" = "x86_64" ]; then \ #git clone -b v02.00.00.3885 https://github.com/intel/ipmctl/ && \ #cd ipmctl && \ #mkdir output && \ #cd output && \ #cmake -DRELEASE=ON -DCMAKE_INSTALL_PREFIX=/ -DCMAKE_INSTALL_LIBDIR=/usr/local/lib .. && \ #make -j all && \ #make install; fi WORKDIR /go/src/github.com/google/cadvisor # Cache Golang Dependencies for faster incremental builds ADD go.mod go.sum ./ RUN go mod download ADD cmd/go.mod cmd/go.sum ./cmd/ RUN cd cmd && go mod download ADD . . ARG VERSION # libipmctl only works on x86_64 CPUs. RUN export GO_TAGS="libpfm,netgo"; \ if [ "$(uname --machine)" = "x86_64" ]; then \ # Disable libipmctl due to https://github.com/google/cadvisor/issues/3482 #export GO_TAGS="$GO_TAGS,libipmctl"; \ export GO_TAGS="$GO_TAGS"; \ fi; \ GO_FLAGS="-tags=$GO_TAGS" ./build/build.sh FROM mirror.gcr.io/library/alpine:3.22 MAINTAINER dengnan@google.com vmarmol@google.com vishnuk@google.com jimmidyson@gmail.com stclair@google.com RUN apk --no-cache add libc6-compat device-mapper findutils ndctl thin-provisioning-tools zfs && \ echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf && \ rm -rf /var/cache/apk/* # Grab cadvisor,libpfm4 and libipmctl from "build" container if they exist (libipmctl only works on amd64/x86_64). COPY --from=build /usr/local/lib/libpfm.so* /usr/local/lib/ # Disable libipmctl due to https://github.com/google/cadvisor/issues/3482 #COPY --from=build /usr/local/lib/libipmctl.so* /usr/local/lib/ COPY --from=build /go/src/github.com/google/cadvisor/_output/cadvisor /usr/bin/cadvisor COPY deploy/entrypoint.sh /usr/bin/entrypoint.sh RUN chmod +x /usr/bin/entrypoint.sh COPY deploy/healthcheck.sh /usr/bin/healthcheck.sh RUN chmod +x /usr/bin/healthcheck.sh # Default port is 8080, but can be changed with -port flag # Users should expose their custom port with: docker run -p : EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \ CMD /usr/bin/healthcheck.sh # Use entrypoint wrapper ENTRYPOINT ["/usr/bin/entrypoint.sh"] ================================================ FILE: deploy/Dockerfile.ppc64le ================================================ FROM ppc64le/alpine:3.15 MAINTAINER dashpole@google.com lysannef@us.ibm.com # Deprecated: the Dockerfile in this directory should support ppc64le # Simply build using: docker buildx build --platform linux/ppc64le -f Dockerfile . RUN apk --no-cache add libc6-compat device-mapper findutils zfs && \ apk --no-cache add thin-provisioning-tools --repository http://dl-3.alpinelinux.org/alpine/edge/main/ && \ echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf && \ rm -rf /var/cache/apk/* # Grab cadvisor from the staging directory. ADD cadvisor /usr/bin/cadvisor EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=3s \ CMD wget --quiet --tries=1 --spider http://localhost:8080/healthz || exit 1 ENTRYPOINT ["/usr/bin/cadvisor", "-logtostderr"] ================================================ FILE: deploy/build.sh ================================================ #!/bin/bash # Copyright 2015 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -e set -x make build docker build -t google/cadvisor:beta -f $(dirname $0)/Dockerfile . ================================================ FILE: deploy/canary/Dockerfile ================================================ FROM golang:1.25 MAINTAINER dashpole@google.com RUN apt-get update && apt-get install -y git dmsetup && apt-get clean RUN git clone https://github.com/google/cadvisor.git /go/src/github.com/google/cadvisor RUN cd /go/src/github.com/google/cadvisor && make ENTRYPOINT ["/go/src/github.com/google/cadvisor/cadvisor"] ================================================ FILE: deploy/entrypoint.sh ================================================ #!/bin/sh # Copyright 2025 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -e # Execute cadvisor with all provided arguments exec /usr/bin/cadvisor -logtostderr "$@" ================================================ FILE: deploy/healthcheck.sh ================================================ #!/bin/sh # Copyright 2025 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Default port PORT=8080 # Extract port from the cadvisor process command line if [ -f /proc/1/cmdline ]; then CMDLINE=$(tr '\0' ' ' < /proc/1/cmdline) # Look for -port=XXXX or --port=XXXX for arg in $CMDLINE; do case "$arg" in -port=*) PORT="${arg#-port=}" ;; --port=*) PORT="${arg#--port=}" ;; esac done fi wget --quiet --tries=1 --spider "http://localhost:${PORT}/healthz" || exit 1 ================================================ FILE: deploy/kubernetes/README.md ================================================ # cAdvisor Kubernetes Daemonset cAdvisor uses [Kustomize](https://github.com/kubernetes-sigs/kustomize) to manage Kubernetes manifests. See the [Install Kustomize](https://kubectl.docs.kubernetes.io/installation/kustomize/) for installation instructions, and for a description of how it works. ## Deploy Pick a [cAdvisor release](https://github.com/google/cadvisor/releases) ``` VERSION=v0.42.0 ``` Deploy to Kubernetes cluster with [remote build](https://github.com/kubernetes-sigs/kustomize/blob/master/examples/remoteBuild.md): ``` kustomize build "https://github.com/google/cadvisor/deploy/kubernetes/base?ref=${VERSION}" | kubectl apply -f - ``` ## Usage To update the image version([reference](https://github.com/kubernetes-sigs/kustomize/blob/master/examples/image.md)): ``` cd deploy/kubernetes/base && kustomize edit set image ghcr.io/google/cadvisor:${VERSION} && cd ../../.. ``` To generate the base daemonset: ``` kubectl kustomize deploy/kubernetes/base ``` To apply the base daemonset to your cluster: ``` kubectl kustomize deploy/kubernetes/base | kubectl apply -f - ``` To generate the daemonset with example patches applied: ``` kubectl kustomize deploy/kubernetes/overlays/examples ``` To apply the daemonset to your cluster with example patches applied: ``` kubectl kustomize deploy/kubernetes/overlays/examples | kubectl apply -f - ``` ### cAdvisor with perf support on Kubernetes Example of modifications needed to deploy cAdvisor with perf support is provided in [overlays/examples_perf](overlays/examples_perf) directory (modification to daemonset and configmap with perf events configuration). To generate and apply the daemonset with patches for cAdvisor with perf support: ``` kubectl kustomize deploy/kubernetes/overlays/examples_perf | kubectl apply -f - ``` ## Kustomization On your own fork of cAdvisor, create your own overlay directory with your patches. Copy patches from the example folder if you intend to use them, but don't modify the originals. Commit your changes in your local branch, and use git to manage them the same way you would any other piece of code. To run the daemonset with your patches applied: ``` kubectl kustomize deploy/kubernetes/overlays/ | kubectl apply -f - ``` To get changes made to the upstream cAdvisor daemonset, simply rebase your fork of cAdvisor on top of upstream. Since you didn't make changes to the originals, you won't have any conflicts. ================================================ FILE: deploy/kubernetes/base/daemonset.yaml ================================================ apiVersion: apps/v1 # for Kubernetes versions before 1.9.0 use apps/v1beta2 kind: DaemonSet metadata: name: cadvisor namespace: cadvisor annotations: seccomp.security.alpha.kubernetes.io/pod: 'docker/default' spec: selector: matchLabels: name: cadvisor template: metadata: labels: name: cadvisor spec: serviceAccountName: cadvisor containers: - name: cadvisor image: ghcr.io/google/cadvisor:0.54.0 resources: requests: memory: 400Mi cpu: 400m limits: memory: 2000Mi cpu: 800m volumeMounts: - name: rootfs mountPath: /rootfs readOnly: true - name: var-run mountPath: /var/run readOnly: true - name: sys mountPath: /sys readOnly: true - name: docker mountPath: /var/lib/docker readOnly: true - name: disk mountPath: /dev/disk readOnly: true ports: - name: http containerPort: 8080 protocol: TCP automountServiceAccountToken: false terminationGracePeriodSeconds: 30 volumes: - name: rootfs hostPath: path: / - name: var-run hostPath: path: /var/run - name: sys hostPath: path: /sys - name: docker hostPath: path: /var/lib/docker - name: disk hostPath: path: /dev/disk ================================================ FILE: deploy/kubernetes/base/kustomization.yaml ================================================ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: cadvisor commonLabels: app: cadvisor resources: - daemonset.yaml - namespace.yaml - serviceaccount.yaml ================================================ FILE: deploy/kubernetes/base/namespace.yaml ================================================ apiVersion: v1 kind: Namespace metadata: name: cadvisor ================================================ FILE: deploy/kubernetes/base/serviceaccount.yaml ================================================ apiVersion: v1 kind: ServiceAccount metadata: name: cadvisor namespace: cadvisor ================================================ FILE: deploy/kubernetes/overlays/examples/cadvisor-args.yaml ================================================ # This patch is an example of setting arguments for the cAdvisor container. # This set of arguments mirrors what the kubelet currently uses for cAdvisor, # enables only cpu, memory, diskIO, disk and network metrics, and shows only # container metrics. apiVersion: apps/v1 # for Kubernetes versions before 1.9.0 use apps/v1beta2 kind: DaemonSet metadata: name: cadvisor namespace: cadvisor spec: template: spec: containers: - name: cadvisor args: - --housekeeping_interval=10s # kubernetes default args - --max_housekeeping_interval=15s - --event_storage_event_limit=default=0 - --event_storage_age_limit=default=0 - --enable_metrics=app,cpu,disk,diskIO,memory,network,process - --docker_only # only show stats for docker containers - --store_container_labels=false - --whitelisted_container_labels=io.kubernetes.container.name, io.kubernetes.pod.name,io.kubernetes.pod.namespace ================================================ FILE: deploy/kubernetes/overlays/examples/critical-priority.yaml ================================================ # This patch sets the priorityClass to system-node-critical, the highest priority available. apiVersion: apps/v1 # for Kubernetes versions before 1.9.0 use apps/v1beta2 kind: DaemonSet metadata: name: cadvisor namespace: cadvisor spec: template: metadata: annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: priorityClassName: system-node-critical tolerations: - key: "CriticalAddonsOnly" operator: "Exists" ================================================ FILE: deploy/kubernetes/overlays/examples/kustomization.yaml ================================================ bases: - ../../base patches: - stackdriver-sidecar.yaml - critical-priority.yaml - cadvisor-args.yaml - gpu-privilages.yaml ================================================ FILE: deploy/kubernetes/overlays/examples/stackdriver-sidecar.yaml ================================================ # This patch adds a sidecar which pushes all metrics to stackdriver apiVersion: apps/v1 # for Kubernetes versions before 1.9.0 use apps/v1beta2 kind: DaemonSet metadata: name: cadvisor namespace: cadvisor spec: template: spec: containers: - name: prometheus-to-sd image: gcr.io/google-containers/prometheus-to-sd:v0.2.6 ports: - name: profiler containerPort: 6061 command: - /monitor - --stackdriver-prefix=custom.googleapis.com - --source=cadvisor:http://localhost:8080 - --pod-id=$(POD_NAME) - --namespace-id=$(POD_NAMESPACE) env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace securityContext: runAsNonRoot: true readOnlyRootFilesystem: true allowPrivilegeEscalation: false ================================================ FILE: deploy/kubernetes/overlays/examples_perf/cadvisor-perf.yaml ================================================ # This patch is an example of setting arguments for the cAdvisor container to collect perf metrics apiVersion: apps/v1 # for Kubernetes versions before 1.9.0 use apps/v1beta2 kind: DaemonSet metadata: name: cadvisor namespace: cadvisor spec: template: spec: containers: - name: cadvisor args: - --perf_events_config=/etc/config/perf-non-hardware.json securityContext: privileged: true volumeMounts: - name: perf-volume mountPath: /etc/config/ volumes: - name: perf-volume configMap: name: perf-config ================================================ FILE: deploy/kubernetes/overlays/examples_perf/configmap.yaml ================================================ apiVersion: v1 kind: ConfigMap metadata: name: perf-config namespace: cadvisor data: perf-non-hardware.json: | { "core": { "events": [ "context-switches", "cpu-migrations-custom" ], "custom_events": [ { "type": 1, "config": [ "0x4" ], "name": "cpu-migrations-custom" } ] } } ================================================ FILE: deploy/kubernetes/overlays/examples_perf/kustomization.yaml ================================================ bases: - ../../base resources: - configmap.yaml patches: - cadvisor-perf.yaml ================================================ FILE: deploy/snap/snapcraft.yaml ================================================ name: cadvisor summary: Container Advisor. description:| Analyzes resource usage and performance characteristics of running containers. adopt-info: cadvisor grade: stable confinement: classic architectures: - build-on: i386 - build-on: amd64 - build-on: armhf - build-on: arm64 apps: cadvisor: command: bin/cadvisor plugs: - home - network - docker - removable-media parts: cadvisor: plugin: nil source: https://github.com/google/cadvisor.git source-type: git override-pull: | git clone https://github.com/google/cadvisor.git src/github.com/google/cadvisor cd src/github.com/google/cadvisor last_committed_tag="$(git describe --tags --abbrev=0)" last_committed_tag_ver="$(echo ${last_committed_tag} | sed 's/v//')" last_released_tag="$(snap info $SNAPCRAFT_PROJECT_NAME | awk '$1 == "beta:" { print $2 }')" # If the latest tag from the upstream project has not been released to # beta, build that tag instead of master. if [ "${last_committed_tag_ver}" != "${last_released_tag}" ]; then git fetch git checkout "${last_committed_tag}" fi snapcraftctl set-version "$(git describe --tags | sed 's/v//')" override-build: | export GOPATH=$PWD cd src/github.com/google/cadvisor env CGO_ENABLED=0 GOOS=linux \ go build --ldflags "-s -w \ -X 'github.com/google/cadvisor/version.GitCommit=$(git rev-list -1 HEAD)' \ -X 'github.com/google/cadvisor/version.Version=$(git describe --tags --abbrev=0)'" \ -a -installsuffix cgo -o $SNAPCRAFT_PART_INSTALL/bin/cadvisor build-snaps: - go build-packages: - git - sed ================================================ FILE: devicemapper/dmsetup_client.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package devicemapper import ( "os/exec" "strconv" "strings" "k8s.io/klog/v2" ) // DmsetupClient is a low-level client for interacting with device mapper via // the `dmsetup` utility, which is provided by the `device-mapper` package. type DmsetupClient interface { // Table runs `dmsetup table` on the given device name and returns the // output or an error. Table(deviceName string) ([]byte, error) // Message runs `dmsetup message` on the given device, passing the given // message to the given sector, and returns the output or an error. Message(deviceName string, sector int, message string) ([]byte, error) // Status runs `dmsetup status` on the given device and returns the output // or an error. Status(deviceName string) ([]byte, error) } // NewDmSetupClient returns a new DmsetupClient. func NewDmsetupClient() DmsetupClient { return &defaultDmsetupClient{} } // defaultDmsetupClient is a functional DmsetupClient type defaultDmsetupClient struct{} var _ DmsetupClient = &defaultDmsetupClient{} func (c *defaultDmsetupClient) Table(deviceName string) ([]byte, error) { return c.dmsetup("table", deviceName) } func (c *defaultDmsetupClient) Message(deviceName string, sector int, message string) ([]byte, error) { return c.dmsetup("message", deviceName, strconv.Itoa(sector), message) } func (c *defaultDmsetupClient) Status(deviceName string) ([]byte, error) { return c.dmsetup("status", deviceName) } func (*defaultDmsetupClient) dmsetup(args ...string) ([]byte, error) { klog.V(5).Infof("running dmsetup %v", strings.Join(args, " ")) return exec.Command("dmsetup", args...).Output() } ================================================ FILE: devicemapper/doc.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package devicemapper contains code for working with devicemapper package devicemapper ================================================ FILE: devicemapper/fake/dmsetup_client_fake.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package fake import ( "testing" ) type DmsetupCommand struct { Name string Result string Err error } // NewFakeDmsetupClient returns a new fake DmsetupClient. func NewFakeDmsetupClient(t *testing.T, commands ...DmsetupCommand) *FakeDmsetupClient { if len(commands) == 0 { commands = make([]DmsetupCommand, 0) } return &FakeDmsetupClient{t: t, commands: commands} } // FakeDmsetupClient is a thread-unsafe fake implementation of the // DmsetupClient interface type FakeDmsetupClient struct { t *testing.T commands []DmsetupCommand } func (c *FakeDmsetupClient) Table(deviceName string) ([]byte, error) { return c.dmsetup("table") } func (c *FakeDmsetupClient) Message(deviceName string, sector int, message string) ([]byte, error) { return c.dmsetup("message") } func (c *FakeDmsetupClient) Status(deviceName string) ([]byte, error) { return c.dmsetup("status") } func (c *FakeDmsetupClient) AddCommand(name string, result string, err error) { c.commands = append(c.commands, DmsetupCommand{name, result, err}) } func (c *FakeDmsetupClient) dmsetup(inputCommand string) ([]byte, error) { var nextCommand DmsetupCommand nextCommand, c.commands = c.commands[0], c.commands[1:] if nextCommand.Name != inputCommand { c.t.Fatalf("unexpected dmsetup command; expected: %q, got %q", nextCommand.Name, inputCommand) // should be unreachable in a test context. } return []byte(nextCommand.Result), nextCommand.Err } ================================================ FILE: devicemapper/fake/thin_ls_client_fake.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package fake type FakeThinLsClient struct { result map[string]uint64 err error } // NewFakeThinLsClient returns a new fake ThinLsClient. func NewFakeThinLsClient(result map[string]uint64, err error) *FakeThinLsClient { return &FakeThinLsClient{result, err} } func (c *FakeThinLsClient) ThinLs(deviceName string) (map[string]uint64, error) { return c.result, c.err } ================================================ FILE: devicemapper/thin_ls_client.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package devicemapper import ( "bufio" "bytes" "fmt" "os/exec" "strconv" "strings" "k8s.io/klog/v2" ) // thinLsClient knows how to run a thin_ls very specific to CoW usage for // containers. type thinLsClient interface { // ThinLs runs a thin ls on the given device, which is expected to be a // metadata device. The caller must hold the metadata snapshot for the // device. ThinLs(deviceName string) (map[string]uint64, error) } // newThinLsClient returns a thinLsClient or an error if the thin_ls binary // couldn't be located. func newThinLsClient() (thinLsClient, error) { thinLsPath, err := ThinLsBinaryPresent() if err != nil { return nil, fmt.Errorf("error creating thin_ls client: %v", err) } return &defaultThinLsClient{thinLsPath}, nil } // defaultThinLsClient is a functional thinLsClient type defaultThinLsClient struct { thinLsPath string } var _ thinLsClient = &defaultThinLsClient{} func (c *defaultThinLsClient) ThinLs(deviceName string) (map[string]uint64, error) { args := []string{"--no-headers", "-m", "-o", "DEV,EXCLUSIVE_BYTES", deviceName} klog.V(4).Infof("running command: thin_ls %v", strings.Join(args, " ")) output, err := exec.Command(c.thinLsPath, args...).Output() if err != nil { return nil, fmt.Errorf("error running command `thin_ls %v`: %v\noutput:\n\n%v", strings.Join(args, " "), err, string(output)) } return parseThinLsOutput(output), nil } // parseThinLsOutput parses the output returned by thin_ls to build a map of // device id -> usage. func parseThinLsOutput(output []byte) map[string]uint64 { cache := map[string]uint64{} // parse output scanner := bufio.NewScanner(bytes.NewReader(output)) for scanner.Scan() { output := scanner.Text() fields := strings.Fields(output) if len(fields) != 2 { continue } deviceID := fields[0] usage, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { klog.Warningf("unexpected error parsing thin_ls output: %v", err) continue } cache[deviceID] = usage } return cache } ================================================ FILE: devicemapper/thin_ls_client_test.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package devicemapper import ( "reflect" "testing" ) func TestParseThinLsOutput(t *testing.T) { cases := []struct { name string input string expectedResult map[string]uint64 }{ { name: "ok", input: ` 1 2293760 2 2097152 3 131072 4 2031616`, expectedResult: map[string]uint64{ "1": 2293760, "2": 2097152, "3": 131072, "4": 2031616, }, }, { name: "skip bad rows", input: ` 1 2293760 2 2097152 3 131072ads 4d dsrv 2031616`, expectedResult: map[string]uint64{ "1": 2293760, "2": 2097152, }, }, } for _, tc := range cases { actualResult := parseThinLsOutput([]byte(tc.input)) if e, a := tc.expectedResult, actualResult; !reflect.DeepEqual(e, a) { t.Errorf("%v: unexpected result: expected %+v got %+v", tc.name, e, a) } } } ================================================ FILE: devicemapper/thin_pool_watcher.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package devicemapper import ( "fmt" "strings" "sync/atomic" "time" "k8s.io/klog/v2" ) // usageCache is a typed wrapper around atomic.Value that eliminates the need // for type assertions at every call site. It stores device ID strings mapped // to usage values (uint64). type usageCache struct { v atomic.Value } // Load retrieves the current cache map. func (c *usageCache) Load() map[string]uint64 { return c.v.Load().(map[string]uint64) } // Store saves a new cache map. func (c *usageCache) Store(m map[string]uint64) { c.v.Store(m) } // ThinPoolWatcher maintains a cache of device name -> usage stats for a // devicemapper thin-pool using thin_ls. type ThinPoolWatcher struct { poolName string metadataDevice string cache usageCache period time.Duration stopChan chan struct{} dmsetup DmsetupClient thinLsClient thinLsClient } // NewThinPoolWatcher returns a new ThinPoolWatcher for the given devicemapper // thin pool name and metadata device or an error. func NewThinPoolWatcher(poolName, metadataDevice string) (*ThinPoolWatcher, error) { thinLsClient, err := newThinLsClient() if err != nil { return nil, fmt.Errorf("encountered error creating thin_ls client: %v", err) } w := &ThinPoolWatcher{ poolName: poolName, metadataDevice: metadataDevice, period: 15 * time.Second, stopChan: make(chan struct{}), dmsetup: NewDmsetupClient(), thinLsClient: thinLsClient, } w.cache.Store(map[string]uint64{}) return w, nil } // Start starts the ThinPoolWatcher. func (w *ThinPoolWatcher) Start() { err := w.Refresh() if err != nil { klog.Errorf("encountered error refreshing thin pool watcher: %v", err) } for { select { case <-w.stopChan: return case <-time.After(w.period): start := time.Now() err = w.Refresh() if err != nil { klog.Errorf("encountered error refreshing thin pool watcher: %v", err) } // print latency for refresh duration := time.Since(start) klog.V(5).Infof("thin_ls(%d) took %s", start.Unix(), duration) } } } // Stop stops the ThinPoolWatcher. func (w *ThinPoolWatcher) Stop() { close(w.stopChan) } // GetUsage gets the cached usage value of the given device. func (w *ThinPoolWatcher) GetUsage(deviceID string) (uint64, error) { cache := w.cache.Load() v, ok := cache[deviceID] if !ok { return 0, fmt.Errorf("no cached value for usage of device %v", deviceID) } return v, nil } const ( reserveMetadataMessage = "reserve_metadata_snap" releaseMetadataMessage = "release_metadata_snap" ) // Refresh performs a `thin_ls` of the pool being watched and refreshes the // cached data with the result. func (w *ThinPoolWatcher) Refresh() error { currentlyReserved, err := w.checkReservation(w.poolName) if err != nil { err = fmt.Errorf("error determining whether snapshot is reserved: %v", err) return err } if currentlyReserved { klog.V(5).Infof("metadata for %v is currently reserved; releasing", w.poolName) _, err = w.dmsetup.Message(w.poolName, 0, releaseMetadataMessage) if err != nil { err = fmt.Errorf("error releasing metadata snapshot for %v: %v", w.poolName, err) return err } } klog.V(5).Infof("reserving metadata snapshot for thin-pool %v", w.poolName) // NOTE: "0" in the call below is for the 'sector' argument to 'dmsetup // message'. It's not needed for thin pools. if output, err := w.dmsetup.Message(w.poolName, 0, reserveMetadataMessage); err != nil { err = fmt.Errorf("error reserving metadata for thin-pool %v: %v output: %v", w.poolName, err, string(output)) return err } klog.V(5).Infof("reserved metadata snapshot for thin-pool %v", w.poolName) defer func() { klog.V(5).Infof("releasing metadata snapshot for thin-pool %v", w.poolName) _, err := w.dmsetup.Message(w.poolName, 0, releaseMetadataMessage) if err != nil { klog.Warningf("Unable to release metadata snapshot for thin-pool %v: %s", w.poolName, err) } }() klog.V(5).Infof("running thin_ls on metadata device %v", w.metadataDevice) newCache, err := w.thinLsClient.ThinLs(w.metadataDevice) if err != nil { err = fmt.Errorf("error performing thin_ls on metadata device %v: %v", w.metadataDevice, err) return err } w.cache.Store(newCache) return nil } const ( thinPoolDmsetupStatusHeldMetadataRoot = 6 thinPoolDmsetupStatusMinFields = thinPoolDmsetupStatusHeldMetadataRoot + 1 ) // checkReservation checks to see whether the thin device is currently holding // userspace metadata. func (w *ThinPoolWatcher) checkReservation(poolName string) (bool, error) { klog.V(5).Infof("checking whether the thin-pool is holding a metadata snapshot") output, err := w.dmsetup.Status(poolName) if err != nil { return false, err } // we care about the field at fields[thinPoolDmsetupStatusHeldMetadataRoot], // so make sure we get enough fields fields := strings.Fields(string(output)) if len(fields) < thinPoolDmsetupStatusMinFields { return false, fmt.Errorf("unexpected output of dmsetup status command; expected at least %d fields, got %v; output: %v", thinPoolDmsetupStatusMinFields, len(fields), string(output)) } heldMetadataRoot := fields[thinPoolDmsetupStatusHeldMetadataRoot] currentlyReserved := heldMetadataRoot != "-" return currentlyReserved, nil } ================================================ FILE: devicemapper/thin_pool_watcher_test.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package devicemapper import ( "fmt" "testing" "time" "github.com/google/cadvisor/devicemapper/fake" ) func TestRefresh(t *testing.T) { usage := map[string]uint64{ "1": 12345, "2": 23456, "3": 34567, } cases := []struct { name string dmsetupCommands []fake.DmsetupCommand thinLsOutput map[string]uint64 thinLsErr error expectedError bool deviceID string expectedUsage uint64 }{ { name: "check reservation fails", dmsetupCommands: []fake.DmsetupCommand{ {Name: "status", Result: "", Err: fmt.Errorf("not gonna work")}, }, expectedError: true, }, { name: "no existing reservation - ok with minimum # of fields", dmsetupCommands: []fake.DmsetupCommand{ {Name: "status", Result: "0 75497472 thin-pool 65 327/524288 14092/589824 -", Err: nil}, // status check {Name: "message", Result: "", Err: nil}, // make reservation {Name: "message", Result: "", Err: nil}, // release reservation }, thinLsOutput: usage, expectedError: false, deviceID: "2", expectedUsage: 23456, }, { name: "no existing reservation - ok", dmsetupCommands: []fake.DmsetupCommand{ {Name: "status", Result: "0 75497472 thin-pool 65 327/524288 14092/589824 - rw no_discard_passdown error_if_no_space - ", Err: nil}, // status check {Name: "message", Result: "", Err: nil}, // make reservation {Name: "message", Result: "", Err: nil}, // release reservation }, thinLsOutput: usage, expectedError: false, deviceID: "2", expectedUsage: 23456, }, { name: "existing reservation - ok", dmsetupCommands: []fake.DmsetupCommand{ // status check {Name: "status", Result: "0 75497472 thin-pool 65 327/524288 14092/589824 39 rw no_discard_passdown error_if_no_space - ", Err: nil}, // release reservation {Name: "message", Result: "", Err: nil}, // make reservation {Name: "message", Result: "", Err: nil}, // release reservation {Name: "message", Result: "", Err: nil}, }, thinLsOutput: usage, expectedError: false, deviceID: "3", expectedUsage: 34567, }, { name: "failure releasing existing reservation", dmsetupCommands: []fake.DmsetupCommand{ // status check {Name: "status", Result: "0 75497472 thin-pool 65 327/524288 14092/589824 39 rw no_discard_passdown error_if_no_space - ", Err: nil}, // release reservation {Name: "message", Result: "", Err: fmt.Errorf("not gonna work")}, }, expectedError: true, }, { name: "failure making reservation", dmsetupCommands: []fake.DmsetupCommand{ // status check {Name: "status", Result: "0 75497472 thin-pool 65 327/524288 14092/589824 39 rw no_discard_passdown error_if_no_space - ", Err: nil}, // release reservation {Name: "message", Result: "", Err: nil}, // make reservation {Name: "message", Result: "", Err: fmt.Errorf("not gonna work")}, }, expectedError: true, }, { name: "failure running thin_ls", dmsetupCommands: []fake.DmsetupCommand{ // status check {Name: "status", Result: "0 75497472 thin-pool 65 327/524288 14092/589824 39 rw no_discard_passdown error_if_no_space - ", Err: nil}, // release reservation {Name: "message", Result: "", Err: nil}, // make reservation {Name: "message", Result: "", Err: nil}, // release reservation {Name: "message", Result: "", Err: nil}, }, thinLsErr: fmt.Errorf("not gonna work"), expectedError: true, }, } for _, tc := range cases { dmsetup := fake.NewFakeDmsetupClient(t, tc.dmsetupCommands...) thinLsClient := fake.NewFakeThinLsClient(tc.thinLsOutput, tc.thinLsErr) watcher := &ThinPoolWatcher{ poolName: "test pool name", metadataDevice: "/dev/mapper/metadata-device", period: 15 * time.Second, stopChan: make(chan struct{}), dmsetup: dmsetup, thinLsClient: thinLsClient, } err := watcher.Refresh() if err != nil { if !tc.expectedError { t.Errorf("%v: unexpected error: %v", tc.name, err) } continue } else if tc.expectedError { t.Errorf("%v: unexpected success", tc.name) continue } actualUsage, err := watcher.GetUsage(tc.deviceID) if err != nil { t.Errorf("%v: device ID not found: %v", tc.deviceID, err) continue } if e, a := tc.expectedUsage, actualUsage; e != a { t.Errorf("%v: actual usage did not match expected usage: expected: %v got: %v", tc.name, e, a) } } } func TestCheckReservation(t *testing.T) { cases := []struct { name string statusResult string statusErr error expectedResult bool expectedErr error }{ { name: "existing reservation 1", statusResult: "0 75497472 thin-pool 65 327/524288 14092/589824 36 rw no_discard_passdown queue_if_no_space - ", expectedResult: true, }, { name: "existing reservation 2", statusResult: "0 12345 thin-pool 65 327/45678 14092/45678 36 rw discard_passdown error_if_no_space needs_check ", expectedResult: true, }, { name: "no reservation 1", statusResult: "0 75497472 thin-pool 65 327/524288 14092/589824 - rw no_discard_passdown error_if_no_space - ", expectedResult: false, }, { name: "no reservation 2", statusResult: "0 75 thin-pool 65 327/12345 14092/589824 - rw no_discard_passdown queue_if_no_space - ", expectedResult: false, }, { name: "no reservation 2", statusResult: "0 75 thin-pool 65 327/12345 14092/589824 - rw no_discard_passdown queue_if_no_space - ", expectedResult: false, }, } for _, tc := range cases { fakeDmsetupClient := fake.NewFakeDmsetupClient(t) fakeDmsetupClient.AddCommand("status", tc.statusResult, tc.statusErr) watcher := &ThinPoolWatcher{dmsetup: fakeDmsetupClient} actualResult, err := watcher.checkReservation("test pool") if err != nil { if tc.expectedErr == nil { t.Errorf("%v: unexpected error running checkReservation: %v", tc.name, err) } } else if tc.expectedErr != nil { t.Errorf("%v: unexpected success running checkReservation", tc.name) } if e, a := tc.expectedResult, actualResult; e != a { t.Errorf("%v: unexpected result from checkReservation: expected: %v got: %v", tc.name, e, a) } } } ================================================ FILE: devicemapper/util.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package devicemapper import ( "fmt" "os" "path/filepath" ) // ThinLsBinaryPresent returns the location of the thin_ls binary in the mount // namespace cadvisor is running in or an error. The locations checked are: // // - /sbin/ // - /bin/ // - /usr/sbin/ // - /usr/bin/ // // The thin_ls binary is provided by the device-mapper-persistent-data // package. func ThinLsBinaryPresent() (string, error) { var ( thinLsPath string err error ) for _, path := range []string{"/sbin", "/bin", "/usr/sbin/", "/usr/bin"} { // try paths for non-containerized operation // note: thin_ls is most likely a symlink to pdata_tools thinLsPath = filepath.Join(path, "thin_ls") _, err = os.Stat(thinLsPath) if err == nil { return thinLsPath, nil } } return "", fmt.Errorf("unable to find thin_ls binary") } ================================================ FILE: doc.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cadvisor ================================================ FILE: docs/api.md ================================================ # cAdvisor Remote REST API cAdvisor exposes its raw and processed stats via a versioned remote REST API: `http://:/api//` The current version of the API is `v1.3`. There is a beta release of the `v2.0` API [available](api_v2.md). ## Version 1.3 This version exposes the same endpoints as `v1.2` with one additional read-only endpoint. ### Events The resource name for Docker container information is as follows: `/api/v1.3/events/` Querying the endpoint receives a list of events which are a serialized `Event` JSON objects (found in [info/v1/container.go](../info/v1/container.go)). The endpoint accepts a certain number of query parameters: | Parameter | Description | Default | |-------------------|--------------------------------------------------------------------------------|-------------------| | `start_time` | Start time of events to query (for stream=false) | Beginning of time | | `end_time` | End time of events to query (for stream=false) | Now | | `stream` | Whether to stream new events as they occur. If false returns historical events | false | | `subcontainers` | Whether to also return events for all subcontainers | false | | `max_events` | The max number of events to return (for stream=false) | 10 | | `all_events` | Whether to include all supported event types | false | | `oom_events` | Whether to include OOM events | false | | `oom_kill_events` | Whether to include OOM kill events | false | | `creation_events` | Whether to include container creation events | false | | `deletion_events` | Whether to include container deletion events | false | ## Version 1.2 This version exposes the same endpoints as `v1.1` with one additional read-only endpoint. ### Docker Container Information The resource name for Docker container information is as follows: `/api/v1.2/docker/` The Docker name can be either the UUID or the short name of the container. It returns the information of the specified container(s). The information is returned as a list of serialized `ContainerInfo` JSON objects (found in [info/v1/container.go](../info/v1/container.go)). ## Version 1.1 This version exposes the same endpoints as `v1.0` with one additional read-only endpoint. ### Subcontainer Information The resource name for subcontainer information is as follows: `/api/v1.1/subcontainers/` Where the absolute container name follows the lmctfy naming convention (described bellow). It returns the information of the specified container and all subcontainers (recursively). The information is returned as a list of serialized `ContainerInfo` JSON objects (found in [info/v1/container.go](../info/v1/container.go)). ## Version 1.0 This version exposes two main endpoints, one for container information and the other for machine information. Both endpoints are read-only in v1.0. ### Container Information The resource name for container information is as follows: `/api/v1.0/containers/` Where the absolute container name follows the lmctfy naming convention. For example: | Container Name | Resource Name | |----------------------|-------------------------------------------| | / | /api/v1.0/containers/ | | /foo | /api/v1.0/containers/foo | | /docker/2c4dee605d22 | /api/v1.0/containers/docker/2c4dee605d22 | Note that the root container (`/`) contains usage for the entire machine. All Docker containers are listed under `/docker`. The container information is returned as a JSON object containing: - Absolute container name - List of subcontainers - ContainerSpec which describes the resource isolation enabled in the container - Detailed resource usage statistics of the container for the last `N` seconds (`N` is globally configurable in cAdvisor) - Histogram of resource usage from the creation of the container The actual object is the marshalled JSON of the `ContainerInfo` struct found in [info/v1/container.go](../info/v1/container.go) ### Machine Information The resource name for machine information is as follows: `/api/vX.Y/machine` This resource is read-only. The machine information is returned as a JSON object containing: - Number of schedulable logical CPU cores - Memory capacity (in bytes) - Maximum supported CPU frequency (in kHz) - Available filesystems: major, minor numbers and capacity (in bytes) - Network devices: mac addresses, MTU, and speed (if available) - Machine topology: Nodes, cores, threads, per-node memory, and caches The actual object is the marshalled JSON of the `MachineInfo` struct found in [info/v1/machine.go](../info/v1/machine.go) ================================================ FILE: docs/api_v2.md ================================================ # cAdvisor Remote REST API cAdvisor exposes its raw and processed stats via a versioned remote REST API: `http://:/api//` This document covers the detail of version 2.0. All resources covered in this version are read-only. NOTE: v2.0 is still a work in progress. ## Version information Software version for cAdvisor can be obtained from version endpoint as follows: `/api/v2.0/version` ## Machine Information The resource name for machine information is as follows: `/api/v2.0/machine` The machine information is returned as a JSON object of the `MachineInfo` struct found in [info/v1/machine.go](../info/v1/machine.go) ## Attributes Attributes endpoint provides hardware and software attributes of the running machine. The resource name for attributes is: `/api/v2.0/attributes` Hardware information includes all information covered by machine endpoint. Software information include version of cAdvisor, kernel, docker, and underlying OS. The actual object is the marshalled JSON of the `Attributes` struct found in [info/v2/machine.go](../info/v2/machine.go) ## Container Stats The resource name for container stats information is: `/api/v2.0/stats/` ### Stats request options Stats support following options in the request: - `type`: describes the type of identifier. Supported values are `name`(default) and `docker`. `name` implies that the identifier is an absolute container name. `docker` implies that the identifier is a docker id. - `recursive`: Option to specify if stats for subcontainers of the requested containers should also be reported. Default is false. - `count`: Number of stats samples to be reported. Default is 64. ### Container name When container identifier is of type `name`, the identifier is interpreted as the absolute container name. Naming follows the lmctfy convention. For example: | Container Name | Resource Name | |----------------------|-------------------------------------------| | / | /api/v2.0/containers/ | | /foo | /api/v2.0/containers/foo | | /docker/2c4dee605d22 | /api/v2.0/containers/docker/2c4dee605d22 | Note that the root container (`/`) contains usage for the entire machine. All Docker containers are listed under `/docker`. Also, `type=name` is not required in the examples above as `name` is the default type. ### Docker Containers When container identifier is of type `docker`, the identifier is interpreted as docker id. For example: | Docker container | Resource Name | |----------------------|-------------------------------------------| | All docker containers| /api/v2.0/stats?type=docker&recursive=true| | clever_colden | /api/v2.0/stats/clever_colden?type=docker | | 2c4dee605d22 | /api/v2.0/stats/2c4dee605d22?type=docker | The Docker name can be either the UUID or the short name of the container. It returns the information of the specified container(s). Note that `recursive` is only valid when docker root is specified. It is used to get stats for all docker containers. ### Returned stats The stats information is returned as a JSON object containing a map from container name to list of stat objects. Stat object is the marshalled JSON of the `ContainerStats` struct found in [info/v2/container.go](../info/v2/container.go) ## Container Stats Summary Instead of a list of periodically collected detailed samples, cAdvisor can also provide a summary of stats for a container. It provides the latest collected stats and percentiles (max, average, and 90%ile) values for usage in last minute and hour. (Usage summary for last day exists, but is not currently used.) Unlike the regular stats API, only selected resources are captured by `summary`. Currently it is limited to cpu and memory usage. The resource name for container summary information is: `/api/v2.0/summary/` Additionally, `type` and `recursive` options can be used to describe the identifier type and ask for summary of all subcontainers respectively. The semantics are same as described for container stats above. The returned summary information is a JSON object containing a map from container name to list of summary objects. Summary object is the marshalled JSON of the `DerivedStats` struct found in [info/v2/container.go](../info/v2/container.go) ## Container Spec The resource name for container stats information is: `/api/v2.0/spec/` Additionally, `type` and `recursive` options can be used to describe the identifier type and ask for spec of all subcontainers respectively. The semantics are same as described for container stats above. The spec information is returned as a JSON object containing a map from container name to list of spec objects. Spec object is the marshalled JSON of the `ContainerSpec` struct found in [info/v2/container.go](../info/v2/container.go) ================================================ FILE: docs/application_metrics.md ================================================ # Collecting Application Metrics with cAdvisor **Note** Application metrics support is in Alpha. We are still making a bunch of interface changes. ## Introduction In addition to usage metrics, cAdvisor can also be configured to collect application metrics. A container can expose application metrics through multiple ways - on a status page, through structured info like prometheus, or have a separate API for fetching stats. cAdvisor provides a generic way to collect these metrics. Additional templates are provided to automate some well-known collection profiles. ## Specifying application metrics Application metrics specification consists of two steps: * Creating a configuration * Passing the configuration location to cadvisor ## Creating a configuration An application metric configuration tells cAdvisor where to look for application metrics and specifies other parameters about how to export the metrics from cAdvisor to UI and backends. The metric config includes: * Endpoint (Location to collect metrics from) * Name of metric * Type (Counter, Gauge, ...) * Data Type (int, float) * Units (kbps, seconds, count) * Polling Frequency * Regexps (Regular expressions to specify which metrics to collect and how to parse them) Here is an example of a very generic metric collector that assumes no structured information: ``` { "endpoint" : "http://localhost:8000/nginx_status", "metrics_config" : [ { "name" : "activeConnections", "metric_type" : "gauge", "units" : "number of active connections", "data_type" : "int", "polling_frequency" : 10, "regex" : "Active connections: ([0-9]+)" }, { "name" : "reading", "metric_type" : "gauge", "units" : "number of reading connections", "data_type" : "int", "polling_frequency" : 10, "regex" : "Reading: ([0-9]+) .*" } ] } ``` For structured metrics export, eg. Prometheus, the config can shrink down to just the endpoint, as other information can be gleaned from the structure. Here is a sample prometheus config that collects all metrics from an endpoint. ``` { "endpoint" : "http://localhost:9100/metrics" } ``` Another sample config that collects only selected metrics: ``` { "endpoint" : "http://localhost:8000/metrics", "metrics_config" : [ "scheduler_binding_latency", "scheduler_e2e_scheduling_latency", "scheduling_algorithm_latency" ] } ``` ## Passing the configuration to cAdvisor cAdvisor can discover any configurations for a container using Docker container labels. Any label starting with ```io.cadvisor.metric``` is parsed as a cadvisor application-metric label. cAdvisor uses the value as an indicator of where the configuration can be found. Labels of the form ```io.cadvisor.metric.prometheus-xyz``` indicate that the configuration points to a Prometheus metrics endpoint. The configuration file can either be part of the container image or can be added on at runtime with a volume. This makes sure that there is no connection between the host where the container is running and the application metrics configuration. A container is self-contained for its metric information. So a sample configuration for redis would look like: Dockerfile (or runtime): ``` FROM redis ADD redis_config.json /var/cadvisor/redis_config.json LABEL io.cadvisor.metric.redis="/var/cadvisor/redis_config.json" ``` cAdvisor will then reach into the container image at runtime, process the config, and start collecting and exposing application metrics. Note that cAdvisor specifically looks at the container labels to extract this information. In Docker 1.8, containers don't inherit labels from their images, and thus you must specify the label at runtime. ## API access to application-specific metrics A new endpoint is added for collecting application-specific metrics for a particular container: ``` http://localhost:8080/api/v2.0/appmetrics/containerName ``` The set of application-metrics being collected can be discovered from the container spec: ``` http://localhost:8080/api/v2.0/spec/containerName ``` Regular stats API also has application-metrics appended to it: ``` http://localhost:8080/api/v2.0/stats/containerName ``` ## UI changes Application-metrics show up on the container page after the resource metrics. ## Ongoing work ### Templates Next step for application-metrics is to add templates for well-known containers that have stable stats API. These would be specified by a new label ```io.cadvisor.metric.type```. If the label value is a known type, cAdvisor would start collecting stats automatically without needing any further config. Config can still be used to override any specific parameters - like set of metrics to collect. ### UI enhancements There are a bunch of UI enhancements under way: * Better handling/display of metrics - eg. allowing overlaying metrics on the same graphs, handling metric types like percentiles. * Moving application metrics to separate tab. * Adding control to show only selected metrics on UI while still exporting everything through the API. ================================================ FILE: docs/clients.md ================================================ # cAdvisor API Clients There is an official Go client implementation in the [client](../client/) directory. You can use it on your own Go project by including it like this: ```go import "github.com/google/cadvisor/client" client, err = client.NewClient("http://localhost:8080/") mInfo, err := client.MachineInfo() ``` Do you know of another cAdvisor client? Maybe in another language? Please let us know! We'd be happy to add a note on this page. ================================================ FILE: docs/deploy.md ================================================ # Building and Deploying the cAdvisor Docker Container ## Building Building the cAdvisor Docker container is simple, just run: ``` $ ./deploy/build.sh ``` Which will statically build the cAdvisor binary and then build the Docker image. The resulting Docker image will be called `google/cadvisor:beta`. This image is very bare, containing the cAdvisor binary and nothing else. ## Deploying All cAdvisor releases are tagged and correspond to a Docker image. The latest supported release uses the `latest` tag. We have a `beta` and `canary` tag for pre-release versions with newer features. You can see more details about this in the cAdvisor [Google Container Registry](https://gcr.io/cadvisor/cadvisor) page. ================================================ FILE: docs/development/README.md ================================================ The [development](./) directory holds documentation for cAdvisor developers and contributors. If you are looking for development using cAdvisor (as opposed to development of cAdvisor), then these documents probably don't apply to you. ================================================ FILE: docs/development/build.md ================================================ # Building and Testing cAdvisor **Note**: cAdvisor only builds on Linux since it uses Linux-only APIs. ## Installing Dependencies cAdvisor is written in the [Go](http://golang.org) programming language. If you haven't set up a Go development environment, please follow [these instructions](http://golang.org/doc/code.html) to install go tool and set up GOPATH. Note that the version of Go in package repositories of some operating systems is outdated, so please [download](https://golang.org/dl/) the latest version. **Note**: cAdvisor requires Go 1.14 to build. After setting up Go, you should be able to `go get` cAdvisor as expected (we use `-d` to only download): ``` $ go get -d github.com/google/cadvisor ``` ## Building from Source At this point you can build cAdvisor from the source folder: ``` $GOPATH/src/github.com/google/cadvisor $ make build ``` or run only unit tests: ``` $GOPATH/src/github.com/google/cadvisor $ make test ``` For integration tests, see the [integration testing](integration_testing.md) page. ### Non-volatile Memory Support cAdvisor can be linked against [libipmctl](https://github.com/intel/ipmctl) library that allows to gather information about Intel® Optane™ DC Persistent memory. If you want to build cAdvisor with libipmctl support you must meet following requirements: * `libipmctl-devel` must be installed on build system. * `libipmctl` must be installed on all systems where cAdvisor is running. Detailed information about building `libipmctl` can be found in the project's [README](https://github.com/intel/ipmctl#build). Make sure to use the most up to date released version. Functionality that relies on `libipmctl` was tested against version 02.00.00.3820 of the library. To enable `libipmctl` support `GO_FLAGS` variable must be set: ``` $GOPATH/src/github.com/google/cadvisor $ GO_FLAGS="-tags=libipmctl,netgo" make build ``` ### Perf Support cAdvisor can be linked against [libpfm4](http://perfmon2.sourceforge.net/) library that allows to gather information about performance monitoring events. If you want to build cAdvisor with libpfm4 support you must meet following requirements: * `libpfm4-dev` must be installed on build system. * `libpfm4` must be installed on all systems where cAdvisor is running. libpfm4 packages are available in Debian- and RHEL-derivatives distributions. libpfm4 can be installed using apt package manager: ``` apt-get install libpfm4 libpfm4-dev ``` or yum package manager: ``` yum install libpfm libpfm-devel ``` To enable `libpfm4` support `GO_FLAGS` variable must be set: ``` $GOPATH/src/github.com/google/cadvisor $ GO_FLAGS="-tags=libpfm,netgo" make build ``` ## Running Built Binary Now you can run the built binary: ``` $GOPATH/src/github.com/google/cadvisor $ sudo ./cadvisor ``` ### Perf Support It is required to include perf config (examplary config is available [here](../../perf/testing/perf-non-hardware.json)) to run cAdvisor with performance monitoring events: ``` $GOPATH/src/github.com/google/cadvisor $ sudo ./cadvisor -perf_events_config=perf/testing/perf-non-hardware.json ``` ================================================ FILE: docs/development/integration_testing.md ================================================ # Integration Testing cAdvisor ## Docker-based tests The cAdvisor integration tests are run per-pr using [Github Actions](https://help.github.com/en/actions). Workflow configuration can be found at [.github/workflows/test.yml](.github/workflows/test.yml). Tests are executed in Docker containers run on MS Azure virtual machines. To run them locally Docker must be installed on your machine. Following command allows you to execute default suite of integration tests: ``` make docker-test-integration ``` Build scripts take care of building cAdvisor and integration tests, and executing them against running cAdvisor process. In order to run non-default tests suites (e.g. such that rely on third-party C libraries) you must source one of the files available at [build/config](build/config), e.g.: ``` source build/config/libpfm4.sh && make docker-test-integration ``` All the necessary packages will be installed, build flags will be applied and additional parameters will be passed to cAdvisor automatically. Configuration is performed using shell environment variables. ## VM-base tests (legacy) The cAdvisor integration tests are run per-pr using the [kubernetes node-e2e testing framework](https://github.com/kubernetes/community/blob/master/contributors/devel/e2e-node-tests.md) on GCE instances. To make use of this framework, complete the setup of GCP described in the node-e2e testing framework, clone `k8s.io/kubernetes`, and from that repository run: ``` $ make test-e2e-node TEST_SUITE=cadvisor REMOTE=true ``` This will create a VM, build cadvisor, run integration tests on that VM, retrieve logs, and will clean up the test afterwards. See the [node-e2e testing documentation](https://github.com/kubernetes/community/blob/master/contributors/devel/e2e-node-tests.md) for more running options. To simply run the tests against an existing cAdvisor: ``` $ go test github.com/google/cadvisor/integration/tests/... -host=HOST -port=PORT ``` Note that `HOST` and `PORT` default to `localhost` and `8080` respectively. Today We only support remote execution in Google Compute Engine since that is where we run our continuous builds. ================================================ FILE: docs/development/issues.md ================================================ # GitHub Issue tracking cAdvisor This document outlines the process around GitHub issue tracking for cAdvisor at https://github.com/google/cadvisor/issues ## Labels A brief explanation of what issue labels mean. Most labels also apply to pull requests, but for pull requests which reference an issue, it is not necessary to copy the same labels to the PR. - `area/API` - For issues related to the API. - `area/UI` - For issues related to the web UI. - `area/documentation` - For issues related to the documentation (inline comments or markdown). - `area/performance` - For issues related to cAdvisor performance (speed, memory, etc.). - `area/storage` - For issues related to cAdvisor storage plugins. - `area/testing` - For issues related to testing (integration tests, unit tests, jenkins, etc.) - `closed/duplicate` - For issues which have been closed as duplicates of another issue. The final comment on the issue should hold a reference the duplicate issue. - `closed/infeasible` - For issues which cannot be resolved (e.g. a request for a feature we cannot or do not want to add). - `community-assigned` - For issues which are being worked on by a community member (when github won't let us assign the issue to them). - `kind/bug` - For issues referring to a bug in the existing implementation. - `kind/enhancement` - For issues proposing an enhancement or new feature. - `kind/support` - For issues which might just be user confusion / environment setup. If support issue ends up requiring a PR, it should probably be relabeled (for example, to `bug`). Many support issues may indicate a shortcoming of the documentation. - `help wanted` - For issues which have been highlighted as a good place to contribute to cAdvisor. `help wanted` issues could be enhancements that the core team is unlikely to get to in the near future, or small projects which might be a good starting point. Lack of a `help wanted` label does not mean we won't accept contributions, it only means it was not identified as a candidate project for community contributions. ================================================ FILE: docs/development/releasing.md ================================================ # cAdvisor Release Instructions ## 1. Send Release PR Example: https://github.com/google/cadvisor/pull/1281 Add release notes to [CHANGELOG.md](../../CHANGELOG.md) - Tip: Use a github PR search to find changes since the last release `is:pr is:merged merged:>2016-04-21` ## 2. Create the release tag ### 2.a Create the release branch (only for major/minor releases) Skip this step for patch releases. ``` # Example version VERSION=v0.23 PATCH_VERSION=$VERSION.0 # Sync to HEAD, or the commit to branch at git fetch upstream && git checkout upstream/master # Create the branch git branch release-$VERSION # Push it to upstream git push git@github.com:google/cadvisor.git release-$VERSION ``` ### 2.b Tag the release (for all releases) ``` # Example patch version VERSION=v0.23 PATCH_VERSION=$VERSION.0 # Checkout the release branch git fetch upstream && git checkout upstream/release-$VERSION # Tag the release commit. If you aren't signing, ommit the -s git tag -s -a $PATCH_VERSION # Push it to upstream git push git@github.com:google/cadvisor.git $PATCH_VERSION ``` ## 3. Build release artifacts Command: `make release` - Make sure your git client is synced to the release cut point - Use the same go version as kubernetes: [dependencies.yaml](https://github.com/kubernetes/kubernetes/blob/master/build/dependencies.yaml#L101) - Tip: use https://github.com/moovweb/gvm to manage multiple go versions. - Try to build it from the release branch, since we include that in the binary version - Verify the ldflags output, in particular check the Version, BuildUser, and GoVersion are expected Once the build is complete, copy the output after `Release info...` and save it to use in step 5 Example: ``` Multi Arch Container: gcr.io/cadvisor/cadvisor:v0.44.1-test-8 Architecture Specific Containers: gcr.io/cadvisor/cadvisor-arm:v0.44.1-test-8 gcr.io/cadvisor/cadvisor-arm64:v0.44.1-test-8 gcr.io/cadvisor/cadvisor-amd64:v0.44.1-test-8 Binaries: SHA256 (cadvisor-v0.44.1-test-8-linux-arm64) = e5e3f9e72208bc6a5ef8b837473f6c12877ace946e6f180bce8d81edadf66767 SHA256 (cadvisor-v0.44.1-test-8-linux-arm) = 7d714e495a4f50d9cc374bd5e6b5c6922ffa40ff1cc7244f2308f7d351c4ccea SHA256 (cadvisor-v0.44.1-test-8-linux-amd64) = ea95c5a6db8eecb47379715c0ca260a8a8d1522971fd3736f80006c7f6cc9466 ``` ## 4. Check that the Containers for the release work The only argument to the script is the tag of the Multi Arch Container from step 3. To verify that the container images for the release were built successfully, use the check_container.sh script. The script will start each cadvisor image and curl the `/healthz` endpoint to confirm that it is working. Running this script requires that you have installed `qemu-user-static` and configured qemu as a binary interpreter. ``` $ sudo apt install qemu-user-static $ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes ``` The only argument to the script is the tag of the Multi Arch Container from step 3. ```sh build/check_container.sh gcr.io/tstapler-gke-dev/cadvisor:v0.44.1-test-8 ``` ## 5. Cut the release Go to https://github.com/google/cadvisor/releases and click "Draft a new release" - "Tag version" and "Release title" should be preceded by 'v' and then the version. Select the tag pushed in step 2.b - Copy an old release as a template (e.g. github.com/google/cadvisor/releases/tag/v0.23.1) - Body should start with release notes (from CHANGELOG.md) - Next are the docker images and binary hashes you copied (from step 3). - Upload the binaries build in step 3, they are located in the `_output` directory. - If this is a minor version release, mark the release as a "pre-release" - Click publish when done ================================================ FILE: docs/roadmap.md ================================================ # cAdvisor project roadmap Last updated: Jan 2026. Status: proposed by SIG Node. Next steps: - Otel community agreement - detailed plans ## Motivation The motivation for this document is a set of new requests for cAdvisor standalone mode. These requests is a reminder that we need to define a cAdvisor roadmap in light of a current developments in K8s project and a modern landscape of tools and projects. ## Background CAdvisor consists of two parts that are interleaved and interconnected: - a library linked into kubelet used to provide information about resource usage that K8s project depends on. - standalone binary for users to monitor containerized workloads. This includes, but not limited to kubernetes. Outside of kubernetes it is docker containers, Mesos, etc. and provide support for dedicated hardware such as Intel PMU perf metrics. The project was originated when the industry looked very differently and not well aligned with modern landscape of tools and projects. Also, since cAdvisor is a Google project, rather than a kubernetes project, results in a few issues: - Google outsized ownership and responsibility for this project with limited OSS governance model. - K8s contributors that currently maintains it has little vested interest in owning the standalone mode scenarios. - Every release of kubernetes requires cAdvisor to be vendored into k8s tree, which can cause significant “dependency hell” and limits what standalone mode cAdvisor can do. There is ongoing work to deprecate the cAdvisor as a vendored library for k8s. The work consist of multiple stages. First stage is tracked as part of this enhancement: [cAdvisor-less, CRI-full Container and Pod Stats](https://github.com/kubernetes/enhancements/issues/2371). There will be more work needed after the KEP above is merged to transition machine-wide metrics to containerd. Once the transition of metrics to container runtime complete, the cAdvisor project will not be in scope of k8s contributors and will be more aligned with the OpenTelemetry project. Also unless SIG instrumentation will take it as their scope, we will deprecate the cAdvisor endpoint and not accept requests like this: [Configurable cAdvisor Metrics Collection](https://github.com/kubernetes/enhancements/pull/5776) as those are also more aligned with the telemetry scenarios rather than orchestration. ## cAdvisor roadmap ### K8s side #### 2026 - finish transition of Pod merics to K8s: [cAdvisor-less, CRI-full Container and Pod Stats](https://github.com/kubernetes/enhancements/issues/2371) - start transition of machine-level metrics to Container Runtime (KEP: TBD). - Decide on the future of `cadvisor` endpoint - likely deprecation of the `cadvisor` endpoint of kubelet #### 2027 - Stop vendoring cAdvisor to K8s. #### 2027+ (maybe way passed it) - Remove the `cadvisor` endpoint of kubelet ### cAdvisor standalone The proposal is to move cAdvisor standalone scenarios to Otel collector. New [receivers](https://opentelemetry.io/docs/collector/components/receiver/) will collect similar information to what cAdvisor collects today and Otel collector can be configured to export as Prometheus endpoint or [any other supported exporter](https://opentelemetry.io/docs/collector/components/exporter/). So there will be a transition path from cAdvisor standalone to Otel collector. The same time cAdvisor project will be placed in maintenance mode and eventually closed. If there will be interest from any project or 3rd party to pick up the project and transfer it to CNCF or other project - there will be an open discussion on this. ## Notes on transition to Otel Collector This is not a detailed spec on transition to Otel Collector. The intent of this section is to highlight the tension points that needs to be clarified as the transition specs are written. ### Distribution model cAdvisor is a specialized software for containers metrics collection. It is easier to configure and likely more lightweight. Otel collector will need to be compiled with the right set of receivers and exporters and configured appropriately. The benefit of using Otel Collector for these scenarios is its flexibility in collecting telemetry for more scenarios and a well-known config as oppose to a custom cAdvisor configuration. The believe of this roadmap is that benefits of cAdvisor's distribution model will not be significant enough to prefer it over the Otel collector. ### Supported metrics The proposal is to transition all metrics to Otel collector to make sure a smooth transition for time-proof set of metrics. However the detailed plan is needed to make a final decision. The design may split metrics into multiple receivers if this will be more convenient. ### Supported endpoints Beyond prometheus metrics, cAdvisor supports a few more endpoint. The list is here: https://github.com/google/cadvisor/blob/master/docs/api.md ### prometheus Prometheus endpoints may expose metrics in a format different as Otel collector prefer dots in names to underscores. Also other renames may potentially be needed as metric names will be aligned with Otel Semantic Convention. Otel collector will expose the single prometheus endpoint with all metrics for all containers and will not support [container-specific endpoints](https://github.com/google/cadvisor/blob/master/docs/application_metrics.md#api-access-to-application-specific-metrics). ### events The proposal is to collect events as Otel events. There is no analogous of events endpoint in Otel collector. So transition to Otel events will require to change design of consumers from pull model to push model for events. #### docker Not supported. No alternatives offered. #### subcontainers Not supported. No alternatives offered. #### containers Not supported. No alternatives offered. #### machine Not supported, use [Node Feature Discovery](https://github.com/kubernetes-sigs/node-feature-discovery). ### Supported runtimes The proposal is to transition container-based metrics collection to Otel collector so all advanced metrics and non-Kubernetes environments monitoring is supported by Otel collector. This way Otel collector will support the same set of environments and runtimes as cAdvisor does today. This may be done by copying code from cAdvisor. However, as a more lightweight implementation, Otel collector may also implement receivers that are based on CRI-exposed metrics based on KEP [cAdvisor-less, CRI-full Container and Pod Stats](https://github.com/kubernetes/enhancements/issues/2371). These receivers will be less flexible and limited to Kubernetes scenarios. However these receivers will be more reliable. The proposal is to design for the full set of scenarios, but not limiting to it and allow for CRI-based metrics receivers. ### Supported OSes cAdvisor does NOT support Windows containers monitoring while Otel collector does. There is a potential for Otel collector to implement this scenario, but it will be outside of a scope of this roadmap document. ================================================ FILE: docs/running.md ================================================ # Running cAdvisor ## With Docker We have a Docker image that includes everything you need to get started. Simply run: ``` VERSION=v0.35.0 # use the latest release version from https://github.com/google/cadvisor/releases sudo docker run \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:rw \ --volume=/sys:/sys:ro \ --volume=/var/lib/docker/:/var/lib/docker:ro \ --publish=8080:8080 \ --detach=true \ --name=cadvisor \ ghcr.io/google/cadvisor:$VERSION # for versions prior to v0.53.0, use gcr.io/cadvisor/cadvisor instead ``` cAdvisor is now running (in the background) on `http://localhost:8080/`. The setup includes directories with Docker state cAdvisor needs to observe. **Note**: - If docker daemon is running with [user namespace enabled](https://docs.docker.com/reference/cli/dockerd/#daemon-user-namespace-options), you need to add `--userns=host` option in order for cAdvisor to monitor Docker containers, otherwise cAdvisor can not connect to docker daemon. - If cadvisor scrapes `process` metrics due to `--disable_metrics` or `--enable_metrics` options, you need to add `--pid=host` and `--privileged` for `docker run` to get `/proc/pid/fd` path in host. - If cAdvisor needs to be run in Docker container without `--privileged` option it is possible to add host devices to container using `--dev` and specify security options using `--security-opt` with secure computing mode (seccomp). For details related to seccomp please [see](https://docs.docker.com/engine/security/seccomp/), the default Docker profile can be found [here](https://github.com/moby/moby/blob/master/profiles/seccomp/default.json). For example to run cAdvisor with perf support in Docker container without `--privileged` option it is required to: - Set perf_event_paranoid using `sudo sysctl kernel.perf_event_paranoid=-1`, see [documentation](https://www.kernel.org/doc/Documentation/sysctl/kernel.txt) - Add "perf_event_open" syscall into syscalls array with the action: "SCMP_ACT_ALLOW" in [default Docker profile](https://github.com/moby/moby/blob/master/profiles/seccomp/default.json) - Run Docker container with following options: ``` docker run \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:ro \ --volume=/sys:/sys:ro \ --volume=/var/lib/docker/:/var/lib/docker:ro \ --volume=/dev/disk/:/dev/disk:ro \ --volume=$GOPATH/src/github.com/google/cadvisor/perf/testing:/etc/configs/perf \ --publish=8080:8080 \ --device=/dev/kmsg \ --security-opt seccomp=default.json \ --name=cadvisor \ ghcr.io/google/cadvisor: -perf_events_config=/etc/configs/perf/perf.json ``` ## With Boot2Docker After booting up a boot2docker instance, run cAdvisor image with the same docker command mentioned above. cAdvisor can now be accessed at port 8080 of your boot2docker instance. The host IP can be found through DOCKER_HOST environment variable setup by boot2docker: ``` $ echo $DOCKER_HOST tcp://192.168.59.103:2376 ``` In this case, cAdvisor UI should be accessible on `http://192.168.59.103:8080` ## Other Configurations ### CentOS, Fedora, and RHEL You may need to run the container with `--privileged=true` and `--volume=/cgroup:/cgroup:ro \` in order for cAdvisor to monitor Docker containers. RHEL and CentOS lock down their containers a bit more. cAdvisor needs access to the Docker daemon through its socket. This requires `--privileged=true` in RHEL and CentOS. On some versions of RHEL and CentOS the cgroup hierarchies are mounted in `/cgroup` so run cAdvisor with an additional Docker option of `--volume=/cgroup:/cgroup:ro \`. **Note**: For a RedHat 7 docker host the default run commands from above throw oci errors. Please use the command below if the host is RedHat 7: ``` docker run --volume=/:/rootfs:ro --volume=/var/run:/var/run:rw --volume=/sys/fs/cgroup/cpu,cpuacct:/sys/fs/cgroup/cpuacct,cpu --volume=/var/lib/docker/:/var/lib/docker:ro --publish=8080:8080 --detach=true --name=cadvisor --privileged=true google/cadvisor:latest ``` ### Debian By default, Debian disables the memory cgroup which does not allow cAdvisor to gather memory stats. To enable the memory cgroup take a look at [these instructions](https://github.com/google/cadvisor/issues/432). ### LXC Docker exec driver If you are using Docker with the LXC exec driver, then you need to manually specify all cgroup mounts by adding the: ``` --volume=/cgroup/cpu:/cgroup/cpu \ --volume=/cgroup/cpuacct:/cgroup/cpuacct \ --volume=/cgroup/cpuset:/cgroup/cpuset \ --volume=/cgroup/memory:/cgroup/memory \ --volume=/cgroup/blkio:/cgroup/blkio \ ``` ### Invalid Bindmount `/` This is a problem seen in older versions of Docker. To fix, start cAdvisor without the `--volume=/:/rootfs:ro` mount. cAdvisor will degrade gracefully by dropping stats that depend on access to the machine root. ## Standalone cAdvisor is a static Go binary with no external dependencies. To run it standalone all you should need to do is run it! Note that some data sources may require root privileges. cAdvisor will gracefully degrade its features to those it can expose with the access given. ``` $ sudo cadvisor ``` cAdvisor is now running (in the foreground) on `http://localhost:8080/`. ## Runtime Options cAdvisor has a series of flags that can be used to configure its runtime behavior. More details can be found in runtime [options](runtime_options.md). ================================================ FILE: docs/runtime_options.md ================================================ # cAdvisor Runtime Options This document describes a set of runtime flags available in cAdvisor. ## Container labels * `--store_container_labels=false` - do not convert container labels and environment variables into labels on prometheus metrics for each container. * `--whitelisted_container_labels` - comma separated list of container labels to be converted to labels on prometheus metrics for each container. `store_container_labels` must be set to false for this to take effect. ## Container envs * `--env_metadata_whitelist`: a comma-separated list of environment variable keys that needs to be collected for containers, only support containerd and docker runtime for now. ## Limiting which containers are monitored * `--docker_only=false` - do not report raw cgroup metrics, except the root cgroup. * `--raw_cgroup_prefix_whitelist` - a comma-separated list of cgroup path prefix that needs to be collected even when `--docker_only` is specified * `--disable_root_cgroup_stats=false` - disable collecting root Cgroup stats. ## Container Hints Container hints are a way to pass extra information about a container to cAdvisor. In this way cAdvisor can augment the stats it gathers. For more information on the container hints format see its [definition](../container/common/container_hints.go). Note that container hints are only used by the raw container driver today. ``` --container_hints="/etc/cadvisor/container_hints.json": location of the container hints file ``` ## CPU ``` --enable_load_reader=false: Whether to enable cpu load reader --max_procs=0: max number of CPUs that can be used simultaneously. Less than 1 for default (number of cores). ``` ## Debugging and Logging cAdvisor-native flags that help in debugging: ``` --log_backtrace_at="": when logging hits line file:N, emit a stack trace --log_cadvisor_usage=false: Whether to log the usage of the cAdvisor container --version=false: print cAdvisor version and exit --profiling=false: Enable profiling via web interface host:port/debug/pprof/ ``` From [glog](https://github.com/golang/glog) here are some flags we find useful: ``` --log_dir="": If non-empty, write log files in this directory --logtostderr=false: log to standard error instead of files --alsologtostderr=false: log to standard error as well as files --stderrthreshold=0: logs at or above this threshold go to stderr --v=0: log level for V logs --vmodule=: comma-separated list of pattern=N settings for file-filtered logging ``` ## Docker ``` --docker="unix:///var/run/docker.sock": docker endpoint (default "unix:///var/run/docker.sock") --docker_root="/var/lib/docker": DEPRECATED: docker root is read from docker info (this is a fallback, default: /var/lib/docker) (default "/var/lib/docker") --docker-tls: use TLS to connect to docker --docker-tls-cert="cert.pem": client certificate for TLS-connection with docker --docker-tls-key="key.pem": private key for TLS-connection with docker --docker-tls-ca="ca.pem": trusted CA for TLS-connection with docker ``` ## Podman ```bash --podman="unix:///var/run/podman/podman.sock": podman endpoint (default "unix:///var/run/podman/podman.sock") ``` ## Housekeeping Housekeeping is the periodic actions cAdvisor takes. During these actions, cAdvisor will gather container stats. These flags control how and when cAdvisor performs housekeeping. #### Dynamic Housekeeping Dynamic housekeeping intervals let cAdvisor vary how often it gathers stats. It does this depending on how active the container is. Turning this off provides predictable housekeeping intervals, but increases the resource usage of cAdvisor. ``` --allow_dynamic_housekeeping=true: Whether to allow the housekeeping interval to be dynamic ``` #### Housekeeping Intervals Intervals for housekeeping. cAdvisor has two housekeepings: global and per-container. Global housekeeping is a singular housekeeping done once in cAdvisor. This typically does detection of new containers. Today, cAdvisor discovers new containers with kernel events so this global housekeeping is mostly used as backup in the case that there are any missed events. Per-container housekeeping is run once on each container cAdvisor tracks. This typically gets container stats. ``` --global_housekeeping_interval=1m0s: Interval between global housekeepings --housekeeping_interval=1s: Interval between container housekeepings --max_housekeeping_interval=1m0s: Largest interval to allow between container housekeepings (default 1m0s) ``` ## HTTP Specify where cAdvisor listens. ``` --http_auth_file="": HTTP auth file for the web UI --http_auth_realm="localhost": HTTP auth realm for the web UI (default "localhost") --http_digest_file="": HTTP digest file for the web UI --http_digest_realm="localhost": HTTP digest file for the web UI (default "localhost") --listen_ip="": IP to listen on, defaults to all IPs --port=8080: port to listen (default 8080) --url_base_prefix=/: optional path prefix aded to all resource URLs; useful when running cAdvisor behind a proxy. (default /) ``` ## Local Storage Duration cAdvisor stores the latest historical data in memory. How long of a history it stores can be configured with the `--storage_duration` flag. ``` --storage_duration=2m0s: How long to store data. ``` ## Machine ``` --boot_id_file="/proc/sys/kernel/random/boot_id": Comma-separated list of files to check for boot-id. Use the first one that exists. (default "/proc/sys/kernel/random/boot_id") --machine_id_file="/etc/machine-id,/var/lib/dbus/machine-id": Comma-separated list of files to check for machine-id. Use the first one that exists. (default "/etc/machine-id,/var/lib/dbus/machine-id") --update_machine_info_interval=5m: Interval between machine info updates. (default 5m) ``` ## Metrics ``` --application_metrics_count_limit=100: Max number of application metrics to store (per container) (default 100) --collector_cert="": Collector's certificate, exposed to endpoints for certificate based authentication. --collector_key="": Key for the collector's certificate --disable_metrics=: comma-separated list of metrics to be disabled. Options are advtcp,app,cpu,cpuLoad,cpu_topology,cpuset,disk,diskIO,hugetlb,memory,memory_numa,network,oom_event,percpu,perf_event,process,referenced_memory,resctrl,sched,tcp,udp. (default advtcp,cpu_topology,cpuset,hugetlb,memory_numa,process,referenced_memory,resctrl,sched,tcp,udp) --enable_metrics=: comma-separated list of metrics to be enabled. If set, overrides 'disable_metrics'. Options are advtcp,app,cpu,cpuLoad,cpu_topology,cpuset,disk,diskIO,hugetlb,memory,memory_numa,network,oom_event,percpu,perf_event,process,referenced_memory,resctrl,sched,tcp,udp. --prometheus_endpoint="/metrics": Endpoint to expose Prometheus metrics on (default "/metrics") --disable_root_cgroup_stats=false: Disable collecting root Cgroup stats ``` ## Storage Drivers ``` --storage_driver="": Storage driver to use. Data is always cached shortly in memory, this controls where data is pushed besides the local cache. Empty means none. Options are: , bigquery, elasticsearch, influxdb, kafka, redis, statsd, stdout --storage_driver_buffer_duration="1m0s": Writes in the storage driver will be buffered for this duration, and committed to the non memory backends as a single transaction (default 1m0s) --storage_driver_db="cadvisor": database name (default "cadvisor") --storage_driver_host="localhost:8086": database host:port (default "localhost:8086") --storage_driver_password="root": database password (default "root") --storage_driver_secure=false: use secure connection with database --storage_driver_table="stats": table name (default "stats") --storage_driver_user="root": database username (default "root") ``` ## Perf Events ``` --perf_events_config="" Path to a JSON file containing configuration of perf events to measure. Empty value disables perf events measuring. ``` Core perf events can be exposed on Prometheus endpoint per CPU or aggregated by event. It is controlled through `--disable_metrics` and `--enable_metrics` parameters with option `percpu`, e.g.: - `--disable_metrics="percpu"` - core perf events are aggregated - `--disable_metrics=""` - core perf events are exposed per CPU. It's possible to get "too many opened files" error when a lot of perf events are exposed per CPU. This happens because of passing system limits. Try to increase max number of file desctriptors with `ulimit -n `. Aggregated form of core perf events significantly decrease volume of data. For aggregated form of core perf events scaling ratio (`container_perf_metric_scaling ratio`) indicates the lowest value of scaling ratio for specific event to show the worst precision. ### Perf subsystem introduction One of the goals of kernel perf subsystem is to instrument CPU performance counters that allow to profile applications. Profiling is performed by setting up performance counters that count hardware events (e.g. number of retired instructions, number of cache misses). The counters are CPU hardware registers and amount of them is limited. Other goals of perf subsystem (such as tracing) are beyond the scope of this documentation and you can follow Further Reading section below to learn more about them. Familiarize yourself with following perf-event-related terms: * `multiplexing` - 2nd Generation Intel® Xeon® Scalable Processors provides 4 counters per each hyper thread. If number of configured events is greater than number of available counters then Linux will multiplex counting and some (or even all) of the events will not be accounted for all the time. In such situation information about amount of time that event was accounted for and amount of time when event was enabled is provided. Counter value that cAdvisor exposes is scaled automatically. * `grouping` - in scenario when accounted for events are used to calculate derivative metrics, it is reasonable to measure them in transactional manner: all the events in a group must be accounted for in the same period of time. Keep in mind that it is impossible to group more events that there are counters available. * `uncore events` - events which can be counted by PMUs outside core. * `PMU` - Performance Monitoring Unit #### Getting config values Using perf tools: * Identify the event in `perf list` output. * Execute command: `perf stat -I 5000 -vvv -e EVENT_NAME` * Find `perf_event_attr` section on `perf stat` output, copy config and type field to configuration file. ``` ------------------------------------------------------------ perf_event_attr: type 18 size 112 config 0x304 sample_type IDENTIFIER read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING disabled 1 inherit 1 exclude_guest 1 ------------------------------------------------------------ ``` * Configuration file should look like: ```json { "core": { "events": [ "event_name" ], "custom_events": [ { "type": 18, "config": [ "0x304" ], "name": "event_name" } ] }, "uncore": { "events": [ "event_name" ], "custom_events": [ { "type": 18, "config": [ "0x304" ], "name": "event_name" } ] } } ``` Config values can be also obtain from: * [Intel® 64 and IA32 Architectures Performance Monitoring Events](https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia32-architectures-performance-monitoring-events.html) ##### Uncore Events configuration Uncore Event name should be in form `PMU_PREFIX/event_name` where **PMU_PREFIX** mean that statistics would be counted on all PMUs with that prefix in name. Let's explain this by example: ```json { "uncore": { "events": [ "uncore_imc/cas_count_read", "uncore_imc_0/cas_count_write", "cas_count_all" ], "custom_events": [ { "config": [ "0x304" ], "name": "uncore_imc_0/cas_count_write" }, { "type": 19, "config": [ "0x304" ], "name": "cas_count_all" } ] } } ``` - `uncore_imc/cas_count_read` - because of `uncore_imc` type and no entry in custom events, it would be counted by **all** Integrated Memory Controller PMUs with config provided from libpfm package. (using this function: https://man7.org/linux/man-pages/man3/pfm_get_os_event_encoding.3.html) - `uncore_imc_0/cas_count_write` - because of `uncore_imc_0` type and entry in custom events it would be counted by `uncore_imc_0` PMU with provided config. - `uncore_imc_1/cas_count_all` - because of entry in custom events with type field, event would be counted by PMU with **19** type and provided config. #### Configuring perf events by name It is possible to configure perf events by names using events supported in [libpfm4](http://perfmon2.sourceforge.net/), for detailed information please see [libpfm4 documentation](http://perfmon2.sourceforge.net/docs_v4.html). Discovery of perf events supported on platform can be made using python script - [pmu.py](https://sourceforge.net/p/perfmon2/libpfm4/ci/master/tree/python/src/pmu.py) provided with libpfm4, please see [script reqirements](https://sourceforge.net/p/perfmon2/libpfm4/ci/master/tree/python/README). ##### Example configuration of perf events using event names supported in libpfm4 Example output of `pmu.py`: ``` $ python pmu.py INSTRUCTIONS 1 u 0 k 1 period 3 freq 4 precise 5 excl 6 mg 7 mh 8 cpu 9 pinned 10 INSTRUCTION_RETIRED 192 e 2 i 3 c 4 t 5 intx 7 intxcp 8 u 0 k 1 period 3 freq 4 excl 6 mg 7 mh 8 cpu 9 pinned 10 UNC_M_CAS_COUNT 4 RD 3 WR 12 e 0 i 1 t 2 period 3 freq 4 excl 6 cpu 9 pinned 10 ``` and perf events configuration for listed events: ```json { "core": { "events": [ "instructions", "instruction_retired" ] }, "uncore": { "events": [ "uncore_imc/unc_m_cas_count:rd", "uncore_imc/unc_m_cas_count:wr" ] } } ``` Notice: PMU_PREFIX is provided in the same way as for configuration with config values. #### Grouping ```json { "core": { "events": [ ["instructions", "instruction_retired"] ] }, "uncore": { "events": [ ["uncore_imc_0/unc_m_cas_count:rd", "uncore_imc_0/unc_m_cas_count:wr"], ["uncore_imc_1/unc_m_cas_count:rd", "uncore_imc_1/unc_m_cas_count:wr"] ] } } ``` ### Further reading * [perf Examples](http://www.brendangregg.com/perf.html) on Brendan Gregg's blog * [Kernel Perf Wiki](https://perf.wiki.kernel.org/index.php/Main_Page) * `man perf_event_open` * [perf subsystem](https://github.com/torvalds/linux/tree/v5.6/kernel/events) in Linux kernel * [Uncore Performance Monitoring Reference Manuals](https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html#uncore) See example configuration below: ```json { "core": { "events": [ "instructions", "instructions_retired" ], "custom_events": [ { "type": 4, "config": [ "0x5300c0" ], "name": "instructions_retired" } ] }, "uncore": { "events": [ "uncore_imc/cas_count_read" ], "custom_events": [ { "config": [ "0xc04" ], "name": "uncore_imc/cas_count_read" } ] } } ``` In the example above: * `instructions` will be measured as a non-grouped event and is specified using human friendly interface that can be obtained by calling `perf list`. You can use any name that appears in the output of `perf list` command. This is interface that majority of users will rely on. * `instructions_retired` will be measured as non-grouped event and is specified using an advanced API that allows to specify any perf event available (some of them are not named and can't be specified with plain string). Event name should be a human readable string that will become a metric name. * `cas_count_read` will be measured as uncore non-grouped event on all Integrated Memory Controllers Performance Monitoring Units because of unset `type` field and `uncore_imc` prefix. ## Resctrl To gain metrics, cAdvisor creates own monitoring groups with `cadvisor` prefix. Resctrl file system is not hierarchical like cgroups, so users should set `--docker_only` flag to avoid race conditions and unexpected behaviours. ``` --resctrl_interval=0: Resctrl mon groups updating interval. Zero value disables updating mon groups. ``` ## Storage driver specific instructions: * [InfluxDB instructions](storage/influxdb.md). * [ElasticSearch instructions](storage/elasticsearch.md). * [Kafka instructions](storage/kafka.md). * [Prometheus instructions](storage/prometheus.md). ================================================ FILE: docs/storage/README.md ================================================ # cAdvisor Storage Plugins cAdvisor supports exporting stats to various storage driver plugins. To enable a storage driver, set the `-storage_driver` flag. ## Storage drivers - [BigQuery](https://cloud.google.com/bigquery/). See the [documentation](../../storage/bigquery/README.md) for usage. - [ElasticSearch](https://www.elastic.co/). See the [documentation](elasticsearch.md) for usage and examples. - [InfluxDB](https://influxdb.com/). See the [documentation](influxdb.md) for usage and examples. - [Kafka](http://kafka.apache.org/). See the [documentation](kafka.md) for usage. - [Prometheus](https://prometheus.io). See the [documentation](prometheus.md) for usage and examples. - [Redis](http://redis.io/) - [StatsD](https://github.com/etsy/statsd). See the [documentation](statsd.md) for usage and examples. - `stdout` - write stats to standard output. ================================================ FILE: docs/storage/elasticsearch.md ================================================ # Exporting cAdvisor Stats to ElasticSearch cAdvisor supports exporting stats to [ElasticSearch](https://www.elastic.co/). To use ES, you need to provide the additional flags to cAdvisor: Set the storage driver as ES: ``` -storage_driver=elasticsearch ``` Specify ES host address: ``` -storage_driver_es_host="http://elasticsearch:9200" ``` There are also optional flags: ``` # ElasticSearch type name. By default it's "stats". -storage_driver_es_type="stats" # ElasticSearch can use a sniffing process to find all nodes of your cluster automatically. False by default. -storage_driver_es_enable_sniffer=false ``` # Examples For a detailed tutorial, see [docker-elk-cadvisor-dashboards](https://github.com/gregbkr/docker-elk-cadvisor-dashboards) ================================================ FILE: docs/storage/influxdb.md ================================================ # Exporting cAdvisor Stats to InfluxDB cAdvisor supports exporting stats to [InfluxDB](http://influxdb.com). To use InfluxDB, you need to pass some additional flags to cAdvisor telling it where the InfluxDB instance is located: Set the storage driver as InfluxDB. ``` -storage_driver=influxdb ``` Specify what InfluxDB instance to push data to: ``` # The *ip:port* of the database. Default is 'localhost:8086' -storage_driver_host=ip:port # database name. Uses db 'cadvisor' by default -storage_driver_db # database username. Default is 'root' -storage_driver_user # database password. Default is 'root' -storage_driver_password # Use secure connection with database. False by default -storage_driver_secure # Writes will be buffered for this duration, and committed to the non memory backends as a single transaction. Default is '60s' -storage_driver_buffer_duration # retention policy. Default is '' which corresponds to the default retention policy of the influxdb database -storage_driver_influxdb_retention_policy ``` # Examples [Brian Christner](https://www.brianchristner.io) wrote a detailed post on [setting up Docker monitoring](https://www.brianchristner.io/how-to-setup-docker-monitoring) with cAdvisor and Influxdb. A docker compose configuration for setting up cadvisor-influxdb-grafana can be found [here](https://github.com/dalekurt/docker-monitoring/blob/master/docker-compose.yml). ================================================ FILE: docs/storage/kafka.md ================================================ # Exporting cAdvisor Stats to Kafka cAdvisor supports exporting stats to [Kafka](http://kafka.apache.org/). To use Kafka, you need to provide the additional flags to cAdvisor: Set the storage driver as Kafka: ``` -storage_driver=kafka ``` If no broker are provided it will default to a broker listening at localhost:9092, with 'stats' as the default topic. Specify a Kafka broker address: ``` -storage_driver_kafka_broker_list=localhost:9092 ``` Specify a Kafka topic: ``` -storage_driver_kafka_topic=myTopic ``` As of version 9.0. Kafka supports TLS client auth: ``` # To enable TLS client auth support you need to provide the following: # Location to Certificate Authority certificate -storage_driver_kafka_ssl_ca=/path/to/ca.pem # Location to client certificate certificate -storage_driver_kafka_ssl_cert=/path/to/client_cert.pem # Location to client certificate key -storage_driver_kafka_ssl_key=/path/to/client_key.pem # Verify SSL certificate chain (default: true) -storage_driver_kafka_ssl_verify=false ``` ================================================ FILE: docs/storage/prometheus.md ================================================ # Monitoring cAdvisor with Prometheus cAdvisor exposes container and hardware statistics as [Prometheus](https://prometheus.io) metrics out of the box. By default, these metrics are served under the `/metrics` HTTP endpoint. This endpoint may be customized by setting the `-prometheus_endpoint` and `-disable_metrics` or `-enable_metrics` command-line flags. To collect some of metrics it is required to build cAdvisor with additional flags, for details see [build instructions](../development/build.md), additional flags are indicated in "additional build flag" column in table below. To monitor cAdvisor with Prometheus, simply configure one or more jobs in Prometheus which scrape the relevant cAdvisor processes at that metrics endpoint. For details, see Prometheus's [Configuration](https://prometheus.io/docs/operating/configuration/) documentation, as well as the [Getting started](https://prometheus.io/docs/introduction/getting_started/) guide. # Examples * [CenturyLink Labs](https://labs.ctl.io/) did an excellent write up on [Monitoring Docker services with Prometheus +cAdvisor](https://www.ctl.io/developers/blog/post/monitoring-docker-services-with-prometheus/), while it is great to get a better overview of cAdvisor integration with Prometheus, the PromDash GUI part is outdated as it has been deprecated for Grafana. * [vegasbrianc](https://github.com/vegasbrianc) provides a [starter project](https://github.com/vegasbrianc/prometheus) for cAdvisor and Prometheus monitoring, alongide a ready-to-use [Grafana dashboard](https://github.com/vegasbrianc/grafana_dashboard). ## Prometheus container metrics The table below lists the Prometheus container metrics exposed by cAdvisor (in alphabetical order by metric name) and corresponding `-disable_metrics` / `-enable_metrics` option parameter: Metric name | Type | Description | Unit (where applicable) | option parameter | additional build flag | :-----------|:-----|:------------|:------------------------|:---------------------------|:---------------------- `container_blkio_device_usage_total` | Counter | Blkio device bytes usage | bytes | diskIO | `container_cpu_cfs_periods_total` | Counter | Number of elapsed enforcement period intervals | | cpu | `container_cpu_cfs_throttled_periods_total` | Counter | Number of throttled period intervals | | cpu | `container_cpu_cfs_throttled_seconds_total` | Counter | Total time duration the container has been throttled | seconds | cpu | `container_cpu_load_average_10s` | Gauge | Value of container cpu load average over the last 10 seconds | | cpuLoad | `container_cpu_schedstat_run_periods_total` | Counter | Number of times processes of the cgroup have run on the cpu | | sched | `container_cpu_schedstat_runqueue_seconds_total` | Counter | Time duration processes of the container have been waiting on a runqueue | seconds | sched | `container_cpu_schedstat_run_seconds_total` | Counter | Time duration the processes of the container have run on the CPU | seconds | sched | `container_cpu_system_seconds_total` | Counter | Cumulative system cpu time consumed | seconds | cpu | `container_cpu_usage_seconds_total` | Counter | Cumulative cpu time consumed | seconds | cpu | `container_cpu_user_seconds_total` | Counter | Cumulative user cpu time consumed | seconds | cpu | `container_file_descriptors` | Gauge | Number of open file descriptors for the container | | process | `container_fs_inodes_free` | Gauge | Number of available Inodes | | disk | `container_fs_inodes_total` | Gauge | Total number of Inodes | | disk | `container_fs_io_current` | Gauge | Number of I/Os currently in progress | | diskIO | `container_fs_io_time_seconds_total` | Counter | Cumulative count of seconds spent doing I/Os | seconds | diskIO | `container_fs_io_time_weighted_seconds_total` | Counter | Cumulative weighted I/O time | seconds | diskIO | `container_fs_limit_bytes` | Gauge | Number of bytes that can be consumed by the container on this filesystem | bytes | disk | `container_fs_reads_bytes_total` | Counter | Cumulative count of bytes read | bytes | diskIO | `container_fs_read_seconds_total` | Counter | Cumulative count of seconds spent reading | | diskIO | `container_fs_reads_merged_total` | Counter | Cumulative count of reads merged | | diskIO | `container_fs_reads_total` | Counter | Cumulative count of reads completed | | diskIO | `container_fs_sector_reads_total` | Counter | Cumulative count of sector reads completed | | diskIO | `container_fs_sector_writes_total` | Counter | Cumulative count of sector writes completed | | diskIO | `container_fs_usage_bytes` | Gauge | Number of bytes that are consumed by the container on this filesystem | bytes | disk | `container_fs_writes_bytes_total` | Counter | Cumulative count of bytes written | bytes | diskIO | `container_fs_write_seconds_total` | Counter | Cumulative count of seconds spent writing | seconds | diskIO | `container_fs_writes_merged_total` | Counter | Cumulative count of writes merged | | diskIO | `container_fs_writes_total` | Counter | Cumulative count of writes completed | | diskIO | `container_health_state` | Gauge | State of the health check probe | | - | `container_hugetlb_failcnt` | Counter | Number of hugepage usage hits limits | | hugetlb | `container_hugetlb_max_usage_bytes` | Gauge | Maximum hugepage usages recorded | bytes | hugetlb | `container_hugetlb_usage_bytes` | Gauge | Current hugepage usage | bytes | hugetlb | `container_last_seen` | Gauge | Last time a container was seen by the exporter | timestamp | - | `container_llc_occupancy_bytes` | Gauge | Last level cache usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM). | bytes | resctrl | `container_memory_bandwidth_bytes` | Gauge | Total memory bandwidth usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM). | bytes | resctrl | `container_memory_bandwidth_local_bytes` | Gauge | Local memory bandwidth usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM). | bytes | resctrl | `container_memory_cache` | Gauge | Total page cache memory | bytes | memory | `container_memory_failcnt` | Counter | Number of memory usage hits limits | | memory | `container_memory_failures_total` | Counter | Cumulative count of memory allocation failures | | memory | `container_memory_mapped_file` | Gauge | Size of memory mapped files | bytes | memory | `container_memory_max_usage_bytes` | Gauge | Maximum memory usage recorded | bytes | memory | `container_memory_migrate` | Gauge | Memory migrate status | | cpuset | `container_memory_numa_pages` | Gauge | Number of used pages per NUMA node | | memory_numa | `container_memory_rss` | Gauge | Size of RSS | bytes | memory | `container_memory_swap` | Gauge | Container swap usage | bytes | memory | `container_memory_usage_bytes` | Gauge | Current memory usage, including all memory regardless of when it was accessed | bytes | memory | `container_memory_working_set_bytes` | Gauge | Current working set | bytes | memory | `container_network_advance_tcp_stats_total` | Gauge | advanced tcp connections statistic for container | | advtcp | `container_network_receive_bytes_total` | Counter | Cumulative count of bytes received | bytes | network | `container_network_receive_errors_total` | Counter | Cumulative count of errors encountered while receiving | | network | `container_network_receive_packets_dropped_total` | Counter | Cumulative count of packets dropped while receiving | | network | `container_network_receive_packets_total` | Counter | Cumulative count of packets received | | network | `container_network_tcp6_usage_total` | Gauge | tcp6 connection usage statistic for container | | tcp | `container_network_tcp_usage_total` | Gauge | tcp connection usage statistic for container | | tcp | `container_network_transmit_bytes_total` | Counter | Cumulative count of bytes transmitted | bytes | network | `container_network_transmit_errors_total` | Counter | Cumulative count of errors encountered while transmitting | | network | `container_network_transmit_packets_dropped_total` | Counter | Cumulative count of packets dropped while transmitting | | network | `container_network_transmit_packets_total` | Counter | Cumulative count of packets transmitted | | network | `container_network_udp6_usage_total` | Gauge | udp6 connection usage statistic for container | | udp | `container_network_udp_usage_total` | Gauge | udp connection usage statistic for container | | udp | `container_oom_events_total` | Counter | Count of out of memory events observed for the container | | oom_event | `container_perf_events_scaling_ratio` | Gauge | Scaling ratio for perf event counter (event can be identified by `event` label and `cpu` indicates the core for which event was measured). See [perf event configuration](../runtime_options.md#perf-events). | | perf_event | libpfm `container_perf_events_total` | Counter | Scaled counter of perf core event (event can be identified by `event` label and `cpu` indicates the core for which event was measured). See [perf event configuration](../runtime_options.md#perf-events). | | perf_event | libpfm `container_perf_uncore_events_scaling_ratio` | Gauge | Scaling ratio for perf uncore event counter (event can be identified by `event` label, `pmu` and `socket` lables indicate the PMU and the CPU socket for which event was measured). See [perf event configuration](../runtime_options.md#perf-events). Metric exists only for main cgroup (id="/"). | | perf_event | libpfm `container_perf_uncore_events_total` | Counter | Scaled counter of perf uncore event (event can be identified by `event` label, `pmu` and `socket` lables indicate the PMU and the CPU socket for which event was measured). See [perf event configuration](../runtime_options.md#perf-events)). Metric exists only for main cgroup (id="/").| | perf_event | libpfm `container_processes` | Gauge | Number of processes running inside the container | | process | `container_referenced_bytes` | Gauge | Container referenced bytes during last measurements cycle based on Referenced field in /proc/smaps file, with /proc/PIDs/clear_refs set to 1 after defined number of cycles configured through `referenced_reset_interval` cAdvisor parameter.
    Warning: this is intrusive collection because can influence kernel page reclaim policy and add latency. Refer to https://github.com/brendangregg/wss#wsspl-referenced-page-flag for more details. | bytes | referenced_memory | `container_sockets` | Gauge | Number of open sockets for the container | | process | `container_spec_cpu_period` | Gauge | CPU period of the container | | - | `container_spec_cpu_quota` | Gauge | CPU quota of the container | | - | `container_spec_cpu_shares` | Gauge | CPU share of the container | | - | `container_spec_memory_limit_bytes` | Gauge | Memory limit for the container | bytes | - | `container_spec_memory_reservation_limit_bytes` | Gauge | Memory reservation limit for the container | bytes | | `container_spec_memory_swap_limit_bytes` | Gauge | Memory swap limit for the container | bytes | | `container_start_time_seconds` | Gauge | Start time of the container since unix epoch | seconds | | `container_tasks_state` | Gauge | Number of tasks in given state (`sleeping`, `running`, `stopped`, `uninterruptible`, or `ioawaiting`) | | cpuLoad | `container_threads` | Gauge | Number of threads running inside the container | | process | `container_threads_max` | Gauge | Maximum number of threads allowed inside the container | | process | `container_ulimits_soft` | Gauge | Soft ulimit values for the container root process. Unlimited if -1, except priority and nice | | process | ## Prometheus hardware metrics The table below lists the Prometheus hardware metrics exposed by cAdvisor (in alphabetical order by metric name) and corresponding `-disable_metrics` / `-enable_metrics` option parameter: Metric name | Type | Description | Unit (where applicable) | option parameter | additional build flag | :-----------|:-----|:------------|:------------------------|:---------------------------|:-------------------- `machine_cpu_cache_capacity_bytes` | Gauge | Cache size in bytes assigned to NUMA node and CPU core | bytes | cpu_topology | `machine_cpu_cores` | Gauge | Number of logical CPU cores | | | `machine_cpu_physical_cores` | Gauge | Number of physical CPU cores | | | `machine_cpu_sockets` | Gauge | Number of CPU sockets | | | `machine_dimm_capacity_bytes` | Gauge | Total RAM DIMM capacity (all types memory modules) value labeled by dimm type,
    information is retrieved from sysfs edac per-DIMM API (/sys/devices/system/edac/mc/) introduced in kernel 3.6 | bytes | | | `machine_dimm_count` | Gauge | Number of RAM DIMM (all types memory modules) value labeled by dimm type,
    information is retrieved from sysfs edac per-DIMM API (/sys/devices/system/edac/mc/) introduced in kernel 3.6 | | | `machine_memory_bytes` | Gauge | Amount of memory installed on the machine | bytes | | `machine_swap_bytes` | Gauge | Amount of swap memory available on the machine | bytes | | `machine_node_distance` | Gauge | Distance between NUMA node and target NUMA node | | cpu_topology | `machine_node_hugepages_count` | Gauge | Numer of hugepages assigned to NUMA node | | cpu_topology | `machine_node_memory_capacity_bytes` | Gauge | Amount of memory assigned to NUMA node | bytes | cpu_topology | `machine_nvm_avg_power_budget_watts` | Gauge | NVM power budget | watts | | libipmctl `machine_nvm_capacity` | Gauge | NVM capacity value labeled by NVM mode (memory mode or app direct mode) | bytes | | libipmctl `machine_thread_siblings_count` | Gauge | Number of CPU thread siblings | | cpu_topology | ================================================ FILE: docs/storage/statsd.md ================================================ # Exporting cAdvisor Stats to statsd cAdvisor supports exporting stats to [statsd](https://github.com/etsy/statsd). To use statsd, you need to pass some additional flags to cAdvisor telling it where to find statsd: Set the storage driver as statsd. ``` -storage_driver=statsd ``` Specify what statsd instance to push data to: ``` # The *ip:port* of the instance. Default is 'localhost:8086' -storage_driver_host=ip:port ``` # Examples The easiest way to get up an running is to start the cadvisor binary with the `--storage_driver` and `--storage_driver_host` flags. ``` cadvisor --storage_driver="statsd" --storage_driver_host="localhost:8125" ``` The default port for statsd is 8125, so this wil start pumping metrics directly to it. ================================================ FILE: docs/web.md ================================================ # cAdvisor Web UI cAdvisor exposes a web UI at its port: `http://:/` This UI has one primary resource at `/containers` which exports live information about all containers on the machine. ## Web UI authentication You can add authentication to the web UI by either HTTP basic or HTTP digest authentication. NOTE: The Web UI authentication only protects the `/containers` endpoint, and not the other cAdvisor HTTP endpoints such as `/api/...` and `/metrics`. Some of these endpoints can expose sensitive information, so it is not advised to expose these endpoints publicly. ### HTTP basic authentication You will need to add a *http_auth_file* parameter with a HTTP basic auth file generated using htpasswd to enable HTTP basic auth. By default the auth realm is set as localhost. `./cadvisor --http_auth_file test.htpasswd --http_auth_realm localhost` The [test.htpasswd](../test.htpasswd) file provided has a username and password already added (`admin:password1`) for testing purposes. ### HTTP Digest authentication You will need to add a *http_digest_file* parameter with a HTTP digest auth file generated using htdigest to enable HTTP Digest auth. By default the auth realm is set as localhost. `./cadvisor --http_digest_file test.htdigest --http_digest_realm localhost` The [test.htdigest](../test.htdigest) file provided has a username and password already added (`admin:password1`) for testing purposes. **Note** : You can use either type of authentication, in case you decide to use both files in the arguments only HTTP basic auth will be enabled. ================================================ FILE: events/handler.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package events import ( "errors" "sort" "strings" "sync" "time" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/utils" "k8s.io/klog/v2" ) type byTimestamp []*info.Event // functions necessary to implement the sort interface on the Events struct func (e byTimestamp) Len() int { return len(e) } func (e byTimestamp) Swap(i, j int) { e[i], e[j] = e[j], e[i] } func (e byTimestamp) Less(i, j int) bool { return e[i].Timestamp.Before(e[j].Timestamp) } type EventChannel struct { // Watch ID. Can be used by the caller to request cancellation of watch events. watchID int // Channel on which the caller can receive watch events. channel chan *info.Event } // Request holds a set of parameters by which Event objects may be screened. // The caller may want events that occurred within a specific timeframe // or of a certain type, which may be specified in the *Request object // they pass to an EventManager function type Request struct { // events falling before StartTime do not satisfy the request. StartTime // must be left blank in calls to WatchEvents StartTime time.Time // events falling after EndTime do not satisfy the request. EndTime // must be left blank in calls to WatchEvents EndTime time.Time // EventType is a map that specifies the type(s) of events wanted EventType map[info.EventType]bool // allows the caller to put a limit on how many // events to receive. If there are more events than MaxEventsReturned // then the most chronologically recent events in the time period // specified are returned. Must be >= 1 MaxEventsReturned int // the absolute container name for which the event occurred ContainerName string // if IncludeSubcontainers is false, only events occurring in the specific // container, and not the subcontainers, will be returned IncludeSubcontainers bool } // EventManager is implemented by Events. It provides two ways to monitor // events and one way to add events type EventManager interface { // WatchEvents() allows a caller to register for receiving events based on the specified request. // On successful registration, an EventChannel object is returned. WatchEvents(request *Request) (*EventChannel, error) // GetEvents() returns all detected events based on the filters specified in request. GetEvents(request *Request) ([]*info.Event, error) // AddEvent allows the caller to add an event to an EventManager // object AddEvent(event *info.Event) error // Cancels a previously requested watch event. StopWatch(watchID int) } // events provides an implementation for the EventManager interface. type events struct { // eventStore holds the events by event type. eventStore map[info.EventType]*utils.TimedStore // map of registered watchers keyed by watch id. watchers map[int]*watch // lock guarding the eventStore. eventsLock sync.RWMutex // lock guarding watchers. watcherLock sync.RWMutex // last allocated watch id. lastID int // Event storage policy. storagePolicy StoragePolicy } // initialized by a call to WatchEvents(), a watch struct will then be added // to the events slice of *watch objects. When AddEvent() finds an event that // satisfies the request parameter of a watch object in events.watchers, // it will send that event out over the watch object's channel. The caller that // called WatchEvents will receive the event over the channel provided to // WatchEvents type watch struct { // request parameters passed in by the caller of WatchEvents() request *Request // a channel used to send event back to the caller. eventChannel *EventChannel } func NewEventChannel(watchID int) *EventChannel { return &EventChannel{ watchID: watchID, channel: make(chan *info.Event, 10), } } // Policy specifying how many events to store. // MaxAge is the max duration for which to keep events. // MaxNumEvents is the max number of events to keep (-1 for no limit). type StoragePolicy struct { // Defaults limites, used if a per-event limit is not set. DefaultMaxAge time.Duration DefaultMaxNumEvents int // Per-event type limits. PerTypeMaxAge map[info.EventType]time.Duration PerTypeMaxNumEvents map[info.EventType]int } func DefaultStoragePolicy() StoragePolicy { return StoragePolicy{ DefaultMaxAge: 24 * time.Hour, DefaultMaxNumEvents: 100000, PerTypeMaxAge: make(map[info.EventType]time.Duration), PerTypeMaxNumEvents: make(map[info.EventType]int), } } // returns a pointer to an initialized Events object. func NewEventManager(storagePolicy StoragePolicy) EventManager { return &events{ eventStore: make(map[info.EventType]*utils.TimedStore), watchers: make(map[int]*watch), storagePolicy: storagePolicy, } } // returns a pointer to an initialized Request object func NewRequest() *Request { return &Request{ EventType: map[info.EventType]bool{}, IncludeSubcontainers: false, MaxEventsReturned: 10, } } // returns a pointer to an initialized watch object func newWatch(request *Request, eventChannel *EventChannel) *watch { return &watch{ request: request, eventChannel: eventChannel, } } func (ch *EventChannel) GetChannel() chan *info.Event { return ch.channel } func (ch *EventChannel) GetWatchId() int { return ch.watchID } // sorts and returns up to the last MaxEventsReturned chronological elements func getMaxEventsReturned(request *Request, eSlice []*info.Event) []*info.Event { sort.Sort(byTimestamp(eSlice)) n := request.MaxEventsReturned if n >= len(eSlice) || n <= 0 { return eSlice } return eSlice[len(eSlice)-n:] } // If the request wants all subcontainers, this returns if the request's // container path is a prefix of the event container path. Otherwise, // it checks that the container paths of the event and request are // equivalent func isSubcontainer(request *Request, event *info.Event) bool { if request.IncludeSubcontainers { return request.ContainerName == "/" || strings.HasPrefix(event.ContainerName+"/", request.ContainerName+"/") } return event.ContainerName == request.ContainerName } // determines if an event occurs within the time set in the request object and is the right type func checkIfEventSatisfiesRequest(request *Request, event *info.Event) bool { startTime := request.StartTime endTime := request.EndTime eventTime := event.Timestamp if !startTime.IsZero() { if startTime.After(eventTime) { return false } } if !endTime.IsZero() { if endTime.Before(eventTime) { return false } } if !request.EventType[event.EventType] { return false } if request.ContainerName != "" { return isSubcontainer(request, event) } return true } // method of Events object that screens Event objects found in the eventStore // attribute and if they fit the parameters passed by the Request object, // adds it to a slice of *Event objects that is returned. If both MaxEventsReturned // and StartTime/EndTime are specified in the request object, then only // up to the most recent MaxEventsReturned events in that time range are returned. func (e *events) GetEvents(request *Request) ([]*info.Event, error) { returnEventList := []*info.Event{} e.eventsLock.RLock() defer e.eventsLock.RUnlock() for eventType, fetch := range request.EventType { if !fetch { continue } evs, ok := e.eventStore[eventType] if !ok { continue } res := evs.InTimeRange(request.StartTime, request.EndTime, request.MaxEventsReturned) for _, in := range res { e := in.(*info.Event) if checkIfEventSatisfiesRequest(request, e) { returnEventList = append(returnEventList, e) } } } returnEventList = getMaxEventsReturned(request, returnEventList) return returnEventList, nil } // method of Events object that maintains an *Event channel passed by the user. // When an event is added by AddEvents that satisfies the parameters in the passed // Request object it is fed to the channel. The StartTime and EndTime of the watch // request should be uninitialized because the purpose is to watch indefinitely // for events that will happen in the future func (e *events) WatchEvents(request *Request) (*EventChannel, error) { if !request.StartTime.IsZero() || !request.EndTime.IsZero() { return nil, errors.New( "for a call to watch, request.StartTime and request.EndTime must be uninitialized") } e.watcherLock.Lock() defer e.watcherLock.Unlock() newID := e.lastID + 1 returnEventChannel := NewEventChannel(newID) newWatcher := newWatch(request, returnEventChannel) e.watchers[newID] = newWatcher e.lastID = newID return returnEventChannel, nil } // helper function to update the event manager's eventStore func (e *events) updateEventStore(event *info.Event) { e.eventsLock.Lock() defer e.eventsLock.Unlock() if _, ok := e.eventStore[event.EventType]; !ok { maxNumEvents := e.storagePolicy.DefaultMaxNumEvents if numEvents, ok := e.storagePolicy.PerTypeMaxNumEvents[event.EventType]; ok { maxNumEvents = numEvents } if maxNumEvents == 0 { // Event storage is disabled for event.EventType return } maxAge := e.storagePolicy.DefaultMaxAge if age, ok := e.storagePolicy.PerTypeMaxAge[event.EventType]; ok { maxAge = age } e.eventStore[event.EventType] = utils.NewTimedStore(maxAge, maxNumEvents) } e.eventStore[event.EventType].Add(event.Timestamp, event) } func (e *events) findValidWatchers(event *info.Event) []*watch { watchesToSend := make([]*watch, 0) for _, watcher := range e.watchers { watchRequest := watcher.request if checkIfEventSatisfiesRequest(watchRequest, event) { watchesToSend = append(watchesToSend, watcher) } } return watchesToSend } // method of Events object that adds the argument Event object to the // eventStore. It also feeds the event to a set of watch channels // held by the manager if it satisfies the request keys of the channels func (e *events) AddEvent(event *info.Event) error { e.updateEventStore(event) e.watcherLock.RLock() defer e.watcherLock.RUnlock() watchesToSend := e.findValidWatchers(event) for _, watchObject := range watchesToSend { watchObject.eventChannel.GetChannel() <- event } klog.V(4).Infof("Added event %v", event) return nil } // Removes a watch instance from the EventManager's watchers map func (e *events) StopWatch(watchID int) { e.watcherLock.Lock() defer e.watcherLock.Unlock() _, ok := e.watchers[watchID] if !ok { klog.Errorf("Could not find watcher instance %v", watchID) } close(e.watchers[watchID].eventChannel.GetChannel()) delete(e.watchers, watchID) } ================================================ FILE: events/handler_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package events import ( "testing" "time" info "github.com/google/cadvisor/info/v1" "github.com/stretchr/testify/assert" ) func createOldTime(t *testing.T) time.Time { const longForm = "Jan 2, 2006 at 3:04pm (MST)" linetime, err := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)") if err != nil { t.Fatalf("could not format time.Time object") } else { return linetime } return time.Now() } // used to convert an OomInstance to an Event object func makeEvent(inTime time.Time, containerName string) *info.Event { return &info.Event{ ContainerName: containerName, Timestamp: inTime, EventType: info.EventOom, } } // returns EventManager and Request to use in tests func initializeScenario(t *testing.T) (EventManager, *Request, *info.Event, *info.Event) { fakeEvent := makeEvent(createOldTime(t), "/") fakeEvent2 := makeEvent(time.Now(), "/") manager := NewEventManager(DefaultStoragePolicy()) return manager, NewRequest(), fakeEvent, fakeEvent2 } func TestIsSubcontainer(t *testing.T) { myRequest := NewRequest() myRequest.ContainerName = "/root" rootRequest := NewRequest() rootRequest.ContainerName = "/" sameContainerEvent := &info.Event{ ContainerName: "/root", } subContainerEvent := &info.Event{ ContainerName: "/root/subdir", } differentContainerEvent := &info.Event{ ContainerName: "/root-completely-different-container", } if isSubcontainer(rootRequest, sameContainerEvent) { t.Errorf("should not have found %v to be a subcontainer of %v", sameContainerEvent, rootRequest) } if !isSubcontainer(myRequest, sameContainerEvent) { t.Errorf("should have found %v and %v had the same container name", myRequest, sameContainerEvent) } if isSubcontainer(myRequest, subContainerEvent) { t.Errorf("should have found %v and %v had different containers", myRequest, subContainerEvent) } rootRequest.IncludeSubcontainers = true myRequest.IncludeSubcontainers = true if !isSubcontainer(rootRequest, sameContainerEvent) { t.Errorf("should have found %v to be a subcontainer of %v", sameContainerEvent.ContainerName, rootRequest.ContainerName) } if !isSubcontainer(myRequest, sameContainerEvent) { t.Errorf("should have found %v and %v had the same container", myRequest.ContainerName, sameContainerEvent.ContainerName) } if !isSubcontainer(myRequest, subContainerEvent) { t.Errorf("should have found %v was a subcontainer of %v", subContainerEvent.ContainerName, myRequest.ContainerName) } if isSubcontainer(myRequest, differentContainerEvent) { t.Errorf("should have found %v and %v had different containers", myRequest.ContainerName, differentContainerEvent.ContainerName) } } func TestWatchEventsDetectsNewEvents(t *testing.T) { myEventHolder, myRequest, fakeEvent, fakeEvent2 := initializeScenario(t) myRequest.EventType[info.EventOom] = true returnEventChannel, err := myEventHolder.WatchEvents(myRequest) assert.NoError(t, err) err = myEventHolder.AddEvent(fakeEvent) assert.NoError(t, err) err = myEventHolder.AddEvent(fakeEvent2) assert.NoError(t, err) startTime := time.Now() go func() { time.Sleep(5 * time.Second) if time.Since(startTime) > (5 * time.Second) { t.Errorf("Took too long to receive all the events") } }() eventsFound := 0 go func() { for event := range returnEventChannel.GetChannel() { eventsFound++ if eventsFound == 1 { assert.Equal(t, fakeEvent, event) } else if eventsFound == 2 { assert.Equal(t, fakeEvent2, event) break } } }() } func TestAddEventAddsEventsToEventManager(t *testing.T) { myEventHolder, _, fakeEvent, _ := initializeScenario(t) err := myEventHolder.AddEvent(fakeEvent) assert.NoError(t, err) events, err := myEventHolder.GetEvents(&Request{ EventType: map[info.EventType]bool{info.EventOom: true}, MaxEventsReturned: -1, }) assert.NoError(t, err) assert.Len(t, events, 1) assert.Equal(t, fakeEvent, events[0]) } func TestGetEventsForOneEvent(t *testing.T) { myEventHolder, myRequest, fakeEvent, fakeEvent2 := initializeScenario(t) myRequest.MaxEventsReturned = 1 myRequest.EventType[info.EventOom] = true err := myEventHolder.AddEvent(fakeEvent) assert.NoError(t, err) err = myEventHolder.AddEvent(fakeEvent2) assert.NoError(t, err) receivedEvents, err := myEventHolder.GetEvents(myRequest) assert.NoError(t, err) assert.Len(t, receivedEvents, 1) assert.Equal(t, fakeEvent2, receivedEvents[0]) } func TestGetEventsForTimePeriod(t *testing.T) { myEventHolder, myRequest, fakeEvent, fakeEvent2 := initializeScenario(t) myRequest.StartTime = time.Now().Add(-1 * time.Second * 10) myRequest.EndTime = time.Now().Add(time.Second * 10) myRequest.EventType[info.EventOom] = true err := myEventHolder.AddEvent(fakeEvent) assert.NoError(t, err) err = myEventHolder.AddEvent(fakeEvent2) assert.NoError(t, err) receivedEvents, err := myEventHolder.GetEvents(myRequest) assert.NoError(t, err) assert.Len(t, receivedEvents, 1) assert.Equal(t, fakeEvent2, receivedEvents[0]) } func TestGetEventsForNoTypeRequested(t *testing.T) { myEventHolder, myRequest, fakeEvent, fakeEvent2 := initializeScenario(t) err := myEventHolder.AddEvent(fakeEvent) assert.NoError(t, err) err = myEventHolder.AddEvent(fakeEvent2) assert.NoError(t, err) receivedEvents, err := myEventHolder.GetEvents(myRequest) assert.NoError(t, err) assert.Len(t, receivedEvents, 0) } ================================================ FILE: fs/btrfs/install/install.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package install import ( "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/btrfs" "k8s.io/klog/v2" ) func init() { err := fs.RegisterPlugin("btrfs", btrfs.NewPlugin()) if err != nil { klog.Fatalf("Failed to register btrfs fs plugin: %v", err) } } ================================================ FILE: fs/btrfs/mount.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package btrfs import ( "fmt" "syscall" mount "github.com/moby/sys/mountinfo" "k8s.io/klog/v2" ) // major extracts the major device number from a device number. func major(devNumber uint64) uint { return uint((devNumber >> 8) & 0xfff) } // minor extracts the minor device number from a device number. func minor(devNumber uint64) uint { return uint((devNumber & 0xff) | ((devNumber >> 12) & 0xfff00)) } // GetBtrfsMajorMinorIds gets the major and minor device IDs for a btrfs mount point. // This is a workaround for wrong btrfs Major and Minor Ids reported in /proc/self/mountinfo. // Instead of using values from /proc/self/mountinfo we use stat to get Ids from btrfs mount point. func GetBtrfsMajorMinorIds(mnt *mount.Info) (int, int, error) { buf := new(syscall.Stat_t) err := syscall.Stat(mnt.Source, buf) if err != nil { err = fmt.Errorf("stat failed on %s with error: %s", mnt.Source, err) return 0, 0, err } klog.V(4).Infof("btrfs mount %#v", mnt) if buf.Mode&syscall.S_IFMT == syscall.S_IFBLK { err := syscall.Stat(mnt.Mountpoint, buf) if err != nil { err = fmt.Errorf("stat failed on %s with error: %s", mnt.Mountpoint, err) return 0, 0, err } // The type Dev and Rdev in Stat_t are 32bit on mips. klog.V(4).Infof("btrfs dev major:minor %d:%d\n", int(major(uint64(buf.Dev))), int(minor(uint64(buf.Dev)))) // nolint: unconvert klog.V(4).Infof("btrfs rdev major:minor %d:%d\n", int(major(uint64(buf.Rdev))), int(minor(uint64(buf.Rdev)))) // nolint: unconvert return int(major(uint64(buf.Dev))), int(minor(uint64(buf.Dev))), nil // nolint: unconvert } return 0, 0, fmt.Errorf("%s is not a block device", mnt.Source) } ================================================ FILE: fs/btrfs/plugin.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package btrfs import ( "strings" "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/vfs" mount "github.com/moby/sys/mountinfo" "k8s.io/klog/v2" ) type btrfsPlugin struct{} // NewPlugin creates a new Btrfs filesystem plugin. func NewPlugin() fs.FsPlugin { return &btrfsPlugin{} } func (p *btrfsPlugin) Name() string { return "btrfs" } // CanHandle returns true if the filesystem type is btrfs. func (p *btrfsPlugin) CanHandle(fsType string) bool { return fsType == "btrfs" } // Priority returns 100 - Btrfs has higher priority than VFS. func (p *btrfsPlugin) Priority() int { return 100 } // GetStats returns filesystem statistics for Btrfs. // Btrfs delegates to VFS for stats collection. func (p *btrfsPlugin) GetStats(device string, partition fs.PartitionInfo) (*fs.FsStats, error) { // Btrfs uses VFS stats capacity, free, avail, inodes, inodesFree, err := vfs.GetVfsStats(partition.Mountpoint) if err != nil { return nil, err } return &fs.FsStats{ Capacity: capacity, Free: free, Available: avail, Inodes: &inodes, InodesFree: &inodesFree, Type: fs.VFS, }, nil } // ProcessMount handles Btrfs mount processing. // Btrfs fix: following workaround fixes wrong btrfs Major and Minor Ids reported in /proc/self/mountinfo. // Instead of using values from /proc/self/mountinfo we use stat to get Ids from btrfs mount point. func (p *btrfsPlugin) ProcessMount(mnt *mount.Info) (bool, *mount.Info, error) { // Only apply fix if Major is 0 and Source starts with /dev/ if mnt.Major == 0 && strings.HasPrefix(mnt.Source, "/dev/") { major, minor, err := GetBtrfsMajorMinorIds(mnt) if err != nil { klog.Warningf("%s", err) } else { // Create a copy with corrected values correctedMnt := *mnt correctedMnt.Major = major correctedMnt.Minor = minor return true, &correctedMnt, nil } } return true, mnt, nil } ================================================ FILE: fs/devicemapper/install/install.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package install import ( "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/devicemapper" "k8s.io/klog/v2" ) func init() { err := fs.RegisterPlugin("devicemapper", devicemapper.NewPlugin()) if err != nil { klog.Fatalf("Failed to register devicemapper fs plugin: %v", err) } } ================================================ FILE: fs/devicemapper/plugin.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package devicemapper import ( "github.com/google/cadvisor/fs" mount "github.com/moby/sys/mountinfo" "k8s.io/klog/v2" ) type dmPlugin struct{} // NewPlugin creates a new DeviceMapper filesystem plugin. func NewPlugin() fs.FsPlugin { return &dmPlugin{} } func (p *dmPlugin) Name() string { return "devicemapper" } // CanHandle returns true if the filesystem type is devicemapper. func (p *dmPlugin) CanHandle(fsType string) bool { return fsType == "devicemapper" } // Priority returns 100 - DeviceMapper has higher priority than VFS. func (p *dmPlugin) Priority() int { return 100 } // GetStats returns filesystem statistics for DeviceMapper thin provisioning. func (p *dmPlugin) GetStats(device string, partition fs.PartitionInfo) (*fs.FsStats, error) { capacity, free, avail, err := GetDMStats(device, partition.BlockSize) if err != nil { return nil, err } klog.V(5).Infof("got devicemapper fs capacity stats: capacity: %v free: %v available: %v", capacity, free, avail) return &fs.FsStats{ Capacity: capacity, Free: free, Available: avail, Type: fs.DeviceMapper, }, nil } // ProcessMount handles DeviceMapper mount processing. // For DeviceMapper, no special processing is needed. func (p *dmPlugin) ProcessMount(mnt *mount.Info) (bool, *mount.Info, error) { return true, mnt, nil } ================================================ FILE: fs/devicemapper/stats.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package devicemapper import ( "fmt" "os/exec" "strconv" "strings" dm "github.com/google/cadvisor/devicemapper" ) // GetDMStats returns devicemapper thin provisioning stats. func GetDMStats(poolName string, dataBlkSize uint) (uint64, uint64, uint64, error) { out, err := exec.Command("dmsetup", "status", poolName).Output() if err != nil { return 0, 0, 0, err } used, total, err := parseDMStatus(string(out)) if err != nil { return 0, 0, 0, err } used *= 512 * uint64(dataBlkSize) total *= 512 * uint64(dataBlkSize) free := total - used return total, free, free, nil } // parseDMStatus parses the output of `dmsetup status`. func parseDMStatus(dmStatus string) (uint64, uint64, error) { dmStatus = strings.Replace(dmStatus, "/", " ", -1) dmFields := strings.Fields(dmStatus) if len(dmFields) < 8 { return 0, 0, fmt.Errorf("invalid dmsetup status output: %s", dmStatus) } used, err := strconv.ParseUint(dmFields[6], 10, 64) if err != nil { return 0, 0, err } total, err := strconv.ParseUint(dmFields[7], 10, 64) if err != nil { return 0, 0, err } return used, total, nil } // parseDMTable parses a single line of `dmsetup table` output and returns the // major device, minor device, block size, and an error. func ParseDMTable(dmTable string) (uint, uint, uint, error) { dmTable = strings.Replace(dmTable, ":", " ", -1) dmFields := strings.Fields(dmTable) if len(dmFields) < 8 { return 0, 0, 0, fmt.Errorf("invalid dmsetup status output: %s", dmTable) } major, err := strconv.ParseUint(dmFields[5], 10, 32) if err != nil { return 0, 0, 0, err } minor, err := strconv.ParseUint(dmFields[6], 10, 32) if err != nil { return 0, 0, 0, err } dataBlkSize, err := strconv.ParseUint(dmFields[7], 10, 32) if err != nil { return 0, 0, 0, err } return uint(major), uint(minor), uint(dataBlkSize), nil } // DockerDMDevice returns information about the devicemapper device and "partition" if // docker is using devicemapper for its storage driver. func DockerDMDevice(driverStatus map[string]string, dmsetup dm.DmsetupClient) (string, uint, uint, uint, error) { const driverStatusPoolName = "Pool Name" poolName, ok := driverStatus[driverStatusPoolName] if !ok || len(poolName) == 0 { return "", 0, 0, 0, fmt.Errorf("could not get dm pool name") } out, err := dmsetup.Table(poolName) if err != nil { return "", 0, 0, 0, err } major, minor, dataBlkSize, err := ParseDMTable(string(out)) if err != nil { return "", 0, 0, 0, err } return poolName, major, minor, dataBlkSize, nil } ================================================ FILE: fs/devicemapper/stats_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package devicemapper import ( "testing" ) var dmStatusTests = []struct { dmStatus string used uint64 total uint64 errExpected bool }{ {`0 409534464 thin-pool 64085 3705/4161600 88106/3199488 - rw no_discard_passdown queue_if_no_space -`, 88106, 3199488, false}, {`0 209715200 thin-pool 707 1215/524288 30282/1638400 - rw discard_passdown`, 30282, 1638400, false}, {`Invalid status line`, 0, 0, false}, } func TestParseDMStatus(t *testing.T) { for _, tt := range dmStatusTests { used, total, err := parseDMStatus(tt.dmStatus) if tt.errExpected && err != nil { t.Errorf("parseDMStatus(%q) expected error", tt.dmStatus) } if used != tt.used { t.Errorf("parseDMStatus(%q) wrong used value => %q, want %q", tt.dmStatus, used, tt.used) } if total != tt.total { t.Errorf("parseDMStatus(%q) wrong total value => %q, want %q", tt.dmStatus, total, tt.total) } } } var dmTableTests = []struct { dmTable string major uint minor uint dataBlkSize uint errExpected bool }{ {`0 409534464 thin-pool 253:6 253:7 128 32768 1 skip_block_zeroing`, 253, 7, 128, false}, {`0 409534464 thin-pool 253:6 258:9 512 32768 1 skip_block_zeroing otherstuff`, 258, 9, 512, false}, {`Invalid status line`, 0, 0, 0, false}, } func TestParseDMTable(t *testing.T) { for _, tt := range dmTableTests { major, minor, dataBlkSize, err := ParseDMTable(tt.dmTable) if tt.errExpected && err != nil { t.Errorf("ParseDMTable(%q) expected error", tt.dmTable) } if major != tt.major { t.Errorf("ParseDMTable(%q) wrong major value => %q, want %q", tt.dmTable, major, tt.major) } if minor != tt.minor { t.Errorf("ParseDMTable(%q) wrong minor value => %q, want %q", tt.dmTable, minor, tt.minor) } if dataBlkSize != tt.dataBlkSize { t.Errorf("ParseDMTable(%q) wrong dataBlkSize value => %q, want %q", tt.dmTable, dataBlkSize, tt.dataBlkSize) } } } ================================================ FILE: fs/fs.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Provides Filesystem Stats package fs import ( "bufio" "errors" "fmt" "os" "path" "path/filepath" "regexp" "strconv" "strings" "syscall" mount "github.com/moby/sys/mountinfo" "github.com/google/cadvisor/devicemapper" "k8s.io/klog/v2" ) const ( LabelSystemRoot = "root" LabelDockerImages = "docker-images" LabelCrioImages = "crio-images" LabelCrioContainers = "crio-containers" DriverStatusPoolName = "Pool Name" DriverStatusDataLoopFile = "Data loop file" ) const ( // The block size in bytes. statBlockSize uint64 = 512 // The maximum number of `disk usage` tasks that can be running at once. maxConcurrentOps = 20 ) // A pool for restricting the number of consecutive `du` and `find` tasks running. var pool = make(chan struct{}, maxConcurrentOps) func init() { for i := 0; i < maxConcurrentOps; i++ { releaseToken() } } func claimToken() { <-pool } func releaseToken() { pool <- struct{}{} } type partition struct { mountpoint string major uint minor uint fsType string blockSize uint } type RealFsInfo struct { // Map from block device path to partition information. partitions map[string]partition // Map from label to block device path. // Labels are intent-specific tags that are auto-detected. labels map[string]string // Map from mountpoint to mount information. mounts map[string]mount.Info // devicemapper client dmsetup devicemapper.DmsetupClient // fsUUIDToDeviceName is a map from the filesystem UUID to its device name. fsUUIDToDeviceName map[string]string } func NewFsInfo(context Context) (FsInfo, error) { fileReader, err := os.Open("/proc/self/mountinfo") if err != nil { return nil, err } mounts, err := mount.GetMountsFromReader(fileReader, nil) if err != nil { return nil, err } fsUUIDToDeviceName, err := getFsUUIDToDeviceNameMap() if err != nil { // UUID is not always available across different OS distributions. // Do not fail if there is an error. klog.Warningf("Failed to get disk UUID mapping, getting disk info by uuid will not work: %v", err) } // Avoid devicemapper container mounts - these are tracked by the ThinPoolWatcher excluded := []string{fmt.Sprintf("%s/devicemapper/mnt", context.Docker.Root)} fsInfo := &RealFsInfo{ partitions: processMounts(mounts, excluded), labels: make(map[string]string), mounts: make(map[string]mount.Info), dmsetup: devicemapper.NewDmsetupClient(), fsUUIDToDeviceName: fsUUIDToDeviceName, } for _, mnt := range mounts { fsInfo.mounts[mnt.Mountpoint] = *mnt } // need to call this before the log line below printing out the partitions, as this function may // add a "partition" for devicemapper to fsInfo.partitions fsInfo.addDockerImagesLabel(context, mounts) fsInfo.addCrioImagesLabel(context, mounts) klog.V(1).Infof("Filesystem UUIDs: %+v", fsInfo.fsUUIDToDeviceName) klog.V(1).Infof("Filesystem partitions: %+v", fsInfo.partitions) fsInfo.addSystemRootLabel(mounts) return fsInfo, nil } // getFsUUIDToDeviceNameMap creates the filesystem uuid to device name map // using the information in /dev/disk/by-uuid. If the directory does not exist, // this function will return an empty map. func getFsUUIDToDeviceNameMap() (map[string]string, error) { const dir = "/dev/disk/by-uuid" if _, err := os.Stat(dir); os.IsNotExist(err) { return make(map[string]string), nil } files, err := os.ReadDir(dir) if err != nil { return nil, err } fsUUIDToDeviceName := make(map[string]string) for _, file := range files { fpath := filepath.Join(dir, file.Name()) target, err := os.Readlink(fpath) if err != nil { klog.Warningf("Failed to resolve symlink for %q", fpath) continue } device, err := filepath.Abs(filepath.Join(dir, target)) if err != nil { return nil, fmt.Errorf("failed to resolve the absolute path of %q", filepath.Join(dir, target)) } fsUUIDToDeviceName[file.Name()] = device } return fsUUIDToDeviceName, nil } func processMounts(mounts []*mount.Info, excludedMountpointPrefixes []string) map[string]partition { partitions := make(map[string]partition) for _, mnt := range mounts { // Use plugin system to determine if filesystem is supported plugin := GetPluginForFsType(mnt.FSType) if plugin == nil { continue } // Avoid bind mounts, but allow tmpfs duplicates (handled by plugin's ProcessMount) if _, ok := partitions[mnt.Source]; ok { if mnt.FSType != "tmpfs" { continue } } // Check for excluded mountpoint prefixes hasPrefix := false for _, prefix := range excludedMountpointPrefixes { if strings.HasPrefix(mnt.Mountpoint, prefix) { hasPrefix = true break } } if hasPrefix { continue } // Let plugin process the mount (handles filesystem-specific modifications) include, processedMnt, err := plugin.ProcessMount(mnt) if err != nil { klog.Warningf("error processing mount for %s: %v", mnt.FSType, err) continue } if !include { continue } partitions[processedMnt.Source] = partition{ fsType: processedMnt.FSType, mountpoint: processedMnt.Mountpoint, major: uint(processedMnt.Major), minor: uint(processedMnt.Minor), } } return partitions } // getDockerDeviceMapperInfo returns information about the devicemapper device and "partition" if // docker is using devicemapper for its storage driver. If a loopback device is being used, don't // return any information or error, as we want to report based on the actual partition where the // loopback file resides, inside of the loopback file itself. func (i *RealFsInfo) getDockerDeviceMapperInfo(context DockerContext) (string, *partition, error) { if context.Driver != DeviceMapper.String() { return "", nil, nil } dataLoopFile := context.DriverStatus[DriverStatusDataLoopFile] if len(dataLoopFile) > 0 { return "", nil, nil } dev, major, minor, blockSize, err := dockerDMDevice(context.DriverStatus, i.dmsetup) if err != nil { return "", nil, err } return dev, &partition{ fsType: DeviceMapper.String(), major: major, minor: minor, blockSize: blockSize, }, nil } // addSystemRootLabel attempts to determine which device contains the mount for /. func (i *RealFsInfo) addSystemRootLabel(mounts []*mount.Info) { for _, m := range mounts { if m.Mountpoint == "/" { i.partitions[m.Source] = partition{ fsType: m.FSType, mountpoint: m.Mountpoint, major: uint(m.Major), minor: uint(m.Minor), } i.labels[LabelSystemRoot] = m.Source return } } } // addDockerImagesLabel attempts to determine which device contains the mount for docker images. func (i *RealFsInfo) addDockerImagesLabel(context Context, mounts []*mount.Info) { if context.Docker.Driver != "" { dockerDev, dockerPartition, err := i.getDockerDeviceMapperInfo(context.Docker) if err != nil { klog.Warningf("Could not get Docker devicemapper device: %v", err) } if len(dockerDev) > 0 && dockerPartition != nil { i.partitions[dockerDev] = *dockerPartition i.labels[LabelDockerImages] = dockerDev } else { i.updateContainerImagesPath(LabelDockerImages, mounts, getDockerImagePaths(context)) } } } func (i *RealFsInfo) addCrioImagesLabel(context Context, mounts []*mount.Info) { labelCrioImageOrContainers := LabelCrioContainers // If imagestore is not specified, let's fall back to the original case. // Everything will be stored in crio-images if context.Crio.ImageStore == "" { labelCrioImageOrContainers = LabelCrioImages } if context.Crio.Root != "" { crioPath := context.Crio.Root crioImagePaths := map[string]struct{}{ "/": {}, } imageOrContainerPath := context.Crio.Driver + "-containers" if context.Crio.ImageStore == "" { // If ImageStore is not specified then we will assume ImageFs is complete separate. // No need to split the image store. imageOrContainerPath = context.Crio.Driver + "-images" } crioImagePaths[path.Join(crioPath, imageOrContainerPath)] = struct{}{} for crioPath != "/" && crioPath != "." { crioImagePaths[crioPath] = struct{}{} crioPath = filepath.Dir(crioPath) } i.updateContainerImagesPath(labelCrioImageOrContainers, mounts, crioImagePaths) } if context.Crio.ImageStore != "" { crioPath := context.Crio.ImageStore crioImagePaths := map[string]struct{}{ "/": {}, } crioImagePaths[path.Join(crioPath, context.Crio.Driver+"-images")] = struct{}{} for crioPath != "/" && crioPath != "." { crioImagePaths[crioPath] = struct{}{} crioPath = filepath.Dir(crioPath) } i.updateContainerImagesPath(LabelCrioImages, mounts, crioImagePaths) } } // Generate a list of possible mount points for docker image management from the docker root directory. // Right now, we look for each type of supported graph driver directories, but we can do better by parsing // some of the context from `docker info`. func getDockerImagePaths(context Context) map[string]struct{} { dockerImagePaths := map[string]struct{}{ "/": {}, } // TODO(rjnagal): Detect docker root and graphdriver directories from docker info. dockerRoot := context.Docker.Root for _, dir := range []string{"devicemapper", "btrfs", "aufs", "overlay", "overlay2", "zfs"} { dockerImagePaths[path.Join(dockerRoot, dir)] = struct{}{} } for dockerRoot != "/" && dockerRoot != "." { dockerImagePaths[dockerRoot] = struct{}{} dockerRoot = filepath.Dir(dockerRoot) } return dockerImagePaths } // This method compares the mountpoints with possible container image mount points. If a match is found, // the label is added to the partition. func (i *RealFsInfo) updateContainerImagesPath(label string, mounts []*mount.Info, containerImagePaths map[string]struct{}) { var useMount *mount.Info for _, m := range mounts { if _, ok := containerImagePaths[m.Mountpoint]; ok { if useMount == nil || (len(useMount.Mountpoint) < len(m.Mountpoint)) { useMount = m } } } if useMount != nil { i.partitions[useMount.Source] = partition{ fsType: useMount.FSType, mountpoint: useMount.Mountpoint, major: uint(useMount.Major), minor: uint(useMount.Minor), } i.labels[label] = useMount.Source } } func (i *RealFsInfo) GetDeviceForLabel(label string) (string, error) { dev, ok := i.labels[label] if !ok { return "", fmt.Errorf("non-existent label %q", label) } return dev, nil } func (i *RealFsInfo) GetLabelsForDevice(device string) ([]string, error) { var labels []string for label, dev := range i.labels { if dev == device { labels = append(labels, label) } } return labels, nil } func (i *RealFsInfo) GetMountpointForDevice(dev string) (string, error) { p, ok := i.partitions[dev] if !ok { return "", fmt.Errorf("no partition info for device %q", dev) } return p.mountpoint, nil } func (i *RealFsInfo) GetFsInfoForPath(mountSet map[string]struct{}) ([]Fs, error) { filesystems := make([]Fs, 0) deviceSet := make(map[string]struct{}) diskStatsMap, err := getDiskStatsMap("/proc/diskstats") if err != nil { return nil, err } // statsCache stores cached filesystem stats by cache key for plugins that implement FsCachingPlugin statsCache := make(map[string]Fs) for device, partition := range i.partitions { _, hasMount := mountSet[partition.mountpoint] _, hasDevice := deviceSet[device] if mountSet == nil || (hasMount && !hasDevice) { var ( statsErr error fs Fs ) // Use plugin system to get filesystem stats plugin := GetPluginForFsType(partition.fsType) if plugin == nil { klog.V(4).Infof("no plugin found for filesystem type: %v", partition.fsType) continue } partInfo := PartitionInfo{ Mountpoint: partition.mountpoint, Major: partition.major, Minor: partition.minor, FsType: partition.fsType, BlockSize: partition.blockSize, } // Check if plugin supports caching and if we have a cached value var cacheKey string if cachingPlugin, ok := plugin.(FsCachingPlugin); ok { cacheKey = cachingPlugin.CacheKey(partInfo) if cacheKey != "" { if cachedFs, found := statsCache[cacheKey]; found { fs = cachedFs // Skip stats fetching, use cached value deviceSet[device] = struct{}{} fs.DeviceInfo = DeviceInfo{ Device: device, Major: uint(partition.major), Minor: uint(partition.minor), } if val, ok := diskStatsMap[device]; ok { fs.DiskStats = val } else { for k, v := range diskStatsMap { if v.MajorNum == uint64(partition.major) && v.MinorNum == uint64(partition.minor) { fs.DiskStats = diskStatsMap[k] break } } } filesystems = append(filesystems, fs) continue } } } stats, statsErr := plugin.GetStats(device, partInfo) if statsErr != nil { // Handle fallback to VFS for plugins that request it if errors.Is(statsErr, ErrFallbackToVFS) { vfsPlugin := GetPluginForFsType("ext4") // VFS handles ext* if vfsPlugin != nil { stats, statsErr = vfsPlugin.GetStats(device, partInfo) } } if statsErr != nil { klog.V(4).Infof("Stat fs failed for %s. Error: %v", partition.fsType, statsErr) continue } } if stats == nil { klog.V(4).Infof("no stats returned for %s at %s", partition.fsType, partition.mountpoint) continue } fs.Capacity = stats.Capacity fs.Free = stats.Free fs.Available = stats.Available fs.Inodes = stats.Inodes fs.InodesFree = stats.InodesFree fs.Type = stats.Type // Store in cache if plugin supports caching if cacheKey != "" { statsCache[cacheKey] = fs } deviceSet[device] = struct{}{} fs.DeviceInfo = DeviceInfo{ Device: device, Major: uint(partition.major), Minor: uint(partition.minor), } if val, ok := diskStatsMap[device]; ok { fs.DiskStats = val } else { for k, v := range diskStatsMap { if v.MajorNum == uint64(partition.major) && v.MinorNum == uint64(partition.minor) { fs.DiskStats = diskStatsMap[k] break } } } filesystems = append(filesystems, fs) } } return filesystems, nil } var partitionRegex = regexp.MustCompile(`^(?:(?:s|v|xv)d[a-z]+\d*|dm-\d+)$`) func getDiskStatsMap(diskStatsFile string) (map[string]DiskStats, error) { diskStatsMap := make(map[string]DiskStats) file, err := os.Open(diskStatsFile) if err != nil { if os.IsNotExist(err) { klog.Warningf("Not collecting filesystem statistics because file %q was not found", diskStatsFile) return diskStatsMap, nil } return nil, err } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() words := strings.Fields(line) if !partitionRegex.MatchString(words[2]) { continue } // 8 50 sdd2 40 0 280 223 7 0 22 108 0 330 330 deviceName := path.Join("/dev", words[2]) var err error devInfo := make([]uint64, 2) for i := 0; i < len(devInfo); i++ { devInfo[i], err = strconv.ParseUint(words[i], 10, 64) if err != nil { return nil, err } } wordLength := len(words) offset := 3 var stats = make([]uint64, wordLength-offset) if len(stats) < 11 { return nil, fmt.Errorf("could not parse all 11 columns of /proc/diskstats") } for i := offset; i < wordLength; i++ { stats[i-offset], err = strconv.ParseUint(words[i], 10, 64) if err != nil { return nil, err } } major64, err := strconv.ParseUint(words[0], 10, 64) if err != nil { return nil, err } minor64, err := strconv.ParseUint(words[1], 10, 64) if err != nil { return nil, err } diskStats := DiskStats{ MajorNum: devInfo[0], MinorNum: devInfo[1], ReadsCompleted: stats[0], ReadsMerged: stats[1], SectorsRead: stats[2], ReadTime: stats[3], WritesCompleted: stats[4], WritesMerged: stats[5], SectorsWritten: stats[6], WriteTime: stats[7], IoInProgress: stats[8], IoTime: stats[9], WeightedIoTime: stats[10], Major: major64, Minor: minor64, } diskStatsMap[deviceName] = diskStats } return diskStatsMap, nil } func (i *RealFsInfo) GetGlobalFsInfo() ([]Fs, error) { return i.GetFsInfoForPath(nil) } func major(devNumber uint64) uint { return uint((devNumber >> 8) & 0xfff) } func minor(devNumber uint64) uint { return uint((devNumber & 0xff) | ((devNumber >> 12) & 0xfff00)) } func (i *RealFsInfo) GetDeviceInfoByFsUUID(uuid string) (*DeviceInfo, error) { deviceName, found := i.fsUUIDToDeviceName[uuid] if !found { return nil, ErrNoSuchDevice } p, found := i.partitions[deviceName] if !found { return nil, fmt.Errorf("cannot find device %q in partitions", deviceName) } return &DeviceInfo{deviceName, p.major, p.minor}, nil } func (i *RealFsInfo) mountInfoFromDir(dir string) (*mount.Info, bool) { mnt, found := i.mounts[dir] // try the parent dir if not found until we reach the root dir // this is an issue on btrfs systems where the directory is not // the subvolume for !found { pathdir, _ := filepath.Split(dir) // break when we reach root if pathdir == "/" { mnt, found = i.mounts["/"] break } // trim "/" from the new parent path otherwise the next possible // filepath.Split in the loop will not split the string any further dir = strings.TrimSuffix(pathdir, "/") mnt, found = i.mounts[dir] } return &mnt, found } func (i *RealFsInfo) GetDirFsDevice(dir string) (*DeviceInfo, error) { buf := new(syscall.Stat_t) err := syscall.Stat(dir, buf) if err != nil { return nil, fmt.Errorf("stat failed on %s with error: %s", dir, err) } // The type Dev in Stat_t is 32bit on mips. major := major(uint64(buf.Dev)) // nolint: unconvert minor := minor(uint64(buf.Dev)) // nolint: unconvert for device, partition := range i.partitions { if partition.major == major && partition.minor == minor { return &DeviceInfo{device, major, minor}, nil } } mnt, found := i.mountInfoFromDir(dir) if found && strings.HasPrefix(mnt.Source, "/dev/") { major, minor := mnt.Major, mnt.Minor if mnt.FSType == "btrfs" && major == 0 { major, minor, err = getBtrfsMajorMinorIds(mnt) if err != nil { klog.Warningf("Unable to get btrfs mountpoint IDs: %v", err) } } return &DeviceInfo{mnt.Source, uint(major), uint(minor)}, nil } return nil, fmt.Errorf("with major: %d, minor: %d: %w", major, minor, ErrDeviceNotInPartitionsMap) } func GetDirUsage(dir string) (UsageInfo, error) { var usage UsageInfo if dir == "" { return usage, fmt.Errorf("invalid directory") } rootInfo, err := os.Stat(dir) if err != nil { return usage, fmt.Errorf("could not stat %q to get inode usage: %v", dir, err) } rootStat, ok := rootInfo.Sys().(*syscall.Stat_t) if !ok { return usage, fmt.Errorf("unsupported fileinfo for getting inode usage of %q", dir) } rootDevID := rootStat.Dev // dedupedInode stores inodes that could be duplicates (nlink > 1) dedupedInodes := make(map[uint64]struct{}) err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if os.IsNotExist(err) { // expected if files appear/vanish return nil } if err != nil { return fmt.Errorf("unable to count inodes for part of dir %s: %s", dir, err) } // according to the docs, Sys can be nil if info.Sys() == nil { return fmt.Errorf("fileinfo Sys is nil") } s, ok := info.Sys().(*syscall.Stat_t) if !ok { return fmt.Errorf("unsupported fileinfo; could not convert to stat_t") } if s.Dev != rootDevID { // don't descend into directories on other devices return filepath.SkipDir } if s.Nlink > 1 { if _, ok := dedupedInodes[s.Ino]; !ok { // Dedupe things that could be hardlinks dedupedInodes[s.Ino] = struct{}{} usage.Bytes += uint64(s.Blocks) * statBlockSize usage.Inodes++ } } else { usage.Bytes += uint64(s.Blocks) * statBlockSize usage.Inodes++ } return nil }) return usage, err } func (i *RealFsInfo) GetDirUsage(dir string) (UsageInfo, error) { claimToken() defer releaseToken() return GetDirUsage(dir) } // Devicemapper thin provisioning is detailed at // https://www.kernel.org/doc/Documentation/device-mapper/thin-provisioning.txt func dockerDMDevice(driverStatus map[string]string, dmsetup devicemapper.DmsetupClient) (string, uint, uint, uint, error) { poolName, ok := driverStatus[DriverStatusPoolName] if !ok || len(poolName) == 0 { return "", 0, 0, 0, fmt.Errorf("could not get dm pool name") } out, err := dmsetup.Table(poolName) if err != nil { return "", 0, 0, 0, err } major, minor, dataBlkSize, err := parseDMTable(string(out)) if err != nil { return "", 0, 0, 0, err } return poolName, major, minor, dataBlkSize, nil } // parseDMTable parses a single line of `dmsetup table` output and returns the // major device, minor device, block size, and an error. func parseDMTable(dmTable string) (uint, uint, uint, error) { dmTable = strings.Replace(dmTable, ":", " ", -1) dmFields := strings.Fields(dmTable) if len(dmFields) < 8 { return 0, 0, 0, fmt.Errorf("invalid dmsetup status output: %s", dmTable) } major, err := strconv.ParseUint(dmFields[5], 10, 32) if err != nil { return 0, 0, 0, err } minor, err := strconv.ParseUint(dmFields[6], 10, 32) if err != nil { return 0, 0, 0, err } dataBlkSize, err := strconv.ParseUint(dmFields[7], 10, 32) if err != nil { return 0, 0, 0, err } return uint(major), uint(minor), uint(dataBlkSize), nil } // Get major and minor Ids for a mount point using btrfs as filesystem. func getBtrfsMajorMinorIds(mount *mount.Info) (int, int, error) { // btrfs fix: following workaround fixes wrong btrfs Major and Minor Ids reported in /proc/self/mountinfo. // instead of using values from /proc/self/mountinfo we use stat to get Ids from btrfs mount point buf := new(syscall.Stat_t) err := syscall.Stat(mount.Source, buf) if err != nil { err = fmt.Errorf("stat failed on %s with error: %s", mount.Source, err) return 0, 0, err } klog.V(4).Infof("btrfs mount %#v", mount) if buf.Mode&syscall.S_IFMT == syscall.S_IFBLK { err := syscall.Stat(mount.Mountpoint, buf) if err != nil { err = fmt.Errorf("stat failed on %s with error: %s", mount.Mountpoint, err) return 0, 0, err } // The type Dev and Rdev in Stat_t are 32bit on mips. klog.V(4).Infof("btrfs dev major:minor %d:%d\n", int(major(uint64(buf.Dev))), int(minor(uint64(buf.Dev)))) // nolint: unconvert klog.V(4).Infof("btrfs rdev major:minor %d:%d\n", int(major(uint64(buf.Rdev))), int(minor(uint64(buf.Rdev)))) // nolint: unconvert return int(major(uint64(buf.Dev))), int(minor(uint64(buf.Dev))), nil // nolint: unconvert } return 0, 0, fmt.Errorf("%s is not a block device", mount.Source) } ================================================ FILE: fs/fs_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package fs import ( "errors" "fmt" "os" "reflect" "strings" "testing" mount "github.com/moby/sys/mountinfo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // testPlugin is a minimal plugin implementation for testing processMounts. type testPlugin struct { name string canHandle func(string) bool priority int processMountFunc func(*mount.Info) (bool, *mount.Info, error) } func (p *testPlugin) Name() string { return p.name } func (p *testPlugin) CanHandle(fsType string) bool { return p.canHandle(fsType) } func (p *testPlugin) Priority() int { return p.priority } func (p *testPlugin) GetStats(device string, partition PartitionInfo) (*FsStats, error) { return nil, nil } func (p *testPlugin) ProcessMount(mnt *mount.Info) (bool, *mount.Info, error) { if p.processMountFunc != nil { return p.processMountFunc(mnt) } return true, mnt, nil } func init() { // Register test plugins for processMounts tests // VFS plugin - handles ext*, xfs RegisterPlugin("test-vfs", &testPlugin{ name: "test-vfs", canHandle: func(fsType string) bool { if strings.HasPrefix(fsType, "ext") { return true } return fsType == "xfs" }, priority: 0, }) // ZFS plugin RegisterPlugin("test-zfs", &testPlugin{ name: "test-zfs", canHandle: func(fsType string) bool { return fsType == "zfs" }, priority: 100, }) // Btrfs plugin RegisterPlugin("test-btrfs", &testPlugin{ name: "test-btrfs", canHandle: func(fsType string) bool { return fsType == "btrfs" }, priority: 100, }) // Overlay plugin - makes source unique with major/minor RegisterPlugin("test-overlay", &testPlugin{ name: "test-overlay", canHandle: func(fsType string) bool { return fsType == "overlay" }, priority: 100, processMountFunc: func(mnt *mount.Info) (bool, *mount.Info, error) { correctedMnt := *mnt correctedMnt.Source = fmt.Sprintf("%s_%d-%d", mnt.Source, mnt.Major, mnt.Minor) return true, &correctedMnt, nil }, }) // NFS plugin RegisterPlugin("test-nfs", &testPlugin{ name: "test-nfs", canHandle: func(fsType string) bool { return strings.HasPrefix(fsType, "nfs") }, priority: 50, }) // tmpfs plugin - uses mountpoint as source RegisterPlugin("test-tmpfs", &testPlugin{ name: "test-tmpfs", canHandle: func(fsType string) bool { return fsType == "tmpfs" }, priority: 100, processMountFunc: func(mnt *mount.Info) (bool, *mount.Info, error) { correctedMnt := *mnt correctedMnt.Source = mnt.Mountpoint return true, &correctedMnt, nil }, }) } func TestMountInfoFromDir(t *testing.T) { as := assert.New(t) fsInfo := &RealFsInfo{ mounts: map[string]mount.Info{ "/": {}, }, } testDirs := []string{"/var/lib/kubelet", "/var/lib/rancher"} for _, testDir := range testDirs { _, found := fsInfo.mountInfoFromDir(testDir) as.True(found, "failed to find MountInfo %s from FsInfo %s", testDir, fsInfo) } } func TestGetDiskStatsMap(t *testing.T) { diskStatsMap, err := getDiskStatsMap("test_resources/diskstats") if err != nil { t.Errorf("Error calling getDiskStatsMap %s", err) } if len(diskStatsMap) != 30 { t.Errorf("diskStatsMap %+v not valid", diskStatsMap) } keySet := map[string]string{ "/dev/sda": "/dev/sda", "/dev/sdb": "/dev/sdb", "/dev/sdc": "/dev/sdc", "/dev/sdd": "/dev/sdd", "/dev/sde": "/dev/sde", "/dev/sdf": "/dev/sdf", "/dev/sdg": "/dev/sdg", "/dev/sdh": "/dev/sdh", "/dev/sdb1": "/dev/sdb1", "/dev/sdb2": "/dev/sdb2", "/dev/sda1": "/dev/sda1", "/dev/sda2": "/dev/sda2", "/dev/sdc1": "/dev/sdc1", "/dev/sdc2": "/dev/sdc2", "/dev/sdc3": "/dev/sdc3", "/dev/sdc4": "/dev/sdc4", "/dev/sdd1": "/dev/sdd1", "/dev/sdd2": "/dev/sdd2", "/dev/sdd3": "/dev/sdd3", "/dev/sdd4": "/dev/sdd4", "/dev/sde1": "/dev/sde1", "/dev/sde2": "/dev/sde2", "/dev/sdf1": "/dev/sdf1", "/dev/sdf2": "/dev/sdf2", "/dev/sdg1": "/dev/sdg1", "/dev/sdg2": "/dev/sdg2", "/dev/sdh1": "/dev/sdh1", "/dev/sdh2": "/dev/sdh2", "/dev/dm-0": "/dev/dm-0", "/dev/dm-1": "/dev/dm-1", } for device := range diskStatsMap { if _, ok := keySet[device]; !ok { t.Errorf("Cannot find device %s", device) } delete(keySet, device) } if len(keySet) != 0 { t.Errorf("diskStatsMap %+v contains illegal keys %+v", diskStatsMap, keySet) } } func TestGetDiskStatsMapMajorMinorNum(t *testing.T) { diskStatsMap, err := getDiskStatsMap("test_resources/diskstats") if err != nil { t.Errorf("Error calling getDiskStatsMap %s", err) } if len(diskStatsMap) != 30 { t.Errorf("diskStatsMap %+v not valid", diskStatsMap) } if stat, ok := diskStatsMap["/dev/dm-0"]; ok { if stat.MajorNum != 252 && stat.MinorNum != 1 { t.Fatalf("getDiskStatsMap did not return correct major (%d) and minor (%d) numbers", stat.MajorNum, stat.MinorNum) } } } func TestFileNotExist(t *testing.T) { _, err := getDiskStatsMap("/file_does_not_exist") if err != nil { t.Fatalf("getDiskStatsMap must not error for absent file: %s", err) } } func TestDirDiskUsage(t *testing.T) { as := assert.New(t) fsInfo, err := NewFsInfo(Context{}) as.NoError(err) dir := t.TempDir() as.NoError(err) defer os.RemoveAll(dir) dataSize := 1024 * 100 //100 KB b := make([]byte, dataSize) f, err := os.CreateTemp(dir, "") as.NoError(err) as.NoError(os.WriteFile(f.Name(), b, 0700)) fi, err := f.Stat() as.NoError(err) expectedSize := uint64(fi.Size()) usage, err := fsInfo.GetDirUsage(dir) as.NoError(err) as.True(expectedSize <= usage.Bytes, "expected dir size to be at-least %d; got size: %d", expectedSize, usage.Bytes) } func TestDirInodeUsage(t *testing.T) { as := assert.New(t) fsInfo, err := NewFsInfo(Context{}) as.NoError(err) dir := t.TempDir() defer os.RemoveAll(dir) numFiles := 1000 for i := 0; i < numFiles; i++ { _, err := os.MkdirTemp(dir, "") require.NoError(t, err) } usage, err := fsInfo.GetDirUsage(dir) as.NoError(err) // We should get numFiles+1 inodes, since we get 1 inode for each file, plus 1 for the directory as.True(uint64(numFiles+1) == usage.Inodes, "expected inodes in dir to be %d; got inodes: %d", numFiles+1, usage.Inodes) } func TestAddSystemRootLabel(t *testing.T) { tests := []struct { mounts []*mount.Info expected string }{ { mounts: []*mount.Info{ {Source: "/dev/sda1", Mountpoint: "/foo"}, {Source: "/dev/sdb1", Mountpoint: "/"}, }, expected: "/dev/sdb1", }, } for i, tt := range tests { fsInfo := &RealFsInfo{ labels: map[string]string{}, partitions: map[string]partition{}, } fsInfo.addSystemRootLabel(tt.mounts) if source, ok := fsInfo.labels[LabelSystemRoot]; !ok || source != tt.expected { t.Errorf("case %d: expected mount source '%s', got '%s'", i, tt.expected, source) } } } type testDmsetup struct { data []byte err error } func (*testDmsetup) Message(deviceName string, sector int, message string) ([]byte, error) { return nil, nil } func (*testDmsetup) Status(deviceName string) ([]byte, error) { return nil, nil } func (t *testDmsetup) Table(poolName string) ([]byte, error) { return t.data, t.err } func TestGetDockerDeviceMapperInfo(t *testing.T) { tests := []struct { name string driver string driverStatus map[string]string dmsetupTable string dmsetupTableError error expectedDevice string expectedPartition *partition expectedError bool }{ { name: "not devicemapper", driver: "btrfs", expectedDevice: "", expectedPartition: nil, expectedError: false, }, { name: "nil driver status", driver: "devicemapper", driverStatus: nil, expectedDevice: "", expectedPartition: nil, expectedError: true, }, { name: "loopback", driver: "devicemapper", driverStatus: map[string]string{"Data loop file": "/var/lib/docker/devicemapper/devicemapper/data"}, expectedDevice: "", expectedPartition: nil, expectedError: false, }, { name: "missing pool name", driver: "devicemapper", driverStatus: map[string]string{}, expectedDevice: "", expectedPartition: nil, expectedError: true, }, { name: "error invoking dmsetup", driver: "devicemapper", driverStatus: map[string]string{"Pool Name": "vg_vagrant-docker--pool"}, dmsetupTableError: errors.New("foo"), expectedDevice: "", expectedPartition: nil, expectedError: true, }, { name: "unable to parse dmsetup table", driver: "devicemapper", driverStatus: map[string]string{"Pool Name": "vg_vagrant-docker--pool"}, dmsetupTable: "no data here!", expectedDevice: "", expectedPartition: nil, expectedError: true, }, { name: "happy path", driver: "devicemapper", driverStatus: map[string]string{"Pool Name": "vg_vagrant-docker--pool"}, dmsetupTable: "0 53870592 thin-pool 253:2 253:3 1024 0 1 skip_block_zeroing", expectedDevice: "vg_vagrant-docker--pool", expectedPartition: &partition{ fsType: "devicemapper", major: 253, minor: 3, blockSize: 1024, }, expectedError: false, }, } for _, tt := range tests { fsInfo := &RealFsInfo{ dmsetup: &testDmsetup{ data: []byte(tt.dmsetupTable), }, } dockerCtx := DockerContext{ Driver: tt.driver, DriverStatus: tt.driverStatus, } device, partition, err := fsInfo.getDockerDeviceMapperInfo(dockerCtx) if tt.expectedError && err == nil { t.Errorf("%s: expected error but got nil", tt.name) continue } if !tt.expectedError && err != nil { t.Errorf("%s: unexpected error: %v", tt.name, err) continue } if e, a := tt.expectedDevice, device; e != a { t.Errorf("%s: device: expected %q, got %q", tt.name, e, a) } if e, a := tt.expectedPartition, partition; !reflect.DeepEqual(e, a) { t.Errorf("%s: partition: expected %#v, got %#v", tt.name, e, a) } } } func TestAddDockerImagesLabel(t *testing.T) { tests := []struct { name string driver string driverStatus map[string]string dmsetupTable string getDockerDeviceMapperInfoError error mounts []*mount.Info expectedDockerDevice string expectedPartition *partition }{ { name: "single partition, no dedicated image fs", driver: "overlay2", mounts: []*mount.Info{ { Source: "/dev/root", Mountpoint: "/", FSType: "ext4", }, { Source: "/sys/fs/cgroup", Mountpoint: "/sys/fs/cgroup", FSType: "tmpfs", }, }, expectedDockerDevice: "/dev/root", }, { name: "devicemapper, not loopback", driver: "devicemapper", driverStatus: map[string]string{"Pool Name": "vg_vagrant-docker--pool"}, dmsetupTable: "0 53870592 thin-pool 253:2 253:3 1024 0 1 skip_block_zeroing", mounts: []*mount.Info{ { Source: "/dev/mapper/vg_vagrant-lv_root", Mountpoint: "/", FSType: "devicemapper", }, }, expectedDockerDevice: "vg_vagrant-docker--pool", expectedPartition: &partition{ fsType: "devicemapper", major: 253, minor: 3, blockSize: 1024, }, }, { name: "devicemapper, loopback on non-root partition", driver: "devicemapper", driverStatus: map[string]string{"Data loop file": "/var/lib/docker/devicemapper/devicemapper/data"}, mounts: []*mount.Info{ { Source: "/dev/mapper/vg_vagrant-lv_root", Mountpoint: "/", FSType: "devicemapper", }, { Source: "/dev/sdb1", Mountpoint: "/var/lib/docker/devicemapper", }, }, expectedDockerDevice: "/dev/sdb1", }, { name: "multiple mounts - innermost check", driver: "overlay2", mounts: []*mount.Info{ { Source: "/dev/sda1", Mountpoint: "/", FSType: "ext4", }, { Source: "/dev/sdb1", Mountpoint: "/var/lib/docker", FSType: "ext4", }, { Source: "/dev/sdb2", Mountpoint: "/var/lib/docker/btrfs", FSType: "btrfs", }, }, expectedDockerDevice: "/dev/sdb2", }, { name: "root fs inside container, docker-images bindmount", driver: "overlay2", mounts: []*mount.Info{ { Source: "overlay", Mountpoint: "/", FSType: "overlay", }, { Source: "/dev/sda1", Mountpoint: "/var/lib/docker", FSType: "ext4", }, }, expectedDockerDevice: "/dev/sda1", }, { name: "[overlay2] root fs inside container - /var/lib/docker bindmount", driver: "overlay2", mounts: []*mount.Info{ { Source: "overlay", Mountpoint: "/", FSType: "overlay", }, { Source: "/dev/sdb1", Mountpoint: "/var/lib/docker", FSType: "ext4", }, { Source: "/dev/sdb2", Mountpoint: "/var/lib/docker/overlay2", FSType: "ext4", }, }, expectedDockerDevice: "/dev/sdb2", }, } for _, tt := range tests { fsInfo := &RealFsInfo{ labels: map[string]string{}, partitions: map[string]partition{}, dmsetup: &testDmsetup{ data: []byte(tt.dmsetupTable), }, } context := Context{ Docker: DockerContext{ Root: "/var/lib/docker", Driver: tt.driver, DriverStatus: tt.driverStatus, }, } fsInfo.addDockerImagesLabel(context, tt.mounts) if e, a := tt.expectedDockerDevice, fsInfo.labels[LabelDockerImages]; e != a { t.Errorf("%s: docker device: expected %q, got %q", tt.name, e, a) } if tt.expectedPartition == nil { continue } if e, a := *tt.expectedPartition, fsInfo.partitions[tt.expectedDockerDevice]; !reflect.DeepEqual(e, a) { t.Errorf("%s: docker partition: expected %#v, got %#v", tt.name, e, a) } } } func TestAddCrioImagesLabel(t *testing.T) { tests := []struct { name string driver string driverStatus map[string]string dmsetupTable string mounts []*mount.Info imageStore string expectedCrioImages string expectedCrioContainers string expectedPartition *partition }{ { name: "single partition, no dedicated image fs", driver: "overlay2", mounts: []*mount.Info{ { Source: "/dev/root", Mountpoint: "/", FSType: "ext4", }, { Source: "/sys/fs/cgroup", Mountpoint: "/sys/fs/cgroup", FSType: "tmpfs", }, }, expectedCrioImages: "/dev/root", expectedCrioContainers: "", }, { name: "root fs inside container, docker-images bindmount", driver: "overlay2", mounts: []*mount.Info{ { Source: "overlay", Mountpoint: "/", FSType: "overlay", }, { Source: "/dev/sda1", Mountpoint: "/var/lib/container", FSType: "ext4", }, }, expectedCrioImages: "/dev/sda1", }, { name: "[overlay2] image and container separate", driver: "overlay2", mounts: []*mount.Info{ { Source: "/dev/sdb1", Mountpoint: "/imagestore", FSType: "ext4", }, { Source: "/dev/sdb2", Mountpoint: "/var/lib/container", FSType: "ext4", }, }, expectedCrioImages: "/dev/sdb1", expectedCrioContainers: "/dev/sdb2", imageStore: "/imagestore", }, } for _, tt := range tests { fsInfo := &RealFsInfo{ labels: map[string]string{}, partitions: map[string]partition{}, dmsetup: &testDmsetup{ data: []byte(tt.dmsetupTable), }, } context := Context{ Crio: CrioContext{ Root: "/var/lib/container", ImageStore: tt.imageStore, Driver: "overlay", }, } fsInfo.addCrioImagesLabel(context, tt.mounts) if tt.imageStore != "" { if e, a := tt.expectedCrioImages, fsInfo.labels[LabelCrioImages]; e != a { t.Errorf("%s: docker device: expected %q, got %q", tt.name, e, a) } if e, a := tt.expectedCrioContainers, fsInfo.labels[LabelCrioContainers]; e != a { t.Errorf("%s: docker device: expected %q, got %q", tt.name, e, a) } } if tt.imageStore == "" { if e, a := tt.expectedCrioImages, fsInfo.labels[LabelCrioImages]; e != a { t.Errorf("%s: docker device: expected %q, got %q", tt.name, e, a) } } if tt.expectedPartition == nil { continue } } } func TestProcessMounts(t *testing.T) { tests := []struct { name string mounts []*mount.Info excludedPrefixes []string expected map[string]partition }{ { name: "unsupported fs types", mounts: []*mount.Info{ {FSType: "somethingelse"}, }, expected: map[string]partition{}, }, { name: "avoid bind mounts", mounts: []*mount.Info{ {Root: "/", Mountpoint: "/", Source: "/dev/sda1", FSType: "xfs", Major: 253, Minor: 0}, {Root: "/foo", Mountpoint: "/bar", Source: "/dev/sda1", FSType: "xfs", Major: 253, Minor: 0}, }, expected: map[string]partition{ "/dev/sda1": {fsType: "xfs", mountpoint: "/", major: 253, minor: 0}, }, }, { name: "exclude prefixes", mounts: []*mount.Info{ {Root: "/", Mountpoint: "/someother", Source: "/dev/sda1", FSType: "xfs", Major: 253, Minor: 2}, {Root: "/", Mountpoint: "/", Source: "/dev/sda2", FSType: "xfs", Major: 253, Minor: 0}, {Root: "/", Mountpoint: "/excludeme", Source: "/dev/sda3", FSType: "xfs", Major: 253, Minor: 1}, }, excludedPrefixes: []string{"/exclude", "/some"}, expected: map[string]partition{ "/dev/sda2": {fsType: "xfs", mountpoint: "/", major: 253, minor: 0}, }, }, { name: "supported fs types", mounts: []*mount.Info{ {Root: "/", Mountpoint: "/a", Source: "/dev/sda", FSType: "ext3", Major: 253, Minor: 0}, {Root: "/", Mountpoint: "/b", Source: "/dev/sdb", FSType: "ext4", Major: 253, Minor: 1}, {Root: "/", Mountpoint: "/c", Source: "/dev/sdc", FSType: "btrfs", Major: 253, Minor: 2}, {Root: "/", Mountpoint: "/d", Source: "/dev/sdd", FSType: "xfs", Major: 253, Minor: 3}, {Root: "/", Mountpoint: "/e", Source: "/dev/sde", FSType: "zfs", Major: 253, Minor: 4}, {Root: "/", Mountpoint: "/f", Source: "overlay", FSType: "overlay", Major: 253, Minor: 5}, {Root: "/", Mountpoint: "/g", Source: "127.0.0.1:/nfs", FSType: "nfs4", Major: 253, Minor: 6}, {Root: "/", Mountpoint: "/test1", Source: "tmpfs", FSType: "tmpfs", Major: 253, Minor: 4}, {Root: "/", Mountpoint: "/test2", Source: "tmpfs", FSType: "tmpfs", Major: 253, Minor: 4}, }, expected: map[string]partition{ "/dev/sda": {fsType: "ext3", mountpoint: "/a", major: 253, minor: 0}, "/dev/sdb": {fsType: "ext4", mountpoint: "/b", major: 253, minor: 1}, "/dev/sdc": {fsType: "btrfs", mountpoint: "/c", major: 253, minor: 2}, "/dev/sdd": {fsType: "xfs", mountpoint: "/d", major: 253, minor: 3}, "/dev/sde": {fsType: "zfs", mountpoint: "/e", major: 253, minor: 4}, "overlay_253-5": {fsType: "overlay", mountpoint: "/f", major: 253, minor: 5}, "127.0.0.1:/nfs": {fsType: "nfs4", mountpoint: "/g", major: 253, minor: 6}, "/test1": {fsType: "tmpfs", mountpoint: "/test1", major: 253, minor: 4}, "/test2": {fsType: "tmpfs", mountpoint: "/test2", major: 253, minor: 4}, }, }, } for _, test := range tests { actual := processMounts(test.mounts, test.excludedPrefixes) if !reflect.DeepEqual(test.expected, actual) { t.Errorf("%s: expected %#v, got %#v", test.name, test.expected, actual) } } } ================================================ FILE: fs/nfs/install/install.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package install import ( "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/nfs" "k8s.io/klog/v2" ) func init() { err := fs.RegisterPlugin("nfs", nfs.NewPlugin()) if err != nil { klog.Fatalf("Failed to register nfs fs plugin: %v", err) } } ================================================ FILE: fs/nfs/plugin.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package nfs import ( "fmt" "strings" "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/vfs" mount "github.com/moby/sys/mountinfo" "k8s.io/klog/v2" ) type nfsPlugin struct{} // Ensure nfsPlugin implements FsCachingPlugin var _ fs.FsCachingPlugin = &nfsPlugin{} // NewPlugin creates a new NFS filesystem plugin. func NewPlugin() fs.FsPlugin { return &nfsPlugin{} } func (p *nfsPlugin) Name() string { return "nfs" } // CanHandle returns true if the filesystem type is NFS (nfs, nfs3, nfs4, etc.). func (p *nfsPlugin) CanHandle(fsType string) bool { return strings.HasPrefix(fsType, "nfs") } // Priority returns 50 - NFS has medium priority (higher than VFS but lower than specific plugins). func (p *nfsPlugin) Priority() int { return 50 } // GetStats returns filesystem statistics for NFS. // NFS uses VFS stats. func (p *nfsPlugin) GetStats(device string, partition fs.PartitionInfo) (*fs.FsStats, error) { capacity, free, avail, inodes, inodesFree, err := vfs.GetVfsStats(partition.Mountpoint) if err != nil { klog.V(4).Infof("the file system type is %s, partition mountpoint does not exist: %v, error: %v", partition.FsType, partition.Mountpoint, err) return nil, err } return &fs.FsStats{ Capacity: capacity, Free: free, Available: avail, Inodes: &inodes, InodesFree: &inodesFree, Type: fs.VFS, }, nil } // ProcessMount handles NFS mount processing. // For NFS, no special processing is needed. func (p *nfsPlugin) ProcessMount(mnt *mount.Info) (bool, *mount.Info, error) { return true, mnt, nil } // CacheKey returns a cache key based on device ID (major:minor). // NFS mounts with the same device ID share the same underlying filesystem, // so we can cache stats to avoid redundant statfs calls. func (p *nfsPlugin) CacheKey(partition fs.PartitionInfo) string { return fmt.Sprintf("%d:%d", partition.Major, partition.Minor) } ================================================ FILE: fs/overlay/install/install.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package install import ( "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/overlay" "k8s.io/klog/v2" ) func init() { err := fs.RegisterPlugin("overlay", overlay.NewPlugin()) if err != nil { klog.Fatalf("Failed to register overlay fs plugin: %v", err) } } ================================================ FILE: fs/overlay/plugin.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package overlay import ( "fmt" "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/vfs" mount "github.com/moby/sys/mountinfo" ) type overlayPlugin struct{} // NewPlugin creates a new Overlay filesystem plugin. func NewPlugin() fs.FsPlugin { return &overlayPlugin{} } func (p *overlayPlugin) Name() string { return "overlay" } // CanHandle returns true if the filesystem type is overlay or overlay2. func (p *overlayPlugin) CanHandle(fsType string) bool { return fsType == "overlay" } // Priority returns 100 - Overlay has higher priority than VFS. func (p *overlayPlugin) Priority() int { return 100 } // GetStats returns filesystem statistics for Overlay. // Overlay delegates to VFS for stats collection. func (p *overlayPlugin) GetStats(device string, partition fs.PartitionInfo) (*fs.FsStats, error) { // Overlay uses VFS stats capacity, free, avail, inodes, inodesFree, err := vfs.GetVfsStats(partition.Mountpoint) if err != nil { return nil, err } return &fs.FsStats{ Capacity: capacity, Free: free, Available: avail, Inodes: &inodes, InodesFree: &inodesFree, Type: fs.VFS, }, nil } // ProcessMount handles Overlay mount processing. // Overlay fix: Making mount source unique for all overlay mounts, using the mount's major and minor ids. // This is needed because multiple overlay mounts can have the same source. func (p *overlayPlugin) ProcessMount(mnt *mount.Info) (bool, *mount.Info, error) { // Create a copy with unique source correctedMnt := *mnt correctedMnt.Source = fmt.Sprintf("%s_%d-%d", mnt.Source, mnt.Major, mnt.Minor) return true, &correctedMnt, nil } ================================================ FILE: fs/plugin.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package fs import ( "errors" "fmt" "sync" mount "github.com/moby/sys/mountinfo" "k8s.io/klog/v2" ) // FsPlugin provides filesystem-specific statistics collection. type FsPlugin interface { // Name returns the plugin identifier (e.g., "zfs", "devicemapper", "vfs"). Name() string // CanHandle returns true if this plugin handles the given filesystem type. CanHandle(fsType string) bool // Priority returns the plugin priority (higher = checked first). // Allows specific plugins (zfs, btrfs) to override generic (vfs). Priority() int // GetStats returns filesystem statistics for a partition. GetStats(device string, partition PartitionInfo) (*FsStats, error) // ProcessMount optionally modifies mount info during processing. // Returns (shouldInclude bool, modifiedMount *mount.Info, error). ProcessMount(mnt *mount.Info) (bool, *mount.Info, error) } // FsCachingPlugin is an optional interface for plugins that want to cache // stats by a key (e.g., device ID) to avoid redundant stat calls. // This is useful for network filesystems like NFS where multiple mounts // may point to the same underlying device. type FsCachingPlugin interface { FsPlugin // CacheKey returns a cache key for the given partition. // Stats will be cached by this key and reused for partitions with the same key. // Return empty string to disable caching for a specific partition. CacheKey(partition PartitionInfo) string } // FsWatcherPlugin is an optional interface for plugins that provide // background monitoring (e.g., ZFS watcher, ThinPool watcher). type FsWatcherPlugin interface { FsPlugin // StartWatcher starts background monitoring. // Returns a Watcher that can be used to get container-level usage. StartWatcher() (FsWatcher, error) } // FsWatcher provides container-level filesystem usage from background monitoring. type FsWatcher interface { // GetUsage returns filesystem usage for a specific container/path. GetUsage(containerID string, deviceID string) (uint64, error) // Stop stops the background monitoring. Stop() } // PartitionInfo contains information needed for stats collection. type PartitionInfo struct { Mountpoint string Major uint Minor uint FsType string BlockSize uint } // FsStats contains filesystem statistics returned by plugins. type FsStats struct { Capacity uint64 Free uint64 Available uint64 Inodes *uint64 InodesFree *uint64 Type FsType } // ErrFallbackToVFS signals that a specialized plugin cannot handle // this filesystem and VFS should be used instead. var ErrFallbackToVFS = errors.New("fallback to VFS") // Plugin registry (init-time registration only). var ( pluginsLock sync.RWMutex plugins = make(map[string]FsPlugin) ) // RegisterPlugin registers a filesystem plugin. // This should be called from init() functions. func RegisterPlugin(name string, plugin FsPlugin) error { pluginsLock.Lock() defer pluginsLock.Unlock() if _, found := plugins[name]; found { return fmt.Errorf("FsPlugin %q was registered twice", name) } klog.V(4).Infof("Registered FsPlugin %q", name) plugins[name] = plugin return nil } // GetPluginForFsType returns the appropriate plugin for the filesystem type. // Returns nil if no plugin can handle the filesystem type. func GetPluginForFsType(fsType string) FsPlugin { pluginsLock.RLock() defer pluginsLock.RUnlock() var best FsPlugin for _, p := range plugins { if p.CanHandle(fsType) { if best == nil || p.Priority() > best.Priority() { best = p } } } return best } // GetAllPlugins returns all registered plugins. func GetAllPlugins() []FsPlugin { pluginsLock.RLock() defer pluginsLock.RUnlock() result := make([]FsPlugin, 0, len(plugins)) for _, p := range plugins { result = append(result, p) } return result } // InitializeWatchers starts all plugin watchers and returns them. func InitializeWatchers() map[string]FsWatcher { pluginsLock.RLock() defer pluginsLock.RUnlock() watchers := make(map[string]FsWatcher) for name, plugin := range plugins { if wp, ok := plugin.(FsWatcherPlugin); ok { watcher, err := wp.StartWatcher() if err != nil { klog.V(4).Infof("Failed to start watcher for plugin %s: %v", name, err) continue } if watcher != nil { watchers[name] = watcher klog.V(4).Infof("Started watcher for FsPlugin %q", name) } } } return watchers } // StopWatchers stops all provided watchers. func StopWatchers(watchers map[string]FsWatcher) { for name, watcher := range watchers { if watcher != nil { watcher.Stop() klog.V(4).Infof("Stopped watcher for FsPlugin %q", name) } } } ================================================ FILE: fs/test_resources/diskstats ================================================ 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 7 0 loop0 0 0 0 0 0 0 0 0 0 0 0 7 1 loop1 0 0 0 0 0 0 0 0 0 0 0 7 2 loop2 0 0 0 0 0 0 0 0 0 0 0 7 3 loop3 0 0 0 0 0 0 0 0 0 0 0 7 4 loop4 0 0 0 0 0 0 0 0 0 0 0 7 5 loop5 0 0 0 0 0 0 0 0 0 0 0 7 6 loop6 0 0 0 0 0 0 0 0 0 0 0 7 7 loop7 0 0 0 0 0 0 0 0 0 0 0 8 16 sdb 931 1157 7601 960 2 0 16 0 0 919 960 8 17 sdb1 477 1147 3895 271 1 0 8 0 0 271 271 8 18 sdb2 395 0 3154 326 1 0 8 0 0 326 326 8 0 sda 931 1157 7601 1065 2 0 16 0 0 873 1065 8 1 sda1 477 1147 3895 419 1 0 8 0 0 419 419 8 2 sda2 395 0 3154 328 1 0 8 0 0 328 328 8 32 sdc 12390 470 457965 36363 72184 244851 9824537 5359169 0 607738 5437210 8 33 sdc1 10907 221 446193 34366 72173 244851 9824499 5359063 0 606972 5435214 8 34 sdc2 650 249 5120 901 7 0 22 93 0 956 994 8 35 sdc3 264 0 2106 380 1 0 8 0 0 380 380 8 36 sdc4 392 0 3130 476 1 0 8 0 0 475 475 8 48 sdd 3371 134 58909 18327 73997 243043 9824537 4532714 0 594248 4602162 8 49 sdd1 2498 134 51977 17192 73986 243043 9824499 4532600 0 593618 4600885 8 50 sdd2 40 0 280 223 7 0 22 108 0 330 330 8 51 sdd3 264 0 2106 328 1 0 8 0 0 328 328 8 52 sdd4 392 0 3130 373 1 0 8 1 0 374 374 8 64 sde 931 1157 7601 768 2 0 16 0 0 632 768 8 65 sde1 477 1147 3895 252 1 0 8 0 0 252 252 8 66 sde2 395 0 3154 281 1 0 8 0 0 281 281 8 80 sdf 931 1157 7601 936 2 0 16 0 0 717 936 8 81 sdf1 477 1147 3895 382 1 0 8 0 0 382 382 8 82 sdf2 395 0 3154 321 1 0 8 0 0 321 321 8 96 sdg 931 1157 7601 858 2 0 16 0 0 804 858 8 97 sdg1 477 1147 3895 244 1 0 8 0 0 244 244 8 98 sdg2 395 0 3154 299 1 0 8 0 0 299 299 8 112 sdh 931 1157 7601 895 2 0 16 0 0 841 895 8 113 sdh1 477 1147 3895 264 1 0 8 0 0 264 264 8 114 sdh2 395 0 3154 311 1 0 8 0 0 311 311 252 0 dm-0 1251094 0 108121362 21287644 111848 0 52908472 22236936 0 4838500 43524784 252 1 dm-1 58415638 0 2682446960 1719953592 20048040 0 543988240 1975572544 0 262085340 3695556828 ================================================ FILE: fs/tmpfs/install/install.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package install import ( "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/tmpfs" "k8s.io/klog/v2" ) func init() { err := fs.RegisterPlugin("tmpfs", tmpfs.NewPlugin()) if err != nil { klog.Fatalf("Failed to register tmpfs fs plugin: %v", err) } } ================================================ FILE: fs/tmpfs/plugin.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package tmpfs import ( "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/vfs" mount "github.com/moby/sys/mountinfo" ) type tmpfsPlugin struct{} // NewPlugin creates a new tmpfs filesystem plugin. func NewPlugin() fs.FsPlugin { return &tmpfsPlugin{} } func (p *tmpfsPlugin) Name() string { return "tmpfs" } // CanHandle returns true if the filesystem type is tmpfs. func (p *tmpfsPlugin) CanHandle(fsType string) bool { return fsType == "tmpfs" } // Priority returns 100 - tmpfs has higher priority than VFS. func (p *tmpfsPlugin) Priority() int { return 100 } // GetStats returns filesystem statistics for tmpfs. // tmpfs delegates to VFS for stats collection. func (p *tmpfsPlugin) GetStats(device string, partition fs.PartitionInfo) (*fs.FsStats, error) { // tmpfs uses VFS stats capacity, free, avail, inodes, inodesFree, err := vfs.GetVfsStats(partition.Mountpoint) if err != nil { return nil, err } return &fs.FsStats{ Capacity: capacity, Free: free, Available: avail, Inodes: &inodes, InodesFree: &inodesFree, Type: fs.VFS, }, nil } // ProcessMount handles tmpfs mount processing. // For tmpfs, we use the mountpoint as the source to make each mount unique. // This allows multiple tmpfs mounts with the same "tmpfs" source to coexist. func (p *tmpfsPlugin) ProcessMount(mnt *mount.Info) (bool, *mount.Info, error) { // Use mountpoint as source to make each tmpfs mount unique correctedMnt := *mnt correctedMnt.Source = mnt.Mountpoint return true, &correctedMnt, nil } // AllowDuplicateSource returns true for tmpfs since multiple tmpfs mounts // should be tracked separately even if they appear to have the same source. func (p *tmpfsPlugin) AllowDuplicateSource() bool { return true } ================================================ FILE: fs/types.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package fs import ( "errors" ) type Context struct { // docker root directory. Docker DockerContext Crio CrioContext Podman PodmanContext } type DockerContext struct { Root string Driver string DriverStatus map[string]string } type PodmanContext struct { Root string Driver string DriverStatus map[string]string } type CrioContext struct { Root string ImageStore string Driver string } type DeviceInfo struct { Device string Major uint Minor uint } type FsType string func (ft FsType) String() string { return string(ft) } const ( ZFS FsType = "zfs" DeviceMapper FsType = "devicemapper" VFS FsType = "vfs" NFS FsType = "nfs" ) type Fs struct { DeviceInfo Type FsType Capacity uint64 Free uint64 Available uint64 Inodes *uint64 InodesFree *uint64 DiskStats DiskStats } type DiskStats struct { MajorNum uint64 MinorNum uint64 ReadsCompleted uint64 ReadsMerged uint64 SectorsRead uint64 ReadTime uint64 WritesCompleted uint64 WritesMerged uint64 SectorsWritten uint64 WriteTime uint64 IoInProgress uint64 IoTime uint64 WeightedIoTime uint64 Major uint64 Minor uint64 } type UsageInfo struct { Bytes uint64 Inodes uint64 } var ( // ErrNoSuchDevice is the error indicating the requested device does not exist. ErrNoSuchDevice = errors.New("cadvisor: no such device") // ErrDeviceNotInPartitionsMap is the error resulting if a device could not be found in the partitions map. ErrDeviceNotInPartitionsMap = errors.New("could not find device in cached partitions map") ) type FsInfo interface { // Returns capacity and free space, in bytes, of all the ext2, ext3, ext4 filesystems on the host. GetGlobalFsInfo() ([]Fs, error) // Returns capacity and free space, in bytes, of the set of mounts passed. GetFsInfoForPath(mountSet map[string]struct{}) ([]Fs, error) // GetDirUsage returns a usage information for 'dir'. GetDirUsage(dir string) (UsageInfo, error) // GetDeviceInfoByFsUUID returns the information of the device with the // specified filesystem uuid. If no such device exists, this function will // return the ErrNoSuchDevice error. GetDeviceInfoByFsUUID(uuid string) (*DeviceInfo, error) // Returns the block device info of the filesystem on which 'dir' resides. GetDirFsDevice(dir string) (*DeviceInfo, error) // Returns the device name associated with a particular label. GetDeviceForLabel(label string) (string, error) // Returns all labels associated with a particular device name. GetLabelsForDevice(device string) ([]string, error) // Returns the mountpoint associated with a particular device. GetMountpointForDevice(device string) (string, error) } ================================================ FILE: fs/vfs/install/install.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package install import ( "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/vfs" "k8s.io/klog/v2" ) func init() { err := fs.RegisterPlugin("vfs", vfs.NewPlugin()) if err != nil { klog.Fatalf("Failed to register vfs fs plugin: %v", err) } } ================================================ FILE: fs/vfs/plugin.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package vfs import ( "strings" "github.com/google/cadvisor/fs" "github.com/google/cadvisor/utils" mount "github.com/moby/sys/mountinfo" "k8s.io/klog/v2" ) type vfsPlugin struct{} // NewPlugin creates a new VFS filesystem plugin. func NewPlugin() fs.FsPlugin { return &vfsPlugin{} } func (p *vfsPlugin) Name() string { return "vfs" } // CanHandle returns true for standard filesystems that use VFS stats. // This includes ext2/3/4, xfs, and similar block-based filesystems. // Virtual/pseudo filesystems (proc, sysfs, cgroup, etc.) are excluded. func (p *vfsPlugin) CanHandle(fsType string) bool { // Exclude virtual/pseudo filesystems that don't have real disk backing switch fsType { case "cgroup", "cgroup2", "cpuset", "mqueue", "proc", "sysfs", "devtmpfs", "devpts", "securityfs", "debugfs", "tracefs", "pstore", "configfs", "fusectl", "hugetlbfs", "autofs", "binfmt_misc", "efivarfs", "rpc_pipefs", "nsfs": return false } // VFS can handle most standard Linux filesystems if strings.HasPrefix(fsType, "ext") { return true } switch fsType { case "xfs", "squashfs", "f2fs", "jfs", "reiserfs", "hfs", "hfsplus", "ntfs", "vfat", "fat", "msdos", "exfat", "udf", "iso9660": return true } // Don't act as a general fallback - only handle known filesystem types return false } // Priority returns 0 - VFS is the lowest priority fallback plugin. func (p *vfsPlugin) Priority() int { return 0 } // GetStats returns filesystem statistics using the statfs syscall. func (p *vfsPlugin) GetStats(device string, partition fs.PartitionInfo) (*fs.FsStats, error) { if !utils.FileExists(partition.Mountpoint) { klog.V(4).Infof("VFS: mountpoint does not exist: %v", partition.Mountpoint) return nil, nil } capacity, free, avail, inodes, inodesFree, err := GetVfsStats(partition.Mountpoint) if err != nil { return nil, err } return &fs.FsStats{ Capacity: capacity, Free: free, Available: avail, Inodes: &inodes, InodesFree: &inodesFree, Type: fs.VFS, }, nil } // ProcessMount handles standard mount processing. // For VFS, no special processing is needed. func (p *vfsPlugin) ProcessMount(mnt *mount.Info) (bool, *mount.Info, error) { return true, mnt, nil } ================================================ FILE: fs/vfs/stats.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package vfs import ( "context" "syscall" "time" ) // GetVfsStats returns filesystem statistics using the statfs syscall. // It has a timeout to prevent hanging on unresponsive filesystems. func GetVfsStats(path string) (total uint64, free uint64, avail uint64, inodes uint64, inodesFree uint64, err error) { // timeout the context with, default is 2sec timeout := 2 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second) defer cancel() type result struct { total uint64 free uint64 avail uint64 inodes uint64 inodesFree uint64 err error } resultChan := make(chan result, 1) go func() { var s syscall.Statfs_t if err = syscall.Statfs(path, &s); err != nil { total, free, avail, inodes, inodesFree = 0, 0, 0, 0, 0 } total = uint64(s.Frsize) * s.Blocks free = uint64(s.Frsize) * s.Bfree avail = uint64(s.Frsize) * s.Bavail inodes = uint64(s.Files) inodesFree = uint64(s.Ffree) resultChan <- result{total: total, free: free, avail: avail, inodes: inodes, inodesFree: inodesFree, err: err} }() select { case <-ctx.Done(): return 0, 0, 0, 0, 0, ctx.Err() case res := <-resultChan: return res.total, res.free, res.avail, res.inodes, res.inodesFree, res.err } } ================================================ FILE: fs/zfs/install/install.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package install import ( "github.com/google/cadvisor/fs" "github.com/google/cadvisor/fs/zfs" "k8s.io/klog/v2" ) func init() { err := fs.RegisterPlugin("zfs", zfs.NewPlugin()) if err != nil { klog.Fatalf("Failed to register zfs fs plugin: %v", err) } } ================================================ FILE: fs/zfs/plugin.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zfs import ( "os" "github.com/google/cadvisor/fs" mount "github.com/moby/sys/mountinfo" ) type zfsPlugin struct{} // NewPlugin creates a new ZFS filesystem plugin. func NewPlugin() fs.FsPlugin { return &zfsPlugin{} } func (p *zfsPlugin) Name() string { return "zfs" } // CanHandle returns true if the filesystem type is zfs. func (p *zfsPlugin) CanHandle(fsType string) bool { return fsType == "zfs" } // Priority returns 100 - ZFS has higher priority than VFS. func (p *zfsPlugin) Priority() int { return 100 } // GetStats returns filesystem statistics for ZFS. func (p *zfsPlugin) GetStats(device string, partition fs.PartitionInfo) (*fs.FsStats, error) { // Check if ZFS is available - if /dev/zfs doesn't exist, fall back to VFS if _, err := os.Stat("/dev/zfs"); os.IsNotExist(err) { return nil, fs.ErrFallbackToVFS } capacity, free, avail, err := GetZfsStats(device) if err != nil { return nil, err } return &fs.FsStats{ Capacity: capacity, Free: free, Available: avail, Type: fs.ZFS, }, nil } // ProcessMount handles ZFS mount processing. // For ZFS, no special processing is needed. func (p *zfsPlugin) ProcessMount(mnt *mount.Info) (bool, *mount.Info, error) { return true, mnt, nil } ================================================ FILE: fs/zfs/stats.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zfs import ( zfslib "github.com/mistifyio/go-zfs" ) // GetZfsStats returns ZFS mount stats using zfsutils. func GetZfsStats(poolName string) (uint64, uint64, uint64, error) { dataset, err := zfslib.GetDataset(poolName) if err != nil { return 0, 0, 0, err } total := dataset.Used + dataset.Avail + dataset.Usedbydataset return total, dataset.Avail, dataset.Avail, nil } ================================================ FILE: fs/zfs/watcher.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zfs import ( "fmt" "sync/atomic" "time" zfslib "github.com/mistifyio/go-zfs" "k8s.io/klog/v2" ) // usageCache is a typed wrapper around atomic.Value that eliminates the need // for type assertions at every call site. It stores filesystem name strings // mapped to usage values (uint64). type usageCache struct { v atomic.Value } // Load retrieves the current cache map. func (c *usageCache) Load() map[string]uint64 { return c.v.Load().(map[string]uint64) } // Store saves a new cache map. func (c *usageCache) Store(m map[string]uint64) { c.v.Store(m) } // ZfsWatcher maintains a cache of filesystem -> usage stats for a // zfs filesystem type ZfsWatcher struct { filesystem string cache usageCache period time.Duration stopChan chan struct{} } // NewZfsWatcher returns a new ZfsWatcher for the given zfs filesystem. func NewZfsWatcher(filesystem string) (*ZfsWatcher, error) { w := &ZfsWatcher{ filesystem: filesystem, period: 15 * time.Second, stopChan: make(chan struct{}), } w.cache.Store(map[string]uint64{}) return w, nil } // Start starts the ZfsWatcher. func (w *ZfsWatcher) Start() { err := w.Refresh() if err != nil { klog.Errorf("encountered error refreshing zfs watcher: %v", err) } for { select { case <-w.stopChan: return case <-time.After(w.period): start := time.Now() err = w.Refresh() if err != nil { klog.Errorf("encountered error refreshing zfs watcher: %v", err) } // print latency for refresh duration := time.Since(start) klog.V(5).Infof("zfs(%d) took %s", start.Unix(), duration) } } } // Stop stops the ZfsWatcher. func (w *ZfsWatcher) Stop() { close(w.stopChan) } // GetUsage gets the cached usage value of the given filesystem. func (w *ZfsWatcher) GetUsage(filesystem string) (uint64, error) { cache := w.cache.Load() v, ok := cache[filesystem] if !ok { return 0, fmt.Errorf("no cached value for usage of filesystem %v", filesystem) } return v, nil } // Refresh performs a zfs get func (w *ZfsWatcher) Refresh() error { parent, err := zfslib.GetDataset(w.filesystem) if err != nil { klog.Errorf("encountered error getting zfs filesystem: %s: %v", w.filesystem, err) return err } children, err := parent.Children(0) if err != nil { klog.Errorf("encountered error getting children of zfs filesystem: %s: %v", w.filesystem, err) return err } newCache := make(map[string]uint64) for _, ds := range children { newCache[ds.Name] = ds.Used } w.cache.Store(newCache) return nil } ================================================ FILE: go.mod ================================================ module github.com/google/cadvisor go 1.24.0 require ( cloud.google.com/go/compute/metadata v0.7.0 github.com/Microsoft/go-winio v0.6.2 github.com/aws/aws-sdk-go-v2/config v1.29.14 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 github.com/blang/semver/v4 v4.0.0 github.com/containerd/containerd/api v1.10.0 github.com/containerd/errdefs v1.0.0 github.com/containerd/errdefs/pkg v0.3.0 github.com/containerd/ttrpc v1.2.7 github.com/containerd/typeurl/v2 v2.2.3 github.com/docker/go-connections v0.6.0 github.com/docker/go-units v0.5.0 github.com/euank/go-kmsg-parser v2.0.0+incompatible github.com/mistifyio/go-zfs v2.1.1+incompatible github.com/moby/moby/api v1.52.0 github.com/moby/moby/client v0.2.1 github.com/moby/sys/mountinfo v0.7.2 github.com/opencontainers/cgroups v0.0.6 github.com/opencontainers/runc v1.4.0 github.com/opencontainers/runtime-spec v1.3.0 github.com/prometheus/client_golang v1.22.0 github.com/prometheus/client_model v0.6.2 github.com/prometheus/common v0.64.0 github.com/stretchr/testify v1.11.1 golang.org/x/sys v0.37.0 google.golang.org/grpc v1.72.2 google.golang.org/protobuf v1.36.8 k8s.io/klog/v2 v2.130.1 k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 ) require ( github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.67 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect github.com/aws/smithy-go v1.22.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/cyphar/filepath-securejoin v0.6.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/stretchr/objx v0.5.2 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect go.opentelemetry.io/otel/metric v1.36.0 // indirect go.opentelemetry.io/otel/trace v1.36.0 // indirect golang.org/x/net v0.43.0 // indirect golang.org/x/text v0.28.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ================================================ FILE: go.sum ================================================ cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM= github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g= github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM= github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8= github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY= github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k= github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/containerd/containerd/api v1.10.0 h1:5n0oHYVBwN4VhoX9fFykCV9dF1/BvAXeg2F8W6UYq1o= github.com/containerd/containerd/api v1.10.0/go.mod h1:NBm1OAk8ZL+LG8R0ceObGxT5hbUYj7CzTmR3xh0DlMM= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRqQ= github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40= github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk= github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/euank/go-kmsg-parser v2.0.0+incompatible h1:cHD53+PLQuuQyLZeriD1V/esuG4MuU0Pjs5y6iknohY= github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8= github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg= github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc= github.com/moby/moby/client v0.2.1 h1:1Grh1552mvv6i+sYOdY+xKKVTvzJegcVMhuXocyDz/k= github.com/moby/moby/client v0.2.1/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/opencontainers/cgroups v0.0.6 h1:tfZFWTIIGaUUFImTyuTg+Mr5x8XRiSdZESgEBW7UxuI= github.com/opencontainers/cgroups v0.0.6/go.mod h1:oWVzJsKK0gG9SCRBfTpnn16WcGEqDI8PAcpMGbqWxcs= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/opencontainers/runc v1.4.0 h1:FG1Hw0GBYPsNki+mBz1QOrSzbwbAcerhrAD2r097QCc= github.com/opencontainers/runc v1.4.0/go.mod h1:sch3Bh3c1NlyAkALoAUz5Br9ubMLZzFcxuovZbnkErk= github.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg= github.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97RvvF3a8J3fP/Lg= k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= ================================================ FILE: info/v1/container.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package v1 import ( "reflect" "time" ) type CpuSpec struct { Limit uint64 `json:"limit"` MaxLimit uint64 `json:"max_limit"` Mask string `json:"mask,omitempty"` Quota uint64 `json:"quota,omitempty"` Period uint64 `json:"period,omitempty"` } type MemorySpec struct { // The amount of memory requested. Default is unlimited (-1). // Units: bytes. Limit uint64 `json:"limit,omitempty"` // The amount of guaranteed memory. Default is 0. // Units: bytes. Reservation uint64 `json:"reservation,omitempty"` // The amount of swap space requested. Default is unlimited (-1). // Units: bytes. SwapLimit uint64 `json:"swap_limit,omitempty"` } type ProcessSpec struct { Limit uint64 `json:"limit,omitempty"` } type ContainerSpec struct { // Time at which the container was created. CreationTime time.Time `json:"creation_time,omitempty"` // Time at which the container was started. // This may be unset if the runtime does not provide it. StartTime time.Time `json:"start_time,omitempty"` // Metadata labels associated with this container. Labels map[string]string `json:"labels,omitempty"` // Metadata envs associated with this container. Only whitelisted envs are added. Envs map[string]string `json:"envs,omitempty"` HasCpu bool `json:"has_cpu"` Cpu CpuSpec `json:"cpu,omitempty"` HasMemory bool `json:"has_memory"` Memory MemorySpec `json:"memory,omitempty"` HasHugetlb bool `json:"has_hugetlb"` HasNetwork bool `json:"has_network"` HasProcesses bool `json:"has_processes"` Processes ProcessSpec `json:"processes,omitempty"` HasFilesystem bool `json:"has_filesystem"` // HasDiskIo when true, indicates that DiskIo stats will be available. HasDiskIo bool `json:"has_diskio"` HasCustomMetrics bool `json:"has_custom_metrics"` CustomMetrics []MetricSpec `json:"custom_metrics,omitempty"` // Image name used for this container. Image string `json:"image,omitempty"` } // Container reference contains enough information to uniquely identify a container type ContainerReference struct { // The container id Id string `json:"id,omitempty"` // The absolute name of the container. This is unique on the machine. Name string `json:"name"` // Other names by which the container is known within a certain namespace. // This is unique within that namespace. Aliases []string `json:"aliases,omitempty"` // Namespace under which the aliases of a container are unique. // An example of a namespace is "docker" for Docker containers. Namespace string `json:"namespace,omitempty"` } // Sorts by container name. type ContainerReferenceSlice []ContainerReference func (s ContainerReferenceSlice) Len() int { return len(s) } func (s ContainerReferenceSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s ContainerReferenceSlice) Less(i, j int) bool { return s[i].Name < s[j].Name } // ContainerInfoRequest is used when users check a container info from the REST API. // It specifies how much data users want to get about a container type ContainerInfoRequest struct { // Max number of stats to return. Specify -1 for all stats currently available. // Default: 60 NumStats int `json:"num_stats,omitempty"` // Start time for which to query information. // If omitted, the beginning of time is assumed. Start time.Time `json:"start,omitempty"` // End time for which to query information. // If omitted, current time is assumed. End time.Time `json:"end,omitempty"` } // Returns a ContainerInfoRequest with all default values specified. func DefaultContainerInfoRequest() ContainerInfoRequest { return ContainerInfoRequest{ NumStats: 60, } } func (r *ContainerInfoRequest) Equals(other ContainerInfoRequest) bool { return r.NumStats == other.NumStats && r.Start.Equal(other.Start) && r.End.Equal(other.End) } type ContainerInfo struct { ContainerReference // The direct subcontainers of the current container. Subcontainers []ContainerReference `json:"subcontainers,omitempty"` // The isolation used in the container. Spec ContainerSpec `json:"spec,omitempty"` // Historical statistics gathered from the container. Stats []*ContainerStats `json:"stats,omitempty"` } // TODO(vmarmol): Refactor to not need this equality comparison. // ContainerInfo may be (un)marshaled by json or other en/decoder. In that // case, the Timestamp field in each stats/sample may not be precisely // en/decoded. This will lead to small but acceptable differences between a // ContainerInfo and its encode-then-decode version. Eq() is used to compare // two ContainerInfo accepting small difference (<10ms) of Time fields. func (ci *ContainerInfo) Eq(b *ContainerInfo) bool { // If both ci and b are nil, then Eq() returns true if ci == nil { return b == nil } if b == nil { return ci == nil } // For fields other than time.Time, we will compare them precisely. // This would require that any slice should have same order. if !reflect.DeepEqual(ci.ContainerReference, b.ContainerReference) { return false } if !reflect.DeepEqual(ci.Subcontainers, b.Subcontainers) { return false } if !ci.Spec.Eq(&b.Spec) { return false } for i, expectedStats := range b.Stats { selfStats := ci.Stats[i] if !expectedStats.Eq(selfStats) { return false } } return true } func (s *ContainerSpec) Eq(b *ContainerSpec) bool { // Creation within 1s of each other. diff := s.CreationTime.Sub(b.CreationTime) if (diff > time.Second) || (diff < -time.Second) { return false } // Start time within 1s of each other. startDiff := s.StartTime.Sub(b.StartTime) if (startDiff > time.Second) || (startDiff < -time.Second) { return false } if s.HasCpu != b.HasCpu { return false } if !reflect.DeepEqual(s.Cpu, b.Cpu) { return false } if s.HasMemory != b.HasMemory { return false } if !reflect.DeepEqual(s.Memory, b.Memory) { return false } if s.HasHugetlb != b.HasHugetlb { return false } if s.HasNetwork != b.HasNetwork { return false } if s.HasProcesses != b.HasProcesses { return false } if s.HasFilesystem != b.HasFilesystem { return false } if s.HasDiskIo != b.HasDiskIo { return false } if s.HasCustomMetrics != b.HasCustomMetrics { return false } if s.Image != b.Image { return false } return true } func (ci *ContainerInfo) StatsAfter(ref time.Time) []*ContainerStats { n := len(ci.Stats) + 1 for i, s := range ci.Stats { if s.Timestamp.After(ref) { n = i break } } if n > len(ci.Stats) { return nil } return ci.Stats[n:] } func (ci *ContainerInfo) StatsStartTime() time.Time { var ret time.Time for _, s := range ci.Stats { if s.Timestamp.Before(ret) || ret.IsZero() { ret = s.Timestamp } } return ret } func (ci *ContainerInfo) StatsEndTime() time.Time { var ret time.Time for i := len(ci.Stats) - 1; i >= 0; i-- { s := ci.Stats[i] if s.Timestamp.After(ret) { ret = s.Timestamp } } return ret } // PSI statistics for an individual resource. type PSIStats struct { // PSI data for all tasks of in the cgroup. Full PSIData `json:"full,omitempty"` // PSI data for some tasks in the cgroup. Some PSIData `json:"some,omitempty"` } type PSIData struct { // Total time duration for tasks in the cgroup have waited due to congestion. // Unit: nanoseconds. Total uint64 `json:"total"` // The average (in %) tasks have waited due to congestion over a 10 second window. Avg10 float64 `json:"avg10"` // The average (in %) tasks have waited due to congestion over a 60 second window. Avg60 float64 `json:"avg60"` // The average (in %) tasks have waited due to congestion over a 300 second window. Avg300 float64 `json:"avg300"` } // This mirrors kernel internal structure. type LoadStats struct { // Number of sleeping tasks. NrSleeping uint64 `json:"nr_sleeping"` // Number of running tasks. NrRunning uint64 `json:"nr_running"` // Number of tasks in stopped state NrStopped uint64 `json:"nr_stopped"` // Number of tasks in uninterruptible state NrUninterruptible uint64 `json:"nr_uninterruptible"` // Number of tasks waiting on IO NrIoWait uint64 `json:"nr_io_wait"` } // CPU usage time statistics. type CpuUsage struct { // Total CPU usage. // Unit: nanoseconds. Total uint64 `json:"total"` // Per CPU/core usage of the container. // Unit: nanoseconds. PerCpu []uint64 `json:"per_cpu_usage,omitempty"` // Time spent in user space. // Unit: nanoseconds. User uint64 `json:"user"` // Time spent in kernel space. // Unit: nanoseconds. System uint64 `json:"system"` } // Cpu Completely Fair Scheduler statistics. type CpuCFS struct { // Total number of elapsed enforcement intervals. Periods uint64 `json:"periods"` // Total number of times tasks in the cgroup have been throttled. ThrottledPeriods uint64 `json:"throttled_periods"` // Total time duration for which tasks in the cgroup have been throttled. // Unit: nanoseconds. ThrottledTime uint64 `json:"throttled_time"` // Total number of periods when CPU burst occurs. BurstsPeriods uint64 `json:"bursts_periods"` // Total time duration when CPU burst occurs. // Unit: nanoseconds. BurstTime uint64 `json:"burst_time"` } // Cpu Aggregated scheduler statistics type CpuSchedstat struct { // https://www.kernel.org/doc/Documentation/scheduler/sched-stats.txt // time spent on the cpu RunTime uint64 `json:"run_time"` // time spent waiting on a runqueue RunqueueTime uint64 `json:"runqueue_time"` // # of timeslices run on this cpu RunPeriods uint64 `json:"run_periods"` } // All CPU usage metrics are cumulative from the creation of the container type CpuStats struct { Usage CpuUsage `json:"usage"` CFS CpuCFS `json:"cfs"` Schedstat CpuSchedstat `json:"schedstat"` // Smoothed average of number of runnable threads x 1000. // We multiply by thousand to avoid using floats, but preserving precision. // Load is smoothed over the last 10 seconds. Instantaneous value can be read // from LoadStats.NrRunning. LoadAverage int32 `json:"load_average"` // from LoadStats.NrUninterruptible LoadDAverage int32 `json:"load_d_average"` PSI PSIStats `json:"psi"` } type PerDiskStats struct { Device string `json:"device"` Major uint64 `json:"major"` Minor uint64 `json:"minor"` Stats map[string]uint64 `json:"stats"` } type DiskIoStats struct { IoServiceBytes []PerDiskStats `json:"io_service_bytes,omitempty"` IoServiced []PerDiskStats `json:"io_serviced,omitempty"` IoQueued []PerDiskStats `json:"io_queued,omitempty"` Sectors []PerDiskStats `json:"sectors,omitempty"` IoServiceTime []PerDiskStats `json:"io_service_time,omitempty"` IoWaitTime []PerDiskStats `json:"io_wait_time,omitempty"` IoMerged []PerDiskStats `json:"io_merged,omitempty"` IoTime []PerDiskStats `json:"io_time,omitempty"` IoCostUsage []PerDiskStats `json:"io_cost_usage,omitempty"` IoCostWait []PerDiskStats `json:"io_cost_wait,omitempty"` IoCostIndebt []PerDiskStats `json:"io_cost_indebt,omitempty"` IoCostIndelay []PerDiskStats `json:"io_cost_indelay,omitempty"` PSI PSIStats `json:"psi"` } type HugetlbStats struct { // current res_counter usage for hugetlb Usage uint64 `json:"usage,omitempty"` // maximum usage ever recorded. MaxUsage uint64 `json:"max_usage,omitempty"` // number of times hugetlb usage allocation failure. Failcnt uint64 `json:"failcnt"` } type MemoryStats struct { // Current memory usage, this includes all memory regardless of when it was // accessed. // Units: Bytes. Usage uint64 `json:"usage"` // Maximum memory usage recorded. // Units: Bytes. MaxUsage uint64 `json:"max_usage"` // Number of bytes of page cache memory. // Units: Bytes. Cache uint64 `json:"cache"` // The amount of anonymous and swap cache memory (includes transparent // hugepages). // Units: Bytes. RSS uint64 `json:"rss"` // The amount of swap currently used by the processes in this cgroup // Units: Bytes. Swap uint64 `json:"swap"` // The amount of memory used for mapped files (includes tmpfs/shmem) MappedFile uint64 `json:"mapped_file"` // The amount of working set memory, this includes recently accessed memory, // dirty memory, and kernel memory. Working set is <= "usage". // Units: Bytes. WorkingSet uint64 `json:"working_set"` // The total amount of active file memory. // Units: Bytes. TotalActiveFile uint64 `json:"total_active_file"` // The total amount of inactive file memory. // Units: Bytes. TotalInactiveFile uint64 `json:"total_inactive_file"` Failcnt uint64 `json:"failcnt"` // Size of kernel memory allocated in bytes. // Units: Bytes. KernelUsage uint64 `json:"kernel"` ContainerData MemoryStatsMemoryData `json:"container_data,omitempty"` HierarchicalData MemoryStatsMemoryData `json:"hierarchical_data,omitempty"` PSI PSIStats `json:"psi"` } type CPUSetStats struct { MemoryMigrate uint64 `json:"memory_migrate"` } type MemoryNumaStats struct { File map[uint8]uint64 `json:"file,omitempty"` Anon map[uint8]uint64 `json:"anon,omitempty"` Unevictable map[uint8]uint64 `json:"unevictable,omitempty"` } type MemoryStatsMemoryData struct { Pgfault uint64 `json:"pgfault"` Pgmajfault uint64 `json:"pgmajfault"` NumaStats MemoryNumaStats `json:"numa_stats,omitempty"` } type InterfaceStats struct { // The name of the interface. Name string `json:"name"` // Cumulative count of bytes received. RxBytes uint64 `json:"rx_bytes"` // Cumulative count of packets received. RxPackets uint64 `json:"rx_packets"` // Cumulative count of receive errors encountered. RxErrors uint64 `json:"rx_errors"` // Cumulative count of packets dropped while receiving. RxDropped uint64 `json:"rx_dropped"` // Cumulative count of bytes transmitted. TxBytes uint64 `json:"tx_bytes"` // Cumulative count of packets transmitted. TxPackets uint64 `json:"tx_packets"` // Cumulative count of transmit errors encountered. TxErrors uint64 `json:"tx_errors"` // Cumulative count of packets dropped while transmitting. TxDropped uint64 `json:"tx_dropped"` } type NetworkStats struct { InterfaceStats `json:",inline"` Interfaces []InterfaceStats `json:"interfaces,omitempty"` // TCP connection stats (Established, Listen...) Tcp TcpStat `json:"tcp"` // TCP6 connection stats (Established, Listen...) Tcp6 TcpStat `json:"tcp6"` // UDP connection stats Udp UdpStat `json:"udp"` // UDP6 connection stats Udp6 UdpStat `json:"udp6"` // TCP advanced stats TcpAdvanced TcpAdvancedStat `json:"tcp_advanced"` } type TcpStat struct { // Count of TCP connections in state "Established" Established uint64 // Count of TCP connections in state "Syn_Sent" SynSent uint64 // Count of TCP connections in state "Syn_Recv" SynRecv uint64 // Count of TCP connections in state "Fin_Wait1" FinWait1 uint64 // Count of TCP connections in state "Fin_Wait2" FinWait2 uint64 // Count of TCP connections in state "Time_Wait TimeWait uint64 // Count of TCP connections in state "Close" Close uint64 // Count of TCP connections in state "Close_Wait" CloseWait uint64 // Count of TCP connections in state "Listen_Ack" LastAck uint64 // Count of TCP connections in state "Listen" Listen uint64 // Count of TCP connections in state "Closing" Closing uint64 } type TcpAdvancedStat struct { // The algorithm used to determine the timeout value used for // retransmitting unacknowledged octets, ref: RFC2698, default 1 RtoAlgorithm uint64 // The minimum value permitted by a TCP implementation for the // retransmission timeout, measured in milliseconds, default 200ms RtoMin uint64 // The maximum value permitted by a TCP implementation for the // retransmission timeout, measured in milliseconds, default 120s RtoMax uint64 // The limit on the total number of TCP connections the entity // can support., default -1, i.e. infinity MaxConn int64 // The number of times TCP connections have made a direct // transition to the SYN-SENT state from the CLOSED state. ActiveOpens uint64 // The number of times TCP connections have made a direct // transition to the SYN-RCVD state from the LISTEN state. PassiveOpens uint64 // The number of times TCP connections have made a direct // transition to the CLOSED state from either the SYN-SENT // state or the SYN-RCVD state, plus the number of times TCP // connections have made a direct transition to the LISTEN // state from the SYN-RCVD state. AttemptFails uint64 // The number of times TCP connections have made a direct // transition to the CLOSED state from either the ESTABLISHED // state or the CLOSE-WAIT state. EstabResets uint64 // The number of TCP connections for which the current state // is either ESTABLISHED or CLOSE- WAIT. CurrEstab uint64 // The total number of segments received, including those // received in error. InSegs uint64 // The total number of segments sent, including those on // current connections but excluding those containing only // retransmitted octets. OutSegs uint64 // The total number of segments retransmitted - that is, the // number of TCP segments transmitted containing one or more // previously transmitted octets. RetransSegs uint64 // The total number of segments received in error (e.g., bad // TCP checksums). InErrs uint64 // The number of TCP segments sent containing the RST flag. OutRsts uint64 // The number of IP Packets with checksum errors InCsumErrors uint64 // The number of resets received for embryonic SYN_RECV sockets EmbryonicRsts uint64 // The number of SYN cookies sent SyncookiesSent uint64 // The number of SYN cookies received SyncookiesRecv uint64 // The number of invalid SYN cookies received SyncookiesFailed uint64 // The number of packets pruned from receive queue because of socket buffer overrun PruneCalled uint64 // The number of packets pruned from receive queue RcvPruned uint64 // The number of packets dropped from out-of-order queue because of socket buffer overrun OfoPruned uint64 // The number of ICMP packets dropped because they were out-of-window OutOfWindowIcmps uint64 // The number of ICMP packets dropped because socket was locked LockDroppedIcmps uint64 // The number of TCP sockets finished time wait in fast timer TW uint64 // The number of time wait sockets recycled by time stamp TWRecycled uint64 // The number of TCP sockets finished time wait in slow timer TWKilled uint64 // counter, if no more mem for TIME-WAIT struct, +1 TCPTimeWaitOverflow uint64 // The number of RTO timer first timeout times TCPTimeouts uint64 // The number of fake timeouts detected by F-RTO TCPSpuriousRTOs uint64 // The number of send Tail Loss Probe (TLP) times by Probe Timeout(PTO) TCPLossProbes uint64 // The number of recovery times by TLP TCPLossProbeRecovery uint64 // The number of RTO failed times when in Recovery state, and remote end has no sack TCPRenoRecoveryFail uint64 // The number of RTO failed times when in Recovery state, and remote end has sack TCPSackRecoveryFail uint64 // The number of RTO failed times when in TCP_CA_Disorder state, and remote end has no sack TCPRenoFailures uint64 // The number of RTO failed times when in TCP_CA_Disorder state, and remote end has sack TCPSackFailures uint64 // The number of RTO failed times when in TCP_CA_Loss state, TCPLossFailures uint64 // The number of delayed acks sent DelayedACKs uint64 // The number of delayed acks further delayed because of locked socket DelayedACKLocked uint64 // The number of quick ack mode was activated times DelayedACKLost uint64 // The number of times the listen queue of a socket overflowed ListenOverflows uint64 // The number of SYNs to LISTEN sockets dropped ListenDrops uint64 // The number of packet headers predicted TCPHPHits uint64 // The number of acknowledgments not containing data payload received TCPPureAcks uint64 // The number of predicted acknowledgments TCPHPAcks uint64 // The number of times recovered from packet loss due to fast retransmit TCPRenoRecovery uint64 // The number of SACK retransmits failed TCPSackRecovery uint64 // The number of bad SACK blocks received TCPSACKReneging uint64 // The number of detected reordering times using FACK TCPFACKReorder uint64 // The number of detected reordering times using SACK TCPSACKReorder uint64 // The number of detected reordering times using Reno TCPRenoReorder uint64 // The number of detected reordering times using time stamp TCPTSReorder uint64 // The number of congestion windows fully recovered without slow start TCPFullUndo uint64 // The number of congestion windows partially recovered using Hoe heuristic TCPPartialUndo uint64 // The number of congestion windows recovered without slow start by DSACK TCPDSACKUndo uint64 // The number of congestion windows recovered without slow start after partial ack TCPLossUndo uint64 // The number of fast retransmits TCPFastRetrans uint64 // The number of retransmits in slow start TCPSlowStartRetrans uint64 // The number of retransmits lost TCPLostRetransmit uint64 // The number of retransmits failed, including FastRetrans, SlowStartRetrans TCPRetransFail uint64 // The number of packets collapsed in receive queue due to low socket buffer TCPRcvCollapsed uint64 // The number of DSACKs sent for old packets TCPDSACKOldSent uint64 // The number of DSACKs sent for out of order packets TCPDSACKOfoSent uint64 // The number of DSACKs received TCPDSACKRecv uint64 // The number of DSACKs for out of order packets received TCPDSACKOfoRecv uint64 // The number of connections reset due to unexpected data TCPAbortOnData uint64 // The number of connections reset due to early user close TCPAbortOnClose uint64 // The number of connections aborted due to memory pressure TCPAbortOnMemory uint64 // The number of connections aborted due to timeout TCPAbortOnTimeout uint64 // The number of connections aborted after user close in linger timeout TCPAbortOnLinger uint64 // The number of times unable to send RST due to no memory TCPAbortFailed uint64 // The number of TCP ran low on memory times TCPMemoryPressures uint64 // The number of TCP cumulative duration of // memory pressure events, by ms TCPMemoryPressuresChrono uint64 // The number of SACKs discard TCPSACKDiscard uint64 // The number of DSACKs ignore old TCPDSACKIgnoredOld uint64 // The number of DSACKs ignore no undo TCPDSACKIgnoredNoUndo uint64 // The number of MD5 not found TCPMD5NotFound uint64 // The number of MD5 unexpected TCPMD5Unexpected uint64 // The number of MD5 failed TCPMD5Failure uint64 // The number of Sack shifted TCPSackShifted uint64 // The number of Sack merged TCPSackMerged uint64 // The number of Sack shift fall back TCPSackShiftFallback uint64 // The number of Backlog drop TCPBacklogDrop uint64 // The number of PFmemalloc drop PFMemallocDrop uint64 // The number of memalloc drop TCPMinTTLDrop uint64 // The number of DeferAccept drop TCPDeferAcceptDrop uint64 // The number of IP reverse path filter IPReversePathFilter uint64 // The number of request full do cookies TCPReqQFullDoCookies uint64 // The number of request full drop TCPReqQFullDrop uint64 // number of successful outbound TFO connections TCPFastOpenActive uint64 // number of SYN-ACK packets received that did not acknowledge data // sent in the SYN packet and caused a retransmissions without SYN data. TCPFastOpenActiveFail uint64 // number of successful inbound TFO connections TCPFastOpenPassive uint64 // number of inbound SYN packets with TFO cookie that was invalid TCPFastOpenPassiveFail uint64 // number of inbound SYN packets that will have TFO disabled because // the socket has exceeded the max queue length TCPFastOpenListenOverflow uint64 // number of inbound SYN packets requesting TFO with TFO set but no cookie TCPFastOpenCookieReqd uint64 // number of SYN and SYN/ACK retransmits to break down retransmissions // into SYN, fast-retransmits, timeout retransmits, etc. TCPSynRetrans uint64 // number of outgoing packets with original data // (excluding retransmission but including data-in-SYN). TCPOrigDataSent uint64 // The number of active connections rejected because of time stamp PAWSActive uint64 // The number of packetes rejected in established connections because of timestamp PAWSEstab uint64 } type UdpStat struct { // Count of UDP sockets in state "Listen" Listen uint64 // Count of UDP packets dropped by the IP stack Dropped uint64 // Count of packets Queued for Receieve RxQueued uint64 // Count of packets Queued for Transmit TxQueued uint64 } type FsStats struct { // The block device name associated with the filesystem. Device string `json:"device,omitempty"` // Type of the filesytem. Type string `json:"type"` // Number of bytes that can be consumed by the container on this filesystem. Limit uint64 `json:"capacity"` // Number of bytes that is consumed by the container on this filesystem. Usage uint64 `json:"usage"` // Base Usage that is consumed by the container's writable layer. // This field is only applicable for docker container's as of now. BaseUsage uint64 `json:"base_usage"` // Number of bytes available for non-root user. Available uint64 `json:"available"` // HasInodes when true, indicates that Inodes info will be available. HasInodes bool `json:"has_inodes"` // Number of Inodes Inodes uint64 `json:"inodes"` // Number of available Inodes InodesFree uint64 `json:"inodes_free"` // Number of reads completed // This is the total number of reads completed successfully. ReadsCompleted uint64 `json:"reads_completed"` // Number of reads merged // Reads and writes which are adjacent to each other may be merged for // efficiency. Thus two 4K reads may become one 8K read before it is // ultimately handed to the disk, and so it will be counted (and queued) // as only one I/O. This field lets you know how often this was done. ReadsMerged uint64 `json:"reads_merged"` // Number of sectors read // This is the total number of sectors read successfully. SectorsRead uint64 `json:"sectors_read"` // Number of milliseconds spent reading // This is the total number of milliseconds spent by all reads (as // measured from __make_request() to end_that_request_last()). ReadTime uint64 `json:"read_time"` // Number of writes completed // This is the total number of writes completed successfully. WritesCompleted uint64 `json:"writes_completed"` // Number of writes merged // See the description of reads merged. WritesMerged uint64 `json:"writes_merged"` // Number of sectors written // This is the total number of sectors written successfully. SectorsWritten uint64 `json:"sectors_written"` // Number of milliseconds spent writing // This is the total number of milliseconds spent by all writes (as // measured from __make_request() to end_that_request_last()). WriteTime uint64 `json:"write_time"` // Number of I/Os currently in progress // The only field that should go to zero. Incremented as requests are // given to appropriate struct request_queue and decremented as they finish. IoInProgress uint64 `json:"io_in_progress"` // Number of milliseconds spent doing I/Os // This field increases so long as field 9 is nonzero. IoTime uint64 `json:"io_time"` // weighted number of milliseconds spent doing I/Os // This field is incremented at each I/O start, I/O completion, I/O // merge, or read of these stats by the number of I/Os in progress // (field 9) times the number of milliseconds spent doing I/O since the // last update of this field. This can provide an easy measure of both // I/O completion time and the backlog that may be accumulating. WeightedIoTime uint64 `json:"weighted_io_time"` } type AcceleratorStats struct { // Make of the accelerator (nvidia, amd, google etc.) Make string `json:"make"` // Model of the accelerator (tesla-p100, tesla-k80 etc.) Model string `json:"model"` // ID of the accelerator. ID string `json:"id"` // Total accelerator memory. // unit: bytes MemoryTotal uint64 `json:"memory_total"` // Total accelerator memory allocated. // unit: bytes MemoryUsed uint64 `json:"memory_used"` // Percent of time over the past sample period during which // the accelerator was actively processing. DutyCycle uint64 `json:"duty_cycle"` } // PerfStat represents value of a single monitored perf event. type PerfStat struct { PerfValue // CPU that perf event was measured on. Cpu int `json:"cpu"` } type PerfValue struct { // Indicates scaling ratio for an event: time_running/time_enabled // (amount of time that event was being measured divided by // amount of time that event was enabled for). // value 1.0 indicates that no multiplexing occurred. Value close // to 0 indicates that event was measured for short time and event's // value might be inaccurate. // See: https://lwn.net/Articles/324756/ ScalingRatio float64 `json:"scaling_ratio"` // Value represents value of perf event retrieved from OS. It is // normalized against ScalingRatio and takes multiplexing into // consideration. Value uint64 `json:"value"` // Name is human readable name of an event. Name string `json:"name"` } // MemoryBandwidthStats corresponds to MBM (Memory Bandwidth Monitoring). // See: https://01.org/cache-monitoring-technology // See: https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt type MemoryBandwidthStats struct { // The 'mbm_total_bytes'. TotalBytes uint64 `json:"mbm_total_bytes,omitempty"` // The 'mbm_local_bytes'. LocalBytes uint64 `json:"mbm_local_bytes,omitempty"` } // CacheStats corresponds to CMT (Cache Monitoring Technology). // See: https://01.org/cache-monitoring-technology // See: https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt type CacheStats struct { // The 'llc_occupancy'. LLCOccupancy uint64 `json:"llc_occupancy,omitempty"` } // ResctrlStats corresponds to statistics from Resource Control. type ResctrlStats struct { // Each NUMA Node statistics corresponds to one element in the array. MemoryBandwidth []MemoryBandwidthStats `json:"memory_bandwidth,omitempty"` Cache []CacheStats `json:"cache,omitempty"` } // PerfUncoreStat represents value of a single monitored perf uncore event. type PerfUncoreStat struct { PerfValue // Socket that perf event was measured on. Socket int `json:"socket"` // PMU is Performance Monitoring Unit which collected these stats. PMU string `json:"pmu"` } type UlimitSpec struct { Name string `json:"name"` SoftLimit int64 `json:"soft_limit"` HardLimit int64 `json:"hard_limit"` } type ProcessStats struct { // Number of processes ProcessCount uint64 `json:"process_count"` // Number of open file descriptors FdCount uint64 `json:"fd_count"` // Number of sockets SocketCount uint64 `json:"socket_count"` // Number of threads currently in container ThreadsCurrent uint64 `json:"threads_current,omitempty"` // Maxium number of threads allowed in container ThreadsMax uint64 `json:"threads_max,omitempty"` // Ulimits for the top-level container process Ulimits []UlimitSpec `json:"ulimits,omitempty"` } type Health struct { // Health status of the container Status string `json:"status"` } type ContainerStats struct { // The time of this stat point. Timestamp time.Time `json:"timestamp"` Cpu CpuStats `json:"cpu,omitempty"` DiskIo DiskIoStats `json:"diskio,omitempty"` Memory MemoryStats `json:"memory,omitempty"` Hugetlb map[string]HugetlbStats `json:"hugetlb,omitempty"` Network NetworkStats `json:"network,omitempty"` // Filesystem statistics Filesystem []FsStats `json:"filesystem,omitempty"` // Task load stats TaskStats LoadStats `json:"task_stats,omitempty"` // Metrics for Accelerators. Each Accelerator corresponds to one element in the array. Accelerators []AcceleratorStats `json:"accelerators,omitempty"` // ProcessStats for Containers Processes ProcessStats `json:"processes,omitempty"` // Custom metrics from all collectors CustomMetrics map[string][]MetricVal `json:"custom_metrics,omitempty"` // Statistics originating from perf events PerfStats []PerfStat `json:"perf_stats,omitempty"` // Statistics originating from perf uncore events. // Applies only for root container. PerfUncoreStats []PerfUncoreStat `json:"perf_uncore_stats,omitempty"` // Referenced memory ReferencedMemory uint64 `json:"referenced_memory,omitempty"` // Resource Control (resctrl) statistics Resctrl ResctrlStats `json:"resctrl,omitempty"` CpuSet CPUSetStats `json:"cpuset,omitempty"` OOMEvents uint64 `json:"oom_events,omitempty"` Health Health `json:"health,omitempty"` } func timeEq(t1, t2 time.Time, tolerance time.Duration) bool { // t1 should not be later than t2 if t1.After(t2) { t1, t2 = t2, t1 } diff := t2.Sub(t1) return diff <= tolerance } const ( // 10ms, i.e. 0.01s timePrecision time.Duration = 10 * time.Millisecond ) // This function is useful because we do not require precise time // representation. func (a *ContainerStats) Eq(b *ContainerStats) bool { if !timeEq(a.Timestamp, b.Timestamp, timePrecision) { return false } return a.StatsEq(b) } // Checks equality of the stats values. func (a *ContainerStats) StatsEq(b *ContainerStats) bool { // TODO(vmarmol): Consider using this through reflection. if !reflect.DeepEqual(a.Cpu, b.Cpu) { return false } if !reflect.DeepEqual(a.Memory, b.Memory) { return false } if !reflect.DeepEqual(a.Hugetlb, b.Hugetlb) { return false } if !reflect.DeepEqual(a.DiskIo, b.DiskIo) { return false } if !reflect.DeepEqual(a.Network, b.Network) { return false } if !reflect.DeepEqual(a.Processes, b.Processes) { return false } if !reflect.DeepEqual(a.Filesystem, b.Filesystem) { return false } if !reflect.DeepEqual(a.TaskStats, b.TaskStats) { return false } if !reflect.DeepEqual(a.Accelerators, b.Accelerators) { return false } if !reflect.DeepEqual(a.CustomMetrics, b.CustomMetrics) { return false } return true } // Event contains information general to events such as the time at which they // occurred, their specific type, and the actual event. Event types are // differentiated by the EventType field of Event. type Event struct { // the absolute container name for which the event occurred ContainerName string `json:"container_name"` // the time at which the event occurred Timestamp time.Time `json:"timestamp"` // the type of event. EventType is an enumerated type EventType EventType `json:"event_type"` // the original event object and all of its extraneous data, ex. an // OomInstance EventData EventData `json:"event_data,omitempty"` } // EventType is an enumerated type which lists the categories under which // events may fall. The Event field EventType is populated by this enum. type EventType string const ( EventOom EventType = "oom" EventOomKill EventType = "oomKill" EventContainerCreation EventType = "containerCreation" EventContainerDeletion EventType = "containerDeletion" ) // Extra information about an event. Only one type will be set. type EventData struct { // Information about an OOM kill event. OomKill *OomKillEventData `json:"oom,omitempty"` // Information about a container deletion event. ContainerDeletion *ContainerDeletionEventData `json:"container_deletion,omitempty"` } // Information related to an OOM kill instance type OomKillEventData struct { // process id of the killed process Pid int `json:"pid"` // The name of the killed process ProcessName string `json:"process_name"` } // Information related to a container deletion event type ContainerDeletionEventData struct { // ExitCode is the exit code of the container. // A value of -1 indicates the exit code was not available or not applicable. ExitCode int `json:"exit_code"` } ================================================ FILE: info/v1/container_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package v1 import ( "testing" "time" ) func TestStatsStartTime(t *testing.T) { N := 10 stats := make([]*ContainerStats, 0, N) ct := time.Now() for i := 0; i < N; i++ { s := &ContainerStats{ Timestamp: ct.Add(time.Duration(i) * time.Second), } stats = append(stats, s) } cinfo := &ContainerInfo{ ContainerReference: ContainerReference{ Name: "/some/container", }, Stats: stats, } ref := ct.Add(time.Duration(N-1) * time.Second) end := cinfo.StatsEndTime() if !ref.Equal(end) { t.Errorf("end time is %v; should be %v", end, ref) } } func TestStatsEndTime(t *testing.T) { N := 10 stats := make([]*ContainerStats, 0, N) ct := time.Now() for i := 0; i < N; i++ { s := &ContainerStats{ Timestamp: ct.Add(time.Duration(i) * time.Second), } stats = append(stats, s) } cinfo := &ContainerInfo{ ContainerReference: ContainerReference{ Name: "/some/container", }, Stats: stats, } ref := ct start := cinfo.StatsStartTime() if !ref.Equal(start) { t.Errorf("start time is %v; should be %v", start, ref) } } ================================================ FILE: info/v1/docker.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Types used for docker containers. package v1 type DockerStatus struct { Version string `json:"version"` APIVersion string `json:"api_version"` KernelVersion string `json:"kernel_version"` OS string `json:"os"` Hostname string `json:"hostname"` RootDir string `json:"root_dir"` Driver string `json:"driver"` DriverStatus map[string]string `json:"driver_status"` ExecDriver string `json:"exec_driver"` NumImages int `json:"num_images"` NumContainers int `json:"num_containers"` } type DockerImage struct { ID string `json:"id"` RepoTags []string `json:"repo_tags"` // repository name and tags. Created int64 `json:"created"` // unix time since creation. VirtualSize int64 `json:"virtual_size"` Size int64 `json:"size"` } ================================================ FILE: info/v1/machine.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package v1 import "time" type FsInfo struct { // Block device associated with the filesystem. Device string `json:"device"` // DeviceMajor is the major identifier of the device, used for correlation with blkio stats DeviceMajor uint64 `json:"-"` // DeviceMinor is the minor identifier of the device, used for correlation with blkio stats DeviceMinor uint64 `json:"-"` // Total number of bytes available on the filesystem. Capacity uint64 `json:"capacity"` // Type of device. Type string `json:"type"` // Total number of inodes available on the filesystem. Inodes uint64 `json:"inodes"` // HasInodes when true, indicates that Inodes info will be available. HasInodes bool `json:"has_inodes"` } type Node struct { Id int `json:"node_id"` // Per-node memory Memory uint64 `json:"memory"` HugePages []HugePagesInfo `json:"hugepages"` Cores []Core `json:"cores"` Caches []Cache `json:"caches"` Distances []uint64 `json:"distances"` } type Core struct { Id int `json:"core_id"` Threads []int `json:"thread_ids"` Caches []Cache `json:"caches"` UncoreCaches []Cache `json:"uncore_caches"` SocketID int `json:"socket_id"` BookID string `json:"book_id,omitempty"` DrawerID string `json:"drawer_id,omitempty"` } type Cache struct { // Id of memory cache Id int `json:"id"` // Size of memory cache in bytes. Size uint64 `json:"size"` // Type of memory cache: data, instruction, or unified. Type string `json:"type"` // Level (distance from cpus) in a multi-level cache hierarchy. Level int `json:"level"` } func (n *Node) FindCore(id int) (bool, int) { for i, n := range n.Cores { if n.Id == id { return true, i } } return false, -1 } // FindCoreByThread returns bool if found Core with same thread as provided and it's index in Node Core array. // If it's not found, returns false and -1. func (n *Node) FindCoreByThread(thread int) (bool, int) { for i, n := range n.Cores { for _, t := range n.Threads { if t == thread { return true, i } } } return false, -1 } func (n *Node) AddThread(thread int, core int) { var coreIdx int if core == -1 { // Assume one hyperthread per core when topology data is missing. core = thread } ok, coreIdx := n.FindCore(core) if !ok { // New core core := Core{Id: core} n.Cores = append(n.Cores, core) coreIdx = len(n.Cores) - 1 } n.Cores[coreIdx].Threads = append(n.Cores[coreIdx].Threads, thread) } func (n *Node) AddNodeCache(c Cache) { n.Caches = append(n.Caches, c) } func (n *Node) AddPerCoreCache(c Cache) { for idx := range n.Cores { n.Cores[idx].Caches = append(n.Cores[idx].Caches, c) } } type HugePagesInfo struct { // huge page size (in kB) PageSize uint64 `json:"page_size"` // number of huge pages NumPages uint64 `json:"num_pages"` } type DiskInfo struct { // device name Name string `json:"name"` // Major number Major uint64 `json:"major"` // Minor number Minor uint64 `json:"minor"` // Size in bytes Size uint64 `json:"size"` // I/O Scheduler - one of "none", "noop", "cfq", "deadline" Scheduler string `json:"scheduler"` } type NetInfo struct { // Device name Name string `json:"name"` // Mac Address MacAddress string `json:"mac_address"` // Speed in MBits/s Speed int64 `json:"speed"` // Maximum Transmission Unit Mtu int64 `json:"mtu"` } type CloudProvider string const ( GCE CloudProvider = "GCE" AWS CloudProvider = "AWS" Azure CloudProvider = "Azure" UnknownProvider CloudProvider = "Unknown" ) type InstanceType string const ( UnknownInstance = "Unknown" ) type InstanceID string const ( UnNamedInstance InstanceID = "None" ) type MachineInfo struct { // The time of this information point. Timestamp time.Time `json:"timestamp"` // Vendor id of CPU. CPUVendorID string `json:"vendor_id"` // The number of cores in this machine. NumCores int `json:"num_cores"` // The number of physical cores in this machine. NumPhysicalCores int `json:"num_physical_cores"` // The number of cpu sockets in this machine. NumSockets int `json:"num_sockets"` // The number of cpu books in this machine. NumBooks int `json:"num_books,omitempty"` // The number of cpu drawers in this machine. NumDrawers int `json:"num_drawers,omitempty"` // Maximum clock speed for the cores, in KHz. CpuFrequency uint64 `json:"cpu_frequency_khz"` // The amount of memory (in bytes) in this machine MemoryCapacity uint64 `json:"memory_capacity"` // The amount of swap (in bytes) in this machine SwapCapacity uint64 `json:"swap_capacity"` // Memory capacity and number of DIMMs by memory type MemoryByType map[string]*MemoryInfo `json:"memory_by_type"` NVMInfo NVMInfo `json:"nvm"` // HugePages on this machine. HugePages []HugePagesInfo `json:"hugepages"` // The machine id MachineID string `json:"machine_id"` // The system uuid SystemUUID string `json:"system_uuid"` // The boot id BootID string `json:"boot_id"` // Filesystems on this machine. Filesystems []FsInfo `json:"filesystems"` // Disk map DiskMap map[string]DiskInfo `json:"disk_map"` // Network devices NetworkDevices []NetInfo `json:"network_devices"` // Machine Topology // Describes cpu/memory layout and hierarchy. Topology []Node `json:"topology"` // Cloud provider the machine belongs to. CloudProvider CloudProvider `json:"cloud_provider"` // Type of cloud instance (e.g. GCE standard) the machine is. InstanceType InstanceType `json:"instance_type"` // ID of cloud instance (e.g. instance-1) given to it by the cloud provider. InstanceID InstanceID `json:"instance_id"` } func (m *MachineInfo) Clone() *MachineInfo { memoryByType := m.MemoryByType if len(m.MemoryByType) > 0 { memoryByType = make(map[string]*MemoryInfo) for memoryType, memoryInfo := range m.MemoryByType { memoryByType[memoryType] = memoryInfo } } diskMap := m.DiskMap if len(m.DiskMap) > 0 { diskMap = make(map[string]DiskInfo) for k, info := range m.DiskMap { diskMap[k] = info } } copy := MachineInfo{ CPUVendorID: m.CPUVendorID, Timestamp: m.Timestamp, NumCores: m.NumCores, NumPhysicalCores: m.NumPhysicalCores, NumSockets: m.NumSockets, NumBooks: m.NumBooks, NumDrawers: m.NumDrawers, CpuFrequency: m.CpuFrequency, MemoryCapacity: m.MemoryCapacity, SwapCapacity: m.SwapCapacity, MemoryByType: memoryByType, NVMInfo: m.NVMInfo, HugePages: m.HugePages, MachineID: m.MachineID, SystemUUID: m.SystemUUID, BootID: m.BootID, Filesystems: m.Filesystems, DiskMap: diskMap, NetworkDevices: m.NetworkDevices, Topology: m.Topology, CloudProvider: m.CloudProvider, InstanceType: m.InstanceType, InstanceID: m.InstanceID, } return © } type MemoryInfo struct { // The amount of memory (in bytes). Capacity uint64 `json:"capacity"` // Number of memory DIMMs. DimmCount uint `json:"dimm_count"` } type NVMInfo struct { // The total NVM capacity in bytes for memory mode. MemoryModeCapacity uint64 `json:"memory_mode_capacity"` //The total NVM capacity in bytes for app direct mode. AppDirectModeCapacity uint64 `json:"app direct_mode_capacity"` // Average power budget in watts for NVM devices configured in BIOS. AvgPowerBudget uint `json:"avg_power_budget"` } type VersionInfo struct { // Kernel version. KernelVersion string `json:"kernel_version"` // OS image being used for cadvisor container, or host image if running on host directly. ContainerOsVersion string `json:"container_os_version"` // Docker version. DockerVersion string `json:"docker_version"` // Docker API Version DockerAPIVersion string `json:"docker_api_version"` // cAdvisor version. CadvisorVersion string `json:"cadvisor_version"` // cAdvisor git revision. CadvisorRevision string `json:"cadvisor_revision"` } type MachineInfoFactory interface { GetMachineInfo() (*MachineInfo, error) GetVersionInfo() (*VersionInfo, error) } ================================================ FILE: info/v1/machine_test.go ================================================ // Copyright 2023 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package v1 import ( "reflect" "testing" "time" "github.com/stretchr/testify/assert" ) func TestMachineInfoClone(t *testing.T) { machineInfo := getFakeMachineInfo() // Make sure all fields are populated machineInfoReflection := reflect.ValueOf(machineInfo) for i := 0; i < machineInfoReflection.NumField(); i++ { assert.Falsef(t, machineInfoReflection.Field(i).IsZero(), "field %s is not populated", machineInfoReflection.Type().Field(i).Name) } clonedMachineInfo := *machineInfo.Clone() assert.Equal(t, machineInfo, clonedMachineInfo, "cloned machine info should be equal to the original") } func getFakeMachineInfo() MachineInfo { return MachineInfo{ Timestamp: time.Now(), CPUVendorID: "fake-id", NumCores: 1, NumPhysicalCores: 2, NumSockets: 3, NumBooks: 1, NumDrawers: 1, CpuFrequency: 4, MemoryCapacity: 5, SwapCapacity: 6, MemoryByType: map[string]*MemoryInfo{ "fake": {Capacity: 2, DimmCount: 3}, }, NVMInfo: NVMInfo{ MemoryModeCapacity: 2, AppDirectModeCapacity: 6, AvgPowerBudget: 3, }, HugePages: []HugePagesInfo{{ PageSize: 512, NumPages: 343, }}, MachineID: "fake-machine-id", SystemUUID: "fake-uuid", BootID: "fake-boot-id", Filesystems: []FsInfo{{ Device: "dev", DeviceMajor: 1, DeviceMinor: 2, Capacity: 3, Type: "fake-type", Inodes: 4, HasInodes: true, }}, DiskMap: map[string]DiskInfo{"fake-disk": { Name: "fake", Major: 1, Minor: 2, Size: 3, Scheduler: "sched", }}, NetworkDevices: []NetInfo{{ Name: "fake-net-info", MacAddress: "123", Speed: 2, Mtu: 3, }}, Topology: []Node{{ Id: 1, Memory: 2, }}, CloudProvider: "fake-provider", InstanceType: "fake-instance-type", InstanceID: "fake-instance-id", } } ================================================ FILE: info/v1/metric.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package v1 import ( "time" ) // Type of metric being exported. type MetricType string const ( // Instantaneous value. May increase or decrease. MetricGauge MetricType = "gauge" // A counter-like value that is only expected to increase. MetricCumulative MetricType = "cumulative" ) // DataType for metric being exported. type DataType string const ( IntType DataType = "int" FloatType DataType = "float" ) // Spec for custom metric. type MetricSpec struct { // The name of the metric. Name string `json:"name"` // Type of the metric. Type MetricType `json:"type"` // Data Type for the stats. Format DataType `json:"format"` // Display Units for the stats. Units string `json:"units"` } // An exported metric. type MetricValBasic struct { // Time at which the metric was queried Timestamp time.Time `json:"timestamp"` // The value of the metric at this point. IntValue int64 `json:"int_value,omitempty"` FloatValue float64 `json:"float_value,omitempty"` } // An exported metric. type MetricVal struct { // Label associated with a metric Label string `json:"label,omitempty"` Labels map[string]string `json:"labels,omitempty"` // Time at which the metric was queried Timestamp time.Time `json:"timestamp"` // The value of the metric at this point. IntValue int64 `json:"int_value,omitempty"` FloatValue float64 `json:"float_value,omitempty"` } ================================================ FILE: info/v1/test/datagen.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "fmt" "math/rand" "time" info "github.com/google/cadvisor/info/v1" ) func GenerateRandomStats(numStats, numCores int, duration time.Duration) []*info.ContainerStats { ret := make([]*info.ContainerStats, numStats) perCoreUsages := make([]uint64, numCores) currentTime := time.Now() for i := range perCoreUsages { perCoreUsages[i] = uint64(rand.Int63n(1000)) } for i := 0; i < numStats; i++ { stats := new(info.ContainerStats) stats.Timestamp = currentTime currentTime = currentTime.Add(duration) percore := make([]uint64, numCores) for i := range perCoreUsages { perCoreUsages[i] += uint64(rand.Int63n(1000)) percore[i] = perCoreUsages[i] stats.Cpu.Usage.Total += percore[i] } stats.Cpu.Usage.PerCpu = percore stats.Cpu.Usage.User = stats.Cpu.Usage.Total stats.Cpu.Usage.System = 0 stats.Memory.Usage = uint64(rand.Int63n(4096)) stats.Memory.Cache = uint64(rand.Int63n(4096)) stats.Memory.RSS = uint64(rand.Int63n(4096)) stats.Memory.MappedFile = uint64(rand.Int63n(4096)) stats.Memory.KernelUsage = uint64(rand.Int63n(4096)) stats.ReferencedMemory = uint64(rand.Int63n(1000)) ret[i] = stats } return ret } func GenerateRandomContainerSpec(numCores int) info.ContainerSpec { ret := info.ContainerSpec{ CreationTime: time.Now(), HasCpu: true, Cpu: info.CpuSpec{}, HasMemory: true, Memory: info.MemorySpec{}, } ret.Cpu.Limit = uint64(1000 + rand.Int63n(2000)) ret.Cpu.MaxLimit = uint64(1000 + rand.Int63n(2000)) ret.Cpu.Mask = fmt.Sprintf("0-%d", numCores-1) ret.Memory.Limit = uint64(4096 + rand.Int63n(4096)) return ret } func GenerateRandomContainerInfo(containerName string, numCores int, query *info.ContainerInfoRequest, duration time.Duration) *info.ContainerInfo { stats := GenerateRandomStats(query.NumStats, numCores, duration) spec := GenerateRandomContainerSpec(numCores) ret := &info.ContainerInfo{ ContainerReference: info.ContainerReference{ Name: containerName, }, Spec: spec, Stats: stats, } return ret } ================================================ FILE: info/v2/container.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package v2 import ( "time" // TODO(rjnagal): Remove dependency after moving all stats structs from v1. // using v1 now for easy conversion. v1 "github.com/google/cadvisor/info/v1" ) const ( TypeName = "name" TypeDocker = "docker" TypePodman = "podman" ) type CpuSpec struct { // Requested cpu shares. Default is 1024. Limit uint64 `json:"limit"` // Requested cpu hard limit. Default is unlimited (0). // Units: milli-cpus. MaxLimit uint64 `json:"max_limit"` // Cpu affinity mask. // TODO(rjnagal): Add a library to convert mask string to set of cpu bitmask. Mask string `json:"mask,omitempty"` // CPUQuota Default is disabled Quota uint64 `json:"quota,omitempty"` // Period is the CPU reference time in ns e.g the quota is compared against this. Period uint64 `json:"period,omitempty"` } type MemorySpec struct { // The amount of memory requested. Default is unlimited (-1). // Units: bytes. Limit uint64 `json:"limit,omitempty"` // The amount of guaranteed memory. Default is 0. // Units: bytes. Reservation uint64 `json:"reservation,omitempty"` // The amount of swap space requested. Default is unlimited (-1). // Units: bytes. SwapLimit uint64 `json:"swap_limit,omitempty"` } type ContainerInfo struct { // Describes the container. Spec ContainerSpec `json:"spec,omitempty"` // Historical statistics gathered from the container. Stats []*ContainerStats `json:"stats,omitempty"` } type ContainerSpec struct { // Time at which the container was created. CreationTime time.Time `json:"creation_time,omitempty"` // Time at which the container was started. // This may be unset if the runtime does not provide it. StartTime time.Time `json:"start_time,omitempty"` // Other names by which the container is known within a certain namespace. // This is unique within that namespace. Aliases []string `json:"aliases,omitempty"` // Namespace under which the aliases of a container are unique. // An example of a namespace is "docker" for Docker containers. Namespace string `json:"namespace,omitempty"` // Metadata labels associated with this container. Labels map[string]string `json:"labels,omitempty"` // Metadata envs associated with this container. Only whitelisted envs are added. Envs map[string]string `json:"envs,omitempty"` HasCpu bool `json:"has_cpu"` Cpu CpuSpec `json:"cpu,omitempty"` HasMemory bool `json:"has_memory"` Memory MemorySpec `json:"memory,omitempty"` HasHugetlb bool `json:"has_hugetlb"` HasCustomMetrics bool `json:"has_custom_metrics"` CustomMetrics []v1.MetricSpec `json:"custom_metrics,omitempty"` HasProcesses bool `json:"has_processes"` Processes v1.ProcessSpec `json:"processes,omitempty"` // Following resources have no associated spec, but are being isolated. HasNetwork bool `json:"has_network"` HasFilesystem bool `json:"has_filesystem"` HasDiskIo bool `json:"has_diskio"` // Image name used for this container. Image string `json:"image,omitempty"` } type DeprecatedContainerStats struct { // The time of this stat point. Timestamp time.Time `json:"timestamp"` // CPU statistics HasCpu bool `json:"has_cpu"` // In nanoseconds (aggregated) Cpu v1.CpuStats `json:"cpu,omitempty"` // In nanocores per second (instantaneous) CpuInst *CpuInstStats `json:"cpu_inst,omitempty"` // Disk IO statistics HasDiskIo bool `json:"has_diskio"` DiskIo v1.DiskIoStats `json:"diskio,omitempty"` // Memory statistics HasMemory bool `json:"has_memory"` Memory v1.MemoryStats `json:"memory,omitempty"` // Hugepage statistics HasHugetlb bool `json:"has_hugetlb"` Hugetlb map[string]v1.HugetlbStats `json:"hugetlb,omitempty"` // Network statistics HasNetwork bool `json:"has_network"` Network NetworkStats `json:"network,omitempty"` // Processes statistics HasProcesses bool `json:"has_processes"` Processes v1.ProcessStats `json:"processes,omitempty"` // Filesystem statistics HasFilesystem bool `json:"has_filesystem"` Filesystem []v1.FsStats `json:"filesystem,omitempty"` // Task load statistics HasLoad bool `json:"has_load"` Load v1.LoadStats `json:"load_stats,omitempty"` // Custom Metrics HasCustomMetrics bool `json:"has_custom_metrics"` CustomMetrics map[string][]v1.MetricVal `json:"custom_metrics,omitempty"` // Perf events counters PerfStats []v1.PerfStat `json:"perf_stats,omitempty"` // Statistics originating from perf uncore events. // Applies only for root container. PerfUncoreStats []v1.PerfUncoreStat `json:"perf_uncore_stats,omitempty"` // Referenced memory ReferencedMemory uint64 `json:"referenced_memory,omitempty"` // Resource Control (resctrl) statistics Resctrl v1.ResctrlStats `json:"resctrl,omitempty"` } type ContainerStats struct { // The time of this stat point. Timestamp time.Time `json:"timestamp"` // CPU statistics // In nanoseconds (aggregated) Cpu *v1.CpuStats `json:"cpu,omitempty"` // In nanocores per second (instantaneous) CpuInst *CpuInstStats `json:"cpu_inst,omitempty"` // Disk IO statistics DiskIo *v1.DiskIoStats `json:"diskio,omitempty"` // Memory statistics Memory *v1.MemoryStats `json:"memory,omitempty"` // Hugepage statistics Hugetlb *map[string]v1.HugetlbStats `json:"hugetlb,omitempty"` // Network statistics Network *NetworkStats `json:"network,omitempty"` // Processes statistics Processes *v1.ProcessStats `json:"processes,omitempty"` // Filesystem statistics Filesystem *FilesystemStats `json:"filesystem,omitempty"` // Task load statistics Load *v1.LoadStats `json:"load_stats,omitempty"` // Metrics for Accelerators. Each Accelerator corresponds to one element in the array. Accelerators []v1.AcceleratorStats `json:"accelerators,omitempty"` // Custom Metrics CustomMetrics map[string][]v1.MetricVal `json:"custom_metrics,omitempty"` // Perf events counters PerfStats []v1.PerfStat `json:"perf_stats,omitempty"` // Statistics originating from perf uncore events. // Applies only for root container. PerfUncoreStats []v1.PerfUncoreStat `json:"perf_uncore_stats,omitempty"` // Referenced memory ReferencedMemory uint64 `json:"referenced_memory,omitempty"` // Resource Control (resctrl) statistics Resctrl v1.ResctrlStats `json:"resctrl,omitempty"` } type Percentiles struct { // Indicates whether the stats are present or not. // If true, values below do not have any data. Present bool `json:"present"` // Average over the collected sample. Mean uint64 `json:"mean"` // Standard deviation of the collected sample. Std uint64 `json:"std"` // Max seen over the collected sample. Max uint64 `json:"max"` // 50th percentile over the collected sample. Fifty uint64 `json:"fifty"` // 90th percentile over the collected sample. Ninety uint64 `json:"ninety"` // 95th percentile over the collected sample. NinetyFive uint64 `json:"ninetyfive"` // Number of samples used to calculate these percentiles. Count uint64 `json:"count"` } type Usage struct { // Indicates amount of data available [0-100]. // If we have data for half a day, we'll still process DayUsage, // but set PercentComplete to 50. PercentComplete int32 `json:"percent_complete"` // Mean, Max, and 90p cpu rate value in milliCpus/seconds. Converted to milliCpus to avoid floats. Cpu Percentiles `json:"cpu"` // Mean, Max, and 90p memory size in bytes. Memory Percentiles `json:"memory"` } // latest sample collected for a container. type InstantUsage struct { // cpu rate in cpu milliseconds/second. Cpu uint64 `json:"cpu"` // Memory usage in bytes. Memory uint64 `json:"memory"` } type DerivedStats struct { // Time of generation of these stats. Timestamp time.Time `json:"timestamp"` // Latest instantaneous sample. LatestUsage InstantUsage `json:"latest_usage"` // Percentiles in last observed minute. MinuteUsage Usage `json:"minute_usage"` // Percentile in last hour. HourUsage Usage `json:"hour_usage"` // Percentile in last day. DayUsage Usage `json:"day_usage"` } type FsInfo struct { // Time of generation of these stats. Timestamp time.Time `json:"timestamp"` // The block device name associated with the filesystem. Device string `json:"device"` // Path where the filesystem is mounted. Mountpoint string `json:"mountpoint"` // Filesystem usage in bytes. Capacity uint64 `json:"capacity"` // Bytes available for non-root use. Available uint64 `json:"available"` // Number of bytes used on this filesystem. Usage uint64 `json:"usage"` // Labels associated with this filesystem. Labels []string `json:"labels"` // Number of Inodes. Inodes *uint64 `json:"inodes,omitempty"` // Number of available Inodes (if known) InodesFree *uint64 `json:"inodes_free,omitempty"` } type RequestOptions struct { // Type of container identifier specified - TypeName (default) or TypeDocker IdType string `json:"type"` // Number of stats to return, -1 means no limit. Count int `json:"count"` // Whether to include stats for child subcontainers. Recursive bool `json:"recursive"` // Update stats if they are older than MaxAge // nil indicates no update, and 0 will always trigger an update. MaxAge *time.Duration `json:"max_age"` } type ProcessInfo struct { User string `json:"user"` Pid int `json:"pid"` Ppid int `json:"parent_pid"` StartTime string `json:"start_time"` PercentCpu float32 `json:"percent_cpu"` PercentMemory float32 `json:"percent_mem"` RSS uint64 `json:"rss"` VirtualSize uint64 `json:"virtual_size"` Status string `json:"status"` RunningTime string `json:"running_time"` CgroupPath string `json:"cgroup_path"` Cmd string `json:"cmd"` FdCount int `json:"fd_count"` Psr int `json:"psr"` } type TcpStat struct { Established uint64 SynSent uint64 SynRecv uint64 FinWait1 uint64 FinWait2 uint64 TimeWait uint64 Close uint64 CloseWait uint64 LastAck uint64 Listen uint64 Closing uint64 } type NetworkStats struct { // Network stats by interface. Interfaces []v1.InterfaceStats `json:"interfaces,omitempty"` // TCP connection stats (Established, Listen...) Tcp TcpStat `json:"tcp"` // TCP6 connection stats (Established, Listen...) Tcp6 TcpStat `json:"tcp6"` // UDP connection stats Udp v1.UdpStat `json:"udp"` // UDP6 connection stats Udp6 v1.UdpStat `json:"udp6"` // TCP advanced stats TcpAdvanced v1.TcpAdvancedStat `json:"tcp_advanced"` } // Instantaneous CPU stats type CpuInstStats struct { Usage CpuInstUsage `json:"usage"` } // CPU usage time statistics. type CpuInstUsage struct { // Total CPU usage. // Units: nanocores per second Total uint64 `json:"total"` // Per CPU/core usage of the container. // Unit: nanocores per second PerCpu []uint64 `json:"per_cpu_usage,omitempty"` // Time spent in user space. // Unit: nanocores per second User uint64 `json:"user"` // Time spent in kernel space. // Unit: nanocores per second System uint64 `json:"system"` } // Filesystem usage statistics. type FilesystemStats struct { // Total Number of bytes consumed by container. TotalUsageBytes *uint64 `json:"totalUsageBytes,omitempty"` // Number of bytes consumed by a container through its root filesystem. BaseUsageBytes *uint64 `json:"baseUsageBytes,omitempty"` // Number of inodes used within the container's root filesystem. // This only accounts for inodes that are shared across containers, // and does not include inodes used in mounted directories. InodeUsage *uint64 `json:"containter_inode_usage,omitempty"` } ================================================ FILE: info/v2/conversion.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package v2 import ( "fmt" "time" "k8s.io/klog/v2" v1 "github.com/google/cadvisor/info/v1" ) func machineFsStatsFromV1(fsStats []v1.FsStats) []MachineFsStats { var result []MachineFsStats for i := range fsStats { stat := fsStats[i] readDuration := time.Millisecond * time.Duration(stat.ReadTime) writeDuration := time.Millisecond * time.Duration(stat.WriteTime) ioDuration := time.Millisecond * time.Duration(stat.IoTime) weightedDuration := time.Millisecond * time.Duration(stat.WeightedIoTime) machineFsStat := MachineFsStats{ Device: stat.Device, Type: stat.Type, Capacity: &stat.Limit, Usage: &stat.Usage, Available: &stat.Available, DiskStats: DiskStats{ ReadsCompleted: &stat.ReadsCompleted, ReadsMerged: &stat.ReadsMerged, SectorsRead: &stat.SectorsRead, ReadDuration: &readDuration, WritesCompleted: &stat.WritesCompleted, WritesMerged: &stat.WritesMerged, SectorsWritten: &stat.SectorsWritten, WriteDuration: &writeDuration, IoInProgress: &stat.IoInProgress, IoDuration: &ioDuration, WeightedIoDuration: &weightedDuration, }, } if stat.HasInodes { machineFsStat.InodesFree = &stat.InodesFree } result = append(result, machineFsStat) } return result } func MachineStatsFromV1(cont *v1.ContainerInfo) []MachineStats { var stats []MachineStats var last *v1.ContainerStats for i := range cont.Stats { val := cont.Stats[i] stat := MachineStats{ Timestamp: val.Timestamp, } if cont.Spec.HasCpu { stat.Cpu = &val.Cpu cpuInst, err := InstCpuStats(last, val) if err != nil { klog.Warningf("Could not get instant cpu stats: %v", err) } else { stat.CpuInst = cpuInst } last = val } if cont.Spec.HasMemory { stat.Memory = &val.Memory } if cont.Spec.HasNetwork { stat.Network = &NetworkStats{ // FIXME: Use reflection instead. Tcp: TcpStat(val.Network.Tcp), Tcp6: TcpStat(val.Network.Tcp6), Interfaces: val.Network.Interfaces, } } if cont.Spec.HasFilesystem { stat.Filesystem = machineFsStatsFromV1(val.Filesystem) } // TODO(rjnagal): Handle load stats. stats = append(stats, stat) } return stats } func ContainerStatsFromV1(containerName string, spec *v1.ContainerSpec, stats []*v1.ContainerStats) []*ContainerStats { newStats := make([]*ContainerStats, 0, len(stats)) var last *v1.ContainerStats for _, val := range stats { stat := &ContainerStats{ Timestamp: val.Timestamp, ReferencedMemory: val.ReferencedMemory, } if spec.HasCpu { stat.Cpu = &val.Cpu cpuInst, err := InstCpuStats(last, val) if err != nil { klog.Warningf("Could not get instant cpu stats: %v", err) } else { stat.CpuInst = cpuInst } last = val } if spec.HasMemory { stat.Memory = &val.Memory } if spec.HasHugetlb { stat.Hugetlb = &val.Hugetlb } if spec.HasNetwork { // TODO: Handle TcpStats stat.Network = &NetworkStats{ Tcp: TcpStat(val.Network.Tcp), Tcp6: TcpStat(val.Network.Tcp6), Interfaces: val.Network.Interfaces, } } if spec.HasProcesses { stat.Processes = &val.Processes } if spec.HasFilesystem { if len(val.Filesystem) == 1 { stat.Filesystem = &FilesystemStats{ TotalUsageBytes: &val.Filesystem[0].Usage, BaseUsageBytes: &val.Filesystem[0].BaseUsage, InodeUsage: &val.Filesystem[0].Inodes, } } else if len(val.Filesystem) > 1 && containerName != "/" { // Cannot handle multiple devices per container. klog.V(4).Infof("failed to handle multiple devices for container %s. Skipping Filesystem stats", containerName) } } if spec.HasDiskIo { stat.DiskIo = &val.DiskIo } if spec.HasCustomMetrics { stat.CustomMetrics = val.CustomMetrics } if len(val.Accelerators) > 0 { stat.Accelerators = val.Accelerators } if len(val.PerfStats) > 0 { stat.PerfStats = val.PerfStats } if len(val.PerfUncoreStats) > 0 { stat.PerfUncoreStats = val.PerfUncoreStats } if len(val.Resctrl.MemoryBandwidth) > 0 || len(val.Resctrl.Cache) > 0 { stat.Resctrl = val.Resctrl } // TODO(rjnagal): Handle load stats. newStats = append(newStats, stat) } return newStats } func DeprecatedStatsFromV1(cont *v1.ContainerInfo) []DeprecatedContainerStats { stats := make([]DeprecatedContainerStats, 0, len(cont.Stats)) var last *v1.ContainerStats for _, val := range cont.Stats { stat := DeprecatedContainerStats{ Timestamp: val.Timestamp, HasCpu: cont.Spec.HasCpu, HasMemory: cont.Spec.HasMemory, HasHugetlb: cont.Spec.HasHugetlb, HasNetwork: cont.Spec.HasNetwork, HasFilesystem: cont.Spec.HasFilesystem, HasDiskIo: cont.Spec.HasDiskIo, HasCustomMetrics: cont.Spec.HasCustomMetrics, ReferencedMemory: val.ReferencedMemory, } if stat.HasCpu { stat.Cpu = val.Cpu cpuInst, err := InstCpuStats(last, val) if err != nil { klog.Warningf("Could not get instant cpu stats: %v", err) } else { stat.CpuInst = cpuInst } last = val } if stat.HasMemory { stat.Memory = val.Memory } if stat.HasHugetlb { stat.Hugetlb = val.Hugetlb } if stat.HasNetwork { stat.Network.Interfaces = val.Network.Interfaces } if stat.HasProcesses { stat.Processes = val.Processes } if stat.HasFilesystem { stat.Filesystem = val.Filesystem } if stat.HasDiskIo { stat.DiskIo = val.DiskIo } if stat.HasCustomMetrics { stat.CustomMetrics = val.CustomMetrics } if len(val.PerfStats) > 0 { stat.PerfStats = val.PerfStats } if len(val.PerfUncoreStats) > 0 { stat.PerfUncoreStats = val.PerfUncoreStats } if len(val.Resctrl.MemoryBandwidth) > 0 || len(val.Resctrl.Cache) > 0 { stat.Resctrl = val.Resctrl } // TODO(rjnagal): Handle load stats. stats = append(stats, stat) } return stats } func InstCpuStats(last, cur *v1.ContainerStats) (*CpuInstStats, error) { if last == nil { return nil, nil } if !cur.Timestamp.After(last.Timestamp) { return nil, fmt.Errorf("container stats move backwards in time") } if len(last.Cpu.Usage.PerCpu) != len(cur.Cpu.Usage.PerCpu) { return nil, fmt.Errorf("different number of cpus") } timeDelta := cur.Timestamp.Sub(last.Timestamp) // Nanoseconds to gain precision and avoid having zero seconds if the // difference between the timestamps is just under a second timeDeltaNs := uint64(timeDelta.Nanoseconds()) convertToRate := func(lastValue, curValue uint64) (uint64, error) { if curValue < lastValue { return 0, fmt.Errorf("cumulative stats decrease") } valueDelta := curValue - lastValue // Use float64 to keep precision return uint64(float64(valueDelta) / float64(timeDeltaNs) * 1e9), nil } total, err := convertToRate(last.Cpu.Usage.Total, cur.Cpu.Usage.Total) if err != nil { return nil, err } percpu := make([]uint64, len(last.Cpu.Usage.PerCpu)) for i := range percpu { var err error percpu[i], err = convertToRate(last.Cpu.Usage.PerCpu[i], cur.Cpu.Usage.PerCpu[i]) if err != nil { return nil, err } } user, err := convertToRate(last.Cpu.Usage.User, cur.Cpu.Usage.User) if err != nil { return nil, err } system, err := convertToRate(last.Cpu.Usage.System, cur.Cpu.Usage.System) if err != nil { return nil, err } return &CpuInstStats{ Usage: CpuInstUsage{ Total: total, PerCpu: percpu, User: user, System: system, }, }, nil } // Get V2 container spec from v1 container info. func ContainerSpecFromV1(specV1 *v1.ContainerSpec, aliases []string, namespace string) ContainerSpec { specV2 := ContainerSpec{ CreationTime: specV1.CreationTime, StartTime: specV1.StartTime, HasCpu: specV1.HasCpu, HasMemory: specV1.HasMemory, HasHugetlb: specV1.HasHugetlb, HasFilesystem: specV1.HasFilesystem, HasNetwork: specV1.HasNetwork, HasProcesses: specV1.HasProcesses, HasDiskIo: specV1.HasDiskIo, HasCustomMetrics: specV1.HasCustomMetrics, Image: specV1.Image, Labels: specV1.Labels, Envs: specV1.Envs, } if specV1.HasCpu { specV2.Cpu.Limit = specV1.Cpu.Limit specV2.Cpu.MaxLimit = specV1.Cpu.MaxLimit specV2.Cpu.Mask = specV1.Cpu.Mask } if specV1.HasMemory { specV2.Memory.Limit = specV1.Memory.Limit specV2.Memory.Reservation = specV1.Memory.Reservation specV2.Memory.SwapLimit = specV1.Memory.SwapLimit } if specV1.HasCustomMetrics { specV2.CustomMetrics = specV1.CustomMetrics } specV2.Aliases = aliases specV2.Namespace = namespace return specV2 } ================================================ FILE: info/v2/conversion_test.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package v2 import ( "reflect" "testing" "time" "github.com/stretchr/testify/assert" v1 "github.com/google/cadvisor/info/v1" ) var ( timestamp = time.Date(1987, time.August, 10, 0, 0, 0, 0, time.UTC) labels = map[string]string{"foo": "bar"} envs = map[string]string{"foo": "bar"} ) func TestContainerSpecFromV1(t *testing.T) { startTime := timestamp.Add(1 * time.Hour) v1Spec := v1.ContainerSpec{ CreationTime: timestamp, StartTime: startTime, Labels: labels, Envs: envs, HasCpu: true, Cpu: v1.CpuSpec{ Limit: 2048, MaxLimit: 4096, Mask: "cpu_mask", }, HasMemory: true, Memory: v1.MemorySpec{ Limit: 2048, Reservation: 1024, SwapLimit: 8192, }, HasHugetlb: true, HasNetwork: true, HasProcesses: true, HasFilesystem: true, HasDiskIo: true, HasCustomMetrics: true, CustomMetrics: []v1.MetricSpec{{ Name: "foo", Type: v1.MetricGauge, Format: v1.IntType, Units: "bars", }}, Image: "gcr.io/kubernetes/kubernetes:v1", } aliases := []string{"baz", "oof"} namespace := "foo_bar_baz" expectedV2Spec := ContainerSpec{ CreationTime: timestamp, StartTime: startTime, Labels: labels, Envs: envs, HasCpu: true, Cpu: CpuSpec{ Limit: 2048, MaxLimit: 4096, Mask: "cpu_mask", }, HasMemory: true, Memory: MemorySpec{ Limit: 2048, Reservation: 1024, SwapLimit: 8192, }, HasHugetlb: true, HasNetwork: true, HasProcesses: true, HasFilesystem: true, HasDiskIo: true, HasCustomMetrics: true, CustomMetrics: []v1.MetricSpec{{ Name: "foo", Type: v1.MetricGauge, Format: v1.IntType, Units: "bars", }}, Image: "gcr.io/kubernetes/kubernetes:v1", Aliases: aliases, Namespace: namespace, } v2Spec := ContainerSpecFromV1(&v1Spec, aliases, namespace) if !reflect.DeepEqual(v2Spec, expectedV2Spec) { t.Errorf("Converted spec differs from expectation!\nExpected: %+v\n Got: %+v\n", expectedV2Spec, v2Spec) } } func TestContainerStatsFromV1(t *testing.T) { v1Spec := v1.ContainerSpec{ CreationTime: timestamp, Labels: labels, HasCpu: true, Cpu: v1.CpuSpec{ Limit: 2048, MaxLimit: 4096, Mask: "cpu_mask", }, HasMemory: true, Memory: v1.MemorySpec{ Limit: 2048, Reservation: 1024, SwapLimit: 8192, }, HasHugetlb: true, HasNetwork: true, HasProcesses: true, HasFilesystem: true, HasDiskIo: true, HasCustomMetrics: true, CustomMetrics: []v1.MetricSpec{{ Name: "foo", Type: v1.MetricGauge, Format: v1.IntType, Units: "bars", }}, Image: "gcr.io/kubernetes/kubernetes:v1", } v1Stats := v1.ContainerStats{ Timestamp: timestamp, Memory: v1.MemoryStats{ Usage: 1, Cache: 2, RSS: 3, WorkingSet: 4, Failcnt: 5, TotalActiveFile: 6, TotalInactiveFile: 7, ContainerData: v1.MemoryStatsMemoryData{ Pgfault: 1, Pgmajfault: 2, }, HierarchicalData: v1.MemoryStatsMemoryData{ Pgfault: 10, Pgmajfault: 20, }, }, Network: v1.NetworkStats{ InterfaceStats: v1.InterfaceStats{ Name: "", RxBytes: 1, RxPackets: 2, RxErrors: 3, RxDropped: 4, TxBytes: 5, TxPackets: 6, TxErrors: 7, TxDropped: 8, }, Interfaces: []v1.InterfaceStats{{ Name: "eth0", RxBytes: 10, RxPackets: 20, RxErrors: 30, RxDropped: 40, TxBytes: 50, TxPackets: 60, TxErrors: 70, TxDropped: 80, }}, }, Processes: v1.ProcessStats{ ProcessCount: 5, FdCount: 1, ThreadsCurrent: 66, ThreadsMax: 6000, }, Filesystem: []v1.FsStats{{ Device: "dev0", Limit: 500, Usage: 100, BaseUsage: 50, Available: 300, InodesFree: 100, }}, Accelerators: []v1.AcceleratorStats{{ Make: "nvidia", Model: "tesla-p100", ID: "GPU-deadbeef-1234-5678-90ab-feedfacecafe", MemoryTotal: 20304050607, MemoryUsed: 2030405060, DutyCycle: 12, }}, PerfStats: []v1.PerfStat{ { PerfValue: v1.PerfValue{ ScalingRatio: 1, Value: 123, Name: "instructions", }, }, { PerfValue: v1.PerfValue{ ScalingRatio: 0.3333333, Value: 123456, Name: "cycles", }, }, }, PerfUncoreStats: []v1.PerfUncoreStat{ { PerfValue: v1.PerfValue{ ScalingRatio: 1.0, Value: 123456, Name: "uncore_imc_0/cas_count_write", }, Socket: 0, PMU: "17", }, { PerfValue: v1.PerfValue{ ScalingRatio: 1.0, Value: 654321, Name: "uncore_imc_0/cas_count_write", }, Socket: 1, PMU: "17", }, }, ReferencedMemory: uint64(1234), Resctrl: v1.ResctrlStats{ MemoryBandwidth: []v1.MemoryBandwidthStats{ { TotalBytes: 72312331, LocalBytes: 1233311, }, { TotalBytes: 32312331, LocalBytes: 2233311, }, }, Cache: []v1.CacheStats{ { LLCOccupancy: 123123441, }, { LLCOccupancy: 123313111, }, }, }, } expectedV2Stats := ContainerStats{ Timestamp: timestamp, Cpu: &v1Stats.Cpu, DiskIo: &v1Stats.DiskIo, Memory: &v1Stats.Memory, Hugetlb: &v1Stats.Hugetlb, Processes: &v1Stats.Processes, Network: &NetworkStats{ Interfaces: v1Stats.Network.Interfaces, }, Filesystem: &FilesystemStats{ TotalUsageBytes: &v1Stats.Filesystem[0].Usage, BaseUsageBytes: &v1Stats.Filesystem[0].BaseUsage, InodeUsage: &v1Stats.Filesystem[0].Inodes, }, Accelerators: v1Stats.Accelerators, PerfStats: v1Stats.PerfStats, PerfUncoreStats: v1Stats.PerfUncoreStats, ReferencedMemory: v1Stats.ReferencedMemory, Resctrl: v1Stats.Resctrl, } v2Stats := ContainerStatsFromV1("test", &v1Spec, []*v1.ContainerStats{&v1Stats}) actualV2Stats := *v2Stats[0] if !reflect.DeepEqual(expectedV2Stats, actualV2Stats) { t.Errorf("Converted stats differs from expectation!\nExpected: %+v\n Got: %+v\n", expectedV2Stats, actualV2Stats) } } func TestInstCpuStats(t *testing.T) { tests := []struct { last *v1.ContainerStats cur *v1.ContainerStats want *CpuInstStats }{ // Last is missing { nil, &v1.ContainerStats{}, nil, }, // Goes back in time { &v1.ContainerStats{ Timestamp: time.Unix(100, 0).Add(time.Second), }, &v1.ContainerStats{ Timestamp: time.Unix(100, 0), }, nil, }, // Zero time delta { &v1.ContainerStats{ Timestamp: time.Unix(100, 0), }, &v1.ContainerStats{ Timestamp: time.Unix(100, 0), }, nil, }, // Different number of cpus { &v1.ContainerStats{ Timestamp: time.Unix(100, 0), Cpu: v1.CpuStats{ Usage: v1.CpuUsage{ PerCpu: []uint64{100, 200}, }, }, }, &v1.ContainerStats{ Timestamp: time.Unix(100, 0).Add(time.Second), Cpu: v1.CpuStats{ Usage: v1.CpuUsage{ PerCpu: []uint64{100, 200, 300}, }, }, }, nil, }, // Stat numbers decrease { &v1.ContainerStats{ Timestamp: time.Unix(100, 0), Cpu: v1.CpuStats{ Usage: v1.CpuUsage{ Total: 300, PerCpu: []uint64{100, 200}, User: 250, System: 50, }, }, }, &v1.ContainerStats{ Timestamp: time.Unix(100, 0).Add(time.Second), Cpu: v1.CpuStats{ Usage: v1.CpuUsage{ Total: 200, PerCpu: []uint64{100, 100}, User: 150, System: 50, }, }, }, nil, }, // One second elapsed { &v1.ContainerStats{ Timestamp: time.Unix(100, 0), Cpu: v1.CpuStats{ Usage: v1.CpuUsage{ Total: 300, PerCpu: []uint64{100, 200}, User: 250, System: 50, }, }, }, &v1.ContainerStats{ Timestamp: time.Unix(100, 0).Add(time.Second), Cpu: v1.CpuStats{ Usage: v1.CpuUsage{ Total: 500, PerCpu: []uint64{200, 300}, User: 400, System: 100, }, }, }, &CpuInstStats{ Usage: CpuInstUsage{ Total: 200, PerCpu: []uint64{100, 100}, User: 150, System: 50, }, }, }, // Two seconds elapsed { &v1.ContainerStats{ Timestamp: time.Unix(100, 0), Cpu: v1.CpuStats{ Usage: v1.CpuUsage{ Total: 300, PerCpu: []uint64{100, 200}, User: 250, System: 50, }, }, }, &v1.ContainerStats{ Timestamp: time.Unix(100, 0).Add(2 * time.Second), Cpu: v1.CpuStats{ Usage: v1.CpuUsage{ Total: 500, PerCpu: []uint64{200, 300}, User: 400, System: 100, }, }, }, &CpuInstStats{ Usage: CpuInstUsage{ Total: 100, PerCpu: []uint64{50, 50}, User: 75, System: 25, }, }, }, } for _, c := range tests { got, err := InstCpuStats(c.last, c.cur) if err != nil { if c.want == nil { continue } t.Errorf("Unexpected error: %v", err) } assert.Equal(t, c.want, got) } } ================================================ FILE: info/v2/machine.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package v2 import ( // TODO(rjnagal): Move structs from v1. "time" v1 "github.com/google/cadvisor/info/v1" ) type Attributes struct { // Kernel version. KernelVersion string `json:"kernel_version"` // OS image being used for cadvisor container, or host image if running on host directly. ContainerOsVersion string `json:"container_os_version"` // Docker version. DockerVersion string `json:"docker_version"` // Docker API version. DockerAPIVersion string `json:"docker_api_version"` // cAdvisor version. CadvisorVersion string `json:"cadvisor_version"` // The number of cores in this machine. NumCores int `json:"num_cores"` // Maximum clock speed for the cores, in KHz. CpuFrequency uint64 `json:"cpu_frequency_khz"` // The amount of memory (in bytes) in this machine MemoryCapacity uint64 `json:"memory_capacity"` // The machine id MachineID string `json:"machine_id"` // The system uuid SystemUUID string `json:"system_uuid"` // HugePages on this machine. HugePages []v1.HugePagesInfo `json:"hugepages"` // Filesystems on this machine. Filesystems []v1.FsInfo `json:"filesystems"` // Disk map DiskMap map[string]v1.DiskInfo `json:"disk_map"` // Network devices NetworkDevices []v1.NetInfo `json:"network_devices"` // Machine Topology // Describes cpu/memory layout and hierarchy. Topology []v1.Node `json:"topology"` // Cloud provider the machine belongs to CloudProvider v1.CloudProvider `json:"cloud_provider"` // Type of cloud instance (e.g. GCE standard) the machine is. InstanceType v1.InstanceType `json:"instance_type"` } func GetAttributes(mi *v1.MachineInfo, vi *v1.VersionInfo) Attributes { return Attributes{ KernelVersion: vi.KernelVersion, ContainerOsVersion: vi.ContainerOsVersion, DockerVersion: vi.DockerVersion, DockerAPIVersion: vi.DockerAPIVersion, CadvisorVersion: vi.CadvisorVersion, NumCores: mi.NumCores, CpuFrequency: mi.CpuFrequency, MemoryCapacity: mi.MemoryCapacity, MachineID: mi.MachineID, SystemUUID: mi.SystemUUID, HugePages: mi.HugePages, Filesystems: mi.Filesystems, DiskMap: mi.DiskMap, NetworkDevices: mi.NetworkDevices, Topology: mi.Topology, CloudProvider: mi.CloudProvider, InstanceType: mi.InstanceType, } } // MachineStats contains usage statistics for the entire machine. type MachineStats struct { // The time of this stat point. Timestamp time.Time `json:"timestamp"` // In nanoseconds (aggregated) Cpu *v1.CpuStats `json:"cpu,omitempty"` // In nanocores per second (instantaneous) CpuInst *CpuInstStats `json:"cpu_inst,omitempty"` // Memory statistics Memory *v1.MemoryStats `json:"memory,omitempty"` // Network statistics Network *NetworkStats `json:"network,omitempty"` // Filesystem statistics Filesystem []MachineFsStats `json:"filesystem,omitempty"` // Task load statistics Load *v1.LoadStats `json:"load_stats,omitempty"` } // MachineFsStats contains per filesystem capacity and usage information. type MachineFsStats struct { // The block device name associated with the filesystem. Device string `json:"device"` // Type of filesystem. Type string `json:"type"` // Number of bytes that can be consumed on this filesystem. Capacity *uint64 `json:"capacity,omitempty"` // Number of bytes that is currently consumed on this filesystem. Usage *uint64 `json:"usage,omitempty"` // Number of bytes available for non-root user on this filesystem. Available *uint64 `json:"available,omitempty"` // Number of inodes that are available on this filesystem. InodesFree *uint64 `json:"inodes_free,omitempty"` // DiskStats for this device. DiskStats `json:"inline"` } // DiskStats contains per partition usage information. // This information is only available at the machine level. type DiskStats struct { // Number of reads completed // This is the total number of reads completed successfully. ReadsCompleted *uint64 `json:"reads_completed,omitempty"` // Number of reads merged // Reads and writes which are adjacent to each other may be merged for // efficiency. Thus two 4K reads may become one 8K read before it is // ultimately handed to the disk, and so it will be counted (and queued) // as only one I/O. This field lets you know how often this was done. ReadsMerged *uint64 `json:"reads_merged,omitempty"` // Number of sectors read // This is the total number of sectors read successfully. SectorsRead *uint64 `json:"sectors_read,omitempty"` // Time spent reading // This is the total number of milliseconds spent by all reads (as // measured from __make_request() to end_that_request_last()). ReadDuration *time.Duration `json:"read_duration,omitempty"` // Number of writes completed // This is the total number of writes completed successfully. WritesCompleted *uint64 `json:"writes_completed,omitempty"` // Number of writes merged // See the description of reads merged. WritesMerged *uint64 `json:"writes_merged,omitempty"` // Number of sectors written // This is the total number of sectors written successfully. SectorsWritten *uint64 `json:"sectors_written,omitempty"` // Time spent writing // This is the total number of milliseconds spent by all writes (as // measured from __make_request() to end_that_request_last()). WriteDuration *time.Duration `json:"write_duration,omitempty"` // Number of I/Os currently in progress // The only field that should go to zero. Incremented as requests are // given to appropriate struct request_queue and decremented as they finish. IoInProgress *uint64 `json:"io_in_progress,omitempty"` // Time spent doing I/Os // This field increases so long as field 9 is nonzero. IoDuration *time.Duration `json:"io_duration,omitempty"` // weighted time spent doing I/Os // This field is incremented at each I/O start, I/O completion, I/O // merge, or read of these stats by the number of I/Os in progress // (field 9) times the number of milliseconds spent doing I/O since the // last update of this field. This can provide an easy measure of both // I/O completion time and the backlog that may be accumulating. WeightedIoDuration *time.Duration `json:"weighted_io_duration,omitempty"` } ================================================ FILE: integration/framework/framework.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package framework import ( "bytes" "encoding/json" "flag" "fmt" "os" "os/exec" "path/filepath" "strings" "testing" "time" "k8s.io/klog/v2" "github.com/google/cadvisor/client" v2 "github.com/google/cadvisor/client/v2" ) var host = flag.String("host", "localhost", "Address of the host being tested") var port = flag.Int("port", 8080, "Port of the application on the host being tested") var sshOptions = flag.String("ssh-options", "", "Command line options for ssh") // Integration test framework. type Framework interface { // Clean the framework state. Cleanup() // The testing.T used by the framework and the current test. T() *testing.T // Returns the hostname being tested. Hostname() HostnameInfo // Returns the Docker actions for the test framework. Docker() DockerActions // Returns the CRI-O actions for the test framework. Crio() CrioActions // Returns the containerd actions for the test framework. Containerd() ContainerdActions // Returns the shell actions for the test framework. Shell() ShellActions // Returns the cAdvisor actions for the test framework. Cadvisor() CadvisorActions } // Instantiates a Framework. Cleanup *must* be called. Class is thread-compatible. // All framework actions report fatal errors on the t specified at creation time. // // Typical use: // // func TestFoo(t *testing.T) { // fm := framework.New(t) // defer fm.Cleanup() // ... actual test ... // } func New(t *testing.T) Framework { // All integration tests are large. if testing.Short() { t.Skip("Skipping framework test in short mode") } // Try to see if non-localhost hosts are GCE instances. fm := &realFramework{ hostname: HostnameInfo{ Host: *host, Port: *port, }, t: t, cleanups: make([]func(), 0), } fm.shellActions = shellActions{ fm: fm, } fm.dockerActions = dockerActions{ fm: fm, } fm.crioActions = crioActions{ fm: fm, podSeqNum: 0, } fm.containerdActions = containerdActions{ fm: fm, seqNum: 0, namespace: "k8s.io", socket: getContainerdSocket(), snapshotter: "native", } return fm } // getContainerdSocket returns the containerd socket path from CONTAINERD_SOCK env var. func getContainerdSocket() string { if sock := os.Getenv("CONTAINERD_SOCK"); sock != "" { return sock } return "/run/containerd/containerd.sock" } const ( Aufs string = "aufs" Overlay string = "overlay" Overlay2 string = "overlay2" DeviceMapper string = "devicemapper" Unknown string = "" ) type DockerActions interface { // Run the no-op pause Docker container and return its ID. RunPause() string // Run the specified command in a Docker busybox container and return its ID. RunBusybox(cmd ...string) string // Runs a Docker container in the background. Uses the specified DockerRunArgs and command. // Returns the ID of the new container. // // e.g.: // Run(DockerRunArgs{Image: "busybox"}, "ping", "www.google.com") // -> docker run busybox ping www.google.com Run(args DockerRunArgs, cmd ...string) string RunStress(args DockerRunArgs, cmd ...string) string Version() []string StorageDriver() string } // CrioActions provides methods for managing CRI-O containers in tests. // CRI-O containers run inside pod sandboxes, so each container requires // a pod to be created first. type CrioActions interface { // Run the no-op pause CRI-O container and return its ID. RunPause() string // Run the specified command in a CRI-O busybox container and return its ID. RunBusybox(cmd ...string) string // Runs a CRI-O container in the background. Uses the specified CrioRunArgs and command. // Returns the ID of the new container. Run(args CrioRunArgs, cmd ...string) string } // CrioRunArgs contains arguments for running a CRI-O container. type CrioRunArgs struct { // Image to use. Image string // Container name (optional, auto-generated if empty). Name string } // ContainerdActions provides methods for managing containerd containers in tests. // Containerd containers are created directly using the ctr CLI tool. type ContainerdActions interface { // Run the no-op pause containerd container and return its ID. RunPause() string // Run the specified command in a containerd busybox container and return its ID. RunBusybox(cmd ...string) string // Runs a containerd container in the background. Uses the specified ContainerdRunArgs and command. // Returns the ID of the new container. Run(args ContainerdRunArgs, cmd ...string) string } // ContainerdRunArgs contains arguments for running a containerd container. type ContainerdRunArgs struct { // Image to use. Image string // Container name (optional, auto-generated if empty). Name string // Labels to add to the container. Labels map[string]string } type ShellActions interface { // Runs a specified command and arguments. Returns the stdout and stderr. Run(cmd string, args ...string) (string, string) RunStress(cmd string, args ...string) (string, string) } type CadvisorActions interface { // Returns a cAdvisor client to the machine being tested. Client() *client.Client ClientV2() *v2.Client } type realFramework struct { hostname HostnameInfo t *testing.T cadvisorClient *client.Client cadvisorClientV2 *v2.Client shellActions shellActions dockerActions dockerActions crioActions crioActions containerdActions containerdActions // Cleanup functions to call on Cleanup() cleanups []func() } type shellActions struct { fm *realFramework } type dockerActions struct { fm *realFramework } type crioActions struct { fm *realFramework podSeqNum int // For generating unique pod names } type containerdActions struct { fm *realFramework seqNum int // For generating unique container names namespace string // containerd namespace (default: k8s.io) socket string // containerd socket path snapshotter string // containerd snapshotter (default: native) } type HostnameInfo struct { Host string Port int } // Returns: http://:/ func (h HostnameInfo) FullHostname() string { return fmt.Sprintf("http://%s:%d/", h.Host, h.Port) } func (f *realFramework) T() *testing.T { return f.t } func (f *realFramework) Hostname() HostnameInfo { return f.hostname } func (f *realFramework) Shell() ShellActions { return f.shellActions } func (f *realFramework) Docker() DockerActions { return f.dockerActions } func (f *realFramework) Crio() CrioActions { return &f.crioActions } func (f *realFramework) Containerd() ContainerdActions { return &f.containerdActions } func (f *realFramework) Cadvisor() CadvisorActions { return f } // Call all cleanup functions. func (f *realFramework) Cleanup() { for _, cleanupFunc := range f.cleanups { cleanupFunc() } } // Gets a client to the cAdvisor being tested. func (f *realFramework) Client() *client.Client { if f.cadvisorClient == nil { cadvisorClient, err := client.NewClient(f.Hostname().FullHostname()) if err != nil { f.t.Fatalf("Failed to instantiate the cAdvisor client: %v", err) } f.cadvisorClient = cadvisorClient } return f.cadvisorClient } // Gets a v2 client to the cAdvisor being tested. func (f *realFramework) ClientV2() *v2.Client { if f.cadvisorClientV2 == nil { cadvisorClientV2, err := v2.NewClient(f.Hostname().FullHostname()) if err != nil { f.t.Fatalf("Failed to instantiate the cAdvisor client: %v", err) } f.cadvisorClientV2 = cadvisorClientV2 } return f.cadvisorClientV2 } func (a dockerActions) RunPause() string { return a.Run(DockerRunArgs{ Image: "registry.k8s.io/pause", }) } // Run the specified command in a Docker busybox container. func (a dockerActions) RunBusybox(cmd ...string) string { return a.Run(DockerRunArgs{ Image: "registry.k8s.io/busybox:1.27", }, cmd...) } type DockerRunArgs struct { // Image to use. Image string // Arguments to the Docker CLI. Args []string InnerArgs []string } // TODO(vmarmol): Use the Docker remote API. // TODO(vmarmol): Refactor a set of "RunCommand" actions. // Runs a Docker container in the background. Uses the specified DockerRunArgs and command. // // e.g.: // RunDockerContainer(DockerRunArgs{Image: "busybox"}, "ping", "www.google.com") // // -> docker run busybox ping www.google.com func (a dockerActions) Run(args DockerRunArgs, cmd ...string) string { dockerCommand := append(append([]string{"docker", "run", "-d"}, args.Args...), args.Image) dockerCommand = append(dockerCommand, cmd...) output, _ := a.fm.Shell().Run("sudo", dockerCommand...) // The last line is the container ID. elements := strings.Fields(output) containerID := elements[len(elements)-1] a.fm.cleanups = append(a.fm.cleanups, func() { a.fm.Shell().Run("sudo", "docker", "rm", "-f", containerID) }) return containerID } func (a dockerActions) Version() []string { dockerCommand := []string{"docker", "version", "-f", "'{{.Server.Version}}'"} output, _ := a.fm.Shell().Run("sudo", dockerCommand...) output = strings.TrimSpace(output) ret := strings.Split(output, ".") if len(ret) != 3 { a.fm.T().Fatalf("invalid version %v", output) } return ret } func (a dockerActions) StorageDriver() string { dockerCommand := []string{"docker", "info"} output, _ := a.fm.Shell().Run("sudo", dockerCommand...) if len(output) < 1 { a.fm.T().Fatalf("failed to find docker storage driver - %v", output) } for _, line := range strings.Split(output, "\n") { line = strings.TrimSpace(line) if strings.HasPrefix(line, "Storage Driver: ") { idx := strings.LastIndex(line, ": ") + 2 driver := line[idx:] switch driver { case Aufs, Overlay, Overlay2, DeviceMapper: return driver default: return Unknown } } } a.fm.T().Fatalf("failed to find docker storage driver from info - %v", output) return Unknown } func (a dockerActions) RunStress(args DockerRunArgs, cmd ...string) string { dockerCommand := append(append(append(append([]string{"docker", "run", "-m=4M", "-d", "-t", "-i"}, args.Args...), args.Image), args.InnerArgs...), cmd...) output, _ := a.fm.Shell().RunStress("sudo", dockerCommand...) // The last line is the container ID. if len(output) < 1 { a.fm.T().Fatalf("need 1 arguments in output %v to get the name but have %v", output, len(output)) } elements := strings.Fields(output) containerID := elements[len(elements)-1] a.fm.cleanups = append(a.fm.cleanups, func() { a.fm.Shell().Run("sudo", "docker", "rm", "-f", containerID) }) return containerID } func (a shellActions) wrapSSH(command string, args ...string) *exec.Cmd { cmd := []string{a.fm.Hostname().Host, "--", "sh", "-c", "\"", command} cmd = append(cmd, args...) cmd = append(cmd, "\"") if *sshOptions != "" { cmd = append(strings.Split(*sshOptions, " "), cmd...) } return exec.Command("ssh", cmd...) } func (a shellActions) Run(command string, args ...string) (string, string) { var cmd *exec.Cmd if a.fm.Hostname().Host == "localhost" { // Just run locally. cmd = exec.Command(command, args...) } else { // We must SSH to the remote machine and run the command. cmd = a.wrapSSH(command, args...) } var stdout bytes.Buffer var stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr klog.Infof("About to run - %v", cmd.Args) err := cmd.Run() if err != nil { a.fm.T().Fatalf("Failed to run %q %v in %q with error: %q. Stdout: %q, Stderr: %s", command, args, a.fm.Hostname().Host, err, stdout.String(), stderr.String()) return "", "" } return stdout.String(), stderr.String() } func (a shellActions) RunStress(command string, args ...string) (string, string) { var cmd *exec.Cmd if a.fm.Hostname().Host == "localhost" { // Just run locally. cmd = exec.Command(command, args...) } else { // We must SSH to the remote machine and run the command. cmd = a.wrapSSH(command, args...) } var stdout bytes.Buffer var stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() if err != nil { a.fm.T().Logf("Ran %q %v in %q and received error: %q. Stdout: %q, Stderr: %s", command, args, a.fm.Hostname().Host, err, stdout.String(), stderr.String()) return stdout.String(), stderr.String() } return stdout.String(), stderr.String() } // Runs retryFunc until no error is returned. After dur time the last error is returned. // Note that the function does not timeout the execution of retryFunc when the limit is reached. func RetryForDuration(retryFunc func() error, dur time.Duration) error { waitUntil := time.Now().Add(dur) var err error for time.Now().Before(waitUntil) { err = retryFunc() if err == nil { return nil } } return err } // CRI-O pod sandbox configuration for crictl type crioPodConfig struct { Metadata struct { Name string `json:"name"` Namespace string `json:"namespace"` UID string `json:"uid"` } `json:"metadata"` Linux struct{} `json:"linux"` } // CRI-O container configuration for crictl type crioContainerConfig struct { Metadata struct { Name string `json:"name"` } `json:"metadata"` Image struct { Image string `json:"image"` } `json:"image"` Command []string `json:"command,omitempty"` Args []string `json:"args,omitempty"` Linux struct{} `json:"linux"` } func (a *crioActions) RunPause() string { return a.Run(CrioRunArgs{ Image: "registry.k8s.io/pause:3.9", }) } func (a *crioActions) RunBusybox(cmd ...string) string { return a.Run(CrioRunArgs{ Image: "registry.k8s.io/busybox:1.27", }, cmd...) } func (a *crioActions) Run(args CrioRunArgs, cmd ...string) string { // Generate unique names for pod and container a.podSeqNum++ podName := fmt.Sprintf("test-pod-%d-%d", os.Getpid(), a.podSeqNum) containerName := args.Name if containerName == "" { containerName = fmt.Sprintf("test-container-%d-%d", os.Getpid(), a.podSeqNum) } // Create temporary directory for config files tmpDir, err := os.MkdirTemp("", "crio-test-") if err != nil { a.fm.T().Fatalf("Failed to create temp directory: %v", err) } // Create pod config JSON podConfig := crioPodConfig{} podConfig.Metadata.Name = podName podConfig.Metadata.Namespace = "default" podConfig.Metadata.UID = fmt.Sprintf("uid-%d-%d", os.Getpid(), a.podSeqNum) podConfigPath := filepath.Join(tmpDir, "pod-config.json") podConfigData, err := json.Marshal(podConfig) if err != nil { a.fm.T().Fatalf("Failed to marshal pod config: %v", err) } if err := os.WriteFile(podConfigPath, podConfigData, 0644); err != nil { a.fm.T().Fatalf("Failed to write pod config: %v", err) } // Create container config JSON containerConfig := crioContainerConfig{} containerConfig.Metadata.Name = containerName containerConfig.Image.Image = args.Image if len(cmd) > 0 { containerConfig.Command = cmd[:1] if len(cmd) > 1 { containerConfig.Args = cmd[1:] } } containerConfigPath := filepath.Join(tmpDir, "container-config.json") containerConfigData, err := json.Marshal(containerConfig) if err != nil { a.fm.T().Fatalf("Failed to marshal container config: %v", err) } if err := os.WriteFile(containerConfigPath, containerConfigData, 0644); err != nil { a.fm.T().Fatalf("Failed to write container config: %v", err) } // Pull the image first klog.Infof("Pulling image %s", args.Image) a.fm.Shell().Run("sudo", "crictl", "pull", args.Image) // Create pod sandbox klog.Infof("Creating pod sandbox %s", podName) podOutput, _ := a.fm.Shell().Run("sudo", "crictl", "runp", podConfigPath) podID := strings.TrimSpace(podOutput) if podID == "" { a.fm.T().Fatalf("Failed to create pod sandbox, got empty pod ID") } klog.Infof("Created pod sandbox with ID: %s", podID) // Create container klog.Infof("Creating container %s in pod %s", containerName, podID) containerOutput, _ := a.fm.Shell().Run("sudo", "crictl", "create", podID, containerConfigPath, podConfigPath) containerID := strings.TrimSpace(containerOutput) if containerID == "" { a.fm.T().Fatalf("Failed to create container, got empty container ID") } klog.Infof("Created container with ID: %s", containerID) // Start container klog.Infof("Starting container %s", containerID) a.fm.Shell().Run("sudo", "crictl", "start", containerID) // Register cleanup function (in reverse order: container first, then pod) a.fm.cleanups = append(a.fm.cleanups, func() { klog.Infof("Cleaning up container %s and pod %s", containerID, podID) // Stop and remove container a.fm.Shell().Run("sudo", "crictl", "stop", containerID) a.fm.Shell().Run("sudo", "crictl", "rm", containerID) // Stop and remove pod a.fm.Shell().Run("sudo", "crictl", "stopp", podID) a.fm.Shell().Run("sudo", "crictl", "rmp", podID) // Clean up temp directory os.RemoveAll(tmpDir) }) return containerID } // Containerd actions implementation func (a *containerdActions) RunPause() string { return a.Run(ContainerdRunArgs{ Image: "registry.k8s.io/pause:3.9", }) } func (a *containerdActions) RunBusybox(cmd ...string) string { return a.Run(ContainerdRunArgs{ Image: "registry.k8s.io/busybox:1.27", }, cmd...) } // Run creates and starts a containerd container using the ctr CLI. // It uses the configured namespace (default "moby" for Docker-in-Docker environments). func (a *containerdActions) Run(args ContainerdRunArgs, cmd ...string) string { a.seqNum++ containerName := args.Name if containerName == "" { // Generate a unique 64-char hex container ID // cAdvisor's containerd handler expects container IDs to match this format // Use timestamp in nanoseconds to ensure uniqueness across test runs containerName = fmt.Sprintf("%016x%016x%016x%016x", os.Getpid(), a.seqNum, time.Now().UnixNano(), time.Now().UnixNano()%1000000) } // Build the ctr command // ctr -a -n run -d [cmd...] ctrArgs := []string{ "ctr", "--address", a.socket, "--namespace", a.namespace, } // Pull the image first klog.Infof("Pulling containerd image %s", args.Image) pullArgs := append(ctrArgs, "image", "pull", args.Image) a.fm.Shell().Run("sudo", pullArgs...) // Build the run command // Use the configured snapshotter (from CONTAINERD_SNAPSHOTTER env var, default overlayfs) runArgs := append(ctrArgs, "run", "-d", "--snapshotter", a.snapshotter) // Add labels if specified for key, value := range args.Labels { runArgs = append(runArgs, "--label", fmt.Sprintf("%s=%s", key, value)) } // Add the image and container name runArgs = append(runArgs, args.Image, containerName) // Add the command if specified if len(cmd) > 0 { runArgs = append(runArgs, cmd...) } klog.Infof("Creating containerd container %s", containerName) a.fm.Shell().Run("sudo", runArgs...) // ctr run returns the container ID (which is the same as the name we provided) containerID := containerName klog.Infof("Created containerd container with ID: %s", containerID) // Register cleanup function // Use RunStress for cleanup commands to avoid test failures when containers have already exited a.fm.cleanups = append(a.fm.cleanups, func() { klog.Infof("Cleaning up containerd container %s", containerID) // Kill the task with SIGKILL to ensure it stops immediately // Use RunStress so we don't fail if the task has already exited killArgs := append([]string{"ctr", "--address", a.socket, "--namespace", a.namespace}, "task", "kill", "--signal", "SIGKILL", containerID) a.fm.Shell().RunStress("sudo", killArgs...) // Wait a moment for the task to stop time.Sleep(500 * time.Millisecond) // Delete the task (with force flag) deleteTaskArgs := append([]string{"ctr", "--address", a.socket, "--namespace", a.namespace}, "task", "delete", "-f", containerID) a.fm.Shell().RunStress("sudo", deleteTaskArgs...) // Delete the container deleteArgs := append([]string{"ctr", "--address", a.socket, "--namespace", a.namespace}, "container", "delete", containerID) a.fm.Shell().RunStress("sudo", deleteArgs...) }) return containerID } ================================================ FILE: integration/framework/metrics.go ================================================ // Copyright 2024 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package framework import ( "fmt" "io" "net/http" "strings" "time" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" ) // MetricsClient provides methods for fetching and parsing Prometheus metrics // from cAdvisor's /metrics endpoint. type MetricsClient struct { baseURL string httpClient *http.Client } // NewMetricsClient creates a new client for the /metrics endpoint. func NewMetricsClient(hostname HostnameInfo) *MetricsClient { return &MetricsClient{ baseURL: hostname.FullHostname(), httpClient: &http.Client{ Timeout: 30 * time.Second, }, } } // Fetch retrieves raw metrics text from the /metrics endpoint. func (m *MetricsClient) Fetch() (string, error) { return m.FetchWithParams("") } // FetchWithParams retrieves metrics with optional query parameters. // Parameters can be "type=docker" or "type=name" to filter containers. func (m *MetricsClient) FetchWithParams(params string) (string, error) { url := m.baseURL + "metrics" if params != "" { url += "?" + params } resp, err := m.httpClient.Get(url) if err != nil { return "", fmt.Errorf("failed to fetch metrics: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return "", fmt.Errorf("metrics endpoint returned %d: %s", resp.StatusCode, string(body)) } body, err := io.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("failed to read response: %w", err) } return string(body), nil } // Parse converts Prometheus text format to metric families. func (m *MetricsClient) Parse(metricsText string) (map[string]*dto.MetricFamily, error) { parser := expfmt.TextParser{} return parser.TextToMetricFamilies(strings.NewReader(metricsText)) } // FetchAndParse combines Fetch and Parse into one call. func (m *MetricsClient) FetchAndParse() (map[string]*dto.MetricFamily, error) { text, err := m.Fetch() if err != nil { return nil, err } return m.Parse(text) } // HasMetric checks if a metric family exists by name. func HasMetric(families map[string]*dto.MetricFamily, name string) bool { _, ok := families[name] return ok } // GetMetricFamily returns a specific metric family by name. func GetMetricFamily(families map[string]*dto.MetricFamily, name string) (*dto.MetricFamily, bool) { mf, ok := families[name] return mf, ok } // FindMetricWithLabels finds a metric matching all specified labels. // Returns nil if no matching metric is found. func FindMetricWithLabels(mf *dto.MetricFamily, labels map[string]string) *dto.Metric { if mf == nil { return nil } for _, metric := range mf.GetMetric() { if matchesLabels(metric, labels) { return metric } } return nil } // FindMetricsWithLabelSubstring finds all metrics where the specified label // contains the given substring. func FindMetricsWithLabelSubstring(mf *dto.MetricFamily, labelName, substring string) []*dto.Metric { if mf == nil { return nil } var result []*dto.Metric for _, metric := range mf.GetMetric() { for _, lp := range metric.GetLabel() { if lp.GetName() == labelName && strings.Contains(lp.GetValue(), substring) { result = append(result, metric) break } } } return result } // GetGaugeValue extracts the value from a gauge metric. func GetGaugeValue(metric *dto.Metric) float64 { if metric == nil || metric.GetGauge() == nil { return 0 } return metric.GetGauge().GetValue() } // GetCounterValue extracts the value from a counter metric. func GetCounterValue(metric *dto.Metric) float64 { if metric == nil || metric.GetCounter() == nil { return 0 } return metric.GetCounter().GetValue() } // GetLabelValue returns the value of a specific label from a metric. // Returns empty string if label is not found. func GetLabelValue(metric *dto.Metric, labelName string) string { if metric == nil { return "" } for _, lp := range metric.GetLabel() { if lp.GetName() == labelName { return lp.GetValue() } } return "" } // ContainsLabelValue checks if any metric in the family has the label // containing the given substring. func ContainsLabelValue(mf *dto.MetricFamily, labelName, substring string) bool { if mf == nil { return false } for _, metric := range mf.GetMetric() { for _, lp := range metric.GetLabel() { if lp.GetName() == labelName && strings.Contains(lp.GetValue(), substring) { return true } } } return false } // GetMetricType returns the type of a metric family as a string. func GetMetricType(mf *dto.MetricFamily) string { if mf == nil { return "unknown" } return mf.GetType().String() } // matchesLabels checks if a metric has all the specified labels with exact values. func matchesLabels(metric *dto.Metric, targetLabels map[string]string) bool { if metric == nil { return false } labelMap := make(map[string]string) for _, lp := range metric.GetLabel() { labelMap[lp.GetName()] = lp.GetValue() } for k, v := range targetLabels { if labelMap[k] != v { return false } } return true } // CountMetrics returns the number of metric samples in a metric family. func CountMetrics(mf *dto.MetricFamily) int { if mf == nil { return 0 } return len(mf.GetMetric()) } // GetAllLabelValues returns all unique values for a given label name across // all metrics in the family. func GetAllLabelValues(mf *dto.MetricFamily, labelName string) []string { if mf == nil { return nil } seen := make(map[string]bool) var values []string for _, metric := range mf.GetMetric() { for _, lp := range metric.GetLabel() { if lp.GetName() == labelName { val := lp.GetValue() if !seen[val] { seen[val] = true values = append(values, val) } } } } return values } ================================================ FILE: integration/runner/retrywhitelist.txt ================================================ Network tx and rx bytes should not be equal Network tx and rx packets should not be equal ================================================ FILE: integration/runner/run.sh ================================================ #!/bin/bash # Copyright 2015 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -e set -x # Check usage. if [ $# == 0 ]; then echo "USAGE: run.sh " exit 1 fi # Don't run on trivial changes. if ! git diff --name-only origin/master | grep -c -E "*.go|*.sh" &> /dev/null; then echo "This PR does not touch files that require integration testing. Skipping integration tests." exit 0 fi # Build the runner. go build github.com/google/cadvisor/integration/runner # Run it. HOSTS=$@ ./runner --logtostderr $HOSTS ================================================ FILE: integration/runner/runner.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "bufio" "bytes" "encoding/json" "errors" "flag" "fmt" "io" "net/http" "os" "os/exec" "path" "regexp" "strconv" "strings" "sync" "time" "k8s.io/klog/v2" cadvisorApi "github.com/google/cadvisor/info/v2" ) // must be able to ssh into hosts without password // go run ./integration/runner/runner.go --logtostderr --v 2 --ssh-config <.ssh/config file> const ( cadvisorBinary = "cadvisor" testTimeout = 15 * time.Minute ) var cadvisorTimeout = flag.Duration("cadvisor_timeout", 15*time.Second, "Time to wait for cAdvisor to come up on the remote host") var port = flag.Int("port", 8080, "Port in which to start cAdvisor in the remote host") var testRetryCount = flag.Int("test-retry-count", 3, "Number of times to retry failed tests before failing.") var testRetryWhitelist = flag.String("test-retry-whitelist", "", "Path to newline separated list of regexexp for test failures that should be retried. If empty, no tests are retried.") var sshOptions = flag.String("ssh-options", "", "Commandline options passed to ssh.") var retryRegex *regexp.Regexp func getAttributes(ipAddress, portStr string) (*cadvisorApi.Attributes, error) { // Get host attributes and log attributes if the tests fail. var attributes cadvisorApi.Attributes resp, err := http.Get(fmt.Sprintf("http://%s:%s/api/v2.1/attributes", ipAddress, portStr)) if err != nil { return nil, fmt.Errorf("failed to get attributes - %v", err) } if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("failed to get attributes. Status code - %v", resp.StatusCode) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("unable to read attributes response body - %v", err) } if err := json.Unmarshal(body, &attributes); err != nil { return nil, fmt.Errorf("failed to unmarshal attributes - %v", err) } return &attributes, nil } func RunCommand(cmd string, args ...string) error { output, err := exec.Command(cmd, args...).CombinedOutput() if err != nil { return fmt.Errorf("command %q %q failed with error: %v and output: %s", cmd, args, err, output) } return nil } func RunSshCommand(cmd string, args ...string) error { if *sshOptions != "" { args = append(strings.Split(*sshOptions, " "), args...) } return RunCommand(cmd, args...) } func PushAndRunTests(host, testDir string) (result error) { // Push binary. klog.Infof("Pushing cAdvisor binary to %q...", host) err := RunSshCommand("ssh", host, "--", "mkdir", "-p", testDir) if err != nil { return fmt.Errorf("failed to make remote testing directory: %v", err) } defer func() { err = RunSshCommand("ssh", host, "--", "rm", "-rf", testDir) if err != nil { klog.Errorf("Failed to cleanup test directory: %v", err) } }() err = RunSshCommand("scp", "-r", cadvisorBinary, fmt.Sprintf("%s:%s", host, testDir)) if err != nil { return fmt.Errorf("failed to copy binary: %v", err) } // Start cAdvisor. klog.Infof("Running cAdvisor on %q...", host) portStr := strconv.Itoa(*port) errChan := make(chan error, 1) go func() { err = RunSshCommand("ssh", host, "--", fmt.Sprintf("sudo GORACE='halt_on_error=1' %s --port %s --logtostderr --env_metadata_whitelist=TEST_VAR &> %s/log.txt", path.Join(testDir, cadvisorBinary), portStr, testDir)) if err != nil { errChan <- fmt.Errorf("error running cAdvisor: %v", err) } }() defer func() { err = RunSshCommand("ssh", host, "--", "sudo", "pkill", cadvisorBinary) if err != nil { klog.Errorf("Failed to cleanup: %v", err) } }() defer func() { if result != nil { // Copy logs from the host err := RunSshCommand("scp", fmt.Sprintf("%s:%s/log.txt", host, testDir), "./") if err != nil { result = fmt.Errorf("error fetching logs: %v for %v", err, result) return } defer os.Remove("./log.txt") logs, err := os.ReadFile("./log.txt") if err != nil { result = fmt.Errorf("error reading local log file: %v for %v", err, result) return } klog.Errorf("----------------------\nLogs from Host: %q\n%v\n", host, string(logs)) // Get attributes for debugging purposes. attributes, err := getAttributes(host, portStr) if err != nil { klog.Errorf("Failed to read host attributes: %v", err) } result = fmt.Errorf("error on host %s: %v\n%+v", host, result, attributes) } }() // Wait for cAdvisor to come up. endTime := time.Now().Add(*cadvisorTimeout) done := false for endTime.After(time.Now()) && !done { select { case err := <-errChan: // Quit early if there was an error. return err case <-time.After(500 * time.Millisecond): // Stop waiting when cAdvisor is healthy.. resp, err := http.Get(fmt.Sprintf("http://%s:%s/healthz", host, portStr)) if err == nil && resp.StatusCode == http.StatusOK { done = true } } } if !done { return fmt.Errorf("timed out waiting for cAdvisor to come up at host %q", host) } // Run the tests in a retry loop. klog.Infof("Running integration tests targeting %q...", host) for i := 0; i <= *testRetryCount; i++ { // Check if this is a retry if i > 0 { time.Sleep(time.Second * 15) // Wait 15 seconds before retrying klog.Warningf("Retrying (%d of %d) tests on host %s due to error %v", i, *testRetryCount, host, err) } // Run the command err = RunCommand("go", "test", "--timeout", testTimeout.String(), "github.com/google/cadvisor/integration/tests/...", "--host", host, "--port", portStr, "--ssh-options", *sshOptions) if err == nil { // On success, break out of retry loop break } // Only retry on test failures caused by these known flaky failure conditions if retryRegex == nil || !retryRegex.Match([]byte(err.Error())) { klog.Warningf("Skipping retry for tests on host %s because error is not whitelisted", host) break } } return err } func Run() error { start := time.Now() defer func() { klog.Infof("Execution time %v", time.Since(start)) }() defer klog.Flush() hosts := flag.Args() testDir := fmt.Sprintf("/tmp/cadvisor-%d", os.Getpid()) klog.Infof("Running integration tests on host(s) %q", strings.Join(hosts, ",")) // Build cAdvisor. klog.Infof("Building cAdvisor...") err := RunCommand("build/build.sh") if err != nil { return err } defer func() { err := RunCommand("rm", cadvisorBinary) if err != nil { klog.Error(err) } }() // Run test on all hosts in parallel. var wg sync.WaitGroup allErrors := make([]error, 0) var allErrorsLock sync.Mutex for _, host := range hosts { wg.Add(1) go func(host string) { defer wg.Done() err := PushAndRunTests(host, testDir) if err != nil { func() { allErrorsLock.Lock() defer allErrorsLock.Unlock() allErrors = append(allErrors, err) }() } }(host) } wg.Wait() if len(allErrors) != 0 { var buffer bytes.Buffer for i, err := range allErrors { buffer.WriteString(fmt.Sprintf("Error %d: ", i)) buffer.WriteString(err.Error()) buffer.WriteString("\n") } return errors.New(buffer.String()) } klog.Infof("All tests pass!") return nil } // initRetryWhitelist initializes the whitelist of test failures that can be retried. func initRetryWhitelist() { if *testRetryWhitelist == "" { return } file, err := os.Open(*testRetryWhitelist) if err != nil { klog.Fatal(err) } defer file.Close() retryStrings := []string{} scanner := bufio.NewScanner(file) for scanner.Scan() { text := scanner.Text() if text != "" { retryStrings = append(retryStrings, text) } } if err := scanner.Err(); err != nil { klog.Fatal(err) } retryRegex = regexp.MustCompile(strings.Join(retryStrings, "|")) } func main() { klog.InitFlags(nil) flag.Parse() // Check usage. if len(flag.Args()) == 0 { klog.Fatalf("USAGE: runner ") } initRetryWhitelist() // Run the tests. err := Run() if err != nil { klog.Fatal(err) } } ================================================ FILE: integration/tests/TODO.md ================================================ Tests to Write: - UI comes up -- / -> /containers -- /containers -- /docker - API tests -- /containers -- /subcontainers ================================================ FILE: integration/tests/api/containerd_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package api import ( "fmt" "os" "testing" "time" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/integration/framework" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // Waits up to 10s for a containerd container with the specified ID to appear in cAdvisor. func waitForContainerdContainer(containerID string, fm framework.Framework) { err := framework.RetryForDuration(func() error { // Query all containers via SubcontainersInfo - containerd containers are in "containerd" namespace allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) if err != nil { return err } // Look for container by ID for _, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { return nil } } // Also check if the container name contains the ID if len(container.Name) > 0 && containsString(container.Name, containerID) { return nil } } return fmt.Errorf("container %q not found in cAdvisor", containerID) }, 10*time.Second) require.NoError(fm.T(), err, "Timed out waiting for containerd container %q to be available in cAdvisor", containerID) } func containsString(s, substr string) bool { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } return false } // Sanity check the container by: // - Checking that the specified ID is a valid alias for this container. // - Verifying that stats are not empty. func sanityCheckContainerd(containerID string, containerInfo info.ContainerInfo, t *testing.T) { assert.Contains(t, containerInfo.Aliases, containerID, "Alias %q should be in list of aliases %v", containerID, containerInfo.Aliases) assert.NotEmpty(t, containerInfo.Stats, "Expected container to have stats") } // findContainerdContainer finds a container by ID in the list of containers. func findContainerdContainer(containerID string, containers []info.ContainerInfo) *info.ContainerInfo { for i, container := range containers { for _, alias := range container.Aliases { if alias == containerID { return &containers[i] } } // Also check if the container name contains the ID if containsString(container.Name, containerID) { return &containers[i] } } return nil } // TestContainerdContainerById tests that cAdvisor can find a containerd container by its ID. func TestContainerdContainerById(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Containerd().RunPause() // Wait for the container to show up in cAdvisor waitForContainerdContainer(containerID, fm) // Query all containers via SubcontainersInfo allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container containerInfo := findContainerdContainer(containerID, allInfo) require.NotNil(t, containerInfo, "Container %q should be found in cAdvisor", containerID) sanityCheckContainerd(containerID, *containerInfo, t) } // TestContainerdContainerByName tests that cAdvisor can find a containerd container by a custom hex ID. // Note: cAdvisor's containerd handler expects 64-char hex container IDs, which is the standard format // used by Kubernetes/CRI. Custom human-readable names are not supported. func TestContainerdContainerByName(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Generate a 64-char hex ID (this is what Kubernetes/CRI uses) containerID := fmt.Sprintf("%032x%032x", os.Getpid(), 999999) _ = fm.Containerd().Run(framework.ContainerdRunArgs{ Image: "registry.k8s.io/pause:3.9", Name: containerID, // Using hex ID as the name }) // Wait for the container to show up waitForContainerdContainer(containerID, fm) // Query all containers via SubcontainersInfo allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container by ID containerInfo := findContainerdContainer(containerID, allInfo) require.NotNil(t, containerInfo, "Container with ID %q should be found in cAdvisor", containerID) sanityCheckContainerd(containerID, *containerInfo, t) } // TestGetAllContainerdContainers tests that cAdvisor can find multiple containerd containers. func TestGetAllContainerdContainers(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start two containers containerID1 := fm.Containerd().RunPause() containerID2 := fm.Containerd().RunPause() // Wait for both containers to show up waitForContainerdContainer(containerID1, fm) waitForContainerdContainer(containerID2, fm) // Query all containers via SubcontainersInfo allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find both containers containerInfo1 := findContainerdContainer(containerID1, allInfo) containerInfo2 := findContainerdContainer(containerID2, allInfo) require.NotNil(t, containerInfo1, "Container %q should be found in cAdvisor", containerID1) require.NotNil(t, containerInfo2, "Container %q should be found in cAdvisor", containerID2) sanityCheckContainerd(containerID1, *containerInfo1, t) sanityCheckContainerd(containerID2, *containerInfo2, t) } // TestBasicContainerdContainer tests basic container properties. func TestBasicContainerdContainer(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Containerd().RunPause() // Wait for the container to show up waitForContainerdContainer(containerID, fm) // Query all containers via SubcontainersInfo allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container containerInfo := findContainerdContainer(containerID, allInfo) require.NotNil(t, containerInfo, "Container %q should be found", containerID) assert.NotEmpty(t, containerInfo.Stats, "Should have at least one stat") } // TestContainerdContainerCpuStats tests CPU statistics collection for containerd containers. func TestContainerdContainerCpuStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Run a busybox container that does some work containerID := fm.Containerd().RunBusybox("sh", "-c", "while true; do echo hello; sleep 1; done") // Wait for the container to show up waitForContainerdContainer(containerID, fm) // Give the container some time to generate CPU usage time.Sleep(2 * time.Second) // Query all containers via SubcontainersInfo allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container containerInfo := findContainerdContainer(containerID, allInfo) require.NotNil(t, containerInfo, "Container %q should be found", containerID) require.NotEmpty(t, containerInfo.Stats, "Should have stats") // Check CPU stats stat := containerInfo.Stats[0] checkCPUStats(t, stat.Cpu) } // TestContainerdContainerMemoryStats tests memory statistics collection for containerd containers. func TestContainerdContainerMemoryStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Run a busybox container containerID := fm.Containerd().RunBusybox("sh", "-c", "while true; do echo hello; sleep 1; done") // Wait for the container to show up waitForContainerdContainer(containerID, fm) // Give the container some time to use memory time.Sleep(2 * time.Second) // Query all containers via SubcontainersInfo allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container containerInfo := findContainerdContainer(containerID, allInfo) require.NotNil(t, containerInfo, "Container %q should be found", containerID) require.NotEmpty(t, containerInfo.Stats, "Should have stats") // Check memory stats stat := containerInfo.Stats[0] checkMemoryStats(t, stat.Memory) } // TestContainerdContainerSpec tests that container spec is correctly populated for containerd containers. func TestContainerdContainerSpec(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Containerd().RunPause() // Wait for the container to show up waitForContainerdContainer(containerID, fm) // Query all containers via SubcontainersInfo allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container containerInfo := findContainerdContainer(containerID, allInfo) require.NotNil(t, containerInfo, "Container %q should be found", containerID) // Check that spec has basic properties assert.True(t, containerInfo.Spec.HasCpu, "CPU should be isolated") assert.True(t, containerInfo.Spec.HasMemory, "Memory should be isolated") } // TestContainerdContainerLabels tests that container labels are correctly captured. func TestContainerdContainerLabels(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Use auto-generated 64-char hex ID (required by cAdvisor's containerd handler) containerID := fm.Containerd().Run(framework.ContainerdRunArgs{ Image: "registry.k8s.io/pause:3.9", Labels: map[string]string{ "test.label.key": "test-value", }, }) // Wait for the container to show up waitForContainerdContainer(containerID, fm) // Query all containers via SubcontainersInfo allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container containerInfo := findContainerdContainer(containerID, allInfo) require.NotNil(t, containerInfo, "Container %q should be found", containerID) // Check that labels are captured assert.Contains(t, containerInfo.Spec.Labels, "test.label.key", "Labels should contain test.label.key") assert.Equal(t, "test-value", containerInfo.Spec.Labels["test.label.key"], "Label value should match") } // TestContainerdContainerCreationTime tests that container creation time is valid. func TestContainerdContainerCreationTime(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() beforeCreation := time.Now().Add(-1 * time.Second) containerID := fm.Containerd().RunPause() waitForContainerdContainer(containerID, fm) afterCreation := time.Now().Add(1 * time.Second) // Query all containers allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) containerInfo := findContainerdContainer(containerID, allInfo) require.NotNil(t, containerInfo, "Container %q should be found", containerID) // Check creation time is within expected range creationTime := containerInfo.Spec.CreationTime assert.True(t, creationTime.After(beforeCreation), "Creation time %v should be after %v", creationTime, beforeCreation) assert.True(t, creationTime.Before(afterCreation), "Creation time %v should be before %v", creationTime, afterCreation) } // TestContainerdContainerDiskIoStats tests DiskIO statistics for containerd containers. func TestContainerdContainerDiskIoStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Run a container that does disk I/O and stays running containerID := fm.Containerd().RunBusybox("sh", "-c", "dd if=/dev/zero of=/tmp/testfile bs=1024 count=1000 && sync && sleep 30") // Wait for the container to show up and do some I/O waitForContainerdContainer(containerID, fm) time.Sleep(3 * time.Second) allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) containerInfo := findContainerdContainer(containerID, allInfo) require.NotNil(t, containerInfo, "Container %q should be found", containerID) // Check that DiskIo stats are present assert.True(t, containerInfo.Spec.HasDiskIo, "Container should have DiskIo isolation") } // TestContainerdContainerImageInfo tests that container image information is captured. func TestContainerdContainerImageInfo(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() expectedImage := "registry.k8s.io/pause:3.9" containerID := fm.Containerd().Run(framework.ContainerdRunArgs{ Image: expectedImage, }) waitForContainerdContainer(containerID, fm) allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) containerInfo := findContainerdContainer(containerID, allInfo) require.NotNil(t, containerInfo, "Container %q should be found", containerID) // Check image name is captured assert.Contains(t, containerInfo.Spec.Image, "pause", "Container image should contain 'pause'") } ================================================ FILE: integration/tests/api/docker_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package api import ( "fmt" "os" "strconv" "testing" "time" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" "github.com/google/cadvisor/integration/framework" "github.com/opencontainers/cgroups" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // Sanity check the container by: // - Checking that the specified alias is a valid one for this container. // - Verifying that stats are not empty. func sanityCheck(alias string, containerInfo info.ContainerInfo, t *testing.T) { assert.Contains(t, containerInfo.Aliases, alias, "Alias %q should be in list of aliases %v", alias, containerInfo.Aliases) assert.NotEmpty(t, containerInfo.Stats, "Expected container to have stats") } // Sanity check the container by: // - Checking that the specified alias is a valid one for this container. // - Verifying that stats are not empty. func sanityCheckV2(alias string, info v2.ContainerInfo, t *testing.T) { assert.Contains(t, info.Spec.Aliases, alias, "Alias %q should be in list of aliases %v", alias, info.Spec.Aliases) assert.NotEmpty(t, info.Stats, "Expected container to have stats") } // Waits up to 5s for a container with the specified alias to appear. func waitForContainer(alias string, fm framework.Framework) { err := framework.RetryForDuration(func() error { ret, err := fm.Cadvisor().Client().DockerContainer(alias, &info.ContainerInfoRequest{ NumStats: 1, }) if err != nil { return err } if len(ret.Stats) != 1 { return fmt.Errorf("no stats returned for container %q", alias) } return nil }, 5*time.Second) require.NoError(fm.T(), err, "Timed out waiting for container %q to be available in cAdvisor: %v", alias, err) } // A Docker container in /docker/ func TestDockerContainerById(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Docker().RunPause() // Wait for the container to show up. waitForContainer(containerID, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) require.NoError(t, err) sanityCheck(containerID, containerInfo, t) } // A Docker container in /docker/ func TestDockerContainerByName(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerName := fmt.Sprintf("test-docker-container-by-name-%d", os.Getpid()) fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/pause", Args: []string{"--name", containerName}, }) // Wait for the container to show up. waitForContainer(containerName, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerName, request) require.NoError(t, err) sanityCheck(containerName, containerInfo, t) } // Find the first container with the specified alias in containers. func findContainer(alias string, containers []info.ContainerInfo, t *testing.T) info.ContainerInfo { for _, cont := range containers { for _, a := range cont.Aliases { if alias == a { return cont } } } t.Fatalf("Failed to find container %q in %+v", alias, containers) return info.ContainerInfo{} } // All Docker containers through /docker func TestGetAllDockerContainers(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Wait for the containers to show up. containerID1 := fm.Docker().RunPause() containerID2 := fm.Docker().RunPause() waitForContainer(containerID1, fm) waitForContainer(containerID2, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } containersInfo, err := fm.Cadvisor().Client().AllDockerContainers(request) require.NoError(t, err) if len(containersInfo) < 2 { t.Fatalf("At least 2 Docker containers should exist, received %d: %+v", len(containersInfo), containersInfo) } sanityCheck(containerID1, findContainer(containerID1, containersInfo, t), t) sanityCheck(containerID2, findContainer(containerID2, containersInfo, t), t) } // Check expected properties of a Docker container. func TestBasicDockerContainer(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerName := fmt.Sprintf("test-basic-docker-container-%d", os.Getpid()) containerID := fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/pause", Args: []string{ "--name", containerName, }, }) // Wait for the container to show up. waitForContainer(containerID, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) require.NoError(t, err) // Check that the container is known by both its name and ID. sanityCheck(containerID, containerInfo, t) sanityCheck(containerName, containerInfo, t) assert.Empty(t, containerInfo.Subcontainers, "Should not have subcontainers") assert.Len(t, containerInfo.Stats, 1, "Should have exactly one stat") } // TODO(vmarmol): Handle if CPU or memory is not isolated on this system. // Check the ContainerSpec. func TestDockerContainerSpec(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() var ( cpuShares = uint64(2048) cpuMask = "0" memoryLimit = uint64(1 << 30) // 1GB image = "registry.k8s.io/pause" env = map[string]string{"test_var": "FOO"} labels = map[string]string{"bar": "baz"} ) containerID := fm.Docker().Run(framework.DockerRunArgs{ Image: image, Args: []string{ "--cpu-shares", strconv.FormatUint(cpuShares, 10), "--cpuset-cpus", cpuMask, "--memory", strconv.FormatUint(memoryLimit, 10), "--env", "TEST_VAR=FOO", "--label", "bar=baz", }, }) // Wait for the container to show up. waitForContainer(containerID, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) require.NoError(t, err) sanityCheck(containerID, containerInfo, t) assert := assert.New(t) assert.True(containerInfo.Spec.HasCpu, "CPU should be isolated") if cgroups.IsCgroup2UnifiedMode() { // cpu shares are rounded slightly on cgroupv2 due to conversion between cgroupv1 (cpu.shares) and cgroupv2 (cpu.weight) // When container is created via docker, runc will convert cpu shares to cpu.weight https://github.com/opencontainers/runc/blob/d11f4d756e85ece5cdba8bb69f8bd4db3cdcbeab/libcontainer/cgroups/utils.go#L423-L428 // And cAdvisor will convert cpu.weight back to cpu shares in https://github.com/google/cadvisor/blob/24e7a9883d12f944fd4403861707f4bafcaf4f3d/container/common/helpers.go#L249-L260 // Worked example: // cpuShares = 2048 (input to docker --cpu-shares) // cpuWeight = int((1 + ((cpuShares-2)*9999)/262142))=79 (conversion done by runc) // cpuWeight back to cpuShares = int(2 + ((cpuWeight-1)*262142)/9999)= 2046 var cgroupV2Shares uint64 = 2046 assert.Equal(cgroupV2Shares, containerInfo.Spec.Cpu.Limit, "Container should have %d shares, has %d", cgroupV2Shares, containerInfo.Spec.Cpu.Limit) } else { assert.Equal(cpuShares, containerInfo.Spec.Cpu.Limit, "Container should have %d shares, has %d", cpuShares, containerInfo.Spec.Cpu.Limit) } assert.Equal(cpuMask, containerInfo.Spec.Cpu.Mask, "Cpu mask should be %q, but is %q", cpuMask, containerInfo.Spec.Cpu.Mask) assert.True(containerInfo.Spec.HasMemory, "Memory should be isolated") assert.Equal(memoryLimit, containerInfo.Spec.Memory.Limit, "Container should have memory limit of %d, has %d", memoryLimit, containerInfo.Spec.Memory.Limit) assert.True(containerInfo.Spec.HasNetwork, "Network should be isolated") assert.True(containerInfo.Spec.HasDiskIo, "Blkio should be isolated") assert.Equal(image, containerInfo.Spec.Image, "Spec should include container image") assert.Equal(env, containerInfo.Spec.Envs, "Spec should include environment variables") assert.Equal(labels, containerInfo.Spec.Labels, "Spec should include labels") } // Check the CPU ContainerStats. func TestDockerContainerCpuStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Wait for the container to show up. containerID := fm.Docker().RunBusybox("ping", "www.google.com") waitForContainer(containerID, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) if err != nil { t.Fatal(err) } sanityCheck(containerID, containerInfo, t) // Checks for CpuStats. checkCPUStats(t, containerInfo.Stats[0].Cpu) } // Check the memory ContainerStats. func TestDockerContainerMemoryStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Wait for the container to show up. containerID := fm.Docker().RunBusybox("ping", "www.google.com") waitForContainer(containerID, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) require.NoError(t, err) sanityCheck(containerID, containerInfo, t) // Checks for MemoryStats. checkMemoryStats(t, containerInfo.Stats[0].Memory) } // Check the network ContainerStats. func TestDockerContainerNetworkStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Wait for the container to show up. containerID := fm.Docker().RunBusybox("watch", "-n1", "wget", "http://www.google.com/") waitForContainer(containerID, fm) // Wait for at least one additional housekeeping interval time.Sleep(20 * time.Second) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) require.NoError(t, err) sanityCheck(containerID, containerInfo, t) stat := containerInfo.Stats[0] ifaceStats := stat.Network.InterfaceStats // macOS we have more than one interface, since traffic is // only on eth0 we need to pick that one if len(stat.Network.Interfaces) > 0 { for _, iface := range stat.Network.Interfaces { if iface.Name == "eth0" { ifaceStats = iface } } } // Checks for NetworkStats. assert := assert.New(t) assert.NotEqual(0, ifaceStats.TxBytes, "Network tx bytes should not be zero") assert.NotEqual(0, ifaceStats.TxPackets, "Network tx packets should not be zero") assert.NotEqual(0, ifaceStats.RxBytes, "Network rx bytes should not be zero") assert.NotEqual(0, ifaceStats.RxPackets, "Network rx packets should not be zero") assert.NotEqual(ifaceStats.RxBytes, ifaceStats.TxBytes, fmt.Sprintf("Network tx (%d) and rx (%d) bytes should not be equal", ifaceStats.TxBytes, ifaceStats.RxBytes)) assert.NotEqual(ifaceStats.RxPackets, ifaceStats.TxPackets, fmt.Sprintf("Network tx (%d) and rx (%d) packets should not be equal", ifaceStats.TxPackets, ifaceStats.RxPackets)) } func TestDockerFilesystemStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() storageDriver := fm.Docker().StorageDriver() if storageDriver == framework.DeviceMapper { // Filesystem stats not supported with devicemapper, yet return } const ( ddUsage = uint64(1 << 3) // 1 KB sleepDuration = 10 * time.Second ) // Wait for the container to show up. // FIXME: Tests should be bundled and run on the remote host instead of being run over ssh. // Escaping bash over ssh is ugly. // Once github issue 1130 is fixed, this logic can be removed. dockerCmd := fmt.Sprintf("dd if=/dev/zero of=/file count=2 bs=%d & ping google.com", ddUsage) if fm.Hostname().Host != "localhost" { dockerCmd = fmt.Sprintf("'%s'", dockerCmd) } containerID := fm.Docker().RunBusybox("/bin/sh", "-c", dockerCmd) waitForContainer(containerID, fm) request := &v2.RequestOptions{ IdType: v2.TypeDocker, Count: 1, } needsBaseUsageCheck := false switch storageDriver { case framework.Aufs, framework.Overlay, framework.Overlay2, framework.DeviceMapper: needsBaseUsageCheck = true } pass := false // We need to wait for the `dd` operation to complete. for i := 0; i < 10; i++ { containerInfo, err := fm.Cadvisor().ClientV2().Stats(containerID, request) if err != nil { t.Logf("%v stats unavailable - %v", time.Now().String(), err) t.Logf("retrying after %s...", sleepDuration.String()) time.Sleep(sleepDuration) continue } require.Equal(t, len(containerInfo), 1) var info v2.ContainerInfo // There is only one container in containerInfo. Since it is a map with unknown key, // use the value blindly. for _, cInfo := range containerInfo { info = cInfo } sanityCheckV2(containerID, info, t) require.NotNil(t, info.Stats[0], "got info: %+v", info) require.NotNil(t, info.Stats[0].Filesystem, "got info: %+v", info) require.NotNil(t, info.Stats[0].Filesystem.TotalUsageBytes, "got info: %+v", info.Stats[0].Filesystem) if *info.Stats[0].Filesystem.TotalUsageBytes >= ddUsage { if !needsBaseUsageCheck { pass = true break } require.NotNil(t, info.Stats[0].Filesystem.BaseUsageBytes) if *info.Stats[0].Filesystem.BaseUsageBytes >= ddUsage { pass = true break } } t.Logf("expected total usage %d bytes to be greater than %d bytes", *info.Stats[0].Filesystem.TotalUsageBytes, ddUsage) if needsBaseUsageCheck { t.Logf("expected base %d bytes to be greater than %d bytes", *info.Stats[0].Filesystem.BaseUsageBytes, ddUsage) } t.Logf("retrying after %s...", sleepDuration.String()) time.Sleep(sleepDuration) } if !pass { t.Fail() } } func TestDockerHealthState(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/busybox:1.27", Args: []string{ "--health-cmd", "exit 0", "--health-interval", "1s", }, }, "sh", "-c", "sleep 10") // Wait for the container to show up. waitForContainer(containerID, fm) getHealth := func() string { containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, &info.ContainerInfoRequest{NumStats: 1}) require.NoError(t, err) require.Len(t, containerInfo.Stats, 1) return containerInfo.Stats[0].Health.Status } // Initially the container is in starting state. require.Equal(t, "starting", getHealth()) // Eventually the container should be in healthy state. require.Eventually(t, func() bool { return getHealth() == "healthy" }, 10*time.Second, 100*time.Millisecond) } // Check that restart count is captured in labels. func TestDockerContainerRestartCount(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerName := fmt.Sprintf("test-restart-count-%d", os.Getpid()) // Run a container that runs briefly then exits with failure, with restart policy // The sleep gives cAdvisor time to detect the container between restarts fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/busybox:1.27", Args: []string{ "--name", containerName, "--restart", "on-failure:5", }, }, "sh", "-c", "sleep 3 && exit 1") // Wait for container to show up initially waitForContainer(containerName, fm) // Wait for at least one restart to occur time.Sleep(5 * time.Second) request := &info.ContainerInfoRequest{ NumStats: 1, } // Query the container - it should still be running or restarting containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerName, request) require.NoError(t, err, "Container should still be available during restart cycle") sanityCheck(containerName, containerInfo, t) // Check that restart count label is present and greater than 0 restartCount, ok := containerInfo.Spec.Labels["restartcount"] require.True(t, ok, "restartcount label should be present") count, err := strconv.Atoi(restartCount) require.NoError(t, err) assert.GreaterOrEqual(t, count, 1, "Restart count should be at least 1") } // Check the DiskIo ContainerStats. func TestDockerContainerDiskIoStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Run a container that does disk I/O and stays running containerID := fm.Docker().RunBusybox("sh", "-c", "dd if=/dev/zero of=/tmp/testfile bs=1024 count=1000 && sync && sleep 30") // Wait for the container to show up and do some I/O waitForContainer(containerID, fm) time.Sleep(3 * time.Second) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) require.NoError(t, err) sanityCheck(containerID, containerInfo, t) // Check that DiskIo stats are present assert.True(t, containerInfo.Spec.HasDiskIo, "Container should have DiskIo isolation") } // Check container with --network none. func TestDockerContainerNetworkNone(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerName := fmt.Sprintf("test-network-none-%d", os.Getpid()) containerID := fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/pause", Args: []string{ "--name", containerName, "--network", "none", }, }) // Wait for the container to show up waitForContainer(containerID, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) require.NoError(t, err) sanityCheck(containerID, containerInfo, t) // Container with network none should still be monitored assert.NotEmpty(t, containerInfo.Stats, "Container should have stats even with --network none") } // Check container with --network host. func TestDockerContainerNetworkHost(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerName := fmt.Sprintf("test-network-host-%d", os.Getpid()) containerID := fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/pause", Args: []string{ "--name", containerName, "--network", "host", }, }) // Wait for the container to show up waitForContainer(containerID, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) require.NoError(t, err) sanityCheck(containerID, containerInfo, t) // Container with host network should be monitored assert.NotEmpty(t, containerInfo.Stats, "Container should have stats with --network host") } // Check container with shared network namespace (--network container:X). // This exercises the code path where we need to inspect another container for IP address. func TestDockerContainerSharedNetwork(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // First, create a container that will share its network namespace networkContainerName := fmt.Sprintf("test-network-provider-%d", os.Getpid()) networkContainerID := fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/pause", Args: []string{ "--name", networkContainerName, }, }) waitForContainer(networkContainerID, fm) // Now create a container that shares the network namespace of the first container sharedNetworkContainerName := fmt.Sprintf("test-network-consumer-%d", os.Getpid()) sharedNetworkContainerID := fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/pause", Args: []string{ "--name", sharedNetworkContainerName, "--network", fmt.Sprintf("container:%s", networkContainerName), }, }) waitForContainer(sharedNetworkContainerID, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } // Both containers should be accessible containerInfo1, err := fm.Cadvisor().Client().DockerContainer(networkContainerID, request) require.NoError(t, err) sanityCheck(networkContainerID, containerInfo1, t) containerInfo2, err := fm.Cadvisor().Client().DockerContainer(sharedNetworkContainerID, request) require.NoError(t, err) sanityCheck(sharedNetworkContainerID, containerInfo2, t) // The container with shared network should have stats assert.NotEmpty(t, containerInfo2.Stats, "Container with shared network should have stats") } // Check that container image information is captured. func TestDockerContainerImageInfo(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() expectedImage := "registry.k8s.io/pause" containerID := fm.Docker().Run(framework.DockerRunArgs{ Image: expectedImage, }) waitForContainer(containerID, fm) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) require.NoError(t, err) sanityCheck(containerID, containerInfo, t) // Check image name is captured assert.Contains(t, containerInfo.Spec.Image, "pause", "Container image should contain 'pause'") } // Check that container creation time is valid. func TestDockerContainerCreationTime(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() beforeCreation := time.Now().Add(-1 * time.Second) containerID := fm.Docker().RunPause() waitForContainer(containerID, fm) afterCreation := time.Now().Add(1 * time.Second) request := &info.ContainerInfoRequest{ NumStats: 1, } containerInfo, err := fm.Cadvisor().Client().DockerContainer(containerID, request) require.NoError(t, err) sanityCheck(containerID, containerInfo, t) // Check creation time is within expected range creationTime := containerInfo.Spec.CreationTime assert.True(t, creationTime.After(beforeCreation), "Creation time %v should be after %v", creationTime, beforeCreation) assert.True(t, creationTime.Before(afterCreation), "Creation time %v should be before %v", creationTime, afterCreation) } ================================================ FILE: integration/tests/api/event_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package api import ( "fmt" "strconv" "strings" "testing" "time" "github.com/stretchr/testify/require" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/integration/framework" ) func TestStreamingEventInformationIsReturned(t *testing.T) { // TODO(vmarmol): De-flake and re-enable. t.Skip() fm := framework.New(t) defer fm.Cleanup() // Watch for container deletions einfo := make(chan *info.Event) go func() { err := fm.Cadvisor().Client().EventStreamingInfo("?deletion_events=true&stream=true&subcontainers=true", einfo) require.NoError(t, err) }() // Create a short-lived container. containerID := fm.Docker().RunBusybox("sleep", "2") // Wait for the deletion event. timeout := time.After(30 * time.Second) done := false for !done { select { case ev := <-einfo: if ev.EventType == info.EventContainerDeletion { if strings.Contains(ev.ContainerName, containerID) { done = true } } case <-timeout: t.Errorf( "timeout happened before destruction event was detected for container %q", containerID) done = true } } // We should have already received a creation event. waitForStaticEvent(containerID, "?creation_events=true&subcontainers=true", t, fm, info.EventContainerCreation) } func waitForStaticEvent(containerID string, urlRequest string, t *testing.T, fm framework.Framework, typeEvent info.EventType) { einfo, err := fm.Cadvisor().Client().EventStaticInfo(urlRequest) require.NoError(t, err) found := false for _, ev := range einfo { if ev.EventType == typeEvent { if strings.Contains(ev.ContainerName, containerID) { found = true break } } } require.True(t, found) } func TestContainerDeletionExitCode(t *testing.T) { tests := []struct { name string exitCode int }{ { name: "successful exit", exitCode: 0, }, { name: "error exit", exitCode: 1, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Docker().RunBusybox("sh", "-c", "exit "+strconv.Itoa(tt.exitCode)) err := framework.RetryForDuration(func() error { events, err := fm.Cadvisor().Client().EventStaticInfo("?deletion_events=true&subcontainers=true") if err != nil { return err } for _, ev := range events { if ev.EventType == info.EventContainerDeletion && strings.Contains(ev.ContainerName, containerID) { if ev.EventData.ContainerDeletion == nil { return fmt.Errorf("deletion event data is nil") } if ev.EventData.ContainerDeletion.ExitCode != tt.exitCode { t.Errorf("expected exit code %d, got %d", tt.exitCode, ev.EventData.ContainerDeletion.ExitCode) } return nil } } return fmt.Errorf("deletion event not found for container %s", containerID) }, 30*time.Second) require.NoError(t, err) }) } } ================================================ FILE: integration/tests/api/perf_test.go ================================================ //go:build libpfm && cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package api import ( "testing" "time" v1 "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/integration/framework" "github.com/stretchr/testify/assert" ) func TestPerfEvents(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Docker().RunPause() waitForContainerInfo(fm, containerID) info, err := fm.Cadvisor().Client().DockerContainer(containerID, &v1.ContainerInfoRequest{ NumStats: 1, }) assert.Nil(t, err) assert.Len(t, info.Stats, 1) assert.Greater(t, len(info.Stats[0].PerfStats), 0, "Length of info.Stats[0].PerfStats is not greater than zero") for k, stat := range info.Stats[0].PerfStats { //Everything beyond name is non-deterministic unfortunately. assert.Contains(t, []string{"context-switches", "cpu-migrations-custom"}, stat.Name, "Wrong metric name for key %d: %#v", k, stat) } } func waitForContainerInfo(fm framework.Framework, containerID string) { err := framework.RetryForDuration(func() error { _, err := fm.Cadvisor().Client().DockerContainer(containerID, &v1.ContainerInfoRequest{NumStats: 1}) if err != nil { return err } return nil }, 5*time.Second) assert.NoError(fm.T(), err) } ================================================ FILE: integration/tests/api/test_utils.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package api import ( "testing" "time" info "github.com/google/cadvisor/info/v1" "github.com/opencontainers/cgroups" "github.com/stretchr/testify/assert" "k8s.io/klog/v2" ) func init() { klog.InitFlags(nil) } // Checks that expected and actual are within delta of each other. func inDelta(t *testing.T, expected, actual, delta uint64, description string) { var diff uint64 if expected > actual { diff = expected - actual } else { diff = actual - expected } if diff > delta { t.Errorf("%s (%d and %d) are not within %d of each other", description, expected, actual, delta) } } // Checks that CPU stats are valid. func checkCPUStats(t *testing.T, stat info.CpuStats) { assert := assert.New(t) assert.NotEqual(0, stat.Usage.Total, "Total CPU usage should not be zero") // PerCPU CPU usage is not supported in cgroupv2 (cpuacct.usage_percpu) // https://github.com/google/cadvisor/issues/3065 if !cgroups.IsCgroup2UnifiedMode() { assert.NotEmpty(stat.Usage.PerCpu, "Per-core usage should not be empty") totalUsage := uint64(0) for _, usage := range stat.Usage.PerCpu { totalUsage += usage } inDelta(t, stat.Usage.Total, totalUsage, uint64((5 * time.Millisecond).Nanoseconds()), "Per-core CPU usage") } inDelta(t, stat.Usage.Total, stat.Usage.User+stat.Usage.System, uint64((500 * time.Millisecond).Nanoseconds()), "User + system CPU usage") // TODO(rjnagal): Add verification for cpu load. } func checkMemoryStats(t *testing.T, stat info.MemoryStats) { assert := assert.New(t) assert.NotEqual(0, stat.Usage, "Memory usage should not be zero") assert.NotEqual(0, stat.WorkingSet, "Memory working set should not be zero") assert.NotEqual(0, stat.TotalActiveFile, "Memory total active file should not be zero") assert.NotEqual(0, stat.TotalInactiveFile, "Memory total inactive file should not be zero") if stat.WorkingSet > stat.Usage { t.Errorf("Memory working set (%d) should be at most equal to memory usage (%d)", stat.WorkingSet, stat.Usage) } // TODO(vmarmol): Add checks for ContainerData and HierarchicalData } ================================================ FILE: integration/tests/common/attributes_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package common import ( "testing" "github.com/google/cadvisor/integration/framework" "github.com/stretchr/testify/assert" ) func TestAttributeInformationIsReturned(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() attributes, err := fm.Cadvisor().ClientV2().Attributes() if err != nil { t.Fatal(err) } vp := `\d+\.\d+\.\d+` assert.True(t, assert.Regexp(t, vp, attributes.KernelVersion), "Expected %s to match %s", attributes.KernelVersion, vp) } ================================================ FILE: integration/tests/common/healthz_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package common import ( "io" "net/http" "testing" "github.com/google/cadvisor/integration/framework" ) func TestHealthzOk(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Ensure that /healthz returns "ok" resp, err := http.Get(fm.Hostname().FullHostname() + "healthz") if err != nil { t.Fatal(err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } if string(body) != "ok" { t.Fatalf("cAdvisor returned unexpected healthz status of %q", body) } } ================================================ FILE: integration/tests/common/machine_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package common contains integration tests that are runtime-independent. // These tests work with any container runtime (Docker, CRI-O, containerd, etc.) // and test cAdvisor's core functionality like machine info, attributes, and health. package common import ( "testing" "github.com/google/cadvisor/integration/framework" ) func TestMachineInformationIsReturned(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() machineInfo, err := fm.Cadvisor().Client().MachineInfo() if err != nil { t.Fatal(err) } // Check for "sane" values. Note these can change with time. if machineInfo.NumCores <= 0 || machineInfo.NumCores >= 1000000 { t.Errorf("Machine info has unexpected number of cores: %v", machineInfo.NumCores) } if machineInfo.MemoryCapacity == 0 || machineInfo.MemoryCapacity >= (1<<50 /* 1PB */) { t.Errorf("Machine info has unexpected amount of memory: %v", machineInfo.MemoryCapacity) } if len(machineInfo.Filesystems) == 0 { t.Errorf("Expected to have some filesystems, found none") } for _, fs := range machineInfo.Filesystems { if fs.Device == "" { t.Errorf("Expected a non-empty device name in: %+v", fs) } if fs.Capacity >= (1 << 60 /* 1 EB*/) { t.Errorf("Unexpected capacity in device %q: %v", fs.Device, fs.Capacity) } if fs.Type == "" { t.Errorf("Filesystem type is not set") } else if fs.Type == "vfs" && fs.Inodes == 0 { if fs.Device != "devpts" { t.Errorf("Inodes not available for device %q", fs.Device) } } } } ================================================ FILE: integration/tests/common/machinestats_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package common import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/opencontainers/cgroups" "github.com/google/cadvisor/integration/framework" ) func TestMachineStatsIsReturned(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() machineStats, err := fm.Cadvisor().ClientV2().MachineStats() if err != nil { t.Fatal(err) } as := assert.New(t) for _, stat := range machineStats { as.NotEqual(stat.Timestamp, time.Time{}) as.True(stat.Cpu.Usage.Total > 0) // PerCPU CPU usage is not supported in cgroupv2 (cpuacct.usage_percpu) // https://github.com/google/cadvisor/issues/3065 if !cgroups.IsCgroup2UnifiedMode() { as.True(len(stat.Cpu.Usage.PerCpu) > 0) } if stat.CpuInst != nil { as.True(stat.CpuInst.Usage.Total > 0) } as.True(stat.Memory.Usage > 0) for _, nStat := range stat.Network.Interfaces { as.NotEqual(nStat.Name, "") as.NotEqual(nStat.RxBytes, 0) } for _, fsStat := range stat.Filesystem { as.NotEqual(fsStat.Device, "") as.NotNil(fsStat.Capacity) as.NotNil(fsStat.Usage) as.NotNil(fsStat.ReadsCompleted) require.NotEmpty(t, fsStat.Type) if fsStat.Type == "vfs" { as.NotNil(fsStat.InodesFree) } } } } ================================================ FILE: integration/tests/crio/crio_test.go ================================================ // Copyright 2024 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package crio import ( "fmt" "os" "testing" "time" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" "github.com/google/cadvisor/integration/framework" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // Waits up to 10s for a CRI-O container with the specified ID to appear in cAdvisor. // CRI-O containers may take longer to appear due to the pod sandbox model. func waitForCrioContainer(containerID string, fm framework.Framework) { err := framework.RetryForDuration(func() error { // Query all containers via SubcontainersInfo - CRI-O containers are in "crio" namespace, // not "docker" namespace, so AllDockerContainers won't find them. allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) if err != nil { return err } // Look for container by ID (CRI-O containers appear with crio- prefix in cgroup) for _, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { return nil } } // Also check if the container name contains the ID if len(container.Name) > 0 && contains(container.Name, containerID) { return nil } } return fmt.Errorf("container %q not found in cAdvisor", containerID) }, 10*time.Second) require.NoError(fm.T(), err, "Timed out waiting for CRI-O container %q to be available in cAdvisor", containerID) } func contains(s, substr string) bool { return len(s) >= len(substr) && (s == substr || len(s) > len(substr) && (s[:len(substr)] == substr || s[len(s)-len(substr):] == substr || findSubstring(s, substr))) } func findSubstring(s, substr string) bool { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } return false } // Sanity check the container by: // - Checking that the specified ID is a valid alias for this container. // - Verifying that stats are not empty. func sanityCheck(containerID string, containerInfo info.ContainerInfo, t *testing.T) { assert.Contains(t, containerInfo.Aliases, containerID, "Alias %q should be in list of aliases %v", containerID, containerInfo.Aliases) assert.NotEmpty(t, containerInfo.Stats, "Expected container to have stats") } // TestCrioContainerById tests that cAdvisor can find a CRI-O container by its ID. func TestCrioContainerById(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Crio().RunPause() // Wait for the container to show up in cAdvisor waitForCrioContainer(containerID, fm) // Query all containers via SubcontainersInfo - CRI-O containers are in "crio" namespace allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container var found bool for _, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { sanityCheck(containerID, container, t) found = true break } } if found { break } } assert.True(t, found, "Container %q should be found in cAdvisor", containerID) } // TestCrioContainerByName tests that cAdvisor can find a CRI-O container by a custom name. func TestCrioContainerByName(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerName := fmt.Sprintf("test-crio-container-by-name-%d", os.Getpid()) containerID := fm.Crio().Run(framework.CrioRunArgs{ Image: "registry.k8s.io/pause:3.9", Name: containerName, }) // Wait for the container to show up waitForCrioContainer(containerID, fm) // Query all containers via SubcontainersInfo - CRI-O containers are in "crio" namespace allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container by ID var found bool for _, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { sanityCheck(containerID, container, t) found = true break } } if found { break } } assert.True(t, found, "Container with ID %q should be found in cAdvisor", containerID) } // TestGetAllCrioContainers tests that cAdvisor can find multiple CRI-O containers. func TestGetAllCrioContainers(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start two containers containerID1 := fm.Crio().RunPause() containerID2 := fm.Crio().RunPause() // Wait for both containers to show up waitForCrioContainer(containerID1, fm) waitForCrioContainer(containerID2, fm) // Query all containers via SubcontainersInfo allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find both containers var found1, found2 bool for _, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID1 { sanityCheck(containerID1, container, t) found1 = true } if alias == containerID2 { sanityCheck(containerID2, container, t) found2 = true } } } assert.True(t, found1, "Container %q should be found in cAdvisor", containerID1) assert.True(t, found2, "Container %q should be found in cAdvisor", containerID2) } // TestBasicCrioContainer tests basic container properties. func TestBasicCrioContainer(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Crio().RunPause() // Wait for the container to show up waitForCrioContainer(containerID, fm) // Query all containers via SubcontainersInfo - CRI-O containers are in "crio" namespace allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container var containerInfo *info.ContainerInfo for i, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { containerInfo = &allInfo[i] break } } if containerInfo != nil { break } } require.NotNil(t, containerInfo, "Container %q should be found", containerID) assert.NotEmpty(t, containerInfo.Stats, "Should have at least one stat") } // TestCrioContainerCpuStats tests CPU statistics collection for CRI-O containers. func TestCrioContainerCpuStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Run a busybox container that does some work containerID := fm.Crio().RunBusybox("sh", "-c", "while true; do echo hello; sleep 1; done") // Wait for the container to show up waitForCrioContainer(containerID, fm) // Give the container some time to generate CPU usage time.Sleep(2 * time.Second) // Query all containers via SubcontainersInfo - CRI-O containers are in "crio" namespace allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container var containerInfo *info.ContainerInfo for i, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { containerInfo = &allInfo[i] break } } if containerInfo != nil { break } } require.NotNil(t, containerInfo, "Container %q should be found", containerID) require.NotEmpty(t, containerInfo.Stats, "Should have stats") // Check CPU stats stat := containerInfo.Stats[0] checkCPUStats(t, stat.Cpu) } // TestCrioContainerMemoryStats tests memory statistics collection for CRI-O containers. func TestCrioContainerMemoryStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Run a busybox container containerID := fm.Crio().RunBusybox("sh", "-c", "while true; do echo hello; sleep 1; done") // Wait for the container to show up waitForCrioContainer(containerID, fm) // Give the container some time to use memory time.Sleep(2 * time.Second) // Query all containers via SubcontainersInfo - CRI-O containers are in "crio" namespace allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container var containerInfo *info.ContainerInfo for i, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { containerInfo = &allInfo[i] break } } if containerInfo != nil { break } } require.NotNil(t, containerInfo, "Container %q should be found", containerID) require.NotEmpty(t, containerInfo.Stats, "Should have stats") // Check memory stats stat := containerInfo.Stats[0] checkMemoryStats(t, stat.Memory) } // TestCrioContainerNetworkStats tests network statistics collection for CRI-O containers. // TODO: Skip this test until network stats collection works reliably for CRI-O containers. // In the CI environment, network stats (TxBytes, RxBytes, etc.) are reported as zero, // possibly due to CNI network namespace issues in the Docker-in-Docker environment. func TestCrioContainerNetworkStats(t *testing.T) { t.Skip("Skipping: network stats are not reliably collected for CRI-O containers in CI") fm := framework.New(t) defer fm.Cleanup() // Run a busybox container that generates network traffic containerID := fm.Crio().RunBusybox("sh", "-c", "while true; do wget -q -O /dev/null http://www.google.com/ 2>/dev/null || true; sleep 1; done") // Wait for the container to show up waitForCrioContainer(containerID, fm) // Wait for at least one additional housekeeping interval for network stats time.Sleep(20 * time.Second) // Query all containers via SubcontainersInfo - CRI-O containers are in "crio" namespace allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container var containerInfo *info.ContainerInfo for i, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { containerInfo = &allInfo[i] break } } if containerInfo != nil { break } } require.NotNil(t, containerInfo, "Container %q should be found", containerID) require.NotEmpty(t, containerInfo.Stats, "Should have stats") stat := containerInfo.Stats[0] ifaceStats := stat.Network.InterfaceStats // Pick eth0 if multiple interfaces exist if len(stat.Network.Interfaces) > 0 { for _, iface := range stat.Network.Interfaces { if iface.Name == "eth0" { ifaceStats = iface } } } // Checks for NetworkStats assert.NotEqual(t, uint64(0), ifaceStats.TxBytes, "Network tx bytes should not be zero") assert.NotEqual(t, uint64(0), ifaceStats.TxPackets, "Network tx packets should not be zero") assert.NotEqual(t, uint64(0), ifaceStats.RxBytes, "Network rx bytes should not be zero") assert.NotEqual(t, uint64(0), ifaceStats.RxPackets, "Network rx packets should not be zero") } // TestCrioContainerSpec tests that container spec is correctly populated for CRI-O containers. func TestCrioContainerSpec(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Crio().RunPause() // Wait for the container to show up waitForCrioContainer(containerID, fm) // Query all containers via SubcontainersInfo - CRI-O containers are in "crio" namespace allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) require.NoError(t, err) // Find our container var containerInfo *info.ContainerInfo for i, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { containerInfo = &allInfo[i] break } } if containerInfo != nil { break } } require.NotNil(t, containerInfo, "Container %q should be found", containerID) // Check that spec has basic properties assert.True(t, containerInfo.Spec.HasCpu, "CPU should be isolated") assert.True(t, containerInfo.Spec.HasMemory, "Memory should be isolated") // CRI-O containers may or may not have network depending on pod config } // TestCrioContainerDeletionExitCode tests that container deletion events include exit codes. // TODO: Skip this test until cAdvisor properly reports exit codes for CRI-O containers. // Currently cAdvisor reports exit code -1 for CRI-O containers even when the container // exits with a specific code. This appears to be a timing/integration issue. func TestCrioContainerDeletionExitCode(t *testing.T) { t.Skip("Skipping: cAdvisor currently reports exit code -1 for CRI-O containers") tests := []struct { name string exitCode int }{ { name: "successful exit", exitCode: 0, }, { name: "error exit", exitCode: 1, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Crio().RunBusybox("sh", "-c", fmt.Sprintf("exit %d", tt.exitCode)) err := framework.RetryForDuration(func() error { events, err := fm.Cadvisor().Client().EventStaticInfo("?deletion_events=true&subcontainers=true") if err != nil { return err } for _, ev := range events { if ev.EventType == info.EventContainerDeletion { // Check if this event is for our container (CRI-O container names contain the ID) if contains(ev.ContainerName, containerID) { if ev.EventData.ContainerDeletion == nil { return fmt.Errorf("deletion event data is nil") } if ev.EventData.ContainerDeletion.ExitCode != tt.exitCode { t.Errorf("expected exit code %d, got %d", tt.exitCode, ev.EventData.ContainerDeletion.ExitCode) } return nil } } } return fmt.Errorf("deletion event not found for container %s", containerID) }, 30*time.Second) require.NoError(t, err) }) } } // TestCrioHealthState tests health state reporting for CRI-O containers. // Docker-style health checks (HEALTHCHECK instruction) are not supported by CRI-O. // CRI-O containers rely on Kubernetes liveness/readiness probes instead, // which are managed by the kubelet, not the container runtime. func TestCrioHealthState(t *testing.T) { t.Skip("Skipping: Docker-style health checks are not supported by CRI-O (use Kubernetes probes instead)") } // TestCrioFilesystemStats tests filesystem statistics collection for CRI-O containers. func TestCrioFilesystemStats(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() const ( ddUsage = uint64(1 << 3) // 1 KB sleepDuration = 10 * time.Second ) // Run a busybox container that creates a file and stays running containerID := fm.Crio().RunBusybox("/bin/sh", "-c", "dd if=/dev/zero of=/file count=2 bs=1024 && while true; do sleep 1; done") // Wait for the container to show up waitForCrioContainer(containerID, fm) request := &v2.RequestOptions{ IdType: v2.TypeName, Count: 1, } pass := false // We need to wait for the `dd` operation to complete. for i := 0; i < 10; i++ { // Query all containers and find ours allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) if err != nil { t.Logf("%v stats unavailable - %v", time.Now().String(), err) t.Logf("retrying after %s...", sleepDuration.String()) time.Sleep(sleepDuration) continue } // Find our container var containerName string for _, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { containerName = container.Name break } } if containerName != "" { break } } if containerName == "" { t.Logf("Container %q not found, retrying...", containerID) time.Sleep(sleepDuration) continue } // Get stats using v2 API containerInfo, err := fm.Cadvisor().ClientV2().Stats(containerName, request) if err != nil { t.Logf("%v stats unavailable - %v", time.Now().String(), err) t.Logf("retrying after %s...", sleepDuration.String()) time.Sleep(sleepDuration) continue } if len(containerInfo) == 0 { t.Logf("No container info returned, retrying...") time.Sleep(sleepDuration) continue } // Get the first (and only) container info var cInfo v2.ContainerInfo for _, ci := range containerInfo { cInfo = ci break } if len(cInfo.Stats) == 0 || cInfo.Stats[0].Filesystem == nil { t.Logf("No filesystem stats available yet, retrying...") time.Sleep(sleepDuration) continue } if cInfo.Stats[0].Filesystem.TotalUsageBytes != nil && *cInfo.Stats[0].Filesystem.TotalUsageBytes >= ddUsage { pass = true break } t.Logf("expected total usage to be greater than %d bytes, retrying...", ddUsage) time.Sleep(sleepDuration) } if !pass { t.Fail() } } ================================================ FILE: integration/tests/crio/test_utils.go ================================================ // Copyright 2024 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package crio import ( "testing" "time" info "github.com/google/cadvisor/info/v1" "github.com/opencontainers/cgroups" "github.com/stretchr/testify/assert" "k8s.io/klog/v2" ) func init() { klog.InitFlags(nil) } // Checks that expected and actual are within delta of each other. func inDelta(t *testing.T, expected, actual, delta uint64, description string) { var diff uint64 if expected > actual { diff = expected - actual } else { diff = actual - expected } if diff > delta { t.Errorf("%s (%d and %d) are not within %d of each other", description, expected, actual, delta) } } // Checks that CPU stats are valid. func checkCPUStats(t *testing.T, stat info.CpuStats) { assert := assert.New(t) assert.NotEqual(0, stat.Usage.Total, "Total CPU usage should not be zero") // PerCPU CPU usage is not supported in cgroupv2 (cpuacct.usage_percpu) // https://github.com/google/cadvisor/issues/3065 if !cgroups.IsCgroup2UnifiedMode() { assert.NotEmpty(stat.Usage.PerCpu, "Per-core usage should not be empty") totalUsage := uint64(0) for _, usage := range stat.Usage.PerCpu { totalUsage += usage } inDelta(t, stat.Usage.Total, totalUsage, uint64((5 * time.Millisecond).Nanoseconds()), "Per-core CPU usage") } inDelta(t, stat.Usage.Total, stat.Usage.User+stat.Usage.System, uint64((500 * time.Millisecond).Nanoseconds()), "User + system CPU usage") } func checkMemoryStats(t *testing.T, stat info.MemoryStats) { assert := assert.New(t) assert.NotEqual(0, stat.Usage, "Memory usage should not be zero") assert.NotEqual(0, stat.WorkingSet, "Memory working set should not be zero") if stat.WorkingSet > stat.Usage { t.Errorf("Memory working set (%d) should be at most equal to memory usage (%d)", stat.WorkingSet, stat.Usage) } } ================================================ FILE: integration/tests/healthz/doc.go ================================================ // Copyright 2024 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package healthz contains healthz endpoint integration tests. // // Deprecated: This package is deprecated. Use integration/tests/common instead, // which contains the same healthz tests along with other runtime-independent tests. package healthz ================================================ FILE: integration/tests/healthz/healthz_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package healthz import ( "io" "net/http" "testing" "github.com/google/cadvisor/integration/framework" ) func TestHealthzOk(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Ensure that /heathz returns "ok" resp, err := http.Get(fm.Hostname().FullHostname() + "healthz") if err != nil { t.Fatal(err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } if string(body) != "ok" { t.Fatalf("cAdvisor returned unexpected healthz status of %q", body) } } ================================================ FILE: integration/tests/healthz/test_utils.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package healthz import "k8s.io/klog/v2" func init() { klog.InitFlags(nil) } ================================================ FILE: integration/tests/metrics/containerd_metrics_test.go ================================================ //go:build linux // Copyright 2024 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package metrics import ( "strings" "testing" "time" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/integration/framework" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // waitForContainerdContainerViaAPI waits for a containerd container to appear in cAdvisor // using the API client, which is more reliable than searching metrics labels. func waitForContainerdContainerViaAPI(containerID string, fm framework.Framework, timeout time.Duration) bool { deadline := time.Now().Add(timeout) for time.Now().Before(deadline) { allInfo, err := fm.Cadvisor().Client().SubcontainersInfo("/", &info.ContainerInfoRequest{ NumStats: 1, }) if err != nil { time.Sleep(500 * time.Millisecond) continue } // Look for container by ID in aliases or name for _, container := range allInfo { for _, alias := range container.Aliases { if alias == containerID { return true } } if strings.Contains(container.Name, containerID) { return true } } time.Sleep(500 * time.Millisecond) } return false } // getContainerdContainerMetricID finds the 'id' label value used for a containerd container // in Prometheus metrics by searching all metrics for one containing the container ID. func getContainerdContainerMetricID(fm framework.Framework, containerID string) string { client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() if err != nil { return "" } // Search in CPU metrics for the container cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") if !ok { return "" } // Look for any metric where the 'id' label contains our container ID for _, metric := range cpuMetric.GetMetric() { id := framework.GetLabelValue(metric, "id") if strings.Contains(id, containerID) { return id } } return "" } // TestContainerdContainerAppearsInMetrics verifies a containerd container's metrics are exposed. func TestContainerdContainerAppearsInMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start a containerd container containerID := fm.Containerd().RunPause() // Wait for container to appear via API first (more reliable) found := waitForContainerdContainerViaAPI(containerID, fm, 15*time.Second) require.True(t, found, "Containerd container %s should appear in cAdvisor API within 15 seconds", containerID) // Now verify it appears in Prometheus metrics metricID := getContainerdContainerMetricID(fm, containerID) require.NotEmpty(t, metricID, "Containerd container %s should appear in Prometheus metrics", containerID) } // TestContainerdContainerCPUMetrics verifies CPU metrics for containerd containers. func TestContainerdContainerCPUMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start a container that does some CPU work containerID := fm.Containerd().RunBusybox("sh", "-c", "while true; do :; done") found := waitForContainerdContainerViaAPI(containerID, fm, 15*time.Second) require.True(t, found, "Container should appear in cAdvisor") // Wait for CPU stats to accumulate time.Sleep(2 * time.Second) client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") require.True(t, ok) // Find metrics for our container (search for container ID substring) metrics := framework.FindMetricsWithLabelSubstring(cpuMetric, "id", containerID) require.NotEmpty(t, metrics, "Should find CPU metrics for containerd container") // Active container should have some CPU usage hasPositiveValue := false for _, m := range metrics { if framework.GetCounterValue(m) > 0 { hasPositiveValue = true break } } assert.True(t, hasPositiveValue, "Active containerd container should have positive CPU usage") } // TestContainerdContainerMemoryMetrics verifies memory metrics for containerd containers. func TestContainerdContainerMemoryMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Containerd().RunPause() found := waitForContainerdContainerViaAPI(containerID, fm, 15*time.Second) require.True(t, found) client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) // Check container_memory_usage_bytes memUsage, ok := framework.GetMetricFamily(families, "container_memory_usage_bytes") require.True(t, ok) metrics := framework.FindMetricsWithLabelSubstring(memUsage, "id", containerID) require.NotEmpty(t, metrics, "Should find memory usage metrics for containerd container") // Memory usage should be non-negative for _, m := range metrics { usage := framework.GetGaugeValue(m) assert.GreaterOrEqual(t, usage, float64(0), "Memory usage should be >= 0") } // Check container_memory_working_set_bytes workingSet, ok := framework.GetMetricFamily(families, "container_memory_working_set_bytes") require.True(t, ok) wsMetrics := framework.FindMetricsWithLabelSubstring(workingSet, "id", containerID) require.NotEmpty(t, wsMetrics, "Should find working set metrics for containerd container") } // TestContainerdContainerLabelsInMetrics verifies container labels appear in metrics. func TestContainerdContainerLabelsInMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start a container with custom labels containerID := fm.Containerd().Run(framework.ContainerdRunArgs{ Image: "registry.k8s.io/pause:3.9", Labels: map[string]string{ "io.kubernetes.pod.name": "test-pod", }, }) found := waitForContainerdContainerViaAPI(containerID, fm, 15*time.Second) require.True(t, found) client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") require.True(t, ok) metrics := framework.FindMetricsWithLabelSubstring(cpuMetric, "id", containerID) require.NotEmpty(t, metrics) // Check if label appears (labels are prefixed with 'container_label_') // Note: dots in label names are converted to underscores metric := metrics[0] labelValue := framework.GetLabelValue(metric, "container_label_io_kubernetes_pod_name") assert.Equal(t, "test-pod", labelValue, "Container label should appear in metrics") } // TestContainerdContainerImageInMetrics verifies container image name appears in metrics. func TestContainerdContainerImageInMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Containerd().Run(framework.ContainerdRunArgs{ Image: "registry.k8s.io/pause:3.9", }) found := waitForContainerdContainerViaAPI(containerID, fm, 15*time.Second) require.True(t, found) client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") require.True(t, ok) metrics := framework.FindMetricsWithLabelSubstring(cpuMetric, "id", containerID) require.NotEmpty(t, metrics) // Check image label image := framework.GetLabelValue(metrics[0], "image") assert.Contains(t, image, "pause", "Image label should contain 'pause'") } // TestContainerdContainerStartTimeMetric verifies container start time is recorded. func TestContainerdContainerStartTimeMetric(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() beforeCreate := time.Now().Unix() containerID := fm.Containerd().RunPause() afterCreate := time.Now().Unix() found := waitForContainerdContainerViaAPI(containerID, fm, 15*time.Second) require.True(t, found) client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) startTime, ok := framework.GetMetricFamily(families, "container_start_time_seconds") require.True(t, ok) metrics := framework.FindMetricsWithLabelSubstring(startTime, "id", containerID) require.NotEmpty(t, metrics) // Start time should be between beforeCreate and afterCreate (with tolerance) startTs := framework.GetGaugeValue(metrics[0]) assert.GreaterOrEqual(t, startTs, float64(beforeCreate-5), "Start time should be recent") assert.LessOrEqual(t, startTs, float64(afterCreate+10), "Start time should not be far in the future") } // TestMultipleContainerdContainersInMetrics verifies multiple containers appear correctly. func TestMultipleContainerdContainersInMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start multiple containers container1 := fm.Containerd().RunPause() container2 := fm.Containerd().RunPause() // Wait for both containers to appear found1 := waitForContainerdContainerViaAPI(container1, fm, 15*time.Second) found2 := waitForContainerdContainerViaAPI(container2, fm, 15*time.Second) require.True(t, found1, "First container should appear in cAdvisor") require.True(t, found2, "Second container should appear in cAdvisor") client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") require.True(t, ok) // Both containers should have distinct metrics metrics1 := framework.FindMetricsWithLabelSubstring(cpuMetric, "id", container1) metrics2 := framework.FindMetricsWithLabelSubstring(cpuMetric, "id", container2) assert.NotEmpty(t, metrics1, "First containerd container should have metrics") assert.NotEmpty(t, metrics2, "Second containerd container should have metrics") // IDs should be different id1 := framework.GetLabelValue(metrics1[0], "id") id2 := framework.GetLabelValue(metrics2[0], "id") assert.NotEqual(t, id1, id2, "Container IDs should be different") } // TestContainerdContainerDiskIOMetrics verifies disk I/O metrics for containerd containers. func TestContainerdContainerDiskIOMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start a container that does some disk I/O containerID := fm.Containerd().RunBusybox("sh", "-c", "dd if=/dev/zero of=/tmp/test bs=1M count=10 2>/dev/null; sleep infinity") found := waitForContainerdContainerViaAPI(containerID, fm, 15*time.Second) require.True(t, found) // Wait for disk I/O to be recorded time.Sleep(3 * time.Second) client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) // Check for disk I/O write metrics fsWrites, ok := framework.GetMetricFamily(families, "container_fs_writes_bytes_total") if ok { metrics := framework.FindMetricsWithLabelSubstring(fsWrites, "id", containerID) if len(metrics) > 0 { writes := framework.GetCounterValue(metrics[0]) // The container wrote at least 10MB assert.GreaterOrEqual(t, writes, float64(0), "Write bytes should be >= 0") } } } ================================================ FILE: integration/tests/metrics/docker_metrics_test.go ================================================ //go:build linux // Copyright 2024 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package metrics import ( "testing" "time" "github.com/google/cadvisor/integration/framework" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // waitForContainerInMetrics waits for a container to appear in the metrics endpoint. func waitForContainerInMetrics(_ *testing.T, client *framework.MetricsClient, containerID string, timeout time.Duration) bool { deadline := time.Now().Add(timeout) for time.Now().Before(deadline) { families, err := client.FetchAndParse() if err != nil { time.Sleep(500 * time.Millisecond) continue } cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") if !ok { time.Sleep(500 * time.Millisecond) continue } // Check if container appears (using first 12 chars of ID) if framework.ContainsLabelValue(cpuMetric, "id", containerID[:12]) { return true } time.Sleep(500 * time.Millisecond) } return false } // TestDockerContainerAppearsInMetrics verifies a Docker container's metrics are exposed. func TestDockerContainerAppearsInMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start a Docker container containerID := fm.Docker().RunPause() client := framework.NewMetricsClient(fm.Hostname()) // Wait for container to appear in metrics found := waitForContainerInMetrics(t, client, containerID, 10*time.Second) require.True(t, found, "Container %s should appear in metrics within 10 seconds", containerID[:12]) } // TestDockerContainerCPUMetrics verifies CPU metrics are collected for Docker containers. func TestDockerContainerCPUMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start a container that does some CPU work containerID := fm.Docker().RunBusybox("sh", "-c", "while true; do :; done") client := framework.NewMetricsClient(fm.Hostname()) // Wait for container and let it accumulate some CPU time found := waitForContainerInMetrics(t, client, containerID, 10*time.Second) require.True(t, found, "Container should appear in metrics") // Wait a bit more for CPU stats to accumulate time.Sleep(2 * time.Second) families, err := client.FetchAndParse() require.NoError(t, err) // Check container_cpu_usage_seconds_total cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") require.True(t, ok) // Find metrics for our container metrics := framework.FindMetricsWithLabelSubstring(cpuMetric, "id", containerID[:12]) require.NotEmpty(t, metrics, "Should find CPU metrics for container %s", containerID[:12]) // At least one metric should have a positive value (the container is doing CPU work) hasPositiveValue := false for _, m := range metrics { if framework.GetCounterValue(m) > 0 { hasPositiveValue = true break } } assert.True(t, hasPositiveValue, "Active container should have positive CPU usage") // Check container_cpu_user_seconds_total exists for this container userCPU, ok := framework.GetMetricFamily(families, "container_cpu_user_seconds_total") if ok { userMetrics := framework.FindMetricsWithLabelSubstring(userCPU, "id", containerID[:12]) assert.NotEmpty(t, userMetrics, "Should have user CPU metrics") } } // TestDockerContainerMemoryMetrics verifies memory metrics are collected for Docker containers. func TestDockerContainerMemoryMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start a container with a memory limit containerID := fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/pause", Args: []string{"--memory=128m"}, }) client := framework.NewMetricsClient(fm.Hostname()) found := waitForContainerInMetrics(t, client, containerID, 10*time.Second) require.True(t, found) families, err := client.FetchAndParse() require.NoError(t, err) // Check container_memory_usage_bytes memUsage, ok := framework.GetMetricFamily(families, "container_memory_usage_bytes") require.True(t, ok) metrics := framework.FindMetricsWithLabelSubstring(memUsage, "id", containerID[:12]) require.NotEmpty(t, metrics, "Should find memory usage metrics") // Memory usage should be non-negative for _, m := range metrics { usage := framework.GetGaugeValue(m) assert.GreaterOrEqual(t, usage, float64(0), "Memory usage should be >= 0") } // Check container_memory_working_set_bytes workingSet, ok := framework.GetMetricFamily(families, "container_memory_working_set_bytes") require.True(t, ok) wsMetrics := framework.FindMetricsWithLabelSubstring(workingSet, "id", containerID[:12]) require.NotEmpty(t, wsMetrics, "Should find working set metrics") // Check container_spec_memory_limit_bytes shows our limit memLimit, ok := framework.GetMetricFamily(families, "container_spec_memory_limit_bytes") if ok { limitMetrics := framework.FindMetricsWithLabelSubstring(memLimit, "id", containerID[:12]) if len(limitMetrics) > 0 { limit := framework.GetGaugeValue(limitMetrics[0]) // 128MB = 134217728 bytes expectedLimit := float64(128 * 1024 * 1024) assert.Equal(t, expectedLimit, limit, "Memory limit should be 128MB") } } } // TestDockerContainerNetworkMetrics verifies network metrics are collected for Docker containers. func TestDockerContainerNetworkMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start a basic container - pause container has minimal network activity containerID := fm.Docker().RunPause() client := framework.NewMetricsClient(fm.Hostname()) found := waitForContainerInMetrics(t, client, containerID, 10*time.Second) require.True(t, found) families, err := client.FetchAndParse() require.NoError(t, err) // Check network receive metrics exist rxBytes, ok := framework.GetMetricFamily(families, "container_network_receive_bytes_total") require.True(t, ok) rxMetrics := framework.FindMetricsWithLabelSubstring(rxBytes, "id", containerID[:12]) // Network metrics may or may not be present depending on network mode // Just verify the metric family exists and has proper structure if len(rxMetrics) > 0 { // Should have 'interface' label iface := framework.GetLabelValue(rxMetrics[0], "interface") assert.NotEmpty(t, iface, "Network metric should have 'interface' label") } // Check network transmit metrics exist txBytes, ok := framework.GetMetricFamily(families, "container_network_transmit_bytes_total") require.True(t, ok) txMetrics := framework.FindMetricsWithLabelSubstring(txBytes, "id", containerID[:12]) if len(txMetrics) > 0 { iface := framework.GetLabelValue(txMetrics[0], "interface") assert.NotEmpty(t, iface, "Network metric should have 'interface' label") } } // TestDockerContainerLabelsInMetrics verifies container labels appear in metrics. func TestDockerContainerLabelsInMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start a container with custom labels containerID := fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/pause", Args: []string{"--label", "test.label=test-value"}, }) client := framework.NewMetricsClient(fm.Hostname()) found := waitForContainerInMetrics(t, client, containerID, 10*time.Second) require.True(t, found) families, err := client.FetchAndParse() require.NoError(t, err) // Find our container's metrics cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") require.True(t, ok) metrics := framework.FindMetricsWithLabelSubstring(cpuMetric, "id", containerID[:12]) require.NotEmpty(t, metrics) // Check if our label appears (labels are prefixed with 'container_label_') // Note: label dots are converted to underscores metric := metrics[0] labelValue := framework.GetLabelValue(metric, "container_label_test_label") assert.Equal(t, "test-value", labelValue, "Container label should appear in metrics") } // TestDockerContainerImageInMetrics verifies container image name appears in metrics. func TestDockerContainerImageInMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/pause", }) client := framework.NewMetricsClient(fm.Hostname()) found := waitForContainerInMetrics(t, client, containerID, 10*time.Second) require.True(t, found) families, err := client.FetchAndParse() require.NoError(t, err) cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") require.True(t, ok) metrics := framework.FindMetricsWithLabelSubstring(cpuMetric, "id", containerID[:12]) require.NotEmpty(t, metrics) // Check image label image := framework.GetLabelValue(metrics[0], "image") assert.Contains(t, image, "pause", "Image label should contain 'pause'") } // TestDockerContainerStartTimeMetric verifies container start time is recorded. func TestDockerContainerStartTimeMetric(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() beforeCreate := time.Now().Unix() containerID := fm.Docker().RunPause() afterCreate := time.Now().Unix() client := framework.NewMetricsClient(fm.Hostname()) found := waitForContainerInMetrics(t, client, containerID, 10*time.Second) require.True(t, found) families, err := client.FetchAndParse() require.NoError(t, err) startTime, ok := framework.GetMetricFamily(families, "container_start_time_seconds") require.True(t, ok) metrics := framework.FindMetricsWithLabelSubstring(startTime, "id", containerID[:12]) require.NotEmpty(t, metrics) // Start time should be between beforeCreate and afterCreate (with some tolerance) startTs := framework.GetGaugeValue(metrics[0]) assert.GreaterOrEqual(t, startTs, float64(beforeCreate-5), "Start time should be recent") assert.LessOrEqual(t, startTs, float64(afterCreate+5), "Start time should not be in the future") } // TestMultipleDockerContainersInMetrics verifies multiple containers appear correctly. func TestMultipleDockerContainersInMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() // Start multiple containers container1 := fm.Docker().RunPause() container2 := fm.Docker().RunPause() client := framework.NewMetricsClient(fm.Hostname()) // Wait for both containers to appear found1 := waitForContainerInMetrics(t, client, container1, 10*time.Second) found2 := waitForContainerInMetrics(t, client, container2, 10*time.Second) require.True(t, found1, "First container should appear in metrics") require.True(t, found2, "Second container should appear in metrics") families, err := client.FetchAndParse() require.NoError(t, err) cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") require.True(t, ok) // Both containers should have distinct metrics metrics1 := framework.FindMetricsWithLabelSubstring(cpuMetric, "id", container1[:12]) metrics2 := framework.FindMetricsWithLabelSubstring(cpuMetric, "id", container2[:12]) assert.NotEmpty(t, metrics1, "First container should have metrics") assert.NotEmpty(t, metrics2, "Second container should have metrics") // IDs should be different id1 := framework.GetLabelValue(metrics1[0], "id") id2 := framework.GetLabelValue(metrics2[0], "id") assert.NotEqual(t, id1, id2, "Container IDs should be different") } // TestDockerContainerFilesystemMetrics verifies filesystem metrics for Docker containers. func TestDockerContainerFilesystemMetrics(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Docker().RunPause() client := framework.NewMetricsClient(fm.Hostname()) found := waitForContainerInMetrics(t, client, containerID, 10*time.Second) require.True(t, found) families, err := client.FetchAndParse() require.NoError(t, err) // Check filesystem usage metric fsUsage, ok := framework.GetMetricFamily(families, "container_fs_usage_bytes") if ok { metrics := framework.FindMetricsWithLabelSubstring(fsUsage, "id", containerID[:12]) // Filesystem metrics may not always be available for all containers if len(metrics) > 0 { usage := framework.GetGaugeValue(metrics[0]) assert.GreaterOrEqual(t, usage, float64(0), "Filesystem usage should be >= 0") // Should have 'device' label device := framework.GetLabelValue(metrics[0], "device") assert.NotEmpty(t, device, "Filesystem metric should have 'device' label") } } } // TestDockerContainerMemoryFailcnt verifies memory failcnt metric exists. func TestDockerContainerMemoryFailcnt(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() containerID := fm.Docker().Run(framework.DockerRunArgs{ Image: "registry.k8s.io/pause", Args: []string{"--memory=64m"}, }) client := framework.NewMetricsClient(fm.Hostname()) found := waitForContainerInMetrics(t, client, containerID, 10*time.Second) require.True(t, found) families, err := client.FetchAndParse() require.NoError(t, err) // container_memory_failcnt should exist (may be 0 for healthy containers) failcnt, ok := framework.GetMetricFamily(families, "container_memory_failcnt") if ok { metrics := framework.FindMetricsWithLabelSubstring(failcnt, "id", containerID[:12]) if len(metrics) > 0 { count := framework.GetCounterValue(metrics[0]) assert.GreaterOrEqual(t, count, float64(0), "Failcnt should be >= 0") } } } ================================================ FILE: integration/tests/metrics/prometheus_test.go ================================================ //go:build linux // Copyright 2024 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package metrics provides integration tests for cAdvisor's Prometheus /metrics endpoint. package metrics import ( "strings" "testing" "github.com/google/cadvisor/integration/framework" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // TestMetricsEndpointReturns200 verifies the /metrics endpoint is accessible // and returns a 200 status code. func TestMetricsEndpointReturns200(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) text, err := client.Fetch() require.NoError(t, err, "Failed to fetch /metrics") require.NotEmpty(t, text, "/metrics returned empty response") } // TestMetricsEndpointReturnsValidPrometheusFormat verifies the response // can be parsed as valid Prometheus text format. func TestMetricsEndpointReturnsValidPrometheusFormat(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err, "Failed to parse Prometheus metrics") require.NotEmpty(t, families, "No metric families found") } // TestCadvisorVersionInfoExists verifies the cadvisor_version_info metric is present // and has expected labels. func TestCadvisorVersionInfoExists(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) versionInfo, ok := framework.GetMetricFamily(families, "cadvisor_version_info") require.True(t, ok, "cadvisor_version_info metric should exist") require.NotEmpty(t, versionInfo.GetMetric(), "cadvisor_version_info should have at least one sample") // Check that expected labels are present metric := versionInfo.GetMetric()[0] labels := make(map[string]bool) for _, lp := range metric.GetLabel() { labels[lp.GetName()] = true } assert.True(t, labels["cadvisorVersion"], "Should have cadvisorVersion label") assert.True(t, labels["kernelVersion"], "Should have kernelVersion label") assert.True(t, labels["osVersion"], "Should have osVersion label") } // TestCoreCPUMetricsExist verifies essential CPU metrics are present. func TestCoreCPUMetricsExist(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) cpuMetrics := []string{ "container_cpu_usage_seconds_total", "container_cpu_user_seconds_total", "container_cpu_system_seconds_total", } for _, name := range cpuMetrics { assert.True(t, framework.HasMetric(families, name), "CPU metric %q should exist", name) } // Verify container_cpu_usage_seconds_total is a counter cpuUsage, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") require.True(t, ok) assert.Equal(t, "COUNTER", framework.GetMetricType(cpuUsage), "container_cpu_usage_seconds_total should be a counter") } // TestCoreMemoryMetricsExist verifies essential memory metrics are present. func TestCoreMemoryMetricsExist(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) memoryMetrics := []string{ "container_memory_usage_bytes", "container_memory_working_set_bytes", "container_memory_cache", "container_memory_rss", } for _, name := range memoryMetrics { assert.True(t, framework.HasMetric(families, name), "Memory metric %q should exist", name) } // Verify container_memory_usage_bytes is a gauge memUsage, ok := framework.GetMetricFamily(families, "container_memory_usage_bytes") require.True(t, ok) assert.Equal(t, "GAUGE", framework.GetMetricType(memUsage), "container_memory_usage_bytes should be a gauge") } // TestCoreNetworkMetricsExist verifies essential network metrics are present. func TestCoreNetworkMetricsExist(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) networkMetrics := []string{ "container_network_receive_bytes_total", "container_network_transmit_bytes_total", "container_network_receive_packets_total", "container_network_transmit_packets_total", } for _, name := range networkMetrics { assert.True(t, framework.HasMetric(families, name), "Network metric %q should exist", name) } } // TestCoreFilesystemMetricsExist verifies essential filesystem metrics are present. func TestCoreFilesystemMetricsExist(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) fsMetrics := []string{ "container_fs_usage_bytes", "container_fs_limit_bytes", } for _, name := range fsMetrics { assert.True(t, framework.HasMetric(families, name), "Filesystem metric %q should exist", name) } } // TestContainerSpecMetricsExist verifies container specification metrics are present. func TestContainerSpecMetricsExist(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) specMetrics := []string{ "container_start_time_seconds", "container_spec_memory_limit_bytes", } for _, name := range specMetrics { assert.True(t, framework.HasMetric(families, name), "Spec metric %q should exist", name) } } // TestMachineMetricsExist verifies machine-level metrics are present with reasonable values. func TestMachineMetricsExist(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) machineMetrics := []string{ "machine_cpu_cores", "machine_cpu_physical_cores", "machine_memory_bytes", } for _, name := range machineMetrics { assert.True(t, framework.HasMetric(families, name), "Machine metric %q should exist", name) } // Verify machine_cpu_cores has a reasonable value (1 to 1024 cores) cpuCores, ok := framework.GetMetricFamily(families, "machine_cpu_cores") require.True(t, ok) require.NotEmpty(t, cpuCores.GetMetric()) cores := framework.GetGaugeValue(cpuCores.GetMetric()[0]) assert.GreaterOrEqual(t, cores, float64(1), "Should have at least 1 CPU core") assert.LessOrEqual(t, cores, float64(1024), "CPU core count seems unreasonably high") // Verify machine_memory_bytes has a reasonable value (100MB to 100TB) memBytes, ok := framework.GetMetricFamily(families, "machine_memory_bytes") require.True(t, ok) require.NotEmpty(t, memBytes.GetMetric()) mem := framework.GetGaugeValue(memBytes.GetMetric()[0]) assert.GreaterOrEqual(t, mem, float64(100*1024*1024), "Machine memory should be at least 100MB") assert.LessOrEqual(t, mem, float64(100*1024*1024*1024*1024), "Machine memory seems unreasonably high") } // TestMetricsHaveCorrectTypes verifies that metric types are correct. func TestMetricsHaveCorrectTypes(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) // Counters should be COUNTER type counterMetrics := []string{ "container_cpu_usage_seconds_total", "container_cpu_user_seconds_total", "container_cpu_system_seconds_total", "container_network_receive_bytes_total", "container_network_transmit_bytes_total", } for _, name := range counterMetrics { if mf, ok := families[name]; ok { assert.Equal(t, "COUNTER", framework.GetMetricType(mf), "%s should be a counter", name) } } // Gauges should be GAUGE type gaugeMetrics := []string{ "container_memory_usage_bytes", "container_memory_working_set_bytes", "machine_cpu_cores", "machine_memory_bytes", } for _, name := range gaugeMetrics { if mf, ok := families[name]; ok { assert.Equal(t, "GAUGE", framework.GetMetricType(mf), "%s should be a gauge", name) } } } // TestMetricsHaveHelpText verifies metrics have help descriptions. func TestMetricsHaveHelpText(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) // Check a few key metrics have non-empty help text metricsToCheck := []string{ "container_cpu_usage_seconds_total", "container_memory_usage_bytes", "machine_memory_bytes", } for _, name := range metricsToCheck { if mf, ok := families[name]; ok { help := mf.GetHelp() assert.NotEmpty(t, help, "Metric %s should have help text", name) } } } // TestContainerLastSeenExists verifies the container_last_seen metric is present. func TestContainerLastSeenExists(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) assert.True(t, framework.HasMetric(families, "container_last_seen"), "container_last_seen metric should exist") } // TestRootContainerMetricsExist verifies the root container (/) has metrics. func TestRootContainerMetricsExist(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) // The root container should appear in CPU metrics with id="/" cpuMetric, ok := framework.GetMetricFamily(families, "container_cpu_usage_seconds_total") require.True(t, ok) // Look for root container found := false for _, metric := range cpuMetric.GetMetric() { id := framework.GetLabelValue(metric, "id") if id == "/" { found = true // Root container should have positive CPU usage value := framework.GetCounterValue(metric) assert.GreaterOrEqual(t, value, float64(0), "Root container CPU should be >= 0") break } } assert.True(t, found, "Root container (/) should appear in CPU metrics") } // TestGoRuntimeMetricsExist verifies Go runtime metrics are exposed. func TestGoRuntimeMetricsExist(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) // Check for at least some Go runtime metrics goMetrics := []string{ "go_goroutines", "go_memstats_alloc_bytes", } foundCount := 0 for _, name := range goMetrics { if framework.HasMetric(families, name) { foundCount++ } } assert.GreaterOrEqual(t, foundCount, 1, "Should have at least one Go runtime metric") } // TestProcessMetricsExist verifies process-level metrics are exposed. func TestProcessMetricsExist(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) // These are process collector metrics for the cAdvisor process itself processMetrics := []string{ "process_cpu_seconds_total", "process_resident_memory_bytes", } foundCount := 0 for _, name := range processMetrics { if framework.HasMetric(families, name) { foundCount++ } } assert.GreaterOrEqual(t, foundCount, 1, "Should have at least one process metric") } // TestMetricsContainExpectedLabels verifies container metrics have the 'id' label. func TestMetricsContainExpectedLabels(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) // Container metrics should have 'id' label containerMetrics := []string{ "container_cpu_usage_seconds_total", "container_memory_usage_bytes", } for _, name := range containerMetrics { mf, ok := families[name] if !ok { continue } if len(mf.GetMetric()) == 0 { continue } // Check first metric has 'id' label metric := mf.GetMetric()[0] id := framework.GetLabelValue(metric, "id") assert.NotEmpty(t, id, "Metric %s should have 'id' label", name) } } // TestDiskIOMetricsExist verifies disk I/O metrics are present. func TestDiskIOMetricsExist(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) families, err := client.FetchAndParse() require.NoError(t, err) // At least some disk I/O metrics should exist diskIOMetrics := []string{ "container_fs_reads_bytes_total", "container_fs_writes_bytes_total", "container_fs_reads_total", "container_fs_writes_total", } foundCount := 0 for _, name := range diskIOMetrics { if framework.HasMetric(families, name) { foundCount++ } } // Some environments may not have all disk I/O metrics // but we should have at least one assert.GreaterOrEqual(t, foundCount, 1, "Should have at least one disk I/O metric") } // TestMetricsResponseContainsComments verifies the response contains # HELP and # TYPE. func TestMetricsResponseContainsComments(t *testing.T) { fm := framework.New(t) defer fm.Cleanup() client := framework.NewMetricsClient(fm.Hostname()) text, err := client.Fetch() require.NoError(t, err) assert.True(t, strings.Contains(text, "# HELP"), "Metrics response should contain # HELP comments") assert.True(t, strings.Contains(text, "# TYPE"), "Metrics response should contain # TYPE comments") } ================================================ FILE: machine/info.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package machine import ( "flag" "os" "path/filepath" "strings" "time" "golang.org/x/sys/unix" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/nvm" "github.com/google/cadvisor/utils/cloudinfo" "github.com/google/cadvisor/utils/sysfs" "github.com/google/cadvisor/utils/sysinfo" "k8s.io/klog/v2" ) const hugepagesDirectory = "/sys/kernel/mm/hugepages/" const memoryControllerPath = "/sys/devices/system/edac/mc/" var machineIDFilePath = flag.String("machine_id_file", "/etc/machine-id,/var/lib/dbus/machine-id", "Comma-separated list of files to check for machine-id. Use the first one that exists.") var bootIDFilePath = flag.String("boot_id_file", "/proc/sys/kernel/random/boot_id", "Comma-separated list of files to check for boot-id. Use the first one that exists.") func getInfoFromFiles(filePaths string) string { if len(filePaths) == 0 { return "" } for _, file := range strings.Split(filePaths, ",") { id, err := os.ReadFile(file) if err == nil { return strings.TrimSpace(string(id)) } } klog.Warningf("Couldn't collect info from any of the files in %q", filePaths) return "" } func Info(sysFs sysfs.SysFs, fsInfo fs.FsInfo, inHostNamespace bool) (*info.MachineInfo, error) { rootFs := "/" if !inHostNamespace { rootFs = "/rootfs" } cpuinfo, err := os.ReadFile(filepath.Join(rootFs, "/proc/cpuinfo")) if err != nil { return nil, err } clockSpeed, err := GetClockSpeed(cpuinfo) if err != nil { return nil, err } memoryCapacity, err := GetMachineMemoryCapacity() if err != nil { return nil, err } memoryByType, err := GetMachineMemoryByType(memoryControllerPath) if err != nil { return nil, err } swapCapacity, err := GetMachineSwapCapacity() if err != nil { return nil, err } nvmInfo, err := nvm.GetInfo() if err != nil { return nil, err } hugePagesInfo, err := sysinfo.GetHugePagesInfo(sysFs, hugepagesDirectory) if err != nil { return nil, err } filesystems, err := fsInfo.GetGlobalFsInfo() if err != nil { klog.Errorf("Failed to get global filesystem information: %v", err) } diskMap, err := sysinfo.GetBlockDeviceInfo(sysFs) if err != nil { klog.Errorf("Failed to get disk map: %v", err) } netDevices, err := sysinfo.GetNetworkDevices(sysFs) if err != nil { klog.Errorf("Failed to get network devices: %v", err) } topology, numCores, err := GetTopology(sysFs) if err != nil { klog.Errorf("Failed to get topology information: %v", err) } systemUUID, err := sysinfo.GetSystemUUID(sysFs) if err != nil { klog.Errorf("Failed to get system UUID: %v", err) } realCloudInfo := cloudinfo.NewRealCloudInfo() cloudProvider := realCloudInfo.GetCloudProvider() instanceType := realCloudInfo.GetInstanceType() instanceID := realCloudInfo.GetInstanceID() machineInfo := &info.MachineInfo{ Timestamp: time.Now(), CPUVendorID: GetCPUVendorID(cpuinfo), NumCores: numCores, NumPhysicalCores: GetPhysicalCores(cpuinfo), NumSockets: GetSockets(cpuinfo), NumBooks: GetBooks(cpuinfo), NumDrawers: GetDrawers(cpuinfo), CpuFrequency: clockSpeed, MemoryCapacity: memoryCapacity, MemoryByType: memoryByType, SwapCapacity: swapCapacity, NVMInfo: nvmInfo, HugePages: hugePagesInfo, DiskMap: diskMap, NetworkDevices: netDevices, Topology: topology, MachineID: getInfoFromFiles(filepath.Join(rootFs, *machineIDFilePath)), SystemUUID: systemUUID, BootID: getInfoFromFiles(filepath.Join(rootFs, *bootIDFilePath)), CloudProvider: cloudProvider, InstanceType: instanceType, InstanceID: instanceID, } for i := range filesystems { fs := filesystems[i] inodes := uint64(0) if fs.Inodes != nil { inodes = *fs.Inodes } machineInfo.Filesystems = append(machineInfo.Filesystems, info.FsInfo{Device: fs.Device, DeviceMajor: uint64(fs.Major), DeviceMinor: uint64(fs.Minor), Type: fs.Type.String(), Capacity: fs.Capacity, Inodes: inodes, HasInodes: fs.Inodes != nil}) } return machineInfo, nil } func ContainerOsVersion() string { os, err := getOperatingSystem() if err != nil { os = "Unknown" } return os } func KernelVersion() string { uname := &unix.Utsname{} if err := unix.Uname(uname); err != nil { return "Unknown" } return unix.ByteSliceToString(uname.Release[:]) } ================================================ FILE: machine/machine.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // The machine package contains functions that extract machine-level specs. package machine import ( "fmt" "os" "path" "regexp" "runtime" "strconv" "strings" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/utils" "github.com/google/cadvisor/utils/sysfs" "github.com/google/cadvisor/utils/sysinfo" "k8s.io/klog/v2" "golang.org/x/sys/unix" ) var ( coreRegExp = regexp.MustCompile(`(?m)^core id\s*:\s*([0-9]+)$`) nodeRegExp = regexp.MustCompile(`(?m)^physical id\s*:\s*([0-9]+)$`) bookRegExp = regexp.MustCompile(`(?m)^book id\s*:\s*([0-9]+)$`) drawerRegExp = regexp.MustCompile(`(?m)^drawer id\s*:\s*([0-9]+)$`) // Power systems have a different format so cater for both cpuClockSpeedMHz = regexp.MustCompile(`(?:cpu MHz|CPU MHz|clock)\s*:\s*([0-9]+\.[0-9]+)(?:MHz)?`) memoryCapacityRegexp = regexp.MustCompile(`MemTotal:\s*([0-9]+) kB`) swapCapacityRegexp = regexp.MustCompile(`SwapTotal:\s*([0-9]+) kB`) vendorIDRegexp = regexp.MustCompile(`vendor_id\s*:\s*(\w+)`) cpuAttributesPath = "/sys/devices/system/cpu/" isMemoryController = regexp.MustCompile("mc[0-9]+") isDimm = regexp.MustCompile("dimm[0-9]+") machineArch = getMachineArch() maxFreqFile = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq" ) const memTypeFileName = "dimm_mem_type" const sizeFileName = "size" // GetCPUVendorID returns "vendor_id" reading /proc/cpuinfo file. func GetCPUVendorID(procInfo []byte) string { vendorID := "" matches := vendorIDRegexp.FindSubmatch(procInfo) if len(matches) != 2 { klog.V(4).Info("Cannot read vendor id correctly, set empty.") return vendorID } vendorID = string(matches[1]) return vendorID } // GetPhysicalCores returns number of CPU cores reading /proc/cpuinfo file or if needed information from sysfs cpu path func GetPhysicalCores(procInfo []byte) int { numCores := getUniqueMatchesCount(string(procInfo), coreRegExp) if numCores == 0 { // read number of cores from /sys/bus/cpu/devices/cpu*/topology/core_id to deal with processors // for which 'core id' is not available in /proc/cpuinfo numCores = sysfs.GetUniqueCPUPropertyCount(cpuAttributesPath, sysfs.CPUCoreID) } if numCores == 0 { klog.Errorf("Cannot read number of physical cores correctly, number of cores set to %d", numCores) } return numCores } // GetSockets returns number of CPU sockets reading /proc/cpuinfo file or if needed information from sysfs cpu path func GetSockets(procInfo []byte) int { numSocket := getUniqueMatchesCount(string(procInfo), nodeRegExp) if numSocket == 0 { // read number of sockets from /sys/bus/cpu/devices/cpu*/topology/physical_package_id to deal with processors // for which 'physical id' is not available in /proc/cpuinfo numSocket = sysfs.GetUniqueCPUPropertyCount(cpuAttributesPath, sysfs.CPUPhysicalPackageID) } if numSocket == 0 { klog.Errorf("Cannot read number of sockets correctly, number of sockets set to %d", numSocket) } return numSocket } // GetBooks returns number of CPU books reading from sysfs cpu path func GetBooks(procInfo []byte) int { if runtime.GOARCH != "s390x" { return 0 } numBook := getUniqueMatchesCount(string(procInfo), bookRegExp) if numBook == 0 { // read number of books from /sys/bus/cpu/devices/cpu*/topology/book_id to deal with processors // for which 'book id' is not available in /proc/cpuinfo numBook = sysfs.GetUniqueCPUPropertyCount(cpuAttributesPath, sysfs.CPUBookID) } if numBook == 0 { klog.Errorf("Cannot read number of books correctly, number of books set to %d", numBook) } return numBook } // GetDrawer returns number of CPU drawerss reading from sysfs cpu path func GetDrawers(procInfo []byte) int { if runtime.GOARCH != "s390x" { return 0 } numDrawer := getUniqueMatchesCount(string(procInfo), drawerRegExp) if numDrawer == 0 { // read number of books from /sys/bus/cpu/devices/cpu*/topology/book_id to deal with processors // read number of drawers from /sys/bus/cpu/devices/cpu*/topology/drawer_id to deal with processors // for which 'drawer id' is not available in /proc/cpuinfo numDrawer = sysfs.GetUniqueCPUPropertyCount(cpuAttributesPath, sysfs.CPUDrawerID) } if numDrawer == 0 { klog.Errorf("Cannot read number of drawers correctly, number of drawers set to %d", numDrawer) } return numDrawer } // GetClockSpeed returns the CPU clock speed, given a []byte formatted as the /proc/cpuinfo file. func GetClockSpeed(procInfo []byte) (uint64, error) { // First look through sys to find a max supported cpu frequency. if utils.FileExists(maxFreqFile) { val, err := os.ReadFile(maxFreqFile) if err != nil { return 0, err } var maxFreq uint64 n, err := fmt.Sscanf(string(val), "%d", &maxFreq) if err != nil || n != 1 { return 0, fmt.Errorf("could not parse frequency %q", val) } return maxFreq, nil } // s390/s390x, mips64, riscv64, aarch64 and arm32 changes if isMips64() || isSystemZ() || isAArch64() || isArm32() || isRiscv64() { return 0, nil } // Fall back to /proc/cpuinfo matches := cpuClockSpeedMHz.FindSubmatch(procInfo) if len(matches) != 2 { return 0, fmt.Errorf("could not detect clock speed from output: %q", string(procInfo)) } speed, err := strconv.ParseFloat(string(matches[1]), 64) if err != nil { return 0, err } // Convert to kHz return uint64(speed * 1000), nil } // GetMachineMemoryCapacity returns the machine's total memory from /proc/meminfo. // Returns the total memory capacity as an uint64 (number of bytes). func GetMachineMemoryCapacity() (uint64, error) { out, err := os.ReadFile("/proc/meminfo") if err != nil { return 0, err } memoryCapacity, err := parseCapacity(out, memoryCapacityRegexp) if err != nil { return 0, err } return memoryCapacity, err } // GetMachineMemoryByType returns information about memory capacity and number of DIMMs. // Information is retrieved from sysfs edac per-DIMM API (/sys/devices/system/edac/mc/) // introduced in kernel 3.6. Documentation can be found at // https://www.kernel.org/doc/Documentation/admin-guide/ras.rst. // Full list of memory types can be found in edac_mc.c // (https://github.com/torvalds/linux/blob/v5.5/drivers/edac/edac_mc.c#L198) func GetMachineMemoryByType(edacPath string) (map[string]*info.MemoryInfo, error) { memory := map[string]*info.MemoryInfo{} names, err := os.ReadDir(edacPath) // On some architectures (such as ARM) memory controller device may not exist. // If this is the case then we ignore error and return empty slice. _, ok := err.(*os.PathError) if err != nil && ok { return memory, nil } else if err != nil { return memory, err } for _, controllerDir := range names { controller := controllerDir.Name() if !isMemoryController.MatchString(controller) { continue } dimms, err := os.ReadDir(path.Join(edacPath, controllerDir.Name())) if err != nil { return map[string]*info.MemoryInfo{}, err } for _, dimmDir := range dimms { dimm := dimmDir.Name() if !isDimm.MatchString(dimm) { continue } memType, err := os.ReadFile(path.Join(edacPath, controller, dimm, memTypeFileName)) if err != nil { return map[string]*info.MemoryInfo{}, err } readableMemType := strings.TrimSpace(string(memType)) if _, exists := memory[readableMemType]; !exists { memory[readableMemType] = &info.MemoryInfo{} } size, err := os.ReadFile(path.Join(edacPath, controller, dimm, sizeFileName)) if err != nil { return map[string]*info.MemoryInfo{}, err } capacity, err := strconv.Atoi(strings.TrimSpace(string(size))) if err != nil { return map[string]*info.MemoryInfo{}, err } memory[readableMemType].Capacity += uint64(mbToBytes(capacity)) memory[readableMemType].DimmCount++ } } return memory, nil } func mbToBytes(megabytes int) int { return megabytes * 1024 * 1024 } // GetMachineSwapCapacity returns the machine's total swap from /proc/meminfo. // Returns the total swap capacity as an uint64 (number of bytes). func GetMachineSwapCapacity() (uint64, error) { out, err := os.ReadFile("/proc/meminfo") if err != nil { return 0, err } swapCapacity, err := parseCapacity(out, swapCapacityRegexp) if err != nil { return 0, err } return swapCapacity, err } // GetTopology returns CPU topology reading information from sysfs func GetTopology(sysFs sysfs.SysFs) ([]info.Node, int, error) { return sysinfo.GetNodesInfo(sysFs) } // parseCapacity matches a Regexp in a []byte, returning the resulting value in bytes. // Assumes that the value matched by the Regexp is in KB. func parseCapacity(b []byte, r *regexp.Regexp) (uint64, error) { matches := r.FindSubmatch(b) if len(matches) != 2 { return 0, fmt.Errorf("failed to match regexp in output: %q", string(b)) } m, err := strconv.ParseUint(string(matches[1]), 10, 64) if err != nil { return 0, err } // Convert to bytes. return m * 1024, err } // getUniqueMatchesCount returns number of unique matches in given argument using provided regular expression func getUniqueMatchesCount(s string, r *regexp.Regexp) int { matches := r.FindAllString(s, -1) uniques := make(map[string]bool) for _, match := range matches { uniques[match] = true } return len(uniques) } func getMachineArch() string { uname := unix.Utsname{} err := unix.Uname(&uname) if err != nil { klog.Errorf("Cannot get machine architecture, err: %v", err) return "" } return unix.ByteSliceToString(uname.Machine[:]) } // arm32 changes func isArm32() bool { return strings.Contains(machineArch, "arm") } // aarch64 changes func isAArch64() bool { return strings.Contains(machineArch, "aarch64") } // s390/s390x changes func isSystemZ() bool { return strings.Contains(machineArch, "390") } // riscv64 changes func isRiscv64() bool { return strings.Contains(machineArch, "riscv64") } // mips64 changes func isMips64() bool { return strings.Contains(machineArch, "mips64") } ================================================ FILE: machine/operatingsystem_unix.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build freebsd || darwin || linux package machine import ( "fmt" "os" "regexp" "runtime" "strings" "golang.org/x/sys/unix" ) var rex = regexp.MustCompile("(PRETTY_NAME)=(.*)") // getOperatingSystem gets the name of the current operating system. func getOperatingSystem() (string, error) { if runtime.GOOS == "darwin" || runtime.GOOS == "freebsd" { uname := unix.Utsname{} err := unix.Uname(&uname) if err != nil { return "", err } return unix.ByteSliceToString(uname.Sysname[:]), nil } bytes, err := os.ReadFile("/etc/os-release") if err != nil && os.IsNotExist(err) { // /usr/lib/os-release in stateless systems like Clear Linux bytes, err = os.ReadFile("/usr/lib/os-release") } if err != nil { return "", fmt.Errorf("error opening file : %v", err) } line := rex.FindAllStringSubmatch(string(bytes), -1) if len(line) > 0 { return strings.Trim(line[0][2], "\""), nil } return "Linux", nil } ================================================ FILE: machine/operatingsystem_windows.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package machine import ( "fmt" "golang.org/x/sys/windows/registry" ) func getOperatingSystem() (string, error) { system := "Windows" k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) if err != nil { return system, err } defer k.Close() productName, _, err := k.GetStringValue("ProductName") if err != nil { return system, nil } releaseId, _, err := k.GetStringValue("ReleaseId") if err != nil { return system, err } currentBuildNumber, _, err := k.GetStringValue("CurrentBuildNumber") if err != nil { return system, err } revision, _, err := k.GetIntegerValue("UBR") if err != nil { return system, err } system = fmt.Sprintf("%s Version %s (OS Build %s.%d)", productName, releaseId, currentBuildNumber, revision) return system, nil } ================================================ FILE: machine/testdata/cpu9999/online ================================================ 1 ================================================ FILE: machine/testdata/cpu9999/topology/core_id ================================================ 8888 ================================================ FILE: machine/testdata/cpu9999/topology/physical_package_id ================================================ 0 ================================================ FILE: machine/testdata/cpuinfo ================================================ processor : 0 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 1596.000 cache size : 12288 KB physical id : 0 siblings : 6 core id : 0 cpu cores : 6 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 1 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 1596.000 cache size : 12288 KB physical id : 0 siblings : 6 core id : 1 cpu cores : 6 apicid : 2 initial apicid : 2 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 2 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 1596.000 cache size : 12288 KB physical id : 0 siblings : 6 core id : 2 cpu cores : 6 apicid : 4 initial apicid : 4 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 3 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 1596.000 cache size : 12288 KB physical id : 1 siblings : 6 core id : 3 cpu cores : 6 apicid : 16 initial apicid : 16 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 4 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 1596.000 cache size : 12288 KB physical id : 1 siblings : 6 core id : 4 cpu cores : 6 apicid : 18 initial apicid : 18 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 5 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 1596.000 cache size : 12288 KB physical id : 1 siblings : 6 core id : 5 cpu cores : 6 apicid : 20 initial apicid : 20 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 6 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 2661.000 cache size : 12288 KB physical id : 0 siblings : 6 core id : 0 cpu cores : 6 apicid : 1 initial apicid : 1 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 7 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 2661.000 cache size : 12288 KB physical id : 0 siblings : 6 core id : 1 cpu cores : 6 apicid : 3 initial apicid : 3 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 8 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 1596.000 cache size : 12288 KB physical id : 0 siblings : 6 core id : 2 cpu cores : 6 apicid : 5 initial apicid : 5 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 9 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 2661.000 cache size : 12288 KB physical id : 1 siblings : 6 core id : 3 cpu cores : 6 apicid : 17 initial apicid : 17 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 10 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 1596.000 cache size : 12288 KB physical id : 1 siblings : 6 core id : 4 cpu cores : 6 apicid : 19 initial apicid : 19 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual processor : 11 cpu family : 6 stepping : 2 microcode : 0x10 cpu MHz : 2661.000 cache size : 12288 KB physical id : 1 siblings : 6 core id : 5 cpu cores : 6 apicid : 21 initial apicid : 21 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes bogomips : 5333.60 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual ================================================ FILE: machine/testdata/cpuinfo_arm ================================================ processor : 0 model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 76.80 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 processor : 1 model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 76.80 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 processor : 2 model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 76.80 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 processor : 3 model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 76.80 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 Hardware : BCM2835 Revision : 0000 Serial : 00000000d0a71bfd ================================================ FILE: machine/testdata/cpuinfo_lower_case ================================================ processor : 0 cpu model : ICT Loongson-3 V0.13 FPU V0.1 model name : ICT Loongson-3A R3 (Loongson-3B3000) @ 1450MHz BogoMIPS : 2887.52 cpu MHz : 1450.00 wait instruction : yes microsecond timers : yes tlb_entries : 1088 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz shadow register sets : 1 kscratch registers : 6 package : 0 core : 0 VCED exceptions : not available VCEI exceptions : not available processor : 1 cpu model : ICT Loongson-3 V0.13 FPU V0.1 model name : ICT Loongson-3A R3 (Loongson-3B3000) @ 1450MHz BogoMIPS : 2902.61 cpu MHz : 1450.00 wait instruction : yes microsecond timers : yes tlb_entries : 1088 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz shadow register sets : 1 kscratch registers : 6 package : 0 core : 1 VCED exceptions : not available VCEI exceptions : not available processor : 2 cpu model : ICT Loongson-3 V0.13 FPU V0.1 model name : ICT Loongson-3A R3 (Loongson-3B3000) @ 1450MHz BogoMIPS : 2902.61 cpu MHz : 1450.00 wait instruction : yes microsecond timers : yes tlb_entries : 1088 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz shadow register sets : 1 kscratch registers : 6 package : 0 core : 2 VCED exceptions : not available VCEI exceptions : not available processor : 3 cpu model : ICT Loongson-3 V0.13 FPU V0.1 model name : ICT Loongson-3A R3 (Loongson-3B3000) @ 1450MHz BogoMIPS : 2902.61 cpu MHz : 1450.00 wait instruction : yes microsecond timers : yes tlb_entries : 1088 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz shadow register sets : 1 kscratch registers : 6 package : 0 core : 3 VCED exceptions : not available VCEI exceptions : not available processor : 4 cpu model : ICT Loongson-3 V0.13 FPU V0.1 model name : ICT Loongson-3A R3 (Loongson-3B3000) @ 1450MHz BogoMIPS : 2887.52 cpu MHz : 1450.00 wait instruction : yes microsecond timers : yes tlb_entries : 1088 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz shadow register sets : 1 kscratch registers : 6 package : 1 core : 0 VCED exceptions : not available VCEI exceptions : not available processor : 5 cpu model : ICT Loongson-3 V0.13 FPU V0.1 model name : ICT Loongson-3A R3 (Loongson-3B3000) @ 1450MHz BogoMIPS : 2887.52 cpu MHz : 1450.00 wait instruction : yes microsecond timers : yes tlb_entries : 1088 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz shadow register sets : 1 kscratch registers : 6 package : 1 core : 1 VCED exceptions : not available VCEI exceptions : not available processor : 6 cpu model : ICT Loongson-3 V0.13 FPU V0.1 model name : ICT Loongson-3A R3 (Loongson-3B3000) @ 1450MHz BogoMIPS : 2887.52 cpu MHz : 1450.00 wait instruction : yes microsecond timers : yes tlb_entries : 1088 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz shadow register sets : 1 kscratch registers : 6 package : 1 core : 2 VCED exceptions : not available VCEI exceptions : not available processor : 7 cpu model : ICT Loongson-3 V0.13 FPU V0.1 model name : ICT Loongson-3A R3 (Loongson-3B3000) @ 1450MHz BogoMIPS : 2887.52 cpu MHz : 1450.00 wait instruction : yes microsecond timers : yes tlb_entries : 1088 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz shadow register sets : 1 kscratch registers : 6 package : 1 core : 3 VCED exceptions : not available VCEI exceptions : not available ================================================ FILE: machine/testdata/cpuinfo_onesocket_many_NUMAs ================================================ processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 0 siblings : 2 core id : 0 cpu cores : 1 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 1 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 0 siblings : 2 core id : 0 cpu cores : 1 apicid : 1 initial apicid : 1 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 2 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 1 siblings : 2 core id : 0 cpu cores : 1 apicid : 2 initial apicid : 2 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 3 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 1 siblings : 2 core id : 0 cpu cores : 1 apicid : 3 initial apicid : 3 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 4 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 2 siblings : 2 core id : 0 cpu cores : 1 apicid : 4 initial apicid : 4 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 5 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 2 siblings : 2 core id : 0 cpu cores : 1 apicid : 5 initial apicid : 5 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 6 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 3 siblings : 2 core id : 0 cpu cores : 1 apicid : 6 initial apicid : 6 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 7 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 3 siblings : 2 core id : 0 cpu cores : 1 apicid : 7 initial apicid : 7 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 8 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 4 siblings : 2 core id : 0 cpu cores : 1 apicid : 8 initial apicid : 8 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 9 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 4 siblings : 2 core id : 0 cpu cores : 1 apicid : 9 initial apicid : 9 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 10 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 5 siblings : 2 core id : 0 cpu cores : 1 apicid : 10 initial apicid : 10 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 11 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 5 siblings : 2 core id : 0 cpu cores : 1 apicid : 11 initial apicid : 11 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 12 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 6 siblings : 2 core id : 0 cpu cores : 1 apicid : 12 initial apicid : 12 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 13 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 6 siblings : 2 core id : 0 cpu cores : 1 apicid : 13 initial apicid : 13 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 14 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 7 siblings : 2 core id : 0 cpu cores : 1 apicid : 14 initial apicid : 14 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 15 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 7 siblings : 2 core id : 0 cpu cores : 1 apicid : 15 initial apicid : 15 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 16 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 8 siblings : 2 core id : 0 cpu cores : 1 apicid : 16 initial apicid : 16 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 17 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 8 siblings : 2 core id : 0 cpu cores : 1 apicid : 17 initial apicid : 17 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 18 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 9 siblings : 2 core id : 0 cpu cores : 1 apicid : 18 initial apicid : 18 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 19 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 9 siblings : 2 core id : 0 cpu cores : 1 apicid : 19 initial apicid : 19 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 20 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 10 siblings : 2 core id : 0 cpu cores : 1 apicid : 20 initial apicid : 20 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 21 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 10 siblings : 2 core id : 0 cpu cores : 1 apicid : 21 initial apicid : 21 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 22 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 11 siblings : 2 core id : 0 cpu cores : 1 apicid : 22 initial apicid : 22 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 23 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 11 siblings : 2 core id : 0 cpu cores : 1 apicid : 23 initial apicid : 23 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 24 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 12 siblings : 2 core id : 0 cpu cores : 1 apicid : 24 initial apicid : 24 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 25 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 12 siblings : 2 core id : 0 cpu cores : 1 apicid : 25 initial apicid : 25 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 26 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 13 siblings : 2 core id : 0 cpu cores : 1 apicid : 26 initial apicid : 26 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 27 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 13 siblings : 2 core id : 0 cpu cores : 1 apicid : 27 initial apicid : 27 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 28 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 14 siblings : 2 core id : 0 cpu cores : 1 apicid : 28 initial apicid : 28 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 29 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 14 siblings : 2 core id : 0 cpu cores : 1 apicid : 29 initial apicid : 29 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 30 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 15 siblings : 2 core id : 0 cpu cores : 1 apicid : 30 initial apicid : 30 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 31 vendor_id : GenuineIntel cpu family : 6 model : 85 model name : Intel(R) Xeon(R) Gold 5218R CPU @ 2.10GHz stepping : 7 microcode : 0x1 cpu MHz : 2095.082 cache size : 16384 KB physical id : 15 siblings : 2 core id : 0 cpu cores : 1 apicid : 31 initial apicid : 31 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat pku ospke avx512_vnni md_clear arch_capabilities bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bogomips : 4190.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: ================================================ FILE: machine/testdata/cpuinfo_rpi4 ================================================ processor : 0 BogoMIPS : 108.00 Features : fp asimd evtstrm crc32 cpuid CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x0 CPU part : 0xd08 CPU revision : 3 processor : 1 BogoMIPS : 108.00 Features : fp asimd evtstrm crc32 cpuid CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x0 CPU part : 0xd08 CPU revision : 3 processor : 2 BogoMIPS : 108.00 Features : fp asimd evtstrm crc32 cpuid CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x0 CPU part : 0xd08 CPU revision : 3 processor : 3 BogoMIPS : 108.00 Features : fp asimd evtstrm crc32 cpuid CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x0 CPU part : 0xd08 CPU revision : 3 Hardware : BCM2835 Revision : c03111 Serial : 10000000bb9410ef Model : Raspberry Pi 4 Model B Rev 1.1 ================================================ FILE: machine/testdata/cpuinfo_upper_case ================================================ processor : 0 cpu model : ICT Loongson-3 V0.4 FPU V0.1 model name : Loongson-3A R4 (Loongson-3B4000) CPU MHz : 1800.00 BogoMIPS : 12730.64 wait instruction : yes microsecond timers : yes tlb_entries : 2112 extra interrupt vector : yes hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz msa Loongson Features : csr lasx lamo cam vz gft lft msi256 extioi csripi shadow register sets : 1 kscratch registers : 6 package : 0 core : 0 VCED exceptions : not available VCEI exceptions : not available processor : 1 cpu model : ICT Loongson-3 V0.4 FPU V0.1 model name : Loongson-3A R4 (Loongson-3B4000) CPU MHz : 1800.00 BogoMIPS : 12711.24 wait instruction : yes microsecond timers : yes tlb_entries : 2112 extra interrupt vector : yes hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz msa Loongson Features : csr lasx lamo cam vz gft lft msi256 extioi csripi shadow register sets : 1 kscratch registers : 6 package : 0 core : 1 VCED exceptions : not available VCEI exceptions : not available processor : 2 cpu model : ICT Loongson-3 V0.4 FPU V0.1 model name : Loongson-3A R4 (Loongson-3B4000) CPU MHz : 1800.00 BogoMIPS : 12730.64 wait instruction : yes microsecond timers : yes tlb_entries : 2112 extra interrupt vector : yes hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz msa Loongson Features : csr lasx lamo cam vz gft lft msi256 extioi csripi shadow register sets : 1 kscratch registers : 6 package : 0 core : 2 VCED exceptions : not available VCEI exceptions : not available processor : 3 cpu model : ICT Loongson-3 V0.4 FPU V0.1 model name : Loongson-3A R4 (Loongson-3B4000) CPU MHz : 1800.00 BogoMIPS : 12730.64 wait instruction : yes microsecond timers : yes tlb_entries : 2112 extra interrupt vector : yes hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz msa Loongson Features : csr lasx lamo cam vz gft lft msi256 extioi csripi shadow register sets : 1 kscratch registers : 6 package : 0 core : 3 VCED exceptions : not available VCEI exceptions : not available processor : 4 cpu model : ICT Loongson-3 V0.4 FPU V0.1 model name : Loongson-3A R4 (Loongson-3B4000) CPU MHz : 1800.00 BogoMIPS : 12730.64 wait instruction : yes microsecond timers : yes tlb_entries : 2112 extra interrupt vector : yes hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz msa Loongson Features : csr lasx lamo cam vz gft lft msi256 extioi csripi shadow register sets : 1 kscratch registers : 6 package : 1 core : 0 VCED exceptions : not available VCEI exceptions : not available processor : 5 cpu model : ICT Loongson-3 V0.4 FPU V0.1 model name : Loongson-3A R4 (Loongson-3B4000) CPU MHz : 1800.00 BogoMIPS : 12730.64 wait instruction : yes microsecond timers : yes tlb_entries : 2112 extra interrupt vector : yes hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz msa Loongson Features : csr lasx lamo cam vz gft lft msi256 extioi csripi shadow register sets : 1 kscratch registers : 6 package : 1 core : 1 VCED exceptions : not available VCEI exceptions : not available processor : 6 cpu model : ICT Loongson-3 V0.4 FPU V0.1 model name : Loongson-3A R4 (Loongson-3B4000) CPU MHz : 1800.00 BogoMIPS : 12730.64 wait instruction : yes microsecond timers : yes tlb_entries : 2112 extra interrupt vector : yes hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz msa Loongson Features : csr lasx lamo cam vz gft lft msi256 extioi csripi shadow register sets : 1 kscratch registers : 6 package : 1 core : 2 VCED exceptions : not available VCEI exceptions : not available processor : 7 cpu model : ICT Loongson-3 V0.4 FPU V0.1 model name : Loongson-3A R4 (Loongson-3B4000) CPU MHz : 1800.00 BogoMIPS : 12730.64 wait instruction : yes microsecond timers : yes tlb_entries : 2112 extra interrupt vector : yes hardware watchpoint : yes, count: 0, address/irw mask: [] isa : mips1 mips2 mips3 mips4 mips5 mips32r1 mips32r2 mips64r1 mips64r2 ASEs implemented : vz msa Loongson Features : csr lasx lamo cam vz gft lft msi256 extioi csripi shadow register sets : 1 kscratch registers : 6 package : 1 core : 3 VCED exceptions : not available VCEI exceptions : not available ================================================ FILE: machine/testdata/edac/mc/mc0/dimm0/dimm_mem_type ================================================ Unbuffered-DDR4 ================================================ FILE: machine/testdata/edac/mc/mc0/dimm0/size ================================================ 789 ================================================ FILE: machine/testdata/edac/mc/mc0/dimm1/dimm_mem_type ================================================ Non-volatile-RAM ================================================ FILE: machine/testdata/edac/mc/mc0/dimm1/size ================================================ 456 ================================================ FILE: machine/testdata/edac/mc/mc0/dimm_is_fake/dimm_mem_type ================================================ Unbuffered-DDR4 ================================================ FILE: machine/testdata/edac/mc/mc0/dimm_is_fake/size ================================================ 321 ================================================ FILE: machine/testdata/edac/mc/mc1/dimm0/dimm_mem_type ================================================ Non-volatile-RAM ================================================ FILE: machine/testdata/edac/mc/mc1/dimm0/size ================================================ 123 ================================================ FILE: machine/testdata/edac/mc/mc_fake/dimm0/dimm0/dimm_mem_type ================================================ Unbuffered-DDR4 ================================================ FILE: machine/testdata/edac/mc/mc_fake/dimm0/dimm0/size ================================================ 789 ================================================ FILE: machine/testdata/edac/mc/mc_fake/dimm0/dimm1/dimm_mem_type ================================================ Non-volatile-RAM ================================================ FILE: machine/testdata/edac/mc/mc_fake/dimm0/dimm1/size ================================================ 456 ================================================ FILE: machine/testdata/edac/mc/mc_fake/dimm0/dimm_mem_type ================================================ Unbuffered-DDR4 ================================================ FILE: machine/testdata/edac/mc/mc_fake/dimm0/size ================================================ 789 ================================================ FILE: machine/testdata/edac/mc/mc_fake/dimm1/dimm_mem_type ================================================ Non-volatile-RAM ================================================ FILE: machine/testdata/edac/mc/mc_fake/dimm1/size ================================================ 456 ================================================ FILE: machine/testdata/sysfs_cpus/cpu0/topology/core_id ================================================ 0 ================================================ FILE: machine/testdata/sysfs_cpus/cpu0/topology/physical_package_id ================================================ 0 ================================================ FILE: machine/testdata/sysfs_cpus/cpu1/.gitkeep ================================================ ================================================ FILE: machine/testdata/wrong_sysfs/cpu0/.gitkeep ================================================ ================================================ FILE: machine/testdata_rpi4/cpu0/hotplug/fail ================================================ -1 ================================================ FILE: machine/testdata_rpi4/cpu0/hotplug/state ================================================ 206 ================================================ FILE: machine/testdata_rpi4/cpu0/hotplug/target ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/core_cpus ================================================ 1 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/core_cpus_list ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/core_id ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/core_siblings ================================================ f ================================================ FILE: machine/testdata_rpi4/cpu0/topology/core_siblings_list ================================================ 0-3 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/die_cpus ================================================ 1 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/die_cpus_list ================================================ 1 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/die_id ================================================ -1 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/package_cpus ================================================ f ================================================ FILE: machine/testdata_rpi4/cpu0/topology/package_cpus_list ================================================ 0-3 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/physical_package_id ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/thread_siblings ================================================ 1 ================================================ FILE: machine/testdata_rpi4/cpu0/topology/thread_siblings_list ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu1/cpu_capacity ================================================ 1024 ================================================ FILE: machine/testdata_rpi4/cpu1/hotplug/fail ================================================ -1 ================================================ FILE: machine/testdata_rpi4/cpu1/hotplug/state ================================================ 206 ================================================ FILE: machine/testdata_rpi4/cpu1/hotplug/target ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/core_cpus ================================================ 2 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/core_cpus_list ================================================ 1 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/core_id ================================================ 1 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/core_siblings ================================================ f ================================================ FILE: machine/testdata_rpi4/cpu1/topology/core_siblings_list ================================================ 0-3 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/die_cpus ================================================ 2 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/die_cpus_list ================================================ 1 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/die_id ================================================ -1 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/package_cpus ================================================ f ================================================ FILE: machine/testdata_rpi4/cpu1/topology/package_cpus_list ================================================ 0-3 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/physical_package_id ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/thread_siblings ================================================ 2 ================================================ FILE: machine/testdata_rpi4/cpu1/topology/thread_siblings_list ================================================ 1 ================================================ FILE: machine/testdata_rpi4/cpu1/uevent ================================================ OF_NAME=cpu OF_FULLNAME=/cpus/cpu@1 OF_TYPE=cpu OF_COMPATIBLE_0=arm,cortex-a72 OF_COMPATIBLE_N=1 MODALIAS=cpu:type:aarch64:feature:,0000,0001,0002,0007,000B ================================================ FILE: machine/testdata_rpi4/cpu2/hotplug/fail ================================================ -1 ================================================ FILE: machine/testdata_rpi4/cpu2/hotplug/state ================================================ 206 ================================================ FILE: machine/testdata_rpi4/cpu2/hotplug/target ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/core_cpus ================================================ 4 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/core_cpus_list ================================================ 2 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/core_id ================================================ 2 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/core_siblings ================================================ f ================================================ FILE: machine/testdata_rpi4/cpu2/topology/core_siblings_list ================================================ 0-3 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/die_cpus ================================================ 4 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/die_cpus_list ================================================ 2 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/die_id ================================================ -1 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/package_cpus ================================================ f ================================================ FILE: machine/testdata_rpi4/cpu2/topology/package_cpus_list ================================================ 0-3 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/physical_package_id ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/thread_siblings ================================================ 4 ================================================ FILE: machine/testdata_rpi4/cpu2/topology/thread_siblings_list ================================================ 2 ================================================ FILE: machine/testdata_rpi4/cpu3/hotplug/fail ================================================ -1 ================================================ FILE: machine/testdata_rpi4/cpu3/hotplug/state ================================================ 206 ================================================ FILE: machine/testdata_rpi4/cpu3/hotplug/target ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/core_cpus ================================================ 8 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/core_cpus_list ================================================ 3 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/core_id ================================================ 3 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/core_siblings ================================================ f ================================================ FILE: machine/testdata_rpi4/cpu3/topology/core_siblings_list ================================================ 0-3 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/die_cpus ================================================ 8 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/die_cpus_list ================================================ 3 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/die_id ================================================ -1 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/package_cpus ================================================ f ================================================ FILE: machine/testdata_rpi4/cpu3/topology/package_cpus_list ================================================ 0-3 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/physical_package_id ================================================ 0 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/thread_siblings ================================================ 8 ================================================ FILE: machine/testdata_rpi4/cpu3/topology/thread_siblings_list ================================================ 3 ================================================ FILE: machine/testdata_rpi4/hotplug/states ================================================ 24: fs/buffer:dead [0/1911] 25: printk:dead 26: mm/memctrl:dead 27: lib/percpu_cnt:dead 28: lib/radix:dead 29: mm/page_alloc:dead 30: net/dev:dead 35: padata:dead 36: workqueue:prepare 38: hrtimers:prepare 41: smpcfd:prepare 42: relay:prepare 43: slab:prepare 44: md/raid5:prepare 45: RCU/tree:prepare 54: base/topology:prepare 57: trace/RB:preapre 58: mm/zsmalloc:prepare 59: mm/zswap:prepare 60: mm/zswap_pool:prepare 63: timers:prepare 65: fork:vm_stack_cache 86: cpu:bringup 87: idle:dead 88: ap:offline 89: sched:starting 90: RCU/tree:dying 91: irqchip/arm/gic:starting 107: arm64/debug_monitors:starting 108: perf/arm64/hw_breakpoint:starting 110: perf/arm/pmu:starting 113: clockevents/arm/arch_timer:starting 125: kvm/cpu:starting 126: kvm/arm/vgic:starting 128: kvm/arm/timer:starting 129: clockevents/dummy_timer:starting 132: arm64/isndep:starting 133: smpcfd:dying 136: ap:online 137: cpu:teardown 139: smpboot/threads:online 141: irq/affinity:online 144: perf:online 155: perf/arm/ccn:online 168: lockup_detector:online 169: workqueue:online 170: RCU/tree:online 172: mm/writeback:online 173: mm/vmstat:online 174: mm/compaction:online 175: arm64/cpuinfo:online 176: padata:online 177: mm/vmscan:online 178: lib/percpu_cnt:online 179: cpufreq:online 180: leds/trigger:starting 181: printk:online 205: sched:active 206: online ================================================ FILE: machine/topology_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package machine import ( "encoding/json" "os" "path/filepath" "reflect" "runtime" "sort" "testing" "github.com/stretchr/testify/assert" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/utils/sysfs" "github.com/google/cadvisor/utils/sysfs/fakesysfs" ) func TestPhysicalCores(t *testing.T) { testfile := "./testdata/cpuinfo" testcpuinfo, err := os.ReadFile(testfile) assert.Nil(t, err) assert.NotNil(t, testcpuinfo) numPhysicalCores := GetPhysicalCores(testcpuinfo) assert.Equal(t, 6, numPhysicalCores) } func TestPhysicalCoresReadingFromCpuBus(t *testing.T) { origCPUAttributesPath := cpuAttributesPath defer func() { cpuAttributesPath = origCPUAttributesPath }() cpuAttributesPath = "./testdata/sysfs_cpus/" // overwriting package variable to mock sysfs testfile := "./testdata/cpuinfo_arm" // mock cpuinfo without core id testcpuinfo, err := os.ReadFile(testfile) assert.Nil(t, err) assert.NotNil(t, testcpuinfo) numPhysicalCores := GetPhysicalCores(testcpuinfo) assert.Equal(t, 1, numPhysicalCores) } func TestPhysicalCoresFromWrongSysFs(t *testing.T) { origCPUAttributesPath := cpuAttributesPath defer func() { cpuAttributesPath = origCPUAttributesPath }() cpuAttributesPath = "./testdata/wrongsysfs" // overwriting package variable to mock sysfs testfile := "./testdata/cpuinfo_arm" // mock cpuinfo without core id testcpuinfo, err := os.ReadFile(testfile) assert.Nil(t, err) assert.NotNil(t, testcpuinfo) numPhysicalCores := GetPhysicalCores(testcpuinfo) assert.Equal(t, 0, numPhysicalCores) } func TestSockets(t *testing.T) { testfile := "./testdata/cpuinfo" testcpuinfo, err := os.ReadFile(testfile) assert.Nil(t, err) assert.NotNil(t, testcpuinfo) numSockets := GetSockets(testcpuinfo) assert.Equal(t, 2, numSockets) } func TestSocketsReadingFromCpuBus(t *testing.T) { origCPUAttributesPath := cpuAttributesPath defer func() { cpuAttributesPath = origCPUAttributesPath }() cpuAttributesPath = "./testdata/wrongsysfs" // overwriting package variable to mock sysfs testfile := "./testdata/cpuinfo_arm" // mock cpuinfo without physical id testcpuinfo, err := os.ReadFile(testfile) assert.Nil(t, err) assert.NotNil(t, testcpuinfo) numSockets := GetSockets(testcpuinfo) assert.Equal(t, 0, numSockets) } func TestSocketsReadingFromWrongSysFs(t *testing.T) { path, err := filepath.Abs("./testdata/sysfs_cpus/") assert.NoError(t, err) origCPUAttributesPath := cpuAttributesPath defer func() { cpuAttributesPath = origCPUAttributesPath }() cpuAttributesPath = path // overwriting package variable to mock sysfs testfile := "./testdata/cpuinfo_arm" // mock cpuinfo without physical id testcpuinfo, err := os.ReadFile(testfile) assert.Nil(t, err) assert.NotNil(t, testcpuinfo) numSockets := GetSockets(testcpuinfo) assert.Equal(t, 1, numSockets) } func TestTopology(t *testing.T) { machineArch = "" // overwrite package variable sysFs := &fakesysfs.FakeSysFs{} c := sysfs.CacheInfo{ Size: 32 * 1024, Type: "unified", Level: 1, Cpus: 2, } sysFs.SetCacheInfo(c) nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", "/fakeSysfs/devices/system/node/node1", } sysFs.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", "/fakeSysfs/devices/system/node/node0/cpu2", "/fakeSysfs/devices/system/node/node0/cpu6", "/fakeSysfs/devices/system/node/node0/cpu7", "/fakeSysfs/devices/system/node/node0/cpu8", }, "/fakeSysfs/devices/system/node/node1": { "/fakeSysfs/devices/system/node/node0/cpu3", "/fakeSysfs/devices/system/node/node0/cpu4", "/fakeSysfs/devices/system/node/node0/cpu5", "/fakeSysfs/devices/system/node/node0/cpu9", "/fakeSysfs/devices/system/node/node0/cpu10", "/fakeSysfs/devices/system/node/node0/cpu11", }, } sysFs.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "1", "/fakeSysfs/devices/system/node/node0/cpu2": "2", "/fakeSysfs/devices/system/node/node0/cpu3": "3", "/fakeSysfs/devices/system/node/node0/cpu4": "4", "/fakeSysfs/devices/system/node/node0/cpu5": "5", "/fakeSysfs/devices/system/node/node0/cpu6": "0", "/fakeSysfs/devices/system/node/node0/cpu7": "1", "/fakeSysfs/devices/system/node/node0/cpu8": "2", "/fakeSysfs/devices/system/node/node0/cpu9": "3", "/fakeSysfs/devices/system/node/node0/cpu10": "4", "/fakeSysfs/devices/system/node/node0/cpu11": "5", } sysFs.SetCoreThreads(coreThread, nil) memTotal := "MemTotal: 32817192 kB" sysFs.SetMemory(memTotal, nil) hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, &fakesysfs.FileInfo{EntryName: "hugepages-1048576kB"}, } sysFs.SetHugePages(hugePages, nil) hugePageNr := map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node1/hugepages/hugepages-1048576kB/nr_hugepages": "1", } sysFs.SetHugePagesNr(hugePageNr, nil) physicalPackageIDs := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "0", "/fakeSysfs/devices/system/node/node0/cpu3": "0", "/fakeSysfs/devices/system/node/node0/cpu4": "0", "/fakeSysfs/devices/system/node/node0/cpu5": "0", "/fakeSysfs/devices/system/node/node0/cpu6": "1", "/fakeSysfs/devices/system/node/node0/cpu7": "1", "/fakeSysfs/devices/system/node/node0/cpu8": "1", "/fakeSysfs/devices/system/node/node0/cpu9": "1", "/fakeSysfs/devices/system/node/node0/cpu10": "1", "/fakeSysfs/devices/system/node/node0/cpu11": "1", } sysFs.SetPhysicalPackageIDs(physicalPackageIDs, nil) sysFs.SetDistances("/fakeSysfs/devices/system/node/node0", "10 11", nil) sysFs.SetDistances("/fakeSysfs/devices/system/node/node1", "11 10", nil) topology, numCores, err := GetTopology(sysFs) assert.Nil(t, err) assert.Equal(t, 12, numCores) expectedTopology := []info.Node{} numNodes := 2 numCoresPerNode := 3 numThreads := 2 cache := info.Cache{ Size: 32 * 1024, Type: "unified", Level: 1, } distances := [][]uint64{ {10, 11}, {11, 10}, } for i := 0; i < numNodes; i++ { node := info.Node{Id: i} // Copy over Memory from result. TODO(rjnagal): Use memory from fake. node.Memory = topology[i].Memory // Copy over HugePagesInfo from result. TODO(ohsewon): Use HugePagesInfo from fake. node.HugePages = topology[i].HugePages node.Distances = distances[i] for j := 0; j < numCoresPerNode; j++ { core := info.Core{Id: i*numCoresPerNode + j} core.Caches = append(core.Caches, cache) for k := 0; k < numThreads; k++ { core.Threads = append(core.Threads, k*numCoresPerNode*numNodes+core.Id) } node.Cores = append(node.Cores, core) } expectedTopology = append(expectedTopology, node) } assert.NotNil(t, reflect.DeepEqual(topology, expectedTopology)) } func TestTopologyEmptySysFs(t *testing.T) { machineArch = "" // overwrite package variable _, _, err := GetTopology(&fakesysfs.FakeSysFs{}) assert.NotNil(t, err) } func TestTopologyWithoutNodes(t *testing.T) { machineArch = "" // overwrite package variable sysFs := &fakesysfs.FakeSysFs{} c := sysfs.CacheInfo{ Id: 0, Size: 32 * 1024, Type: "unified", Level: 0, Cpus: 2, } sysFs.SetCacheInfo(c) nodesPaths := []string{} sysFs.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/sys/devices/system/cpu": { "/sys/devices/system/cpu/cpu0", "/sys/devices/system/cpu/cpu1", "/sys/devices/system/cpu/cpu2", "/sys/devices/system/cpu/cpu3", }, } sysFs.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/sys/devices/system/cpu/cpu0": "0", "/sys/devices/system/cpu/cpu1": "1", "/sys/devices/system/cpu/cpu2": "0", "/sys/devices/system/cpu/cpu3": "1", } sysFs.SetCoreThreads(coreThread, nil) physicalPackageIDs := map[string]string{ "/sys/devices/system/cpu/cpu0": "0", "/sys/devices/system/cpu/cpu1": "1", "/sys/devices/system/cpu/cpu2": "0", "/sys/devices/system/cpu/cpu3": "1", } sysFs.SetPhysicalPackageIDs(physicalPackageIDs, nil) topology, numCores, err := GetTopology(sysFs) sort.SliceStable(topology, func(i, j int) bool { return topology[i].Id < topology[j].Id }) assert.Nil(t, err) assert.Equal(t, 2, len(topology)) assert.Equal(t, 4, numCores) topologyJSON1, err := json.Marshal(topology[0]) assert.Nil(t, err) topologyJSON2, err := json.Marshal(topology[1]) assert.Nil(t, err) expectedTopology1 := `{"node_id":0,"memory":0,"hugepages":null,"distances":null,"cores":[{"core_id":0,"thread_ids":[0,2],"caches":[{"id":0, "size":32768,"type":"unified","level":0}], "socket_id": 0, "uncore_caches":null}],"caches":null}` expectedTopology2 := ` { "node_id":1, "memory":0, "hugepages":null, "distances": null, "cores":[ { "core_id":1, "thread_ids":[ 1, 3 ], "caches":[ { "id": 0, "size":32768, "type":"unified", "level":0 } ], "socket_id": 1, "uncore_caches": null } ], "caches":null }` json1 := string(topologyJSON1) json2 := string(topologyJSON2) assert.JSONEq(t, expectedTopology1, json1) assert.JSONEq(t, expectedTopology2, json2) } func TestTopologyWithNodesWithoutCPU(t *testing.T) { machineArch = "" // overwrite package variable sysFs := &fakesysfs.FakeSysFs{} nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", "/fakeSysfs/devices/system/node/node1", } sysFs.SetNodesPaths(nodesPaths, nil) memTotal := "MemTotal: 32817192 kB" sysFs.SetMemory(memTotal, nil) hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, &fakesysfs.FileInfo{EntryName: "hugepages-1048576kB"}, } sysFs.SetHugePages(hugePages, nil) hugePageNr := map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node1/hugepages/hugepages-1048576kB/nr_hugepages": "1", } sysFs.SetHugePagesNr(hugePageNr, nil) sysFs.SetDistances("/fakeSysfs/devices/system/node/node0", "10 11", nil) sysFs.SetDistances("/fakeSysfs/devices/system/node/node1", "11 10", nil) topology, numCores, err := GetTopology(sysFs) assert.Nil(t, err) assert.Equal(t, 0, numCores) topologyJSON, err := json.Marshal(topology) assert.Nil(t, err) expectedTopology := `[ { "caches": null, "cores": null, "hugepages": [ { "num_pages": 1, "page_size": 2048 }, { "num_pages": 1, "page_size": 1048576 } ], "distances": [ 10, 11 ], "memory": 33604804608, "node_id": 0 }, { "caches": null, "cores": null, "hugepages": [ { "num_pages": 1, "page_size": 2048 }, { "num_pages": 1, "page_size": 1048576 } ], "distances": [ 11, 10 ], "memory": 33604804608, "node_id": 1 } ] ` assert.JSONEq(t, expectedTopology, string(topologyJSON)) } func TestTopologyOnSystemZ(t *testing.T) { if runtime.GOARCH != "s390x" { t.Skip("skipping TestTopologyOnSystemZ due to wrong architecture") } else { machineArch = "s390" // overwrite package variable sysFs := &fakesysfs.FakeSysFs{} c := sysfs.CacheInfo{ Id: 0, Size: 128 * 1024, Type: "Data", Level: 0, Cpus: 2, } sysFs.SetCacheInfo(c) nodesPaths := []string{} sysFs.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/sys/devices/system/cpu": { "/sys/devices/system/cpu/cpu0", "/sys/devices/system/cpu/cpu1", "/sys/devices/system/cpu/cpu2", "/sys/devices/system/cpu/cpu3", }, } sysFs.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/sys/devices/system/cpu/cpu0": "0", "/sys/devices/system/cpu/cpu1": "1", "/sys/devices/system/cpu/cpu2": "0", "/sys/devices/system/cpu/cpu3": "1", } sysFs.SetCoreThreads(coreThread, nil) physicalPackageIDs := map[string]string{ "/sys/devices/system/cpu/cpu0": "0", "/sys/devices/system/cpu/cpu1": "1", "/sys/devices/system/cpu/cpu2": "0", "/sys/devices/system/cpu/cpu3": "1", } sysFs.SetPhysicalPackageIDs(physicalPackageIDs, nil) bookIDs := map[string]string{ "/sys/devices/system/cpu/cpu0": "1", "/sys/devices/system/cpu/cpu1": "1", "/sys/devices/system/cpu/cpu2": "1", "/sys/devices/system/cpu/cpu3": "1", } sysFs.SetBookIDs(bookIDs, nil) drawerIDs := map[string]string{ "/sys/devices/system/cpu/cpu0": "0", "/sys/devices/system/cpu/cpu1": "0", "/sys/devices/system/cpu/cpu2": "0", "/sys/devices/system/cpu/cpu3": "0", } sysFs.SetDrawerIDs(drawerIDs, nil) topology, numCores, err := GetTopology(sysFs) assert.Nil(t, err) assert.Equal(t, 2, len(topology)) assert.Equal(t, 4, numCores) topologyJSON1, err := json.Marshal(topology[0]) assert.Nil(t, err) topologyJSON2, err := json.Marshal(topology[1]) assert.Nil(t, err) expectedTopology1 := `{"node_id":0,"memory":0,"hugepages":null,"distances":null,"cores":[{"core_id":0,"thread_ids":[0,2],"caches":[{"id":0, "size":131072,"type":"Data","level":0}], "socket_id": 0, "book_id":"1", "drawer_id":"0", "uncore_caches":null}],"caches":null}` expectedTopology2 := ` { "node_id":1, "memory":0, "hugepages":null, "distances": null, "cores":[ { "core_id":1, "thread_ids":[ 1, 3 ], "caches":[ { "id": 0, "size":131072, "type":"Data", "level":0 } ], "socket_id": 1, "book_id": "1", "drawer_id": "0", "uncore_caches": null } ], "caches":null }` json1 := string(topologyJSON1) json2 := string(topologyJSON2) assert.JSONEq(t, expectedTopology1, json1) assert.JSONEq(t, expectedTopology2, json2) } } func TestMemoryInfo(t *testing.T) { testPath := "./testdata/edac/mc" memory, err := GetMachineMemoryByType(testPath) assert.Nil(t, err) assert.Len(t, memory, 2) assert.Equal(t, uint64(789*1024*1024), memory["Unbuffered-DDR4"].Capacity) assert.Equal(t, uint64(579*1024*1024), memory["Non-volatile-RAM"].Capacity) assert.Equal(t, uint(1), memory["Unbuffered-DDR4"].DimmCount) assert.Equal(t, uint(2), memory["Non-volatile-RAM"].DimmCount) } func TestMemoryInfoOnArchThatDoNotExposeMemoryController(t *testing.T) { testPath := "./there/is/no/spoon" memory, err := GetMachineMemoryByType(testPath) assert.Nil(t, err) assert.Len(t, memory, 0) } func TestClockSpeedOnCpuUpperCase(t *testing.T) { maxFreqFile = "" // do not read the system max frequency machineArch = "" // overwrite package variable testfile := "./testdata/cpuinfo_upper_case" // mock cpuinfo with CPU MHz testcpuinfo, err := os.ReadFile(testfile) assert.Nil(t, err) assert.NotNil(t, testcpuinfo) clockSpeed, err := GetClockSpeed(testcpuinfo) assert.Nil(t, err) assert.NotNil(t, clockSpeed) assert.Equal(t, uint64(1800*1000), clockSpeed) } func TestClockSpeedOnCpuLowerCase(t *testing.T) { maxFreqFile = "" // do not read the system max frequency machineArch = "" // overwrite package variable testfile := "./testdata/cpuinfo_lower_case" // mock cpuinfo with cpu MHz testcpuinfo, err := os.ReadFile(testfile) assert.Nil(t, err) assert.NotNil(t, testcpuinfo) clockSpeed, err := GetClockSpeed(testcpuinfo) assert.Nil(t, err) assert.NotNil(t, clockSpeed) assert.Equal(t, uint64(1450*1000), clockSpeed) } func TestGetCPUVendorID(t *testing.T) { var testCases = []struct { file string expected string }{ { "./testdata/cpuinfo_onesocket_many_NUMAs", "GenuineIntel", }, { "./testdata/cpuinfo_arm", "", }, } for _, test := range testCases { testcpuinfo, err := os.ReadFile(test.file) assert.Nil(t, err) assert.NotNil(t, testcpuinfo) cpuVendorID := GetCPUVendorID(testcpuinfo) assert.Equal(t, test.expected, cpuVendorID) } } ================================================ FILE: manager/container.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package manager import ( "flag" "fmt" "math" "math/rand" "os" "os/exec" "path" "regexp" "sort" "strconv" "strings" "sync" "sync/atomic" "time" "github.com/google/cadvisor/cache/memory" "github.com/google/cadvisor/collector" "github.com/google/cadvisor/container" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" "github.com/google/cadvisor/stats" "github.com/google/cadvisor/summary" "github.com/google/cadvisor/utils/cpuload" "github.com/docker/go-units" "k8s.io/klog/v2" "k8s.io/utils/clock" ) // Housekeeping interval. var enableLoadReader = flag.Bool("enable_load_reader", false, "Whether to enable cpu load reader") var HousekeepingInterval = flag.Duration("housekeeping_interval", 1*time.Second, "Interval between container housekeepings") // TODO: replace regular expressions with something simpler, such as strings.Split(). // cgroup type chosen to fetch the cgroup path of a process. // Memory has been chosen, as it is one of the default cgroups that is enabled for most containers... var cgroupMemoryPathRegExp = regexp.MustCompile(`memory[^:]*:(.*?)[,;$]`) // ... but there are systems (e.g. Raspberry Pi 4) where memory cgroup controller is disabled by default. // We should check cpu cgroup then. var cgroupCPUPathRegExp = regexp.MustCompile(`cpu[^:]*:(.*?)[,;$]`) type containerInfo struct { info.ContainerReference Subcontainers []info.ContainerReference Spec info.ContainerSpec } // atomicTime is a lock-free wrapper for storing and retrieving time values. // It stores time as Unix nanoseconds in an atomic.Int64, enabling concurrent // reads and writes without mutex contention. type atomicTime struct { atomic.Int64 } // Time returns the stored time value as a time.Time. func (t *atomicTime) Time() time.Time { return time.Unix(0, t.Load()) } type containerData struct { oomEvents uint64 handler container.ContainerHandler info containerInfo memoryCache *memory.InMemoryCache lock sync.Mutex loadReader cpuload.CpuLoadReader summaryReader *summary.StatsSummary loadAvg float64 // smoothed load average seen so far. loadDAvg float64 // smoothed load.d average seen so far. housekeepingInterval time.Duration maxHousekeepingInterval time.Duration allowDynamicHousekeeping bool infoLastUpdatedTime atomicTime // Unix nano statsLastUpdatedTime atomicTime // Unix nano lastErrorTime time.Time // used to track time clock clock.Clock // Decay value used for load average smoothing. Interval length of 10 seconds is used. loadDecay float64 // Whether to log the usage of this container when it is updated. logUsage bool // Tells the container to stop. stop chan struct{} stopOnce sync.Once // Tells the container to immediately collect stats onDemandChan chan chan struct{} // Runs custom metric collectors. collectorManager collector.CollectorManager // perfCollector updates stats for perf_event cgroup controller. perfCollector stats.Collector // resctrlCollector updates stats for resctrl controller. resctrlCollector stats.Collector } // jitter returns a time.Duration between duration and duration + maxFactor * duration, // to allow clients to avoid converging on periodic behavior. If maxFactor is 0.0, a // suggested default value will be chosen. func jitter(duration time.Duration, maxFactor float64) time.Duration { if maxFactor <= 0.0 { maxFactor = 1.0 } wait := duration + time.Duration(rand.Float64()*maxFactor*float64(duration)) return wait } func (cd *containerData) Start() error { go cd.housekeeping() return nil } func (cd *containerData) Stop() error { err := cd.memoryCache.RemoveContainer(cd.info.Name) if err != nil { return err } // Use sync.Once to ensure the channel is only closed once, preventing // panic from concurrent calls to Stop() when multiple goroutines try // to destroy the same container simultaneously. cd.stopOnce.Do(func() { close(cd.stop) }) cd.perfCollector.Destroy() cd.resctrlCollector.Destroy() return nil } func (cd *containerData) allowErrorLogging() bool { if cd.clock.Since(cd.lastErrorTime) > time.Minute { cd.lastErrorTime = cd.clock.Now() return true } return false } // OnDemandHousekeeping performs housekeeping on the container and blocks until it has completed. // It is designed to be used in conjunction with periodic housekeeping, and will cause the timer for // periodic housekeeping to reset. This should be used sparingly, as calling OnDemandHousekeeping frequently // can have serious performance costs. func (cd *containerData) OnDemandHousekeeping(maxAge time.Duration) { timeSinceStatsLastUpdate := cd.clock.Since(cd.statsLastUpdatedTime.Time()) if timeSinceStatsLastUpdate > maxAge { housekeepingFinishedChan := make(chan struct{}) cd.onDemandChan <- housekeepingFinishedChan select { case <-cd.stop: case <-housekeepingFinishedChan: } } } // notifyOnDemand notifies all calls to OnDemandHousekeeping that housekeeping is finished func (cd *containerData) notifyOnDemand() { for { select { case finishedChan := <-cd.onDemandChan: close(finishedChan) default: return } } } func (cd *containerData) GetInfo(shouldUpdateSubcontainers bool) (*containerInfo, error) { // Get spec and subcontainers. if cd.clock.Since(cd.infoLastUpdatedTime.Time()) > 5*time.Second || shouldUpdateSubcontainers { err := cd.updateSpec() if err != nil { return nil, err } if shouldUpdateSubcontainers { err = cd.updateSubcontainers() if err != nil { return nil, err } } cd.infoLastUpdatedTime.Store(cd.clock.Now().UnixNano()) } cd.lock.Lock() defer cd.lock.Unlock() cInfo := containerInfo{ Subcontainers: cd.info.Subcontainers, Spec: cd.info.Spec, } cInfo.Id = cd.info.Id cInfo.Name = cd.info.Name cInfo.Aliases = cd.info.Aliases cInfo.Namespace = cd.info.Namespace return &cInfo, nil } func (cd *containerData) DerivedStats() (v2.DerivedStats, error) { if cd.summaryReader == nil { return v2.DerivedStats{}, fmt.Errorf("derived stats not enabled for container %q", cd.info.Name) } return cd.summaryReader.DerivedStats() } func (cd *containerData) getCgroupPath(cgroups string) string { if cgroups == "-" { return "/" } if strings.HasPrefix(cgroups, "0::") { return cgroups[3:] } matches := cgroupMemoryPathRegExp.FindSubmatch([]byte(cgroups)) if len(matches) != 2 { klog.V(3).Infof( "failed to get memory cgroup path from %q, will try to get cpu cgroup path", cgroups, ) // On some systems (e.g. Raspberry PI 4) cgroup memory controlled is disabled by default. matches = cgroupCPUPathRegExp.FindSubmatch([]byte(cgroups)) if len(matches) != 2 { klog.V(3).Infof("failed to get cpu cgroup path from %q; assuming root cgroup", cgroups) // return root in case of failures - memory hierarchy might not be enabled. return "/" } } return string(matches[1]) } // Returns contents of a file inside the container root. // Takes in a path relative to container root. func (cd *containerData) ReadFile(filepath string, inHostNamespace bool) ([]byte, error) { pids, err := cd.getContainerPids(inHostNamespace) if err != nil { return nil, err } // TODO(rjnagal): Optimize by just reading container's cgroup.proc file when in host namespace. rootfs := "/" if !inHostNamespace { rootfs = "/rootfs" } for _, pid := range pids { filePath := path.Join(rootfs, "/proc", pid, "/root", filepath) klog.V(3).Infof("Trying path %q", filePath) data, err := os.ReadFile(filePath) if err == nil { return data, err } } // No process paths could be found. Declare config non-existent. return nil, fmt.Errorf("file %q does not exist", filepath) } // Return output for ps command in host /proc with specified format func (cd *containerData) getPsOutput(inHostNamespace bool, format string) ([]byte, error) { args := []string{} command := "ps" if !inHostNamespace { command = "/usr/sbin/chroot" args = append(args, "/rootfs", "ps") } args = append(args, "-e", "-o", format) out, err := exec.Command(command, args...).Output() if err != nil { return nil, fmt.Errorf("failed to execute %q command: %v", command, err) } return out, err } // Get pids of processes in this container. // A slightly lighterweight call than GetProcessList if other details are not required. func (cd *containerData) getContainerPids(inHostNamespace bool) ([]string, error) { format := "pid,cgroup" out, err := cd.getPsOutput(inHostNamespace, format) if err != nil { return nil, err } expectedFields := 2 lines := strings.Split(string(out), "\n") pids := []string{} for _, line := range lines[1:] { if len(line) == 0 { continue } fields := strings.Fields(line) if len(fields) < expectedFields { return nil, fmt.Errorf("expected at least %d fields, found %d: output: %q", expectedFields, len(fields), line) } pid := fields[0] cgroup := cd.getCgroupPath(fields[1]) if cd.info.Name == cgroup { pids = append(pids, pid) } } return pids, nil } func (cd *containerData) GetProcessList(cadvisorContainer string, inHostNamespace bool) ([]v2.ProcessInfo, error) { format := "user,pid,ppid,stime,pcpu,pmem,rss,vsz,stat,time,comm,psr,cgroup" out, err := cd.getPsOutput(inHostNamespace, format) if err != nil { return nil, err } return cd.parseProcessList(cadvisorContainer, inHostNamespace, out) } func (cd *containerData) parseProcessList(cadvisorContainer string, inHostNamespace bool, out []byte) ([]v2.ProcessInfo, error) { rootfs := "/" if !inHostNamespace { rootfs = "/rootfs" } processes := []v2.ProcessInfo{} lines := strings.Split(string(out), "\n") for _, line := range lines[1:] { processInfo, err := cd.parsePsLine(line, cadvisorContainer, inHostNamespace) if err != nil { return nil, fmt.Errorf("could not parse line %s: %v", line, err) } if processInfo == nil { continue } var fdCount int dirPath := path.Join(rootfs, "/proc", strconv.Itoa(processInfo.Pid), "fd") fds, err := os.ReadDir(dirPath) if err != nil { klog.V(4).Infof("error while listing directory %q to measure fd count: %v", dirPath, err) continue } fdCount = len(fds) processInfo.FdCount = fdCount processes = append(processes, *processInfo) } return processes, nil } func (cd *containerData) isRoot() bool { return cd.info.Name == "/" } func (cd *containerData) parsePsLine(line, cadvisorContainer string, inHostNamespace bool) (*v2.ProcessInfo, error) { const expectedFields = 13 if len(line) == 0 { return nil, nil } info := v2.ProcessInfo{} var err error fields := strings.Fields(line) if len(fields) < expectedFields { return nil, fmt.Errorf("expected at least %d fields, found %d: output: %q", expectedFields, len(fields), line) } info.User = fields[0] info.StartTime = fields[3] info.Status = fields[8] info.RunningTime = fields[9] info.Pid, err = strconv.Atoi(fields[1]) if err != nil { return nil, fmt.Errorf("invalid pid %q: %v", fields[1], err) } info.Ppid, err = strconv.Atoi(fields[2]) if err != nil { return nil, fmt.Errorf("invalid ppid %q: %v", fields[2], err) } percentCPU, err := strconv.ParseFloat(fields[4], 32) if err != nil { return nil, fmt.Errorf("invalid cpu percent %q: %v", fields[4], err) } info.PercentCpu = float32(percentCPU) percentMem, err := strconv.ParseFloat(fields[5], 32) if err != nil { return nil, fmt.Errorf("invalid memory percent %q: %v", fields[5], err) } info.PercentMemory = float32(percentMem) info.RSS, err = strconv.ParseUint(fields[6], 0, 64) if err != nil { return nil, fmt.Errorf("invalid rss %q: %v", fields[6], err) } info.VirtualSize, err = strconv.ParseUint(fields[7], 0, 64) if err != nil { return nil, fmt.Errorf("invalid virtual size %q: %v", fields[7], err) } // convert to bytes info.RSS *= 1024 info.VirtualSize *= 1024 // According to `man ps`: The following user-defined format specifiers may contain spaces: args, cmd, comm, command, // fname, ucmd, ucomm, lstart, bsdstart, start. // Therefore we need to be able to parse comm that consists of multiple space-separated parts. info.Cmd = strings.Join(fields[10:len(fields)-2], " ") // These are last two parts of the line. We create a subslice of `fields` to handle comm that includes spaces. lastTwoFields := fields[len(fields)-2:] info.Psr, err = strconv.Atoi(lastTwoFields[0]) if err != nil { return nil, fmt.Errorf("invalid psr %q: %v", lastTwoFields[0], err) } info.CgroupPath = cd.getCgroupPath(lastTwoFields[1]) // Remove the ps command we just ran from cadvisor container. // Not necessary, but makes the cadvisor page look cleaner. if !inHostNamespace && cadvisorContainer == info.CgroupPath && info.Cmd == "ps" { return nil, nil } // Do not report processes from other containers when non-root container requested. if !cd.isRoot() && info.CgroupPath != cd.info.Name { return nil, nil } // Remove cgroup information when non-root container requested. if !cd.isRoot() { info.CgroupPath = "" } return &info, nil } func newContainerData(containerName string, memoryCache *memory.InMemoryCache, handler container.ContainerHandler, logUsage bool, collectorManager collector.CollectorManager, maxHousekeepingInterval time.Duration, allowDynamicHousekeeping bool, clock clock.Clock) (*containerData, error) { if memoryCache == nil { return nil, fmt.Errorf("nil memory storage") } if handler == nil { return nil, fmt.Errorf("nil container handler") } ref, err := handler.ContainerReference() if err != nil { return nil, err } cont := &containerData{ handler: handler, memoryCache: memoryCache, housekeepingInterval: *HousekeepingInterval, maxHousekeepingInterval: maxHousekeepingInterval, allowDynamicHousekeeping: allowDynamicHousekeeping, logUsage: logUsage, loadAvg: -1.0, // negative value indicates uninitialized. loadDAvg: -1.0, // negative value indicates uninitialized. stop: make(chan struct{}), collectorManager: collectorManager, onDemandChan: make(chan chan struct{}, 100), clock: clock, perfCollector: &stats.NoopCollector{}, resctrlCollector: &stats.NoopCollector{}, } cont.info.ContainerReference = ref cont.loadDecay = math.Exp(float64(-cont.housekeepingInterval.Seconds() / 10)) if *enableLoadReader { // Create cpu load reader. loadReader, err := cpuload.New() if err != nil { klog.Warningf("Could not initialize cpu load reader for %q: %s", ref.Name, err) } else { cont.loadReader = loadReader } } err = cont.updateSpec() if err != nil { return nil, err } cont.summaryReader, err = summary.New(cont.info.Spec) if err != nil { cont.summaryReader = nil klog.V(5).Infof("Failed to create summary reader for %q: %v", ref.Name, err) } return cont, nil } // Determine when the next housekeeping should occur. func (cd *containerData) nextHousekeepingInterval() time.Duration { if cd.allowDynamicHousekeeping { var empty time.Time stats, err := cd.memoryCache.RecentStats(cd.info.Name, empty, empty, 2) if err != nil { if cd.allowErrorLogging() { klog.V(4).Infof("Failed to get RecentStats(%q) while determining the next housekeeping: %v", cd.info.Name, err) } } else if len(stats) == 2 { // TODO(vishnuk): Use no processes as a signal. // Raise the interval if usage hasn't changed in the last housekeeping. if stats[0].StatsEq(stats[1]) && (cd.housekeepingInterval < cd.maxHousekeepingInterval) { cd.housekeepingInterval *= 2 if cd.housekeepingInterval > cd.maxHousekeepingInterval { cd.housekeepingInterval = cd.maxHousekeepingInterval } } else if cd.housekeepingInterval != *HousekeepingInterval { // Lower interval back to the baseline. cd.housekeepingInterval = *HousekeepingInterval } } } return jitter(cd.housekeepingInterval, 1.0) } // TODO(vmarmol): Implement stats collecting as a custom collector. func (cd *containerData) housekeeping() { // Start any background goroutines - must be cleaned up in cd.handler.Cleanup(). cd.handler.Start() defer cd.handler.Cleanup() // Initialize cpuload reader - must be cleaned up in cd.loadReader.Stop() if cd.loadReader != nil { err := cd.loadReader.Start() if err != nil { klog.Warningf("Could not start cpu load stat collector for %q: %s", cd.info.Name, err) } defer cd.loadReader.Stop() } // Long housekeeping is either 100ms or half of the housekeeping interval. longHousekeeping := 100 * time.Millisecond if *HousekeepingInterval/2 < longHousekeeping { longHousekeeping = *HousekeepingInterval / 2 } // Housekeep every second. klog.V(3).Infof("Start housekeeping for container %q\n", cd.info.Name) houseKeepingTimer := cd.clock.NewTimer(0 * time.Second) defer houseKeepingTimer.Stop() for { if !cd.housekeepingTick(houseKeepingTimer.C(), longHousekeeping) { return } // Stop and drain the timer so that it is safe to reset it if !houseKeepingTimer.Stop() { select { case <-houseKeepingTimer.C(): default: } } // Log usage if asked to do so. if cd.logUsage { const numSamples = 60 var empty time.Time stats, err := cd.memoryCache.RecentStats(cd.info.Name, empty, empty, numSamples) if err != nil { if cd.allowErrorLogging() { klog.Warningf("[%s] Failed to get recent stats for logging usage: %v", cd.info.Name, err) } } else if len(stats) < numSamples { // Ignore, not enough stats yet. } else { usageCPUNs := uint64(0) for i := range stats { if i > 0 { usageCPUNs += stats[i].Cpu.Usage.Total - stats[i-1].Cpu.Usage.Total } } usageMemory := stats[numSamples-1].Memory.Usage instantUsageInCores := float64(stats[numSamples-1].Cpu.Usage.Total-stats[numSamples-2].Cpu.Usage.Total) / float64(stats[numSamples-1].Timestamp.Sub(stats[numSamples-2].Timestamp).Nanoseconds()) usageInCores := float64(usageCPUNs) / float64(stats[numSamples-1].Timestamp.Sub(stats[0].Timestamp).Nanoseconds()) usageInHuman := units.HumanSize(float64(usageMemory)) // Don't set verbosity since this is already protected by the logUsage flag. klog.Infof("[%s] %.3f cores (average: %.3f cores), %s of memory", cd.info.Name, instantUsageInCores, usageInCores, usageInHuman) } } houseKeepingTimer.Reset(cd.nextHousekeepingInterval()) } } func (cd *containerData) housekeepingTick(timer <-chan time.Time, longHousekeeping time.Duration) bool { select { case <-cd.stop: // Stop housekeeping when signaled. return false case finishedChan := <-cd.onDemandChan: // notify the calling function once housekeeping has completed defer close(finishedChan) case <-timer: } start := cd.clock.Now() err := cd.updateStats() if err != nil { if cd.allowErrorLogging() { klog.Warningf("Failed to update stats for container \"%s\": %s", cd.info.Name, err) } } // Log if housekeeping took too long. duration := cd.clock.Since(start) if duration >= longHousekeeping { klog.V(3).Infof("[%s] Housekeeping took %s", cd.info.Name, duration) } cd.notifyOnDemand() cd.statsLastUpdatedTime.Store(cd.clock.Now().UnixNano()) return true } func (cd *containerData) updateSpec() error { spec, err := cd.handler.GetSpec() if err != nil { // Ignore errors if the container is dead. if !cd.handler.Exists() { return nil } return err } customMetrics, err := cd.collectorManager.GetSpec() if err != nil { return err } if len(customMetrics) > 0 { spec.HasCustomMetrics = true spec.CustomMetrics = customMetrics } cd.lock.Lock() defer cd.lock.Unlock() cd.info.Spec = spec return nil } // Calculate new smoothed load average using the new sample of runnable threads. // The decay used ensures that the load will stabilize on a new constant value within // 10 seconds. func (cd *containerData) updateLoad(newLoad uint64) { if cd.loadAvg < 0 { cd.loadAvg = float64(newLoad) // initialize to the first seen sample for faster stabilization. } else { cd.loadAvg = cd.loadAvg*cd.loadDecay + float64(newLoad)*(1.0-cd.loadDecay) } } func (cd *containerData) updateLoadD(newLoad uint64) { if cd.loadDAvg < 0 { cd.loadDAvg = float64(newLoad) // initialize to the first seen sample for faster stabilization. } else { cd.loadDAvg = cd.loadDAvg*cd.loadDecay + float64(newLoad)*(1.0-cd.loadDecay) } } func (cd *containerData) updateStats() error { stats, statsErr := cd.handler.GetStats() if statsErr != nil { // Ignore errors if the container is dead. if !cd.handler.Exists() { return nil } // Stats may be partially populated, push those before we return an error. statsErr = fmt.Errorf("%v, continuing to push stats", statsErr) } if stats == nil { return statsErr } if cd.loadReader != nil { // TODO(vmarmol): Cache this path. path, err := cd.handler.GetCgroupPath("cpu") if err == nil { loadStats, err := cd.loadReader.GetCpuLoad(cd.info.Name, path) if err != nil { return fmt.Errorf("failed to get load stat for %q - path %q, error %s", cd.info.Name, path, err) } stats.TaskStats = loadStats cd.updateLoad(loadStats.NrRunning) // convert to 'milliLoad' to avoid floats and preserve precision. stats.Cpu.LoadAverage = int32(cd.loadAvg * 1000) cd.updateLoadD(loadStats.NrUninterruptible) // convert to 'milliLoad' to avoid floats and preserve precision. stats.Cpu.LoadDAverage = int32(cd.loadDAvg * 1000) } } if cd.summaryReader != nil { err := cd.summaryReader.AddSample(*stats) if err != nil { // Ignore summary errors for now. klog.V(2).Infof("Failed to add summary stats for %q: %v", cd.info.Name, err) } } stats.OOMEvents = atomic.LoadUint64(&cd.oomEvents) var customStatsErr error cm := cd.collectorManager.(*collector.GenericCollectorManager) if len(cm.Collectors) > 0 { if cm.NextCollectionTime.Before(cd.clock.Now()) { customStats, err := cd.updateCustomStats() if customStats != nil { stats.CustomMetrics = customStats } if err != nil { customStatsErr = err } } } perfStatsErr := cd.perfCollector.UpdateStats(stats) resctrlStatsErr := cd.resctrlCollector.UpdateStats(stats) ref, err := cd.handler.ContainerReference() if err != nil { // Ignore errors if the container is dead. if !cd.handler.Exists() { return nil } return err } cInfo := info.ContainerInfo{ ContainerReference: ref, } err = cd.memoryCache.AddStats(&cInfo, stats) if err != nil { return err } if statsErr != nil { return statsErr } if perfStatsErr != nil { klog.Errorf("error occurred while collecting perf stats for container %s: %s", cInfo.Name, perfStatsErr) return perfStatsErr } if resctrlStatsErr != nil { klog.Errorf("error occurred while collecting resctrl stats for container %s: %s", cInfo.Name, resctrlStatsErr) return resctrlStatsErr } return customStatsErr } func (cd *containerData) updateCustomStats() (map[string][]info.MetricVal, error) { _, customStats, customStatsErr := cd.collectorManager.Collect() if customStatsErr != nil { if !cd.handler.Exists() { return customStats, nil } customStatsErr = fmt.Errorf("%v, continuing to push custom stats", customStatsErr) } return customStats, customStatsErr } func (cd *containerData) updateSubcontainers() error { var subcontainers info.ContainerReferenceSlice subcontainers, err := cd.handler.ListContainers(container.ListSelf) if err != nil { // Ignore errors if the container is dead. if !cd.handler.Exists() { return nil } return err } sort.Sort(subcontainers) cd.lock.Lock() defer cd.lock.Unlock() cd.info.Subcontainers = subcontainers return nil } ================================================ FILE: manager/container_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Per-container manager. package manager import ( "fmt" "reflect" "sync" "testing" "time" "github.com/google/cadvisor/cache/memory" "github.com/google/cadvisor/collector" "github.com/google/cadvisor/container" containertest "github.com/google/cadvisor/container/testing" info "github.com/google/cadvisor/info/v1" itest "github.com/google/cadvisor/info/v1/test" v2 "github.com/google/cadvisor/info/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" clock "k8s.io/utils/clock/testing" ) const ( containerName = "/container" testLongHousekeeping = time.Second ) // Create a containerData instance for a test. func setupContainerData(t *testing.T, spec info.ContainerSpec) (*containerData, *containertest.MockContainerHandler, *memory.InMemoryCache, *clock.FakeClock) { mockHandler := containertest.NewMockContainerHandler(containerName) mockHandler.On("GetSpec").Return( spec, nil, ) memoryCache := memory.New(60, nil) fakeClock := clock.NewFakeClock(time.Now()) ret, err := newContainerData(containerName, memoryCache, mockHandler, false, &collector.GenericCollectorManager{}, 60*time.Second, true, fakeClock) if err != nil { t.Fatal(err) } return ret, mockHandler, memoryCache, fakeClock } // Create a containerData instance for a test and add a default GetSpec mock. func newTestContainerData(t *testing.T) (*containerData, *containertest.MockContainerHandler, *memory.InMemoryCache, *clock.FakeClock) { return setupContainerData(t, itest.GenerateRandomContainerSpec(4)) } func TestUpdateSubcontainers(t *testing.T) { subcontainers := []info.ContainerReference{ {Name: "/container/ee0103"}, {Name: "/container/abcd"}, {Name: "/container/something"}, } cd, mockHandler, _, _ := newTestContainerData(t) mockHandler.On("ListContainers", container.ListSelf).Return( subcontainers, nil, ) err := cd.updateSubcontainers() if err != nil { t.Fatal(err) } if len(cd.info.Subcontainers) != len(subcontainers) { t.Errorf("Received %v subcontainers, should be %v", len(cd.info.Subcontainers), len(subcontainers)) } for _, sub := range cd.info.Subcontainers { found := false for _, sub2 := range subcontainers { if sub.Name == sub2.Name { found = true } } if !found { t.Errorf("Received unknown sub container %v", sub) } } mockHandler.AssertExpectations(t) } func TestUpdateSubcontainersWithError(t *testing.T) { cd, mockHandler, _, _ := newTestContainerData(t) mockHandler.On("ListContainers", container.ListSelf).Return( []info.ContainerReference{}, fmt.Errorf("some error"), ) mockHandler.On("Exists").Return(true) assert.NotNil(t, cd.updateSubcontainers()) assert.Empty(t, cd.info.Subcontainers, "subcontainers should not be populated on failure") mockHandler.AssertExpectations(t) } func TestUpdateSubcontainersWithErrorOnDeadContainer(t *testing.T) { cd, mockHandler, _, _ := newTestContainerData(t) mockHandler.On("ListContainers", container.ListSelf).Return( []info.ContainerReference{}, fmt.Errorf("some error"), ) mockHandler.On("Exists").Return(false) assert.Nil(t, cd.updateSubcontainers()) mockHandler.AssertExpectations(t) } func checkNumStats(t *testing.T, memoryCache *memory.InMemoryCache, numStats int) { var empty time.Time stats, err := memoryCache.RecentStats(containerName, empty, empty, -1) require.Nil(t, err) assert.Len(t, stats, numStats) } func TestUpdateStats(t *testing.T) { statsList := itest.GenerateRandomStats(1, 4, 1*time.Second) stats := statsList[0] cd, mockHandler, memoryCache, _ := newTestContainerData(t) mockHandler.On("GetStats").Return( stats, nil, ) err := cd.updateStats() if err != nil { t.Fatal(err) } checkNumStats(t, memoryCache, 1) mockHandler.AssertExpectations(t) } func TestUpdateSpec(t *testing.T) { spec := itest.GenerateRandomContainerSpec(4) cd, mockHandler, _, _ := newTestContainerData(t) mockHandler.On("GetSpec").Return( spec, nil, ) err := cd.updateSpec() if err != nil { t.Fatal(err) } mockHandler.AssertExpectations(t) } func TestGetInfo(t *testing.T) { spec := itest.GenerateRandomContainerSpec(4) subcontainers := []info.ContainerReference{ {Name: "/container/ee0103"}, {Name: "/container/abcd"}, {Name: "/container/something"}, } cd, mockHandler, _, _ := setupContainerData(t, spec) mockHandler.On("ListContainers", container.ListSelf).Return( subcontainers, nil, ) mockHandler.Aliases = []string{"a1", "a2"} info, err := cd.GetInfo(true) if err != nil { t.Fatal(err) } mockHandler.AssertExpectations(t) if len(info.Subcontainers) != len(subcontainers) { t.Errorf("Received %v subcontainers, should be %v", len(info.Subcontainers), len(subcontainers)) } for _, sub := range info.Subcontainers { found := false for _, sub2 := range subcontainers { if sub.Name == sub2.Name { found = true } } if !found { t.Errorf("Received unknown sub container %v", sub) } } if !reflect.DeepEqual(spec, info.Spec) { t.Errorf("received wrong container spec") } if info.Name != mockHandler.Name { t.Errorf("received wrong container name: received %v; should be %v", info.Name, mockHandler.Name) } } func TestOnDemandHousekeeping(t *testing.T) { statsList := itest.GenerateRandomStats(1, 4, 1*time.Second) stats := statsList[0] cd, mockHandler, memoryCache, fakeClock := newTestContainerData(t) mockHandler.On("GetStats").Return(stats, nil) defer func() { err := cd.Stop() assert.NoError(t, err) }() // 0 seconds should always trigger an update go cd.OnDemandHousekeeping(0 * time.Second) cd.housekeepingTick(fakeClock.NewTimer(time.Minute).C(), testLongHousekeeping) fakeClock.Step(2 * time.Second) // This should return without requiring a housekeepingTick because stats have been updated recently enough cd.OnDemandHousekeeping(3 * time.Second) go cd.OnDemandHousekeeping(1 * time.Second) cd.housekeepingTick(fakeClock.NewTimer(time.Minute).C(), testLongHousekeeping) checkNumStats(t, memoryCache, 2) mockHandler.AssertExpectations(t) } func TestConcurrentOnDemandHousekeeping(t *testing.T) { statsList := itest.GenerateRandomStats(1, 4, 1*time.Second) stats := statsList[0] cd, mockHandler, memoryCache, fakeClock := newTestContainerData(t) mockHandler.On("GetStats").Return(stats, nil) defer func() { err := cd.Stop() assert.NoError(t, err) }() numConcurrentCalls := 5 var waitForHousekeeping sync.WaitGroup waitForHousekeeping.Add(numConcurrentCalls) onDemandCache := []chan struct{}{} for i := 0; i < numConcurrentCalls; i++ { go func() { cd.OnDemandHousekeeping(0 * time.Second) waitForHousekeeping.Done() }() // Wait for work to be queued onDemandCache = append(onDemandCache, <-cd.onDemandChan) } // Requeue work: for _, ch := range onDemandCache { cd.onDemandChan <- ch } go cd.housekeepingTick(fakeClock.NewTimer(time.Minute).C(), testLongHousekeeping) // Ensure that all queued calls return with only a single call to housekeepingTick waitForHousekeeping.Wait() checkNumStats(t, memoryCache, 1) mockHandler.AssertExpectations(t) } func TestOnDemandHousekeepingReturnsAfterStopped(t *testing.T) { statsList := itest.GenerateRandomStats(1, 4, 1*time.Second) stats := statsList[0] cd, mockHandler, memoryCache, fakeClock := newTestContainerData(t) mockHandler.On("GetStats").Return(stats, nil) // trigger housekeeping update go cd.OnDemandHousekeeping(0 * time.Second) cd.housekeepingTick(fakeClock.NewTimer(time.Minute).C(), testLongHousekeeping) checkNumStats(t, memoryCache, 1) fakeClock.Step(2 * time.Second) err := cd.Stop() assert.NoError(t, err) // housekeeping tick should detect stop and not store any more metrics assert.False(t, cd.housekeepingTick(fakeClock.NewTimer(time.Minute).C(), testLongHousekeeping)) fakeClock.Step(1 * time.Second) // on demand housekeeping should not block and return cd.OnDemandHousekeeping(-1 * time.Second) mockHandler.AssertExpectations(t) } func TestOnDemandHousekeepingRace(t *testing.T) { statsList := itest.GenerateRandomStats(1, 4, 1*time.Second) stats := statsList[0] cd, mockHandler, _, _ := newTestContainerData(t) mockHandler.On("GetStats").Return(stats, nil) wg := sync.WaitGroup{} wg.Add(1002) go func() { time.Sleep(10 * time.Millisecond) err := cd.Start() assert.NoError(t, err) wg.Done() }() go func() { t.Log("starting on demand goroutine") for i := 0; i < 1000; i++ { go func() { time.Sleep(1 * time.Microsecond) cd.OnDemandHousekeeping(0 * time.Millisecond) wg.Done() }() } wg.Done() }() wg.Wait() } var psOutput = [][]byte{ []byte("root 15886 2 23:51 0.1 0.0 0 0 I 00:00:00 kworker/u8:3-ev 3 -\nroot 15887 2 23:51 0.0 0.0 0 0 I< 00:00:00 kworker/1:2H 1 -\nubuntu 15888 1804 23:51 0.0 0.0 2832 10176 R+ 00:00:00 ps 1 8:devices:/user.slice,6:pids:/user.slice/user-1000.slice/session-3.scope,5:blkio:/user.slice,2:cpu,cpuacct:/user.slice,1:na"), []byte("root 104 2 21:34 0.0 0.0 0 0 I< 00:00:00 kthrotld 3 -\nroot 105 2 21:34 0.0 0.0 0 0 S 00:00:00 irq/41-aerdrv 0 -\nroot 107 2 21:34 0.0 0.0 0 0 I< 00:00:00 DWC Notificatio 3 -\nroot 109 2 21:34 0.0 0.0 0 0 S< 00:00:00 vchiq-slot/0 1 -\nroot 110 2 21:34 0.0 0.0 0 0 S< 00:00:00 vchiq-recy/0 3 -"), } func TestParseProcessList(t *testing.T) { for i, ps := range psOutput { t.Run(fmt.Sprintf("iteration %d", i), func(tt *testing.T) { cd := &containerData{} _, err := cd.parseProcessList("/", true, ps) // checking *only* parsing errors - otherwise /proc would have to be emulated. assert.NoError(tt, err) }) } } var psLine = []struct { name string line string cadvisorContainer string isHostNamespace bool process *v2.ProcessInfo err error cd *containerData }{ { name: "plain process with cgroup", line: "ubuntu 15888 1804 23:51 0.1 0.0 2832 10176 R+ 00:10:00 cadvisor 1 10:cpuset:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,9:devices:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,8:pids:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,7:memory:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,6:freezer:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,5:perf_event:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,4:blkio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,3:cpu,cpuacct:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,2:net_cls,net_prio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,1:name=systemd:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", cadvisorContainer: "/docker/cadvisor", isHostNamespace: true, process: &v2.ProcessInfo{ User: "ubuntu", Pid: 15888, Ppid: 1804, StartTime: "23:51", PercentCpu: 0.1, PercentMemory: 0.0, RSS: 2899968, VirtualSize: 10420224, Status: "R+", RunningTime: "00:10:00", CgroupPath: "/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", Cmd: "cadvisor", Psr: 1, }, cd: &containerData{ info: containerInfo{ContainerReference: info.ContainerReference{Name: "/"}}, }, }, { name: "process with space in name and no cgroup", line: "root 107 2 21:34 0.0 0.1 3 4 I< 00:20:00 DWC Notificatio 3 -", cadvisorContainer: "/docker/cadvisor", process: &v2.ProcessInfo{ User: "root", Pid: 107, Ppid: 2, StartTime: "21:34", PercentCpu: 0.0, PercentMemory: 0.1, RSS: 3072, VirtualSize: 4096, Status: "I<", RunningTime: "00:20:00", CgroupPath: "/", Cmd: "DWC Notificatio", Psr: 3, }, cd: &containerData{ info: containerInfo{ContainerReference: info.ContainerReference{Name: "/"}}, }, }, { name: "process with highly unusual name (one 2 three 4 five 6 eleven), cgroup to be ignored", line: "root 107 2 21:34 0.0 0.1 3 4 I< 00:20:00 one 2 three 4 five 6 eleven 3 10:cpuset:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,9:devices:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,8:pids:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,7:memory:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,6:freezer:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,5:perf_event:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,4:blkio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,3:cpu,cpuacct:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,2:net_cls,net_prio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,1:name=systemd:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", cadvisorContainer: "/docker/cadvisor", isHostNamespace: true, process: &v2.ProcessInfo{ User: "root", Pid: 107, Ppid: 2, StartTime: "21:34", PercentCpu: 0.0, PercentMemory: 0.1, RSS: 3072, VirtualSize: 4096, Status: "I<", RunningTime: "00:20:00", Cmd: "one 2 three 4 five 6 eleven", Psr: 3, CgroupPath: "/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", }, cd: &containerData{ info: containerInfo{ContainerReference: info.ContainerReference{Name: "/"}}, }, }, { name: "wrong field count", line: "ps output it is not", cadvisorContainer: "/docker/cadvisor", err: fmt.Errorf("expected at least 13 fields, found 5: output: \"ps output it is not\""), cd: &containerData{}, }, { name: "ps running in cadvisor container should be ignored", line: "root 107 2 21:34 0.0 0.1 3 4 I< 00:20:00 ps 3 10:cpuset:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,9:devices:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,8:pids:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,7:memory:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,6:freezer:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,5:perf_event:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,4:blkio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,3:cpu,cpuacct:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,2:net_cls,net_prio:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831,1:name=systemd:/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", cadvisorContainer: "/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", cd: &containerData{ info: containerInfo{ContainerReference: info.ContainerReference{Name: "/"}}, }, }, { name: "non-root container but process belongs to the container", line: "root 107 2 21:34 0.0 0.1 3 4 I< 00:20:00 sleep inf 3 10:cpuset:/docker/some-random-container,9:devices:/docker/some-random-container,8:pids:/docker/some-random-container,7:memory:/docker/some-random-container,6:freezer:/docker/some-random-container,5:perf_event:/docker/some-random-container,4:blkio:/docker/some-random-container,3:cpu,cpuacct:/docker/some-random-container,2:net_cls,net_prio:/docker/some-random-container,1:name=systemd:/docker/some-random-container", process: &v2.ProcessInfo{ User: "root", Pid: 107, Ppid: 2, StartTime: "21:34", PercentCpu: 0.0, PercentMemory: 0.1, RSS: 3072, VirtualSize: 4096, Status: "I<", RunningTime: "00:20:00", Cmd: "sleep inf", Psr: 3, }, cadvisorContainer: "/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", cd: &containerData{ info: containerInfo{ContainerReference: info.ContainerReference{Name: "/docker/some-random-container"}}, }, }, { name: "non-root container and process belonging to another container", line: "root 107 2 21:34 0.0 0.1 3 4 I< 00:20:00 sleep inf 3 10:cpuset:/docker/some-random-container,9:devices:/docker/some-random-container,8:pids:/docker/some-random-container,7:memory:/docker/some-random-container,6:freezer:/docker/some-random-container,5:perf_event:/docker/some-random-container,4:blkio:/docker/some-random-container,3:cpu,cpuacct:/docker/some-random-container,2:net_cls,net_prio:/docker/some-random-container,1:name=systemd:/docker/some-random-container", cadvisorContainer: "/docker/dd479c33249f6c3f0f1189aa88f07dad3eeb3e6fedfc71385c27ddd699994831", cd: &containerData{ info: containerInfo{ContainerReference: info.ContainerReference{Name: "/docker/some-other-container"}}, }, }, } func TestParsePsLine(t *testing.T) { for _, ps := range psLine { t.Run(ps.name, func(tt *testing.T) { process, err := ps.cd.parsePsLine(ps.line, ps.cadvisorContainer, ps.isHostNamespace) assert.Equal(tt, ps.err, err) assert.EqualValues(tt, ps.process, process) }) } } var cgroupCases = []struct { name string cgroups string path string }{ { name: "no cgroup", cgroups: "-", path: "/", }, { name: "random and meaningless string", cgroups: "/this/is/a/path/to/some.file", path: "/", }, { name: "0::-type cgroup", cgroups: "0::/docker/some-cgroup", path: "/docker/some-cgroup", }, { name: "memory cgroup", cgroups: "4:memory:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", }, { name: "cpu,cpuacct cgroup", cgroups: "4:cpu,cpuacct:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", }, { name: "cpu cgroup", cgroups: "4:cpu:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", }, { name: "cpuacct cgroup", cgroups: "4:cpuacct:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6,2:net_cls:/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", path: "/docker/09c89cd48b3597db904ab8e6920fef2cbf93588d037d9613ce362e25188f8ec6", }, } func TestGetCgroupPath(t *testing.T) { for _, cgroup := range cgroupCases { t.Run(cgroup.name, func(tt *testing.T) { cd := &containerData{} path := cd.getCgroupPath(cgroup.cgroups) assert.Equal(t, cgroup.path, path) }) } } ================================================ FILE: manager/manager.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Manager of cAdvisor-monitored containers. package manager import ( "flag" "fmt" "net/http" "os" "path" "strconv" "strings" "sync" "sync/atomic" "time" "github.com/google/cadvisor/cache/memory" "github.com/google/cadvisor/collector" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/raw" "github.com/google/cadvisor/events" "github.com/google/cadvisor/fs" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" "github.com/google/cadvisor/machine" "github.com/google/cadvisor/nvm" "github.com/google/cadvisor/perf" "github.com/google/cadvisor/resctrl" "github.com/google/cadvisor/stats" "github.com/google/cadvisor/utils/oomparser" "github.com/google/cadvisor/utils/sysfs" "github.com/google/cadvisor/version" "github.com/google/cadvisor/watcher" "github.com/opencontainers/cgroups" "k8s.io/klog/v2" "k8s.io/utils/clock" ) var globalHousekeepingInterval = flag.Duration("global_housekeeping_interval", 1*time.Minute, "Interval between global housekeepings") var updateMachineInfoInterval = flag.Duration("update_machine_info_interval", 5*time.Minute, "Interval between machine info updates.") var logCadvisorUsage = flag.Bool("log_cadvisor_usage", false, "Whether to log the usage of the cAdvisor container") var eventStorageAgeLimit = flag.String("event_storage_age_limit", "default=24h", "Max length of time for which to store events (per type). Value is a comma separated list of key values, where the keys are event types (e.g.: creation, oom) or \"default\" and the value is a duration. Default is applied to all non-specified event types") var eventStorageEventLimit = flag.String("event_storage_event_limit", "default=100000", "Max number of events to store (per type). Value is a comma separated list of key values, where the keys are event types (e.g.: creation, oom) or \"default\" and the value is an integer. Default is applied to all non-specified event types") var applicationMetricsCountLimit = flag.Int("application_metrics_count_limit", 100, "Max number of application metrics to store (per container)") // The namespace under which aliases are unique. const ( DockerNamespace = "docker" PodmanNamespace = "podman" ) var HousekeepingConfigFlags = HousekeepingConfig{ flag.Duration("max_housekeeping_interval", 60*time.Second, "Largest interval to allow between container housekeepings"), flag.Bool("allow_dynamic_housekeeping", true, "Whether to allow the housekeeping interval to be dynamic"), } // The Manager interface defines operations for starting a manager and getting // container and machine information. type Manager interface { // Start the manager. Calling other manager methods before this returns // may produce undefined behavior. Start() error // Stops the manager. Stop() error // information about a container. GetContainerInfo(containerName string, query *info.ContainerInfoRequest) (*info.ContainerInfo, error) // Get V2 information about a container. // Recursive (subcontainer) requests are best-effort, and may return a partial result alongside an // error in the partial failure case. GetContainerInfoV2(containerName string, options v2.RequestOptions) (map[string]v2.ContainerInfo, error) // Get information about all subcontainers of the specified container (includes self). SubcontainersInfo(containerName string, query *info.ContainerInfoRequest) ([]*info.ContainerInfo, error) // Gets all the Docker containers. Return is a map from full container name to ContainerInfo. AllDockerContainers(query *info.ContainerInfoRequest) (map[string]info.ContainerInfo, error) // Gets information about a specific Docker container. The specified name is within the Docker namespace. DockerContainer(dockerName string, query *info.ContainerInfoRequest) (info.ContainerInfo, error) // Gets spec for all containers based on request options. GetContainerSpec(containerName string, options v2.RequestOptions) (map[string]v2.ContainerSpec, error) // Gets summary stats for all containers based on request options. GetDerivedStats(containerName string, options v2.RequestOptions) (map[string]v2.DerivedStats, error) // Get info for all requested containers based on the request options. GetRequestedContainersInfo(containerName string, options v2.RequestOptions) (map[string]*info.ContainerInfo, error) // Returns true if the named container exists. Exists(containerName string) bool // Get information about the machine. GetMachineInfo() (*info.MachineInfo, error) // Get version information about different components we depend on. GetVersionInfo() (*info.VersionInfo, error) // GetFsInfoByFsUUID returns the information of the device having the // specified filesystem uuid. If no such device with the UUID exists, this // function will return the fs.ErrNoSuchDevice error. GetFsInfoByFsUUID(uuid string) (v2.FsInfo, error) // Get filesystem information for the filesystem that contains the given directory GetDirFsInfo(dir string) (v2.FsInfo, error) // Get filesystem information for a given label. // Returns information for all global filesystems if label is empty. GetFsInfo(label string) ([]v2.FsInfo, error) // Get ps output for a container. GetProcessList(containerName string, options v2.RequestOptions) ([]v2.ProcessInfo, error) // Get events streamed through passedChannel that fit the request. WatchForEvents(request *events.Request) (*events.EventChannel, error) // Get past events that have been detected and that fit the request. GetPastEvents(request *events.Request) ([]*info.Event, error) CloseEventChannel(watchID int) // Returns debugging information. Map of lines per category. DebugInfo() map[string][]string AllPodmanContainers(c *info.ContainerInfoRequest) (map[string]info.ContainerInfo, error) PodmanContainer(containerName string, query *info.ContainerInfoRequest) (info.ContainerInfo, error) } // Housekeeping configuration for the manager type HousekeepingConfig = struct { Interval *time.Duration AllowDynamic *bool } // New takes a memory storage and returns a new manager. func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, HousekeepingConfig HousekeepingConfig, includedMetricsSet container.MetricSet, collectorHTTPClient *http.Client, rawContainerCgroupPathPrefixWhiteList, containerEnvMetadataWhiteList []string, perfEventsFile string, resctrlInterval time.Duration) (Manager, error) { if memoryCache == nil { return nil, fmt.Errorf("manager requires memory storage") } // Detect the container we are running on. selfContainer := "/" var err error // Avoid using GetOwnCgroupPath on cgroup v2 as it is not supported by libcontainer if !cgroups.IsCgroup2UnifiedMode() { selfContainer, err = cgroups.GetOwnCgroup("cpu") if err != nil { return nil, err } klog.V(2).Infof("cAdvisor running in container: %q", selfContainer) } context := fs.Context{} if err := container.InitializeFSContext(&context); err != nil { return nil, err } fsInfo, err := fs.NewFsInfo(context) if err != nil { return nil, err } // If cAdvisor was started with host's rootfs mounted, assume that its running // in its own namespaces. inHostNamespace := false if _, err := os.Stat("/rootfs/proc"); os.IsNotExist(err) { inHostNamespace = true } // Register for new subcontainers. eventsChannel := make(chan watcher.ContainerEvent, 16) newManager := &manager{ quitChannels: make([]chan error, 0, 2), memoryCache: memoryCache, fsInfo: fsInfo, sysFs: sysfs, cadvisorContainer: selfContainer, inHostNamespace: inHostNamespace, startupTime: time.Now(), maxHousekeepingInterval: *HousekeepingConfig.Interval, allowDynamicHousekeeping: *HousekeepingConfig.AllowDynamic, includedMetrics: includedMetricsSet, containerWatchers: []watcher.ContainerWatcher{}, eventsChannel: eventsChannel, collectorHTTPClient: collectorHTTPClient, rawContainerCgroupPathPrefixWhiteList: rawContainerCgroupPathPrefixWhiteList, containerEnvMetadataWhiteList: containerEnvMetadataWhiteList, } machineInfo, err := machine.Info(sysfs, fsInfo, inHostNamespace) if err != nil { return nil, err } newManager.machineInfo = *machineInfo klog.V(1).Infof("Machine: %+v", newManager.machineInfo) newManager.perfManager, err = perf.NewManager(perfEventsFile, machineInfo.Topology) if err != nil { return nil, err } newManager.resctrlManager, err = resctrl.NewManager(resctrlInterval, machineInfo.CPUVendorID, inHostNamespace) if err != nil { klog.V(4).Infof("Cannot gather resctrl metrics: %v", err) } versionInfo, err := getVersionInfo() if err != nil { return nil, err } klog.V(1).Infof("Version: %+v", *versionInfo) newManager.eventHandler = events.NewEventManager(parseEventsStoragePolicy()) return newManager, nil } // A namespaced container name. type namespacedContainerName struct { // The namespace of the container. Can be empty for the root namespace. Namespace string // The name of the container in this namespace. Name string } // containerMap is a type-safe wrapper around sync.Map for storing containerData // keyed by namespacedContainerName. type containerMap struct { m sync.Map } // Load returns the containerData for the given name, or nil if not found. func (c *containerMap) Load(name namespacedContainerName) (*containerData, bool) { v, ok := c.m.Load(name) if !ok { return nil, false } return v.(*containerData), true } // Store stores the containerData for the given name. func (c *containerMap) Store(name namespacedContainerName, data *containerData) { c.m.Store(name, data) } // Delete removes the containerData for the given name. func (c *containerMap) Delete(name namespacedContainerName) { c.m.Delete(name) } // Range calls f for each container in the map. If f returns false, iteration stops. func (c *containerMap) Range(f func(name namespacedContainerName, data *containerData) bool) { c.m.Range(func(key, value any) bool { return f(key.(namespacedContainerName), value.(*containerData)) }) } type manager struct { containers containerMap memoryCache *memory.InMemoryCache fsInfo fs.FsInfo sysFs sysfs.SysFs machineMu sync.RWMutex // protects machineInfo machineInfo info.MachineInfo quitChannels []chan error cadvisorContainer string inHostNamespace bool eventHandler events.EventManager startupTime time.Time maxHousekeepingInterval time.Duration allowDynamicHousekeeping bool includedMetrics container.MetricSet containerWatchers []watcher.ContainerWatcher eventsChannel chan watcher.ContainerEvent collectorHTTPClient *http.Client perfManager stats.Manager resctrlManager resctrl.ResControlManager // List of raw container cgroup path prefix whitelist. rawContainerCgroupPathPrefixWhiteList []string // List of container env prefix whitelist, the matched container envs would be collected into metrics as extra labels. containerEnvMetadataWhiteList []string } func (m *manager) PodmanContainer(containerName string, query *info.ContainerInfoRequest) (info.ContainerInfo, error) { container, err := m.namespacedContainer(containerName, PodmanNamespace) if err != nil { return info.ContainerInfo{}, err } inf, err := m.containerDataToContainerInfo(container, query) if err != nil { return info.ContainerInfo{}, err } return *inf, nil } // Start the container manager. func (m *manager) Start() error { m.containerWatchers = container.InitializePlugins(m, m.fsInfo, m.includedMetrics) err := raw.Register(m, m.fsInfo, m.includedMetrics, m.rawContainerCgroupPathPrefixWhiteList) if err != nil { klog.Errorf("Registration of the raw container factory failed: %v", err) } rawWatcher, err := raw.NewRawContainerWatcher(m.includedMetrics) if err != nil { return err } m.containerWatchers = append(m.containerWatchers, rawWatcher) // Watch for OOMs. err = m.watchForNewOoms() if err != nil { klog.Warningf("Could not configure a source for OOM detection, disabling OOM events: %v", err) } // If there are no factories, don't start any housekeeping and serve the information we do have. if !container.HasFactories() { return nil } // Create root and then recover all containers. err = m.createContainer("/", watcher.Raw) if err != nil { return err } klog.V(2).Infof("Starting recovery of all containers") err = m.detectSubcontainers("/") if err != nil { return err } klog.V(2).Infof("Recovery completed") // Watch for new container. quitWatcher := make(chan error) err = m.watchForNewContainers(quitWatcher) if err != nil { return err } m.quitChannels = append(m.quitChannels, quitWatcher) // Look for new containers in the main housekeeping thread. quitGlobalHousekeeping := make(chan error) m.quitChannels = append(m.quitChannels, quitGlobalHousekeeping) go m.globalHousekeeping(quitGlobalHousekeeping) quitUpdateMachineInfo := make(chan error) m.quitChannels = append(m.quitChannels, quitUpdateMachineInfo) go m.updateMachineInfo(quitUpdateMachineInfo) return nil } func (m *manager) Stop() error { defer m.destroyCollectors() // Stop and wait on all quit channels. for i, c := range m.quitChannels { // Send the exit signal and wait on the thread to exit (by closing the channel). c <- nil err := <-c if err != nil { // Remove the channels that quit successfully. m.quitChannels = m.quitChannels[i:] return err } } m.quitChannels = make([]chan error, 0, 2) nvm.Finalize() perf.Finalize() return nil } func (m *manager) destroyCollectors() { m.containers.Range(func(_ namespacedContainerName, container *containerData) bool { if container == nil { return true } container.perfCollector.Destroy() container.resctrlCollector.Destroy() return true }) } func (m *manager) updateMachineInfo(quit chan error) { ticker := time.NewTicker(*updateMachineInfoInterval) for { select { case <-ticker.C: info, err := machine.Info(m.sysFs, m.fsInfo, m.inHostNamespace) if err != nil { klog.Errorf("Could not get machine info: %v", err) break } m.machineMu.Lock() m.machineInfo = *info m.machineMu.Unlock() klog.V(5).Infof("Update machine info: %+v", *info) case <-quit: ticker.Stop() quit <- nil return } } } func (m *manager) globalHousekeeping(quit chan error) { // Long housekeeping is either 100ms or half of the housekeeping interval. longHousekeeping := 100 * time.Millisecond if *globalHousekeepingInterval/2 < longHousekeeping { longHousekeeping = *globalHousekeepingInterval / 2 } ticker := time.NewTicker(*globalHousekeepingInterval) for { select { case t := <-ticker.C: start := time.Now() // Check for new containers. err := m.detectSubcontainers("/") if err != nil { klog.Errorf("Failed to detect containers: %s", err) } // Log if housekeeping took too long. duration := time.Since(start) if duration >= longHousekeeping { klog.V(3).Infof("Global Housekeeping(%d) took %s", t.Unix(), duration) } case <-quit: // Quit if asked to do so. quit <- nil klog.Infof("Exiting global housekeeping thread") return } } } func (m *manager) getContainerData(containerName string) (*containerData, error) { // Ensure we have the container. cont, ok := m.containers.Load(namespacedContainerName{Name: containerName}) if !ok { return nil, fmt.Errorf("unknown container %q", containerName) } return cont, nil } func (m *manager) GetDerivedStats(containerName string, options v2.RequestOptions) (map[string]v2.DerivedStats, error) { conts, err := m.getRequestedContainers(containerName, options) if err != nil { return nil, err } var errs partialFailure stats := make(map[string]v2.DerivedStats) for name, cont := range conts { d, err := cont.DerivedStats() if err != nil { errs.append(name, "DerivedStats", err) } stats[name] = d } return stats, errs.OrNil() } func (m *manager) GetContainerSpec(containerName string, options v2.RequestOptions) (map[string]v2.ContainerSpec, error) { conts, err := m.getRequestedContainers(containerName, options) if err != nil { return nil, err } var errs partialFailure specs := make(map[string]v2.ContainerSpec) for name, cont := range conts { cinfo, err := cont.GetInfo(false) if err != nil { errs.append(name, "GetInfo", err) } spec := m.getV2Spec(cinfo) specs[name] = spec } return specs, errs.OrNil() } // Get V2 container spec from v1 container info. func (m *manager) getV2Spec(cinfo *containerInfo) v2.ContainerSpec { spec := m.getAdjustedSpec(cinfo) return v2.ContainerSpecFromV1(&spec, cinfo.Aliases, cinfo.Namespace) } func (m *manager) getAdjustedSpec(cinfo *containerInfo) info.ContainerSpec { spec := cinfo.Spec // Set default value to an actual value if spec.HasMemory { // Memory.Limit is 0 means there's no limit if spec.Memory.Limit == 0 { m.machineMu.RLock() spec.Memory.Limit = uint64(m.machineInfo.MemoryCapacity) m.machineMu.RUnlock() } } return spec } func (m *manager) GetContainerInfo(containerName string, query *info.ContainerInfoRequest) (*info.ContainerInfo, error) { cont, err := m.getContainerData(containerName) if err != nil { return nil, err } return m.containerDataToContainerInfo(cont, query) } func (m *manager) GetContainerInfoV2(containerName string, options v2.RequestOptions) (map[string]v2.ContainerInfo, error) { containers, err := m.getRequestedContainers(containerName, options) if err != nil { return nil, err } var errs partialFailure var nilTime time.Time // Ignored. infos := make(map[string]v2.ContainerInfo, len(containers)) for name, container := range containers { result := v2.ContainerInfo{} cinfo, err := container.GetInfo(false) if err != nil { errs.append(name, "GetInfo", err) infos[name] = result continue } result.Spec = m.getV2Spec(cinfo) stats, err := m.memoryCache.RecentStats(name, nilTime, nilTime, options.Count) if err != nil { errs.append(name, "RecentStats", err) infos[name] = result continue } result.Stats = v2.ContainerStatsFromV1(containerName, &cinfo.Spec, stats) infos[name] = result } return infos, errs.OrNil() } func (m *manager) containerDataToContainerInfo(cont *containerData, query *info.ContainerInfoRequest) (*info.ContainerInfo, error) { // Get the info from the container. cinfo, err := cont.GetInfo(true) if err != nil { return nil, err } stats, err := m.memoryCache.RecentStats(cinfo.Name, query.Start, query.End, query.NumStats) if err != nil { return nil, err } // Make a copy of the info for the user. ret := &info.ContainerInfo{ ContainerReference: cinfo.ContainerReference, Subcontainers: cinfo.Subcontainers, Spec: m.getAdjustedSpec(cinfo), Stats: stats, } return ret, nil } func (m *manager) getContainer(containerName string) (*containerData, error) { cont, ok := m.containers.Load(namespacedContainerName{Name: containerName}) if !ok { return nil, fmt.Errorf("unknown container %q", containerName) } return cont, nil } func (m *manager) getSubcontainers(containerName string) map[string]*containerData { matchedName := path.Join(containerName, "/") containersMap := make(map[string]*containerData) // Get all the unique subcontainers of the specified container m.containers.Range(func(_ namespacedContainerName, cont *containerData) bool { if cont == nil { return true } name := cont.info.Name if name == containerName || strings.HasPrefix(name, matchedName) { containersMap[name] = cont } return true }) return containersMap } func (m *manager) SubcontainersInfo(containerName string, query *info.ContainerInfoRequest) ([]*info.ContainerInfo, error) { containersMap := m.getSubcontainers(containerName) containers := make([]*containerData, 0, len(containersMap)) for _, cont := range containersMap { containers = append(containers, cont) } return m.containerDataSliceToContainerInfoSlice(containers, query) } func (m *manager) getAllNamespacedContainers(ns string) map[string]*containerData { containers := make(map[string]*containerData) // Get containers in a namespace. m.containers.Range(func(name namespacedContainerName, cont *containerData) bool { if cont == nil { return true } if name.Namespace == ns { containers[cont.info.Name] = cont } return true }) return containers } func (m *manager) AllDockerContainers(query *info.ContainerInfoRequest) (map[string]info.ContainerInfo, error) { containers := m.getAllNamespacedContainers(DockerNamespace) return m.containersInfo(containers, query) } func (m *manager) namespacedContainer(containerName string, ns string) (*containerData, error) { // Check for the container in the namespace. if cont, ok := m.containers.Load(namespacedContainerName{Namespace: ns, Name: containerName}); ok { return cont, nil } // Look for container by short prefix name if no exact match found. var cont *containerData var err error m.containers.Range(func(name namespacedContainerName, c *containerData) bool { if name.Namespace == ns && strings.HasPrefix(name.Name, containerName) { if cont == nil { cont = c } else { err = fmt.Errorf("unable to find container in %q namespace. Container %q is not unique", ns, containerName) return false // stop iteration } } return true }) if err != nil { return nil, err } if cont == nil { return nil, fmt.Errorf("unable to find container %q in %q namespace", containerName, ns) } return cont, nil } func (m *manager) DockerContainer(containerName string, query *info.ContainerInfoRequest) (info.ContainerInfo, error) { container, err := m.namespacedContainer(containerName, DockerNamespace) if err != nil { return info.ContainerInfo{}, err } inf, err := m.containerDataToContainerInfo(container, query) if err != nil { return info.ContainerInfo{}, err } return *inf, nil } func (m *manager) containerDataSliceToContainerInfoSlice(containers []*containerData, query *info.ContainerInfoRequest) ([]*info.ContainerInfo, error) { if len(containers) == 0 { return nil, fmt.Errorf("no containers found") } // Get the info for each container. output := make([]*info.ContainerInfo, 0, len(containers)) for i := range containers { cinfo, err := m.containerDataToContainerInfo(containers[i], query) if err != nil { // Skip containers with errors, we try to degrade gracefully. klog.V(4).Infof("convert container data to container info failed with error %s", err.Error()) continue } output = append(output, cinfo) } return output, nil } func (m *manager) GetRequestedContainersInfo(containerName string, options v2.RequestOptions) (map[string]*info.ContainerInfo, error) { containers, err := m.getRequestedContainers(containerName, options) if err != nil { return nil, err } var errs partialFailure containersMap := make(map[string]*info.ContainerInfo) query := info.ContainerInfoRequest{ NumStats: options.Count, } for name, data := range containers { info, err := m.containerDataToContainerInfo(data, &query) if err != nil { if err == memory.ErrDataNotFound { klog.V(4).Infof("Error getting data for container %s because of race condition", name) continue } errs.append(name, "containerDataToContainerInfo", err) } containersMap[name] = info } return containersMap, errs.OrNil() } func (m *manager) getRequestedContainers(containerName string, options v2.RequestOptions) (map[string]*containerData, error) { containersMap := make(map[string]*containerData) switch options.IdType { case v2.TypeName: if !options.Recursive { cont, err := m.getContainer(containerName) if err != nil { return containersMap, err } containersMap[cont.info.Name] = cont } else { containersMap = m.getSubcontainers(containerName) if len(containersMap) == 0 { return containersMap, fmt.Errorf("unknown container: %q", containerName) } } case v2.TypeDocker, v2.TypePodman: namespace := map[string]string{ v2.TypeDocker: DockerNamespace, v2.TypePodman: PodmanNamespace, }[options.IdType] if !options.Recursive { containerName = strings.TrimPrefix(containerName, "/") cont, err := m.namespacedContainer(containerName, namespace) if err != nil { return containersMap, err } containersMap[cont.info.Name] = cont } else { if containerName != "/" { return containersMap, fmt.Errorf("invalid request for %s container %q with subcontainers", options.IdType, containerName) } containersMap = m.getAllNamespacedContainers(namespace) } default: return containersMap, fmt.Errorf("invalid request type %q", options.IdType) } if options.MaxAge != nil { // update stats for all containers in containersMap var waitGroup sync.WaitGroup waitGroup.Add(len(containersMap)) for _, container := range containersMap { go func(cont *containerData) { cont.OnDemandHousekeeping(*options.MaxAge) waitGroup.Done() }(container) } waitGroup.Wait() } return containersMap, nil } func (m *manager) GetDirFsInfo(dir string) (v2.FsInfo, error) { device, err := m.fsInfo.GetDirFsDevice(dir) if err != nil { return v2.FsInfo{}, fmt.Errorf("failed to get device for dir %q: %v", dir, err) } return m.getFsInfoByDeviceName(device.Device) } func (m *manager) GetFsInfoByFsUUID(uuid string) (v2.FsInfo, error) { device, err := m.fsInfo.GetDeviceInfoByFsUUID(uuid) if err != nil { return v2.FsInfo{}, err } return m.getFsInfoByDeviceName(device.Device) } func (m *manager) GetFsInfo(label string) ([]v2.FsInfo, error) { var empty time.Time // Get latest data from filesystems hanging off root container. stats, err := m.memoryCache.RecentStats("/", empty, empty, 1) if err != nil { return nil, err } dev := "" if len(label) != 0 { dev, err = m.fsInfo.GetDeviceForLabel(label) if err != nil { return nil, err } } fsInfo := []v2.FsInfo{} for i := range stats[0].Filesystem { fs := stats[0].Filesystem[i] if len(label) != 0 && fs.Device != dev { continue } mountpoint, err := m.fsInfo.GetMountpointForDevice(fs.Device) if err != nil { return nil, err } labels, err := m.fsInfo.GetLabelsForDevice(fs.Device) if err != nil { return nil, err } fi := v2.FsInfo{ Timestamp: stats[0].Timestamp, Device: fs.Device, Mountpoint: mountpoint, Capacity: fs.Limit, Usage: fs.Usage, Available: fs.Available, Labels: labels, } if fs.HasInodes { fi.Inodes = &fs.Inodes fi.InodesFree = &fs.InodesFree } fsInfo = append(fsInfo, fi) } return fsInfo, nil } func (m *manager) GetMachineInfo() (*info.MachineInfo, error) { m.machineMu.RLock() defer m.machineMu.RUnlock() return m.machineInfo.Clone(), nil } func (m *manager) GetVersionInfo() (*info.VersionInfo, error) { // TODO: Consider caching this and periodically updating. The VersionInfo may change if // the docker daemon is started after the cAdvisor client is created. Caching the value // would be helpful so we would be able to return the last known docker version if // docker was down at the time of a query. return getVersionInfo() } func (m *manager) Exists(containerName string) bool { _, ok := m.containers.Load(namespacedContainerName{Name: containerName}) return ok } func (m *manager) GetProcessList(containerName string, options v2.RequestOptions) ([]v2.ProcessInfo, error) { // override recursive. Only support single container listing. options.Recursive = false // override MaxAge. ProcessList does not require updated stats. options.MaxAge = nil conts, err := m.getRequestedContainers(containerName, options) if err != nil { return nil, err } if len(conts) != 1 { return nil, fmt.Errorf("expected the request to match only one container") } // TODO(rjnagal): handle count? Only if we can do count by type (eg. top 5 cpu users) ps := []v2.ProcessInfo{} for _, cont := range conts { ps, err = cont.GetProcessList(m.cadvisorContainer, m.inHostNamespace) if err != nil { return nil, err } } return ps, nil } func (m *manager) registerCollectors(collectorConfigs map[string]string, cont *containerData) error { for k, v := range collectorConfigs { configFile, err := cont.ReadFile(v, m.inHostNamespace) if err != nil { return fmt.Errorf("failed to read config file %q for config %q, container %q: %v", k, v, cont.info.Name, err) } klog.V(4).Infof("Got config from %q: %q", v, configFile) if strings.HasPrefix(k, "prometheus") || strings.HasPrefix(k, "Prometheus") { newCollector, err := collector.NewPrometheusCollector(k, configFile, *applicationMetricsCountLimit, cont.handler, m.collectorHTTPClient) if err != nil { return fmt.Errorf("failed to create collector for container %q, config %q: %v", cont.info.Name, k, err) } err = cont.collectorManager.RegisterCollector(newCollector) if err != nil { return fmt.Errorf("failed to register collector for container %q, config %q: %v", cont.info.Name, k, err) } } else { newCollector, err := collector.NewCollector(k, configFile, *applicationMetricsCountLimit, cont.handler, m.collectorHTTPClient) if err != nil { return fmt.Errorf("failed to create collector for container %q, config %q: %v", cont.info.Name, k, err) } err = cont.collectorManager.RegisterCollector(newCollector) if err != nil { return fmt.Errorf("failed to register collector for container %q, config %q: %v", cont.info.Name, k, err) } } } return nil } // Create a container. func (m *manager) createContainer(containerName string, watchSource watcher.ContainerWatchSource) error { namespacedName := namespacedContainerName{ Name: containerName, } // Check that the container didn't already exist. if _, ok := m.containers.Load(namespacedName); ok { return nil } handler, accept, err := container.NewContainerHandler(containerName, watchSource, m.containerEnvMetadataWhiteList, m.inHostNamespace) if err != nil { return err } if !accept { // ignoring this container. klog.V(4).Infof("ignoring container %q", containerName) return nil } collectorManager, err := collector.NewCollectorManager() if err != nil { return err } logUsage := *logCadvisorUsage && containerName == m.cadvisorContainer cont, err := newContainerData(containerName, m.memoryCache, handler, logUsage, collectorManager, m.maxHousekeepingInterval, m.allowDynamicHousekeeping, clock.RealClock{}) if err != nil { return err } if m.includedMetrics.Has(container.PerfMetrics) { perfCgroupPath, err := handler.GetCgroupPath("perf_event") if err != nil { klog.Warningf("Error getting perf_event cgroup path: %q", err) } else { cont.perfCollector, err = m.perfManager.GetCollector(perfCgroupPath) if err != nil { klog.Errorf("Perf event metrics will not be available for container %q: %v", containerName, err) } } } if m.includedMetrics.Has(container.ResctrlMetrics) { m.machineMu.Lock() noOfNUMA := len(m.machineInfo.Topology) m.machineMu.Unlock() cont.resctrlCollector, err = m.resctrlManager.GetCollector(containerName, func() ([]string, error) { return cont.getContainerPids(m.inHostNamespace) }, noOfNUMA) if err != nil { klog.V(4).Infof("resctrl metrics will not be available for container %s: %s", cont.info.Name, err) } } // Add collectors labels := handler.GetContainerLabels() collectorConfigs := collector.GetCollectorConfigs(labels) err = m.registerCollectors(collectorConfigs, cont) if err != nil { klog.Warningf("Failed to register collectors for %q: %v", containerName, err) } // Add the container name and all its aliases. The aliases must be within the namespace of the factory. m.containers.Store(namespacedName, cont) for _, alias := range cont.info.Aliases { m.containers.Store(namespacedContainerName{ Namespace: cont.info.Namespace, Name: alias, }, cont) } klog.V(3).Infof("Added container: %q (aliases: %v, namespace: %q)", containerName, cont.info.Aliases, cont.info.Namespace) contSpec, err := cont.handler.GetSpec() if err != nil { return err } contRef, err := cont.handler.ContainerReference() if err != nil { return err } newEvent := &info.Event{ ContainerName: contRef.Name, Timestamp: contSpec.CreationTime, EventType: info.EventContainerCreation, } err = m.eventHandler.AddEvent(newEvent) if err != nil { return err } // Start the container's housekeeping. return cont.Start() } func (m *manager) destroyContainer(containerName string) error { namespacedName := namespacedContainerName{ Name: containerName, } cont, ok := m.containers.Load(namespacedName) if !ok { // Already destroyed, done. return nil } exitCode, err := cont.handler.GetExitCode() if err != nil { klog.V(4).Infof("Could not retrieve exit code for container %q: %v (using -1)", containerName, err) exitCode = -1 } err = cont.Stop() if err != nil { return err } // Remove the container from our records (and all its aliases). m.containers.Delete(namespacedName) for _, alias := range cont.info.Aliases { m.containers.Delete(namespacedContainerName{ Namespace: cont.info.Namespace, Name: alias, }) } klog.V(3).Infof("Destroyed container: %q (aliases: %v, namespace: %q, exit_code: %d)", containerName, cont.info.Aliases, cont.info.Namespace, exitCode) contRef, err := cont.handler.ContainerReference() if err != nil { return err } newEvent := &info.Event{ ContainerName: contRef.Name, Timestamp: time.Now(), EventType: info.EventContainerDeletion, EventData: info.EventData{ ContainerDeletion: &info.ContainerDeletionEventData{ ExitCode: exitCode, }, }, } err = m.eventHandler.AddEvent(newEvent) if err != nil { return err } return nil } // Detect all containers that have been added or deleted from the specified container. func (m *manager) getContainersDiff(containerName string) (added []info.ContainerReference, removed []info.ContainerReference, err error) { // Get all subcontainers recursively. cont, ok := m.containers.Load(namespacedContainerName{Name: containerName}) if !ok { return nil, nil, fmt.Errorf("failed to find container %q while checking for new containers", containerName) } allContainers, err := cont.handler.ListContainers(container.ListRecursive) if err != nil { return nil, nil, err } allContainers = append(allContainers, info.ContainerReference{Name: containerName}) // Determine which were added and which were removed. allContainersSet := make(map[string]*containerData) m.containers.Range(func(name namespacedContainerName, cont *containerData) bool { if cont == nil { return true } // Only add the canonical name. if cont.info.Name == name.Name { allContainersSet[name.Name] = cont } return true }) // Added containers for _, c := range allContainers { delete(allContainersSet, c.Name) _, ok := m.containers.Load(namespacedContainerName{Name: c.Name}) if !ok { added = append(added, c) } } // Removed ones are no longer in the container listing. for _, d := range allContainersSet { removed = append(removed, d.info.ContainerReference) } return } // Detect the existing subcontainers and reflect the setup here. func (m *manager) detectSubcontainers(containerName string) error { added, removed, err := m.getContainersDiff(containerName) if err != nil { return err } // Add the new containers. for _, cont := range added { err = m.createContainer(cont.Name, watcher.Raw) if err != nil { klog.Errorf("Failed to create existing container: %s: %s", cont.Name, err) } } // Remove the old containers. for _, cont := range removed { err = m.destroyContainer(cont.Name) if err != nil { klog.Errorf("Failed to destroy existing container: %s: %s", cont.Name, err) } } return nil } // Watches for new containers started in the system. Runs forever unless there is a setup error. func (m *manager) watchForNewContainers(quit chan error) error { watched := make([]watcher.ContainerWatcher, 0) for _, watcher := range m.containerWatchers { err := watcher.Start(m.eventsChannel) if err != nil { for _, w := range watched { stopErr := w.Stop() if stopErr != nil { klog.Warningf("Failed to stop wacher %v with error: %v", w, stopErr) } } return err } watched = append(watched, watcher) } // There is a race between starting the watch and new container creation so we do a detection before we read new containers. err := m.detectSubcontainers("/") if err != nil { return err } // Listen to events from the container handler. go func() { for { select { case event := <-m.eventsChannel: switch { case event.EventType == watcher.ContainerAdd: switch event.WatchSource { default: err = m.createContainer(event.Name, event.WatchSource) } case event.EventType == watcher.ContainerDelete: err = m.destroyContainer(event.Name) } if err != nil { klog.Warningf("Failed to process watch event %+v: %v", event, err) } case <-quit: var errs partialFailure // Stop processing events if asked to quit. for i, watcher := range m.containerWatchers { err := watcher.Stop() if err != nil { errs.append(fmt.Sprintf("watcher %d", i), "Stop", err) } } if len(errs) > 0 { quit <- errs } else { quit <- nil klog.Infof("Exiting thread watching subcontainers") return } } } }() return nil } func (m *manager) watchForNewOoms() error { klog.V(2).Infof("Started watching for new ooms in manager") outStream := make(chan *oomparser.OomInstance, 10) oomLog, err := oomparser.New() if err != nil { return err } go oomLog.StreamOoms(outStream) go func() { for oomInstance := range outStream { // Surface OOM and OOM kill events. newEvent := &info.Event{ ContainerName: oomInstance.ContainerName, Timestamp: oomInstance.TimeOfDeath, EventType: info.EventOom, } err := m.eventHandler.AddEvent(newEvent) if err != nil { klog.Errorf("failed to add OOM event for %q: %v", oomInstance.ContainerName, err) } klog.V(3).Infof("Created an OOM event in container %q at %v", oomInstance.ContainerName, oomInstance.TimeOfDeath) newEvent = &info.Event{ ContainerName: oomInstance.VictimContainerName, Timestamp: oomInstance.TimeOfDeath, EventType: info.EventOomKill, EventData: info.EventData{ OomKill: &info.OomKillEventData{ Pid: oomInstance.Pid, ProcessName: oomInstance.ProcessName, }, }, } err = m.eventHandler.AddEvent(newEvent) if err != nil { klog.Errorf("failed to add OOM kill event for %q: %v", oomInstance.ContainerName, err) } // Count OOM events for later collection by prometheus request := v2.RequestOptions{ IdType: v2.TypeName, Count: 1, } conts, err := m.getRequestedContainers(oomInstance.ContainerName, request) if err != nil { klog.V(2).Infof("failed getting container info for %q: %v", oomInstance.ContainerName, err) continue } if len(conts) != 1 { klog.V(2).Info("Expected the request to match only one container") continue } for _, cont := range conts { atomic.AddUint64(&cont.oomEvents, 1) } } }() return nil } // can be called by the api which will take events returned on the channel func (m *manager) WatchForEvents(request *events.Request) (*events.EventChannel, error) { return m.eventHandler.WatchEvents(request) } // can be called by the api which will return all events satisfying the request func (m *manager) GetPastEvents(request *events.Request) ([]*info.Event, error) { return m.eventHandler.GetEvents(request) } // called by the api when a client is no longer listening to the channel func (m *manager) CloseEventChannel(watchID int) { m.eventHandler.StopWatch(watchID) } // Parses the events StoragePolicy from the flags. func parseEventsStoragePolicy() events.StoragePolicy { policy := events.DefaultStoragePolicy() // Parse max age. parts := strings.Split(*eventStorageAgeLimit, ",") for _, part := range parts { items := strings.Split(part, "=") if len(items) != 2 { klog.Warningf("Unknown event storage policy %q when parsing max age", part) continue } dur, err := time.ParseDuration(items[1]) if err != nil { klog.Warningf("Unable to parse event max age duration %q: %v", items[1], err) continue } if items[0] == "default" { policy.DefaultMaxAge = dur continue } policy.PerTypeMaxAge[info.EventType(items[0])] = dur } // Parse max number. parts = strings.Split(*eventStorageEventLimit, ",") for _, part := range parts { items := strings.Split(part, "=") if len(items) != 2 { klog.Warningf("Unknown event storage policy %q when parsing max event limit", part) continue } val, err := strconv.Atoi(items[1]) if err != nil { klog.Warningf("Unable to parse integer from %q: %v", items[1], err) continue } if items[0] == "default" { policy.DefaultMaxNumEvents = val continue } policy.PerTypeMaxNumEvents[info.EventType(items[0])] = val } return policy } func (m *manager) DebugInfo() map[string][]string { debugInfo := container.DebugInfo() // Get unique containers. conts := make(map[*containerData]struct{}) m.containers.Range(func(_ namespacedContainerName, cont *containerData) bool { if cont != nil { conts[cont] = struct{}{} } return true }) // List containers. lines := make([]string, 0, len(conts)) for cont := range conts { lines = append(lines, cont.info.Name) if cont.info.Namespace != "" { lines = append(lines, fmt.Sprintf("\tNamespace: %s", cont.info.Namespace)) } if len(cont.info.Aliases) != 0 { lines = append(lines, "\tAliases:") for _, alias := range cont.info.Aliases { lines = append(lines, fmt.Sprintf("\t\t%s", alias)) } } } debugInfo["Managed containers"] = lines return debugInfo } func (m *manager) getFsInfoByDeviceName(deviceName string) (v2.FsInfo, error) { mountPoint, err := m.fsInfo.GetMountpointForDevice(deviceName) if err != nil { return v2.FsInfo{}, fmt.Errorf("failed to get mount point for device %q: %v", deviceName, err) } infos, err := m.GetFsInfo("") if err != nil { return v2.FsInfo{}, err } for _, info := range infos { if info.Mountpoint == mountPoint { return info, nil } } return v2.FsInfo{}, fmt.Errorf("cannot find filesystem info for device %q", deviceName) } func (m *manager) containersInfo(containers map[string]*containerData, query *info.ContainerInfoRequest) (map[string]info.ContainerInfo, error) { output := make(map[string]info.ContainerInfo, len(containers)) for name, cont := range containers { inf, err := m.containerDataToContainerInfo(cont, query) if err != nil { // Ignore the error because of race condition and return best-effort result. if err == memory.ErrDataNotFound { klog.V(4).Infof("Error getting data for container %s because of race condition", name) continue } return nil, err } output[name] = *inf } return output, nil } func (m *manager) AllPodmanContainers(query *info.ContainerInfoRequest) (map[string]info.ContainerInfo, error) { containers := m.getAllNamespacedContainers(PodmanNamespace) return m.containersInfo(containers, query) } func getVersionInfo() (*info.VersionInfo, error) { kernelVersion := machine.KernelVersion() osVersion := machine.ContainerOsVersion() return &info.VersionInfo{ KernelVersion: kernelVersion, ContainerOsVersion: osVersion, CadvisorVersion: version.Info["version"], CadvisorRevision: version.Info["revision"], }, nil } // Helper for accumulating partial failures. type partialFailure []string func (f *partialFailure) append(id, operation string, err error) { *f = append(*f, fmt.Sprintf("[%q: %s: %s]", id, operation, err)) } func (f partialFailure) Error() string { return fmt.Sprintf("partial failures: %s", strings.Join(f, ", ")) } func (f partialFailure) OrNil() error { if len(f) == 0 { return nil } return f } ================================================ FILE: manager/manager_bench_test.go ================================================ // Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package manager import ( "fmt" "sync" "testing" ) // Benchmark concurrent reads on sync.Map func BenchmarkSyncMapConcurrentReads(b *testing.B) { var m sync.Map for i := 0; i < 1000; i++ { key := namespacedContainerName{Name: fmt.Sprintf("/container/%d", i)} m.Store(key, &containerData{}) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { key := namespacedContainerName{Name: fmt.Sprintf("/container/%d", i%1000)} m.Load(key) i++ } }) } // Benchmark concurrent reads on RWMutex and map func BenchmarkRWMutexMapConcurrentReads(b *testing.B) { var mu sync.RWMutex m := make(map[namespacedContainerName]*containerData) for i := 0; i < 1000; i++ { key := namespacedContainerName{Name: fmt.Sprintf("/container/%d", i)} m[key] = &containerData{} } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { key := namespacedContainerName{Name: fmt.Sprintf("/container/%d", i%1000)} mu.RLock() _ = m[key] mu.RUnlock() i++ } }) } // Benchmark iteration with sync.Map func BenchmarkSyncMapIteration(b *testing.B) { var m sync.Map for i := 0; i < 1000; i++ { key := namespacedContainerName{Name: fmt.Sprintf("/container/%d", i)} m.Store(key, &containerData{}) } b.ResetTimer() for i := 0; i < b.N; i++ { count := 0 m.Range(func(_, _ any) bool { count++ return true }) } } // Benchmark iteration with RWMutex and map func BenchmarkRWMutexMapIteration(b *testing.B) { var mu sync.RWMutex m := make(map[namespacedContainerName]*containerData) for i := 0; i < 1000; i++ { key := namespacedContainerName{Name: fmt.Sprintf("/container/%d", i)} m[key] = &containerData{} } b.ResetTimer() for i := 0; i < b.N; i++ { mu.RLock() count := 0 for range m { count++ } mu.RUnlock() } } // Benchmark mixed read/write with sync.Map func BenchmarkSyncMapMixedReadWrite(b *testing.B) { var m sync.Map for i := 0; i < 1000; i++ { key := namespacedContainerName{Name: fmt.Sprintf("/container/%d", i)} m.Store(key, &containerData{}) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { if i%100 == 0 { // 1% writes key := namespacedContainerName{Name: fmt.Sprintf("/container/new/%d", i)} m.Store(key, &containerData{}) } else { // 99% reads key := namespacedContainerName{Name: fmt.Sprintf("/container/%d", i%1000)} m.Load(key) } i++ } }) } // Benchmark mixed read/write with RWMutex and map func BenchmarkRWMutexMapMixedReadWrite(b *testing.B) { var mu sync.RWMutex m := make(map[namespacedContainerName]*containerData) for i := 0; i < 1000; i++ { key := namespacedContainerName{Name: fmt.Sprintf("/container/%d", i)} m[key] = &containerData{} } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { if i%100 == 0 { // 1% writes key := namespacedContainerName{Name: fmt.Sprintf("/container/new/%d", i)} mu.Lock() m[key] = &containerData{} mu.Unlock() } else { // 99% reads key := namespacedContainerName{Name: fmt.Sprintf("/container/%d", i%1000)} mu.RLock() _ = m[key] mu.RUnlock() } i++ } }) } ================================================ FILE: manager/manager_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Per-container manager. package manager import ( "fmt" "reflect" "strings" "sync" "testing" "time" "github.com/google/cadvisor/cache/memory" "github.com/google/cadvisor/collector" "github.com/google/cadvisor/container" containertest "github.com/google/cadvisor/container/testing" "github.com/google/cadvisor/events" info "github.com/google/cadvisor/info/v1" itest "github.com/google/cadvisor/info/v1/test" v2 "github.com/google/cadvisor/info/v2" "github.com/google/cadvisor/stats" "github.com/google/cadvisor/utils/sysfs/fakesysfs" "github.com/stretchr/testify/assert" clock "k8s.io/utils/clock/testing" // install all the container runtimes included in the library version for testing. // as these are moved to cmd/internal/container, remove them from here. _ "github.com/google/cadvisor/container/containerd/install" _ "github.com/google/cadvisor/container/crio/install" _ "github.com/google/cadvisor/container/docker/install" _ "github.com/google/cadvisor/container/systemd/install" ) // TODO(vmarmol): Refactor these tests. func createManagerAndAddContainers( memoryCache *memory.InMemoryCache, sysfs *fakesysfs.FakeSysFs, containers []string, f func(*containertest.MockContainerHandler), t *testing.T, ) *manager { container.ClearContainerHandlerFactories() mif := &manager{ quitChannels: make([]chan error, 0, 2), memoryCache: memoryCache, } for _, name := range containers { mockHandler := containertest.NewMockContainerHandler(name) spec := itest.GenerateRandomContainerSpec(4) mockHandler.On("GetSpec").Return( spec, nil, ).Once() cont, err := newContainerData(name, memoryCache, mockHandler, false, &collector.GenericCollectorManager{}, 60*time.Second, true, clock.NewFakeClock(time.Now())) if err != nil { t.Fatal(err) } mif.containers.Store(namespacedContainerName{ Name: name, }, cont) // Add Docker containers under their namespace. if strings.HasPrefix(name, "/docker") { mif.containers.Store(namespacedContainerName{ Namespace: DockerNamespace, Name: strings.TrimPrefix(name, "/docker/"), }, cont) } f(mockHandler) } return mif } func createManagerAndAddSubContainers( memoryCache *memory.InMemoryCache, sysfs *fakesysfs.FakeSysFs, containers []string, f func(*containertest.MockContainerHandler), t *testing.T, ) *manager { container.ClearContainerHandlerFactories() mif := &manager{ quitChannels: make([]chan error, 0, 2), memoryCache: memoryCache, } subcontainers1 := []info.ContainerReference{ {Name: "/kubepods/besteffort"}, {Name: "/kubepods/burstable"}, } subcontainers2 := []info.ContainerReference(nil) subcontainers3 := []info.ContainerReference{ {Name: "/kubepods/burstable/pod01042b28-179d-446a-954a-7266557e12cd"}, {Name: "/kubepods/burstable/pod01042b28-179d-446a-954a-7266557e12ce"}, } subcontainers4 := []info.ContainerReference{ {Name: "/kubepods/burstable/pod01042b28-179d-446a-954a-7266557e12cd/22f44d2a517778590e2d8bcafafe501f79e8a509e5b6de70b7700c4d37722bce"}, {Name: "/kubepods/burstable/pod01042b28-179d-446a-954a-7266557e12cd/ae9465f98d275998e148b6fc12f5f92e5d4a64fca0d255f6dc3a13cc6f93a10f"}, } subcontainers5 := []info.ContainerReference(nil) subcontainers6 := []info.ContainerReference(nil) subcontainerList := [][]info.ContainerReference{subcontainers1, subcontainers2, subcontainers3, subcontainers4, subcontainers5, subcontainers6} for idx, name := range containers { mockHandler := containertest.NewMockContainerHandler(name) spec := itest.GenerateRandomContainerSpec(4) mockHandler.On("GetSpec").Return( spec, nil, ).Once() mockHandler.On("ListContainers", container.ListSelf).Return( subcontainerList[idx], nil, ) cont, err := newContainerData(name, memoryCache, mockHandler, false, &collector.GenericCollectorManager{}, 60*time.Second, true, clock.NewFakeClock(time.Now())) if err != nil { t.Fatal(err) } mif.containers.Store(namespacedContainerName{ Name: name, }, cont) // Add Docker containers under their namespace. if strings.HasPrefix(name, "/docker") { mif.containers.Store(namespacedContainerName{ Namespace: DockerNamespace, Name: strings.TrimPrefix(name, "/docker/"), }, cont) } f(mockHandler) } return mif } // Expect a manager with the specified containers and query. Returns the manager, map of ContainerInfo objects, // and map of MockContainerHandler objects.} func expectManagerWithContainers(containers []string, query *info.ContainerInfoRequest, t *testing.T) (*manager, map[string]*info.ContainerInfo, map[string]*containertest.MockContainerHandler) { infosMap := make(map[string]*info.ContainerInfo, len(containers)) handlerMap := make(map[string]*containertest.MockContainerHandler, len(containers)) for _, container := range containers { infosMap[container] = itest.GenerateRandomContainerInfo(container, 4, query, 1*time.Second) } memoryCache := memory.New(time.Duration(query.NumStats)*time.Second, nil) sysfs := &fakesysfs.FakeSysFs{} m := createManagerAndAddContainers( memoryCache, sysfs, containers, func(h *containertest.MockContainerHandler) { cinfo := infosMap[h.Name] ref, err := h.ContainerReference() if err != nil { t.Error(err) } cInfo := info.ContainerInfo{ ContainerReference: ref, } for _, stat := range cinfo.Stats { err = memoryCache.AddStats(&cInfo, stat) if err != nil { t.Error(err) } } spec := cinfo.Spec h.On("ListContainers", container.ListSelf).Return( []info.ContainerReference(nil), nil, ) h.On("GetSpec").Return( spec, nil, ).Once() handlerMap[h.Name] = h }, t, ) return m, infosMap, handlerMap } // Expect a manager with the specified containers and query. Returns the manager, map of ContainerInfo objects, // and map of MockContainerHandler objects.} func expectManagerWithSubContainers(containers []string, query *info.ContainerInfoRequest, t *testing.T) (*manager, map[string]*info.ContainerInfo, map[string]*containertest.MockContainerHandler) { infosMap := make(map[string]*info.ContainerInfo, len(containers)) handlerMap := make(map[string]*containertest.MockContainerHandler, len(containers)) for _, container := range containers { infosMap[container] = itest.GenerateRandomContainerInfo(container, 4, query, 1*time.Second) } memoryCache := memory.New(time.Duration(query.NumStats)*time.Second, nil) sysfs := &fakesysfs.FakeSysFs{} m := createManagerAndAddSubContainers( memoryCache, sysfs, containers, func(h *containertest.MockContainerHandler) { cinfo := infosMap[h.Name] ref, err := h.ContainerReference() if err != nil { t.Error(err) } cInfo := info.ContainerInfo{ ContainerReference: ref, } for _, stat := range cinfo.Stats { err = memoryCache.AddStats(&cInfo, stat) if err != nil { t.Error(err) } } spec := cinfo.Spec h.On("GetSpec").Return( spec, nil, ).Once() handlerMap[h.Name] = h }, t, ) return m, infosMap, handlerMap } // Expect a manager with the specified containers and query. Returns the manager, map of ContainerInfo objects, // and map of MockContainerHandler objects.} func expectManagerWithContainersV2(containers []string, query *info.ContainerInfoRequest, t *testing.T) (*manager, map[string]*info.ContainerInfo, map[string]*containertest.MockContainerHandler) { infosMap := make(map[string]*info.ContainerInfo, len(containers)) handlerMap := make(map[string]*containertest.MockContainerHandler, len(containers)) for _, container := range containers { infosMap[container] = itest.GenerateRandomContainerInfo(container, 4, query, 1*time.Second) } memoryCache := memory.New(time.Duration(query.NumStats)*time.Second, nil) sysfs := &fakesysfs.FakeSysFs{} m := createManagerAndAddContainers( memoryCache, sysfs, containers, func(h *containertest.MockContainerHandler) { cinfo := infosMap[h.Name] ref, err := h.ContainerReference() if err != nil { t.Error(err) } cInfo := info.ContainerInfo{ ContainerReference: ref, } for _, stat := range cinfo.Stats { err = memoryCache.AddStats(&cInfo, stat) if err != nil { t.Error(err) } } spec := cinfo.Spec h.On("GetSpec").Return( spec, nil, ).Once() handlerMap[h.Name] = h }, t, ) return m, infosMap, handlerMap } func TestGetContainerInfo(t *testing.T) { containers := []string{ "/c1", "/c2", } query := &info.ContainerInfoRequest{ NumStats: 256, } m, infosMap, handlerMap := expectManagerWithContainers(containers, query, t) returnedInfos := make(map[string]*info.ContainerInfo, len(containers)) for _, container := range containers { cinfo, err := m.GetContainerInfo(container, query) if err != nil { t.Fatalf("Unable to get info for container %v: %v", container, err) } returnedInfos[container] = cinfo } for container, handler := range handlerMap { handler.AssertExpectations(t) returned := returnedInfos[container] expected := infosMap[container] if !reflect.DeepEqual(returned, expected) { t.Errorf("returned unexpected info for container %v; returned %+v; expected %+v", container, returned, expected) } } } func TestGetContainerInfoV2(t *testing.T) { containers := []string{ "/", "/c1", "/c2", } options := v2.RequestOptions{ IdType: v2.TypeName, Count: 1, Recursive: true, } query := &info.ContainerInfoRequest{ NumStats: 2, } m, _, handlerMap := expectManagerWithContainersV2(containers, query, t) infos, err := m.GetContainerInfoV2("/", options) if err != nil { t.Fatalf("GetContainerInfoV2 failed: %v", err) } for container, handler := range handlerMap { handler.AssertExpectations(t) info, ok := infos[container] assert.True(t, ok, "Missing info for container %q", container) assert.NotEqual(t, v2.ContainerSpec{}, info.Spec, "Empty spec for container %q", container) assert.NotEmpty(t, info.Stats, "Missing stats for container %q", container) } } func TestGetContainerInfoV2Failure(t *testing.T) { successful := "/" statless := "/c1" failing := "/c2" containers := []string{ successful, statless, failing, } options := v2.RequestOptions{ IdType: v2.TypeName, Count: 1, Recursive: true, } query := &info.ContainerInfoRequest{ NumStats: 2, } m, _, handlerMap := expectManagerWithContainers(containers, query, t) // Remove /c1 stats err := m.memoryCache.RemoveContainer(statless) if err != nil { t.Fatalf("RemoveContainer failed: %v", err) } // Make GetSpec fail on /c2 mockErr := fmt.Errorf("intentional GetSpec failure") _, err = handlerMap[failing].GetSpec() assert.NoError(t, err) // Use up default GetSpec call, and replace below handlerMap[failing].On("GetSpec").Return(info.ContainerSpec{}, mockErr) handlerMap[failing].On("Exists").Return(true) // Force GetSpec by resetting infoLastUpdatedTime to zero. if cont, ok := m.containers.Load(namespacedContainerName{Name: failing}); ok { cont.infoLastUpdatedTime.Store(0) } infos, err := m.GetContainerInfoV2("/", options) if err == nil { t.Error("Expected error calling GetContainerInfoV2") } // Successful containers still successful. info, ok := infos[successful] assert.True(t, ok, "Missing info for container %q", successful) assert.NotEqual(t, v2.ContainerSpec{}, info.Spec, "Empty spec for container %q", successful) assert.NotEmpty(t, info.Stats, "Missing stats for container %q", successful) // "/c1" present with spec. info, ok = infos[statless] assert.True(t, ok, "Missing info for container %q", statless) assert.NotEqual(t, v2.ContainerSpec{}, info.Spec, "Empty spec for container %q", statless) assert.Empty(t, info.Stats, "Missing stats for container %q", successful) // "/c2" should be present but empty. info, ok = infos[failing] assert.True(t, ok, "Missing info for failed container") assert.Equal(t, v2.ContainerInfo{}, info, "Empty spec for failed container") assert.Empty(t, info.Stats, "Missing stats for failed container") } func TestSubcontainersInfo(t *testing.T) { containers := []string{ "/c1", "/c2", } query := &info.ContainerInfoRequest{ NumStats: 64, } m, _, _ := expectManagerWithContainers(containers, query, t) result, err := m.SubcontainersInfo("/", query) if err != nil { t.Fatalf("expected to succeed: %s", err) } if len(result) != len(containers) { t.Errorf("expected to received containers: %v, but received: %v", containers, result) } for _, res := range result { found := false for _, name := range containers { if res.Name == name { found = true break } } if !found { t.Errorf("unexpected container %q in result, expected one of %v", res.Name, containers) } } } func TestSubcontainersInfoError(t *testing.T) { containers := []string{ "/kubepods", "/kubepods/besteffort", "/kubepods/burstable", "/kubepods/burstable/pod01042b28-179d-446a-954a-7266557e12cd", "/kubepods/burstable/pod01042b28-179d-446a-954a-7266557e12cd/22f44d2a517778590e2d8bcafafe501f79e8a509e5b6de70b7700c4d37722bce", "/kubepods/burstable/pod01042b28-179d-446a-954a-7266557e12cd/ae9465f98d275998e148b6fc12f5f92e5d4a64fca0d255f6dc3a13cc6f93a10f", } query := &info.ContainerInfoRequest{ NumStats: 1, } m, _, _ := expectManagerWithSubContainers(containers, query, t) result, err := m.SubcontainersInfo("/kubepods", query) if err != nil { t.Fatalf("expected to succeed: %s", err) } if len(result) != len(containers) { t.Errorf("expected to received containers: %v, but received: %v", containers, result) } totalBurstable := 0 burstableCount := 0 totalBesteffort := 0 besteffortCount := 0 for _, res := range result { found := false if res.Name == "/kubepods/burstable" { totalBurstable = len(res.Subcontainers) } else if res.Name == "/kubepods/besteffort" { totalBesteffort = len(res.Subcontainers) } else if strings.HasPrefix(res.Name, "/kubepods/burstable") && len(res.Name) == len("/kubepods/burstable/pod01042b28-179d-446a-954a-7266557e12cd") { burstableCount++ } else if strings.HasPrefix(res.Name, "/kubepods/besteffort") && len(res.Name) == len("/kubepods/besteffort/pod01042b28-179d-446a-954a-7266557e12cd") { besteffortCount++ } for _, name := range containers { if res.Name == name { found = true break } } if !found { t.Errorf("unexpected container %q in result, expected one of %v", res.Name, containers) } } assert.NotEqual(t, totalBurstable, burstableCount) assert.Equal(t, totalBesteffort, besteffortCount) } func TestDockerContainersInfo(t *testing.T) { containers := []string{ "/docker/c1a", "/docker/c2a", } query := &info.ContainerInfoRequest{ NumStats: 2, } m, _, _ := expectManagerWithContainers(containers, query, t) result, err := m.DockerContainer("c1a", query) if err != nil { t.Fatalf("expected to succeed: %s", err) } if result.Name != containers[0] { t.Errorf("Unexpected container %q in result. Expected container %q", result.Name, containers[0]) } result, err = m.DockerContainer("c2", query) if err != nil { t.Fatalf("expected to succeed: %s", err) } if result.Name != containers[1] { t.Errorf("Unexpected container %q in result. Expected container %q", result.Name, containers[1]) } result, err = m.DockerContainer("c", query) expectedError := "unable to find container. Container \"c\" is not unique" if err == nil { t.Errorf("expected error %q but received %q", expectedError, err) } } func TestDestroyContainerWithExitCode(t *testing.T) { mockHandler := containertest.NewMockContainerHandler("/test") mockHandler.On("GetExitCode").Return(42, nil) memoryCache := memory.New(60*time.Second, nil) m := &manager{ quitChannels: make([]chan error, 0, 2), memoryCache: memoryCache, } cont := &containerData{ handler: mockHandler, memoryCache: memoryCache, perfCollector: &stats.NoopCollector{}, resctrlCollector: &stats.NoopCollector{}, info: containerInfo{ ContainerReference: info.ContainerReference{ Name: "/test", }, }, stop: make(chan struct{}), } m.containers.Store(namespacedContainerName{Name: "/test"}, cont) mockEventHandler := &mockEventHandler{ events: make([]*info.Event, 0), } m.eventHandler = mockEventHandler err := m.destroyContainer("/test") if err != nil { t.Logf("destroyContainer error: %v", err) } assert.Nil(t, err) assert.Len(t, mockEventHandler.events, 1) event := mockEventHandler.events[0] assert.Equal(t, info.EventContainerDeletion, event.EventType) assert.NotNil(t, event.EventData.ContainerDeletion) assert.Equal(t, 42, event.EventData.ContainerDeletion.ExitCode) mockHandler.AssertExpectations(t) } func TestDestroyContainerExitCodeUnavailable(t *testing.T) { mockHandler := containertest.NewMockContainerHandler("/test") mockHandler.On("GetExitCode").Return(-1, fmt.Errorf("container not found")) memoryCache := memory.New(60*time.Second, nil) m := &manager{ quitChannels: make([]chan error, 0, 2), memoryCache: memoryCache, } cont := &containerData{ handler: mockHandler, memoryCache: memoryCache, perfCollector: &stats.NoopCollector{}, resctrlCollector: &stats.NoopCollector{}, info: containerInfo{ ContainerReference: info.ContainerReference{ Name: "/test", }, }, stop: make(chan struct{}), } m.containers.Store(namespacedContainerName{Name: "/test"}, cont) mockEventHandler := &mockEventHandler{ events: make([]*info.Event, 0), } m.eventHandler = mockEventHandler err := m.destroyContainer("/test") if err != nil { t.Logf("destroyContainer error: %v", err) } assert.Nil(t, err) assert.Len(t, mockEventHandler.events, 1) event := mockEventHandler.events[0] assert.Equal(t, info.EventContainerDeletion, event.EventType) assert.NotNil(t, event.EventData.ContainerDeletion) assert.Equal(t, -1, event.EventData.ContainerDeletion.ExitCode) mockHandler.AssertExpectations(t) } type mockEventHandler struct { events []*info.Event } func (m *mockEventHandler) AddEvent(e *info.Event) error { m.events = append(m.events, e) return nil } func (m *mockEventHandler) WatchEvents(request *events.Request) (*events.EventChannel, error) { return nil, fmt.Errorf("not implemented") } func (m *mockEventHandler) GetEvents(request *events.Request) ([]*info.Event, error) { return nil, fmt.Errorf("not implemented") } func (m *mockEventHandler) StopWatch(watchID int) { } // threadSafeEventHandler is a thread-safe version of mockEventHandler for concurrent tests. type threadSafeEventHandler struct { mu sync.Mutex events []*info.Event } func (m *threadSafeEventHandler) AddEvent(e *info.Event) error { m.mu.Lock() defer m.mu.Unlock() m.events = append(m.events, e) return nil } func (m *threadSafeEventHandler) WatchEvents(request *events.Request) (*events.EventChannel, error) { return nil, fmt.Errorf("not implemented") } func (m *threadSafeEventHandler) GetEvents(request *events.Request) ([]*info.Event, error) { return nil, fmt.Errorf("not implemented") } func (m *threadSafeEventHandler) StopWatch(watchID int) { } // TestContainerDataStopConcurrent verifies that concurrent calls to Stop() // do not cause a panic. This is a regression test for a race condition where // multiple goroutines could call Stop() on the same containerData, causing a // "close of closed channel" panic. func TestContainerDataStopConcurrent(t *testing.T) { memoryCache := memory.New(60*time.Second, nil) // Create a minimal containerData with the fields needed for Stop() cd := &containerData{ info: containerInfo{ ContainerReference: info.ContainerReference{ Name: "/test-concurrent", }, }, memoryCache: memoryCache, stop: make(chan struct{}), perfCollector: &stats.NoopCollector{}, resctrlCollector: &stats.NoopCollector{}, } // Launch multiple goroutines that all try to call Stop() simultaneously const numGoroutines = 10 var wg sync.WaitGroup wg.Add(numGoroutines) // Use a channel to synchronize goroutines to start at the same time start := make(chan struct{}) for i := 0; i < numGoroutines; i++ { go func() { defer wg.Done() <-start // Wait for signal to start // This should not panic even if called multiple times concurrently _ = cd.Stop() }() } // Signal all goroutines to start simultaneously close(start) // Wait for all goroutines to complete - if there's a panic, the test will fail wg.Wait() } // TestDestroyContainerConcurrent verifies that concurrent calls to destroyContainer // for the same container do not cause a panic. func TestDestroyContainerConcurrent(t *testing.T) { memoryCache := memory.New(60*time.Second, nil) m := &manager{ quitChannels: make([]chan error, 0, 2), memoryCache: memoryCache, } mockEventHandler := &threadSafeEventHandler{} mockHandler := containertest.NewMockContainerHandler("/test-concurrent") mockHandler.On("Start").Return(nil) mockHandler.On("Cleanup").Return() mockHandler.On("Stop").Return() // GetExitCode may be called multiple times due to concurrent access mockHandler.On("GetExitCode").Return(-1, nil).Maybe() // Create the container cd := &containerData{ handler: mockHandler, info: containerInfo{ ContainerReference: info.ContainerReference{ Name: "/test-concurrent", }, }, memoryCache: memoryCache, stop: make(chan struct{}), perfCollector: &stats.NoopCollector{}, resctrlCollector: &stats.NoopCollector{}, } // Add to manager's container map m.containers.Store(namespacedContainerName{Name: "/test-concurrent"}, cd) // Register event handler m.eventHandler = mockEventHandler // Launch multiple goroutines that all try to destroy the same container const numGoroutines = 10 var wg sync.WaitGroup wg.Add(numGoroutines) start := make(chan struct{}) for i := 0; i < numGoroutines; i++ { go func() { defer wg.Done() <-start _ = m.destroyContainer("/test-concurrent") }() } close(start) wg.Wait() // With sync.Once protecting only the channel close, multiple goroutines // can still process the container and add events. The key assertion is // that no panic occurred (test would fail otherwise). // At least one event should be recorded. assert.GreaterOrEqual(t, len(mockEventHandler.events), 1, "at least one destruction event should be recorded") } ================================================ FILE: metrics/metrics.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package metrics import ( "time" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" ) // metricValue describes a single metric value for a given set of label values // within a parent containerMetric. type metricValue struct { value float64 labels []string timestamp time.Time } type metricValues []metricValue // infoProvider will usually be manager.Manager, but can be swapped out for testing. type infoProvider interface { // GetRequestedContainersInfo gets info for all requested containers based on the request options. GetRequestedContainersInfo(containerName string, options v2.RequestOptions) (map[string]*info.ContainerInfo, error) // GetVersionInfo provides information about the version. GetVersionInfo() (*info.VersionInfo, error) // GetMachineInfo provides information about the machine. GetMachineInfo() (*info.MachineInfo, error) } ================================================ FILE: metrics/prometheus.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package metrics import ( "fmt" "regexp" "strconv" "time" "github.com/google/cadvisor/container" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" "github.com/prometheus/client_golang/prometheus" "k8s.io/klog/v2" "k8s.io/utils/clock" ) // asFloat64 converts a uint64 into a float64. func asFloat64(v uint64) float64 { return float64(v) } // asMicrosecondsToSeconds converts nanoseconds into a float64 representing seconds. func asMicrosecondsToSeconds(v uint64) float64 { return float64(v) / 1e6 } // asNanosecondsToSeconds converts nanoseconds into a float64 representing seconds. func asNanosecondsToSeconds(v uint64) float64 { return float64(v) / 1e9 } // fsValues is a helper method for assembling per-filesystem stats. func fsValues(fsStats []info.FsStats, valueFn func(*info.FsStats) float64, timestamp time.Time) metricValues { values := make(metricValues, 0, len(fsStats)) for _, stat := range fsStats { values = append(values, metricValue{ value: valueFn(&stat), labels: []string{stat.Device}, timestamp: timestamp, }) } return values } // ioValues is a helper method for assembling per-disk and per-filesystem stats. func ioValues(ioStats []info.PerDiskStats, ioType string, ioValueFn func(uint64) float64, fsStats []info.FsStats, valueFn func(*info.FsStats) float64, timestamp time.Time) metricValues { values := make(metricValues, 0, len(ioStats)+len(fsStats)) for _, stat := range ioStats { values = append(values, metricValue{ value: ioValueFn(stat.Stats[ioType]), labels: []string{stat.Device}, timestamp: timestamp, }) } for _, stat := range fsStats { values = append(values, metricValue{ value: valueFn(&stat), labels: []string{stat.Device}, timestamp: timestamp, }) } return values } // containerMetric describes a multi-dimensional metric used for exposing a // certain type of container statistic. type containerMetric struct { name string help string valueType prometheus.ValueType extraLabels []string condition func(s info.ContainerSpec) bool getValues func(s *info.ContainerStats) metricValues } func (cm *containerMetric) desc(baseLabels []string) *prometheus.Desc { return prometheus.NewDesc(cm.name, cm.help, append(baseLabels, cm.extraLabels...), nil) } // ContainerLabelsFunc defines all base labels and their values attached to // each metric exported by cAdvisor. type ContainerLabelsFunc func(*info.ContainerInfo) map[string]string // PrometheusCollector implements prometheus.Collector. type PrometheusCollector struct { infoProvider infoProvider errors prometheus.Gauge containerMetrics []containerMetric containerLabelsFunc ContainerLabelsFunc includedMetrics container.MetricSet opts v2.RequestOptions } // NewPrometheusCollector returns a new PrometheusCollector. The passed // ContainerLabelsFunc specifies which base labels will be attached to all // exported metrics. If left to nil, the DefaultContainerLabels function // will be used instead. func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetrics container.MetricSet, now clock.Clock, opts v2.RequestOptions) *PrometheusCollector { if f == nil { f = DefaultContainerLabels } c := &PrometheusCollector{ infoProvider: i, containerLabelsFunc: f, errors: prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "container", Name: "scrape_error", Help: "1 if there was an error while getting container metrics, 0 otherwise", }), containerMetrics: []containerMetric{ { name: "container_last_seen", help: "Last time a container was seen by the exporter", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{ value: float64(now.Now().Unix()), timestamp: now.Now(), }} }, }, { name: "container_health_state", help: "The result of the container's health check", valueType: prometheus.GaugeValue, getValues: getContainerHealthState, }, }, includedMetrics: includedMetrics, opts: opts, } if includedMetrics.Has(container.CpuUsageMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_cpu_user_seconds_total", help: "Cumulative user cpu time consumed in seconds.", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Cpu.Usage.User) / float64(time.Second), timestamp: s.Timestamp, }, } }, }, { name: "container_cpu_system_seconds_total", help: "Cumulative system cpu time consumed in seconds.", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Cpu.Usage.System) / float64(time.Second), timestamp: s.Timestamp, }, } }, }, { name: "container_cpu_usage_seconds_total", help: "Cumulative cpu time consumed in seconds.", valueType: prometheus.CounterValue, extraLabels: []string{"cpu"}, getValues: func(s *info.ContainerStats) metricValues { if len(s.Cpu.Usage.PerCpu) == 0 { if s.Cpu.Usage.Total > 0 { return metricValues{{ value: float64(s.Cpu.Usage.Total) / float64(time.Second), labels: []string{"total"}, timestamp: s.Timestamp, }} } } values := make(metricValues, 0, len(s.Cpu.Usage.PerCpu)) for i, value := range s.Cpu.Usage.PerCpu { if value > 0 { values = append(values, metricValue{ value: float64(value) / float64(time.Second), labels: []string{fmt.Sprintf("cpu%02d", i)}, timestamp: s.Timestamp, }) } } return values }, }, { name: "container_cpu_cfs_periods_total", help: "Number of elapsed enforcement period intervals.", valueType: prometheus.CounterValue, condition: func(s info.ContainerSpec) bool { return s.Cpu.Quota != 0 }, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Cpu.CFS.Periods), timestamp: s.Timestamp, }} }, }, { name: "container_cpu_cfs_throttled_periods_total", help: "Number of throttled period intervals.", valueType: prometheus.CounterValue, condition: func(s info.ContainerSpec) bool { return s.Cpu.Quota != 0 }, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Cpu.CFS.ThrottledPeriods), timestamp: s.Timestamp, }} }, }, { name: "container_cpu_cfs_throttled_seconds_total", help: "Total time duration the container has been throttled.", valueType: prometheus.CounterValue, condition: func(s info.ContainerSpec) bool { return s.Cpu.Quota != 0 }, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Cpu.CFS.ThrottledTime) / float64(time.Second), timestamp: s.Timestamp, }} }, }, { name: "container_cpu_cfs_burst_periods_total", help: "Number of periods when burst occurs.", valueType: prometheus.CounterValue, condition: func(s info.ContainerSpec) bool { return s.Cpu.Quota != 0 }, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Cpu.CFS.BurstsPeriods), timestamp: s.Timestamp, }} }, }, { name: "container_cpu_cfs_burst_seconds_total", help: "Total time duration the container has been bursted.", valueType: prometheus.CounterValue, condition: func(s info.ContainerSpec) bool { return s.Cpu.Quota != 0 }, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Cpu.CFS.BurstTime) / float64(time.Second), timestamp: s.Timestamp, }} }, }, }...) } if includedMetrics.Has(container.ProcessSchedulerMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_cpu_schedstat_run_seconds_total", help: "Time duration the processes of the container have run on the CPU.", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{ value: float64(s.Cpu.Schedstat.RunTime) / float64(time.Second), timestamp: s.Timestamp, }} }, }, { name: "container_cpu_schedstat_runqueue_seconds_total", help: "Time duration processes of the container have been waiting on a runqueue.", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{ value: float64(s.Cpu.Schedstat.RunqueueTime) / float64(time.Second), timestamp: s.Timestamp, }} }, }, { name: "container_cpu_schedstat_run_periods_total", help: "Number of times processes of the cgroup have run on the cpu", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{ value: float64(s.Cpu.Schedstat.RunPeriods), timestamp: s.Timestamp, }} }, }, }...) } if includedMetrics.Has(container.CpuLoadMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_cpu_load_average_10s", help: "Value of container cpu load average over the last 10 seconds.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Cpu.LoadAverage), timestamp: s.Timestamp}} }, }, { name: "container_cpu_load_d_average_10s", help: "Value of container cpu load.d average over the last 10 seconds.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Cpu.LoadDAverage), timestamp: s.Timestamp}} }, }, { name: "container_tasks_state", help: "Number of tasks in given state", extraLabels: []string{"state"}, valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.TaskStats.NrSleeping), labels: []string{"sleeping"}, timestamp: s.Timestamp, }, { value: float64(s.TaskStats.NrRunning), labels: []string{"running"}, timestamp: s.Timestamp, }, { value: float64(s.TaskStats.NrStopped), labels: []string{"stopped"}, timestamp: s.Timestamp, }, { value: float64(s.TaskStats.NrUninterruptible), labels: []string{"uninterruptible"}, timestamp: s.Timestamp, }, { value: float64(s.TaskStats.NrIoWait), labels: []string{"iowaiting"}, timestamp: s.Timestamp, }, } }, }, }...) } if includedMetrics.Has(container.HugetlbUsageMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_hugetlb_failcnt", help: "Number of hugepage usage hits limits", valueType: prometheus.CounterValue, extraLabels: []string{"pagesize"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Hugetlb)) for k, v := range s.Hugetlb { values = append(values, metricValue{ value: float64(v.Failcnt), labels: []string{k}, timestamp: s.Timestamp, }) } return values }, }, { name: "container_hugetlb_usage_bytes", help: "Current hugepage usage in bytes", valueType: prometheus.GaugeValue, extraLabels: []string{"pagesize"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Hugetlb)) for k, v := range s.Hugetlb { values = append(values, metricValue{ value: float64(v.Usage), labels: []string{k}, timestamp: s.Timestamp, }) } return values }, }, { name: "container_hugetlb_max_usage_bytes", help: "Maximum hugepage usage recorded in bytes", valueType: prometheus.GaugeValue, extraLabels: []string{"pagesize"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Hugetlb)) for k, v := range s.Hugetlb { values = append(values, metricValue{ value: float64(v.MaxUsage), labels: []string{k}, timestamp: s.Timestamp, }) } return values }, }, }...) } if includedMetrics.Has(container.MemoryUsageMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_memory_cache", help: "Number of bytes of page cache memory.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Memory.Cache), timestamp: s.Timestamp}} }, }, { name: "container_memory_rss", help: "Size of RSS in bytes.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Memory.RSS), timestamp: s.Timestamp}} }, }, { name: "container_memory_kernel_usage", help: "Size of kernel memory allocated in bytes.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Memory.KernelUsage), timestamp: s.Timestamp}} }, }, { name: "container_memory_mapped_file", help: "Size of memory mapped files in bytes.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Memory.MappedFile), timestamp: s.Timestamp}} }, }, { name: "container_memory_swap", help: "Container swap usage in bytes.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Memory.Swap), timestamp: s.Timestamp}} }, }, { name: "container_memory_failcnt", help: "Number of memory usage hits limits", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{ value: float64(s.Memory.Failcnt), timestamp: s.Timestamp, }} }, }, { name: "container_memory_usage_bytes", help: "Current memory usage in bytes, including all memory regardless of when it was accessed", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Memory.Usage), timestamp: s.Timestamp}} }, }, { name: "container_memory_max_usage_bytes", help: "Maximum memory usage recorded in bytes", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Memory.MaxUsage), timestamp: s.Timestamp}} }, }, { name: "container_memory_working_set_bytes", help: "Current working set in bytes.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Memory.WorkingSet), timestamp: s.Timestamp}} }, }, { name: "container_memory_total_active_file_bytes", help: "Current total active file in bytes.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Memory.TotalActiveFile), timestamp: s.Timestamp}} }, }, { name: "container_memory_total_inactive_file_bytes", help: "Current total inactive file in bytes.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Memory.TotalInactiveFile), timestamp: s.Timestamp}} }, }, { name: "container_memory_failures_total", help: "Cumulative count of memory allocation failures.", valueType: prometheus.CounterValue, extraLabels: []string{"failure_type", "scope"}, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Memory.ContainerData.Pgfault), labels: []string{"pgfault", "container"}, timestamp: s.Timestamp, }, { value: float64(s.Memory.ContainerData.Pgmajfault), labels: []string{"pgmajfault", "container"}, timestamp: s.Timestamp, }, { value: float64(s.Memory.HierarchicalData.Pgfault), labels: []string{"pgfault", "hierarchy"}, timestamp: s.Timestamp, }, { value: float64(s.Memory.HierarchicalData.Pgmajfault), labels: []string{"pgmajfault", "hierarchy"}, timestamp: s.Timestamp, }, } }, }, }...) } if includedMetrics.Has(container.CPUSetMetrics) { c.containerMetrics = append(c.containerMetrics, containerMetric{ name: "container_memory_migrate", help: "Memory migrate status.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.CpuSet.MemoryMigrate), timestamp: s.Timestamp}} }, }) } if includedMetrics.Has(container.MemoryNumaMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_memory_numa_pages", help: "Number of used pages per NUMA node", valueType: prometheus.GaugeValue, extraLabels: []string{"type", "scope", "node"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0) values = append(values, getNumaStatsPerNode(s.Memory.ContainerData.NumaStats.File, []string{"file", "container"}, s.Timestamp)...) values = append(values, getNumaStatsPerNode(s.Memory.ContainerData.NumaStats.Anon, []string{"anon", "container"}, s.Timestamp)...) values = append(values, getNumaStatsPerNode(s.Memory.ContainerData.NumaStats.Unevictable, []string{"unevictable", "container"}, s.Timestamp)...) values = append(values, getNumaStatsPerNode(s.Memory.HierarchicalData.NumaStats.File, []string{"file", "hierarchy"}, s.Timestamp)...) values = append(values, getNumaStatsPerNode(s.Memory.HierarchicalData.NumaStats.Anon, []string{"anon", "hierarchy"}, s.Timestamp)...) values = append(values, getNumaStatsPerNode(s.Memory.HierarchicalData.NumaStats.Unevictable, []string{"unevictable", "hierarchy"}, s.Timestamp)...) return values }, }, }...) } if includedMetrics.Has(container.DiskUsageMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_fs_inodes_free", help: "Number of available Inodes", valueType: prometheus.GaugeValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return fsValues(s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.InodesFree) }, s.Timestamp) }, }, { name: "container_fs_inodes_total", help: "Number of Inodes", valueType: prometheus.GaugeValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return fsValues(s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.Inodes) }, s.Timestamp) }, }, { name: "container_fs_limit_bytes", help: "Number of bytes that can be consumed by the container on this filesystem.", valueType: prometheus.GaugeValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return fsValues(s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.Limit) }, s.Timestamp) }, }, { name: "container_fs_usage_bytes", help: "Number of bytes that are consumed by the container on this filesystem.", valueType: prometheus.GaugeValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return fsValues(s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.Usage) }, s.Timestamp) }, }, }...) } if includedMetrics.Has(container.DiskIOMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_fs_reads_bytes_total", help: "Cumulative count of bytes read", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoServiceBytes, "Read", asFloat64, nil, nil, s.Timestamp, ) }, }, { name: "container_fs_reads_total", help: "Cumulative count of reads completed", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoServiced, "Read", asFloat64, s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.ReadsCompleted) }, s.Timestamp, ) }, }, { name: "container_fs_sector_reads_total", help: "Cumulative count of sector reads completed", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.Sectors, "Read", asFloat64, s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.SectorsRead) }, s.Timestamp, ) }, }, { name: "container_fs_reads_merged_total", help: "Cumulative count of reads merged", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoMerged, "Read", asFloat64, s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.ReadsMerged) }, s.Timestamp, ) }, }, { name: "container_fs_read_seconds_total", help: "Cumulative count of seconds spent reading", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoServiceTime, "Read", asNanosecondsToSeconds, s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.ReadTime) / float64(time.Second) }, s.Timestamp, ) }, }, { name: "container_fs_writes_bytes_total", help: "Cumulative count of bytes written", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoServiceBytes, "Write", asFloat64, nil, nil, s.Timestamp, ) }, }, { name: "container_fs_writes_total", help: "Cumulative count of writes completed", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoServiced, "Write", asFloat64, s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.WritesCompleted) }, s.Timestamp, ) }, }, { name: "container_fs_sector_writes_total", help: "Cumulative count of sector writes completed", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.Sectors, "Write", asFloat64, s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.SectorsWritten) }, s.Timestamp, ) }, }, { name: "container_fs_writes_merged_total", help: "Cumulative count of writes merged", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoMerged, "Write", asFloat64, s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.WritesMerged) }, s.Timestamp, ) }, }, { name: "container_fs_write_seconds_total", help: "Cumulative count of seconds spent writing", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoServiceTime, "Write", asNanosecondsToSeconds, s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.WriteTime) / float64(time.Second) }, s.Timestamp, ) }, }, { name: "container_fs_io_current", help: "Number of I/Os currently in progress", valueType: prometheus.GaugeValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoQueued, "Total", asFloat64, s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.IoInProgress) }, s.Timestamp, ) }, }, { name: "container_fs_io_time_seconds_total", help: "Cumulative count of seconds spent doing I/Os", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoServiceTime, "Total", asNanosecondsToSeconds, s.Filesystem, func(fs *info.FsStats) float64 { return float64(float64(fs.IoTime) / float64(time.Second)) }, s.Timestamp, ) }, }, { name: "container_fs_io_time_weighted_seconds_total", help: "Cumulative weighted I/O time in seconds", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return fsValues(s.Filesystem, func(fs *info.FsStats) float64 { return float64(fs.WeightedIoTime) / float64(time.Second) }, s.Timestamp) }, }, { name: "container_fs_io_cost_usage_seconds_total", help: "Cumulative IOCost usage in seconds", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoCostUsage, "Count", asMicrosecondsToSeconds, []info.FsStats{}, nil, s.Timestamp, ) }, }, { name: "container_fs_io_cost_wait_seconds_total", help: "Cumulative IOCost wait in seconds", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoCostWait, "Count", asMicrosecondsToSeconds, []info.FsStats{}, nil, s.Timestamp, ) }, }, { name: "container_fs_io_cost_indebt_seconds_total", help: "Cumulative IOCost debt in seconds", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoCostIndebt, "Count", asMicrosecondsToSeconds, []info.FsStats{}, nil, s.Timestamp, ) }, }, { name: "container_fs_io_cost_indelay_seconds_total", help: "Cumulative IOCost delay in seconds", valueType: prometheus.CounterValue, extraLabels: []string{"device"}, getValues: func(s *info.ContainerStats) metricValues { return ioValues( s.DiskIo.IoCostIndelay, "Count", asMicrosecondsToSeconds, []info.FsStats{}, nil, s.Timestamp, ) }, }, { name: "container_blkio_device_usage_total", help: "Blkio Device bytes usage", valueType: prometheus.CounterValue, extraLabels: []string{"device", "major", "minor", "operation"}, getValues: func(s *info.ContainerStats) metricValues { var values metricValues for _, diskStat := range s.DiskIo.IoServiceBytes { for operation, value := range diskStat.Stats { values = append(values, metricValue{ value: float64(value), labels: []string{diskStat.Device, strconv.Itoa(int(diskStat.Major)), strconv.Itoa(int(diskStat.Minor)), operation}, timestamp: s.Timestamp, }) } } return values }, }, }...) } if includedMetrics.Has(container.NetworkUsageMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_network_receive_bytes_total", help: "Cumulative count of bytes received", valueType: prometheus.CounterValue, extraLabels: []string{"interface"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Network.Interfaces)) for _, value := range s.Network.Interfaces { values = append(values, metricValue{ value: float64(value.RxBytes), labels: []string{value.Name}, timestamp: s.Timestamp, }) } return values }, }, { name: "container_network_receive_packets_total", help: "Cumulative count of packets received", valueType: prometheus.CounterValue, extraLabels: []string{"interface"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Network.Interfaces)) for _, value := range s.Network.Interfaces { values = append(values, metricValue{ value: float64(value.RxPackets), labels: []string{value.Name}, timestamp: s.Timestamp, }) } return values }, }, { name: "container_network_receive_packets_dropped_total", help: "Cumulative count of packets dropped while receiving", valueType: prometheus.CounterValue, extraLabels: []string{"interface"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Network.Interfaces)) for _, value := range s.Network.Interfaces { values = append(values, metricValue{ value: float64(value.RxDropped), labels: []string{value.Name}, timestamp: s.Timestamp, }) } return values }, }, { name: "container_network_receive_errors_total", help: "Cumulative count of errors encountered while receiving", valueType: prometheus.CounterValue, extraLabels: []string{"interface"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Network.Interfaces)) for _, value := range s.Network.Interfaces { values = append(values, metricValue{ value: float64(value.RxErrors), labels: []string{value.Name}, timestamp: s.Timestamp, }) } return values }, }, { name: "container_network_transmit_bytes_total", help: "Cumulative count of bytes transmitted", valueType: prometheus.CounterValue, extraLabels: []string{"interface"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Network.Interfaces)) for _, value := range s.Network.Interfaces { values = append(values, metricValue{ value: float64(value.TxBytes), labels: []string{value.Name}, timestamp: s.Timestamp, }) } return values }, }, { name: "container_network_transmit_packets_total", help: "Cumulative count of packets transmitted", valueType: prometheus.CounterValue, extraLabels: []string{"interface"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Network.Interfaces)) for _, value := range s.Network.Interfaces { values = append(values, metricValue{ value: float64(value.TxPackets), labels: []string{value.Name}, timestamp: s.Timestamp, }) } return values }, }, { name: "container_network_transmit_packets_dropped_total", help: "Cumulative count of packets dropped while transmitting", valueType: prometheus.CounterValue, extraLabels: []string{"interface"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Network.Interfaces)) for _, value := range s.Network.Interfaces { values = append(values, metricValue{ value: float64(value.TxDropped), labels: []string{value.Name}, timestamp: s.Timestamp, }) } return values }, }, { name: "container_network_transmit_errors_total", help: "Cumulative count of errors encountered while transmitting", valueType: prometheus.CounterValue, extraLabels: []string{"interface"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Network.Interfaces)) for _, value := range s.Network.Interfaces { values = append(values, metricValue{ value: float64(value.TxErrors), labels: []string{value.Name}, timestamp: s.Timestamp, }) } return values }, }, }...) } if includedMetrics.Has(container.NetworkTcpUsageMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_network_tcp_usage_total", help: "tcp connection usage statistic for container", valueType: prometheus.GaugeValue, extraLabels: []string{"tcp_state"}, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Network.Tcp.Established), labels: []string{"established"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp.SynSent), labels: []string{"synsent"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp.SynRecv), labels: []string{"synrecv"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp.FinWait1), labels: []string{"finwait1"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp.FinWait2), labels: []string{"finwait2"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp.TimeWait), labels: []string{"timewait"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp.Close), labels: []string{"close"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp.CloseWait), labels: []string{"closewait"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp.LastAck), labels: []string{"lastack"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp.Listen), labels: []string{"listen"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp.Closing), labels: []string{"closing"}, timestamp: s.Timestamp, }, } }, }, }...) c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_network_tcp6_usage_total", help: "tcp6 connection usage statistic for container", valueType: prometheus.GaugeValue, extraLabels: []string{"tcp_state"}, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Network.Tcp6.Established), labels: []string{"established"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp6.SynSent), labels: []string{"synsent"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp6.SynRecv), labels: []string{"synrecv"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp6.FinWait1), labels: []string{"finwait1"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp6.FinWait2), labels: []string{"finwait2"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp6.TimeWait), labels: []string{"timewait"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp6.Close), labels: []string{"close"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp6.CloseWait), labels: []string{"closewait"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp6.LastAck), labels: []string{"lastack"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp6.Listen), labels: []string{"listen"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Tcp6.Closing), labels: []string{"closing"}, timestamp: s.Timestamp, }, } }, }, }...) } if includedMetrics.Has(container.NetworkAdvancedTcpUsageMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_network_advance_tcp_stats_total", help: "advance tcp connections statistic for container", valueType: prometheus.GaugeValue, extraLabels: []string{"tcp_state"}, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Network.TcpAdvanced.RtoAlgorithm), labels: []string{"rtoalgorithm"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.RtoMin), labels: []string{"rtomin"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.RtoMax), labels: []string{"rtomax"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.MaxConn), labels: []string{"maxconn"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.ActiveOpens), labels: []string{"activeopens"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.PassiveOpens), labels: []string{"passiveopens"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.AttemptFails), labels: []string{"attemptfails"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.EstabResets), labels: []string{"estabresets"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.CurrEstab), labels: []string{"currestab"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.InSegs), labels: []string{"insegs"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.OutSegs), labels: []string{"outsegs"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.RetransSegs), labels: []string{"retranssegs"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.InErrs), labels: []string{"inerrs"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.OutRsts), labels: []string{"outrsts"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.InCsumErrors), labels: []string{"incsumerrors"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.EmbryonicRsts), labels: []string{"embryonicrsts"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.SyncookiesSent), labels: []string{"syncookiessent"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.SyncookiesRecv), labels: []string{"syncookiesrecv"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.SyncookiesFailed), labels: []string{"syncookiesfailed"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.PruneCalled), labels: []string{"prunecalled"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.RcvPruned), labels: []string{"rcvpruned"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.OfoPruned), labels: []string{"ofopruned"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.OutOfWindowIcmps), labels: []string{"outofwindowicmps"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.LockDroppedIcmps), labels: []string{"lockdroppedicmps"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TW), labels: []string{"tw"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TWRecycled), labels: []string{"twrecycled"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TWKilled), labels: []string{"twkilled"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPTimeWaitOverflow), labels: []string{"tcptimewaitoverflow"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPTimeouts), labels: []string{"tcptimeouts"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSpuriousRTOs), labels: []string{"tcpspuriousrtos"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPLossProbes), labels: []string{"tcplossprobes"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPLossProbeRecovery), labels: []string{"tcplossproberecovery"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPRenoRecoveryFail), labels: []string{"tcprenorecoveryfail"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSackRecoveryFail), labels: []string{"tcpsackrecoveryfail"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPRenoFailures), labels: []string{"tcprenofailures"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSackFailures), labels: []string{"tcpsackfailures"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPLossFailures), labels: []string{"tcplossfailures"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.DelayedACKs), labels: []string{"delayedacks"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.DelayedACKLocked), labels: []string{"delayedacklocked"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.DelayedACKLost), labels: []string{"delayedacklost"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.ListenOverflows), labels: []string{"listenoverflows"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.ListenDrops), labels: []string{"listendrops"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPHPHits), labels: []string{"tcphphits"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPPureAcks), labels: []string{"tcppureacks"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPHPAcks), labels: []string{"tcphpacks"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPRenoRecovery), labels: []string{"tcprenorecovery"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSackRecovery), labels: []string{"tcpsackrecovery"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSACKReneging), labels: []string{"tcpsackreneging"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPFACKReorder), labels: []string{"tcpfackreorder"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSACKReorder), labels: []string{"tcpsackreorder"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPRenoReorder), labels: []string{"tcprenoreorder"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPTSReorder), labels: []string{"tcptsreorder"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPFullUndo), labels: []string{"tcpfullundo"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPPartialUndo), labels: []string{"tcppartialundo"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPDSACKUndo), labels: []string{"tcpdsackundo"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPLossUndo), labels: []string{"tcplossundo"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPFastRetrans), labels: []string{"tcpfastretrans"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSlowStartRetrans), labels: []string{"tcpslowstartretrans"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPLostRetransmit), labels: []string{"tcplostretransmit"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPRetransFail), labels: []string{"tcpretransfail"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPRcvCollapsed), labels: []string{"tcprcvcollapsed"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPDSACKOldSent), labels: []string{"tcpdsackoldsent"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPDSACKOfoSent), labels: []string{"tcpdsackofosent"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPDSACKRecv), labels: []string{"tcpdsackrecv"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPDSACKOfoRecv), labels: []string{"tcpdsackoforecv"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPAbortOnData), labels: []string{"tcpabortondata"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPAbortOnClose), labels: []string{"tcpabortonclose"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPAbortOnMemory), labels: []string{"tcpabortonmemory"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPAbortOnTimeout), labels: []string{"tcpabortontimeout"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPAbortOnLinger), labels: []string{"tcpabortonlinger"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPAbortFailed), labels: []string{"tcpabortfailed"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPMemoryPressures), labels: []string{"tcpmemorypressures"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPMemoryPressuresChrono), labels: []string{"tcpmemorypressureschrono"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSACKDiscard), labels: []string{"tcpsackdiscard"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPDSACKIgnoredOld), labels: []string{"tcpdsackignoredold"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPDSACKIgnoredNoUndo), labels: []string{"tcpdsackignorednoundo"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPMD5NotFound), labels: []string{"tcpmd5notfound"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPMD5Unexpected), labels: []string{"tcpmd5unexpected"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPMD5Failure), labels: []string{"tcpmd5failure"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSackShifted), labels: []string{"tcpsackshifted"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSackMerged), labels: []string{"tcpsackmerged"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSackShiftFallback), labels: []string{"tcpsackshiftfallback"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPBacklogDrop), labels: []string{"tcpbacklogdrop"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.PFMemallocDrop), labels: []string{"pfmemallocdrop"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPMinTTLDrop), labels: []string{"tcpminttldrop"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPDeferAcceptDrop), labels: []string{"tcpdeferacceptdrop"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.IPReversePathFilter), labels: []string{"ipreversepathfilter"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPReqQFullDoCookies), labels: []string{"tcpreqqfulldocookies"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPReqQFullDrop), labels: []string{"tcpreqqfulldrop"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPFastOpenActive), labels: []string{"tcpfastopenactive"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPFastOpenActiveFail), labels: []string{"tcpfastopenactivefail"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPFastOpenPassive), labels: []string{"tcpfastopenpassive"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPFastOpenPassiveFail), labels: []string{"tcpfastopenpassivefail"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPFastOpenListenOverflow), labels: []string{"tcpfastopenlistenoverflow"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPFastOpenCookieReqd), labels: []string{"tcpfastopencookiereqd"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPSynRetrans), labels: []string{"tcpsynretrans"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.TCPOrigDataSent), labels: []string{"tcporigdatasent"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.PAWSActive), labels: []string{"pawsactive"}, timestamp: s.Timestamp, }, { value: float64(s.Network.TcpAdvanced.PAWSEstab), labels: []string{"pawsestab"}, timestamp: s.Timestamp, }, } }, }, }...) } if includedMetrics.Has(container.NetworkUdpUsageMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_network_udp6_usage_total", help: "udp6 connection usage statistic for container", valueType: prometheus.GaugeValue, extraLabels: []string{"udp_state"}, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Network.Udp6.Listen), labels: []string{"listen"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Udp6.Dropped), labels: []string{"dropped"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Udp6.RxQueued), labels: []string{"rxqueued"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Udp6.TxQueued), labels: []string{"txqueued"}, timestamp: s.Timestamp, }, } }, }, }...) c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_network_udp_usage_total", help: "udp connection usage statistic for container", valueType: prometheus.GaugeValue, extraLabels: []string{"udp_state"}, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Network.Udp.Listen), labels: []string{"listen"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Udp.Dropped), labels: []string{"dropped"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Udp.RxQueued), labels: []string{"rxqueued"}, timestamp: s.Timestamp, }, { value: float64(s.Network.Udp.TxQueued), labels: []string{"txqueued"}, timestamp: s.Timestamp, }, } }, }, }...) } if includedMetrics.Has(container.ProcessMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_processes", help: "Number of processes running inside the container.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Processes.ProcessCount), timestamp: s.Timestamp}} }, }, { name: "container_file_descriptors", help: "Number of open file descriptors for the container.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Processes.FdCount), timestamp: s.Timestamp}} }, }, { name: "container_sockets", help: "Number of open sockets for the container.", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.Processes.SocketCount), timestamp: s.Timestamp}} }, }, { name: "container_threads_max", help: "Maximum number of threads allowed inside the container, infinity if value is zero", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Processes.ThreadsMax), timestamp: s.Timestamp, }, } }, }, { name: "container_threads", help: "Number of threads running inside the container", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{ { value: float64(s.Processes.ThreadsCurrent), timestamp: s.Timestamp, }, } }, }, { name: "container_ulimits_soft", help: "Soft ulimit values for the container root process. Unlimited if -1, except priority and nice", valueType: prometheus.GaugeValue, extraLabels: []string{"ulimit"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.Processes.Ulimits)) for _, ulimit := range s.Processes.Ulimits { values = append(values, metricValue{ value: float64(ulimit.SoftLimit), labels: []string{ulimit.Name}, timestamp: s.Timestamp, }) } return values }, }, }...) } if includedMetrics.Has(container.PerfMetrics) { if includedMetrics.Has(container.PerCpuUsageMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_perf_events_total", help: "Perf event metric.", valueType: prometheus.CounterValue, extraLabels: []string{"cpu", "event"}, getValues: func(s *info.ContainerStats) metricValues { return getPerCPUCorePerfEvents(s) }, }, { name: "container_perf_events_scaling_ratio", help: "Perf event metric scaling ratio.", valueType: prometheus.GaugeValue, extraLabels: []string{"cpu", "event"}, getValues: func(s *info.ContainerStats) metricValues { return getPerCPUCoreScalingRatio(s) }, }}...) } else { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_perf_events_total", help: "Perf event metric.", valueType: prometheus.CounterValue, extraLabels: []string{"cpu", "event"}, getValues: func(s *info.ContainerStats) metricValues { return getAggregatedCorePerfEvents(s) }, }, { name: "container_perf_events_scaling_ratio", help: "Perf event metric scaling ratio.", valueType: prometheus.GaugeValue, extraLabels: []string{"cpu", "event"}, getValues: func(s *info.ContainerStats) metricValues { return getMinCoreScalingRatio(s) }, }}...) } c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_perf_uncore_events_total", help: "Perf uncore event metric.", valueType: prometheus.CounterValue, extraLabels: []string{"socket", "event", "pmu"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.PerfUncoreStats)) for _, metric := range s.PerfUncoreStats { values = append(values, metricValue{ value: float64(metric.Value), labels: []string{strconv.Itoa(metric.Socket), metric.Name, metric.PMU}, timestamp: s.Timestamp, }) } return values }, }, { name: "container_perf_uncore_events_scaling_ratio", help: "Perf uncore event metric scaling ratio.", valueType: prometheus.GaugeValue, extraLabels: []string{"socket", "event", "pmu"}, getValues: func(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.PerfUncoreStats)) for _, metric := range s.PerfUncoreStats { values = append(values, metricValue{ value: metric.ScalingRatio, labels: []string{strconv.Itoa(metric.Socket), metric.Name, metric.PMU}, timestamp: s.Timestamp, }) } return values }, }, }...) } if includedMetrics.Has(container.ReferencedMemoryMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_referenced_bytes", help: "Container referenced bytes during last measurements cycle", valueType: prometheus.GaugeValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.ReferencedMemory), timestamp: s.Timestamp}} }, }, }...) } if includedMetrics.Has(container.ResctrlMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_memory_bandwidth_bytes", help: "Total memory bandwidth usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM).", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusNodeLabelName}, getValues: func(s *info.ContainerStats) metricValues { numberOfNUMANodes := len(s.Resctrl.MemoryBandwidth) metrics := make(metricValues, numberOfNUMANodes) for numaNode, stats := range s.Resctrl.MemoryBandwidth { metrics[numaNode] = metricValue{ value: float64(stats.TotalBytes), timestamp: s.Timestamp, labels: []string{strconv.Itoa(numaNode)}, } } return metrics }, }, { name: "container_memory_bandwidth_local_bytes", help: "Local memory bandwidth usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM).", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusNodeLabelName}, getValues: func(s *info.ContainerStats) metricValues { numberOfNUMANodes := len(s.Resctrl.MemoryBandwidth) metrics := make(metricValues, numberOfNUMANodes) for numaNode, stats := range s.Resctrl.MemoryBandwidth { metrics[numaNode] = metricValue{ value: float64(stats.LocalBytes), timestamp: s.Timestamp, labels: []string{strconv.Itoa(numaNode)}, } } return metrics }, }, { name: "container_llc_occupancy_bytes", help: "Last level cache usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM).", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusNodeLabelName}, getValues: func(s *info.ContainerStats) metricValues { numberOfNUMANodes := len(s.Resctrl.Cache) metrics := make(metricValues, numberOfNUMANodes) for numaNode, stats := range s.Resctrl.Cache { metrics[numaNode] = metricValue{ value: float64(stats.LLCOccupancy), timestamp: s.Timestamp, labels: []string{strconv.Itoa(numaNode)}, } } return metrics }, }, }...) } if includedMetrics.Has(container.OOMMetrics) { c.containerMetrics = append(c.containerMetrics, containerMetric{ name: "container_oom_events_total", help: "Count of out of memory events observed for the container", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: float64(s.OOMEvents), timestamp: s.Timestamp}} }, }) } if includedMetrics.Has(container.PressureMetrics) { c.containerMetrics = append(c.containerMetrics, []containerMetric{ { name: "container_pressure_cpu_stalled_seconds_total", help: "Total time duration no tasks in the container could make progress due to CPU congestion.", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: asMicrosecondsToSeconds(s.Cpu.PSI.Full.Total), timestamp: s.Timestamp}} }, }, { name: "container_pressure_cpu_waiting_seconds_total", help: "Total time duration tasks in the container have waited due to CPU congestion.", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: asMicrosecondsToSeconds(s.Cpu.PSI.Some.Total), timestamp: s.Timestamp}} }, }, { name: "container_pressure_memory_stalled_seconds_total", help: "Total time duration no tasks in the container could make progress due to memory congestion.", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: asMicrosecondsToSeconds(s.Memory.PSI.Full.Total), timestamp: s.Timestamp}} }, }, { name: "container_pressure_memory_waiting_seconds_total", help: "Total time duration tasks in the container have waited due to memory congestion.", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: asMicrosecondsToSeconds(s.Memory.PSI.Some.Total), timestamp: s.Timestamp}} }, }, { name: "container_pressure_io_stalled_seconds_total", help: "Total time duration no tasks in the container could make progress due to IO congestion.", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: asMicrosecondsToSeconds(s.DiskIo.PSI.Full.Total), timestamp: s.Timestamp}} }, }, { name: "container_pressure_io_waiting_seconds_total", help: "Total time duration tasks in the container have waited due to IO congestion.", valueType: prometheus.CounterValue, getValues: func(s *info.ContainerStats) metricValues { return metricValues{{value: asMicrosecondsToSeconds(s.DiskIo.PSI.Some.Total), timestamp: s.Timestamp}} }, }, }...) } return c } var ( versionInfoDesc = prometheus.NewDesc("cadvisor_version_info", "A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision.", []string{"kernelVersion", "osVersion", "dockerVersion", "cadvisorVersion", "cadvisorRevision"}, nil) creationTimeDesc = prometheus.NewDesc("container_creation_time_seconds", "Container creation time since unix epoch in seconds.", nil, nil) startTimeDesc = prometheus.NewDesc("container_start_time_seconds", "Start time of the container since unix epoch in seconds.", nil, nil) cpuPeriodDesc = prometheus.NewDesc("container_spec_cpu_period", "CPU period of the container.", nil, nil) cpuQuotaDesc = prometheus.NewDesc("container_spec_cpu_quota", "CPU quota of the container.", nil, nil) cpuSharesDesc = prometheus.NewDesc("container_spec_cpu_shares", "CPU share of the container.", nil, nil) ) // Describe describes all the metrics ever exported by cadvisor. It // implements prometheus.PrometheusCollector. func (c *PrometheusCollector) Describe(ch chan<- *prometheus.Desc) { c.errors.Describe(ch) for _, cm := range c.containerMetrics { ch <- cm.desc([]string{}) } ch <- creationTimeDesc ch <- startTimeDesc ch <- cpuPeriodDesc ch <- cpuQuotaDesc ch <- cpuSharesDesc ch <- versionInfoDesc } // Collect fetches the stats from all containers and delivers them as // Prometheus metrics. It implements prometheus.PrometheusCollector. func (c *PrometheusCollector) Collect(ch chan<- prometheus.Metric) { c.errors.Set(0) c.collectVersionInfo(ch) c.collectContainersInfo(ch) c.errors.Collect(ch) } const ( // ContainerLabelPrefix is the prefix added to all container labels. ContainerLabelPrefix = "container_label_" // ContainerEnvPrefix is the prefix added to all env variable labels. ContainerEnvPrefix = "container_env_" // LabelID is the name of the id label. LabelID = "id" // LabelName is the name of the name label. LabelName = "name" // LabelImage is the name of the image label. LabelImage = "image" ) // DefaultContainerLabels implements ContainerLabelsFunc. It exports the // container name, first alias, image name as well as all its env and label // values. func DefaultContainerLabels(container *info.ContainerInfo) map[string]string { set := map[string]string{LabelID: container.Name} if len(container.Aliases) > 0 { set[LabelName] = container.Aliases[0] } if image := container.Spec.Image; len(image) > 0 { set[LabelImage] = image } for k, v := range container.Spec.Labels { set[ContainerLabelPrefix+k] = v } for k, v := range container.Spec.Envs { set[ContainerEnvPrefix+k] = v } return set } // BaseContainerLabels returns a ContainerLabelsFunc that exports the container // name, first alias, image name as well as all its white listed env and label values. func BaseContainerLabels(whiteList []string) func(container *info.ContainerInfo) map[string]string { whiteListMap := make(map[string]struct{}, len(whiteList)) for _, k := range whiteList { whiteListMap[k] = struct{}{} } return func(container *info.ContainerInfo) map[string]string { set := map[string]string{LabelID: container.Name} if len(container.Aliases) > 0 { set[LabelName] = container.Aliases[0] } if image := container.Spec.Image; len(image) > 0 { set[LabelImage] = image } for k, v := range container.Spec.Labels { if _, ok := whiteListMap[k]; ok { set[ContainerLabelPrefix+k] = v } } for k, v := range container.Spec.Envs { set[ContainerEnvPrefix+k] = v } return set } } func (c *PrometheusCollector) collectContainersInfo(ch chan<- prometheus.Metric) { containers, err := c.infoProvider.GetRequestedContainersInfo("/", c.opts) if err != nil { c.errors.Set(1) klog.Warningf("Couldn't get containers: %s", err) return } rawLabels := map[string]struct{}{} for _, container := range containers { for l := range c.containerLabelsFunc(container) { rawLabels[l] = struct{}{} } } for _, cont := range containers { values := make([]string, 0, len(rawLabels)) labels := make([]string, 0, len(rawLabels)) containerLabels := c.containerLabelsFunc(cont) for l := range rawLabels { duplicate := false sl := sanitizeLabelName(l) for _, x := range labels { if sl == x { duplicate = true break } } if !duplicate { labels = append(labels, sl) values = append(values, containerLabels[l]) } } // Container spec desc := prometheus.NewDesc("container_creation_time_seconds", "Container creation time since unix epoch in seconds.", labels, nil) ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(cont.Spec.CreationTime.Unix()), values...) desc = prometheus.NewDesc("container_start_time_seconds", "Start time of the container since unix epoch in seconds.", labels, nil) startTime := cont.Spec.CreationTime if !cont.Spec.StartTime.IsZero() { startTime = cont.Spec.StartTime } ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(startTime.Unix()), values...) if cont.Spec.HasCpu { desc = prometheus.NewDesc("container_spec_cpu_period", "CPU period of the container.", labels, nil) ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(cont.Spec.Cpu.Period), values...) if cont.Spec.Cpu.Quota != 0 { desc = prometheus.NewDesc("container_spec_cpu_quota", "CPU quota of the container.", labels, nil) ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(cont.Spec.Cpu.Quota), values...) } desc := prometheus.NewDesc("container_spec_cpu_shares", "CPU share of the container.", labels, nil) ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(cont.Spec.Cpu.Limit), values...) } if cont.Spec.HasMemory { desc := prometheus.NewDesc("container_spec_memory_limit_bytes", "Memory limit for the container.", labels, nil) ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, specMemoryValue(cont.Spec.Memory.Limit), values...) desc = prometheus.NewDesc("container_spec_memory_swap_limit_bytes", "Memory swap limit for the container.", labels, nil) ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, specMemoryValue(cont.Spec.Memory.SwapLimit), values...) desc = prometheus.NewDesc("container_spec_memory_reservation_limit_bytes", "Memory reservation limit for the container.", labels, nil) ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, specMemoryValue(cont.Spec.Memory.Reservation), values...) } // Now for the actual metrics if len(cont.Stats) == 0 { continue } stats := cont.Stats[0] for _, cm := range c.containerMetrics { if cm.condition != nil && !cm.condition(cont.Spec) { continue } desc := cm.desc(labels) for _, metricValue := range cm.getValues(stats) { ch <- prometheus.NewMetricWithTimestamp( metricValue.timestamp, prometheus.MustNewConstMetric(desc, cm.valueType, float64(metricValue.value), append(values, metricValue.labels...)...), ) } } if c.includedMetrics.Has(container.AppMetrics) { for metricLabel, v := range stats.CustomMetrics { for _, metric := range v { clabels := make([]string, len(rawLabels), len(rawLabels)+len(metric.Labels)) cvalues := make([]string, len(rawLabels), len(rawLabels)+len(metric.Labels)) copy(clabels, labels) copy(cvalues, values) for label, value := range metric.Labels { clabels = append(clabels, sanitizeLabelName("app_"+label)) cvalues = append(cvalues, value) } desc := prometheus.NewDesc(metricLabel, "Custom application metric.", clabels, nil) ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(metric.FloatValue), cvalues...) } } } } } func (c *PrometheusCollector) collectVersionInfo(ch chan<- prometheus.Metric) { versionInfo, err := c.infoProvider.GetVersionInfo() if err != nil { c.errors.Set(1) klog.Warningf("Couldn't get version info: %s", err) return } ch <- prometheus.MustNewConstMetric(versionInfoDesc, prometheus.GaugeValue, 1, []string{versionInfo.KernelVersion, versionInfo.ContainerOsVersion, versionInfo.DockerVersion, versionInfo.CadvisorVersion, versionInfo.CadvisorRevision}...) } // Size after which we consider memory to be "unlimited". This is not // MaxInt64 due to rounding by the kernel. const maxMemorySize = uint64(1 << 62) func specMemoryValue(v uint64) float64 { if v > maxMemorySize { return 0 } return float64(v) } var invalidNameCharRE = regexp.MustCompile(`[^a-zA-Z0-9_]`) // sanitizeLabelName replaces anything that doesn't match // client_label.LabelNameRE with an underscore. func sanitizeLabelName(name string) string { return invalidNameCharRE.ReplaceAllString(name, "_") } func getNumaStatsPerNode(nodeStats map[uint8]uint64, labels []string, timestamp time.Time) metricValues { mValues := make(metricValues, 0, len(nodeStats)) for node, stat := range nodeStats { nodeLabels := append(labels, strconv.FormatUint(uint64(node), 10)) mValues = append(mValues, metricValue{value: float64(stat), labels: nodeLabels, timestamp: timestamp}) } return mValues } func getPerCPUCorePerfEvents(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.PerfStats)) for _, metric := range s.PerfStats { values = append(values, metricValue{ value: float64(metric.Value), labels: []string{strconv.Itoa(metric.Cpu), metric.Name}, timestamp: s.Timestamp, }) } return values } func getPerCPUCoreScalingRatio(s *info.ContainerStats) metricValues { values := make(metricValues, 0, len(s.PerfStats)) for _, metric := range s.PerfStats { values = append(values, metricValue{ value: metric.ScalingRatio, labels: []string{strconv.Itoa(metric.Cpu), metric.Name}, timestamp: s.Timestamp, }) } return values } func getAggregatedCorePerfEvents(s *info.ContainerStats) metricValues { values := make(metricValues, 0) perfEventStatAgg := make(map[string]uint64) // aggregate by event for _, perfStat := range s.PerfStats { perfEventStatAgg[perfStat.Name] += perfStat.Value } // create aggregated metrics for perfEvent, perfValue := range perfEventStatAgg { values = append(values, metricValue{ value: float64(perfValue), labels: []string{"", perfEvent}, timestamp: s.Timestamp, }) } return values } func getMinCoreScalingRatio(s *info.ContainerStats) metricValues { values := make(metricValues, 0) perfEventStatMin := make(map[string]float64) // search for minimal value of scalin ratio for specific event for _, perfStat := range s.PerfStats { if _, ok := perfEventStatMin[perfStat.Name]; !ok { // found a new event perfEventStatMin[perfStat.Name] = perfStat.ScalingRatio } else if perfStat.ScalingRatio < perfEventStatMin[perfStat.Name] { // found a lower value of scaling ration so replace the minimal value perfEventStatMin[perfStat.Name] = perfStat.ScalingRatio } } for perfEvent, perfScalingRatio := range perfEventStatMin { values = append(values, metricValue{ value: perfScalingRatio, labels: []string{"", perfEvent}, timestamp: s.Timestamp, }) } return values } func getContainerHealthState(s *info.ContainerStats) metricValues { value := float64(0) switch s.Health.Status { case "healthy": value = 1 case "": // if container has no health check defined value = -1 default: // starting or unhealthy } return metricValues{{ value: value, timestamp: s.Timestamp, }} } ================================================ FILE: metrics/prometheus_fake.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package metrics import ( "errors" "time" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" ) type testSubcontainersInfoProvider struct{} func (p testSubcontainersInfoProvider) GetVersionInfo() (*info.VersionInfo, error) { return &info.VersionInfo{ KernelVersion: "4.1.6-200.fc22.x86_64", ContainerOsVersion: "Fedora 22 (Twenty Two)", DockerVersion: "1.8.1", CadvisorVersion: "0.16.0", CadvisorRevision: "abcdef", }, nil } func (p testSubcontainersInfoProvider) GetMachineInfo() (*info.MachineInfo, error) { return &info.MachineInfo{ Timestamp: time.Unix(1395066363, 0), NumCores: 4, NumPhysicalCores: 1, NumSockets: 1, MemoryCapacity: 1024, MemoryByType: map[string]*info.MemoryInfo{ "Non-volatile-RAM": {Capacity: 2168421613568, DimmCount: 8}, "Unbuffered-DDR4": {Capacity: 412316860416, DimmCount: 12}, }, NVMInfo: info.NVMInfo{ MemoryModeCapacity: 429496729600, AppDirectModeCapacity: 1735166787584, }, MachineID: "machine-id-test", SystemUUID: "system-uuid-test", BootID: "boot-id-test", Topology: []info.Node{ { Id: 0, Memory: 33604804608, HugePages: []info.HugePagesInfo{ { PageSize: uint64(1048576), NumPages: uint64(0), }, { PageSize: uint64(2048), NumPages: uint64(0), }, }, Cores: []info.Core{ { Id: 0, Threads: []int{0, 1}, Caches: []info.Cache{ { Size: 32768, Type: "Data", Level: 1, }, { Size: 32768, Type: "Instruction", Level: 1, }, { Size: 262144, Type: "Unified", Level: 2, }, }, }, { Id: 1, Threads: []int{2, 3}, Caches: []info.Cache{ { Size: 32764, Type: "Data", Level: 1, }, { Size: 32764, Type: "Instruction", Level: 1, }, { Size: 262148, Type: "Unified", Level: 2, }, }, }, { Id: 2, Threads: []int{4, 5}, Caches: []info.Cache{ { Size: 32768, Type: "Data", Level: 1, }, { Size: 32768, Type: "Instruction", Level: 1, }, { Size: 262144, Type: "Unified", Level: 2, }, }, }, { Id: 3, Threads: []int{6, 7}, Caches: []info.Cache{ { Size: 32764, Type: "Data", Level: 1, }, { Size: 32764, Type: "Instruction", Level: 1, }, { Size: 262148, Type: "Unified", Level: 2, }, }, }, }, Distances: []uint64{ 10, 12, }, }, { Id: 1, Memory: 33604804606, HugePages: []info.HugePagesInfo{ { PageSize: uint64(1048576), NumPages: uint64(2), }, { PageSize: uint64(2048), NumPages: uint64(4), }, }, Cores: []info.Core{ { Id: 4, Threads: []int{8, 9}, Caches: []info.Cache{ { Size: 32768, Type: "Data", Level: 1, }, { Size: 32768, Type: "Instruction", Level: 1, }, { Size: 262144, Type: "Unified", Level: 2, }, }, }, { Id: 5, Threads: []int{10, 11}, Caches: []info.Cache{ { Size: 32764, Type: "Data", Level: 1, }, { Size: 32764, Type: "Instruction", Level: 1, }, { Size: 262148, Type: "Unified", Level: 2, }, }, }, { Id: 6, Threads: []int{12, 13}, Caches: []info.Cache{ { Size: 32768, Type: "Data", Level: 1, }, { Size: 32768, Type: "Instruction", Level: 1, }, { Size: 262144, Type: "Unified", Level: 2, }, }, }, { Id: 7, Threads: []int{14, 15}, Caches: []info.Cache{ { Size: 32764, Type: "Data", Level: 1, }, { Size: 32764, Type: "Instruction", Level: 1, }, { Size: 262148, Type: "Unified", Level: 2, }, }, }, }, Caches: []info.Cache{ { Size: 8388608, Type: "Unified", Level: 3, }, }, Distances: []uint64{ 12, 10, }, }, }, }, nil } func (p testSubcontainersInfoProvider) GetRequestedContainersInfo(string, v2.RequestOptions) (map[string]*info.ContainerInfo, error) { return map[string]*info.ContainerInfo{ "testcontainer": { ContainerReference: info.ContainerReference{ Name: "testcontainer", Aliases: []string{"testcontaineralias"}, }, Spec: info.ContainerSpec{ Image: "test", HasCpu: true, Cpu: info.CpuSpec{ Limit: 1000, Period: 100000, Quota: 10000, }, Memory: info.MemorySpec{ Limit: 2048, Reservation: 1024, SwapLimit: 4096, }, HasHugetlb: true, HasProcesses: true, Processes: info.ProcessSpec{ Limit: 100, }, CreationTime: time.Unix(1257894000, 0), StartTime: time.Unix(1257895000, 0), Labels: map[string]string{ "foo.label": "bar", }, Envs: map[string]string{ "foo+env": "prod", }, }, Stats: []*info.ContainerStats{ { Timestamp: time.Unix(1395066363, 0), Cpu: info.CpuStats{ Usage: info.CpuUsage{ Total: 1, PerCpu: []uint64{2, 3, 4, 5}, User: 6, System: 7, }, CFS: info.CpuCFS{ Periods: 723, ThrottledPeriods: 18, ThrottledTime: 1724314000, BurstsPeriods: 25, BurstTime: 500000000, }, Schedstat: info.CpuSchedstat{ RunTime: 53643567, RunqueueTime: 479424566378, RunPeriods: 984285, }, LoadAverage: 2, LoadDAverage: 2, PSI: info.PSIStats{ Full: info.PSIData{ Avg10: 0.3, Avg60: 0.2, Avg300: 0.1, Total: 100, }, Some: info.PSIData{ Avg10: 0.6, Avg60: 0.4, Avg300: 0.2, Total: 200, }, }, }, Memory: info.MemoryStats{ Usage: 8, MaxUsage: 8, WorkingSet: 9, TotalActiveFile: 7, TotalInactiveFile: 6, ContainerData: info.MemoryStatsMemoryData{ Pgfault: 10, Pgmajfault: 11, NumaStats: info.MemoryNumaStats{ File: map[uint8]uint64{0: 16649, 1: 10000}, Anon: map[uint8]uint64{0: 10000, 1: 7109}, Unevictable: map[uint8]uint64{0: 8900, 1: 10000}, }, }, HierarchicalData: info.MemoryStatsMemoryData{ Pgfault: 12, Pgmajfault: 13, NumaStats: info.MemoryNumaStats{ File: map[uint8]uint64{0: 36649, 1: 10000}, Anon: map[uint8]uint64{0: 20000, 1: 7109}, Unevictable: map[uint8]uint64{0: 8900, 1: 20000}, }, }, Cache: 14, RSS: 15, MappedFile: 16, KernelUsage: 17, Swap: 8192, PSI: info.PSIStats{ Full: info.PSIData{ Avg10: 0.3, Avg60: 0.2, Avg300: 0.1, Total: 1000, }, Some: info.PSIData{ Avg10: 0.6, Avg60: 0.4, Avg300: 0.2, Total: 2000, }, }, }, Hugetlb: map[string]info.HugetlbStats{ "2Mi": { Usage: 4, MaxUsage: 10, Failcnt: 1, }, "1Gi": { Usage: 0, MaxUsage: 0, Failcnt: 0, }, }, Network: info.NetworkStats{ InterfaceStats: info.InterfaceStats{ Name: "eth0", RxBytes: 14, RxPackets: 15, RxErrors: 16, RxDropped: 17, TxBytes: 18, TxPackets: 19, TxErrors: 20, TxDropped: 21, }, Interfaces: []info.InterfaceStats{ { Name: "eth0", RxBytes: 14, RxPackets: 15, RxErrors: 16, RxDropped: 17, TxBytes: 18, TxPackets: 19, TxErrors: 20, TxDropped: 21, }, }, Tcp: info.TcpStat{ Established: 13, SynSent: 0, SynRecv: 0, FinWait1: 0, FinWait2: 0, TimeWait: 0, Close: 0, CloseWait: 0, LastAck: 0, Listen: 3, Closing: 0, }, Tcp6: info.TcpStat{ Established: 11, SynSent: 0, SynRecv: 0, FinWait1: 0, FinWait2: 0, TimeWait: 0, Close: 0, CloseWait: 0, LastAck: 0, Listen: 3, Closing: 0, }, TcpAdvanced: info.TcpAdvancedStat{ TCPFullUndo: 2361, TCPMD5NotFound: 0, TCPDSACKRecv: 83680, TCPSackShifted: 2, TCPSackShiftFallback: 298, PFMemallocDrop: 0, EstabResets: 37, InSegs: 140370590, TCPPureAcks: 24251339, TCPDSACKOldSent: 15633, IPReversePathFilter: 0, TCPFastOpenPassiveFail: 0, InCsumErrors: 0, TCPRenoFailures: 43414, TCPMemoryPressuresChrono: 0, TCPDeferAcceptDrop: 0, TW: 10436427, TCPSpuriousRTOs: 0, TCPDSACKIgnoredNoUndo: 71885, RtoMax: 120000, ActiveOpens: 11038621, EmbryonicRsts: 0, RcvPruned: 0, TCPLossProbeRecovery: 401, TCPHPHits: 56096478, TCPPartialUndo: 3, TCPAbortOnMemory: 0, AttemptFails: 48997, RetransSegs: 462961, SyncookiesFailed: 0, OfoPruned: 0, TCPAbortOnLinger: 0, TCPAbortFailed: 0, TCPRenoReorder: 839, TCPRcvCollapsed: 0, TCPDSACKIgnoredOld: 0, TCPReqQFullDrop: 0, OutOfWindowIcmps: 0, TWKilled: 0, TCPLossProbes: 88648, TCPRenoRecoveryFail: 394, TCPFastOpenCookieReqd: 0, TCPHPAcks: 21490641, TCPSACKReneging: 0, TCPTSReorder: 3, TCPSlowStartRetrans: 290832, MaxConn: -1, SyncookiesRecv: 0, TCPSackFailures: 60, DelayedACKLocked: 90, TCPDSACKOfoSent: 1, TCPSynRetrans: 988, TCPDSACKOfoRecv: 10, TCPSACKDiscard: 0, TCPMD5Unexpected: 0, TCPSackMerged: 6, RtoMin: 200, CurrEstab: 22, TCPTimeWaitOverflow: 0, ListenOverflows: 0, DelayedACKs: 503975, TCPLossUndo: 61374, TCPOrigDataSent: 130698387, TCPBacklogDrop: 0, TCPReqQFullDoCookies: 0, TCPFastOpenPassive: 0, PAWSActive: 0, OutRsts: 91699, TCPSackRecoveryFail: 2, DelayedACKLost: 18843, TCPAbortOnData: 8, TCPMinTTLDrop: 0, PruneCalled: 0, TWRecycled: 0, ListenDrops: 0, TCPAbortOnTimeout: 0, SyncookiesSent: 0, TCPSACKReorder: 11, TCPDSACKUndo: 33, TCPMD5Failure: 0, TCPLostRetransmit: 0, TCPAbortOnClose: 7, TCPFastOpenListenOverflow: 0, OutSegs: 211580512, InErrs: 31, TCPTimeouts: 27422, TCPLossFailures: 729, TCPSackRecovery: 159, RtoAlgorithm: 1, PassiveOpens: 59, LockDroppedIcmps: 0, TCPRenoRecovery: 3519, TCPFACKReorder: 0, TCPFastRetrans: 11794, TCPRetransFail: 0, TCPMemoryPressures: 0, TCPFastOpenActive: 0, TCPFastOpenActiveFail: 0, PAWSEstab: 0, }, Udp: info.UdpStat{ Listen: 0, Dropped: 0, RxQueued: 0, TxQueued: 0, }, Udp6: info.UdpStat{ Listen: 0, Dropped: 0, RxQueued: 0, TxQueued: 0, }, }, DiskIo: info.DiskIoStats{ IoServiceBytes: []info.PerDiskStats{{ Device: "/dev/sdb", Major: 8, Minor: 0, Stats: map[string]uint64{ "Async": 1, "Discard": 2, "Read": 3, "Sync": 4, "Total": 5, "Write": 6, }, }}, IoCostUsage: []info.PerDiskStats{{ Device: "sda1", Major: 8, Minor: 1, Stats: map[string]uint64{"Count": 1500000}, }}, IoCostWait: []info.PerDiskStats{{ Device: "sda1", Major: 8, Minor: 1, Stats: map[string]uint64{"Count": 2500000}, }}, IoCostIndebt: []info.PerDiskStats{{ Device: "sda1", Major: 8, Minor: 1, Stats: map[string]uint64{"Count": 500000}, }}, IoCostIndelay: []info.PerDiskStats{{ Device: "sda1", Major: 8, Minor: 1, Stats: map[string]uint64{"Count": 750000}, }}, PSI: info.PSIStats{ Full: info.PSIData{ Avg10: 0.3, Avg60: 0.2, Avg300: 0.1, Total: 1100, }, Some: info.PSIData{ Avg10: 0.6, Avg60: 0.4, Avg300: 0.2, Total: 2200, }, }, }, Filesystem: []info.FsStats{ { Device: "sda1", InodesFree: 524288, Inodes: 2097152, Limit: 22, Usage: 23, ReadsCompleted: 24, ReadsMerged: 25, SectorsRead: 26, ReadTime: 27, WritesCompleted: 28, WritesMerged: 39, SectorsWritten: 40, WriteTime: 41, IoInProgress: 42, IoTime: 43, WeightedIoTime: 44, }, { Device: "sda2", InodesFree: 262144, Inodes: 2097152, Limit: 37, Usage: 38, ReadsCompleted: 39, ReadsMerged: 40, SectorsRead: 41, ReadTime: 42, WritesCompleted: 43, WritesMerged: 44, SectorsWritten: 45, WriteTime: 46, IoInProgress: 47, IoTime: 48, WeightedIoTime: 49, }, }, Accelerators: []info.AcceleratorStats{ { Make: "nvidia", Model: "tesla-p100", ID: "GPU-deadbeef-1234-5678-90ab-feedfacecafe", MemoryTotal: 20304050607, MemoryUsed: 2030405060, DutyCycle: 12, }, { Make: "nvidia", Model: "tesla-k80", ID: "GPU-deadbeef-0123-4567-89ab-feedfacecafe", MemoryTotal: 10203040506, MemoryUsed: 1020304050, DutyCycle: 6, }, }, Processes: info.ProcessStats{ ProcessCount: 1, FdCount: 5, SocketCount: 3, ThreadsCurrent: 5, ThreadsMax: 100, Ulimits: []info.UlimitSpec{ { Name: "max_open_files", SoftLimit: 16384, HardLimit: 16384, }, }, }, TaskStats: info.LoadStats{ NrSleeping: 50, NrRunning: 51, NrStopped: 52, NrUninterruptible: 53, NrIoWait: 54, }, CustomMetrics: map[string][]info.MetricVal{ "container_custom_app_metric_1": { { FloatValue: float64(1.1), Timestamp: time.Now(), Label: "testlabel_1_1_1", Labels: map[string]string{"test_label": "1_1", "test_label_2": "2_1"}, }, { FloatValue: float64(1.2), Timestamp: time.Now(), Label: "testlabel_1_1_2", Labels: map[string]string{"test_label": "1_2", "test_label_2": "2_2"}, }, }, "container_custom_app_metric_2": { { FloatValue: float64(2), Timestamp: time.Now(), Label: "testlabel2", Labels: map[string]string{"test_label": "test_value"}, }, }, "container_custom_app_metric_3": { { FloatValue: float64(3), Timestamp: time.Now(), Label: "testlabel3", Labels: map[string]string{"test_label": "test_value"}, }, }, }, PerfStats: []info.PerfStat{ { PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 123, Name: "instructions", }, Cpu: 0, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.5, Value: 456, Name: "instructions", }, Cpu: 1, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.66666666666, Value: 321, Name: "instructions_retired", }, Cpu: 0, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.33333333333, Value: 789, Name: "instructions_retired", }, Cpu: 1, }, }, PerfUncoreStats: []info.PerfUncoreStat{ { PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 1231231512.0, Name: "cas_count_read", }, Socket: 0, PMU: "uncore_imc_0", }, { PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 1111231331.0, Name: "cas_count_read", }, Socket: 1, PMU: "uncore_imc_0", }, }, ReferencedMemory: 1234, Resctrl: info.ResctrlStats{ MemoryBandwidth: []info.MemoryBandwidthStats{ { TotalBytes: 4512312, LocalBytes: 2390393, }, { TotalBytes: 2173713, LocalBytes: 1231233, }, }, Cache: []info.CacheStats{ { LLCOccupancy: 162626, }, { LLCOccupancy: 213777, }, }, }, CpuSet: info.CPUSetStats{MemoryMigrate: 1}, Health: info.Health{Status: "healthy"}, }, }, }, }, nil } type erroringSubcontainersInfoProvider struct { successfulProvider testSubcontainersInfoProvider shouldFail bool } func (p *erroringSubcontainersInfoProvider) GetVersionInfo() (*info.VersionInfo, error) { if p.shouldFail { return nil, errors.New("oops 1") } return p.successfulProvider.GetVersionInfo() } func (p *erroringSubcontainersInfoProvider) GetMachineInfo() (*info.MachineInfo, error) { if p.shouldFail { return nil, errors.New("oops 2") } return p.successfulProvider.GetMachineInfo() } func (p *erroringSubcontainersInfoProvider) GetRequestedContainersInfo( a string, opt v2.RequestOptions) (map[string]*info.ContainerInfo, error) { if p.shouldFail { return map[string]*info.ContainerInfo{}, errors.New("oops 3") } return p.successfulProvider.GetRequestedContainersInfo(a, opt) } ================================================ FILE: metrics/prometheus_machine.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package metrics import ( "strconv" "github.com/prometheus/client_golang/prometheus" "github.com/google/cadvisor/container" info "github.com/google/cadvisor/info/v1" "k8s.io/klog/v2" ) var baseLabelsNames = []string{"machine_id", "system_uuid", "boot_id"} const ( prometheusModeLabelName = "mode" prometheusTypeLabelName = "type" prometheusLevelLabelName = "level" prometheusNodeLabelName = "node_id" prometheusCoreLabelName = "core_id" prometheusThreadLabelName = "thread_id" prometheusPageSizeLabelName = "page_size" prometheusTargetNodeLabelName = "target_node_id" nvmMemoryMode = "memory_mode" nvmAppDirectMode = "app_direct_mode" memoryByTypeDimmCountKey = "DimmCount" memoryByTypeDimmCapacityKey = "Capacity" emptyLabelValue = "" ) // machineMetric describes a multi-dimensional metric used for exposing a // certain type of machine statistic. type machineMetric struct { name string help string valueType prometheus.ValueType extraLabels []string condition func(machineInfo *info.MachineInfo) bool getValues func(machineInfo *info.MachineInfo) metricValues } func (metric *machineMetric) desc(baseLabels []string) *prometheus.Desc { return prometheus.NewDesc(metric.name, metric.help, append(baseLabels, metric.extraLabels...), nil) } // PrometheusMachineCollector implements prometheus.Collector. type PrometheusMachineCollector struct { infoProvider infoProvider errors prometheus.Gauge machineMetrics []machineMetric } // NewPrometheusMachineCollector returns a new PrometheusCollector. func NewPrometheusMachineCollector(i infoProvider, includedMetrics container.MetricSet) *PrometheusMachineCollector { c := &PrometheusMachineCollector{ infoProvider: i, errors: prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "machine", Name: "scrape_error", Help: "1 if there was an error while getting machine metrics, 0 otherwise.", }), machineMetrics: []machineMetric{ { name: "machine_cpu_physical_cores", help: "Number of physical CPU cores.", valueType: prometheus.GaugeValue, getValues: func(machineInfo *info.MachineInfo) metricValues { return metricValues{{value: float64(machineInfo.NumPhysicalCores), timestamp: machineInfo.Timestamp}} }, }, { name: "machine_cpu_cores", help: "Number of logical CPU cores.", valueType: prometheus.GaugeValue, getValues: func(machineInfo *info.MachineInfo) metricValues { return metricValues{{value: float64(machineInfo.NumCores), timestamp: machineInfo.Timestamp}} }, }, { name: "machine_cpu_sockets", help: "Number of CPU sockets.", valueType: prometheus.GaugeValue, getValues: func(machineInfo *info.MachineInfo) metricValues { return metricValues{{value: float64(machineInfo.NumSockets), timestamp: machineInfo.Timestamp}} }, }, { name: "machine_cpu_books", help: "Number of CPU books.", valueType: prometheus.GaugeValue, getValues: func(machineInfo *info.MachineInfo) metricValues { return metricValues{{value: float64(machineInfo.NumBooks), timestamp: machineInfo.Timestamp}} }, }, { name: "machine_cpu_drawers", help: "Number of CPU drawers.", valueType: prometheus.GaugeValue, getValues: func(machineInfo *info.MachineInfo) metricValues { return metricValues{{value: float64(machineInfo.NumDrawers), timestamp: machineInfo.Timestamp}} }, }, { name: "machine_memory_bytes", help: "Amount of memory installed on the machine.", valueType: prometheus.GaugeValue, getValues: func(machineInfo *info.MachineInfo) metricValues { return metricValues{{value: float64(machineInfo.MemoryCapacity), timestamp: machineInfo.Timestamp}} }, }, { name: "machine_swap_bytes", help: "Amount of swap memory available on the machine.", valueType: prometheus.GaugeValue, getValues: func(machineInfo *info.MachineInfo) metricValues { return metricValues{{value: float64(machineInfo.SwapCapacity), timestamp: machineInfo.Timestamp}} }, }, { name: "machine_dimm_count", help: "Number of RAM DIMM (all types memory modules) value labeled by dimm type.", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusTypeLabelName}, condition: func(machineInfo *info.MachineInfo) bool { return len(machineInfo.MemoryByType) != 0 }, getValues: func(machineInfo *info.MachineInfo) metricValues { return getMemoryByType(machineInfo, memoryByTypeDimmCountKey) }, }, { name: "machine_dimm_capacity_bytes", help: "Total RAM DIMM capacity (all types memory modules) value labeled by dimm type.", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusTypeLabelName}, condition: func(machineInfo *info.MachineInfo) bool { return len(machineInfo.MemoryByType) != 0 }, getValues: func(machineInfo *info.MachineInfo) metricValues { return getMemoryByType(machineInfo, memoryByTypeDimmCapacityKey) }, }, { name: "machine_nvm_capacity", help: "NVM capacity value labeled by NVM mode (memory mode or app direct mode).", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusModeLabelName}, getValues: func(machineInfo *info.MachineInfo) metricValues { return metricValues{ {value: float64(machineInfo.NVMInfo.MemoryModeCapacity), labels: []string{nvmMemoryMode}, timestamp: machineInfo.Timestamp}, {value: float64(machineInfo.NVMInfo.AppDirectModeCapacity), labels: []string{nvmAppDirectMode}, timestamp: machineInfo.Timestamp}, } }, }, { name: "machine_nvm_avg_power_budget_watts", help: "NVM power budget.", valueType: prometheus.GaugeValue, getValues: func(machineInfo *info.MachineInfo) metricValues { return metricValues{{value: float64(machineInfo.NVMInfo.AvgPowerBudget), timestamp: machineInfo.Timestamp}} }, }, }, } if includedMetrics.Has(container.CPUTopologyMetrics) { c.machineMetrics = append(c.machineMetrics, []machineMetric{ { name: "machine_cpu_cache_capacity_bytes", help: "Cache size in bytes assigned to NUMA node and CPU core.", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusNodeLabelName, prometheusCoreLabelName, prometheusTypeLabelName, prometheusLevelLabelName}, getValues: func(machineInfo *info.MachineInfo) metricValues { return getCaches(machineInfo) }, }, { name: "machine_thread_siblings_count", help: "Number of CPU thread siblings.", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusNodeLabelName, prometheusCoreLabelName, prometheusThreadLabelName}, getValues: func(machineInfo *info.MachineInfo) metricValues { return getThreadsSiblingsCount(machineInfo) }, }, { name: "machine_node_memory_capacity_bytes", help: "Amount of memory assigned to NUMA node.", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusNodeLabelName}, getValues: func(machineInfo *info.MachineInfo) metricValues { return getNodeMemory(machineInfo) }, }, { name: "machine_node_hugepages_count", help: "Numer of hugepages assigned to NUMA node.", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusNodeLabelName, prometheusPageSizeLabelName}, getValues: func(machineInfo *info.MachineInfo) metricValues { return getHugePagesCount(machineInfo) }, }, { name: "machine_node_distance", help: "Distance between NUMA node and target NUMA node.", valueType: prometheus.GaugeValue, extraLabels: []string{prometheusNodeLabelName, prometheusTargetNodeLabelName}, getValues: func(machineInfo *info.MachineInfo) metricValues { return getDistance(machineInfo) }, }, }...) } return c } // Describe describes all the machine metrics ever exported by cadvisor. It // implements prometheus.PrometheusCollector. func (collector *PrometheusMachineCollector) Describe(ch chan<- *prometheus.Desc) { collector.errors.Describe(ch) for _, metric := range collector.machineMetrics { ch <- metric.desc([]string{}) } } // Collect fetches information about machine and delivers them as // Prometheus metrics. It implements prometheus.PrometheusCollector. func (collector *PrometheusMachineCollector) Collect(ch chan<- prometheus.Metric) { collector.errors.Set(0) collector.collectMachineInfo(ch) collector.errors.Collect(ch) } func (collector *PrometheusMachineCollector) collectMachineInfo(ch chan<- prometheus.Metric) { machineInfo, err := collector.infoProvider.GetMachineInfo() if err != nil { collector.errors.Set(1) klog.Warningf("Couldn't get machine info: %s", err) return } baseLabelsValues := []string{machineInfo.MachineID, machineInfo.SystemUUID, machineInfo.BootID} for _, metric := range collector.machineMetrics { if metric.condition != nil && !metric.condition(machineInfo) { continue } for _, metricValue := range metric.getValues(machineInfo) { labelValues := make([]string, len(baseLabelsValues)) copy(labelValues, baseLabelsValues) if len(metric.extraLabels) != 0 { labelValues = append(labelValues, metricValue.labels...) } prometheusMetric := prometheus.MustNewConstMetric(metric.desc(baseLabelsNames), metric.valueType, metricValue.value, labelValues...) if metricValue.timestamp.IsZero() { ch <- prometheusMetric } else { ch <- prometheus.NewMetricWithTimestamp(metricValue.timestamp, prometheusMetric) } } } } func getMemoryByType(machineInfo *info.MachineInfo, property string) metricValues { mValues := make(metricValues, 0, len(machineInfo.MemoryByType)) for memoryType, memoryInfo := range machineInfo.MemoryByType { propertyValue := 0.0 switch property { case memoryByTypeDimmCapacityKey: propertyValue = float64(memoryInfo.Capacity) case memoryByTypeDimmCountKey: propertyValue = float64(memoryInfo.DimmCount) default: klog.Warningf("Incorrect propery name for MemoryByType, property %s", property) return metricValues{} } mValues = append(mValues, metricValue{value: propertyValue, labels: []string{memoryType}, timestamp: machineInfo.Timestamp}) } return mValues } func getThreadsSiblingsCount(machineInfo *info.MachineInfo) metricValues { mValues := make(metricValues, 0, machineInfo.NumCores) for _, node := range machineInfo.Topology { nodeID := strconv.Itoa(node.Id) for _, core := range node.Cores { coreID := strconv.Itoa(core.Id) siblingsCount := len(core.Threads) for _, thread := range core.Threads { mValues = append(mValues, metricValue{ value: float64(siblingsCount), labels: []string{nodeID, coreID, strconv.Itoa(thread)}, timestamp: machineInfo.Timestamp, }) } } } return mValues } func getNodeMemory(machineInfo *info.MachineInfo) metricValues { mValues := make(metricValues, 0, len(machineInfo.Topology)) for _, node := range machineInfo.Topology { nodeID := strconv.Itoa(node.Id) mValues = append(mValues, metricValue{ value: float64(node.Memory), labels: []string{nodeID}, timestamp: machineInfo.Timestamp, }) } return mValues } func getHugePagesCount(machineInfo *info.MachineInfo) metricValues { mValues := make(metricValues, 0) for _, node := range machineInfo.Topology { nodeID := strconv.Itoa(node.Id) for _, hugePage := range node.HugePages { mValues = append(mValues, metricValue{ value: float64(hugePage.NumPages), labels: []string{nodeID, strconv.FormatUint(hugePage.PageSize, 10)}, timestamp: machineInfo.Timestamp, }) } } return mValues } func getCaches(machineInfo *info.MachineInfo) metricValues { mValues := make(metricValues, 0) for _, node := range machineInfo.Topology { nodeID := strconv.Itoa(node.Id) for _, core := range node.Cores { coreID := strconv.Itoa(core.Id) for _, cache := range core.Caches { mValues = append(mValues, metricValue{ value: float64(cache.Size), labels: []string{nodeID, coreID, cache.Type, strconv.Itoa(cache.Level)}, timestamp: machineInfo.Timestamp, }) } for _, cache := range core.UncoreCaches { mValues = append(mValues, metricValue{ value: float64(cache.Size), labels: []string{nodeID, coreID, cache.Type, strconv.Itoa(cache.Level)}, timestamp: machineInfo.Timestamp, }) } } for _, cache := range node.Caches { mValues = append(mValues, metricValue{ value: float64(cache.Size), labels: []string{nodeID, emptyLabelValue, cache.Type, strconv.Itoa(cache.Level)}, timestamp: machineInfo.Timestamp, }) } } return mValues } func getDistance(machineInfo *info.MachineInfo) metricValues { mValues := make(metricValues, 0, len(machineInfo.Topology)^2) for _, node := range machineInfo.Topology { nodeID := strconv.Itoa(node.Id) for i, target := range node.Distances { mValues = append(mValues, metricValue{ value: float64(target), labels: []string{nodeID, strconv.Itoa(i)}, timestamp: machineInfo.Timestamp, }) } } return mValues } ================================================ FILE: metrics/prometheus_machine_test.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package metrics import ( "bytes" "os" "reflect" "testing" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/expfmt" "github.com/stretchr/testify/assert" "github.com/google/cadvisor/container" ) const machineMetricsFile = "testdata/prometheus_machine_metrics" const machineMetricsFailureFile = "testdata/prometheus_machine_metrics_failure" func TestPrometheusMachineCollector(t *testing.T) { collector := NewPrometheusMachineCollector(testSubcontainersInfoProvider{}, container.AllMetrics) registry := prometheus.NewRegistry() registry.MustRegister(collector) metricsFamily, err := registry.Gather() assert.Nil(t, err) var metricBuffer bytes.Buffer for _, metricFamily := range metricsFamily { _, err := expfmt.MetricFamilyToText(&metricBuffer, metricFamily) assert.Nil(t, err) } collectedMetrics := metricBuffer.String() expectedMetrics, err := os.ReadFile(machineMetricsFile) assert.Nil(t, err) assert.Equal(t, string(expectedMetrics), collectedMetrics) } func TestPrometheusMachineCollectorWithFailure(t *testing.T) { provider := &erroringSubcontainersInfoProvider{ successfulProvider: testSubcontainersInfoProvider{}, shouldFail: true, } collector := NewPrometheusMachineCollector(provider, container.AllMetrics) registry := prometheus.NewRegistry() registry.MustRegister(collector) metricsFamily, err := registry.Gather() assert.Nil(t, err) var metricBuffer bytes.Buffer for _, metricFamily := range metricsFamily { _, err := expfmt.MetricFamilyToText(&metricBuffer, metricFamily) assert.Nil(t, err) } collectedMetrics := metricBuffer.String() expectedMetrics, err := os.ReadFile(machineMetricsFailureFile) assert.Nil(t, err) assert.Equal(t, string(expectedMetrics), collectedMetrics) } func TestGetMemoryByType(t *testing.T) { machineInfo, err := testSubcontainersInfoProvider{}.GetMachineInfo() assert.Nil(t, err) capacityMetrics := getMemoryByType(machineInfo, memoryByTypeDimmCapacityKey) assert.Equal(t, 2, len(capacityMetrics)) countMetrics := getMemoryByType(machineInfo, memoryByTypeDimmCountKey) assert.Equal(t, 2, len(countMetrics)) } func TestGetMemoryByTypeWithWrongProperty(t *testing.T) { machineInfo, err := testSubcontainersInfoProvider{}.GetMachineInfo() assert.Nil(t, err) metricVals := getMemoryByType(machineInfo, "wrong_property_name") assert.Equal(t, 0, len(metricVals)) } func TestGetCaches(t *testing.T) { machineInfo, err := testSubcontainersInfoProvider{}.GetMachineInfo() assert.Nil(t, err) metricVals := getCaches(machineInfo) assert.Equal(t, 25, len(metricVals)) expectedMetricVals := []metricValue{ {value: 32768, labels: []string{"0", "0", "Data", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 32768, labels: []string{"0", "0", "Instruction", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 262144, labels: []string{"0", "0", "Unified", "2"}, timestamp: time.Unix(1395066363, 0)}, {value: 32764, labels: []string{"0", "1", "Data", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 32764, labels: []string{"0", "1", "Instruction", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 262148, labels: []string{"0", "1", "Unified", "2"}, timestamp: time.Unix(1395066363, 0)}, {value: 32768, labels: []string{"0", "2", "Data", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 32768, labels: []string{"0", "2", "Instruction", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 262144, labels: []string{"0", "2", "Unified", "2"}, timestamp: time.Unix(1395066363, 0)}, {value: 32764, labels: []string{"0", "3", "Data", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 32764, labels: []string{"0", "3", "Instruction", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 262148, labels: []string{"0", "3", "Unified", "2"}, timestamp: time.Unix(1395066363, 0)}, {value: 32768, labels: []string{"1", "4", "Data", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 32768, labels: []string{"1", "4", "Instruction", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 262144, labels: []string{"1", "4", "Unified", "2"}, timestamp: time.Unix(1395066363, 0)}, {value: 32764, labels: []string{"1", "5", "Data", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 32764, labels: []string{"1", "5", "Instruction", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 262148, labels: []string{"1", "5", "Unified", "2"}, timestamp: time.Unix(1395066363, 0)}, {value: 32768, labels: []string{"1", "6", "Data", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 32768, labels: []string{"1", "6", "Instruction", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 262144, labels: []string{"1", "6", "Unified", "2"}, timestamp: time.Unix(1395066363, 0)}, {value: 32764, labels: []string{"1", "7", "Data", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 32764, labels: []string{"1", "7", "Instruction", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 262148, labels: []string{"1", "7", "Unified", "2"}, timestamp: time.Unix(1395066363, 0)}, {value: 8388608, labels: []string{"1", "", "Unified", "3"}, timestamp: time.Unix(1395066363, 0)}, } assertMetricValues(t, expectedMetricVals, metricVals, "Unexpected information about Node memory") } func TestGetThreadsSiblingsCount(t *testing.T) { machineInfo, err := testSubcontainersInfoProvider{}.GetMachineInfo() assert.Nil(t, err) metricVals := getThreadsSiblingsCount(machineInfo) assert.Equal(t, 16, len(metricVals)) expectedMetricVals := []metricValue{ {value: 2, labels: []string{"0", "0", "0"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"0", "0", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"0", "1", "2"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"0", "1", "3"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"0", "2", "4"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"0", "2", "5"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"0", "3", "6"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"0", "3", "7"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"1", "4", "8"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"1", "4", "9"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"1", "5", "10"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"1", "5", "11"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"1", "6", "12"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"1", "6", "13"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"1", "7", "14"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"1", "7", "15"}, timestamp: time.Unix(1395066363, 0)}, } assertMetricValues(t, expectedMetricVals, metricVals, "Unexpected information about CPU threads") } func TestGetNodeMemory(t *testing.T) { machineInfo, err := testSubcontainersInfoProvider{}.GetMachineInfo() assert.Nil(t, err) metricVals := getNodeMemory(machineInfo) assert.Equal(t, 2, len(metricVals)) expectedMetricVals := []metricValue{ {value: 33604804608, labels: []string{"0"}, timestamp: time.Unix(1395066363, 0)}, {value: 33604804606, labels: []string{"1"}, timestamp: time.Unix(1395066363, 0)}, } assertMetricValues(t, expectedMetricVals, metricVals, "Unexpected information about Node memory") } func TestGetHugePagesCount(t *testing.T) { machineInfo, err := testSubcontainersInfoProvider{}.GetMachineInfo() assert.Nil(t, err) metricVals := getHugePagesCount(machineInfo) assert.Equal(t, 4, len(metricVals)) expectedMetricVals := []metricValue{ {value: 0, labels: []string{"0", "1048576"}, timestamp: time.Unix(1395066363, 0)}, {value: 0, labels: []string{"0", "2048"}, timestamp: time.Unix(1395066363, 0)}, {value: 2, labels: []string{"1", "1048576"}, timestamp: time.Unix(1395066363, 0)}, {value: 4, labels: []string{"1", "2048"}, timestamp: time.Unix(1395066363, 0)}, } assertMetricValues(t, expectedMetricVals, metricVals, "Unexpected information about Node memory") } func TestGetDistance(t *testing.T) { machineInfo, err := testSubcontainersInfoProvider{}.GetMachineInfo() assert.Nil(t, err) metricVals := getDistance(machineInfo) assert.Equal(t, 4, len(metricVals)) expectedMetricVals := []metricValue{ {value: 10, labels: []string{"0", "0"}, timestamp: time.Unix(1395066363, 0)}, {value: 12, labels: []string{"0", "1"}, timestamp: time.Unix(1395066363, 0)}, {value: 12, labels: []string{"1", "0"}, timestamp: time.Unix(1395066363, 0)}, {value: 10, labels: []string{"1", "1"}, timestamp: time.Unix(1395066363, 0)}, } assertMetricValues(t, expectedMetricVals, metricVals, "Unexpected information about Node memory") } func assertMetricValues(t *testing.T, expected metricValues, actual metricValues, message string) { for i := range actual { assert.Truef(t, reflect.DeepEqual(expected[i], actual[i]), "%s expected %#v but found %#v\n", message, expected[i], actual[i]) } } ================================================ FILE: metrics/prometheus_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package metrics import ( "errors" "os" "testing" "time" "github.com/google/cadvisor/container" info "github.com/google/cadvisor/info/v1" v2 "github.com/google/cadvisor/info/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" clock "k8s.io/utils/clock/testing" ) var now = clock.NewFakeClock(time.Unix(1395066363, 0)) func TestPrometheusCollector(t *testing.T) { c := NewPrometheusCollector(testSubcontainersInfoProvider{}, func(container *info.ContainerInfo) map[string]string { s := DefaultContainerLabels(container) s["zone.name"] = "hello" return s }, container.AllMetrics, now, v2.RequestOptions{}) reg := prometheus.NewRegistry() reg.MustRegister(c) testPrometheusCollector(t, reg, "testdata/prometheus_metrics") } func TestPrometheusCollectorWithWhiteList(t *testing.T) { c := NewPrometheusCollector(testSubcontainersInfoProvider{}, func(container *info.ContainerInfo) map[string]string { whitelistedLabels := []string{ "no_one_match", } containerLabelFunc := BaseContainerLabels(whitelistedLabels) s := containerLabelFunc(container) s["zone.name"] = "hello" return s }, container.AllMetrics, now, v2.RequestOptions{}) reg := prometheus.NewRegistry() reg.MustRegister(c) testPrometheusCollector(t, reg, "testdata/prometheus_metrics_whitelist_filtered") } func TestPrometheusCollectorWithPerfAggregated(t *testing.T) { metrics := container.MetricSet{ container.PerfMetrics: struct{}{}, } c := NewPrometheusCollector(testSubcontainersInfoProvider{}, func(container *info.ContainerInfo) map[string]string { s := DefaultContainerLabels(container) s["zone.name"] = "hello" return s }, metrics, now, v2.RequestOptions{}) reg := prometheus.NewRegistry() reg.MustRegister(c) testPrometheusCollector(t, reg, "testdata/prometheus_metrics_perf_aggregated") } func testPrometheusCollector(t *testing.T, gatherer prometheus.Gatherer, metricsFile string) { wantMetrics, err := os.Open(metricsFile) if err != nil { t.Fatalf("unable to read input test file %s", metricsFile) } err = testutil.GatherAndCompare(gatherer, wantMetrics) if err != nil { t.Fatalf("Metric comparison failed: %s", err) } } func TestPrometheusCollector_scrapeFailure(t *testing.T) { provider := &erroringSubcontainersInfoProvider{ successfulProvider: testSubcontainersInfoProvider{}, shouldFail: true, } c := NewPrometheusCollector(provider, func(container *info.ContainerInfo) map[string]string { s := DefaultContainerLabels(container) s["zone.name"] = "hello" return s }, container.AllMetrics, now, v2.RequestOptions{}) reg := prometheus.NewRegistry() reg.MustRegister(c) testPrometheusCollector(t, reg, "testdata/prometheus_metrics_failure") provider.shouldFail = false testPrometheusCollector(t, reg, "testdata/prometheus_metrics") } func TestNewPrometheusCollectorWithPerf(t *testing.T) { c := NewPrometheusCollector(&mockInfoProvider{}, mockLabelFunc, container.MetricSet{container.PerfMetrics: struct{}{}}, now, v2.RequestOptions{}) assert.Len(t, c.containerMetrics, 6) names := []string{} for _, m := range c.containerMetrics { names = append(names, m.name) } assert.Contains(t, names, "container_last_seen") assert.Contains(t, names, "container_health_state") assert.Contains(t, names, "container_perf_events_total") assert.Contains(t, names, "container_perf_events_scaling_ratio") assert.Contains(t, names, "container_perf_uncore_events_total") assert.Contains(t, names, "container_perf_uncore_events_scaling_ratio") } func TestNewPrometheusCollectorWithRequestOptions(t *testing.T) { p := mockInfoProvider{} opts := v2.RequestOptions{ IdType: "docker", } c := NewPrometheusCollector(&p, mockLabelFunc, container.AllMetrics, now, opts) ch := make(chan prometheus.Metric, 10) c.Collect(ch) assert.Equal(t, p.options, opts) } type mockInfoProvider struct { options v2.RequestOptions } func (m *mockInfoProvider) GetRequestedContainersInfo(containerName string, options v2.RequestOptions) (map[string]*info.ContainerInfo, error) { m.options = options return map[string]*info.ContainerInfo{}, nil } func (m *mockInfoProvider) GetVersionInfo() (*info.VersionInfo, error) { return nil, errors.New("not supported") } func (m *mockInfoProvider) GetMachineInfo() (*info.MachineInfo, error) { return nil, errors.New("not supported") } func mockLabelFunc(*info.ContainerInfo) map[string]string { return map[string]string{} } func TestGetPerCpuCorePerfEvents(t *testing.T) { containerStats := &info.ContainerStats{ Timestamp: time.Unix(1395066367, 0), PerfStats: []info.PerfStat{ { PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 123, Name: "instructions", }, Cpu: 0, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.5, Value: 456, Name: "instructions", }, Cpu: 1, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.7, Value: 321, Name: "instructions_retired"}, Cpu: 0, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.3, Value: 789, Name: "instructions_retired"}, Cpu: 1, }, }, } metricVals := getPerCPUCorePerfEvents(containerStats) assert.Equal(t, 4, len(metricVals)) values := []float64{} for _, metric := range metricVals { values = append(values, metric.value) } assert.Contains(t, values, 123.0) assert.Contains(t, values, 456.0) assert.Contains(t, values, 321.0) assert.Contains(t, values, 789.0) } func TestGetPerCpuCoreScalingRatio(t *testing.T) { containerStats := &info.ContainerStats{ Timestamp: time.Unix(1395066367, 0), PerfStats: []info.PerfStat{ { PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 123, Name: "instructions"}, Cpu: 0, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.5, Value: 456, Name: "instructions"}, Cpu: 1, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.7, Value: 321, Name: "instructions_retired"}, Cpu: 0, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.3, Value: 789, Name: "instructions_retired"}, Cpu: 1, }, }, } metricVals := getPerCPUCoreScalingRatio(containerStats) assert.Equal(t, 4, len(metricVals)) values := []float64{} for _, metric := range metricVals { values = append(values, metric.value) } assert.Contains(t, values, 1.0) assert.Contains(t, values, 0.5) assert.Contains(t, values, 0.7) assert.Contains(t, values, 0.3) } func TestGetAggCorePerfEvents(t *testing.T) { containerStats := &info.ContainerStats{ Timestamp: time.Unix(1395066367, 0), PerfStats: []info.PerfStat{ { PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 123, Name: "instructions"}, Cpu: 0, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.5, Value: 456, Name: "instructions"}, Cpu: 1, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.7, Value: 321, Name: "instructions_retired"}, Cpu: 0, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.3, Value: 789, Name: "instructions_retired"}, Cpu: 1, }, }, } metricVals := getAggregatedCorePerfEvents(containerStats) assert.Equal(t, 2, len(metricVals)) values := []float64{} for _, metric := range metricVals { values = append(values, metric.value) } assert.Contains(t, values, 579.0) assert.Contains(t, values, 1110.0) } func TestGetMinCoreScalingRatio(t *testing.T) { containerStats := &info.ContainerStats{ Timestamp: time.Unix(1395066367, 0), PerfStats: []info.PerfStat{ { PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 123, Name: "instructions"}, Cpu: 0, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.5, Value: 456, Name: "instructions"}, Cpu: 1, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.7, Value: 321, Name: "instructions_retired"}, Cpu: 0, }, { PerfValue: info.PerfValue{ ScalingRatio: 0.3, Value: 789, Name: "instructions_retired"}, Cpu: 1, }, }, } metricVals := getMinCoreScalingRatio(containerStats) assert.Equal(t, 2, len(metricVals)) values := []float64{} for _, metric := range metricVals { values = append(values, metric.value) } assert.Contains(t, values, 0.5) assert.Contains(t, values, 0.3) } func TestGetContainerHealthState(t *testing.T) { testCases := []struct { name string containerStats *info.ContainerStats expectedValue float64 }{ {name: "healthy", expectedValue: 1.0, containerStats: &info.ContainerStats{Health: info.Health{Status: "healthy"}}}, {name: "unhealthy", expectedValue: 0.0, containerStats: &info.ContainerStats{Health: info.Health{Status: "unhealthy"}}}, {name: "starting", expectedValue: 0.0, containerStats: &info.ContainerStats{Health: info.Health{Status: "unknown"}}}, {name: "empty", expectedValue: -1.0, containerStats: &info.ContainerStats{}}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { metricVals := getContainerHealthState(tc.containerStats) assert.Equal(t, 1, len(metricVals)) assert.Equal(t, tc.expectedValue, metricVals[0].value) }) } } func TestIOCostMetrics(t *testing.T) { containerStats := &info.ContainerStats{ Timestamp: time.Unix(1395066363, 0), DiskIo: info.DiskIoStats{ IoCostUsage: []info.PerDiskStats{{ Device: "sda1", Major: 8, Minor: 1, Stats: map[string]uint64{"Count": 1500000}, }}, IoCostWait: []info.PerDiskStats{{ Device: "sda1", Major: 8, Minor: 1, Stats: map[string]uint64{"Count": 2500000}, }}, IoCostIndebt: []info.PerDiskStats{{ Device: "sda1", Major: 8, Minor: 1, Stats: map[string]uint64{"Count": 500000}, }}, IoCostIndelay: []info.PerDiskStats{{ Device: "sda1", Major: 8, Minor: 1, Stats: map[string]uint64{"Count": 750000}, }}, }, } testCases := []struct { name string stats []info.PerDiskStats expectedValue float64 }{ { name: "IoCostUsage", stats: containerStats.DiskIo.IoCostUsage, expectedValue: 1.5, }, { name: "IoCostWait", stats: containerStats.DiskIo.IoCostWait, expectedValue: 2.5, }, { name: "IoCostIndebt", stats: containerStats.DiskIo.IoCostIndebt, expectedValue: 0.5, }, { name: "IoCostIndelay", stats: containerStats.DiskIo.IoCostIndelay, expectedValue: 0.75, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { values := ioValues( tc.stats, "Count", asMicrosecondsToSeconds, []info.FsStats{}, nil, containerStats.Timestamp, ) assert.Equal(t, 1, len(values)) assert.Equal(t, tc.expectedValue, values[0].value) assert.Equal(t, []string{"sda1"}, values[0].labels) }) } } func TestCPUBurstMetrics(t *testing.T) { containerStats := &info.ContainerStats{ Timestamp: time.Unix(1395066363, 0), Cpu: info.CpuStats{ CFS: info.CpuCFS{ BurstsPeriods: 25, BurstTime: 500000000, }, }, } testCases := []struct { name string getValue func() float64 expectedValue float64 }{ { name: "BurstsPeriods", getValue: func() float64 { return float64(containerStats.Cpu.CFS.BurstsPeriods) }, expectedValue: 25.0, }, { name: "BurstTime", getValue: func() float64 { return float64(containerStats.Cpu.CFS.BurstTime) / float64(time.Second) }, expectedValue: 0.5, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := tc.getValue() assert.Equal(t, tc.expectedValue, result) }) } } ================================================ FILE: metrics/testdata/prometheus_machine_metrics ================================================ # HELP machine_cpu_books Number of CPU books. # TYPE machine_cpu_books gauge machine_cpu_books{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test"} 0 1395066363000 # HELP machine_cpu_cache_capacity_bytes Cache size in bytes assigned to NUMA node and CPU core. # TYPE machine_cpu_cache_capacity_bytes gauge machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="",level="3",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Unified"} 8.388608e+06 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="0",level="1",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Data"} 32768 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="0",level="1",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Instruction"} 32768 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="0",level="2",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Unified"} 262144 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="1",level="1",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Data"} 32764 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="1",level="1",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Instruction"} 32764 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="1",level="2",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Unified"} 262148 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="2",level="1",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Data"} 32768 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="2",level="1",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Instruction"} 32768 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="2",level="2",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Unified"} 262144 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="3",level="1",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Data"} 32764 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="3",level="1",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Instruction"} 32764 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="3",level="2",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",type="Unified"} 262148 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="4",level="1",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Data"} 32768 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="4",level="1",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Instruction"} 32768 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="4",level="2",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Unified"} 262144 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="5",level="1",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Data"} 32764 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="5",level="1",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Instruction"} 32764 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="5",level="2",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Unified"} 262148 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="6",level="1",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Data"} 32768 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="6",level="1",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Instruction"} 32768 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="6",level="2",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Unified"} 262144 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="7",level="1",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Data"} 32764 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="7",level="1",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Instruction"} 32764 1395066363000 machine_cpu_cache_capacity_bytes{boot_id="boot-id-test",core_id="7",level="2",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",type="Unified"} 262148 1395066363000 # HELP machine_cpu_cores Number of logical CPU cores. # TYPE machine_cpu_cores gauge machine_cpu_cores{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test"} 4 1395066363000 # HELP machine_cpu_drawers Number of CPU drawers. # TYPE machine_cpu_drawers gauge machine_cpu_drawers{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test"} 0 1395066363000 # HELP machine_cpu_physical_cores Number of physical CPU cores. # TYPE machine_cpu_physical_cores gauge machine_cpu_physical_cores{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test"} 1 1395066363000 # HELP machine_cpu_sockets Number of CPU sockets. # TYPE machine_cpu_sockets gauge machine_cpu_sockets{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test"} 1 1395066363000 # HELP machine_dimm_capacity_bytes Total RAM DIMM capacity (all types memory modules) value labeled by dimm type. # TYPE machine_dimm_capacity_bytes gauge machine_dimm_capacity_bytes{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test",type="Non-volatile-RAM"} 2.168421613568e+12 1395066363000 machine_dimm_capacity_bytes{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test",type="Unbuffered-DDR4"} 4.12316860416e+11 1395066363000 # HELP machine_dimm_count Number of RAM DIMM (all types memory modules) value labeled by dimm type. # TYPE machine_dimm_count gauge machine_dimm_count{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test",type="Non-volatile-RAM"} 8 1395066363000 machine_dimm_count{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test",type="Unbuffered-DDR4"} 12 1395066363000 # HELP machine_memory_bytes Amount of memory installed on the machine. # TYPE machine_memory_bytes gauge machine_memory_bytes{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test"} 1024 1395066363000 # HELP machine_node_distance Distance between NUMA node and target NUMA node. # TYPE machine_node_distance gauge machine_node_distance{boot_id="boot-id-test",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",target_node_id="0"} 10 1395066363000 machine_node_distance{boot_id="boot-id-test",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",target_node_id="1"} 12 1395066363000 machine_node_distance{boot_id="boot-id-test",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",target_node_id="0"} 12 1395066363000 machine_node_distance{boot_id="boot-id-test",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",target_node_id="1"} 10 1395066363000 # HELP machine_node_hugepages_count Numer of hugepages assigned to NUMA node. # TYPE machine_node_hugepages_count gauge machine_node_hugepages_count{boot_id="boot-id-test",machine_id="machine-id-test",node_id="0",page_size="1048576",system_uuid="system-uuid-test"} 0 1395066363000 machine_node_hugepages_count{boot_id="boot-id-test",machine_id="machine-id-test",node_id="0",page_size="2048",system_uuid="system-uuid-test"} 0 1395066363000 machine_node_hugepages_count{boot_id="boot-id-test",machine_id="machine-id-test",node_id="1",page_size="1048576",system_uuid="system-uuid-test"} 2 1395066363000 machine_node_hugepages_count{boot_id="boot-id-test",machine_id="machine-id-test",node_id="1",page_size="2048",system_uuid="system-uuid-test"} 4 1395066363000 # HELP machine_node_memory_capacity_bytes Amount of memory assigned to NUMA node. # TYPE machine_node_memory_capacity_bytes gauge machine_node_memory_capacity_bytes{boot_id="boot-id-test",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test"} 3.3604804608e+10 1395066363000 machine_node_memory_capacity_bytes{boot_id="boot-id-test",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test"} 3.3604804606e+10 1395066363000 # HELP machine_nvm_avg_power_budget_watts NVM power budget. # TYPE machine_nvm_avg_power_budget_watts gauge machine_nvm_avg_power_budget_watts{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test"} 0 1395066363000 # HELP machine_nvm_capacity NVM capacity value labeled by NVM mode (memory mode or app direct mode). # TYPE machine_nvm_capacity gauge machine_nvm_capacity{boot_id="boot-id-test",machine_id="machine-id-test",mode="app_direct_mode",system_uuid="system-uuid-test"} 1.735166787584e+12 1395066363000 machine_nvm_capacity{boot_id="boot-id-test",machine_id="machine-id-test",mode="memory_mode",system_uuid="system-uuid-test"} 4.294967296e+11 1395066363000 # HELP machine_scrape_error 1 if there was an error while getting machine metrics, 0 otherwise. # TYPE machine_scrape_error gauge machine_scrape_error 0 # HELP machine_swap_bytes Amount of swap memory available on the machine. # TYPE machine_swap_bytes gauge machine_swap_bytes{boot_id="boot-id-test",machine_id="machine-id-test",system_uuid="system-uuid-test"} 0 1395066363000 # HELP machine_thread_siblings_count Number of CPU thread siblings. # TYPE machine_thread_siblings_count gauge machine_thread_siblings_count{boot_id="boot-id-test",core_id="0",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",thread_id="0"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="0",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",thread_id="1"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="1",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",thread_id="2"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="1",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",thread_id="3"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="2",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",thread_id="4"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="2",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",thread_id="5"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="3",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",thread_id="6"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="3",machine_id="machine-id-test",node_id="0",system_uuid="system-uuid-test",thread_id="7"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="4",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",thread_id="8"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="4",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",thread_id="9"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="5",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",thread_id="10"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="5",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",thread_id="11"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="6",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",thread_id="12"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="6",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",thread_id="13"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="7",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",thread_id="14"} 2 1395066363000 machine_thread_siblings_count{boot_id="boot-id-test",core_id="7",machine_id="machine-id-test",node_id="1",system_uuid="system-uuid-test",thread_id="15"} 2 1395066363000 ================================================ FILE: metrics/testdata/prometheus_machine_metrics_failure ================================================ # HELP machine_scrape_error 1 if there was an error while getting machine metrics, 0 otherwise. # TYPE machine_scrape_error gauge machine_scrape_error 1 ================================================ FILE: metrics/testdata/prometheus_metrics ================================================ # HELP cadvisor_version_info A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision. # TYPE cadvisor_version_info gauge cadvisor_version_info{cadvisorRevision="abcdef",cadvisorVersion="0.16.0",dockerVersion="1.8.1",kernelVersion="4.1.6-200.fc22.x86_64",osVersion="Fedora 22 (Twenty Two)"} 1 # HELP container_blkio_device_usage_total Blkio Device bytes usage # TYPE container_blkio_device_usage_total counter container_blkio_device_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Async",zone_name="hello"} 1 1395066363000 container_blkio_device_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Discard",zone_name="hello"} 2 1395066363000 container_blkio_device_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Read",zone_name="hello"} 3 1395066363000 container_blkio_device_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Sync",zone_name="hello"} 4 1395066363000 container_blkio_device_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Total",zone_name="hello"} 5 1395066363000 container_blkio_device_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Write",zone_name="hello"} 6 1395066363000 # HELP container_cpu_cfs_periods_total Number of elapsed enforcement period intervals. # TYPE container_cpu_cfs_periods_total counter container_cpu_cfs_periods_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 723 1395066363000 # HELP container_cpu_cfs_throttled_periods_total Number of throttled period intervals. # TYPE container_cpu_cfs_throttled_periods_total counter container_cpu_cfs_throttled_periods_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 18 1395066363000 # HELP container_cpu_cfs_throttled_seconds_total Total time duration the container has been throttled. # TYPE container_cpu_cfs_throttled_seconds_total counter container_cpu_cfs_throttled_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.724314 1395066363000 # HELP container_cpu_cfs_burst_periods_total Number of periods when burst occurs. # TYPE container_cpu_cfs_burst_periods_total counter container_cpu_cfs_burst_periods_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 25 1395066363000 # HELP container_cpu_cfs_burst_seconds_total Total time duration the container has been bursted. # TYPE container_cpu_cfs_burst_seconds_total counter container_cpu_cfs_burst_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.5 1395066363000 # HELP container_cpu_load_average_10s Value of container cpu load average over the last 10 seconds. # TYPE container_cpu_load_average_10s gauge container_cpu_load_average_10s{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2 1395066363000 # HELP container_cpu_load_d_average_10s Value of container cpu load.d average over the last 10 seconds. # TYPE container_cpu_load_d_average_10s gauge container_cpu_load_d_average_10s{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2 1395066363000 # HELP container_cpu_schedstat_run_periods_total Number of times processes of the cgroup have run on the cpu # TYPE container_cpu_schedstat_run_periods_total counter container_cpu_schedstat_run_periods_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 984285 1395066363000 # HELP container_cpu_schedstat_run_seconds_total Time duration the processes of the container have run on the CPU. # TYPE container_cpu_schedstat_run_seconds_total counter container_cpu_schedstat_run_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.053643567 1395066363000 # HELP container_cpu_schedstat_runqueue_seconds_total Time duration processes of the container have been waiting on a runqueue. # TYPE container_cpu_schedstat_runqueue_seconds_total counter container_cpu_schedstat_runqueue_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 479.424566378 1395066363000 # HELP container_cpu_system_seconds_total Cumulative system cpu time consumed in seconds. # TYPE container_cpu_system_seconds_total counter container_cpu_system_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 7e-09 1395066363000 # HELP container_cpu_usage_seconds_total Cumulative cpu time consumed in seconds. # TYPE container_cpu_usage_seconds_total counter container_cpu_usage_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",cpu="cpu00",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2e-09 1395066363000 container_cpu_usage_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",cpu="cpu01",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 3e-09 1395066363000 container_cpu_usage_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",cpu="cpu02",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4e-09 1395066363000 container_cpu_usage_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",cpu="cpu03",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 5e-09 1395066363000 # HELP container_cpu_user_seconds_total Cumulative user cpu time consumed in seconds. # TYPE container_cpu_user_seconds_total counter container_cpu_user_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 6e-09 1395066363000 # HELP container_custom_app_metric_1 Custom application metric. # TYPE container_custom_app_metric_1 gauge container_custom_app_metric_1{app_test_label="1_1",app_test_label_2="2_1",container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.1 container_custom_app_metric_1{app_test_label="1_2",app_test_label_2="2_2",container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.2 # HELP container_custom_app_metric_2 Custom application metric. # TYPE container_custom_app_metric_2 gauge container_custom_app_metric_2{app_test_label="test_value",container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2 # HELP container_custom_app_metric_3 Custom application metric. # TYPE container_custom_app_metric_3 gauge container_custom_app_metric_3{app_test_label="test_value",container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 3 # HELP container_file_descriptors Number of open file descriptors for the container. # TYPE container_file_descriptors gauge container_file_descriptors{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 5 1395066363000 # HELP container_fs_inodes_free Number of available Inodes # TYPE container_fs_inodes_free gauge container_fs_inodes_free{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 524288 1395066363000 container_fs_inodes_free{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 262144 1395066363000 # HELP container_fs_inodes_total Number of Inodes # TYPE container_fs_inodes_total gauge container_fs_inodes_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2.097152e+06 1395066363000 container_fs_inodes_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2.097152e+06 1395066363000 # HELP container_fs_io_current Number of I/Os currently in progress # TYPE container_fs_io_current gauge container_fs_io_current{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 42 1395066363000 container_fs_io_current{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 47 1395066363000 # HELP container_fs_io_time_seconds_total Cumulative count of seconds spent doing I/Os # TYPE container_fs_io_time_seconds_total counter container_fs_io_time_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.3e-08 1395066363000 container_fs_io_time_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.8e-08 1395066363000 # HELP container_fs_io_time_weighted_seconds_total Cumulative weighted I/O time in seconds # TYPE container_fs_io_time_weighted_seconds_total counter container_fs_io_time_weighted_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.4e-08 1395066363000 container_fs_io_time_weighted_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.9e-08 1395066363000 # HELP container_fs_io_cost_usage_seconds_total Cumulative IOCost usage in seconds # TYPE container_fs_io_cost_usage_seconds_total counter container_fs_io_cost_usage_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.5 1395066363000 # HELP container_fs_io_cost_wait_seconds_total Cumulative IOCost wait in seconds # TYPE container_fs_io_cost_wait_seconds_total counter container_fs_io_cost_wait_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2.5 1395066363000 # HELP container_fs_io_cost_indebt_seconds_total Cumulative IOCost debt in seconds # TYPE container_fs_io_cost_indebt_seconds_total counter container_fs_io_cost_indebt_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.5 1395066363000 # HELP container_fs_io_cost_indelay_seconds_total Cumulative IOCost delay in seconds # TYPE container_fs_io_cost_indelay_seconds_total counter container_fs_io_cost_indelay_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.75 1395066363000 # HELP container_fs_limit_bytes Number of bytes that can be consumed by the container on this filesystem. # TYPE container_fs_limit_bytes gauge container_fs_limit_bytes{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 22 1395066363000 container_fs_limit_bytes{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 37 1395066363000 # HELP container_fs_read_seconds_total Cumulative count of seconds spent reading # TYPE container_fs_read_seconds_total counter container_fs_read_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2.7e-08 1395066363000 container_fs_read_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.2e-08 1395066363000 # HELP container_fs_reads_bytes_total Cumulative count of bytes read # TYPE container_fs_reads_bytes_total counter container_fs_reads_bytes_total{container_env_foo_env="prod",container_label_foo_label="bar",device="/dev/sdb",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 3 1395066363000 # HELP container_fs_reads_merged_total Cumulative count of reads merged # TYPE container_fs_reads_merged_total counter container_fs_reads_merged_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 25 1395066363000 container_fs_reads_merged_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 40 1395066363000 # HELP container_fs_reads_total Cumulative count of reads completed # TYPE container_fs_reads_total counter container_fs_reads_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 24 1395066363000 container_fs_reads_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 39 1395066363000 # HELP container_fs_sector_reads_total Cumulative count of sector reads completed # TYPE container_fs_sector_reads_total counter container_fs_sector_reads_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 26 1395066363000 container_fs_sector_reads_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 41 1395066363000 # HELP container_fs_sector_writes_total Cumulative count of sector writes completed # TYPE container_fs_sector_writes_total counter container_fs_sector_writes_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 40 1395066363000 container_fs_sector_writes_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 45 1395066363000 # HELP container_fs_usage_bytes Number of bytes that are consumed by the container on this filesystem. # TYPE container_fs_usage_bytes gauge container_fs_usage_bytes{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 23 1395066363000 container_fs_usage_bytes{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 38 1395066363000 # HELP container_fs_write_seconds_total Cumulative count of seconds spent writing # TYPE container_fs_write_seconds_total counter container_fs_write_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.1e-08 1395066363000 container_fs_write_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.6e-08 1395066363000 # HELP container_fs_writes_bytes_total Cumulative count of bytes written # TYPE container_fs_writes_bytes_total counter container_fs_writes_bytes_total{container_env_foo_env="prod",container_label_foo_label="bar",device="/dev/sdb",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 6 1395066363000 # HELP container_fs_writes_merged_total Cumulative count of writes merged # TYPE container_fs_writes_merged_total counter container_fs_writes_merged_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 39 1395066363000 container_fs_writes_merged_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 44 1395066363000 # HELP container_fs_writes_total Cumulative count of writes completed # TYPE container_fs_writes_total counter container_fs_writes_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 28 1395066363000 container_fs_writes_total{container_env_foo_env="prod",container_label_foo_label="bar",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 43 1395066363000 # HELP container_health_state The result of the container's health check # TYPE container_health_state gauge container_health_state{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1 1395066363000 # HELP container_hugetlb_failcnt Number of hugepage usage hits limits # TYPE container_hugetlb_failcnt counter container_hugetlb_failcnt{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",pagesize="1Gi",zone_name="hello"} 0 1395066363000 container_hugetlb_failcnt{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",pagesize="2Mi",zone_name="hello"} 1 1395066363000 # HELP container_hugetlb_max_usage_bytes Maximum hugepage usage recorded in bytes # TYPE container_hugetlb_max_usage_bytes gauge container_hugetlb_max_usage_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",pagesize="1Gi",zone_name="hello"} 0 1395066363000 container_hugetlb_max_usage_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",pagesize="2Mi",zone_name="hello"} 10 1395066363000 # HELP container_hugetlb_usage_bytes Current hugepage usage in bytes # TYPE container_hugetlb_usage_bytes gauge container_hugetlb_usage_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",pagesize="1Gi",zone_name="hello"} 0 1395066363000 container_hugetlb_usage_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",pagesize="2Mi",zone_name="hello"} 4 1395066363000 # HELP container_last_seen Last time a container was seen by the exporter # TYPE container_last_seen gauge container_last_seen{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.395066363e+09 1395066363000 # HELP container_memory_cache Number of bytes of page cache memory. # TYPE container_memory_cache gauge container_memory_cache{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 14 1395066363000 # HELP container_memory_failcnt Number of memory usage hits limits # TYPE container_memory_failcnt counter container_memory_failcnt{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0 1395066363000 # HELP container_memory_failures_total Cumulative count of memory allocation failures. # TYPE container_memory_failures_total counter container_memory_failures_total{container_env_foo_env="prod",container_label_foo_label="bar",failure_type="pgfault",id="testcontainer",image="test",name="testcontaineralias",scope="container",zone_name="hello"} 10 1395066363000 container_memory_failures_total{container_env_foo_env="prod",container_label_foo_label="bar",failure_type="pgfault",id="testcontainer",image="test",name="testcontaineralias",scope="hierarchy",zone_name="hello"} 12 1395066363000 container_memory_failures_total{container_env_foo_env="prod",container_label_foo_label="bar",failure_type="pgmajfault",id="testcontainer",image="test",name="testcontaineralias",scope="container",zone_name="hello"} 11 1395066363000 container_memory_failures_total{container_env_foo_env="prod",container_label_foo_label="bar",failure_type="pgmajfault",id="testcontainer",image="test",name="testcontaineralias",scope="hierarchy",zone_name="hello"} 13 1395066363000 # HELP container_memory_kernel_usage Size of kernel memory allocated in bytes. # TYPE container_memory_kernel_usage gauge container_memory_kernel_usage{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 17 1395066363000 # HELP container_memory_mapped_file Size of memory mapped files in bytes. # TYPE container_memory_mapped_file gauge container_memory_mapped_file{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 16 1395066363000 # HELP container_memory_max_usage_bytes Maximum memory usage recorded in bytes # TYPE container_memory_max_usage_bytes gauge container_memory_max_usage_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 8 1395066363000 # HELP container_memory_migrate Memory migrate status. # TYPE container_memory_migrate gauge container_memory_migrate{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1 1395066363000 # HELP container_memory_numa_pages Number of used pages per NUMA node # TYPE container_memory_numa_pages gauge container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="container",type="anon",zone_name="hello"} 10000 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="container",type="file",zone_name="hello"} 16649 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="container",type="unevictable",zone_name="hello"} 8900 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="hierarchy",type="anon",zone_name="hello"} 20000 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="hierarchy",type="file",zone_name="hello"} 36649 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="hierarchy",type="unevictable",zone_name="hello"} 8900 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="container",type="anon",zone_name="hello"} 7109 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="container",type="file",zone_name="hello"} 10000 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="container",type="unevictable",zone_name="hello"} 10000 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="hierarchy",type="anon",zone_name="hello"} 7109 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="hierarchy",type="file",zone_name="hello"} 10000 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="hierarchy",type="unevictable",zone_name="hello"} 20000 1395066363000 # HELP container_memory_rss Size of RSS in bytes. # TYPE container_memory_rss gauge container_memory_rss{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 15 1395066363000 # HELP container_memory_swap Container swap usage in bytes. # TYPE container_memory_swap gauge container_memory_swap{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 8192 1395066363000 # HELP container_memory_total_active_file_bytes Current total active file in bytes. # TYPE container_memory_total_active_file_bytes gauge container_memory_total_active_file_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 7 1395066363000 # HELP container_memory_total_inactive_file_bytes Current total inactive file in bytes. # TYPE container_memory_total_inactive_file_bytes gauge container_memory_total_inactive_file_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 6 1395066363000 # HELP container_memory_usage_bytes Current memory usage in bytes, including all memory regardless of when it was accessed # TYPE container_memory_usage_bytes gauge container_memory_usage_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 8 1395066363000 # HELP container_memory_working_set_bytes Current working set in bytes. # TYPE container_memory_working_set_bytes gauge container_memory_working_set_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 9 1395066363000 # HELP container_network_advance_tcp_stats_total advance tcp connections statistic for container # TYPE container_network_advance_tcp_stats_total gauge container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="activeopens",zone_name="hello"} 1.1038621e+07 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="attemptfails",zone_name="hello"} 48997 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="currestab",zone_name="hello"} 22 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="delayedacklocked",zone_name="hello"} 90 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="delayedacklost",zone_name="hello"} 18843 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="delayedacks",zone_name="hello"} 503975 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="embryonicrsts",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="estabresets",zone_name="hello"} 37 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="incsumerrors",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="inerrs",zone_name="hello"} 31 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="insegs",zone_name="hello"} 1.4037059e+08 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="ipreversepathfilter",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="listendrops",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="listenoverflows",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="lockdroppedicmps",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="maxconn",zone_name="hello"} -1 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="ofopruned",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="outofwindowicmps",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="outrsts",zone_name="hello"} 91699 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="outsegs",zone_name="hello"} 2.11580512e+08 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="passiveopens",zone_name="hello"} 59 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="pawsactive",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="pawsestab",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="pfmemallocdrop",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="prunecalled",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="rcvpruned",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="retranssegs",zone_name="hello"} 462961 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="rtoalgorithm",zone_name="hello"} 1 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="rtomax",zone_name="hello"} 120000 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="rtomin",zone_name="hello"} 200 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="syncookiesfailed",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="syncookiesrecv",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="syncookiessent",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortfailed",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortonclose",zone_name="hello"} 7 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortondata",zone_name="hello"} 8 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortonlinger",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortonmemory",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortontimeout",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpbacklogdrop",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdeferacceptdrop",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackignorednoundo",zone_name="hello"} 71885 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackignoredold",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackoforecv",zone_name="hello"} 10 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackofosent",zone_name="hello"} 1 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackoldsent",zone_name="hello"} 15633 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackrecv",zone_name="hello"} 83680 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackundo",zone_name="hello"} 33 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfackreorder",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopenactive",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopenactivefail",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopencookiereqd",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopenlistenoverflow",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopenpassive",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopenpassivefail",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastretrans",zone_name="hello"} 11794 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfullundo",zone_name="hello"} 2361 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcphpacks",zone_name="hello"} 2.1490641e+07 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcphphits",zone_name="hello"} 5.6096478e+07 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcplossfailures",zone_name="hello"} 729 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcplossproberecovery",zone_name="hello"} 401 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcplossprobes",zone_name="hello"} 88648 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcplossundo",zone_name="hello"} 61374 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcplostretransmit",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpmd5failure",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpmd5notfound",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpmd5unexpected",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpmemorypressures",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpmemorypressureschrono",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpminttldrop",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcporigdatasent",zone_name="hello"} 1.30698387e+08 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcppartialundo",zone_name="hello"} 3 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcppureacks",zone_name="hello"} 2.4251339e+07 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcprcvcollapsed",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcprenofailures",zone_name="hello"} 43414 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcprenorecovery",zone_name="hello"} 3519 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcprenorecoveryfail",zone_name="hello"} 394 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcprenoreorder",zone_name="hello"} 839 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpreqqfulldocookies",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpreqqfulldrop",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpretransfail",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackdiscard",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackfailures",zone_name="hello"} 60 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackmerged",zone_name="hello"} 6 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackrecovery",zone_name="hello"} 159 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackrecoveryfail",zone_name="hello"} 2 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackreneging",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackreorder",zone_name="hello"} 11 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackshifted",zone_name="hello"} 2 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackshiftfallback",zone_name="hello"} 298 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpslowstartretrans",zone_name="hello"} 290832 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpspuriousrtos",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsynretrans",zone_name="hello"} 988 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcptimeouts",zone_name="hello"} 27422 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcptimewaitoverflow",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcptsreorder",zone_name="hello"} 3 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tw",zone_name="hello"} 1.0436427e+07 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="twkilled",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="twrecycled",zone_name="hello"} 0 1395066363000 # HELP container_network_receive_bytes_total Cumulative count of bytes received # TYPE container_network_receive_bytes_total counter container_network_receive_bytes_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 14 1395066363000 # HELP container_network_receive_errors_total Cumulative count of errors encountered while receiving # TYPE container_network_receive_errors_total counter container_network_receive_errors_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 16 1395066363000 # HELP container_network_receive_packets_dropped_total Cumulative count of packets dropped while receiving # TYPE container_network_receive_packets_dropped_total counter container_network_receive_packets_dropped_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 17 1395066363000 # HELP container_network_receive_packets_total Cumulative count of packets received # TYPE container_network_receive_packets_total counter container_network_receive_packets_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 15 1395066363000 # HELP container_network_tcp6_usage_total tcp6 connection usage statistic for container # TYPE container_network_tcp6_usage_total gauge container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="close",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="closewait",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="closing",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="established",zone_name="hello"} 11 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="finwait1",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="finwait2",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="lastack",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="listen",zone_name="hello"} 3 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="synrecv",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="synsent",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="timewait",zone_name="hello"} 0 1395066363000 # HELP container_network_tcp_usage_total tcp connection usage statistic for container # TYPE container_network_tcp_usage_total gauge container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="close",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="closewait",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="closing",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="established",zone_name="hello"} 13 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="finwait1",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="finwait2",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="lastack",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="listen",zone_name="hello"} 3 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="synrecv",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="synsent",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",tcp_state="timewait",zone_name="hello"} 0 1395066363000 # HELP container_network_transmit_bytes_total Cumulative count of bytes transmitted # TYPE container_network_transmit_bytes_total counter container_network_transmit_bytes_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 18 1395066363000 # HELP container_network_transmit_errors_total Cumulative count of errors encountered while transmitting # TYPE container_network_transmit_errors_total counter container_network_transmit_errors_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 20 1395066363000 # HELP container_network_transmit_packets_dropped_total Cumulative count of packets dropped while transmitting # TYPE container_network_transmit_packets_dropped_total counter container_network_transmit_packets_dropped_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 21 1395066363000 # HELP container_network_transmit_packets_total Cumulative count of packets transmitted # TYPE container_network_transmit_packets_total counter container_network_transmit_packets_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 19 1395066363000 # HELP container_network_udp6_usage_total udp6 connection usage statistic for container # TYPE container_network_udp6_usage_total gauge container_network_udp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",udp_state="dropped",zone_name="hello"} 0 1395066363000 container_network_udp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",udp_state="listen",zone_name="hello"} 0 1395066363000 container_network_udp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",udp_state="rxqueued",zone_name="hello"} 0 1395066363000 container_network_udp6_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",udp_state="txqueued",zone_name="hello"} 0 1395066363000 # HELP container_network_udp_usage_total udp connection usage statistic for container # TYPE container_network_udp_usage_total gauge container_network_udp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",udp_state="dropped",zone_name="hello"} 0 1395066363000 container_network_udp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",udp_state="listen",zone_name="hello"} 0 1395066363000 container_network_udp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",udp_state="rxqueued",zone_name="hello"} 0 1395066363000 container_network_udp_usage_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",udp_state="txqueued",zone_name="hello"} 0 1395066363000 # HELP container_oom_events_total Count of out of memory events observed for the container # TYPE container_oom_events_total counter container_oom_events_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0 1395066363000 # HELP container_perf_events_total Perf event metric. # TYPE container_perf_events_total counter container_perf_events_total{container_env_foo_env="prod",container_label_foo_label="bar",cpu="0",event="instructions",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 123 1395066363000 container_perf_events_total{container_env_foo_env="prod",container_label_foo_label="bar",cpu="0",event="instructions_retired",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 321 1395066363000 container_perf_events_total{container_env_foo_env="prod",container_label_foo_label="bar",cpu="1",event="instructions",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 456 1395066363000 container_perf_events_total{container_env_foo_env="prod",container_label_foo_label="bar",cpu="1",event="instructions_retired",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 789 1395066363000 # HELP container_perf_events_scaling_ratio Perf event metric scaling ratio. # TYPE container_perf_events_scaling_ratio gauge container_perf_events_scaling_ratio{container_env_foo_env="prod",container_label_foo_label="bar",cpu="0",event="instructions",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1 1395066363000 container_perf_events_scaling_ratio{container_env_foo_env="prod",container_label_foo_label="bar",cpu="0",event="instructions_retired",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.66666666666 1395066363000 container_perf_events_scaling_ratio{container_env_foo_env="prod",container_label_foo_label="bar",cpu="1",event="instructions",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.5 1395066363000 container_perf_events_scaling_ratio{container_env_foo_env="prod",container_label_foo_label="bar",cpu="1",event="instructions_retired",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.33333333333 1395066363000 # HELP container_perf_uncore_events_total Perf uncore event metric. # TYPE container_perf_uncore_events_total counter container_perf_uncore_events_total{container_env_foo_env="prod",container_label_foo_label="bar",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="0",zone_name="hello"} 1.231231512e+09 1395066363000 container_perf_uncore_events_total{container_env_foo_env="prod",container_label_foo_label="bar",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="1",zone_name="hello"} 1.111231331e+09 1395066363000 # HELP container_perf_uncore_events_scaling_ratio Perf uncore event metric scaling ratio. # TYPE container_perf_uncore_events_scaling_ratio gauge container_perf_uncore_events_scaling_ratio{container_env_foo_env="prod",container_label_foo_label="bar",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="0",zone_name="hello"} 1 1395066363000 container_perf_uncore_events_scaling_ratio{container_env_foo_env="prod",container_label_foo_label="bar",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="1",zone_name="hello"} 1 1395066363000 # HELP container_pressure_cpu_stalled_seconds_total Total time duration no tasks in the container could make progress due to CPU congestion. # TYPE container_pressure_cpu_stalled_seconds_total counter container_pressure_cpu_stalled_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.0001 1395066363000 # HELP container_pressure_cpu_waiting_seconds_total Total time duration tasks in the container have waited due to CPU congestion. # TYPE container_pressure_cpu_waiting_seconds_total counter container_pressure_cpu_waiting_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.0002 1395066363000 # HELP container_pressure_io_stalled_seconds_total Total time duration no tasks in the container could make progress due to IO congestion. # TYPE container_pressure_io_stalled_seconds_total counter container_pressure_io_stalled_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.0011 1395066363000 # HELP container_pressure_io_waiting_seconds_total Total time duration tasks in the container have waited due to IO congestion. # TYPE container_pressure_io_waiting_seconds_total counter container_pressure_io_waiting_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.0022 1395066363000 # HELP container_pressure_memory_stalled_seconds_total Total time duration no tasks in the container could make progress due to memory congestion. # TYPE container_pressure_memory_stalled_seconds_total counter container_pressure_memory_stalled_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.001 1395066363000 # HELP container_pressure_memory_waiting_seconds_total Total time duration tasks in the container have waited due to memory congestion. # TYPE container_pressure_memory_waiting_seconds_total counter container_pressure_memory_waiting_seconds_total{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.002 1395066363000 # HELP container_processes Number of processes running inside the container. # TYPE container_processes gauge container_processes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1 1395066363000 # HELP container_referenced_bytes Container referenced bytes during last measurements cycle # TYPE container_referenced_bytes gauge container_referenced_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1234 1395066363000 # HELP container_scrape_error 1 if there was an error while getting container metrics, 0 otherwise # TYPE container_scrape_error gauge container_scrape_error 0 # HELP container_sockets Number of open sockets for the container. # TYPE container_sockets gauge container_sockets{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 3 1395066363000 # HELP container_spec_cpu_period CPU period of the container. # TYPE container_spec_cpu_period gauge container_spec_cpu_period{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 100000 # HELP container_spec_cpu_quota CPU quota of the container. # TYPE container_spec_cpu_quota gauge container_spec_cpu_quota{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 10000 # HELP container_spec_cpu_shares CPU share of the container. # TYPE container_spec_cpu_shares gauge container_spec_cpu_shares{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1000 # HELP container_creation_time_seconds Container creation time since unix epoch in seconds. # TYPE container_creation_time_seconds gauge container_creation_time_seconds{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.257894e+09 # HELP container_start_time_seconds Start time of the container since unix epoch in seconds. # TYPE container_start_time_seconds gauge container_start_time_seconds{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.257895e+09 # HELP container_tasks_state Number of tasks in given state # TYPE container_tasks_state gauge container_tasks_state{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",state="iowaiting",zone_name="hello"} 54 1395066363000 container_tasks_state{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",state="running",zone_name="hello"} 51 1395066363000 container_tasks_state{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",state="sleeping",zone_name="hello"} 50 1395066363000 container_tasks_state{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",state="stopped",zone_name="hello"} 52 1395066363000 container_tasks_state{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",state="uninterruptible",zone_name="hello"} 53 1395066363000 # HELP container_threads Number of threads running inside the container # TYPE container_threads gauge container_threads{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 5 1395066363000 # HELP container_threads_max Maximum number of threads allowed inside the container, infinity if value is zero # TYPE container_threads_max gauge container_threads_max{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 100 1395066363000 # HELP container_ulimits_soft Soft ulimit values for the container root process. Unlimited if -1, except priority and nice # TYPE container_ulimits_soft gauge container_ulimits_soft{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",ulimit="max_open_files",zone_name="hello"} 16384 1395066363000 # HELP container_llc_occupancy_bytes Last level cache usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM). # TYPE container_llc_occupancy_bytes gauge container_llc_occupancy_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node_id="0",zone_name="hello"} 162626 1395066363000 container_llc_occupancy_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node_id="1",zone_name="hello"} 213777 1395066363000 # HELP container_memory_bandwidth_bytes Total memory bandwidth usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM). # TYPE container_memory_bandwidth_bytes gauge container_memory_bandwidth_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node_id="0",zone_name="hello"} 4.512312e+06 1395066363000 container_memory_bandwidth_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node_id="1",zone_name="hello"} 2.173713e+06 1395066363000 # HELP container_memory_bandwidth_local_bytes Local memory bandwidth usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM). # TYPE container_memory_bandwidth_local_bytes gauge container_memory_bandwidth_local_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node_id="0",zone_name="hello"} 2.390393e+06 1395066363000 container_memory_bandwidth_local_bytes{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",node_id="1",zone_name="hello"} 1.231233e+06 1395066363000 ================================================ FILE: metrics/testdata/prometheus_metrics_failure ================================================ # HELP container_scrape_error 1 if there was an error while getting container metrics, 0 otherwise # TYPE container_scrape_error gauge container_scrape_error 1 ================================================ FILE: metrics/testdata/prometheus_metrics_perf_aggregated ================================================ # HELP cadvisor_version_info A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision. # TYPE cadvisor_version_info gauge cadvisor_version_info{cadvisorRevision="abcdef",cadvisorVersion="0.16.0",dockerVersion="1.8.1",kernelVersion="4.1.6-200.fc22.x86_64",osVersion="Fedora 22 (Twenty Two)"} 1 # HELP container_health_state The result of the container's health check # TYPE container_health_state gauge container_health_state{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1 1395066363000 # HELP container_last_seen Last time a container was seen by the exporter # TYPE container_last_seen gauge container_last_seen{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.395066363e+09 1395066363000 # HELP container_perf_events_scaling_ratio Perf event metric scaling ratio. # TYPE container_perf_events_scaling_ratio gauge container_perf_events_scaling_ratio{container_env_foo_env="prod",container_label_foo_label="bar",cpu="",event="instructions",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.5 1395066363000 container_perf_events_scaling_ratio{container_env_foo_env="prod",container_label_foo_label="bar",cpu="",event="instructions_retired",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.33333333333 1395066363000 # HELP container_perf_events_total Perf event metric. # TYPE container_perf_events_total counter container_perf_events_total{container_env_foo_env="prod",container_label_foo_label="bar",cpu="",event="instructions",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 579 1395066363000 container_perf_events_total{container_env_foo_env="prod",container_label_foo_label="bar",cpu="",event="instructions_retired",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1110 1395066363000 # HELP container_perf_uncore_events_scaling_ratio Perf uncore event metric scaling ratio. # TYPE container_perf_uncore_events_scaling_ratio gauge container_perf_uncore_events_scaling_ratio{container_env_foo_env="prod",container_label_foo_label="bar",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="0",zone_name="hello"} 1 1395066363000 container_perf_uncore_events_scaling_ratio{container_env_foo_env="prod",container_label_foo_label="bar",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="1",zone_name="hello"} 1 1395066363000 # HELP container_perf_uncore_events_total Perf uncore event metric. # TYPE container_perf_uncore_events_total counter container_perf_uncore_events_total{container_env_foo_env="prod",container_label_foo_label="bar",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="0",zone_name="hello"} 1.231231512e+09 1395066363000 container_perf_uncore_events_total{container_env_foo_env="prod",container_label_foo_label="bar",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="1",zone_name="hello"} 1.111231331e+09 1395066363000 # HELP container_scrape_error 1 if there was an error while getting container metrics, 0 otherwise # TYPE container_scrape_error gauge container_scrape_error 0 # HELP container_spec_cpu_period CPU period of the container. # TYPE container_spec_cpu_period gauge container_spec_cpu_period{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 100000 # HELP container_spec_cpu_quota CPU quota of the container. # TYPE container_spec_cpu_quota gauge container_spec_cpu_quota{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 10000 # HELP container_spec_cpu_shares CPU share of the container. # TYPE container_spec_cpu_shares gauge container_spec_cpu_shares{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1000 # HELP container_creation_time_seconds Container creation time since unix epoch in seconds. # TYPE container_creation_time_seconds gauge container_creation_time_seconds{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.257894e+09 # HELP container_start_time_seconds Start time of the container since unix epoch in seconds. # TYPE container_start_time_seconds gauge container_start_time_seconds{container_env_foo_env="prod",container_label_foo_label="bar",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.257895e+09 ================================================ FILE: metrics/testdata/prometheus_metrics_whitelist_filtered ================================================ # HELP cadvisor_version_info A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision. # TYPE cadvisor_version_info gauge cadvisor_version_info{cadvisorRevision="abcdef",cadvisorVersion="0.16.0",dockerVersion="1.8.1",kernelVersion="4.1.6-200.fc22.x86_64",osVersion="Fedora 22 (Twenty Two)"} 1 # HELP container_blkio_device_usage_total Blkio Device bytes usage # TYPE container_blkio_device_usage_total counter container_blkio_device_usage_total{container_env_foo_env="prod",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Async",zone_name="hello"} 1 1395066363000 container_blkio_device_usage_total{container_env_foo_env="prod",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Discard",zone_name="hello"} 2 1395066363000 container_blkio_device_usage_total{container_env_foo_env="prod",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Read",zone_name="hello"} 3 1395066363000 container_blkio_device_usage_total{container_env_foo_env="prod",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Sync",zone_name="hello"} 4 1395066363000 container_blkio_device_usage_total{container_env_foo_env="prod",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Total",zone_name="hello"} 5 1395066363000 container_blkio_device_usage_total{container_env_foo_env="prod",device="/dev/sdb",id="testcontainer",image="test",major="8",minor="0",name="testcontaineralias",operation="Write",zone_name="hello"} 6 1395066363000 # HELP container_cpu_cfs_periods_total Number of elapsed enforcement period intervals. # TYPE container_cpu_cfs_periods_total counter container_cpu_cfs_periods_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 723 1395066363000 # HELP container_cpu_cfs_throttled_periods_total Number of throttled period intervals. # TYPE container_cpu_cfs_throttled_periods_total counter container_cpu_cfs_throttled_periods_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 18 1395066363000 # HELP container_cpu_cfs_throttled_seconds_total Total time duration the container has been throttled. # TYPE container_cpu_cfs_throttled_seconds_total counter container_cpu_cfs_throttled_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.724314 1395066363000 # HELP container_cpu_cfs_burst_periods_total Number of periods when burst occurs. # TYPE container_cpu_cfs_burst_periods_total counter container_cpu_cfs_burst_periods_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 25 1395066363000 # HELP container_cpu_cfs_burst_seconds_total Total time duration the container has been bursted. # TYPE container_cpu_cfs_burst_seconds_total counter container_cpu_cfs_burst_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.5 1395066363000 # HELP container_cpu_load_average_10s Value of container cpu load average over the last 10 seconds. # TYPE container_cpu_load_average_10s gauge container_cpu_load_average_10s{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2 1395066363000 # HELP container_cpu_load_d_average_10s Value of container cpu load.d average over the last 10 seconds. # TYPE container_cpu_load_d_average_10s gauge container_cpu_load_d_average_10s{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2 1395066363000 # HELP container_cpu_schedstat_run_periods_total Number of times processes of the cgroup have run on the cpu # TYPE container_cpu_schedstat_run_periods_total counter container_cpu_schedstat_run_periods_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 984285 1395066363000 # HELP container_cpu_schedstat_run_seconds_total Time duration the processes of the container have run on the CPU. # TYPE container_cpu_schedstat_run_seconds_total counter container_cpu_schedstat_run_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.053643567 1395066363000 # HELP container_cpu_schedstat_runqueue_seconds_total Time duration processes of the container have been waiting on a runqueue. # TYPE container_cpu_schedstat_runqueue_seconds_total counter container_cpu_schedstat_runqueue_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 479.424566378 1395066363000 # HELP container_cpu_system_seconds_total Cumulative system cpu time consumed in seconds. # TYPE container_cpu_system_seconds_total counter container_cpu_system_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 7e-09 1395066363000 # HELP container_cpu_usage_seconds_total Cumulative cpu time consumed in seconds. # TYPE container_cpu_usage_seconds_total counter container_cpu_usage_seconds_total{container_env_foo_env="prod",cpu="cpu00",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2e-09 1395066363000 container_cpu_usage_seconds_total{container_env_foo_env="prod",cpu="cpu01",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 3e-09 1395066363000 container_cpu_usage_seconds_total{container_env_foo_env="prod",cpu="cpu02",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4e-09 1395066363000 container_cpu_usage_seconds_total{container_env_foo_env="prod",cpu="cpu03",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 5e-09 1395066363000 # HELP container_cpu_user_seconds_total Cumulative user cpu time consumed in seconds. # TYPE container_cpu_user_seconds_total counter container_cpu_user_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 6e-09 1395066363000 # HELP container_custom_app_metric_1 Custom application metric. # TYPE container_custom_app_metric_1 gauge container_custom_app_metric_1{app_test_label="1_1",app_test_label_2="2_1",container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.1 container_custom_app_metric_1{app_test_label="1_2",app_test_label_2="2_2",container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.2 # HELP container_custom_app_metric_2 Custom application metric. # TYPE container_custom_app_metric_2 gauge container_custom_app_metric_2{app_test_label="test_value",container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2 # HELP container_custom_app_metric_3 Custom application metric. # TYPE container_custom_app_metric_3 gauge container_custom_app_metric_3{app_test_label="test_value",container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 3 # HELP container_file_descriptors Number of open file descriptors for the container. # TYPE container_file_descriptors gauge container_file_descriptors{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 5 1395066363000 # HELP container_fs_inodes_free Number of available Inodes # TYPE container_fs_inodes_free gauge container_fs_inodes_free{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 524288 1395066363000 container_fs_inodes_free{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 262144 1395066363000 # HELP container_fs_inodes_total Number of Inodes # TYPE container_fs_inodes_total gauge container_fs_inodes_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2.097152e+06 1395066363000 container_fs_inodes_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2.097152e+06 1395066363000 # HELP container_fs_io_current Number of I/Os currently in progress # TYPE container_fs_io_current gauge container_fs_io_current{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 42 1395066363000 container_fs_io_current{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 47 1395066363000 # HELP container_fs_io_time_seconds_total Cumulative count of seconds spent doing I/Os # TYPE container_fs_io_time_seconds_total counter container_fs_io_time_seconds_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.3e-08 1395066363000 container_fs_io_time_seconds_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.8e-08 1395066363000 # HELP container_fs_io_time_weighted_seconds_total Cumulative weighted I/O time in seconds # TYPE container_fs_io_time_weighted_seconds_total counter container_fs_io_time_weighted_seconds_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.4e-08 1395066363000 container_fs_io_time_weighted_seconds_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.9e-08 1395066363000 # HELP container_fs_io_cost_usage_seconds_total Cumulative IOCost usage in seconds # TYPE container_fs_io_cost_usage_seconds_total counter container_fs_io_cost_usage_seconds_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.5 1395066363000 # HELP container_fs_io_cost_wait_seconds_total Cumulative IOCost wait in seconds # TYPE container_fs_io_cost_wait_seconds_total counter container_fs_io_cost_wait_seconds_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2.5 1395066363000 # HELP container_fs_io_cost_indebt_seconds_total Cumulative IOCost debt in seconds # TYPE container_fs_io_cost_indebt_seconds_total counter container_fs_io_cost_indebt_seconds_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.5 1395066363000 # HELP container_fs_io_cost_indelay_seconds_total Cumulative IOCost delay in seconds # TYPE container_fs_io_cost_indelay_seconds_total counter container_fs_io_cost_indelay_seconds_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.75 1395066363000 # HELP container_fs_limit_bytes Number of bytes that can be consumed by the container on this filesystem. # TYPE container_fs_limit_bytes gauge container_fs_limit_bytes{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 22 1395066363000 container_fs_limit_bytes{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 37 1395066363000 # HELP container_fs_read_seconds_total Cumulative count of seconds spent reading # TYPE container_fs_read_seconds_total counter container_fs_read_seconds_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 2.7e-08 1395066363000 container_fs_read_seconds_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.2e-08 1395066363000 # HELP container_fs_reads_bytes_total Cumulative count of bytes read # TYPE container_fs_reads_bytes_total counter container_fs_reads_bytes_total{container_env_foo_env="prod",device="/dev/sdb",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 3 1395066363000 # HELP container_fs_reads_merged_total Cumulative count of reads merged # TYPE container_fs_reads_merged_total counter container_fs_reads_merged_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 25 1395066363000 container_fs_reads_merged_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 40 1395066363000 # HELP container_fs_reads_total Cumulative count of reads completed # TYPE container_fs_reads_total counter container_fs_reads_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 24 1395066363000 container_fs_reads_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 39 1395066363000 # HELP container_fs_sector_reads_total Cumulative count of sector reads completed # TYPE container_fs_sector_reads_total counter container_fs_sector_reads_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 26 1395066363000 container_fs_sector_reads_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 41 1395066363000 # HELP container_fs_sector_writes_total Cumulative count of sector writes completed # TYPE container_fs_sector_writes_total counter container_fs_sector_writes_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 40 1395066363000 container_fs_sector_writes_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 45 1395066363000 # HELP container_fs_usage_bytes Number of bytes that are consumed by the container on this filesystem. # TYPE container_fs_usage_bytes gauge container_fs_usage_bytes{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 23 1395066363000 container_fs_usage_bytes{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 38 1395066363000 # HELP container_fs_write_seconds_total Cumulative count of seconds spent writing # TYPE container_fs_write_seconds_total counter container_fs_write_seconds_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.1e-08 1395066363000 container_fs_write_seconds_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 4.6e-08 1395066363000 # HELP container_fs_writes_bytes_total Cumulative count of bytes written # TYPE container_fs_writes_bytes_total counter container_fs_writes_bytes_total{container_env_foo_env="prod",device="/dev/sdb",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 6 1395066363000 # HELP container_fs_writes_merged_total Cumulative count of writes merged # TYPE container_fs_writes_merged_total counter container_fs_writes_merged_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 39 1395066363000 container_fs_writes_merged_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 44 1395066363000 # HELP container_fs_writes_total Cumulative count of writes completed # TYPE container_fs_writes_total counter container_fs_writes_total{container_env_foo_env="prod",device="sda1",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 28 1395066363000 container_fs_writes_total{container_env_foo_env="prod",device="sda2",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 43 1395066363000 # HELP container_health_state The result of the container's health check # TYPE container_health_state gauge container_health_state{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1 1395066363000 # HELP container_hugetlb_failcnt Number of hugepage usage hits limits # TYPE container_hugetlb_failcnt counter container_hugetlb_failcnt{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",pagesize="1Gi",zone_name="hello"} 0 1395066363000 container_hugetlb_failcnt{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",pagesize="2Mi",zone_name="hello"} 1 1395066363000 # HELP container_hugetlb_max_usage_bytes Maximum hugepage usage recorded in bytes # TYPE container_hugetlb_max_usage_bytes gauge container_hugetlb_max_usage_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",pagesize="1Gi",zone_name="hello"} 0 1395066363000 container_hugetlb_max_usage_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",pagesize="2Mi",zone_name="hello"} 10 1395066363000 # HELP container_hugetlb_usage_bytes Current hugepage usage in bytes # TYPE container_hugetlb_usage_bytes gauge container_hugetlb_usage_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",pagesize="1Gi",zone_name="hello"} 0 1395066363000 container_hugetlb_usage_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",pagesize="2Mi",zone_name="hello"} 4 1395066363000 # HELP container_last_seen Last time a container was seen by the exporter # TYPE container_last_seen gauge container_last_seen{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.395066363e+09 1395066363000 # HELP container_memory_cache Number of bytes of page cache memory. # TYPE container_memory_cache gauge container_memory_cache{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 14 1395066363000 # HELP container_memory_failcnt Number of memory usage hits limits # TYPE container_memory_failcnt counter container_memory_failcnt{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0 1395066363000 # HELP container_memory_failures_total Cumulative count of memory allocation failures. # TYPE container_memory_failures_total counter container_memory_failures_total{container_env_foo_env="prod",failure_type="pgfault",id="testcontainer",image="test",name="testcontaineralias",scope="container",zone_name="hello"} 10 1395066363000 container_memory_failures_total{container_env_foo_env="prod",failure_type="pgfault",id="testcontainer",image="test",name="testcontaineralias",scope="hierarchy",zone_name="hello"} 12 1395066363000 container_memory_failures_total{container_env_foo_env="prod",failure_type="pgmajfault",id="testcontainer",image="test",name="testcontaineralias",scope="container",zone_name="hello"} 11 1395066363000 container_memory_failures_total{container_env_foo_env="prod",failure_type="pgmajfault",id="testcontainer",image="test",name="testcontaineralias",scope="hierarchy",zone_name="hello"} 13 1395066363000 # HELP container_memory_kernel_usage Size of kernel memory allocated in bytes. # TYPE container_memory_kernel_usage gauge container_memory_kernel_usage{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 17 1395066363000 # HELP container_memory_mapped_file Size of memory mapped files in bytes. # TYPE container_memory_mapped_file gauge container_memory_mapped_file{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 16 1395066363000 # HELP container_memory_max_usage_bytes Maximum memory usage recorded in bytes # TYPE container_memory_max_usage_bytes gauge container_memory_max_usage_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 8 1395066363000 # HELP container_memory_migrate Memory migrate status. # TYPE container_memory_migrate gauge container_memory_migrate{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1 1395066363000 # HELP container_memory_numa_pages Number of used pages per NUMA node # TYPE container_memory_numa_pages gauge container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="container",type="anon",zone_name="hello"} 10000 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="container",type="file",zone_name="hello"} 16649 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="container",type="unevictable",zone_name="hello"} 8900 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="hierarchy",type="anon",zone_name="hello"} 20000 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="hierarchy",type="file",zone_name="hello"} 36649 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="0",scope="hierarchy",type="unevictable",zone_name="hello"} 8900 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="container",type="anon",zone_name="hello"} 7109 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="container",type="file",zone_name="hello"} 10000 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="container",type="unevictable",zone_name="hello"} 10000 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="hierarchy",type="anon",zone_name="hello"} 7109 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="hierarchy",type="file",zone_name="hello"} 10000 1395066363000 container_memory_numa_pages{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node="1",scope="hierarchy",type="unevictable",zone_name="hello"} 20000 1395066363000 # HELP container_memory_rss Size of RSS in bytes. # TYPE container_memory_rss gauge container_memory_rss{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 15 1395066363000 # HELP container_memory_swap Container swap usage in bytes. # TYPE container_memory_swap gauge container_memory_swap{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 8192 1395066363000 # HELP container_memory_total_active_file_bytes Current total active file in bytes. # TYPE container_memory_total_active_file_bytes gauge container_memory_total_active_file_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 7 1395066363000 # HELP container_memory_total_inactive_file_bytes Current total inactive file in bytes. # TYPE container_memory_total_inactive_file_bytes gauge container_memory_total_inactive_file_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 6 1395066363000 # HELP container_memory_usage_bytes Current memory usage in bytes, including all memory regardless of when it was accessed # TYPE container_memory_usage_bytes gauge container_memory_usage_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 8 1395066363000 # HELP container_memory_working_set_bytes Current working set in bytes. # TYPE container_memory_working_set_bytes gauge container_memory_working_set_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 9 1395066363000 # HELP container_network_advance_tcp_stats_total advance tcp connections statistic for container # TYPE container_network_advance_tcp_stats_total gauge container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="activeopens",zone_name="hello"} 1.1038621e+07 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="attemptfails",zone_name="hello"} 48997 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="currestab",zone_name="hello"} 22 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="delayedacklocked",zone_name="hello"} 90 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="delayedacklost",zone_name="hello"} 18843 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="delayedacks",zone_name="hello"} 503975 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="embryonicrsts",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="estabresets",zone_name="hello"} 37 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="incsumerrors",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="inerrs",zone_name="hello"} 31 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="insegs",zone_name="hello"} 1.4037059e+08 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="ipreversepathfilter",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="listendrops",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="listenoverflows",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="lockdroppedicmps",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="maxconn",zone_name="hello"} -1 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="ofopruned",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="outofwindowicmps",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="outrsts",zone_name="hello"} 91699 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="outsegs",zone_name="hello"} 2.11580512e+08 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="passiveopens",zone_name="hello"} 59 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="pawsactive",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="pawsestab",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="pfmemallocdrop",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="prunecalled",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="rcvpruned",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="retranssegs",zone_name="hello"} 462961 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="rtoalgorithm",zone_name="hello"} 1 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="rtomax",zone_name="hello"} 120000 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="rtomin",zone_name="hello"} 200 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="syncookiesfailed",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="syncookiesrecv",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="syncookiessent",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortfailed",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortonclose",zone_name="hello"} 7 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortondata",zone_name="hello"} 8 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortonlinger",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortonmemory",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpabortontimeout",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpbacklogdrop",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdeferacceptdrop",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackignorednoundo",zone_name="hello"} 71885 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackignoredold",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackoforecv",zone_name="hello"} 10 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackofosent",zone_name="hello"} 1 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackoldsent",zone_name="hello"} 15633 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackrecv",zone_name="hello"} 83680 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpdsackundo",zone_name="hello"} 33 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfackreorder",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopenactive",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopenactivefail",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopencookiereqd",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopenlistenoverflow",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopenpassive",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastopenpassivefail",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfastretrans",zone_name="hello"} 11794 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpfullundo",zone_name="hello"} 2361 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcphpacks",zone_name="hello"} 2.1490641e+07 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcphphits",zone_name="hello"} 5.6096478e+07 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcplossfailures",zone_name="hello"} 729 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcplossproberecovery",zone_name="hello"} 401 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcplossprobes",zone_name="hello"} 88648 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcplossundo",zone_name="hello"} 61374 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcplostretransmit",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpmd5failure",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpmd5notfound",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpmd5unexpected",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpmemorypressures",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpmemorypressureschrono",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpminttldrop",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcporigdatasent",zone_name="hello"} 1.30698387e+08 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcppartialundo",zone_name="hello"} 3 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcppureacks",zone_name="hello"} 2.4251339e+07 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcprcvcollapsed",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcprenofailures",zone_name="hello"} 43414 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcprenorecovery",zone_name="hello"} 3519 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcprenorecoveryfail",zone_name="hello"} 394 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcprenoreorder",zone_name="hello"} 839 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpreqqfulldocookies",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpreqqfulldrop",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpretransfail",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackdiscard",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackfailures",zone_name="hello"} 60 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackmerged",zone_name="hello"} 6 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackrecovery",zone_name="hello"} 159 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackrecoveryfail",zone_name="hello"} 2 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackreneging",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackreorder",zone_name="hello"} 11 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackshifted",zone_name="hello"} 2 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsackshiftfallback",zone_name="hello"} 298 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpslowstartretrans",zone_name="hello"} 290832 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpspuriousrtos",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcpsynretrans",zone_name="hello"} 988 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcptimeouts",zone_name="hello"} 27422 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcptimewaitoverflow",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tcptsreorder",zone_name="hello"} 3 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="tw",zone_name="hello"} 1.0436427e+07 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="twkilled",zone_name="hello"} 0 1395066363000 container_network_advance_tcp_stats_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="twrecycled",zone_name="hello"} 0 1395066363000 # HELP container_network_receive_bytes_total Cumulative count of bytes received # TYPE container_network_receive_bytes_total counter container_network_receive_bytes_total{container_env_foo_env="prod",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 14 1395066363000 # HELP container_network_receive_errors_total Cumulative count of errors encountered while receiving # TYPE container_network_receive_errors_total counter container_network_receive_errors_total{container_env_foo_env="prod",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 16 1395066363000 # HELP container_network_receive_packets_dropped_total Cumulative count of packets dropped while receiving # TYPE container_network_receive_packets_dropped_total counter container_network_receive_packets_dropped_total{container_env_foo_env="prod",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 17 1395066363000 # HELP container_network_receive_packets_total Cumulative count of packets received # TYPE container_network_receive_packets_total counter container_network_receive_packets_total{container_env_foo_env="prod",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 15 1395066363000 # HELP container_network_tcp6_usage_total tcp6 connection usage statistic for container # TYPE container_network_tcp6_usage_total gauge container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="close",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="closewait",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="closing",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="established",zone_name="hello"} 11 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="finwait1",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="finwait2",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="lastack",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="listen",zone_name="hello"} 3 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="synrecv",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="synsent",zone_name="hello"} 0 1395066363000 container_network_tcp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="timewait",zone_name="hello"} 0 1395066363000 # HELP container_network_tcp_usage_total tcp connection usage statistic for container # TYPE container_network_tcp_usage_total gauge container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="close",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="closewait",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="closing",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="established",zone_name="hello"} 13 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="finwait1",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="finwait2",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="lastack",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="listen",zone_name="hello"} 3 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="synrecv",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="synsent",zone_name="hello"} 0 1395066363000 container_network_tcp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",tcp_state="timewait",zone_name="hello"} 0 1395066363000 # HELP container_network_transmit_bytes_total Cumulative count of bytes transmitted # TYPE container_network_transmit_bytes_total counter container_network_transmit_bytes_total{container_env_foo_env="prod",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 18 1395066363000 # HELP container_network_transmit_errors_total Cumulative count of errors encountered while transmitting # TYPE container_network_transmit_errors_total counter container_network_transmit_errors_total{container_env_foo_env="prod",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 20 1395066363000 # HELP container_network_transmit_packets_dropped_total Cumulative count of packets dropped while transmitting # TYPE container_network_transmit_packets_dropped_total counter container_network_transmit_packets_dropped_total{container_env_foo_env="prod",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 21 1395066363000 # HELP container_network_transmit_packets_total Cumulative count of packets transmitted # TYPE container_network_transmit_packets_total counter container_network_transmit_packets_total{container_env_foo_env="prod",id="testcontainer",image="test",interface="eth0",name="testcontaineralias",zone_name="hello"} 19 1395066363000 # HELP container_network_udp6_usage_total udp6 connection usage statistic for container # TYPE container_network_udp6_usage_total gauge container_network_udp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",udp_state="dropped",zone_name="hello"} 0 1395066363000 container_network_udp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",udp_state="listen",zone_name="hello"} 0 1395066363000 container_network_udp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",udp_state="rxqueued",zone_name="hello"} 0 1395066363000 container_network_udp6_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",udp_state="txqueued",zone_name="hello"} 0 1395066363000 # HELP container_network_udp_usage_total udp connection usage statistic for container # TYPE container_network_udp_usage_total gauge container_network_udp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",udp_state="dropped",zone_name="hello"} 0 1395066363000 container_network_udp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",udp_state="listen",zone_name="hello"} 0 1395066363000 container_network_udp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",udp_state="rxqueued",zone_name="hello"} 0 1395066363000 container_network_udp_usage_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",udp_state="txqueued",zone_name="hello"} 0 1395066363000 # HELP container_oom_events_total Count of out of memory events observed for the container # TYPE container_oom_events_total counter container_oom_events_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0 1395066363000 # HELP container_perf_events_total Perf event metric. # TYPE container_perf_events_total counter container_perf_events_total{container_env_foo_env="prod",cpu="0",event="instructions",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 123 1395066363000 container_perf_events_total{container_env_foo_env="prod",cpu="0",event="instructions_retired",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 321 1395066363000 container_perf_events_total{container_env_foo_env="prod",cpu="1",event="instructions",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 456 1395066363000 container_perf_events_total{container_env_foo_env="prod",cpu="1",event="instructions_retired",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 789 1395066363000 # HELP container_perf_events_scaling_ratio Perf event metric scaling ratio. # TYPE container_perf_events_scaling_ratio gauge container_perf_events_scaling_ratio{container_env_foo_env="prod",cpu="0",event="instructions",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1 1395066363000 container_perf_events_scaling_ratio{container_env_foo_env="prod",cpu="0",event="instructions_retired",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.66666666666 1395066363000 container_perf_events_scaling_ratio{container_env_foo_env="prod",cpu="1",event="instructions",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.5 1395066363000 container_perf_events_scaling_ratio{container_env_foo_env="prod",cpu="1",event="instructions_retired",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.33333333333 1395066363000 # HELP container_perf_uncore_events_total Perf uncore event metric. # TYPE container_perf_uncore_events_total counter container_perf_uncore_events_total{container_env_foo_env="prod",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="0",zone_name="hello"} 1.231231512e+09 1395066363000 container_perf_uncore_events_total{container_env_foo_env="prod",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="1",zone_name="hello"} 1.111231331e+09 1395066363000 # HELP container_perf_uncore_events_scaling_ratio Perf uncore event metric scaling ratio. # TYPE container_perf_uncore_events_scaling_ratio gauge container_perf_uncore_events_scaling_ratio{container_env_foo_env="prod",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="0",zone_name="hello"} 1 1395066363000 container_perf_uncore_events_scaling_ratio{container_env_foo_env="prod",event="cas_count_read",id="testcontainer",image="test",name="testcontaineralias",pmu="uncore_imc_0",socket="1",zone_name="hello"} 1 1395066363000 # HELP container_pressure_cpu_stalled_seconds_total Total time duration no tasks in the container could make progress due to CPU congestion. # TYPE container_pressure_cpu_stalled_seconds_total counter container_pressure_cpu_stalled_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.0001 1395066363000 # HELP container_pressure_cpu_waiting_seconds_total Total time duration tasks in the container have waited due to CPU congestion. # TYPE container_pressure_cpu_waiting_seconds_total counter container_pressure_cpu_waiting_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.0002 1395066363000 # HELP container_pressure_io_stalled_seconds_total Total time duration no tasks in the container could make progress due to IO congestion. # TYPE container_pressure_io_stalled_seconds_total counter container_pressure_io_stalled_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.0011 1395066363000 # HELP container_pressure_io_waiting_seconds_total Total time duration tasks in the container have waited due to IO congestion. # TYPE container_pressure_io_waiting_seconds_total counter container_pressure_io_waiting_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.0022 1395066363000 # HELP container_pressure_memory_stalled_seconds_total Total time duration no tasks in the container could make progress due to memory congestion. # TYPE container_pressure_memory_stalled_seconds_total counter container_pressure_memory_stalled_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.001 1395066363000 # HELP container_pressure_memory_waiting_seconds_total Total time duration tasks in the container have waited due to memory congestion. # TYPE container_pressure_memory_waiting_seconds_total counter container_pressure_memory_waiting_seconds_total{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 0.002 1395066363000 # HELP container_processes Number of processes running inside the container. # TYPE container_processes gauge container_processes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1 1395066363000 # HELP container_referenced_bytes Container referenced bytes during last measurements cycle # TYPE container_referenced_bytes gauge container_referenced_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1234 1395066363000 # HELP container_scrape_error 1 if there was an error while getting container metrics, 0 otherwise # TYPE container_scrape_error gauge container_scrape_error 0 # HELP container_sockets Number of open sockets for the container. # TYPE container_sockets gauge container_sockets{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 3 1395066363000 # HELP container_spec_cpu_period CPU period of the container. # TYPE container_spec_cpu_period gauge container_spec_cpu_period{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 100000 # HELP container_spec_cpu_quota CPU quota of the container. # TYPE container_spec_cpu_quota gauge container_spec_cpu_quota{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 10000 # HELP container_spec_cpu_shares CPU share of the container. # TYPE container_spec_cpu_shares gauge container_spec_cpu_shares{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1000 # HELP container_creation_time_seconds Container creation time since unix epoch in seconds. # TYPE container_creation_time_seconds gauge container_creation_time_seconds{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.257894e+09 # HELP container_start_time_seconds Start time of the container since unix epoch in seconds. # TYPE container_start_time_seconds gauge container_start_time_seconds{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 1.257895e+09 # HELP container_tasks_state Number of tasks in given state # TYPE container_tasks_state gauge container_tasks_state{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",state="iowaiting",zone_name="hello"} 54 1395066363000 container_tasks_state{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",state="running",zone_name="hello"} 51 1395066363000 container_tasks_state{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",state="sleeping",zone_name="hello"} 50 1395066363000 container_tasks_state{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",state="stopped",zone_name="hello"} 52 1395066363000 container_tasks_state{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",state="uninterruptible",zone_name="hello"} 53 1395066363000 # HELP container_threads Number of threads running inside the container # TYPE container_threads gauge container_threads{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 5 1395066363000 # HELP container_threads_max Maximum number of threads allowed inside the container, infinity if value is zero # TYPE container_threads_max gauge container_threads_max{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",zone_name="hello"} 100 1395066363000 # HELP container_ulimits_soft Soft ulimit values for the container root process. Unlimited if -1, except priority and nice # TYPE container_ulimits_soft gauge container_ulimits_soft{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",ulimit="max_open_files",zone_name="hello"} 16384 1395066363000 # HELP container_llc_occupancy_bytes Last level cache usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM). # TYPE container_llc_occupancy_bytes gauge container_llc_occupancy_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node_id="0",zone_name="hello"} 162626 1395066363000 container_llc_occupancy_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node_id="1",zone_name="hello"} 213777 1395066363000 # HELP container_memory_bandwidth_bytes Total memory bandwidth usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM). # TYPE container_memory_bandwidth_bytes gauge container_memory_bandwidth_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node_id="0",zone_name="hello"} 4.512312e+06 1395066363000 container_memory_bandwidth_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node_id="1",zone_name="hello"} 2.173713e+06 1395066363000 # HELP container_memory_bandwidth_local_bytes Local memory bandwidth usage statistics for container counted with RDT Memory Bandwidth Monitoring (MBM). # TYPE container_memory_bandwidth_local_bytes gauge container_memory_bandwidth_local_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node_id="0",zone_name="hello"} 2.390393e+06 1395066363000 container_memory_bandwidth_local_bytes{container_env_foo_env="prod",id="testcontainer",image="test",name="testcontaineralias",node_id="1",zone_name="hello"} 1.231233e+06 1395066363000 ================================================ FILE: nvm/machine_libipmctl.go ================================================ //go:build libipmctl && cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package nvm // #cgo pkg-config: libipmctl // #include import "C" import ( "fmt" "sync" info "github.com/google/cadvisor/info/v1" "k8s.io/klog/v2" ) var ( isNVMLibInitialized = false nvmLibMutex = sync.Mutex{} ) func init() { nvmLibMutex.Lock() defer nvmLibMutex.Unlock() cErr := C.nvm_init() if cErr != C.NVM_SUCCESS { // Unfortunately klog does not seem to work here. I believe it's better to // output information using fmt rather then let it disappear silently. fmt.Printf("libipmctl initialization failed with status %d", cErr) return } isNVMLibInitialized = true } // getAvgPowerBudget retrieves configured power budget // (in watts) for NVM devices. When libipmctl is not available // zero is returned. func getAvgPowerBudget() (uint, error) { // Get number of devices on the platform // see: https://github.com/intel/ipmctl/blob/v01.00.00.3497/src/os/nvm_api/nvm_management.h#L1478 count := C.uint(0) err := C.nvm_get_number_of_devices(&count) if err != C.NVM_SUCCESS { klog.Warningf("Unable to get number of NVM devices. Status code: %d", err) return uint(0), fmt.Errorf("Unable to get number of NVM devices. Status code: %d", err) } if count == 0 { klog.V(4).Infof("There are no NVM devices.") return uint(0), nil } // Load basic device information for all the devices // to obtain UID of the first one. devices := make([]C.struct_device_discovery, count) err = C.nvm_get_devices(&devices[0], C.uchar(count)) if err != C.NVM_SUCCESS { klog.Warningf("Unable to get all NVM devices. Status code: %d", err) return uint(0), fmt.Errorf("Unable to get all NVM devices. Status code: %d", err) } // Power budget is same for all the devices // so we can rely on any of them. device := C.struct_device_details{} err = C.nvm_get_device_details(&devices[0].uid[0], &device) if err != C.NVM_SUCCESS { uid := C.GoString(&devices[0].uid[0]) klog.Warningf("Unable to get details of NVM device %q. Status code: %d", uid, err) return uint(0), fmt.Errorf("Unable to get details of NVM device %q. Status code: %d", uid, err) } return uint(device.avg_power_budget / 1000), nil } // getCapacities retrieves the total NVM capacity in bytes for memory mode and app direct mode func getCapacities() (uint64, uint64, error) { caps := C.struct_device_capacities{} err := C.nvm_get_nvm_capacities(&caps) if err != C.NVM_SUCCESS { klog.Warningf("Unable to get NVM capacity. Status code: %d", err) return uint64(0), uint64(0), fmt.Errorf("Unable to get NVM capacity. Status code: %d", err) } return uint64(caps.memory_capacity), uint64(caps.app_direct_capacity), nil } // GetInfo returns information specific for non-volatile memory modules func GetInfo() (info.NVMInfo, error) { nvmLibMutex.Lock() defer nvmLibMutex.Unlock() nvmInfo := info.NVMInfo{} if !isNVMLibInitialized { klog.V(1).Info("libipmctl has not been initialized. NVM information will not be available") return nvmInfo, nil } var err error nvmInfo.MemoryModeCapacity, nvmInfo.AppDirectModeCapacity, err = getCapacities() if err != nil { return info.NVMInfo{}, fmt.Errorf("Unable to get NVM capacities, err: %s", err) } nvmInfo.AvgPowerBudget, err = getAvgPowerBudget() if err != nil { return info.NVMInfo{}, fmt.Errorf("Unable to get NVM average power budget, err: %s", err) } return nvmInfo, nil } // Finalize un-initializes libipmctl. See https://github.com/google/cadvisor/issues/2457. func Finalize() { nvmLibMutex.Lock() defer nvmLibMutex.Unlock() klog.V(1).Info("Attempting to un-initialize libipmctl") if !isNVMLibInitialized { klog.V(1).Info("libipmctl has not been initialized; not un-initializing.") return } C.nvm_uninit() isNVMLibInitialized = false } ================================================ FILE: nvm/machine_no_libipmctl.go ================================================ //go:build !libipmctl || !cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package nvm import ( "k8s.io/klog/v2" info "github.com/google/cadvisor/info/v1" ) // GetInfo returns information specific for non-volatile memory modules. // When libipmctl is not available zero value is returned. func GetInfo() (info.NVMInfo, error) { return info.NVMInfo{}, nil } // Finalize un-initializes libipmctl. See https://github.com/google/cadvisor/issues/2457. // When libipmctl is not available it just logs that it's being called. func Finalize() { klog.V(4).Info("libipmctl not available, doing nothing.") } ================================================ FILE: perf/collector_libpfm.go ================================================ //go:build libpfm && cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Collector of perf events for a container. package perf // #cgo CFLAGS: -I/usr/include // #cgo LDFLAGS: -lpfm // #include // #include // #include import "C" import ( "bytes" "encoding/binary" "fmt" "os" "sync" "unsafe" "golang.org/x/sys/unix" "k8s.io/klog/v2" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/stats" ) type collector struct { cgroupPath string events PerfEvents cpuFiles map[int]group cpuFilesLock sync.Mutex onlineCPUs []int eventToCustomEvent map[Event]*CustomEvent uncore stats.Collector // Handle for mocking purposes. perfEventOpen func(attr *unix.PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) ioctlSetInt func(fd int, req uint, value int) error } type group struct { cpuFiles map[string]map[int]readerCloser names []string leaderName string } var ( isLibpfmInitialized = false libpfmMutex = sync.Mutex{} ) const ( groupLeaderFileDescriptor = -1 ) func init() { libpfmMutex.Lock() defer libpfmMutex.Unlock() pErr := C.pfm_initialize() if pErr != C.PFM_SUCCESS { klog.Errorf("unable to initialize libpfm: %d", int(pErr)) return } isLibpfmInitialized = true } func newCollector(cgroupPath string, events PerfEvents, onlineCPUs []int, cpuToSocket map[int]int) *collector { collector := &collector{cgroupPath: cgroupPath, events: events, onlineCPUs: onlineCPUs, cpuFiles: map[int]group{}, uncore: NewUncoreCollector(cgroupPath, events, cpuToSocket), perfEventOpen: unix.PerfEventOpen, ioctlSetInt: unix.IoctlSetInt} mapEventsToCustomEvents(collector) return collector } func (c *collector) UpdateStats(stats *info.ContainerStats) error { err := c.uncore.UpdateStats(stats) if err != nil { klog.Errorf("Failed to get uncore perf event stats: %v", err) } c.cpuFilesLock.Lock() defer c.cpuFilesLock.Unlock() stats.PerfStats = []info.PerfStat{} klog.V(5).Infof("Attempting to update perf_event stats from cgroup %q", c.cgroupPath) for _, group := range c.cpuFiles { for cpu, file := range group.cpuFiles[group.leaderName] { stat, err := readGroupPerfStat(file, group, cpu, c.cgroupPath) if err != nil { klog.Warningf("Unable to read from perf_event_file (event: %q, CPU: %d) for %q: %q", group.leaderName, cpu, c.cgroupPath, err.Error()) continue } stats.PerfStats = append(stats.PerfStats, stat...) } } return nil } func readGroupPerfStat(file readerCloser, group group, cpu int, cgroupPath string) ([]info.PerfStat, error) { values, err := getPerfValues(file, group) if err != nil { return nil, err } perfStats := make([]info.PerfStat, len(values)) for i, value := range values { klog.V(5).Infof("Read metric for event %q for cpu %d from cgroup %q: %d", value.Name, cpu, cgroupPath, value.Value) perfStats[i] = info.PerfStat{ PerfValue: value, Cpu: cpu, } } return perfStats, nil } func getPerfValues(file readerCloser, group group) ([]info.PerfValue, error) { // 24 bytes of GroupReadFormat struct. // 16 bytes of Values struct for each element in group. // See https://man7.org/linux/man-pages/man2/perf_event_open.2.html section "Reading results" with PERF_FORMAT_GROUP specified. buf := make([]byte, 24+16*len(group.names)) _, err := file.Read(buf) if err != nil { return []info.PerfValue{}, fmt.Errorf("unable to read perf event group ( leader = %s ): %w", group.leaderName, err) } perfData := &GroupReadFormat{} reader := bytes.NewReader(buf[:24]) err = binary.Read(reader, binary.LittleEndian, perfData) if err != nil { return []info.PerfValue{}, fmt.Errorf("unable to decode perf event group ( leader = %s ): %w", group.leaderName, err) } values := make([]Values, perfData.Nr) reader = bytes.NewReader(buf[24:]) err = binary.Read(reader, binary.LittleEndian, values) if err != nil { return []info.PerfValue{}, fmt.Errorf("unable to decode perf event group values ( leader = %s ): %w", group.leaderName, err) } scalingRatio := 1.0 if perfData.TimeRunning != 0 && perfData.TimeEnabled != 0 { scalingRatio = float64(perfData.TimeRunning) / float64(perfData.TimeEnabled) } perfValues := make([]info.PerfValue, perfData.Nr) if scalingRatio != float64(0) { for i, name := range group.names { perfValues[i] = info.PerfValue{ ScalingRatio: scalingRatio, Value: uint64(float64(values[i].Value) / scalingRatio), Name: name, } } } else { for i, name := range group.names { perfValues[i] = info.PerfValue{ ScalingRatio: scalingRatio, Value: values[i].Value, Name: name, } } } return perfValues, nil } func (c *collector) setup() error { cgroup, err := os.Open(c.cgroupPath) if err != nil { return fmt.Errorf("unable to open cgroup directory %s: %s", c.cgroupPath, err) } defer cgroup.Close() c.cpuFilesLock.Lock() defer c.cpuFilesLock.Unlock() cgroupFd := int(cgroup.Fd()) groupIndex := 0 for _, group := range c.events.Core.Events { // CPUs file descriptors of group leader needed for perf_event_open. leaderFileDescriptors := make(map[int]int, len(c.onlineCPUs)) for _, cpu := range c.onlineCPUs { leaderFileDescriptors[cpu] = groupLeaderFileDescriptor } leaderFileDescriptors, err := c.createLeaderFileDescriptors(group.events, cgroupFd, groupIndex, leaderFileDescriptors) if err != nil { klog.Errorf("Cannot count perf event group %v: %v", group.events, err) c.deleteGroup(groupIndex) continue } else { groupIndex++ } // Group is prepared so we should reset and enable counting. for _, fd := range leaderFileDescriptors { err = c.ioctlSetInt(fd, unix.PERF_EVENT_IOC_RESET, 0) if err != nil { return err } err = c.ioctlSetInt(fd, unix.PERF_EVENT_IOC_ENABLE, 0) if err != nil { return err } } } return nil } func (c *collector) createLeaderFileDescriptors(events []Event, cgroupFd int, groupIndex int, leaderFileDescriptors map[int]int) (map[int]int, error) { for j, event := range events { // First element is group leader. isGroupLeader := j == 0 customEvent, ok := c.eventToCustomEvent[event] var err error if ok { config := c.createConfigFromRawEvent(customEvent) leaderFileDescriptors, err = c.registerEvent(eventInfo{string(customEvent.Name), config, cgroupFd, groupIndex, isGroupLeader}, leaderFileDescriptors) if err != nil { return nil, fmt.Errorf("cannot register perf event: %v", err) } } else { config, err := c.createConfigFromEvent(event) if err != nil { return nil, fmt.Errorf("cannot create config from perf event: %v", err) } leaderFileDescriptors, err = c.registerEvent(eventInfo{string(event), config, cgroupFd, groupIndex, isGroupLeader}, leaderFileDescriptors) if err != nil { return nil, fmt.Errorf("cannot register perf event: %v", err) } // Clean memory allocated by C code. C.free(unsafe.Pointer(config)) } } return leaderFileDescriptors, nil } func readPerfEventAttr(name string, pfmGetOsEventEncoding func(string, unsafe.Pointer) error) (*unix.PerfEventAttr, error) { perfEventAttrMemory := C.malloc(C.size_t(unsafe.Sizeof(unix.PerfEventAttr{}))) // Fill memory with 0 values. C.memset(perfEventAttrMemory, 0, C.size_t(unsafe.Sizeof(unix.PerfEventAttr{}))) err := pfmGetOsEventEncoding(name, unsafe.Pointer(perfEventAttrMemory)) if err != nil { return nil, err } return (*unix.PerfEventAttr)(perfEventAttrMemory), nil } func pfmGetOsEventEncoding(name string, perfEventAttrMemory unsafe.Pointer) error { event := pfmPerfEncodeArgT{} fstr := C.CString("") defer C.free(unsafe.Pointer(fstr)) event.fstr = unsafe.Pointer(fstr) event.attr = perfEventAttrMemory event.size = C.size_t(unsafe.Sizeof(event)) cSafeName := C.CString(name) defer C.free(unsafe.Pointer(cSafeName)) pErr := C.pfm_get_os_event_encoding(cSafeName, C.PFM_PLM0|C.PFM_PLM3, C.PFM_OS_PERF_EVENT, unsafe.Pointer(&event)) if pErr != C.PFM_SUCCESS { return fmt.Errorf("unable to transform event name %s to perf_event_attr: %d", name, int(pErr)) } return nil } type eventInfo struct { name string config *unix.PerfEventAttr pid int groupIndex int isGroupLeader bool } func (c *collector) registerEvent(event eventInfo, leaderFileDescriptors map[int]int) (map[int]int, error) { newLeaderFileDescriptors := make(map[int]int, len(c.onlineCPUs)) var pid, flags int if event.isGroupLeader { pid = event.pid flags = unix.PERF_FLAG_FD_CLOEXEC | unix.PERF_FLAG_PID_CGROUP } else { pid = -1 flags = unix.PERF_FLAG_FD_CLOEXEC } setAttributes(event.config, event.isGroupLeader) for _, cpu := range c.onlineCPUs { fd, err := c.perfEventOpen(event.config, pid, cpu, leaderFileDescriptors[cpu], flags) if err != nil { return leaderFileDescriptors, fmt.Errorf("setting up perf event %#v failed: %q", event.config, err) } perfFile := os.NewFile(uintptr(fd), event.name) if perfFile == nil { return leaderFileDescriptors, fmt.Errorf("unable to create os.File from file descriptor %#v", fd) } c.addEventFile(event.groupIndex, event.name, cpu, perfFile) // If group leader, save fd for others. if event.isGroupLeader { newLeaderFileDescriptors[cpu] = fd } } if event.isGroupLeader { return newLeaderFileDescriptors, nil } return leaderFileDescriptors, nil } func (c *collector) addEventFile(index int, name string, cpu int, perfFile *os.File) { _, ok := c.cpuFiles[index] if !ok { c.cpuFiles[index] = group{ leaderName: name, cpuFiles: map[string]map[int]readerCloser{}, } } _, ok = c.cpuFiles[index].cpuFiles[name] if !ok { c.cpuFiles[index].cpuFiles[name] = map[int]readerCloser{} } c.cpuFiles[index].cpuFiles[name][cpu] = perfFile // Check if name is already stored. for _, have := range c.cpuFiles[index].names { if name == have { return } } // Otherwise save it. c.cpuFiles[index] = group{ cpuFiles: c.cpuFiles[index].cpuFiles, names: append(c.cpuFiles[index].names, name), leaderName: c.cpuFiles[index].leaderName, } } func (c *collector) deleteGroup(index int) { for name, files := range c.cpuFiles[index].cpuFiles { for cpu, file := range files { klog.V(5).Infof("Closing perf event file descriptor for cgroup %q, event %q and CPU %d", c.cgroupPath, name, cpu) err := file.Close() if err != nil { klog.Warningf("Unable to close perf event file descriptor for cgroup %q, event %q and CPU %d", c.cgroupPath, name, cpu) } } } delete(c.cpuFiles, index) } func createPerfEventAttr(event CustomEvent) *unix.PerfEventAttr { length := len(event.Config) config := &unix.PerfEventAttr{ Type: event.Type, Config: event.Config[0], } if length >= 2 { config.Ext1 = event.Config[1] } if length == 3 { config.Ext2 = event.Config[2] } klog.V(5).Infof("perf_event_attr struct prepared: %#v", config) return config } func setAttributes(config *unix.PerfEventAttr, leader bool) { config.Sample_type = unix.PERF_SAMPLE_IDENTIFIER config.Read_format = unix.PERF_FORMAT_TOTAL_TIME_ENABLED | unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_GROUP | unix.PERF_FORMAT_ID config.Bits = unix.PerfBitInherit // Group leader should have this flag set to disable counting until all group would be prepared. if leader { config.Bits |= unix.PerfBitDisabled } config.Size = uint32(unsafe.Sizeof(unix.PerfEventAttr{})) } func (c *collector) Destroy() { c.uncore.Destroy() c.cpuFilesLock.Lock() defer c.cpuFilesLock.Unlock() for i := range c.cpuFiles { c.deleteGroup(i) } } // Finalize terminates libpfm4 to free resources. func Finalize() { libpfmMutex.Lock() defer libpfmMutex.Unlock() klog.V(1).Info("Attempting to terminate libpfm4") if !isLibpfmInitialized { klog.V(1).Info("libpfm4 has not been initialized; not terminating.") return } C.pfm_terminate() isLibpfmInitialized = false } func mapEventsToCustomEvents(collector *collector) { collector.eventToCustomEvent = map[Event]*CustomEvent{} for key, event := range collector.events.Core.CustomEvents { collector.eventToCustomEvent[event.Name] = &collector.events.Core.CustomEvents[key] } } func (c *collector) createConfigFromRawEvent(event *CustomEvent) *unix.PerfEventAttr { klog.V(5).Infof("Setting up raw perf event %#v", event) config := createPerfEventAttr(*event) klog.V(5).Infof("perf_event_attr: %#v", config) return config } func (c *collector) createConfigFromEvent(event Event) (*unix.PerfEventAttr, error) { klog.V(5).Infof("Setting up perf event %s", string(event)) config, err := readPerfEventAttr(string(event), pfmGetOsEventEncoding) if err != nil { C.free((unsafe.Pointer)(config)) return nil, err } klog.V(5).Infof("perf_event_attr: %#v", config) return config, nil } ================================================ FILE: perf/collector_libpfm_test.go ================================================ //go:build libpfm && cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Collector of perf events for a container. package perf import ( "bytes" "encoding/binary" "os" "testing" "unsafe" "golang.org/x/sys/unix" "github.com/stretchr/testify/assert" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/stats" ) type buffer struct { *bytes.Buffer } func (b buffer) Close() error { return nil } func TestCollector_UpdateStats(t *testing.T) { collector := collector{uncore: &stats.NoopCollector{}} notScaledBuffer := buffer{bytes.NewBuffer([]byte{})} scaledBuffer := buffer{bytes.NewBuffer([]byte{})} groupedBuffer := buffer{bytes.NewBuffer([]byte{})} err := binary.Write(notScaledBuffer, binary.LittleEndian, GroupReadFormat{ Nr: 1, TimeEnabled: 100, TimeRunning: 100, }) assert.NoError(t, err) err = binary.Write(notScaledBuffer, binary.LittleEndian, Values{ Value: 123456789, ID: 0, }) assert.NoError(t, err) err = binary.Write(scaledBuffer, binary.LittleEndian, GroupReadFormat{ Nr: 1, TimeEnabled: 3, TimeRunning: 1, }) assert.NoError(t, err) err = binary.Write(scaledBuffer, binary.LittleEndian, Values{ Value: 333333333, ID: 2, }) assert.NoError(t, err) err = binary.Write(groupedBuffer, binary.LittleEndian, GroupReadFormat{ Nr: 2, TimeEnabled: 100, TimeRunning: 100, }) assert.NoError(t, err) err = binary.Write(groupedBuffer, binary.LittleEndian, Values{ Value: 123456, ID: 0, }) assert.NoError(t, err) err = binary.Write(groupedBuffer, binary.LittleEndian, Values{ Value: 654321, ID: 1, }) assert.NoError(t, err) collector.cpuFiles = map[int]group{ 1: { cpuFiles: map[string]map[int]readerCloser{ "instructions": {0: notScaledBuffer}, }, names: []string{"instructions"}, leaderName: "instructions", }, 2: { cpuFiles: map[string]map[int]readerCloser{ "cycles": {11: scaledBuffer}, }, names: []string{"cycles"}, leaderName: "cycles", }, 3: { cpuFiles: map[string]map[int]readerCloser{ "cache-misses": { 0: groupedBuffer, }, }, names: []string{"cache-misses", "cache-references"}, leaderName: "cache-misses", }, } stats := &info.ContainerStats{} err = collector.UpdateStats(stats) assert.NoError(t, err) assert.Len(t, stats.PerfStats, 4) assert.Contains(t, stats.PerfStats, info.PerfStat{ PerfValue: info.PerfValue{ ScalingRatio: 0.3333333333333333, Value: 999999999, Name: "cycles", }, Cpu: 11, }) assert.Contains(t, stats.PerfStats, info.PerfStat{ PerfValue: info.PerfValue{ ScalingRatio: 1, Value: 123456789, Name: "instructions", }, Cpu: 0, }) assert.Contains(t, stats.PerfStats, info.PerfStat{ PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 123456, Name: "cache-misses", }, Cpu: 0, }) assert.Contains(t, stats.PerfStats, info.PerfStat{ PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 654321, Name: "cache-references", }, Cpu: 0, }) } func TestCreatePerfEventAttr(t *testing.T) { event := CustomEvent{ Type: 0x1, Config: Config{uint64(0x2), uint64(0x3), uint64(0x4)}, Name: "fake_event", } attributes := createPerfEventAttr(event) assert.Equal(t, uint32(1), attributes.Type) assert.Equal(t, uint64(2), attributes.Config) assert.Equal(t, uint64(3), attributes.Ext1) assert.Equal(t, uint64(4), attributes.Ext2) } func TestSetGroupAttributes(t *testing.T) { event := CustomEvent{ Type: 0x1, Config: Config{uint64(0x2), uint64(0x3), uint64(0x4)}, Name: "fake_event", } attributes := createPerfEventAttr(event) setAttributes(attributes, true) assert.Equal(t, uint64(65536), attributes.Sample_type) assert.Equal(t, uint64(0xf), attributes.Read_format) assert.Equal(t, uint64(0x3), attributes.Bits) attributes = createPerfEventAttr(event) setAttributes(attributes, false) assert.Equal(t, uint64(65536), attributes.Sample_type) assert.Equal(t, uint64(0xf), attributes.Read_format) assert.Equal(t, uint64(0x2), attributes.Bits) } func TestNewCollector(t *testing.T) { perfCollector := newCollector("cgroup", PerfEvents{ Core: Events{ Events: []Group{{[]Event{"event_1"}, false}, {[]Event{"event_2"}, false}}, CustomEvents: []CustomEvent{{ Type: 0, Config: []uint64{1, 2, 3}, Name: "event_2", }}, }, }, []int{0, 1, 2, 3}, map[int]int{}) assert.Len(t, perfCollector.eventToCustomEvent, 1) assert.Nil(t, perfCollector.eventToCustomEvent[Event("event_1")]) assert.Same(t, &perfCollector.events.Core.CustomEvents[0], perfCollector.eventToCustomEvent[Event("event_2")]) } func TestCollectorSetup(t *testing.T) { path, err := os.MkdirTemp("", "cgroup") assert.Nil(t, err) defer func() { err := os.RemoveAll(path) assert.Nil(t, err) }() events := PerfEvents{ Core: Events{ Events: []Group{ {[]Event{"cache-misses"}, false}, {[]Event{"non-existing-event"}, false}, }, }, } c := newCollector(path, events, []int{0}, map[int]int{0: 0}) c.perfEventOpen = func(attr *unix.PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { return int(attr.Config), nil } c.ioctlSetInt = func(fd int, req uint, value int) error { return nil } err = c.setup() assert.Nil(t, err) assert.Equal(t, 1, len(c.cpuFiles)) assert.Equal(t, []string{"cache-misses"}, c.cpuFiles[0].names) } var readGroupPerfStatCases = []struct { test string file GroupReadFormat valuesFile Values name string cpu int perfStat []info.PerfStat err error }{ { test: "no scaling", file: GroupReadFormat{ TimeEnabled: 0, TimeRunning: 0, Nr: 1, }, valuesFile: Values{ Value: 5, ID: 0, }, name: "some metric", cpu: 1, perfStat: []info.PerfStat{{ PerfValue: info.PerfValue{ ScalingRatio: 1, Value: 5, Name: "some metric", }, Cpu: 1, }}, err: nil, }, { test: "no scaling - TimeEnabled = 0", file: GroupReadFormat{ TimeEnabled: 0, TimeRunning: 1, Nr: 1, }, valuesFile: Values{ Value: 5, ID: 0, }, name: "some metric", cpu: 1, perfStat: []info.PerfStat{{ PerfValue: info.PerfValue{ ScalingRatio: 1, Value: 5, Name: "some metric", }, Cpu: 1, }}, err: nil, }, { test: "scaling - 0.5", file: GroupReadFormat{ TimeEnabled: 4, TimeRunning: 2, Nr: 1, }, valuesFile: Values{ Value: 4, ID: 0, }, name: "some metric", cpu: 2, perfStat: []info.PerfStat{{ PerfValue: info.PerfValue{ ScalingRatio: 0.5, Value: 8, Name: "some metric", }, Cpu: 2, }}, err: nil, }, { test: "scaling - 0 (TimeEnabled = 1, TimeRunning = 0)", file: GroupReadFormat{ TimeEnabled: 1, TimeRunning: 0, Nr: 1, }, valuesFile: Values{ Value: 4, ID: 0, }, name: "some metric", cpu: 3, perfStat: []info.PerfStat{{ PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 4, Name: "some metric", }, Cpu: 3, }}, err: nil, }, { test: "scaling - 0 (TimeEnabled = 0, TimeRunning = 1)", file: GroupReadFormat{ TimeEnabled: 0, TimeRunning: 1, Nr: 1, }, valuesFile: Values{ Value: 4, ID: 0, }, name: "some metric", cpu: 3, perfStat: []info.PerfStat{{ PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 4, Name: "some metric", }, Cpu: 3, }}, err: nil, }, { test: "zeros, zeros everywhere", file: GroupReadFormat{ TimeEnabled: 0, TimeRunning: 0, Nr: 1, }, valuesFile: Values{ Value: 0, ID: 0, }, name: "some metric", cpu: 4, perfStat: []info.PerfStat{{ PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 0, Name: "some metric", }, Cpu: 4, }}, err: nil, }, { test: "non-zero TimeRunning", file: GroupReadFormat{ TimeEnabled: 0, TimeRunning: 3, Nr: 1, }, valuesFile: Values{ Value: 0, ID: 0, }, name: "some metric", cpu: 4, perfStat: []info.PerfStat{{ PerfValue: info.PerfValue{ ScalingRatio: 1.0, Value: 0, Name: "some metric", }, Cpu: 4, }}, err: nil, }, } func TestReadPerfStat(t *testing.T) { for _, test := range readGroupPerfStatCases { t.Run(test.test, func(tt *testing.T) { buf := &buffer{bytes.NewBuffer([]byte{})} err := binary.Write(buf, binary.LittleEndian, test.file) assert.NoError(tt, err) err = binary.Write(buf, binary.LittleEndian, test.valuesFile) assert.NoError(tt, err) stat, err := readGroupPerfStat(buf, group{ cpuFiles: nil, names: []string{test.name}, leaderName: test.name, }, test.cpu, "/") assert.Equal(tt, test.perfStat, stat) assert.Equal(tt, test.err, err) }) } } func TestReadPerfEventAttr(t *testing.T) { var testCases = []struct { expected *unix.PerfEventAttr pfmMockedFunc func(string, unsafe.Pointer) error }{ { &unix.PerfEventAttr{ Type: 0, Size: 0, Config: 0, Sample: 0, Sample_type: 0, Read_format: 0, Bits: 0, Wakeup: 0, Bp_type: 0, Ext1: 0, Ext2: 0, Branch_sample_type: 0, Sample_regs_user: 0, Sample_stack_user: 0, Clockid: 0, Sample_regs_intr: 0, Aux_watermark: 0, Sample_max_stack: 0, }, func(s string, pointer unsafe.Pointer) error { return nil }, }, } for _, test := range testCases { got, err := readPerfEventAttr("event_name", test.pfmMockedFunc) assert.NoError(t, err) assert.Equal(t, test.expected, got) } } ================================================ FILE: perf/collector_no_libpfm.go ================================================ //go:build !libpfm || !cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Collector of perf events for a container. package perf import ( "github.com/google/cadvisor/stats" "k8s.io/klog/v2" ) func NewCollector(cgroupPath string, events Events, numCores int) stats.Collector { return &stats.NoopCollector{} } // Finalize terminates libpfm4 to free resources. func Finalize() { klog.V(1).Info("cAdvisor is build without cgo and/or libpfm support. Nothing to be finalized") } ================================================ FILE: perf/config.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Configuration for perf event manager. package perf import ( "encoding/json" "fmt" "os" "strconv" "k8s.io/klog/v2" ) type PerfEvents struct { // Core perf events to be measured. Core Events `json:"core,omitempty"` // Uncore perf events to be measured. Uncore Events `json:"uncore,omitempty"` } type Events struct { // List of perf events' names to be measured. Events []Group `json:"events"` // List of custom perf events' to be measured. It is impossible to // specify some events using their names and in such case you have // to provide lower level configuration. CustomEvents []CustomEvent `json:"custom_events"` } type Event string type CustomEvent struct { // Type of the event. See perf_event_attr documentation // at man perf_event_open. Type uint32 `json:"type,omitempty"` // Symbolically formed event like: // pmu/config=PerfEvent.Config[0],config1=PerfEvent.Config[1],config2=PerfEvent.Config[2] // as described in man perf-stat. Config Config `json:"config"` // Human readable name of metric that will be created from the event. Name Event `json:"name"` } type Config []uint64 func (c *Config) UnmarshalJSON(b []byte) error { config := []string{} err := json.Unmarshal(b, &config) if err != nil { klog.Errorf("Unmarshalling %s into slice of strings failed: %q", b, err) return fmt.Errorf("unmarshalling %s into slice of strings failed: %q", b, err) } intermediate := []uint64{} for _, v := range config { uintValue, err := strconv.ParseUint(v, 0, 64) if err != nil { klog.Errorf("Parsing %#v into uint64 failed: %q", v, err) return fmt.Errorf("parsing %#v into uint64 failed: %q", v, err) } intermediate = append(intermediate, uintValue) } *c = intermediate return nil } func parseConfig(file *os.File) (events PerfEvents, err error) { decoder := json.NewDecoder(file) err = decoder.Decode(&events) if err != nil { err = fmt.Errorf("unable to load perf events configuration from %q: %q", file.Name(), err) return } return } type Group struct { events []Event array bool } func (g *Group) UnmarshalJSON(b []byte) error { var jsonObj interface{} err := json.Unmarshal(b, &jsonObj) if err != nil { return err } switch obj := jsonObj.(type) { case string: *g = Group{ events: []Event{Event(obj)}, array: false, } return nil case []interface{}: group := Group{ events: make([]Event, 0, len(obj)), array: true, } for _, v := range obj { value, ok := v.(string) if !ok { return fmt.Errorf("cannot unmarshal %v", value) } group.events = append(group.events, Event(value)) } *g = group return nil } return fmt.Errorf("unsupported type") } ================================================ FILE: perf/config_test.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package perf import ( "os" "testing" "github.com/stretchr/testify/assert" ) func TestConfigParsing(t *testing.T) { file, err := os.Open("testing/perf.json") assert.Nil(t, err) defer file.Close() events, err := parseConfig(file) assert.Nil(t, err) assert.Len(t, events.Core.Events, 2) assert.Len(t, events.Core.Events[0].events, 2) assert.Equal(t, true, events.Core.Events[0].array) assert.Equal(t, Event("instructions"), events.Core.Events[0].events[0]) assert.Equal(t, Event("instructions_retired"), events.Core.Events[0].events[1]) assert.Len(t, events.Core.Events[1].events, 1) assert.Equal(t, false, events.Core.Events[1].array) assert.Equal(t, Event("cycles"), events.Core.Events[1].events[0]) assert.Len(t, events.Uncore.Events, 3) assert.Equal(t, Event("cas_count_write"), events.Uncore.Events[0].events[0]) assert.Equal(t, Event("uncore_imc_0/UNC_M_CAS_COUNT:RD"), events.Uncore.Events[1].events[0]) assert.Equal(t, Event("uncore_ubox/UNC_U_EVENT_MSG"), events.Uncore.Events[2].events[0]) assert.Len(t, events.Uncore.CustomEvents, 1) assert.Equal(t, Config{0x5300}, events.Uncore.CustomEvents[0].Config) assert.Equal(t, uint32(0x12), events.Uncore.CustomEvents[0].Type) assert.Equal(t, Event("cas_count_write"), events.Uncore.CustomEvents[0].Name) } ================================================ FILE: perf/manager_libpfm.go ================================================ //go:build libpfm && cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Manager of perf events for containers. package perf import ( "fmt" "os" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/stats" "github.com/google/cadvisor/utils/sysinfo" ) type manager struct { events PerfEvents onlineCPUs []int cpuToSocket map[int]int stats.NoopDestroy } func NewManager(configFile string, topology []info.Node) (stats.Manager, error) { if configFile == "" { return &stats.NoopManager{}, nil } file, err := os.Open(configFile) if err != nil { return nil, fmt.Errorf("unable to read configuration file %q: %w", configFile, err) } config, err := parseConfig(file) if err != nil { return nil, fmt.Errorf("unable to parse configuration file %q: %w", configFile, err) } if len(config.Core.Events) == 0 && len(config.Uncore.Events) == 0 { return nil, fmt.Errorf("there is no events in config file %q", configFile) } onlineCPUs := sysinfo.GetOnlineCPUs(topology) cpuToSocket := make(map[int]int) for _, cpu := range onlineCPUs { cpuToSocket[cpu] = sysinfo.GetSocketFromCPU(topology, cpu) } return &manager{events: config, onlineCPUs: onlineCPUs, cpuToSocket: cpuToSocket}, nil } func (m *manager) GetCollector(cgroupPath string) (stats.Collector, error) { collector := newCollector(cgroupPath, m.events, m.onlineCPUs, m.cpuToSocket) err := collector.setup() if err != nil { collector.Destroy() return &stats.NoopCollector{}, err } return collector, nil } ================================================ FILE: perf/manager_libpfm_test.go ================================================ //go:build libpfm && cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Manager of perf events for containers. package perf import ( "testing" "github.com/stretchr/testify/assert" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/stats" ) func TestEmptyConfigPassed(t *testing.T) { manager, err := NewManager("testing/perf-no-events.json", []info.Node{}) assert.NotNil(t, err) assert.Nil(t, manager) } func TestNoConfigFilePassed(t *testing.T) { manager, err := NewManager("", []info.Node{}) assert.Nil(t, err) _, ok := manager.(*stats.NoopManager) assert.True(t, ok) } func TestNonExistentFile(t *testing.T) { manager, err := NewManager("this-file-is-so-non-existent", []info.Node{}) assert.NotNil(t, err) assert.Nil(t, manager) } func TestMalformedJsonFile(t *testing.T) { manager, err := NewManager("testing/this-is-some-random.json", []info.Node{}) assert.NotNil(t, err) assert.Nil(t, manager) } func TestNewManager(t *testing.T) { managerInstance, err := NewManager("testing/perf.json", []info.Node{}) assert.Nil(t, err) _, ok := managerInstance.(*manager) assert.True(t, ok) } ================================================ FILE: perf/manager_no_libpfm.go ================================================ //go:build !libpfm || !cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Manager of perf events for containers. package perf import ( info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/stats" "k8s.io/klog/v2" ) func NewManager(configFile string, topology []info.Node) (stats.Manager, error) { klog.V(1).Info("cAdvisor is build without cgo and/or libpfm support. Perf event counters are not available.") return &stats.NoopManager{}, nil } ================================================ FILE: perf/testing/perf-no-events.json ================================================ { "core": { "events": [], "custom_events": [] }, "uncore": { "events": [], "custom_events": [] } } ================================================ FILE: perf/testing/perf-non-hardware.json ================================================ { "core": { "events": [ "context-switches", "cpu-migrations-custom" ], "custom_events": [ { "type": 1, "config": [ "0x4" ], "name": "cpu-migrations-custom" } ] } } ================================================ FILE: perf/testing/perf.json ================================================ { "core": { "events": [ ["instructions", "instructions_retired"], "cycles" ], "custom_events": [ { "type": 4, "config": [ "0x5300c0" ], "name": "instructions_retired" } ] }, "uncore": { "events": [ "cas_count_write", "uncore_imc_0/UNC_M_CAS_COUNT:RD", "uncore_ubox/UNC_U_EVENT_MSG" ], "custom_events": [ { "type": 18, "config": [ "0x5300" ], "name": "cas_count_write" } ] } } ================================================ FILE: perf/testing/this-is-some-random.json ================================================ [] ================================================ FILE: perf/types_libpfm.go ================================================ //go:build libpfm && cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Types related to handling perf events that are missing from unix package. package perf import "C" import ( "io" "unsafe" ) // GroupReadFormat allows to read perf event's values for grouped events. // See https://man7.org/linux/man-pages/man2/perf_event_open.2.html section "Reading results" with PERF_FORMAT_GROUP specified. type GroupReadFormat struct { Nr uint64 /* The number of events */ TimeEnabled uint64 /* if PERF_FORMAT_TOTAL_TIME_ENABLED */ TimeRunning uint64 /* if PERF_FORMAT_TOTAL_TIME_RUNNING */ } type Values struct { Value uint64 /* The value of the event */ ID uint64 /* if PERF_FORMAT_ID */ } // pfmPerfEncodeArgT represents structure that is used to parse perf event nam // into perf_event_attr using libpfm. type pfmPerfEncodeArgT struct { attr unsafe.Pointer fstr unsafe.Pointer size C.size_t _ C.int // idx _ C.int // cpu _ C.int // flags } type readerCloser interface { io.Reader io.Closer } ================================================ FILE: perf/uncore_libpfm.go ================================================ //go:build libpfm && cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Uncore perf events logic. package perf // #cgo CFLAGS: -I/usr/include // #cgo LDFLAGS: -lpfm // #include // #include import "C" import ( "fmt" "os" "path/filepath" "reflect" "regexp" "strconv" "strings" "sync" "unsafe" "golang.org/x/sys/unix" "k8s.io/klog/v2" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/stats" ) type pmu struct { name string typeOf uint32 cpus []uint32 } const ( uncorePMUPrefix = "uncore" pmuTypeFilename = "type" pmuCpumaskFilename = "cpumask" systemDevicesPath = "/sys/devices" rootPerfEventPath = "/sys/fs/cgroup/perf_event" uncorePID = -1 ) func getPMU(pmus uncorePMUs, gotType uint32) (*pmu, error) { for _, pmu := range pmus { if pmu.typeOf == gotType { return &pmu, nil } } return nil, fmt.Errorf("there is no pmu with event type: %#v", gotType) } type uncorePMUs map[string]pmu func readUncorePMU(path string, name string, cpumaskRegexp *regexp.Regexp) (*pmu, error) { buf, err := os.ReadFile(filepath.Join(path, pmuTypeFilename)) if err != nil { return nil, err } typeString := strings.TrimSpace(string(buf)) eventType, err := strconv.ParseUint(typeString, 0, 32) if err != nil { return nil, err } buf, err = os.ReadFile(filepath.Join(path, pmuCpumaskFilename)) if err != nil { return nil, err } var cpus []uint32 cpumask := strings.TrimSpace(string(buf)) for _, cpu := range cpumaskRegexp.Split(cpumask, -1) { parsedCPU, err := strconv.ParseUint(cpu, 0, 32) if err != nil { return nil, err } cpus = append(cpus, uint32(parsedCPU)) } return &pmu{name: name, typeOf: uint32(eventType), cpus: cpus}, nil } func getUncorePMUs(devicesPath string) (uncorePMUs, error) { pmus := make(uncorePMUs) // Depends on platform, cpu mask could be for example in form "0-1" or "0,1". cpumaskRegexp := regexp.MustCompile("[-,\n]") err := filepath.Walk(devicesPath, func(path string, info os.FileInfo, err error) error { // Skip root path. if path == devicesPath { return nil } if info.IsDir() { if strings.HasPrefix(info.Name(), uncorePMUPrefix) { pmu, err := readUncorePMU(path, info.Name(), cpumaskRegexp) if err != nil { return err } pmus[info.Name()] = *pmu } } return nil }) if err != nil { return nil, err } return pmus, nil } type uncoreCollector struct { cpuFilesLock sync.Mutex cpuFiles map[int]map[string]group events []Group eventToCustomEvent map[Event]*CustomEvent cpuToSocket map[int]int // Handle for mocking purposes. perfEventOpen func(attr *unix.PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) ioctlSetInt func(fd int, req uint, value int) error } func NewUncoreCollector(cgroupPath string, events PerfEvents, cpuToSocket map[int]int) stats.Collector { if cgroupPath != rootPerfEventPath { // Uncore metric doesn't exists for cgroups, only for entire platform. return &stats.NoopCollector{} } collector := &uncoreCollector{ cpuToSocket: cpuToSocket, perfEventOpen: unix.PerfEventOpen, ioctlSetInt: unix.IoctlSetInt, } err := collector.setup(events, systemDevicesPath) if err != nil { klog.Errorf("Perf uncore metrics will not be available: unable to setup uncore perf event collector: %v", err) return &stats.NoopCollector{} } return collector } func (c *uncoreCollector) createLeaderFileDescriptors(events []Event, groupIndex int, groupPMUs map[Event]uncorePMUs, leaderFileDescriptors map[string]map[uint32]int) (map[string]map[uint32]int, error) { var err error for _, event := range events { eventName, _ := parseEventName(string(event)) customEvent, ok := c.eventToCustomEvent[event] if ok { err = c.setupRawEvent(customEvent, groupPMUs[event], groupIndex, leaderFileDescriptors) } else { err = c.setupEvent(eventName, groupPMUs[event], groupIndex, leaderFileDescriptors) } if err != nil { break } } if err != nil { c.deleteGroup(groupIndex) return nil, fmt.Errorf("cannot create config from perf event: %v", err) } return leaderFileDescriptors, nil } func (c *uncoreCollector) setup(events PerfEvents, devicesPath string) error { readUncorePMUs, err := getUncorePMUs(devicesPath) if err != nil { return err } c.cpuFiles = make(map[int]map[string]group) c.events = events.Uncore.Events c.eventToCustomEvent = parseUncoreEvents(events.Uncore) c.cpuFilesLock.Lock() defer c.cpuFilesLock.Unlock() for i, group := range c.events { // Check what PMUs are needed. groupPMUs, err := parsePMUs(group, readUncorePMUs, c.eventToCustomEvent) if err != nil { return err } err = checkGroup(group, groupPMUs) if err != nil { return err } // CPUs file descriptors of group leader needed for perf_event_open. leaderFileDescriptors := make(map[string]map[uint32]int) for _, pmu := range readUncorePMUs { leaderFileDescriptors[pmu.name] = make(map[uint32]int) for _, cpu := range pmu.cpus { leaderFileDescriptors[pmu.name][cpu] = groupLeaderFileDescriptor } } leaderFileDescriptors, err = c.createLeaderFileDescriptors(group.events, i, groupPMUs, leaderFileDescriptors) if err != nil { klog.Error(err) continue } // Group is prepared so we should reset and enable counting. for _, pmuCPUs := range leaderFileDescriptors { for _, fd := range pmuCPUs { // Call only for used PMUs. if fd != groupLeaderFileDescriptor { err = c.ioctlSetInt(fd, unix.PERF_EVENT_IOC_RESET, 0) if err != nil { return err } err = c.ioctlSetInt(fd, unix.PERF_EVENT_IOC_ENABLE, 0) if err != nil { return err } } } } } return nil } func checkGroup(group Group, eventPMUs map[Event]uncorePMUs) error { if group.array { var pmu uncorePMUs for _, event := range group.events { if len(eventPMUs[event]) > 1 { return fmt.Errorf("the events in group usually have to be from single PMU, try reorganizing the \"%v\" group", group.events) } if len(eventPMUs[event]) == 1 { if pmu == nil { pmu = eventPMUs[event] continue } eq := reflect.DeepEqual(pmu, eventPMUs[event]) if !eq { return fmt.Errorf("the events in group usually have to be from the same PMU, try reorganizing the \"%v\" group", group.events) } } } return nil } if len(eventPMUs[group.events[0]]) < 1 { return fmt.Errorf("the event %q don't have any PMU to count with", group.events[0]) } return nil } func parseEventName(eventName string) (string, string) { // First "/" separate pmu prefix and event name // ex. "uncore_imc_0/cas_count_read" -> uncore_imc_0 and cas_count_read. splittedEvent := strings.SplitN(eventName, "/", 2) var pmuPrefix = "" if len(splittedEvent) == 2 { pmuPrefix = splittedEvent[0] eventName = splittedEvent[1] } return eventName, pmuPrefix } func parsePMUs(group Group, pmus uncorePMUs, customEvents map[Event]*CustomEvent) (map[Event]uncorePMUs, error) { eventPMUs := make(map[Event]uncorePMUs) for _, event := range group.events { _, prefix := parseEventName(string(event)) custom, ok := customEvents[event] if ok { if custom.Type != 0 { pmu, err := getPMU(pmus, custom.Type) if err != nil { return nil, err } eventPMUs[event] = uncorePMUs{pmu.name: *pmu} continue } } eventPMUs[event] = obtainPMUs(prefix, pmus) } return eventPMUs, nil } func obtainPMUs(want string, gotPMUs uncorePMUs) uncorePMUs { pmus := make(uncorePMUs) if want == "" { return pmus } for _, pmu := range gotPMUs { if strings.HasPrefix(pmu.name, want) { pmus[pmu.name] = pmu } } return pmus } func parseUncoreEvents(events Events) map[Event]*CustomEvent { eventToCustomEvent := map[Event]*CustomEvent{} for _, group := range events.Events { for _, uncoreEvent := range group.events { for _, customEvent := range events.CustomEvents { if uncoreEvent == customEvent.Name { eventToCustomEvent[customEvent.Name] = &customEvent break } } } } return eventToCustomEvent } func (c *uncoreCollector) Destroy() { c.cpuFilesLock.Lock() defer c.cpuFilesLock.Unlock() for groupIndex := range c.cpuFiles { c.deleteGroup(groupIndex) delete(c.cpuFiles, groupIndex) } } func (c *uncoreCollector) UpdateStats(stats *info.ContainerStats) error { klog.V(5).Info("Attempting to update uncore perf_event stats") for _, groupPMUs := range c.cpuFiles { for pmu, group := range groupPMUs { for cpu, file := range group.cpuFiles[group.leaderName] { stat, err := readPerfUncoreStat(file, group, cpu, pmu, c.cpuToSocket) if err != nil { klog.Warningf("Unable to read from perf_event_file (event: %q, CPU: %d) for %q: %q", group.leaderName, cpu, pmu, err.Error()) continue } stats.PerfUncoreStats = append(stats.PerfUncoreStats, stat...) } } } return nil } func (c *uncoreCollector) setupEvent(name string, pmus uncorePMUs, groupIndex int, leaderFileDescriptors map[string]map[uint32]int) error { if !isLibpfmInitialized { return fmt.Errorf("libpfm4 is not initialized, cannot proceed with setting perf events up") } klog.V(5).Infof("Setting up uncore perf event %s", name) config, err := readPerfEventAttr(name, pfmGetOsEventEncoding) if err != nil { C.free((unsafe.Pointer)(config)) return err } // Register event for all memory controllers. for _, pmu := range pmus { config.Type = pmu.typeOf isGroupLeader := leaderFileDescriptors[pmu.name][pmu.cpus[0]] == groupLeaderFileDescriptor setAttributes(config, isGroupLeader) leaderFileDescriptors[pmu.name], err = c.registerEvent(eventInfo{name, config, uncorePID, groupIndex, isGroupLeader}, pmu, leaderFileDescriptors[pmu.name]) if err != nil { return err } } // Clean memory allocated by C code. C.free(unsafe.Pointer(config)) return nil } func (c *uncoreCollector) registerEvent(eventInfo eventInfo, pmu pmu, leaderFileDescriptors map[uint32]int) (map[uint32]int, error) { newLeaderFileDescriptors := make(map[uint32]int) isGroupLeader := false for _, cpu := range pmu.cpus { groupFd, flags := leaderFileDescriptors[cpu], 0 fd, err := c.perfEventOpen(eventInfo.config, eventInfo.pid, int(cpu), groupFd, flags) if err != nil { return nil, fmt.Errorf("setting up perf event %#v failed: %q | (pmu: %q, groupFd: %d, cpu: %d)", eventInfo.config, err, pmu, groupFd, cpu) } perfFile := os.NewFile(uintptr(fd), eventInfo.name) if perfFile == nil { return nil, fmt.Errorf("unable to create os.File from file descriptor %#v", fd) } c.addEventFile(eventInfo.groupIndex, eventInfo.name, pmu.name, int(cpu), perfFile) // If group leader, save fd for others. if leaderFileDescriptors[cpu] == groupLeaderFileDescriptor { newLeaderFileDescriptors[cpu] = fd isGroupLeader = true } } if isGroupLeader { return newLeaderFileDescriptors, nil } return leaderFileDescriptors, nil } func (c *uncoreCollector) addEventFile(index int, name string, pmu string, cpu int, perfFile *os.File) { _, ok := c.cpuFiles[index] if !ok { c.cpuFiles[index] = map[string]group{} } _, ok = c.cpuFiles[index][pmu] if !ok { c.cpuFiles[index][pmu] = group{ cpuFiles: map[string]map[int]readerCloser{}, leaderName: name, } } _, ok = c.cpuFiles[index][pmu].cpuFiles[name] if !ok { c.cpuFiles[index][pmu].cpuFiles[name] = map[int]readerCloser{} } c.cpuFiles[index][pmu].cpuFiles[name][cpu] = perfFile // Check if name is already stored. for _, have := range c.cpuFiles[index][pmu].names { if name == have { return } } // Otherwise save it. c.cpuFiles[index][pmu] = group{ cpuFiles: c.cpuFiles[index][pmu].cpuFiles, names: append(c.cpuFiles[index][pmu].names, name), leaderName: c.cpuFiles[index][pmu].leaderName, } } func (c *uncoreCollector) setupRawEvent(event *CustomEvent, pmus uncorePMUs, groupIndex int, leaderFileDescriptors map[string]map[uint32]int) error { klog.V(5).Infof("Setting up raw perf uncore event %#v", event) for _, pmu := range pmus { newEvent := CustomEvent{ Type: pmu.typeOf, Config: event.Config, Name: event.Name, } config := createPerfEventAttr(newEvent) isGroupLeader := leaderFileDescriptors[pmu.name][pmu.cpus[0]] == groupLeaderFileDescriptor setAttributes(config, isGroupLeader) var err error leaderFileDescriptors[pmu.name], err = c.registerEvent(eventInfo{string(newEvent.Name), config, uncorePID, groupIndex, isGroupLeader}, pmu, leaderFileDescriptors[pmu.name]) if err != nil { return err } } return nil } func (c *uncoreCollector) deleteGroup(groupIndex int) { groupPMUs := c.cpuFiles[groupIndex] for pmu, group := range groupPMUs { for name, cpus := range group.cpuFiles { for cpu, file := range cpus { klog.V(5).Infof("Closing uncore perf event file descriptor for event %q, PMU %s and CPU %d", name, pmu, cpu) err := file.Close() if err != nil { klog.Warningf("Unable to close perf event file descriptor for event %q, PMU %s and CPU %d", name, pmu, cpu) } } delete(group.cpuFiles, name) } delete(groupPMUs, pmu) } delete(c.cpuFiles, groupIndex) } func readPerfUncoreStat(file readerCloser, group group, cpu int, pmu string, cpuToSocket map[int]int) ([]info.PerfUncoreStat, error) { values, err := getPerfValues(file, group) if err != nil { return nil, err } socket, ok := cpuToSocket[cpu] if !ok { // Socket is unknown. socket = -1 } perfUncoreStats := make([]info.PerfUncoreStat, len(values)) for i, value := range values { klog.V(5).Infof("Read metric for event %q for cpu %d from pmu %q: %d", value.Name, cpu, pmu, value.Value) perfUncoreStats[i] = info.PerfUncoreStat{ PerfValue: value, Socket: socket, PMU: pmu, } } return perfUncoreStats, nil } ================================================ FILE: perf/uncore_libpfm_test.go ================================================ //go:build libpfm && cgo // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Uncore perf events logic tests. package perf import ( "bytes" "encoding/binary" "os" "path/filepath" "testing" "golang.org/x/sys/unix" "github.com/stretchr/testify/assert" v1 "github.com/google/cadvisor/info/v1" ) func mockSystemDevices() (string, error) { testDir, err := os.MkdirTemp("", "uncore_imc_test") if err != nil { return "", err } // First Uncore IMC PMU. firstPMUPath := filepath.Join(testDir, "uncore_imc_0") err = os.MkdirAll(firstPMUPath, os.ModePerm) if err != nil { return "", err } err = os.WriteFile(filepath.Join(firstPMUPath, "cpumask"), []byte("0-1"), 0777) if err != nil { return "", err } err = os.WriteFile(filepath.Join(firstPMUPath, "type"), []byte("18"), 0777) if err != nil { return "", err } // Second Uncore IMC PMU. secondPMUPath := filepath.Join(testDir, "uncore_imc_1") err = os.MkdirAll(secondPMUPath, os.ModePerm) if err != nil { return "", err } err = os.WriteFile(filepath.Join(secondPMUPath, "cpumask"), []byte("0,1"), 0777) if err != nil { return "", err } err = os.WriteFile(filepath.Join(secondPMUPath, "type"), []byte("19"), 0777) if err != nil { return "", err } return testDir, nil } func TestUncore(t *testing.T) { path, err := mockSystemDevices() assert.Nil(t, err) defer func() { err := os.RemoveAll(path) assert.Nil(t, err) }() actual, err := getUncorePMUs(path) assert.Nil(t, err) expected := uncorePMUs{ "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, } assert.Equal(t, expected, actual) pmuSet := uncorePMUs{ "uncore_imc_0": actual["uncore_imc_0"], "uncore_imc_1": actual["uncore_imc_1"], } actualPMU, err := getPMU(pmuSet, expected["uncore_imc_0"].typeOf) assert.Nil(t, err) assert.Equal(t, expected["uncore_imc_0"], *actualPMU) } func TestUncoreCollectorSetup(t *testing.T) { path, err := mockSystemDevices() assert.Nil(t, err) defer func() { err := os.RemoveAll(path) assert.Nil(t, err) }() events := PerfEvents{ Core: Events{ Events: []Group{ {[]Event{"cache-misses"}, false}, }, }, Uncore: Events{ Events: []Group{ {[]Event{"uncore_imc_1/cas_count_read"}, false}, {[]Event{"uncore_imc_1/non_existing_event"}, false}, {[]Event{"uncore_imc_0/cas_count_write", "uncore_imc_0/cas_count_read"}, true}, }, CustomEvents: []CustomEvent{ {19, Config{0x01, 0x02}, "uncore_imc_1/cas_count_read"}, {0, Config{0x02, 0x03}, "uncore_imc_0/cas_count_write"}, {18, Config{0x01, 0x02}, "uncore_imc_0/cas_count_read"}, }, }, } collector := &uncoreCollector{} collector.perfEventOpen = func(attr *unix.PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { return int(attr.Config), nil } collector.ioctlSetInt = func(fd int, req uint, value int) error { return nil } err = collector.setup(events, path) assert.Equal(t, []string{"uncore_imc_1/cas_count_read"}, getMapKeys(collector.cpuFiles[0]["uncore_imc_1"].cpuFiles)) assert.ElementsMatch(t, []string{"uncore_imc_0/cas_count_write", "uncore_imc_0/cas_count_read"}, getMapKeys(collector.cpuFiles[2]["uncore_imc_0"].cpuFiles)) // There are no errors. assert.Nil(t, err) } func TestParseUncoreEvents(t *testing.T) { events := PerfEvents{ Uncore: Events{ Events: []Group{ {[]Event{"cas_count_read"}, false}, {[]Event{"cas_count_write"}, false}, }, CustomEvents: []CustomEvent{ { Type: 17, Config: Config{0x50, 0x60}, Name: "cas_count_read", }, }, }, } eventToCustomEvent := parseUncoreEvents(events.Uncore) assert.Len(t, eventToCustomEvent, 1) assert.Equal(t, eventToCustomEvent["cas_count_read"].Name, Event("cas_count_read")) assert.Equal(t, eventToCustomEvent["cas_count_read"].Type, uint32(17)) assert.Equal(t, eventToCustomEvent["cas_count_read"].Config, Config{0x50, 0x60}) } func TestObtainPMUs(t *testing.T) { got := uncorePMUs{ "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, } actual := obtainPMUs("uncore_imc_0", got) assert.Equal(t, uncorePMUs{"uncore_imc_0": got["uncore_imc_0"]}, actual) actual = obtainPMUs("uncore_imc_1", got) assert.Equal(t, uncorePMUs{"uncore_imc_1": got["uncore_imc_1"]}, actual) actual = obtainPMUs("", got) assert.Equal(t, uncorePMUs{}, actual) } func TestUncoreParseEventName(t *testing.T) { eventName, pmuPrefix := parseEventName("some_event") assert.Equal(t, "some_event", eventName) assert.Empty(t, pmuPrefix) eventName, pmuPrefix = parseEventName("some_pmu/some_event") assert.Equal(t, "some_pmu", pmuPrefix) assert.Equal(t, "some_event", eventName) eventName, pmuPrefix = parseEventName("some_pmu/some_event/first_slash/second_slash") assert.Equal(t, "some_pmu", pmuPrefix) assert.Equal(t, "some_event/first_slash/second_slash", eventName) } func TestCheckGroup(t *testing.T) { var testCases = []struct { group Group eventPMUs map[Event]uncorePMUs expectedOutput string }{ { Group{[]Event{"uncore_imc/cas_count_write"}, false}, map[Event]uncorePMUs{}, "the event \"uncore_imc/cas_count_write\" don't have any PMU to count with", }, { Group{[]Event{"uncore_imc/cas_count_write", "uncore_imc/cas_count_read"}, true}, map[Event]uncorePMUs{"uncore_imc/cas_count_write": { "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, }, "uncore_imc/cas_count_read": { "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, }, }, "the events in group usually have to be from single PMU, try reorganizing the \"[uncore_imc/cas_count_write uncore_imc/cas_count_read]\" group", }, { Group{[]Event{"uncore_imc_0/cas_count_write", "uncore_imc_1/cas_count_read"}, true}, map[Event]uncorePMUs{"uncore_imc_0/cas_count_write": { "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, }, "uncore_imc_1/cas_count_read": { "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, }, }, "the events in group usually have to be from the same PMU, try reorganizing the \"[uncore_imc_0/cas_count_write uncore_imc_1/cas_count_read]\" group", }, { Group{[]Event{"uncore_imc/cas_count_write"}, false}, map[Event]uncorePMUs{"uncore_imc/cas_count_write": { "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, }}, "", }, { Group{[]Event{"uncore_imc_0/cas_count_write", "uncore_imc_0/cas_count_read"}, true}, map[Event]uncorePMUs{"uncore_imc_0/cas_count_write": { "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, }, "uncore_imc_0/cas_count_read": { "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, }}, "", }, } for _, tc := range testCases { err := checkGroup(tc.group, tc.eventPMUs) if tc.expectedOutput == "" { assert.Nil(t, err) } else { assert.EqualError(t, err, tc.expectedOutput) } } } func TestReadPerfUncoreStat(t *testing.T) { file := GroupReadFormat{ TimeEnabled: 0, TimeRunning: 1, Nr: 1, } valuesFile := Values{ Value: 4, ID: 0, } expectedStat := []v1.PerfUncoreStat{{ PerfValue: v1.PerfValue{ ScalingRatio: 1, Value: 4, Name: "foo", }, Socket: 0, PMU: "bar", }} cpuToSocket := map[int]int{ 1: 0, 2: 0, } buf := &buffer{bytes.NewBuffer([]byte{})} err := binary.Write(buf, binary.LittleEndian, file) assert.NoError(t, err) err = binary.Write(buf, binary.LittleEndian, valuesFile) assert.NoError(t, err) stat, err := readPerfUncoreStat(buf, group{ cpuFiles: nil, names: []string{"foo"}, leaderName: "foo", }, 1, "bar", cpuToSocket) assert.NoError(t, err) assert.Equal(t, expectedStat, stat) } func getMapKeys(someMap map[string]map[int]readerCloser) []string { var keys []string for key := range someMap { keys = append(keys, key) } return keys } ================================================ FILE: resctrl/factory.go ================================================ // Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package resctrl import ( "fmt" "sync" "time" "github.com/google/cadvisor/stats" "k8s.io/klog/v2" ) type ResControlManager interface { Destroy() GetCollector(containerName string, getContainerPids func() ([]string, error), numberOfNUMANodes int) (stats.Collector, error) } // All registered auth provider plugins. var pluginsLock sync.Mutex var plugins = make(map[string]ResControlManagerPlugin) type ResControlManagerPlugin interface { NewManager(interval time.Duration, vendorID string, inHostNamespace bool) (ResControlManager, error) } func RegisterPlugin(name string, plugin ResControlManagerPlugin) error { pluginsLock.Lock() defer pluginsLock.Unlock() if _, found := plugins[name]; found { return fmt.Errorf("ResControlManagerPlugin %q was registered twice", name) } klog.V(4).Infof("Registered ResControlManagerPlugin %q", name) plugins[name] = plugin return nil } func NewManager(interval time.Duration, vendorID string, inHostNamespace bool) (ResControlManager, error) { pluginsLock.Lock() defer pluginsLock.Unlock() for _, plugin := range plugins { return plugin.NewManager(interval, vendorID, inHostNamespace) } return nil, fmt.Errorf("unable to find plugins for resctrl manager") } ================================================ FILE: resctrl/intel/collector.go ================================================ //go:build linux // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Collector of resctrl for a container. package intel import ( "fmt" "os" "path/filepath" "strings" "sync" "time" "k8s.io/klog/v2" info "github.com/google/cadvisor/info/v1" ) const noInterval = 0 type collector struct { id string interval time.Duration getContainerPids func() ([]string, error) resctrlPath string running bool destroyed bool numberOfNUMANodes int vendorID string mu sync.Mutex inHostNamespace bool } func newCollector(id string, getContainerPids func() ([]string, error), interval time.Duration, numberOfNUMANodes int, vendorID string, inHostNamespace bool) *collector { return &collector{id: id, interval: interval, getContainerPids: getContainerPids, numberOfNUMANodes: numberOfNUMANodes, vendorID: vendorID, mu: sync.Mutex{}, inHostNamespace: inHostNamespace} } func (c *collector) setup() error { var err error c.resctrlPath, err = prepareMonitoringGroup(c.id, c.getContainerPids, c.inHostNamespace) if c.interval != noInterval { if err != nil { klog.Errorf("Failed to setup container %q resctrl collector: %s \n Trying again in next intervals.", c.id, err) } else { c.running = true } go func() { for { time.Sleep(c.interval) c.mu.Lock() if c.destroyed { break } klog.V(5).Infof("Trying to check %q containers control group.", c.id) if c.running { err = c.checkMonitoringGroup() if err != nil { c.running = false klog.Errorf("Failed to check %q resctrl collector control group: %s \n Trying again in next intervals.", c.id, err) } } else { c.resctrlPath, err = prepareMonitoringGroup(c.id, c.getContainerPids, c.inHostNamespace) if err != nil { c.running = false klog.Errorf("Failed to setup container %q resctrl collector: %s \n Trying again in next intervals.", c.id, err) } } c.mu.Unlock() } }() } else { // There is no interval set, if setup fail, stop. if err != nil { return fmt.Errorf("failed to setup container %q resctrl collector: %w", c.id, err) } c.running = true } return nil } func (c *collector) checkMonitoringGroup() error { newPath, err := prepareMonitoringGroup(c.id, c.getContainerPids, c.inHostNamespace) if err != nil { return fmt.Errorf("couldn't obtain mon_group path: %v", err) } // Check if container moved between control groups. if newPath != c.resctrlPath { err = c.clear() if err != nil { return fmt.Errorf("couldn't clear previous monitoring group: %w", err) } c.resctrlPath = newPath } return nil } func (c *collector) UpdateStats(stats *info.ContainerStats) error { c.mu.Lock() defer c.mu.Unlock() if c.running { stats.Resctrl = info.ResctrlStats{} resctrlStats, err := getIntelRDTStatsFrom(c.resctrlPath, c.vendorID) if err != nil { return err } stats.Resctrl.MemoryBandwidth = make([]info.MemoryBandwidthStats, 0, c.numberOfNUMANodes) stats.Resctrl.Cache = make([]info.CacheStats, 0, c.numberOfNUMANodes) for _, numaNodeStats := range *resctrlStats.MBMStats { stats.Resctrl.MemoryBandwidth = append(stats.Resctrl.MemoryBandwidth, info.MemoryBandwidthStats{ TotalBytes: numaNodeStats.MBMTotalBytes, LocalBytes: numaNodeStats.MBMLocalBytes, }) } for _, numaNodeStats := range *resctrlStats.CMTStats { stats.Resctrl.Cache = append(stats.Resctrl.Cache, info.CacheStats{LLCOccupancy: numaNodeStats.LLCOccupancy}) } } return nil } func (c *collector) Destroy() { c.mu.Lock() defer c.mu.Unlock() c.running = false err := c.clear() if err != nil { klog.Errorf("trying to destroy %q resctrl collector but: %v", c.id, err) } c.destroyed = true } func (c *collector) clear() error { // Not allowed to remove root or undefined resctrl directory. if c.id != rootContainer && c.resctrlPath != "" { // Remove only own prepared mon group. if strings.HasPrefix(filepath.Base(c.resctrlPath), monGroupPrefix) { err := os.RemoveAll(c.resctrlPath) if err != nil { return fmt.Errorf("couldn't clear mon_group: %v", err) } } } return nil } ================================================ FILE: resctrl/intel/collector_test.go ================================================ //go:build linux // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Collector tests. package intel import ( "fmt" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" info "github.com/google/cadvisor/info/v1" ) func TestNewCollectorWithSetup(t *testing.T) { rootResctrl = mockResctrl() defer os.RemoveAll(rootResctrl) pidsPath = mockContainersPids() defer os.RemoveAll(pidsPath) processPath = mockProcFs() defer os.RemoveAll(processPath) expectedID := "container" expectedResctrlPath := filepath.Join(rootResctrl, monGroupsDirName, fmt.Sprintf("%s-%s", monGroupPrefix, expectedID)) collector := newCollector(expectedID, mockGetContainerPids, 0, 2, "", true) err := collector.setup() assert.NoError(t, err) assert.Equal(t, collector.id, expectedID) assert.Equal(t, collector.resctrlPath, expectedResctrlPath) } func TestUpdateStats(t *testing.T) { rootResctrl = mockResctrl() defer os.RemoveAll(rootResctrl) pidsPath = mockContainersPids() defer os.RemoveAll(pidsPath) processPath = mockProcFs() defer os.RemoveAll(processPath) collector := newCollector("container", mockGetContainerPids, 0, 2, "", true) err := collector.setup() assert.NoError(t, err) mockResctrlMonData(collector.resctrlPath) enabledCMT, enabledMBM = true, true stats := info.ContainerStats{} // Write some dumb data. err = collector.UpdateStats(&stats) assert.NoError(t, err) assert.Equal(t, stats.Resctrl.Cache, []info.CacheStats{ {LLCOccupancy: 1111}, {LLCOccupancy: 3333}, }) assert.Equal(t, stats.Resctrl.MemoryBandwidth, []info.MemoryBandwidthStats{ { TotalBytes: 3333, LocalBytes: 2222, }, { TotalBytes: 3333, LocalBytes: 1111, }, }) } func TestDestroy(t *testing.T) { rootResctrl = mockResctrl() defer os.RemoveAll(rootResctrl) pidsPath = mockContainersPids() defer os.RemoveAll(pidsPath) processPath = mockProcFs() defer os.RemoveAll(processPath) collector := newCollector("container", mockGetContainerPids, 0, 2, "", true) err := collector.setup() if err != nil { t.Fail() } path := collector.resctrlPath if stat, err := os.Stat(path); stat == nil && err != nil { t.Fail() } collector.Destroy() if stat, err := os.Stat(path); stat != nil && err == nil { t.Fail() } } ================================================ FILE: resctrl/intel/install/install.go ================================================ // Copyright 2025 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package install import ( "time" "github.com/google/cadvisor/resctrl" "github.com/google/cadvisor/resctrl/intel" "k8s.io/klog/v2" ) type managerplugin struct { } func (m *managerplugin) NewManager(interval time.Duration, vendorID string, inHostNamespace bool) (resctrl.ResControlManager, error) { return intel.NewManager(interval, intel.Setup, vendorID, inHostNamespace) } func init() { err := resctrl.RegisterPlugin("intel", &managerplugin{}) if err != nil { klog.Fatalf("Failed to register intel resctrl plugin: %v", err) } } ================================================ FILE: resctrl/intel/manager.go ================================================ //go:build linux // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ResControlManager of resctrl for containers. package intel import ( "errors" "time" "k8s.io/klog/v2" "github.com/google/cadvisor/container/raw" "github.com/google/cadvisor/resctrl" "github.com/google/cadvisor/stats" ) type manager struct { stats.NoopDestroy interval time.Duration vendorID string inHostNamespace bool } func (m *manager) GetCollector(containerName string, getContainerPids func() ([]string, error), numberOfNUMANodes int) (stats.Collector, error) { collector := newCollector(containerName, getContainerPids, m.interval, numberOfNUMANodes, m.vendorID, m.inHostNamespace) err := collector.setup() if err != nil { return &stats.NoopCollector{}, err } return collector, nil } func NewManager(interval time.Duration, setup func() error, vendorID string, inHostNamespace bool) (resctrl.ResControlManager, error) { err := setup() if err != nil { return &NoopManager{}, err } if !isResctrlInitialized { return &NoopManager{}, errors.New("the resctrl isn't initialized") } if !(enabledCMT || enabledMBM) { return &NoopManager{}, errors.New("there are no monitoring features available") } if !*raw.DockerOnly { klog.Warning("--docker_only should be set when collecting Resctrl metrics! See the runtime docs.") } return &manager{interval: interval, vendorID: vendorID, inHostNamespace: inHostNamespace}, nil } type NoopManager struct { stats.NoopDestroy } func (np *NoopManager) GetCollector(_ string, _ func() ([]string, error), _ int) (stats.Collector, error) { return &stats.NoopCollector{}, nil } ================================================ FILE: resctrl/intel/manager_test.go ================================================ //go:build linux // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ResControlManager tests. package intel import ( "os" "testing" "github.com/stretchr/testify/assert" "github.com/google/cadvisor/resctrl" ) func TestNewManager(t *testing.T) { var testCases = []struct { isResctrlInitialized bool enabledCMT bool enabledMBM bool inHostNamespace bool err string expected resctrl.ResControlManager }{ { true, true, false, true, "", &manager{interval: 0, inHostNamespace: true}, }, { true, false, true, true, "", &manager{interval: 0, inHostNamespace: true}, }, { true, true, true, false, "", &manager{interval: 0, inHostNamespace: false}, }, { false, true, false, false, "the resctrl isn't initialized", &NoopManager{}, }, { false, false, true, false, "the resctrl isn't initialized", &NoopManager{}, }, { false, true, true, true, "the resctrl isn't initialized", &NoopManager{}, }, { false, false, false, true, "the resctrl isn't initialized", &NoopManager{}, }, { true, false, false, true, "there are no monitoring features available", &NoopManager{}, }, } for _, test := range testCases { setup := func() error { isResctrlInitialized = test.isResctrlInitialized enabledCMT = test.enabledCMT enabledMBM = test.enabledMBM return nil } got, err := NewManager(0, setup, "", test.inHostNamespace) assert.Equal(t, got, test.expected) checkError(t, err, test.err) } } func TestGetCollector(t *testing.T) { rootResctrl = mockResctrl() defer os.RemoveAll(rootResctrl) pidsPath = mockContainersPids() defer os.RemoveAll(pidsPath) processPath = mockProcFs() defer os.RemoveAll(processPath) expectedID := "container" setup := func() error { isResctrlInitialized = true enabledCMT = true enabledMBM = true return nil } manager, err := NewManager(0, setup, "", true) assert.NoError(t, err) _, err = manager.GetCollector(expectedID, mockGetContainerPids, 2) assert.NoError(t, err) } ================================================ FILE: resctrl/intel/testing/tasks_empty ================================================ ================================================ FILE: resctrl/intel/testing/tasks_one ================================================ 2 ================================================ FILE: resctrl/intel/testing/tasks_two ================================================ 12 77 ================================================ FILE: resctrl/intel/utils.go ================================================ //go:build linux // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Utilities. package intel import ( "bufio" "bytes" "errors" "fmt" "os" "path/filepath" "strconv" "strings" "github.com/opencontainers/cgroups" "github.com/opencontainers/cgroups/fs2" "github.com/opencontainers/runc/libcontainer/intelrdt" ) const ( cpuCgroup = "cpu" rootContainer = "/" monitoringGroupDir = "mon_groups" processTask = "task" cpusFileName = "cpus" cpusListFileName = "cpus_list" schemataFileName = "schemata" tasksFileName = "tasks" modeFileName = "mode" sizeFileName = "size" infoDirName = "info" monDataDirName = "mon_data" monGroupsDirName = "mon_groups" noPidsPassedError = "there are no pids passed" noContainerNameError = "there are no container name passed" noControlGroupFoundError = "couldn't find control group matching container" llcOccupancyFileName = "llc_occupancy" mbmLocalBytesFileName = "mbm_local_bytes" mbmTotalBytesFileName = "mbm_total_bytes" containerPrefix = '/' minContainerNameLen = 2 // "/" e.g. "/a" unavailable = "Unavailable" monGroupPrefix = "cadvisor" ) var ( rootResctrl = "" pidsPath = "" processPath = "/proc" enabledMBM = false enabledCMT = false isResctrlInitialized = false groupDirectories = map[string]struct{}{ cpusFileName: {}, cpusListFileName: {}, infoDirName: {}, monDataDirName: {}, monGroupsDirName: {}, schemataFileName: {}, tasksFileName: {}, modeFileName: {}, sizeFileName: {}, } ) func Setup() error { var err error rootResctrl, err = intelrdt.Root() if err != nil { return fmt.Errorf("unable to initialize resctrl: %v", err) } if cgroups.IsCgroup2UnifiedMode() { pidsPath = fs2.UnifiedMountpoint } else { pidsPath = filepath.Join(fs2.UnifiedMountpoint, cpuCgroup) } enabledMBM = intelrdt.IsMBMEnabled() enabledCMT = intelrdt.IsCMTEnabled() isResctrlInitialized = true return nil } func prepareMonitoringGroup(containerName string, getContainerPids func() ([]string, error), inHostNamespace bool) (string, error) { if containerName == rootContainer { return rootResctrl, nil } pids, err := getContainerPids() if err != nil { return "", err } if len(pids) == 0 { return "", fmt.Errorf("couldn't obtain %q container pids: there is no pids in cgroup", containerName) } // Firstly, find the control group to which the container belongs. // Consider the root group. controlGroupPath, err := findGroup(rootResctrl, pids, true, false) if err != nil { return "", fmt.Errorf("%q %q: %q", noControlGroupFoundError, containerName, err) } if controlGroupPath == "" { return "", fmt.Errorf("%q %q", noControlGroupFoundError, containerName) } // Check if there is any monitoring group. monGroupPath, err := findGroup(filepath.Join(controlGroupPath, monGroupsDirName), pids, false, true) if err != nil { return "", fmt.Errorf("couldn't find monitoring group matching %q container: %v", containerName, err) } // Prepare new one if not exists. if monGroupPath == "" { // Remove leading prefix. // e.g. /my/container -> my/container if len(containerName) >= minContainerNameLen && containerName[0] == containerPrefix { containerName = containerName[1:] } // Add own prefix and use `-` instead `/`. // e.g. my/container -> cadvisor-my-container properContainerName := fmt.Sprintf("%s-%s", monGroupPrefix, strings.Replace(containerName, "/", "-", -1)) monGroupPath = filepath.Join(controlGroupPath, monitoringGroupDir, properContainerName) err = os.MkdirAll(monGroupPath, os.ModePerm) if err != nil { return "", fmt.Errorf("couldn't create monitoring group directory for %q container: %w", containerName, err) } if !inHostNamespace { processPath = "/rootfs/proc" } for _, pid := range pids { processThreads, err := getAllProcessThreads(filepath.Join(processPath, pid, processTask)) if err != nil { return "", err } for _, thread := range processThreads { err = intelrdt.WriteIntelRdtTasks(monGroupPath, thread) if err != nil { secondError := os.Remove(monGroupPath) if secondError != nil { return "", fmt.Errorf( "coudn't assign pids to %q container monitoring group: %w \n couldn't clear %q monitoring group: %v", containerName, err, containerName, secondError) } return "", fmt.Errorf("coudn't assign pids to %q container monitoring group: %w", containerName, err) } } } } return monGroupPath, nil } func getPids(containerName string) ([]int, error) { if len(containerName) == 0 { // No container name passed. return nil, errors.New(noContainerNameError) } pids, err := cgroups.GetAllPids(filepath.Join(pidsPath, containerName)) if err != nil { return nil, fmt.Errorf("couldn't obtain pids for %q container: %v", containerName, err) } return pids, nil } // getAllProcessThreads obtains all available processes from directory. // e.g. ls /proc/4215/task/ -> 4215, 4216, 4217, 4218 // func will return [4215, 4216, 4217, 4218]. func getAllProcessThreads(path string) ([]int, error) { processThreads := make([]int, 0) threadDirs, err := os.ReadDir(path) if err != nil { return processThreads, err } for _, dir := range threadDirs { pid, err := strconv.Atoi(dir.Name()) if err != nil { return nil, fmt.Errorf("couldn't parse %q dir: %v", dir.Name(), err) } processThreads = append(processThreads, pid) } return processThreads, nil } // findGroup returns the path of a control/monitoring group in which the pids are. func findGroup(group string, pids []string, includeGroup bool, exclusive bool) (string, error) { if len(pids) == 0 { return "", errors.New(noPidsPassedError) } availablePaths := make([]string, 0) if includeGroup { availablePaths = append(availablePaths, group) } files, err := os.ReadDir(group) for _, file := range files { if _, ok := groupDirectories[file.Name()]; !ok { availablePaths = append(availablePaths, filepath.Join(group, file.Name())) } } if err != nil { return "", fmt.Errorf("couldn't obtain groups paths: %w", err) } for _, path := range availablePaths { groupFound, err := arePIDsInGroup(path, pids, exclusive) if err != nil { return "", err } if groupFound { return path, nil } } return "", nil } // arePIDsInGroup returns true if all of the pids are within control group. func arePIDsInGroup(path string, pids []string, exclusive bool) (bool, error) { if len(pids) == 0 { return false, fmt.Errorf("couldn't obtain pids from %q path: %v", path, noPidsPassedError) } tasks, err := readTasksFile(filepath.Join(path, tasksFileName)) if err != nil { return false, err } any := false for _, pid := range pids { _, ok := tasks[pid] if !ok { // There are missing pids within group. if any { return false, fmt.Errorf("there should be all pids in group") } return false, nil } any = true } // Check if there should be only passed pids in group. if exclusive { if len(tasks) != len(pids) { return false, fmt.Errorf("group should have container pids only") } } return true, nil } // readTasksFile returns pids map from given tasks path. func readTasksFile(tasksPath string) (map[string]struct{}, error) { tasks := make(map[string]struct{}) tasksFile, err := os.Open(tasksPath) if err != nil { return tasks, fmt.Errorf("couldn't read tasks file from %q path: %w", tasksPath, err) } defer tasksFile.Close() scanner := bufio.NewScanner(tasksFile) for scanner.Scan() { tasks[scanner.Text()] = struct{}{} } if err := scanner.Err(); err != nil { return tasks, fmt.Errorf("couldn't obtain pids from %q path: %w", tasksPath, err) } return tasks, nil } func readStatFrom(path string, vendorID string) (uint64, error) { context, err := os.ReadFile(path) if err != nil { return 0, err } contextString := string(bytes.TrimSpace(context)) if contextString == unavailable { err := fmt.Errorf("\"Unavailable\" value from file %q", path) if vendorID == "AuthenticAMD" { kernelBugzillaLink := "https://bugzilla.kernel.org/show_bug.cgi?id=213311" err = fmt.Errorf("%v, possible bug: %q", err, kernelBugzillaLink) } return 0, err } stat, err := strconv.ParseUint(contextString, 10, 64) if err != nil { return stat, fmt.Errorf("unable to parse %q as a uint from file %q", string(context), path) } return stat, nil } func getIntelRDTStatsFrom(path string, vendorID string) (intelrdt.Stats, error) { stats := intelrdt.Stats{} statsDirectories, err := filepath.Glob(filepath.Join(path, monDataDirName, "*")) if err != nil { return stats, err } if len(statsDirectories) == 0 { return stats, fmt.Errorf("there is no mon_data stats directories: %q", path) } var cmtStats []intelrdt.CMTNumaNodeStats var mbmStats []intelrdt.MBMNumaNodeStats for _, dir := range statsDirectories { if enabledCMT { llcOccupancy, err := readStatFrom(filepath.Join(dir, llcOccupancyFileName), vendorID) if err != nil { return stats, err } cmtStats = append(cmtStats, intelrdt.CMTNumaNodeStats{LLCOccupancy: llcOccupancy}) } if enabledMBM { mbmTotalBytes, err := readStatFrom(filepath.Join(dir, mbmTotalBytesFileName), vendorID) if err != nil { return stats, err } mbmLocalBytes, err := readStatFrom(filepath.Join(dir, mbmLocalBytesFileName), vendorID) if err != nil { return stats, err } mbmStats = append(mbmStats, intelrdt.MBMNumaNodeStats{ MBMTotalBytes: mbmTotalBytes, MBMLocalBytes: mbmLocalBytes, }) } } stats.CMTStats = &cmtStats stats.MBMStats = &mbmStats return stats, nil } ================================================ FILE: resctrl/intel/utils_test.go ================================================ //go:build linux // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Utilities tests. // // Mocked environment: // - "container" first container with {1, 2, 3} processes. // - "another" second container with {5, 6} processes. package intel import ( "fmt" "os" "path/filepath" "testing" "github.com/opencontainers/cgroups" "github.com/opencontainers/runc/libcontainer/intelrdt" "github.com/stretchr/testify/assert" ) func init() { // All the test cases in this file uses "fake" cgroups (not the real // cgroupfs). This setting relaxes filesystem type check in cgroups // package so it can work with fake cgroups. cgroups.TestMode = true } func mockAllGetContainerPids() ([]string, error) { return []string{"1", "2", "3", "5", "6"}, nil } func mockGetContainerPids() ([]string, error) { return []string{"1", "2", "3"}, nil } func mockAnotherGetContainerPids() ([]string, error) { return []string{"5", "6"}, nil } func touch(path string) error { file, err := os.OpenFile(path, os.O_CREATE, os.ModePerm) if err != nil { return err } return file.Close() } func touchDir(path string) error { err := os.MkdirAll(path, os.ModePerm) if err != nil { return err } return nil } func fillPids(path string, pids []int) error { f, err := os.OpenFile(path, os.O_WRONLY, os.ModePerm) if err != nil { return err } defer f.Close() for _, pid := range pids { _, err := fmt.Fprintln(f, pid) if err != nil { return err } } return nil } func mockResctrl() string { path, _ := os.MkdirTemp("", "resctrl") var files = []struct { path string touch func(string) error }{ // Mock root files. { filepath.Join(path, cpusFileName), touch, }, { filepath.Join(path, cpusListFileName), touch, }, { filepath.Join(path, infoDirName), touchDir, }, { filepath.Join(path, monDataDirName), touchDir, }, { filepath.Join(path, monGroupsDirName), touchDir, }, { filepath.Join(path, schemataFileName), touch, }, { filepath.Join(path, modeFileName), touch, }, { filepath.Join(path, sizeFileName), touch, }, { filepath.Join(path, tasksFileName), touch, }, // Create custom CLOSID "m1". { filepath.Join(path, "m1"), touchDir, }, { filepath.Join(path, "m1", cpusFileName), touch, }, { filepath.Join(path, "m1", cpusListFileName), touch, }, { filepath.Join(path, "m1", monDataDirName), touchDir, }, { filepath.Join(path, "m1", monGroupsDirName), touchDir, }, { filepath.Join(path, "m1", schemataFileName), touch, }, { filepath.Join(path, "m1", tasksFileName), touch, }, { filepath.Join(path, "m1", monGroupsDirName, "test"), touchDir, }, { filepath.Join(path, "m1", monGroupsDirName, "test", tasksFileName), touch, }, } for _, file := range files { err := file.touch(file.path) if err != nil { return "" } } // Mock root group task file. err := fillPids(filepath.Join(path, tasksFileName), []int{1, 2, 3, 4}) if err != nil { return "" } // Mock custom CLOSID "m1" task file. err = fillPids(filepath.Join(path, "m1", tasksFileName), []int{5, 6, 7, 8, 9, 10}) if err != nil { return "" } // Mock custom mon group "test" task file. err = fillPids(filepath.Join(path, "m1", monGroupsDirName, "test", tasksFileName), []int{7, 8}) if err != nil { return "" } return path } func mockResctrlMonData(path string) { _ = touchDir(filepath.Join(path, monDataDirName, "mon_L3_00")) _ = touchDir(filepath.Join(path, monDataDirName, "mon_L3_01")) var files = []struct { path string value string }{ { filepath.Join(path, monDataDirName, "mon_L3_00", llcOccupancyFileName), "1111", }, { filepath.Join(path, monDataDirName, "mon_L3_00", mbmLocalBytesFileName), "2222", }, { filepath.Join(path, monDataDirName, "mon_L3_00", mbmTotalBytesFileName), "3333", }, { filepath.Join(path, monDataDirName, "mon_L3_01", llcOccupancyFileName), "3333", }, { filepath.Join(path, monDataDirName, "mon_L3_01", mbmLocalBytesFileName), "1111", }, { filepath.Join(path, monDataDirName, "mon_L3_01", mbmTotalBytesFileName), "3333", }, } for _, file := range files { _ = touch(file.path) _ = os.WriteFile(file.path, []byte(file.value), os.ModePerm) } } func mockContainersPids() string { path, _ := os.MkdirTemp("", "cgroup") // container _ = touchDir(filepath.Join(path, "container")) _ = touch(filepath.Join(path, "container", cgroups.CgroupProcesses)) err := fillPids(filepath.Join(path, "container", cgroups.CgroupProcesses), []int{1, 2, 3}) if err != nil { return "" } // another _ = touchDir(filepath.Join(path, "another")) _ = touch(filepath.Join(path, "another", cgroups.CgroupProcesses)) err = fillPids(filepath.Join(path, "another", cgroups.CgroupProcesses), []int{5}) if err != nil { return "" } return path } func mockProcFs() string { path, _ := os.MkdirTemp("", "proc") var files = []struct { path string touch func(string) error }{ // container { filepath.Join(path, "1", processTask, "1"), touchDir, }, { filepath.Join(path, "2", processTask, "2"), touchDir, }, { filepath.Join(path, "3", processTask, "3"), touchDir, }, { filepath.Join(path, "4", processTask, "4"), touchDir, }, // another { filepath.Join(path, "5", processTask, "5"), touchDir, }, { filepath.Join(path, "6", processTask, "6"), touchDir, }, } for _, file := range files { _ = file.touch(file.path) } return path } func checkError(t *testing.T, err error, expected string) { if expected != "" { assert.EqualError(t, err, expected) } else { assert.NoError(t, err) } } func TestPrepareMonitoringGroup(t *testing.T) { rootResctrl = mockResctrl() defer os.RemoveAll(rootResctrl) pidsPath = mockContainersPids() defer os.RemoveAll(pidsPath) processPath = mockProcFs() defer os.RemoveAll(processPath) var testCases = []struct { container string getContainerPids func() ([]string, error) expected string err string }{ { "container", mockGetContainerPids, filepath.Join(rootResctrl, monGroupsDirName, "cadvisor-container"), "", }, { "another", mockAnotherGetContainerPids, filepath.Join(rootResctrl, "m1", monGroupsDirName, "cadvisor-another"), "", }, { "/", mockAllGetContainerPids, rootResctrl, "", }, } for _, test := range testCases { actual, err := prepareMonitoringGroup(test.container, test.getContainerPids, true) assert.Equal(t, test.expected, actual) checkError(t, err, test.err) } } func TestGetPids(t *testing.T) { pidsPath = mockContainersPids() defer os.RemoveAll(pidsPath) var testCases = []struct { container string expected []int err string }{ { "", nil, noContainerNameError, }, { "container", []int{1, 2, 3}, "", }, { "no_container", nil, fmt.Sprintf("couldn't obtain pids for \"no_container\" container: lstat %v: no such file or directory", filepath.Join(pidsPath, "no_container")), }, } for _, test := range testCases { actual, err := getPids(test.container) assert.Equal(t, test.expected, actual) checkError(t, err, test.err) } } func TestGetAllProcessThreads(t *testing.T) { mockProcFs := func() string { path, _ := os.MkdirTemp("", "proc") var files = []struct { path string touch func(string) error }{ // correct { filepath.Join(path, "4215", processTask, "4215"), touchDir, }, { filepath.Join(path, "4215", processTask, "4216"), touchDir, }, { filepath.Join(path, "4215", processTask, "4217"), touchDir, }, { filepath.Join(path, "4215", processTask, "4218"), touchDir, }, // invalid { filepath.Join(path, "301", processTask, "301"), touchDir, }, { filepath.Join(path, "301", processTask, "incorrect"), touchDir, }, } for _, file := range files { _ = file.touch(file.path) } return path } mockedProcFs := mockProcFs() defer os.RemoveAll(mockedProcFs) var testCases = []struct { path string expected []int err string }{ { filepath.Join(mockedProcFs, "4215", processTask), []int{4215, 4216, 4217, 4218}, "", }, { filepath.Join(mockedProcFs, "301", processTask), nil, "couldn't parse \"incorrect\" dir: strconv.Atoi: parsing \"incorrect\": invalid syntax", }, } for _, test := range testCases { actual, err := getAllProcessThreads(test.path) assert.Equal(t, test.expected, actual) checkError(t, err, test.err) } } func TestFindGroup(t *testing.T) { rootResctrl = mockResctrl() defer os.RemoveAll(rootResctrl) var testCases = []struct { path string pids []string includeGroup bool exclusive bool expected string err string }{ { rootResctrl, []string{"1", "2", "3", "4"}, true, false, rootResctrl, "", }, { rootResctrl, []string{}, true, false, "", "there are no pids passed", }, { rootResctrl, []string{"5", "6"}, true, false, filepath.Join(rootResctrl, "m1"), "", }, { rootResctrl, []string{"11", "12"}, true, false, "", "", }, { filepath.Join(rootResctrl, "m1", monGroupsDirName), []string{"5", "6"}, false, true, "", "", }, { filepath.Join(rootResctrl, "m1", monGroupsDirName), []string{"7", "8"}, false, true, filepath.Join(rootResctrl, "m1", monGroupsDirName, "test"), "", }, { filepath.Join(rootResctrl, "m1", monGroupsDirName), []string{"7"}, false, true, "", "group should have container pids only", }, } for _, test := range testCases { actual, err := findGroup(test.path, test.pids, test.includeGroup, test.exclusive) assert.Equal(t, test.expected, actual) checkError(t, err, test.err) } } func TestArePIDsInGroup(t *testing.T) { rootResctrl = mockResctrl() defer os.RemoveAll(rootResctrl) var testCases = []struct { expected bool err string path string pids []string exclusive bool }{ { true, "", rootResctrl, []string{"1", "2"}, false, }, { false, "there should be all pids in group", rootResctrl, []string{"4", "5"}, false, }, { false, "", filepath.Join(rootResctrl, "m1"), []string{"1"}, false, }, { false, fmt.Sprintf("couldn't read tasks file from %q path: open %s: no such file or directory", filepath.Join(rootResctrl, monitoringGroupDir, tasksFileName), filepath.Join(rootResctrl, monitoringGroupDir, tasksFileName)), filepath.Join(rootResctrl, monitoringGroupDir), []string{"1", "2"}, false, }, { false, fmt.Sprintf("couldn't obtain pids from %q path: %v", rootResctrl, noPidsPassedError), rootResctrl, nil, false, }, } for _, test := range testCases { actual, err := arePIDsInGroup(test.path, test.pids, test.exclusive) assert.Equal(t, test.expected, actual) checkError(t, err, test.err) } } func TestGetStats(t *testing.T) { rootResctrl = mockResctrl() defer os.RemoveAll(rootResctrl) pidsPath = mockContainersPids() defer os.RemoveAll(pidsPath) processPath = mockProcFs() defer os.RemoveAll(processPath) enabledCMT, enabledMBM = true, true var testCases = []struct { container string expected intelrdt.Stats err string }{ { "container", intelrdt.Stats{ MBMStats: &[]intelrdt.MBMNumaNodeStats{ { MBMTotalBytes: 3333, MBMLocalBytes: 2222, }, { MBMTotalBytes: 3333, MBMLocalBytes: 1111, }, }, CMTStats: &[]intelrdt.CMTNumaNodeStats{ { LLCOccupancy: 1111, }, { LLCOccupancy: 3333, }, }, }, "", }, { "another", intelrdt.Stats{ MBMStats: &[]intelrdt.MBMNumaNodeStats{ { MBMTotalBytes: 3333, MBMLocalBytes: 2222, }, { MBMTotalBytes: 3333, MBMLocalBytes: 1111, }, }, CMTStats: &[]intelrdt.CMTNumaNodeStats{ { LLCOccupancy: 1111, }, { LLCOccupancy: 3333, }, }, }, "", }, { "/", intelrdt.Stats{ MBMStats: &[]intelrdt.MBMNumaNodeStats{ { MBMTotalBytes: 3333, MBMLocalBytes: 2222, }, { MBMTotalBytes: 3333, MBMLocalBytes: 1111, }, }, CMTStats: &[]intelrdt.CMTNumaNodeStats{ { LLCOccupancy: 1111, }, { LLCOccupancy: 3333, }, }, }, "", }, } for _, test := range testCases { containerPath, _ := prepareMonitoringGroup(test.container, mockGetContainerPids, true) mockResctrlMonData(containerPath) actual, err := getIntelRDTStatsFrom(containerPath, "") checkError(t, err, test.err) assert.Equal(t, test.expected.CMTStats, actual.CMTStats) assert.Equal(t, test.expected.MBMStats, actual.MBMStats) } } func TestReadTasksFile(t *testing.T) { var testCases = []struct { tasksFile string expected map[string]struct{} err string }{ {"testing/tasks_two", map[string]struct{}{ "12": {}, "77": {}, }, "", }, {"testing/tasks_one", map[string]struct{}{ "2": {}, }, "", }, {"testing/tasks_empty", map[string]struct{}{}, "", }, } for _, test := range testCases { actual, err := readTasksFile(test.tasksFile) assert.Equal(t, test.expected, actual) checkError(t, err, test.err) } } ================================================ FILE: stats/noop.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Noop perf Manager and Collector. package stats import ( "k8s.io/klog/v2" v1 "github.com/google/cadvisor/info/v1" ) type NoopManager struct { NoopDestroy } type NoopDestroy struct{} func (nsd NoopDestroy) Destroy() { klog.V(5).Info("No-op Destroy function called") } func (m *NoopManager) GetCollector(cgroup string) (Collector, error) { return &NoopCollector{}, nil } type NoopCollector struct { NoopDestroy } func (c *NoopCollector) UpdateStats(stats *v1.ContainerStats) error { return nil } ================================================ FILE: stats/types.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Handling statistics that are fully controlled in cAdvisor package stats import info "github.com/google/cadvisor/info/v1" // This is supposed to store global state about an cAdvisor metrics collector. // cAdvisor manager will call Destroy() when it stops. // For each container detected by the cAdvisor manager, it will call // GetCollector() with the devices cgroup path for that container. // GetCollector() is supposed to return an object that can update // external stats for that container. type Manager interface { Destroy() GetCollector(deviceCgroup string) (Collector, error) } // Collector can update ContainerStats by adding more metrics. type Collector interface { Destroy() UpdateStats(*info.ContainerStats) error } ================================================ FILE: storage/common_flags.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package storage import ( "flag" "time" ) var ArgDbUsername = flag.String("storage_driver_user", "root", "database username") var ArgDbPassword = flag.String("storage_driver_password", "root", "database password") var ArgDbHost = flag.String("storage_driver_host", "localhost:8086", "database host:port") var ArgDbName = flag.String("storage_driver_db", "cadvisor", "database name") var ArgDbTable = flag.String("storage_driver_table", "stats", "table name") var ArgDbIsSecure = flag.Bool("storage_driver_secure", false, "use secure connection with database") var ArgDbBufferDuration = flag.Duration("storage_driver_buffer_duration", 60*time.Second, "Writes in the storage driver will be buffered for this duration, and committed to the non memory backends as a single transaction") ================================================ FILE: storage/storage.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package storage import ( "fmt" "sort" info "github.com/google/cadvisor/info/v1" ) type StorageDriver interface { AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error // Close will clear the state of the storage driver. The elements // stored in the underlying storage may or may not be deleted depending // on the implementation of the storage driver. Close() error } type StorageDriverFunc func() (StorageDriver, error) var registeredPlugins = map[string](StorageDriverFunc){} func RegisterStorageDriver(name string, f StorageDriverFunc) { registeredPlugins[name] = f } func New(name string) (StorageDriver, error) { if name == "" { return nil, nil } f, ok := registeredPlugins[name] if !ok { return nil, fmt.Errorf("unknown backend storage driver: %s", name) } return f() } func ListDrivers() []string { drivers := make([]string, 0, len(registeredPlugins)) for name := range registeredPlugins { drivers = append(drivers, name) } sort.Strings(drivers) return drivers } ================================================ FILE: summary/buffer.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package summary import ( info "github.com/google/cadvisor/info/v2" ) // Manages a buffer of usage samples. // This is similar to stats buffer in cache/memory. // The main difference is that we do not pre-allocate the buffer as most containers // won't live that long. type SamplesBuffer struct { // list of collected samples. samples []info.Usage // maximum size this buffer can grow to. maxSize int // index for the latest sample. index int } // Initializes an empty buffer. func NewSamplesBuffer(size int) *SamplesBuffer { return &SamplesBuffer{ index: -1, maxSize: size, } } // Returns the current number of samples in the buffer. func (s *SamplesBuffer) Size() int { return len(s.samples) } // Add an element to the buffer. Oldest one is overwritten if required. func (s *SamplesBuffer) Add(stat info.Usage) { if len(s.samples) < s.maxSize { s.samples = append(s.samples, stat) s.index++ return } s.index = (s.index + 1) % s.maxSize s.samples[s.index] = stat } // Returns pointers to the last 'n' stats. func (s *SamplesBuffer) RecentStats(n int) []*info.Usage { if n > len(s.samples) { n = len(s.samples) } start := s.index - (n - 1) if start < 0 { start += len(s.samples) } out := make([]*info.Usage, n) for i := 0; i < n; i++ { index := (start + i) % len(s.samples) out[i] = &s.samples[index] } return out } ================================================ FILE: summary/buffer_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package summary import ( "reflect" "testing" info "github.com/google/cadvisor/info/v2" ) func createSample(i uint64) info.Usage { usage := info.Usage{} usage.PercentComplete = 100 usage.Cpu = info.Percentiles{ Present: true, Mean: i * 50, Max: i * 100, Ninety: i * 90, } usage.Memory = info.Percentiles{ Present: true, Mean: i * 50 * 1024, Max: i * 100 * 1024, Ninety: i * 90 * 1024, } return usage } func expectSize(t *testing.T, b *SamplesBuffer, expectedSize int) { if b.Size() != expectedSize { t.Errorf("Expected size %d, got %d", expectedSize, b.Size()) } } func expectElements(t *testing.T, b *SamplesBuffer, expected []info.Usage) { out := b.RecentStats(b.Size()) if len(out) != len(expected) { t.Errorf("Expected %d elements, got %d", len(expected), len(out)) } for i, el := range out { if !reflect.DeepEqual(*el, expected[i]) { t.Errorf("Expected elements %v, got %v", expected[i], *el) } } } func TestEmpty(t *testing.T) { b := NewSamplesBuffer(5) expectSize(t, b, 0) expectElements(t, b, []info.Usage{}) } func TestAddSingleSample(t *testing.T) { b := NewSamplesBuffer(5) sample := createSample(1) b.Add(sample) expectSize(t, b, 1) expectElements(t, b, []info.Usage{sample}) } func TestFullBuffer(t *testing.T) { maxSize := 5 b := NewSamplesBuffer(maxSize) samples := []info.Usage{} for i := 0; i < maxSize; i++ { sample := createSample(uint64(i)) samples = append(samples, sample) b.Add(sample) } expectSize(t, b, maxSize) expectElements(t, b, samples) } func TestOverflow(t *testing.T) { maxSize := 5 overflow := 2 b := NewSamplesBuffer(maxSize) samples := []info.Usage{} for i := 0; i < maxSize+overflow; i++ { sample := createSample(uint64(i)) if i >= overflow { samples = append(samples, sample) } b.Add(sample) } expectSize(t, b, maxSize) expectElements(t, b, samples) } func TestReplaceAll(t *testing.T) { maxSize := 5 b := NewSamplesBuffer(maxSize) samples := []info.Usage{} for i := 0; i < maxSize*2; i++ { sample := createSample(uint64(i)) if i >= maxSize { samples = append(samples, sample) } b.Add(sample) } expectSize(t, b, maxSize) expectElements(t, b, samples) } ================================================ FILE: summary/percentiles.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Utility methods to calculate percentiles. package summary import ( "fmt" "math" "sort" info "github.com/google/cadvisor/info/v2" ) const secondsToMilliSeconds = 1000 const milliSecondsToNanoSeconds = 1000000 const secondsToNanoSeconds = secondsToMilliSeconds * milliSecondsToNanoSeconds type Uint64Slice []uint64 func (s Uint64Slice) Len() int { return len(s) } func (s Uint64Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s Uint64Slice) Less(i, j int) bool { return s[i] < s[j] } // Get percentile of the provided samples. Round to integer. func (s Uint64Slice) GetPercentile(d float64) uint64 { if d < 0.0 || d > 1.0 { return 0 } count := s.Len() if count == 0 { return 0 } sort.Sort(s) n := float64(d * (float64(count) + 1)) idx, frac := math.Modf(n) index := int(idx) percentile := float64(s[index-1]) if index > 1 && index < count { percentile += frac * float64(s[index]-s[index-1]) } return uint64(percentile) } type mean struct { // current count. count uint64 // current mean. Mean float64 } func (m *mean) Add(value uint64) { m.count++ if m.count == 1 { m.Mean = float64(value) return } c := float64(m.count) v := float64(value) m.Mean = (m.Mean*(c-1) + v) / c } type Percentile interface { Add(info.Percentiles) AddSample(uint64) GetAllPercentiles() info.Percentiles } type resource struct { // list of samples being tracked. samples Uint64Slice // average from existing samples. mean mean // maximum value seen so far in the added samples. max uint64 } // Adds a new percentile sample. func (r *resource) Add(p info.Percentiles) { if !p.Present { return } if p.Max > r.max { r.max = p.Max } r.mean.Add(p.Mean) // Selecting 90p of 90p :( r.samples = append(r.samples, p.Ninety) } // Add a single sample. Internally, we convert it to a fake percentile sample. func (r *resource) AddSample(val uint64) { sample := info.Percentiles{ Present: true, Mean: val, Std: 0, Max: val, Fifty: val, Ninety: val, NinetyFive: val, Count: 1, } r.Add(sample) } // Get max, average, and 90p from existing samples. func (r *resource) GetAllPercentiles() info.Percentiles { p := info.Percentiles{} p.Mean = uint64(r.mean.Mean) p.Std = uint64(r.samples.getStandardDeviation(r.mean.Mean)) p.Max = r.max p.Fifty = r.samples.GetPercentile(0.5) p.Ninety = r.samples.GetPercentile(0.9) p.NinetyFive = r.samples.GetPercentile(0.95) // len(samples) is equal to count stored in mean. p.Count = r.mean.count p.Present = true return p } func NewResource(size int) Percentile { return &resource{ samples: make(Uint64Slice, 0, size), mean: mean{count: 0, Mean: 0}, } } // Return aggregated percentiles from the provided percentile samples. func GetDerivedPercentiles(stats []*info.Usage) info.Usage { cpu := NewResource(len(stats)) memory := NewResource(len(stats)) for _, stat := range stats { cpu.Add(stat.Cpu) memory.Add(stat.Memory) } usage := info.Usage{} usage.Cpu = cpu.GetAllPercentiles() usage.Memory = memory.GetAllPercentiles() return usage } // Calculate part of a minute this sample set represent. func getPercentComplete(stats []*secondSample) (percent int32) { numSamples := len(stats) if numSamples > 1 { percent = 100 timeRange := stats[numSamples-1].Timestamp.Sub(stats[0].Timestamp).Nanoseconds() // allow some slack if timeRange < 58*secondsToNanoSeconds { percent = int32((timeRange * 100) / 60 * secondsToNanoSeconds) } } return } func (s Uint64Slice) getStandardDeviation(mean float64) float64 { n := len(s) if n <= 1 { return 0 } var ss float64 for _, v := range s { d := float64(v) - mean ss += d * d } // Use Bessel's correction (n-1) to calculate sample standard deviation. // This provides an unbiased estimate of population variance from sample data. return math.Sqrt(ss / float64(n-1)) } // Calculate cpurate from two consecutive total cpu usage samples. func getCPURate(latest, previous secondSample) (uint64, error) { elapsed := latest.Timestamp.Sub(previous.Timestamp).Nanoseconds() if elapsed < 10*milliSecondsToNanoSeconds { return 0, fmt.Errorf("elapsed time too small: %d ns: time now %s last %s", elapsed, latest.Timestamp.String(), previous.Timestamp.String()) } if latest.Cpu < previous.Cpu { return 0, fmt.Errorf("bad sample: cumulative cpu usage dropped from %d to %d", latest.Cpu, previous.Cpu) } // Cpurate is calculated in cpu-milliseconds per second. cpuRate := (latest.Cpu - previous.Cpu) * secondsToMilliSeconds / uint64(elapsed) return cpuRate, nil } // Returns a percentile sample for a minute by aggregating seconds samples. func GetMinutePercentiles(stats []*secondSample) info.Usage { lastSample := secondSample{} cpu := NewResource(len(stats)) memory := NewResource(len(stats)) for _, stat := range stats { if !lastSample.Timestamp.IsZero() { cpuRate, err := getCPURate(*stat, lastSample) if err != nil { continue } cpu.AddSample(cpuRate) memory.AddSample(stat.Memory) } else { memory.AddSample(stat.Memory) } lastSample = *stat } percent := getPercentComplete(stats) return info.Usage{ PercentComplete: percent, Cpu: cpu.GetAllPercentiles(), Memory: memory.GetAllPercentiles(), } } ================================================ FILE: summary/percentiles_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package summary import ( "math" "testing" "time" info "github.com/google/cadvisor/info/v2" ) const ( Nanosecond = 1000000000 N = 100 // Standard deviation of the sequence [1..99] using sample standard deviation formula. // N = 100 in every test // This is sqrt(Σ(i - 50)² / 98) where i ∈ [1,99], mean = 50, n = 99. StdDevFactor = 28.722813232 ) func assertPercentile(t *testing.T, s Uint64Slice, f float64, want uint64) { if got := s.GetPercentile(f); got != want { t.Errorf("GetPercentile(%f) is %d, should be %d.", f, got, want) } } func TestPercentile(t *testing.T) { s := make(Uint64Slice, 0, N) for i := N; i > 0; i-- { s = append(s, uint64(i)) } assertPercentile(t, s, 0.2, 20) assertPercentile(t, s, 0.7, 70) assertPercentile(t, s, 0.9, 90) for i := 101; i <= N+5; i++ { s = append(s, uint64(i)) } // 90p should be between 94 and 95. Promoted to 95. assertPercentile(t, s, 0.2, 21) assertPercentile(t, s, 0.7, 74) assertPercentile(t, s, 0.9, 95) } func TestMean(t *testing.T) { var i uint64 mean := mean{count: 0, Mean: 0} for i = 1; i < N; i++ { mean.Add(i) } if mean.Mean != 50.0 { t.Errorf("Mean is %f, should be 50.0", mean.Mean) } } func TestAggregates(t *testing.T) { var i uint64 ct := time.Now() stats := make([]*secondSample, 0, N) for i = 1; i < N; i++ { s := &secondSample{ Timestamp: ct.Add(time.Duration(i) * time.Second), // cpu rate is 1 s/s Cpu: i * Nanosecond, // Memory grows by a KB every second. Memory: i * 1024, } stats = append(stats, s) } usage := GetMinutePercentiles(stats) // Cpu mean, max, and 90p should all be 1000 ms/s. cpuExpected := info.Percentiles{ Present: true, Mean: 1000, Std: 0, Max: 1000, Fifty: 1000, Ninety: 1000, NinetyFive: 1000, // Since cpu is calculated between samples, we lose 1 sample. Count: N - 2, } if usage.Cpu != cpuExpected { t.Errorf("cpu stats are %+v. Expected %+v", usage.Cpu, cpuExpected) } memExpected := info.Percentiles{ Present: true, Mean: 50 * 1024, Std: uint64(math.Round(StdDevFactor * 1024)), Max: 99 * 1024, Fifty: 50 * 1024, Ninety: 90 * 1024, NinetyFive: 95 * 1024, Count: N - 1, } if usage.Memory != memExpected { t.Errorf("memory stats are mean %+v. Expected %+v", usage.Memory, memExpected) } } func TestSamplesCloseInTimeIgnored(t *testing.T) { var i uint64 ct := time.Now() stats := make([]*secondSample, 0, N*2) for i = 1; i < N; i++ { s1 := &secondSample{ Timestamp: ct.Add(time.Duration(i) * time.Second), // cpu rate is 1 s/s Cpu: i * Nanosecond, // Memory grows by a KB every second. Memory: i * 1024, } stats = append(stats, s1) // Add another dummy sample too close in time to the last one. s2 := &secondSample{ // Add extra millisecond. Timestamp: ct.Add(time.Duration(i) * time.Second).Add(time.Duration(1) * time.Millisecond), Cpu: i * 100 * Nanosecond, Memory: i * 1024 * 1024, } stats = append(stats, s2) } usage := GetMinutePercentiles(stats) // Cpu mean, max, and 90p should all be 1000 ms/s. All high-value samples are discarded. cpuExpected := info.Percentiles{ Present: true, Mean: 1000, Std: 0, Max: 1000, Fifty: 1000, Ninety: 1000, NinetyFive: 1000, // Since cpu is calculated between samples, we lose 1 sample. Count: N - 2, } if usage.Cpu != cpuExpected { t.Errorf("cpu stats are %+v. Expected %+v", usage.Cpu, cpuExpected) } memExpected := info.Percentiles{ Present: true, Mean: 50 * 1024, Std: uint64(math.Round(StdDevFactor * 1024)), Max: 99 * 1024, Fifty: 50 * 1024, Ninety: 90 * 1024, NinetyFive: 95 * 1024, Count: N - 1, } if usage.Memory != memExpected { t.Errorf("memory stats are mean %+v. Expected %+v", usage.Memory, memExpected) } } func TestDerivedStats(t *testing.T) { var i uint64 stats := make([]*info.Usage, 0, N) for i = 1; i < N; i++ { s := &info.Usage{ PercentComplete: 100, Cpu: info.Percentiles{ Present: true, Mean: i * Nanosecond, Max: i * Nanosecond, Fifty: i * Nanosecond, Ninety: i * Nanosecond, NinetyFive: i * Nanosecond, }, Memory: info.Percentiles{ Present: true, Mean: i * 1024, Max: i * 1024, Fifty: i * 1024, Ninety: i * 1024, NinetyFive: i * 1024, }, } stats = append(stats, s) } usage := GetDerivedPercentiles(stats) cpuExpected := info.Percentiles{ Present: true, Mean: 50 * Nanosecond, Std: uint64(math.Round(StdDevFactor * Nanosecond)), Max: 99 * Nanosecond, Fifty: 50 * Nanosecond, Ninety: 90 * Nanosecond, NinetyFive: 95 * Nanosecond, // GetDerivedPercentiles calculates directly from samples, hence we don't lose any samples. Count: N - 1, } if usage.Cpu != cpuExpected { t.Errorf("cpu stats are %+v. Expected %+v", usage.Cpu, cpuExpected) } memExpected := info.Percentiles{ Present: true, Mean: 50 * 1024, Std: uint64(math.Round(StdDevFactor * 1024)), Max: 99 * 1024, Fifty: 50 * 1024, Ninety: 90 * 1024, NinetyFive: 95 * 1024, Count: N - 1, } if usage.Memory != memExpected { t.Errorf("memory stats are mean %+v. Expected %+v", usage.Memory, memExpected) } } ================================================ FILE: summary/summary.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Maintains the summary of aggregated minute, hour, and day stats. // For a container running for more than a day, amount of tracked data can go up to // 40 KB when cpu and memory are tracked. We'll start by enabling collection for the // node, followed by docker, and then all containers as we understand the usage pattern // better // TODO(rjnagal): Optimize the size if we start running it for every container. package summary import ( "fmt" "sync" "time" v1 "github.com/google/cadvisor/info/v1" info "github.com/google/cadvisor/info/v2" ) // Usage fields we track for generating percentiles. type secondSample struct { Timestamp time.Time // time when the sample was recorded. Cpu uint64 // cpu usage Memory uint64 // memory usage } type availableResources struct { Cpu bool Memory bool } type StatsSummary struct { // Resources being tracked for this container. available availableResources // list of second samples. The list is cleared when a new minute samples is generated. secondSamples []*secondSample // minute percentiles. We track 24 * 60 maximum samples. minuteSamples *SamplesBuffer // latest derived instant, minute, hour, and day stats. Instant sample updated every second. // Others updated every minute. derivedStats info.DerivedStats // Guarded by dataLock. dataLock sync.RWMutex } // Adds a new seconds sample. // If enough seconds samples are collected, a minute sample is generated and derived // stats are updated. func (s *StatsSummary) AddSample(stat v1.ContainerStats) error { sample := secondSample{} sample.Timestamp = stat.Timestamp if s.available.Cpu { sample.Cpu = stat.Cpu.Usage.Total } if s.available.Memory { sample.Memory = stat.Memory.WorkingSet } s.secondSamples = append(s.secondSamples, &sample) s.updateLatestUsage() // TODO(jnagal): Use 'available' to avoid unnecessary computation. numSamples := len(s.secondSamples) elapsed := time.Nanosecond if numSamples > 1 { start := s.secondSamples[0].Timestamp end := s.secondSamples[numSamples-1].Timestamp elapsed = end.Sub(start) } if elapsed > 60*time.Second { // Make a minute sample. This works with dynamic housekeeping as long // as we keep max dynamic housekeeping period close to a minute. minuteSample := GetMinutePercentiles(s.secondSamples) // Clear seconds samples. Keep the latest sample for continuity. // Copying and resizing helps avoid slice re-allocation. s.secondSamples[0] = s.secondSamples[numSamples-1] s.secondSamples = s.secondSamples[:1] s.minuteSamples.Add(minuteSample) err := s.updateDerivedStats() if err != nil { return err } } return nil } func (s *StatsSummary) updateLatestUsage() { usage := info.InstantUsage{} numStats := len(s.secondSamples) if numStats < 1 { return } latest := s.secondSamples[numStats-1] usage.Memory = latest.Memory if numStats > 1 { previous := s.secondSamples[numStats-2] cpu, err := getCPURate(*latest, *previous) if err == nil { usage.Cpu = cpu } } s.dataLock.Lock() defer s.dataLock.Unlock() s.derivedStats.LatestUsage = usage s.derivedStats.Timestamp = latest.Timestamp } // Generate new derived stats based on current minute stats samples. func (s *StatsSummary) updateDerivedStats() error { derived := info.DerivedStats{} derived.Timestamp = time.Now() minuteSamples := s.minuteSamples.RecentStats(1) if len(minuteSamples) != 1 { return fmt.Errorf("failed to retrieve minute stats") } derived.MinuteUsage = *minuteSamples[0] hourUsage, err := s.getDerivedUsage(60) if err != nil { return fmt.Errorf("failed to compute hour stats: %v", err) } dayUsage, err := s.getDerivedUsage(60 * 24) if err != nil { return fmt.Errorf("failed to compute day usage: %v", err) } derived.HourUsage = hourUsage derived.DayUsage = dayUsage s.dataLock.Lock() defer s.dataLock.Unlock() derived.LatestUsage = s.derivedStats.LatestUsage s.derivedStats = derived return nil } // helper method to get hour and daily derived stats func (s *StatsSummary) getDerivedUsage(n int) (info.Usage, error) { if n < 1 { return info.Usage{}, fmt.Errorf("invalid number of samples requested: %d", n) } samples := s.minuteSamples.RecentStats(n) numSamples := len(samples) if numSamples < 1 { return info.Usage{}, fmt.Errorf("failed to retrieve any minute stats") } // We generate derived stats even with partial data. usage := GetDerivedPercentiles(samples) // Assumes we have equally placed minute samples. usage.PercentComplete = int32(numSamples * 100 / n) return usage, nil } // Return the latest calculated derived stats. func (s *StatsSummary) DerivedStats() (info.DerivedStats, error) { s.dataLock.RLock() defer s.dataLock.RUnlock() return s.derivedStats, nil } func New(spec v1.ContainerSpec) (*StatsSummary, error) { summary := StatsSummary{} if spec.HasCpu { summary.available.Cpu = true } if spec.HasMemory { summary.available.Memory = true } if !summary.available.Cpu && !summary.available.Memory { return nil, fmt.Errorf("none of the resources are being tracked") } summary.minuteSamples = NewSamplesBuffer(60 /* one hour */) return &summary, nil } ================================================ FILE: test.htdigest ================================================ admin:localhost:70f2631dded4ce5ad0ebbea5faa6ad6e ================================================ FILE: test.htpasswd ================================================ admin:$apr1$WVO0Bsre$VrmWGDbcBV1fdAkvgQwdk0 ================================================ FILE: utils/cloudinfo/aws/aws.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cloudinfo import ( "context" "io" "os" "strings" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/utils/cloudinfo" ) const ( productVerFileName = "/sys/class/dmi/id/product_version" biosVerFileName = "/sys/class/dmi/id/bios_vendor" systemdOSReleaseFileName = "/etc/os-release" amazon = "amazon" ) func init() { cloudinfo.RegisterCloudProvider(info.AWS, &provider{}) } type provider struct{} var _ cloudinfo.CloudProvider = provider{} func (provider) IsActiveProvider() bool { return fileContainsAmazonIdentifier(productVerFileName) || fileContainsAmazonIdentifier(biosVerFileName) || fileContainsAmazonIdentifier(systemdOSReleaseFileName) } func fileContainsAmazonIdentifier(filename string) bool { fileContent, err := os.ReadFile(filename) if err != nil { return false } return strings.Contains(string(fileContent), amazon) } func getAwsMetadata(name string) string { cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { return info.UnknownInstance } client := imds.NewFromConfig(cfg) data, err := client.GetMetadata(context.TODO(), &imds.GetMetadataInput{ Path: name, }) if err != nil { return info.UnknownInstance } raw, err := io.ReadAll(data.Content) if err != nil { return info.UnknownInstance } return string(raw) } func (provider) GetInstanceType() info.InstanceType { return info.InstanceType(getAwsMetadata("instance-type")) } func (provider) GetInstanceID() info.InstanceID { return info.InstanceID(getAwsMetadata("instance-id")) } ================================================ FILE: utils/cloudinfo/azure/azure.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cloudinfo import ( "os" "strings" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/utils/cloudinfo" ) const ( sysVendorFileName = "/sys/class/dmi/id/sys_vendor" biosUUIDFileName = "/sys/class/dmi/id/product_uuid" microsoftCorporation = "Microsoft Corporation" ) func init() { cloudinfo.RegisterCloudProvider(info.Azure, &provider{}) } type provider struct{} var _ cloudinfo.CloudProvider = provider{} func (provider) IsActiveProvider() bool { data, err := os.ReadFile(sysVendorFileName) if err != nil { return false } return strings.Contains(string(data), microsoftCorporation) } // TODO: Implement method. func (provider) GetInstanceType() info.InstanceType { return info.UnknownInstance } func (provider) GetInstanceID() info.InstanceID { data, err := os.ReadFile(biosUUIDFileName) if err != nil { return info.UnNamedInstance } return info.InstanceID(strings.TrimSuffix(string(data), "\n")) } ================================================ FILE: utils/cloudinfo/cloudinfo.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Get information about the cloud provider (if any) cAdvisor is running on. package cloudinfo import ( "k8s.io/klog/v2" info "github.com/google/cadvisor/info/v1" ) type CloudInfo interface { GetCloudProvider() info.CloudProvider GetInstanceType() info.InstanceType GetInstanceID() info.InstanceID } // CloudProvider is an abstraction for providing cloud-specific information. type CloudProvider interface { // IsActiveProvider determines whether this is the cloud provider operating // this instance. IsActiveProvider() bool // GetInstanceType gets the type of instance this process is running on. // The behavior is undefined if this is not the active provider. GetInstanceType() info.InstanceType // GetInstanceType gets the ID of the instance this process is running on. // The behavior is undefined if this is not the active provider. GetInstanceID() info.InstanceID } var providers = map[info.CloudProvider]CloudProvider{} // RegisterCloudProvider registers the given cloud provider func RegisterCloudProvider(name info.CloudProvider, provider CloudProvider) { if _, alreadyRegistered := providers[name]; alreadyRegistered { klog.Warningf("Duplicate registration of CloudProvider %s", name) } providers[name] = provider } type realCloudInfo struct { cloudProvider info.CloudProvider instanceType info.InstanceType instanceID info.InstanceID } func NewRealCloudInfo() CloudInfo { for name, provider := range providers { if provider.IsActiveProvider() { return &realCloudInfo{ cloudProvider: name, instanceType: provider.GetInstanceType(), instanceID: provider.GetInstanceID(), } } } // No registered active provider. return &realCloudInfo{ cloudProvider: info.UnknownProvider, instanceType: info.UnknownInstance, instanceID: info.UnNamedInstance, } } func (i *realCloudInfo) GetCloudProvider() info.CloudProvider { return i.cloudProvider } func (i *realCloudInfo) GetInstanceType() info.InstanceType { return i.instanceType } func (i *realCloudInfo) GetInstanceID() info.InstanceID { return i.instanceID } ================================================ FILE: utils/cloudinfo/gce/gce.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gce import ( "context" "os" "strings" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/utils/cloudinfo" "cloud.google.com/go/compute/metadata" ) const ( gceProductName = "/sys/class/dmi/id/product_name" google = "Google" ) func init() { cloudinfo.RegisterCloudProvider(info.GCE, &provider{}) } type provider struct{} var _ cloudinfo.CloudProvider = provider{} func (provider) IsActiveProvider() bool { data, err := os.ReadFile(gceProductName) if err != nil { return false } return strings.Contains(string(data), google) } func (provider) GetInstanceType() info.InstanceType { machineType, err := metadata.GetWithContext(context.TODO(), "instance/machine-type") if err != nil { return info.UnknownInstance } responseParts := strings.Split(machineType, "/") // Extract the instance name from the machine type. return info.InstanceType(responseParts[len(responseParts)-1]) } func (provider) GetInstanceID() info.InstanceID { instanceID, err := metadata.GetWithContext(context.TODO(), "instance/id") if err != nil { return info.UnknownInstance } return info.InstanceID(info.InstanceType(instanceID)) } ================================================ FILE: utils/container/container.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package container import ( info "github.com/google/cadvisor/info/v1" ) // Returns the alias a container is known by within a certain namespace, // if available. Otherwise returns the absolute name of the container. func GetPreferredName(ref info.ContainerReference) string { var containerName string if len(ref.Aliases) > 0 { containerName = ref.Aliases[0] } else { containerName = ref.Name } return containerName } ================================================ FILE: utils/cpuload/cpuload.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package cpuload import ( "fmt" info "github.com/google/cadvisor/info/v1" "k8s.io/klog/v2" "github.com/google/cadvisor/utils/cpuload/netlink" ) type CpuLoadReader interface { // Start the reader. Start() error // Stop the reader and clean up internal state. Stop() // Retrieve Cpu load for a given group. // name is the full hierarchical name of the container. // Path is an absolute filesystem path for a container under CPU cgroup hierarchy. GetCpuLoad(name string, path string) (info.LoadStats, error) } func New() (CpuLoadReader, error) { reader, err := netlink.New() if err != nil { return nil, fmt.Errorf("failed to create a netlink based cpuload reader: %v", err) } klog.V(4).Info("Using a netlink-based load reader") return reader, nil } ================================================ FILE: utils/cpuload/cpuload_unsupported.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build !linux package cpuload import ( "fmt" info "github.com/google/cadvisor/info/v1" ) type CpuLoadReader interface { // Start the reader. Start() error // Stop the reader and clean up internal state. Stop() // Retrieve Cpu load for a given group. // name is the full hierarchical name of the container. // Path is an absolute filesystem path for a container under CPU cgroup hierarchy. GetCpuLoad(name string, path string) (info.LoadStats, error) } func New() (CpuLoadReader, error) { return nil, fmt.Errorf("cpuload is not supported on this platform") } ================================================ FILE: utils/cpuload/netlink/conn.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package netlink import ( "bufio" "bytes" "encoding/binary" "os" "syscall" ) type Connection struct { // netlink socket fd int // cache pid to use in every netlink request. pid uint32 // sequence number for netlink messages. seq uint32 addr syscall.SockaddrNetlink rbuf *bufio.Reader } // Create and bind a new netlink socket. func newConnection() (*Connection, error) { fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM, syscall.NETLINK_GENERIC) if err != nil { return nil, err } conn := new(Connection) conn.fd = fd conn.seq = 0 conn.pid = uint32(os.Getpid()) conn.addr.Family = syscall.AF_NETLINK conn.rbuf = bufio.NewReader(conn) err = syscall.Bind(fd, &conn.addr) if err != nil { syscall.Close(fd) return nil, err } return conn, err } func (c *Connection) Read(b []byte) (n int, err error) { n, _, err = syscall.Recvfrom(c.fd, b, 0) return n, err } func (c *Connection) Write(b []byte) (n int, err error) { err = syscall.Sendto(c.fd, b, 0, &c.addr) return len(b), err } func (c *Connection) Close() error { return syscall.Close(c.fd) } func (c *Connection) WriteMessage(msg syscall.NetlinkMessage) error { w := bytes.NewBuffer(nil) msg.Header.Len = uint32(syscall.NLMSG_HDRLEN + len(msg.Data)) msg.Header.Seq = c.seq c.seq++ msg.Header.Pid = c.pid err := binary.Write(w, binary.LittleEndian, msg.Header) if err != nil { return err } _, err = w.Write(msg.Data) if err != nil { return err } _, err = c.Write(w.Bytes()) return err } func (c *Connection) ReadMessage() (msg syscall.NetlinkMessage, err error) { err = binary.Read(c.rbuf, binary.LittleEndian, &msg.Header) if err != nil { return msg, err } msg.Data = make([]byte, msg.Header.Len-syscall.NLMSG_HDRLEN) _, err = c.rbuf.Read(msg.Data) return msg, err } ================================================ FILE: utils/cpuload/netlink/example/example.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package main import ( "log" "github.com/google/cadvisor/utils/cpuload/netlink" ) func main() { n, err := netlink.New() if err != nil { log.Printf("Failed to create cpu load util: %s", err) return } defer n.Stop() paths := []string{"/sys/fs/cgroup/cpu", "/sys/fs/cgroup/cpu/docker"} names := []string{"/", "/docker"} for i, path := range paths { stats, err := n.GetCpuLoad(names[i], path) if err != nil { log.Printf("Error getting cpu load for %q: %s", path, err) } log.Printf("Task load for %s: %+v", path, stats) } } ================================================ FILE: utils/cpuload/netlink/netlink.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package netlink import ( "bytes" "encoding/binary" "fmt" "os" "syscall" "golang.org/x/sys/unix" info "github.com/google/cadvisor/info/v1" ) var ( // TODO(rjnagal): Verify and fix for other architectures. Endian = binary.LittleEndian ) type genMsghdr struct { Command uint8 Version uint8 Reserved uint16 } type netlinkMessage struct { Header syscall.NlMsghdr GenHeader genMsghdr Data []byte } func (m netlinkMessage) toRawMsg() (rawmsg syscall.NetlinkMessage) { rawmsg.Header = m.Header w := bytes.NewBuffer([]byte{}) _ = binary.Write(w, Endian, m.GenHeader) w.Write(m.Data) rawmsg.Data = w.Bytes() return rawmsg } type loadStatsResp struct { Header syscall.NlMsghdr GenHeader genMsghdr Stats info.LoadStats } // Return required padding to align 'size' to 'alignment'. func padding(size int, alignment int) int { unalignedPart := size % alignment return (alignment - unalignedPart) % alignment } // Get family id for taskstats subsystem. func getFamilyID(conn *Connection) (uint16, error) { msg := prepareFamilyMessage() err := conn.WriteMessage(msg.toRawMsg()) if err != nil { return 0, err } resp, err := conn.ReadMessage() if err != nil { return 0, err } id, err := parseFamilyResp(resp) if err != nil { return 0, err } return id, nil } // Append an attribute to the message. // Adds attribute info (length and type), followed by the data and necessary padding. // Can be called multiple times to add attributes. Only fixed size and string type // attributes are handled. We don't need nested attributes for task stats. func addAttribute(buf *bytes.Buffer, attrType uint16, data interface{}, dataSize int) { attr := syscall.RtAttr{ Len: syscall.SizeofRtAttr, Type: attrType, } attr.Len += uint16(dataSize) _ = binary.Write(buf, Endian, attr) switch data := data.(type) { case string: _ = binary.Write(buf, Endian, []byte(data)) buf.WriteByte(0) // terminate default: _ = binary.Write(buf, Endian, data) } for i := 0; i < padding(int(attr.Len), syscall.NLMSG_ALIGNTO); i++ { buf.WriteByte(0) } } // Prepares the message and generic headers and appends attributes as data. func prepareMessage(headerType uint16, cmd uint8, attributes []byte) (msg netlinkMessage) { msg.Header.Type = headerType msg.Header.Flags = syscall.NLM_F_REQUEST msg.GenHeader.Command = cmd msg.GenHeader.Version = 0x1 msg.Data = attributes return msg } // Prepares message to query family id for task stats. func prepareFamilyMessage() (msg netlinkMessage) { buf := bytes.NewBuffer([]byte{}) addAttribute(buf, unix.CTRL_ATTR_FAMILY_NAME, unix.TASKSTATS_GENL_NAME, len(unix.TASKSTATS_GENL_NAME)+1) return prepareMessage(unix.GENL_ID_CTRL, unix.CTRL_CMD_GETFAMILY, buf.Bytes()) } // Prepares message to query task stats for a task group. func prepareCmdMessage(id uint16, cfd uintptr) (msg netlinkMessage) { buf := bytes.NewBuffer([]byte{}) addAttribute(buf, unix.CGROUPSTATS_CMD_ATTR_FD, uint32(cfd), 4) return prepareMessage(id, unix.CGROUPSTATS_CMD_GET, buf.Bytes()) } // Extracts returned family id from the response. func parseFamilyResp(msg syscall.NetlinkMessage) (uint16, error) { m := new(netlinkMessage) m.Header = msg.Header err := verifyHeader(msg) if err != nil { return 0, err } buf := bytes.NewBuffer(msg.Data) // extract generic header from data. err = binary.Read(buf, Endian, &m.GenHeader) if err != nil { return 0, err } id := uint16(0) // Extract attributes. kernel reports family name, id, version, etc. // Scan till we find id. for buf.Len() > syscall.SizeofRtAttr { var attr syscall.RtAttr err = binary.Read(buf, Endian, &attr) if err != nil { return 0, err } if attr.Type == unix.CTRL_ATTR_FAMILY_ID { err = binary.Read(buf, Endian, &id) if err != nil { return 0, err } return id, nil } payload := int(attr.Len) - syscall.SizeofRtAttr skipLen := payload + padding(payload, syscall.SizeofRtAttr) name := make([]byte, skipLen) err = binary.Read(buf, Endian, name) if err != nil { return 0, err } } return 0, fmt.Errorf("family id not found in the response") } // Extract task stats from response returned by kernel. func parseLoadStatsResp(msg syscall.NetlinkMessage) (*loadStatsResp, error) { m := new(loadStatsResp) m.Header = msg.Header err := verifyHeader(msg) if err != nil { return m, err } buf := bytes.NewBuffer(msg.Data) // Scan the general header. err = binary.Read(buf, Endian, &m.GenHeader) if err != nil { return m, err } // cgroup stats response should have just one attribute. // Read it directly into the stats structure. var attr syscall.RtAttr err = binary.Read(buf, Endian, &attr) if err != nil { return m, err } err = binary.Read(buf, Endian, &m.Stats) if err != nil { return m, err } return m, err } // Verify and return any error reported by kernel. func verifyHeader(msg syscall.NetlinkMessage) error { switch msg.Header.Type { case syscall.NLMSG_DONE: return fmt.Errorf("expected a response, got nil") case syscall.NLMSG_ERROR: buf := bytes.NewBuffer(msg.Data) var errno int32 err := binary.Read(buf, Endian, errno) if err != nil { return err } return fmt.Errorf("netlink request failed with error %s", syscall.Errno(-errno)) } return nil } // Get load stats for a task group. // id: family id for taskstats. // cfd: open file to path to the cgroup directory under cpu hierarchy. // conn: open netlink connection used to communicate with kernel. func getLoadStats(id uint16, cfd *os.File, conn *Connection) (info.LoadStats, error) { msg := prepareCmdMessage(id, cfd.Fd()) err := conn.WriteMessage(msg.toRawMsg()) if err != nil { return info.LoadStats{}, err } resp, err := conn.ReadMessage() if err != nil { return info.LoadStats{}, err } parsedmsg, err := parseLoadStatsResp(resp) if err != nil { return info.LoadStats{}, err } return parsedmsg.Stats, nil } ================================================ FILE: utils/cpuload/netlink/reader.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package netlink import ( "fmt" "os" info "github.com/google/cadvisor/info/v1" "k8s.io/klog/v2" ) type NetlinkReader struct { familyID uint16 conn *Connection } func New() (*NetlinkReader, error) { conn, err := newConnection() if err != nil { return nil, fmt.Errorf("failed to create a new connection: %s", err) } id, err := getFamilyID(conn) if err != nil { return nil, fmt.Errorf("failed to get netlink family id for task stats: %s", err) } klog.V(4).Infof("Family id for taskstats: %d", id) return &NetlinkReader{ familyID: id, conn: conn, }, nil } func (r *NetlinkReader) Stop() { if r.conn != nil { r.conn.Close() } } func (r *NetlinkReader) Start() error { // We do the start setup for netlink in New(). Nothing to do here. return nil } // Returns instantaneous number of running tasks in a group. // Caller can use historical data to calculate cpu load. // path is an absolute filesystem path for a container under the CPU cgroup hierarchy. // NOTE: non-hierarchical load is returned. It does not include load for subcontainers. func (r *NetlinkReader) GetCpuLoad(name string, path string) (info.LoadStats, error) { if len(path) == 0 { return info.LoadStats{}, fmt.Errorf("cgroup path can not be empty") } cfd, err := os.Open(path) if err != nil { return info.LoadStats{}, fmt.Errorf("failed to open cgroup path %s: %q", path, err) } defer cfd.Close() stats, err := getLoadStats(r.familyID, cfd, r.conn) if err != nil { return info.LoadStats{}, err } klog.V(4).Infof("Task stats for %q: %+v", path, stats) return stats, nil } ================================================ FILE: utils/oomparser/oomexample/main.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package main import ( "flag" "k8s.io/klog/v2" "github.com/google/cadvisor/utils/oomparser" ) // demonstrates how to run oomparser.OomParser to get OomInstance information func main() { klog.InitFlags(nil) flag.Parse() // out is a user-provided channel from which the user can read incoming // OomInstance objects outStream := make(chan *oomparser.OomInstance) oomLog, err := oomparser.New() if err != nil { klog.Infof("Couldn't make a new oomparser. %v", err) } else { go oomLog.StreamOoms(outStream) // demonstration of how to get oomLog's list of oomInstances or access // the user-declared oomInstance channel, here called outStream for oomInstance := range outStream { klog.Infof("Reading the buffer. Output is %v", oomInstance) } } } ================================================ FILE: utils/oomparser/oomparser.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package oomparser import ( "path" "regexp" "strconv" "time" "github.com/euank/go-kmsg-parser/kmsgparser" "k8s.io/klog/v2" ) var ( legacyContainerRegexp = regexp.MustCompile(`Task in (.*) killed as a result of limit of (.*)`) // Starting in 5.0 linux kernels, the OOM message changed containerRegexp = regexp.MustCompile(`oom-kill:constraint=(.*),nodemask=(.*),cpuset=(.*),mems_allowed=(.*),oom_memcg=(.*),task_memcg=(.*),task=(.*),pid=(.*),uid=(.*)`) lastLineRegexp = regexp.MustCompile(`Killed process ([0-9]+) \((.+)\)`) firstLineRegexp = regexp.MustCompile(`invoked oom-killer:`) ) // OomParser wraps a kmsgparser in order to extract OOM events from the // individual kernel ring buffer messages. type OomParser struct { parser kmsgparser.Parser } // struct that contains information related to an OOM kill instance type OomInstance struct { // process id of the killed process Pid int // the name of the killed process ProcessName string // the time that the process was reported to be killed, // accurate to the minute TimeOfDeath time.Time // the absolute name of the container that OOMed ContainerName string // the absolute name of the container that was killed // due to the OOM. VictimContainerName string // the constraint that triggered the OOM. One of CONSTRAINT_NONE, // CONSTRAINT_CPUSET, CONSTRAINT_MEMORY_POLICY, CONSTRAINT_MEMCG Constraint string } // gets the container name from a line and adds it to the oomInstance. func getLegacyContainerName(line string, currentOomInstance *OomInstance) error { parsedLine := legacyContainerRegexp.FindStringSubmatch(line) if parsedLine == nil { return nil } currentOomInstance.ContainerName = path.Join("/", parsedLine[1]) currentOomInstance.VictimContainerName = path.Join("/", parsedLine[2]) return nil } // gets the container name from a line and adds it to the oomInstance. func getContainerName(line string, currentOomInstance *OomInstance) (bool, error) { parsedLine := containerRegexp.FindStringSubmatch(line) if parsedLine == nil { // Fall back to the legacy format if it isn't found here. return false, getLegacyContainerName(line, currentOomInstance) } currentOomInstance.ContainerName = parsedLine[6] currentOomInstance.VictimContainerName = parsedLine[5] currentOomInstance.Constraint = parsedLine[1] pid, err := strconv.Atoi(parsedLine[8]) if err != nil { return false, err } currentOomInstance.Pid = pid currentOomInstance.ProcessName = parsedLine[7] return true, nil } // gets the pid, name, and date from a line and adds it to oomInstance func getProcessNamePid(line string, currentOomInstance *OomInstance) (bool, error) { reList := lastLineRegexp.FindStringSubmatch(line) if reList == nil { return false, nil } pid, err := strconv.Atoi(reList[1]) if err != nil { return false, err } currentOomInstance.Pid = pid currentOomInstance.ProcessName = reList[2] return true, nil } // uses regex to see if line is the start of a kernel oom log func checkIfStartOfOomMessages(line string) bool { potentialOomStart := firstLineRegexp.MatchString(line) return potentialOomStart } // StreamOoms writes to a provided a stream of OomInstance objects representing // OOM events that are found in the logs. // It will block and should be called from a goroutine. func (p *OomParser) StreamOoms(outStream chan<- *OomInstance) { kmsgEntries := p.parser.Parse() defer p.parser.Close() for msg := range kmsgEntries { isOomMessage := checkIfStartOfOomMessages(msg.Message) if isOomMessage { oomCurrentInstance := &OomInstance{ ContainerName: "/", VictimContainerName: "/", TimeOfDeath: msg.Timestamp, } for msg := range kmsgEntries { finished, err := getContainerName(msg.Message, oomCurrentInstance) if err != nil { klog.Errorf("%v", err) } if !finished { finished, err = getProcessNamePid(msg.Message, oomCurrentInstance) if err != nil { klog.Errorf("%v", err) } } if finished { oomCurrentInstance.TimeOfDeath = msg.Timestamp break } } outStream <- oomCurrentInstance } } // Should not happen klog.Errorf("exiting analyzeLines. OOM events will not be reported.") } // initializes an OomParser object. Returns an OomParser object and an error. func New() (*OomParser, error) { parser, err := kmsgparser.NewParser() if err != nil { return nil, err } parser.SetLogger(glogAdapter{}) return &OomParser{parser: parser}, nil } type glogAdapter struct{} var _ kmsgparser.Logger = glogAdapter{} func (glogAdapter) Infof(format string, args ...interface{}) { klog.V(4).Infof(format, args...) } func (glogAdapter) Warningf(format string, args ...interface{}) { klog.V(2).Infof(format, args...) } func (glogAdapter) Errorf(format string, args ...interface{}) { klog.Warningf(format, args...) } ================================================ FILE: utils/oomparser/oomparser_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package oomparser import ( "fmt" "testing" "time" "github.com/euank/go-kmsg-parser/kmsgparser" "github.com/stretchr/testify/assert" ) const ( startLine = "ruby invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0" endLine = "Killed process 19667 (evil-program2) total-vm:1460016kB, anon-rss:1414008kB, file-rss:4kB" legacyContainerLine = "Task in /mem2 killed as a result of limit of /mem3" containerLine = "oom-kill:constraint=CONSTRAINT_MEMCG,nodemask=(null),cpuset=ef807430361e6e82b45db92e2e9b6fbec98f419b12c591e655c1a725565e73a8,mems_allowed=0,oom_memcg=/kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012,task_memcg=/kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012/ef807430361e6e82b45db92e2e9b6fbec98f419b12c591e655c1a725565e73a8,task=manager,pid=966,uid=0" ) func TestGetLegacyContainerName(t *testing.T) { currentOomInstance := new(OomInstance) finished, err := getContainerName(startLine, currentOomInstance) if err != nil { t.Errorf("bad line fed to getContainerName should yield no error, but had error %v", err) } if finished { t.Errorf("bad line fed to getContainerName should not result in a finished oom log, but it did") } if currentOomInstance.ContainerName != "" { t.Errorf("bad line fed to getContainerName yielded no container name but set it to %s", currentOomInstance.ContainerName) } finished, err = getContainerName(legacyContainerLine, currentOomInstance) if err != nil { t.Errorf("container line fed to getContainerName should yield no error, but had error %v", err) } if finished { t.Errorf("getContainerName with the legacy log line should not result in a finished oom log, but it did") } if currentOomInstance.ContainerName != "/mem2" { t.Errorf("getContainerName should have set containerName to /mem2, not %s", currentOomInstance.ContainerName) } if currentOomInstance.VictimContainerName != "/mem3" { t.Errorf("getContainerName should have set victimContainerName to /mem3, not %s", currentOomInstance.VictimContainerName) } } func TestGetContainerName(t *testing.T) { currentOomInstance := new(OomInstance) finished, err := getContainerName(startLine, currentOomInstance) if err != nil { t.Errorf("bad line fed to getContainerName should yield no error, but had error %v", err) } if finished { t.Errorf("bad line fed to getContainerName should not result in a finished oom log, but it did") } if currentOomInstance.ContainerName != "" { t.Errorf("bad line fed to getContainerName yielded no container name but set it to %s", currentOomInstance.ContainerName) } finished, err = getContainerName(containerLine, currentOomInstance) if err != nil { t.Errorf("container line fed to getContainerName should yield no error, but had error %v", err) } if !finished { t.Errorf("getContainerName with the complete log line should result in a finished oom log, but it did not") } if currentOomInstance.ContainerName != "/kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012/ef807430361e6e82b45db92e2e9b6fbec98f419b12c591e655c1a725565e73a8" { t.Errorf("getContainerName should have set containerName to /kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012/ef807430361e6e82b45db92e2e9b6fbec98f419b12c591e655c1a725565e73a8, not %s", currentOomInstance.ContainerName) } if currentOomInstance.VictimContainerName != "/kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012" { t.Errorf("getContainerName should have set victimContainerName to /kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012, not %s", currentOomInstance.VictimContainerName) } if currentOomInstance.Pid != 966 { t.Errorf("getContainerName should have set Pid to 966, not %d", currentOomInstance.Pid) } if currentOomInstance.ProcessName != "manager" { t.Errorf("getContainerName should have set ProcessName to manager, not %s", currentOomInstance.ProcessName) } if currentOomInstance.Constraint != "CONSTRAINT_MEMCG" { t.Errorf("getContainerName should have set ProcessName to CONSTRAINT_MEMCG, not %s", currentOomInstance.Constraint) } } func TestGetProcessNamePid(t *testing.T) { currentOomInstance := new(OomInstance) couldParseLine, err := getProcessNamePid(startLine, currentOomInstance) if err != nil { t.Errorf("bad line fed to getProcessNamePid should yield no error, but had error %v", err) } if couldParseLine { t.Errorf("bad line fed to getProcessNamePid should return false but returned %v", couldParseLine) } couldParseLine, err = getProcessNamePid(endLine, currentOomInstance) if err != nil { t.Errorf("good line fed to getProcessNamePid should yield no error, but had error %v", err) } if !couldParseLine { t.Errorf("good line fed to getProcessNamePid should return true but returned %v", couldParseLine) } if currentOomInstance.ProcessName != "evil-program2" { t.Errorf("getProcessNamePid should have set processName to evil-program2, not %s", currentOomInstance.ProcessName) } if currentOomInstance.Pid != 19667 { t.Errorf("getProcessNamePid should have set PID to 19667, not %d", currentOomInstance.Pid) } } func TestCheckIfStartOfMessages(t *testing.T) { couldParseLine := checkIfStartOfOomMessages(endLine) if couldParseLine { t.Errorf("bad line fed to checkIfStartOfMessages should return false but returned %v", couldParseLine) } couldParseLine = checkIfStartOfOomMessages(startLine) if !couldParseLine { t.Errorf("start line fed to checkIfStartOfMessages should return true but returned %v", couldParseLine) } } func TestLastLineRegex(t *testing.T) { processNames := []string{"foo", "python3.4", "foo-bar", "Plex Media Server", "x86_64-pc-linux-gnu-c++-5.4.0", "[", "()", `"with quotes"`} for _, name := range processNames { line := fmt.Sprintf("Jan 21 22:01:49 localhost kernel: [62279.421192] Killed process 1234 (%s) total-vm:1460016kB, anon-rss:1414008kB, file-rss:4kB", name) oomInfo := &OomInstance{} isPid, err := getProcessNamePid(line, oomInfo) assert.True(t, isPid) assert.NoError(t, err) assert.Equal(t, 1234, oomInfo.Pid) assert.Equal(t, name, oomInfo.ProcessName) } } func TestStreamOOMs(t *testing.T) { mockMsgs := make(chan kmsgparser.Message) p := &OomParser{ parser: &mockKmsgParser{ messages: mockMsgs, }, } oomsOut := make(chan *OomInstance) go func() { p.StreamOoms(oomsOut) }() writeAll := func(m []string, t time.Time) { for _, msg := range m { mockMsgs <- kmsgparser.Message{ Message: msg, Timestamp: t, } } } type in struct { msgs []string time time.Time } testTime := time.Unix(0xf331f4ee, 0) testTime2 := time.Unix(0xfa51f001, 0) testPairs := []struct { in []in out []*OomInstance }{ { in: []in{{ time: testTime, msgs: []string{ "memorymonster invoked oom-killer: gfp_mask=0xd0, order=0, oom_score_adj=0", "memorymonster cpuset=/ mems_allowed=0", "CPU: 5 PID: 13536 Comm: memorymonster Tainted: P OX 3.13.0-43-generic #72-Ubuntu", "Hardware name: Hewlett-Packard HP Z420 Workstation/1589, BIOS J61 v03.65 12/19/2013", " ffff88072ae10800 ffff8807a4835c48 ffffffff81720bf6 ffff8807a8e86000", " ffff8807a4835cd0 ffffffff8171b4b1 0000000000000246 ffff88072ae10800", " ffff8807a4835c90 ffff8807a4835ca0 ffffffff811522a7 0000000000000001", "Call Trace:", " [] dump_stack+0x45/0x56", " [] dump_header+0x7f/0x1f1", " [] ? find_lock_task_mm+0x27/0x70", " [] oom_kill_process+0x1ce/0x330", " [] ? security_capable_noaudit+0x15/0x20", " [] mem_cgroup_oom_synchronize+0x51c/0x560", " [] ? mem_cgroup_charge_common+0xa0/0xa0", " [] pagefault_out_of_memory+0x14/0x80", " [] mm_fault_error+0x8e/0x180", " [] __do_page_fault+0x4a1/0x560", " [] ? set_next_entity+0x95/0xb0", " [] ? __switch_to+0x169/0x4c0", " [] do_page_fault+0x1a/0x70", " [] page_fault+0x28/0x30", "Task in /mem2 killed as a result of limit of /mem2", "memory: usage 980kB, limit 980kB, failcnt 4152239", "memory+swap: usage 0kB, limit 18014398509481983kB, failcnt 0", "kmem: usage 0kB, limit 18014398509481983kB, failcnt 0", "Memory cgroup stats for /mem2: cache:0KB rss:980KB rss_huge:0KB mapped_file:0KB writeback:20KB inactive_anon:560KB active_anon:420KB inactive_file:0KB active_file:0KB unevictable:0KB", "[ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name", "[13536] 275858 13536 8389663 343 16267 8324326 0 memorymonster", "Memory cgroup out of memory: Kill process 13536 (memorymonster) score 996 or sacrifice child", "Killed process 13536 (memorymonster) total-vm:33558652kB, anon-rss:920kB, file-rss:452kB", }, }}, out: []*OomInstance{{ TimeOfDeath: testTime, ContainerName: "/mem2", ProcessName: "memorymonster", Pid: 13536, VictimContainerName: "/mem2", }}, }, { in: []in{{ time: testTime, msgs: []string{ "badsysprogram invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0", "badsysprogram cpuset=/ mems_allowed=0", "CPU: 0 PID: 1532 Comm: badsysprogram Not tainted 3.13.0-27-generic #50-Ubuntu", "Hardware name: Google Google, BIOS Google 01/01/2011", " 0000000000000000 ffff880069715a90 ffffffff817199c4 ffff8800680d8000", " ffff880069715b18 ffffffff817142ff 0000000000000000 0000000000000000", " 0000000000000000 0000000000000000 0000000000000000 0000000000000000", "Call Trace:", " [] dump_stack+0x45/0x56", " [] dump_header+0x7f/0x1f1", " [] oom_kill_process+0x1ce/0x330", " [] ? security_capable_noaudit+0x15/0x20", " [] out_of_memory+0x414/0x450", " [] __alloc_pages_nodemask+0xa87/0xb20", " [] alloc_pages_vma+0x9a/0x140", " [] handle_mm_fault+0xb2b/0xf10", " [] __do_page_fault+0x184/0x560", " [] ? sched_clock+0x9/0x10", " [] ? sched_clock_local+0x1d/0x80", " [] ? acct_account_cputime+0x1c/0x20", " [] ? account_user_time+0x8b/0xa0", " [] ? vtime_account_user+0x54/0x60", " [] do_page_fault+0x1a/0x70", " [] page_fault+0x28/0x30", "Mem-Info:", "Node 0 DMA per-cpu:", "CPU 0: hi: 0, btch: 1 usd: 0", "Node 0 DMA32 per-cpu:", "CPU 0: hi: 186, btch: 31 usd: 86", "active_anon:405991 inactive_anon:57 isolated_anon:0", " active_file:35 inactive_file:69 isolated_file:0", " unevictable:0 dirty:0 writeback:0 unstable:0", " free:12929 slab_reclaimable:1635 slab_unreclaimable:1919", " mapped:34 shmem:70 pagetables:1423 bounce:0", " free_cma:0", "Node 0 DMA free:7124kB min:412kB low:512kB high:616kB active_anon:8508kB inactive_anon:4kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:4kB slab_reclaimable:16kB slab_unreclaimable:16kB kernel_stack:0kB pagetables:12kB unstable:0kB bounce:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes", "lowmem_reserve[]: 0 1679 1679 1679", "Node 0 DMA32 free:44592kB min:44640kB low:55800kB high:66960kB active_anon:1615456kB inactive_anon:224kB active_file:140kB inactive_file:276kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:1765368kB managed:1722912kB mlocked:0kB dirty:0kB writeback:0kB mapped:136kB shmem:276kB slab_reclaimable:6524kB slab_unreclaimable:7660kB kernel_stack:592kB pagetables:5680kB unstable:0kB bounce:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:819 all_unreclaimable? yes", "lowmem_reserve[]: 0 0 0 0", "Node 0 DMA: 5*4kB (UM) 6*8kB (UEM) 7*16kB (UEM) 1*32kB (M) 2*64kB (UE) 3*128kB (UEM) 1*256kB (E) 2*512kB (EM) 3*1024kB (UEM) 1*2048kB (R) 0*4096kB = 7124kB", "Node 0 DMA32: 74*4kB (UEM) 125*8kB (UEM) 78*16kB (UEM) 26*32kB (UE) 12*64kB (UEM) 4*128kB (UE) 4*256kB (UE) 2*512kB (E) 11*1024kB (UE) 7*2048kB (UE) 3*4096kB (UR) = 44592kB", "Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB", "204 total pagecache pages", "0 pages in swap cache", "Swap cache stats: add 0, delete 0, find 0/0", "Free swap = 0kB", "Total swap = 0kB", "445340 pages RAM", "0 pages HighMem/MovableOnly", "10614 pages reserved", "[ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name", "[ 273] 0 273 4869 50 13 0 0 upstart-udev-br", "[ 293] 0 293 12802 154 28 0 -1000 systemd-udevd", "[ 321] 0 321 3819 54 12 0 0 upstart-file-br", "[ 326] 102 326 9805 109 24 0 0 dbus-daemon", "[ 334] 101 334 63960 94 26 0 0 rsyslogd", "[ 343] 0 343 10863 102 26 0 0 systemd-logind", "[ 546] 0 546 3815 60 13 0 0 upstart-socket-", "[ 710] 0 710 2556 587 8 0 0 dhclient", "[ 863] 0 863 3955 48 13 0 0 getty", "[ 865] 0 865 3955 50 13 0 0 getty", "[ 867] 0 867 3955 51 13 0 0 getty", "[ 868] 0 868 3955 51 12 0 0 getty", "[ 870] 0 870 3955 49 13 0 0 getty", "[ 915] 0 915 5914 61 16 0 0 cron", "[ 1015] 0 1015 10885 1524 25 0 0 manage_addresse", "[ 1028] 0 1028 3955 49 13 0 0 getty", "[ 1033] 0 1033 3197 48 12 0 0 getty", "[ 1264] 0 1264 11031 1635 26 0 0 manage_accounts", "[ 1268] 0 1268 15341 180 33 0 -1000 sshd", "[ 1313] 104 1313 6804 154 17 0 0 ntpd", "[ 1389] 0 1389 25889 255 55 0 0 sshd", "[ 1407] 1020 1407 25889 255 52 0 0 sshd", "[ 1408] 1020 1408 5711 581 17 0 0 bash", "[ 1425] 0 1425 25889 256 53 0 0 sshd", "[ 1443] 1020 1443 25889 257 52 0 0 sshd", "[ 1444] 1020 1444 5711 581 16 0 0 bash", "[ 1476] 1020 1476 1809 25 9 0 0 tail", "[ 1532] 1020 1532 410347 398810 788 0 0 badsysprogram", "Out of memory: Kill process 1532 (badsysprogram) score 919 or sacrifice child", "Killed process 1532 (badsysprogram) total-vm:1641388kB, anon-rss:1595164kB, file-rss:76kB", }, }}, out: []*OomInstance{{ Pid: 1532, ProcessName: "badsysprogram", TimeOfDeath: testTime, ContainerName: "/", VictimContainerName: "/", }}, }, { // Multiple OOMs // These were generated via `docker run -m 20M euank/gunpowder-memhog 2G; docker run -m 300M euank/gunpowder-memhog 800M` // followed by nabbing output from `/dev/kmsg` and stripping the syslog-ish prefixes `kmsgparser` will handle anyways. in: []in{ { time: testTime, msgs: []string{ "docker0: port 2(veth380a1cd) entered disabled state", "device veth380a1cd left promiscuous mode", "docker0: port 2(veth380a1cd) entered disabled state", "docker0: port 2(vethcd0dbfb) entered blocking state", "docker0: port 2(vethcd0dbfb) entered disabled state", "device vethcd0dbfb entered promiscuous mode", "IPv6: ADDRCONF(NETDEV_UP): vethcd0dbfb: link is not ready", "IPv6: ADDRCONF(NETDEV_CHANGE): vethcd0dbfb: link becomes ready", "docker0: port 2(vethcd0dbfb) entered blocking state", "docker0: port 2(vethcd0dbfb) entered forwarding state", "docker0: port 2(vethcd0dbfb) entered disabled state", "eth0: renamed from vethbcd01c4", "docker0: port 2(vethcd0dbfb) entered blocking state", "docker0: port 2(vethcd0dbfb) entered forwarding state", "gunpowder-memho invoked oom-killer: gfp_mask=0x24000c0(GFP_KERNEL), order=0, oom_score_adj=0", "gunpowder-memho cpuset=2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50 mems_allowed=0", "CPU: 0 PID: 1381 Comm: gunpowder-memho Tainted: G O 4.8.0-gentoo #2", "Hardware name: LENOVO 20BSCTO1WW/20BSCTO1WW, BIOS N14ET32W (1.10 ) 08/13/2015", " 0000000000000000 ffff8800968e3ca0 ffffffff8137ad47 ffff8800968e3d68", " ffff8800b74ee540 ffff8800968e3d00 ffffffff811261dd 0000000000000003", " 0000000000000000 0000000000000001 0000000000000246 0000000000000202", "Call Trace:", " [] dump_stack+0x4d/0x63", " [] dump_header+0x58/0x1c8", " [] oom_kill_process+0x7e/0x362", " [] ? mem_cgroup_iter+0x109/0x23e", " [] mem_cgroup_out_of_memory+0x241/0x299", " [] mem_cgroup_oom_synchronize+0x273/0x28c", " [] ? __mem_cgroup_insert_exceeded+0x76/0x76", " [] pagefault_out_of_memory+0x1f/0x76", " [] mm_fault_error+0x56/0x108", " [] __do_page_fault+0x36b/0x3ee", " [] do_page_fault+0xc/0xe", " [] page_fault+0x22/0x30", "Task in /docker/2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50 killed as a result of limit of /docker/2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50", "memory: usage 20480kB, limit 20480kB, failcnt 1204", "memory+swap: usage 40940kB, limit 40960kB, failcnt 6", "kmem: usage 220kB, limit 9007199254740988kB, failcnt 0", "Memory cgroup stats for /docker/2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50: cache:0KB rss:20260KB rss_huge:0KB mapped_file:0KB dirty:0KB writeback:1016KB swap:20460KB inactive_anon:10232KB active_anon:10028KB inactive_file:0KB active_file:0KB unevictable:0KB", "[ pid ] uid tgid total_vm rss nr_ptes nr_pmds swapents oom_score_adj name", "[ 1381] 0 1381 530382 5191 34 4 5489 0 gunpowder-memho", "Memory cgroup out of memory: Kill process 1381 (gunpowder-memho) score 1046 or sacrifice child", "Killed process 1381 (gunpowder-memho) total-vm:2121528kB, anon-rss:18624kB, file-rss:2140kB, shmem-rss:0kB", "oom_reaper: reaped process 1381 (gunpowder-memho), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB", "docker0: port 2(vethcd0dbfb) entered disabled state", "vethbcd01c4: renamed from eth0", "docker0: port 2(vethcd0dbfb) entered disabled state", "device vethcd0dbfb left promiscuous mode", "docker0: port 2(vethcd0dbfb) entered disabled state", "docker0: port 2(veth4cb51e1) entered blocking state", "docker0: port 2(veth4cb51e1) entered disabled state", "device veth4cb51e1 entered promiscuous mode", }, }, { time: testTime2, msgs: []string{ "IPv6: ADDRCONF(NETDEV_UP): veth4cb51e1: link is not ready", "docker0: port 2(veth4cb51e1) entered blocking state", "docker0: port 2(veth4cb51e1) entered forwarding state", "IPv6: ADDRCONF(NETDEV_CHANGE): veth4cb51e1: link becomes ready", "docker0: port 2(veth4cb51e1) entered disabled state", "eth0: renamed from veth4b89c12", "docker0: port 2(veth4cb51e1) entered blocking state", "docker0: port 2(veth4cb51e1) entered forwarding state", "gunpowder-memho invoked oom-killer: gfp_mask=0x24000c0(GFP_KERNEL), order=0, oom_score_adj=0", "gunpowder-memho cpuset=6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70 mems_allowed=0", "CPU: 0 PID: 1667 Comm: gunpowder-memho Tainted: G O 4.8.0-gentoo #2", "Hardware name: LENOVO 20BSCTO1WW/20BSCTO1WW, BIOS N14ET32W (1.10 ) 08/13/2015", " 0000000000000000 ffff88008137fca0 ffffffff8137ad47 ffff88008137fd68", " ffff8801c75b0c40 ffff88008137fd00 ffffffff811261dd 0000000000000003", " 0000000000000000 0000000000000001 0000000000000246 0000000000000202", "Call Trace:", " [] dump_stack+0x4d/0x63", " [] dump_header+0x58/0x1c8", " [] oom_kill_process+0x7e/0x362", " [] ? mem_cgroup_iter+0x109/0x23e", " [] mem_cgroup_out_of_memory+0x241/0x299", " [] mem_cgroup_oom_synchronize+0x273/0x28c", " [] ? __mem_cgroup_insert_exceeded+0x76/0x76", " [] pagefault_out_of_memory+0x1f/0x76", " [] mm_fault_error+0x56/0x108", " [] __do_page_fault+0x36b/0x3ee", " [] do_page_fault+0xc/0xe", " [] page_fault+0x22/0x30", "Task in /docker/6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70 killed as a result of limit of /docker/6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70", "memory: usage 307112kB, limit 307200kB, failcnt 35982", "memory+swap: usage 614400kB, limit 614400kB, failcnt 11", "kmem: usage 1308kB, limit 9007199254740988kB, failcnt 0", "Memory cgroup stats for /docker/6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70: cache:0KB rss:305804KB rss_huge:0KB mapped_file:0KB dirty:0KB writeback:55884KB swap:307288KB inactive_anon:152940KB active_anon:152832KB inactive_file:0KB active_file:0KB unevictable:0KB", "[ pid ] uid tgid total_vm rss nr_ptes nr_pmds swapents oom_score_adj name", "[ 1667] 0 1667 210894 62557 315 4 91187 0 gunpowder-memho", "Memory cgroup out of memory: Kill process 1667 (gunpowder-memho) score 1003 or sacrifice child", "Killed process 1667 (gunpowder-memho) total-vm:843576kB, anon-rss:248180kB, file-rss:2048kB, shmem-rss:0kB", "oom_reaper: reaped process 1667 (gunpowder-memho), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB", "docker0: port 2(veth4cb51e1) entered disabled state", "veth4b89c12: renamed from eth0", "docker0: port 2(veth4cb51e1) entered blocking state", "docker0: port 2(veth4cb51e1) entered forwarding state", "docker0: port 2(veth4cb51e1) entered disabled state", "device veth4cb51e1 left promiscuous mode", "docker0: port 2(veth4cb51e1) entered disabled state", }, }, }, out: []*OomInstance{ { Pid: 1381, ProcessName: "gunpowder-memho", TimeOfDeath: testTime, ContainerName: "/docker/2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50", VictimContainerName: "/docker/2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50", }, { Pid: 1667, ProcessName: "gunpowder-memho", TimeOfDeath: testTime2, ContainerName: "/docker/6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70", VictimContainerName: "/docker/6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70", }, }, }, } for _, pair := range testPairs { pair := pair go func() { for _, x := range pair.in { writeAll(x.msgs, x.time) } }() for _, expected := range pair.out { oom := <-oomsOut assert.Equal(t, expected, oom) } select { case oom := <-oomsOut: t.Errorf("did not expect any remaining OOMs, got %+v", oom) default: } } } type mockKmsgParser struct { messages chan kmsgparser.Message } func (m *mockKmsgParser) SeekEnd() error { return nil } func (m *mockKmsgParser) Parse() <-chan kmsgparser.Message { return m.messages } func (m *mockKmsgParser) SetLogger(kmsgparser.Logger) {} func (m *mockKmsgParser) Close() error { close(m.messages) return nil } ================================================ FILE: utils/path.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils import "os" func FileExists(file string) bool { if _, err := os.Stat(file); err != nil { return false } return true } ================================================ FILE: utils/sysfs/fakesysfs/fake.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package fakesysfs import ( "fmt" "os" "time" "github.com/google/cadvisor/utils/sysfs" ) // If we extend sysfs to support more interfaces, it might be worth making this a mock instead of a fake. type FileInfo struct { EntryName string } func (i *FileInfo) Name() string { return i.EntryName } func (i *FileInfo) Size() int64 { return 1234567 } func (i *FileInfo) Mode() os.FileMode { return 0 } func (i *FileInfo) ModTime() time.Time { return time.Time{} } func (i *FileInfo) IsDir() bool { return true } func (i *FileInfo) Sys() interface{} { return nil } type FakeSysFs struct { info FileInfo cache sysfs.CacheInfo nodesPaths []string nodePathErr error cpusPaths map[string][]string cpuPathErr error coreThread map[string]string coreIDErr map[string]error physicalPackageIDs map[string]string physicalPackageIDErr map[string]error bookIDs map[string]string bookIDErr map[string]error drawerIDs map[string]string drawerIDErr map[string]error memTotal string memErr error hugePages []os.FileInfo hugePagesErr error hugePagesNr map[string]string hugePagesNrErr error distances map[string]string distancesErr error onlineCPUs map[string]interface{} } func (fs *FakeSysFs) GetNodesPaths() ([]string, error) { return fs.nodesPaths, fs.nodePathErr } func (fs *FakeSysFs) GetCPUsPaths(cpusPath string) ([]string, error) { return fs.cpusPaths[cpusPath], fs.cpuPathErr } func (fs *FakeSysFs) GetCoreID(coreIDPath string) (string, error) { return fs.coreThread[coreIDPath], fs.coreIDErr[coreIDPath] } func (fs *FakeSysFs) GetCPUPhysicalPackageID(cpuPath string) (string, error) { return fs.physicalPackageIDs[cpuPath], fs.physicalPackageIDErr[cpuPath] } func (fs *FakeSysFs) GetBookID(coreIDPath string) (string, error) { return fs.bookIDs[coreIDPath], fs.bookIDErr[coreIDPath] } func (fs *FakeSysFs) GetDrawerID(coreIDPath string) (string, error) { return fs.drawerIDs[coreIDPath], fs.drawerIDErr[coreIDPath] } func (fs *FakeSysFs) GetMemInfo(nodePath string) (string, error) { return fs.memTotal, fs.memErr } func (fs *FakeSysFs) GetHugePagesInfo(hugepagesDirectory string) ([]os.FileInfo, error) { return fs.hugePages, fs.hugePagesErr } func (fs *FakeSysFs) GetHugePagesNr(hugepagesDirectory string, hugePageName string) (string, error) { hugePageFile := fmt.Sprintf("%s%s/%s", hugepagesDirectory, hugePageName, sysfs.HugePagesNrFile) return fs.hugePagesNr[hugePageFile], fs.hugePagesNrErr } func (fs *FakeSysFs) GetBlockDevices() ([]os.FileInfo, error) { fs.info.EntryName = "sda" return []os.FileInfo{&fs.info}, nil } func (fs *FakeSysFs) GetBlockDeviceSize(name string) (string, error) { return "1234567", nil } func (fs *FakeSysFs) GetBlockDeviceScheduler(name string) (string, error) { return "noop deadline [cfq]", nil } func (fs *FakeSysFs) GetBlockDeviceNumbers(name string) (string, error) { return "8:0\n", nil } func (fs *FakeSysFs) IsBlockDeviceHidden(name string) (bool, error) { return false, nil } func (fs *FakeSysFs) GetNetworkDevices() ([]os.FileInfo, error) { return []os.FileInfo{&fs.info}, nil } func (fs *FakeSysFs) GetNetworkAddress(name string) (string, error) { return "42:01:02:03:04:f4\n", nil } func (fs *FakeSysFs) GetNetworkMtu(name string) (string, error) { return "1024\n", nil } func (fs *FakeSysFs) GetNetworkSpeed(name string) (string, error) { return "1000\n", nil } func (fs *FakeSysFs) GetNetworkStatValue(name string, stat string) (uint64, error) { return 1024, nil } func (fs *FakeSysFs) GetCaches(id int) ([]os.FileInfo, error) { fs.info.EntryName = "index0" return []os.FileInfo{&fs.info}, nil } func (fs *FakeSysFs) GetCacheInfo(cpu int, cache string) (sysfs.CacheInfo, error) { return fs.cache, nil } func (fs *FakeSysFs) SetCacheInfo(cache sysfs.CacheInfo) { fs.cache = cache } func (fs *FakeSysFs) SetNodesPaths(paths []string, err error) { fs.nodesPaths = paths fs.nodePathErr = err } func (fs *FakeSysFs) SetCPUsPaths(paths map[string][]string, err error) { fs.cpusPaths = paths fs.cpuPathErr = err } func (fs *FakeSysFs) SetCoreThreads(coreThread map[string]string, coreThreadErrors map[string]error) { fs.coreThread = coreThread fs.coreIDErr = coreThreadErrors } func (fs *FakeSysFs) SetPhysicalPackageIDs(physicalPackageIDs map[string]string, physicalPackageIDErrors map[string]error) { fs.physicalPackageIDs = physicalPackageIDs fs.physicalPackageIDErr = physicalPackageIDErrors } func (fs *FakeSysFs) SetBookIDs(bookIDs map[string]string, bookIDErrors map[string]error) { fs.bookIDs = bookIDs fs.bookIDErr = bookIDErrors } func (fs *FakeSysFs) SetDrawerIDs(drawerIDs map[string]string, drawerIDErrors map[string]error) { fs.drawerIDs = drawerIDs fs.drawerIDErr = drawerIDErrors } func (fs *FakeSysFs) SetMemory(memTotal string, err error) { fs.memTotal = memTotal fs.memErr = err } func (fs *FakeSysFs) SetHugePages(hugePages []os.FileInfo, err error) { fs.hugePages = hugePages fs.hugePagesErr = err } func (fs *FakeSysFs) SetHugePagesNr(hugePagesNr map[string]string, err error) { fs.hugePagesNr = hugePagesNr fs.hugePagesNrErr = err } func (fs *FakeSysFs) SetEntryName(name string) { fs.info.EntryName = name } func (fs *FakeSysFs) GetSystemUUID() (string, error) { return "1F862619-BA9F-4526-8F85-ECEAF0C97430", nil } func (fs *FakeSysFs) GetDistances(nodeDir string) (string, error) { if fs.distancesErr != nil { return "", fs.distancesErr } if _, ok := fs.distances[nodeDir]; !ok { return "", fmt.Errorf("distance not found") } return fs.distances[nodeDir], nil } func (fs *FakeSysFs) SetDistances(nodeDir string, distances string, err error) { if fs.distances == nil { fs.distances = map[string]string{nodeDir: distances} } else { fs.distances[nodeDir] = distances } fs.distancesErr = err } func (fs *FakeSysFs) IsCPUOnline(dir string) bool { if fs.onlineCPUs == nil { return true } _, ok := fs.onlineCPUs[dir] return ok } func (fs *FakeSysFs) SetOnlineCPUs(online map[string]interface{}) { fs.onlineCPUs = online } ================================================ FILE: utils/sysfs/sysfs.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sysfs import ( "bytes" "fmt" "os" "path" "path/filepath" "regexp" "runtime" "strconv" "strings" "k8s.io/klog/v2" ) const ( blockDir = "/sys/block" cacheDir = "/sys/devices/system/cpu/cpu" netDir = "/sys/class/net" dmiDir = "/sys/class/dmi" ppcDevTree = "/proc/device-tree" s390xDevTree = "/etc" // s390/s390x changes meminfoFile = "meminfo" distanceFile = "distance" sysFsCPUTopology = "topology" // CPUPhysicalPackageID is a physical package id of cpu#. Typically corresponds to a physical socket number, // but the actual value is architecture and platform dependent. CPUPhysicalPackageID = "physical_package_id" // CPUCoreID is the CPU core ID of cpu#. Typically it is the hardware platform's identifier // (rather than the kernel's). The actual value is architecture and platform dependent. CPUCoreID = "core_id" // On some architecture there exists additional level of book and drawer id // CPUBookID is the book ID of cpu#. Typically corresponds to a physical book number. CPUBookID = "book_id" // CPUDrawerID is the drawer ID of cpu#. Typically corresponds to a physical drawer number. CPUDrawerID = "drawer_id" coreIDFilePath = "/" + sysFsCPUTopology + "/core_id" packageIDFilePath = "/" + sysFsCPUTopology + "/physical_package_id" bookIDFilePath = "/" + sysFsCPUTopology + "/book_id" drawerIDFilePath = "/" + sysFsCPUTopology + "/drawer_id" // memory size calculations cpuDirPattern = "cpu*[0-9]" nodeDirPattern = "node*[0-9]" //HugePagesNrFile name of nr_hugepages file in sysfs HugePagesNrFile = "nr_hugepages" ) var ( nodeDir = "/sys/devices/system/node/" ) type CacheInfo struct { // cache id Id int // size in bytes Size uint64 // cache type - instruction, data, unified Type string // distance from cpus in a multi-level hierarchy Level int // number of cpus that can access this cache. Cpus int } // Abstracts the lowest level calls to sysfs. type SysFs interface { // Get NUMA nodes paths GetNodesPaths() ([]string, error) // Get paths to CPUs in provided directory e.g. /sys/devices/system/node/node0 or /sys/devices/system/cpu GetCPUsPaths(cpusPath string) ([]string, error) // Get physical core id for specified CPU GetCoreID(coreIDFilePath string) (string, error) // Get physical package id for specified CPU GetCPUPhysicalPackageID(cpuPath string) (string, error) // Get book id for specified CPU GetBookID(cpuPath string) (string, error) // Get drawer id for specified CPU GetDrawerID(cpuPath string) (string, error) // Get total memory for specified NUMA node GetMemInfo(nodeDir string) (string, error) // Get hugepages from specified directory GetHugePagesInfo(hugePagesDirectory string) ([]os.FileInfo, error) // Get hugepage_nr from specified directory GetHugePagesNr(hugePagesDirectory string, hugePageName string) (string, error) // Get directory information for available block devices. GetBlockDevices() ([]os.FileInfo, error) // Get Size of a given block device. GetBlockDeviceSize(string) (string, error) // Get scheduler type for the block device. GetBlockDeviceScheduler(string) (string, error) // Get device major:minor number string. GetBlockDeviceNumbers(string) (string, error) // Is the device "hidden" (meaning will not have a device handle) // This is the case with native nvme multipathing. IsBlockDeviceHidden(string) (bool, error) GetNetworkDevices() ([]os.FileInfo, error) GetNetworkAddress(string) (string, error) GetNetworkMtu(string) (string, error) GetNetworkSpeed(string) (string, error) GetNetworkStatValue(dev string, stat string) (uint64, error) // Get directory information for available caches accessible to given cpu. GetCaches(id int) ([]os.FileInfo, error) // Get information for a cache accessible from the given cpu. GetCacheInfo(cpu int, cache string) (CacheInfo, error) GetSystemUUID() (string, error) // GetDistances returns distance array GetDistances(string) (string, error) // IsCPUOnline determines if CPU status from kernel hotplug machanism standpoint. // See: https://www.kernel.org/doc/html/latest/core-api/cpu_hotplug.html IsCPUOnline(dir string) bool } type realSysFs struct { cpuPath string } func NewRealSysFs() SysFs { return &realSysFs{ cpuPath: "/sys/devices/system/cpu", } } func (fs *realSysFs) GetNodesPaths() ([]string, error) { pathPattern := fmt.Sprintf("%s%s", nodeDir, nodeDirPattern) return filepath.Glob(pathPattern) } func (fs *realSysFs) GetCPUsPaths(cpusPath string) ([]string, error) { pathPattern := fmt.Sprintf("%s/%s", cpusPath, cpuDirPattern) return filepath.Glob(pathPattern) } func (fs *realSysFs) GetCoreID(cpuPath string) (string, error) { coreIDFilePath := fmt.Sprintf("%s%s", cpuPath, coreIDFilePath) coreID, err := os.ReadFile(coreIDFilePath) if err != nil { return "", err } return strings.TrimSpace(string(coreID)), err } func (fs *realSysFs) GetCPUPhysicalPackageID(cpuPath string) (string, error) { packageIDFilePath := fmt.Sprintf("%s%s", cpuPath, packageIDFilePath) packageID, err := os.ReadFile(packageIDFilePath) if err != nil { return "", err } return strings.TrimSpace(string(packageID)), err } func (fs *realSysFs) GetBookID(cpuPath string) (string, error) { bookIDFilePath := fmt.Sprintf("%s%s", cpuPath, bookIDFilePath) bookID, err := os.ReadFile(bookIDFilePath) if err != nil { return "", err } return strings.TrimSpace(string(bookID)), nil } func (fs *realSysFs) GetDrawerID(cpuPath string) (string, error) { drawerIDFilePath := fmt.Sprintf("%s%s", cpuPath, drawerIDFilePath) drawerID, err := os.ReadFile(drawerIDFilePath) if err != nil { return "", err } return strings.TrimSpace(string(drawerID)), nil } func (fs *realSysFs) GetMemInfo(nodePath string) (string, error) { meminfoPath := fmt.Sprintf("%s/%s", nodePath, meminfoFile) meminfo, err := os.ReadFile(meminfoPath) if err != nil { return "", err } return strings.TrimSpace(string(meminfo)), err } func (fs *realSysFs) GetDistances(nodePath string) (string, error) { distancePath := fmt.Sprintf("%s/%s", nodePath, distanceFile) distance, err := os.ReadFile(distancePath) if err != nil { return "", err } return strings.TrimSpace(string(distance)), err } func (fs *realSysFs) GetHugePagesInfo(hugePagesDirectory string) ([]os.FileInfo, error) { dirs, err := os.ReadDir(hugePagesDirectory) if err != nil { return nil, err } return toFileInfo(dirs) } func (fs *realSysFs) GetHugePagesNr(hugepagesDirectory string, hugePageName string) (string, error) { hugePageFilePath := fmt.Sprintf("%s%s/%s", hugepagesDirectory, hugePageName, HugePagesNrFile) hugePageFile, err := os.ReadFile(hugePageFilePath) if err != nil { return "", err } return strings.TrimSpace(string(hugePageFile)), err } func (fs *realSysFs) GetBlockDevices() ([]os.FileInfo, error) { dirs, err := os.ReadDir(blockDir) if err != nil { return nil, err } return toFileInfo(dirs) } func (fs *realSysFs) GetBlockDeviceNumbers(name string) (string, error) { dev, err := os.ReadFile(path.Join(blockDir, name, "/dev")) if err != nil { return "", err } return string(dev), nil } func (fs *realSysFs) IsBlockDeviceHidden(name string) (bool, error) { // See: https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-block // https://git.kernel.org/pub/scm/utils/util-linux/util-linux.git // - c8487d854ba5 ("lsblk: Ignore hidden devices") devHiddenPath := path.Join(blockDir, name, "/hidden") hidden, err := os.ReadFile(devHiddenPath) if err != nil && os.IsNotExist(err) { // older OS may not have /hidden sysfs entry, so for sure // it is not a hidden device... return false, nil } if err != nil { return false, fmt.Errorf("failed to read %s: %w", devHiddenPath, err) } return strings.TrimSpace(string(hidden)) == "1", nil } func (fs *realSysFs) GetBlockDeviceScheduler(name string) (string, error) { sched, err := os.ReadFile(path.Join(blockDir, name, "/queue/scheduler")) if err != nil { return "", err } return string(sched), nil } func (fs *realSysFs) GetBlockDeviceSize(name string) (string, error) { size, err := os.ReadFile(path.Join(blockDir, name, "/size")) if err != nil { return "", err } return string(size), nil } func (fs *realSysFs) GetNetworkDevices() ([]os.FileInfo, error) { dirs, err := os.ReadDir(netDir) if err != nil { return nil, err } files, err := toFileInfo(dirs) if err != nil { return nil, err } // Filter out non-directory & non-symlink files filtered := []os.FileInfo{} for _, f := range files { if f.Mode()|os.ModeSymlink != 0 { f, err = os.Stat(path.Join(netDir, f.Name())) if err != nil { continue } } if f.IsDir() { filtered = append(filtered, f) } } return filtered, nil } func (fs *realSysFs) GetNetworkAddress(name string) (string, error) { address, err := os.ReadFile(path.Join(netDir, name, "/address")) if err != nil { return "", err } return string(address), nil } func (fs *realSysFs) GetNetworkMtu(name string) (string, error) { mtu, err := os.ReadFile(path.Join(netDir, name, "/mtu")) if err != nil { return "", err } return string(mtu), nil } func (fs *realSysFs) GetNetworkSpeed(name string) (string, error) { speed, err := os.ReadFile(path.Join(netDir, name, "/speed")) if err != nil { return "", err } return string(speed), nil } func (fs *realSysFs) GetNetworkStatValue(dev string, stat string) (uint64, error) { statPath := path.Join(netDir, dev, "/statistics", stat) out, err := os.ReadFile(statPath) if err != nil { return 0, fmt.Errorf("failed to read stat from %q for device %q", statPath, dev) } var s uint64 n, err := fmt.Sscanf(string(out), "%d", &s) if err != nil || n != 1 { return 0, fmt.Errorf("could not parse value from %q for file %s", string(out), statPath) } return s, nil } func (fs *realSysFs) GetCaches(id int) ([]os.FileInfo, error) { cpuPath := fmt.Sprintf("%s%d/cache", cacheDir, id) dir, err := os.ReadDir(cpuPath) if err != nil { return nil, err } return toFileInfo(dir) } func toFileInfo(dirs []os.DirEntry) ([]os.FileInfo, error) { info := []os.FileInfo{} for _, dir := range dirs { fI, err := dir.Info() if err != nil { return nil, err } info = append(info, fI) } return info, nil } func bitCount(i uint64) (count int) { for i != 0 { if i&1 == 1 { count++ } i >>= 1 } return } func getCPUCount(cache string) (count int, err error) { out, err := os.ReadFile(path.Join(cache, "/shared_cpu_map")) if err != nil { return 0, err } masks := strings.Split(string(out), ",") for _, mask := range masks { // convert hex string to uint64 m, err := strconv.ParseUint(strings.TrimSpace(mask), 16, 64) if err != nil { return 0, fmt.Errorf("failed to parse cpu map %q: %v", string(out), err) } count += bitCount(m) } return } func (fs *realSysFs) GetCacheInfo(cpu int, name string) (CacheInfo, error) { cachePath := fmt.Sprintf("%s%d/cache/%s", cacheDir, cpu, name) var id int if runtime.GOARCH != "s390x" { out, err := os.ReadFile(path.Join(cachePath, "/id")) if err != nil { return CacheInfo{}, err } n, err := fmt.Sscanf(string(out), "%d", &id) if err != nil || n != 1 { return CacheInfo{}, err } } out, err := os.ReadFile(path.Join(cachePath, "/size")) if err != nil { return CacheInfo{}, err } var size uint64 n, err := fmt.Sscanf(string(out), "%dK", &size) if err != nil || n != 1 { return CacheInfo{}, err } // convert to bytes size = size * 1024 out, err = os.ReadFile(path.Join(cachePath, "/level")) if err != nil { return CacheInfo{}, err } var level int n, err = fmt.Sscanf(string(out), "%d", &level) if err != nil || n != 1 { return CacheInfo{}, err } out, err = os.ReadFile(path.Join(cachePath, "/type")) if err != nil { return CacheInfo{}, err } cacheType := strings.TrimSpace(string(out)) cpuCount, err := getCPUCount(cachePath) if err != nil { return CacheInfo{}, err } return CacheInfo{ Id: id, Size: size, Level: level, Type: cacheType, Cpus: cpuCount, }, nil } func (fs *realSysFs) GetSystemUUID() (string, error) { if id, err := os.ReadFile(path.Join(dmiDir, "id", "product_uuid")); err == nil { return strings.TrimSpace(string(id)), nil } else if id, err = os.ReadFile(path.Join(ppcDevTree, "system-id")); err == nil { return strings.TrimSpace(strings.TrimRight(string(id), "\000")), nil } else if id, err = os.ReadFile(path.Join(ppcDevTree, "vm,uuid")); err == nil { return strings.TrimSpace(strings.TrimRight(string(id), "\000")), nil } else if id, err = os.ReadFile(path.Join(s390xDevTree, "machine-id")); err == nil { return strings.TrimSpace(string(id)), nil } else { return "", err } } func (fs *realSysFs) IsCPUOnline(cpuPath string) bool { cpuOnlinePath, err := filepath.Abs(fs.cpuPath + "/online") if err != nil { klog.V(1).Infof("Unable to get absolute path for %s", cpuPath) return false } // Quick check to determine if file exists: if it does not then kernel CPU hotplug is disabled and all CPUs are online. _, err = os.Stat(cpuOnlinePath) if err != nil && os.IsNotExist(err) { return true } if err != nil { klog.V(1).Infof("Unable to stat %s: %s", cpuOnlinePath, err) } cpuID, err := getCPUID(cpuPath) if err != nil { klog.V(1).Infof("Unable to get CPU ID from path %s: %s", cpuPath, err) return false } isOnline, err := isCPUOnline(cpuOnlinePath, cpuID) if err != nil { klog.V(1).Infof("Unable to get online CPUs list: %s", err) return false } return isOnline } func getCPUID(dir string) (uint16, error) { regex := regexp.MustCompile("cpu([0-9]+)") matches := regex.FindStringSubmatch(dir) if len(matches) == 2 { id, err := strconv.Atoi(matches[1]) if err != nil { return 0, err } return uint16(id), nil } return 0, fmt.Errorf("can't get CPU ID from %s", dir) } // isCPUOnline is copied from github.com/opencontainers/runc/libcontainer/cgroups/fs and modified to suite cAdvisor // needs as Apache 2.0 license allows. // It parses CPU list (such as: 0,3-5,10) into a struct that allows to determine quickly if CPU or particular ID is online. // see: https://github.com/opencontainers/runc/blob/ab27e12cebf148aa5d1ee3ad13d9fc7ae12bf0b6/libcontainer/cgroups/fs/cpuset.go#L45 func isCPUOnline(path string, cpuID uint16) (bool, error) { fileContent, err := os.ReadFile(path) if err != nil { return false, err } if len(fileContent) == 0 { return false, fmt.Errorf("%s found to be empty", path) } cpuList := strings.TrimSpace(string(fileContent)) for _, s := range strings.Split(cpuList, ",") { splitted := strings.SplitN(s, "-", 3) switch len(splitted) { case 3: return false, fmt.Errorf("invalid values in %s", path) case 2: min, err := strconv.ParseUint(splitted[0], 10, 16) if err != nil { return false, err } max, err := strconv.ParseUint(splitted[1], 10, 16) if err != nil { return false, err } if min > max { return false, fmt.Errorf("invalid values in %s", path) } // Return true, if the CPU under consideration is in the range of online CPUs. if cpuID >= uint16(min) && cpuID <= uint16(max) { return true, nil } case 1: value, err := strconv.ParseUint(s, 10, 16) if err != nil { return false, err } if uint16(value) == cpuID { return true, nil } } } return false, nil } // Looks for sysfs cpu path containing given CPU property, e.g. core_id or physical_package_id // and returns number of unique values of given property, exemplary usage: getting number of CPU physical cores func GetUniqueCPUPropertyCount(cpuAttributesPath string, propertyName string) int { absCPUAttributesPath, err := filepath.Abs(cpuAttributesPath) if err != nil { klog.Errorf("Cannot make %s absolute", cpuAttributesPath) return 0 } pathPattern := absCPUAttributesPath + "/cpu*[0-9]" sysCPUPaths, err := filepath.Glob(pathPattern) if err != nil { klog.Errorf("Cannot find files matching pattern (pathPattern: %s), number of unique %s set to 0", pathPattern, propertyName) return 0 } cpuOnlinePath, err := filepath.Abs(cpuAttributesPath + "/online") if err != nil { klog.V(1).Infof("Unable to get absolute path for %s", cpuAttributesPath+"/../online") return 0 } if err != nil { klog.V(1).Infof("Unable to get online CPUs list: %s", err) return 0 } uniques := make(map[string]bool) for _, sysCPUPath := range sysCPUPaths { cpuID, err := getCPUID(sysCPUPath) if err != nil { klog.V(1).Infof("Unable to get CPU ID from path %s: %s", sysCPUPath, err) return 0 } isOnline, err := isCPUOnline(cpuOnlinePath, cpuID) if err != nil && !os.IsNotExist(err) { klog.V(1).Infof("Unable to determine CPU online state: %s", err) continue } if !isOnline && !os.IsNotExist(err) { continue } propertyPath := filepath.Join(sysCPUPath, sysFsCPUTopology, propertyName) propertyVal, err := os.ReadFile(propertyPath) if err != nil { klog.Warningf("Cannot open %s, assuming 0 for %s of CPU %d", propertyPath, propertyName, cpuID) propertyVal = []byte("0") } packagePath := filepath.Join(sysCPUPath, sysFsCPUTopology, CPUPhysicalPackageID) packageVal, err := os.ReadFile(packagePath) if err != nil { klog.Warningf("Cannot open %s, assuming 0 %s of CPU %d", packagePath, CPUPhysicalPackageID, cpuID) packageVal = []byte("0") } uniques[fmt.Sprintf("%s_%s", bytes.TrimSpace(propertyVal), bytes.TrimSpace(packageVal))] = true } return len(uniques) } ================================================ FILE: utils/sysfs/sysfs_notx86.go ================================================ //go:build !x86 // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sysfs var isX86 = false ================================================ FILE: utils/sysfs/sysfs_test.go ================================================ // Copyright 2020 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sysfs import ( "os" "strconv" "testing" "github.com/stretchr/testify/assert" ) func TestGetNodes(t *testing.T) { //overwrite global variable nodeDir = "./testdata/" sysFs := NewRealSysFs() nodesDirs, err := sysFs.GetNodesPaths() assert.Nil(t, err) assert.Equal(t, 2, len(nodesDirs)) assert.Contains(t, nodesDirs, "testdata/node0") assert.Contains(t, nodesDirs, "testdata/node1") } func TestGetNodesWithNonExistingDir(t *testing.T) { //overwrite global variable nodeDir = "./testdata/NonExistingDir/" sysFs := NewRealSysFs() nodesDirs, err := sysFs.GetNodesPaths() assert.Nil(t, err) assert.Equal(t, 0, len(nodesDirs)) } func TestGetCPUsPaths(t *testing.T) { sysFs := NewRealSysFs() cpuDirs, err := sysFs.GetCPUsPaths("./testdata/node0") assert.Nil(t, err) assert.Equal(t, 2, len(cpuDirs)) assert.Contains(t, cpuDirs, "testdata/node0/cpu0") assert.Contains(t, cpuDirs, "testdata/node0/cpu1") } func TestGetCPUsPathsFromNodeWithoutCPU(t *testing.T) { sysFs := NewRealSysFs() cpuDirs, err := sysFs.GetCPUsPaths("./testdata/node1") assert.Nil(t, err) assert.Equal(t, 0, len(cpuDirs)) } func TestGetCoreID(t *testing.T) { sysFs := NewRealSysFs() rawCoreID, err := sysFs.GetCoreID("./testdata/node0/cpu0") assert.Nil(t, err) coreID, err := strconv.Atoi(rawCoreID) assert.Nil(t, err) assert.Equal(t, 0, coreID) } func TestGetCoreIDWhenFileIsMissing(t *testing.T) { sysFs := NewRealSysFs() rawCoreID, err := sysFs.GetCoreID("./testdata/node0/cpu1") assert.NotNil(t, err) assert.Equal(t, "", rawCoreID) } func TestGetMemInfo(t *testing.T) { sysFs := NewRealSysFs() memInfo, err := sysFs.GetMemInfo("./testdata/node0") assert.Nil(t, err) assert.Equal(t, "Node 0 MemTotal: 32817192 kB", memInfo) } func TestGetMemInfoWhenFileIsMissing(t *testing.T) { sysFs := NewRealSysFs() memInfo, err := sysFs.GetMemInfo("./testdata/node1") assert.NotNil(t, err) assert.Equal(t, "", memInfo) } func TestGetHugePagesInfo(t *testing.T) { sysFs := NewRealSysFs() hugePages, err := sysFs.GetHugePagesInfo("./testdata/node0/hugepages") assert.Nil(t, err) assert.Equal(t, 2, len(hugePages)) assert.Equal(t, "hugepages-1048576kB", hugePages[0].Name()) assert.Equal(t, "hugepages-2048kB", hugePages[1].Name()) } func TestGetHugePagesInfoWhenDirIsMissing(t *testing.T) { sysFs := NewRealSysFs() hugePages, err := sysFs.GetHugePagesInfo("./testdata/node1/hugepages") assert.NotNil(t, err) assert.Equal(t, []os.FileInfo([]os.FileInfo(nil)), hugePages) } func TestGetHugePagesNr(t *testing.T) { sysFs := NewRealSysFs() rawHugePageNr, err := sysFs.GetHugePagesNr("./testdata/node0/hugepages/", "hugepages-1048576kB") assert.Nil(t, err) hugePageNr, err := strconv.Atoi(rawHugePageNr) assert.Nil(t, err) assert.Equal(t, 1, hugePageNr) } func TestGetHugePagesNrWhenFileIsMissing(t *testing.T) { sysFs := NewRealSysFs() rawHugePageNr, err := sysFs.GetHugePagesNr("./testdata/node1/hugepages/", "hugepages-1048576kB") assert.NotNil(t, err) assert.Equal(t, "", rawHugePageNr) } func TestIsCPUOnline(t *testing.T) { sysFs := &realSysFs{ cpuPath: "./testdata_epyc7402_nohyperthreading", } online := sysFs.IsCPUOnline("./testdata_epyc7402_nohyperthreading/cpu14") assert.True(t, online) online = sysFs.IsCPUOnline("./testdata_epyc7402_nohyperthreading/cpu13") assert.False(t, online) } func TestIsCPUOnlineNoFileAndCPU0MustBeOnline(t *testing.T) { // Test on x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = false sysFs := &realSysFs{ cpuPath: "./testdata/missing_online/node0", } online := sysFs.IsCPUOnline("./testdata/missing_online/node0/cpu33") assert.True(t, online) } func TestIsCPU0OnlineOnx86(t *testing.T) { // Test on x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = true sysFs := NewRealSysFs() online := sysFs.IsCPUOnline("path/is/irrelevant/it/is/zero/that/matters/cpu0") assert.True(t, online) } func TestCPU0OfflineOnNotx86(t *testing.T) { // Test on arch other than x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = false sysFs := &realSysFs{ cpuPath: "./testdata_graviton2", } online := sysFs.IsCPUOnline("./testdata_graviton2/cpu0") assert.False(t, online) } func TestIsCpuOnlineRaspberryPi4(t *testing.T) { // Test on arch other than x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = false sysFS := &realSysFs{ cpuPath: "./testdata_rpi4", } online := sysFS.IsCPUOnline("./testdata_rpi4/cpu0") assert.True(t, online) online = sysFS.IsCPUOnline("./testdata_rpi4/cpu1") assert.True(t, online) online = sysFS.IsCPUOnline("./testdata_rpi4/cpu2") assert.True(t, online) online = sysFS.IsCPUOnline("./testdata_rpi4/cpu3") assert.True(t, online) } func TestIsCpuOnlineGraviton2(t *testing.T) { // Test on arch other than x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = false sysFS := &realSysFs{ cpuPath: "./testdata_graviton2", } online := sysFS.IsCPUOnline("./testdata_graviton2/cpu0") assert.False(t, online) online = sysFS.IsCPUOnline("./testdata_graviton2/cpu1") assert.True(t, online) online = sysFS.IsCPUOnline("./testdata_graviton2/cpu2") assert.True(t, online) online = sysFS.IsCPUOnline("./testdata_graviton2/cpu3") assert.True(t, online) } func TestGetUniqueCPUPropertyCountOnRaspberryPi4(t *testing.T) { // Test on arch other than x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = false count := GetUniqueCPUPropertyCount("./testdata_rpi4/", CPUPhysicalPackageID) assert.Equal(t, 1, count) count = GetUniqueCPUPropertyCount("./testdata_rpi4/", CPUCoreID) assert.Equal(t, 4, count) } func TestGetUniqueCPUPropertyCountOnEpyc7402(t *testing.T) { // Test on x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = true count := GetUniqueCPUPropertyCount("./testdata_epyc7402/", CPUPhysicalPackageID) assert.Equal(t, 1, count) count = GetUniqueCPUPropertyCount("./testdata_epyc7402/", CPUCoreID) assert.Equal(t, 24, count) } func TestGetUniqueCPUPropertyCountOnEpyc7402NoHyperThreading(t *testing.T) { // Test on x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = true count := GetUniqueCPUPropertyCount("./testdata_epyc7402_nohyperthreading/", CPUPhysicalPackageID) assert.Equal(t, 1, count) count = GetUniqueCPUPropertyCount("./testdata_epyc7402_nohyperthreading/", CPUCoreID) assert.Equal(t, 17, count) } func TestGetUniqueCPUPropertyCountOnXeon4214(t *testing.T) { // Test on x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = true count := GetUniqueCPUPropertyCount("./testdata_xeon4214_2socket/", CPUPhysicalPackageID) assert.Equal(t, 2, count) count = GetUniqueCPUPropertyCount("./testdata_xeon4214_2socket/", CPUCoreID) assert.Equal(t, 24, count) } func TestGetUniqueCPUPropertyCountOnXeon5218NoHyperThreadingNoHotplug(t *testing.T) { // Test on x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = true count := GetUniqueCPUPropertyCount("./testdata_xeon5218_nohyperthread_2socket_nohotplug/", CPUPhysicalPackageID) assert.Equal(t, 2, count) count = GetUniqueCPUPropertyCount("./testdata_xeon5218_nohyperthread_2socket_nohotplug/", CPUCoreID) assert.Equal(t, 32, count) } func TestUniqueCPUPropertyOnSingleSocketMultipleNUMAsSystem(t *testing.T) { // Test on x86. origIsX86 := isX86 defer func() { isX86 = origIsX86 }() isX86 = true count := GetUniqueCPUPropertyCount("./testdata_single_socket_many_NUMAs/", CPUPhysicalPackageID) assert.Equal(t, 16, count) count = GetUniqueCPUPropertyCount("./testdata_single_socket_many_NUMAs/", CPUCoreID) assert.Equal(t, 16, count) } func TestGetDistances(t *testing.T) { sysFs := NewRealSysFs() distances, err := sysFs.GetDistances("./testdata/node0") assert.Nil(t, err) assert.Equal(t, "10 11", distances) } func TestGetDistancesFileIsMissing(t *testing.T) { sysFs := NewRealSysFs() distances, err := sysFs.GetDistances("./testdata/node1") assert.NotNil(t, err) assert.Equal(t, "", distances) } ================================================ FILE: utils/sysfs/sysfs_x86.go ================================================ //go:build x86 // Copyright 2021 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sysfs var isX86 = true ================================================ FILE: utils/sysfs/testdata/edac/mc/mc0/dimm0/dimm_mem_type ================================================ Unbuffered-DDR4 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc0/dimm0/size ================================================ 789 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc0/dimm1/dimm_mem_type ================================================ Non-volatile-RAM ================================================ FILE: utils/sysfs/testdata/edac/mc/mc0/dimm1/size ================================================ 456 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc0/dimm_is_fake/dimm_mem_type ================================================ Unbuffered-DDR4 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc0/dimm_is_fake/size ================================================ 321 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc1/dimm0/dimm_mem_type ================================================ Non-volatile-RAM ================================================ FILE: utils/sysfs/testdata/edac/mc/mc1/dimm0/size ================================================ 123 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc_fake/dimm0/dimm0/dimm_mem_type ================================================ Unbuffered-DDR4 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc_fake/dimm0/dimm0/size ================================================ 789 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc_fake/dimm0/dimm1/dimm_mem_type ================================================ Non-volatile-RAM ================================================ FILE: utils/sysfs/testdata/edac/mc/mc_fake/dimm0/dimm1/size ================================================ 456 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc_fake/dimm0/dimm_mem_type ================================================ Unbuffered-DDR4 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc_fake/dimm0/size ================================================ 789 ================================================ FILE: utils/sysfs/testdata/edac/mc/mc_fake/dimm1/dimm_mem_type ================================================ Non-volatile-RAM ================================================ FILE: utils/sysfs/testdata/edac/mc/mc_fake/dimm1/size ================================================ 456 ================================================ FILE: utils/sysfs/testdata/missing_online/node0/cpu0/.gitkeep ================================================ ================================================ FILE: utils/sysfs/testdata/missing_online/node0/cpu33/.gitkeep ================================================ ================================================ FILE: utils/sysfs/testdata/node0/cpu0/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata/node0/cpu1/topology/.gitkeep ================================================ ================================================ FILE: utils/sysfs/testdata/node0/distance ================================================ 10 11 ================================================ FILE: utils/sysfs/testdata/node0/hugepages/hugepages-1048576kB/nr_hugepages ================================================ 1 ================================================ FILE: utils/sysfs/testdata/node0/hugepages/hugepages-2048kB/nr_hugepages ================================================ 2 ================================================ FILE: utils/sysfs/testdata/node0/meminfo ================================================ Node 0 MemTotal: 32817192 kB ================================================ FILE: utils/sysfs/testdata/node1/.gitkeep ================================================ ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/core_cpus ================================================ 0000,01000001 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/core_cpus_list ================================================ 0,24 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/thread_siblings ================================================ 0000,01000001 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu0/topology/thread_siblings_list ================================================ 0,24 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/core_cpus ================================================ 0000,02000002 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/core_cpus_list ================================================ 1,25 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/thread_siblings ================================================ 0000,02000002 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu1/topology/thread_siblings_list ================================================ 1,25 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/core_cpus ================================================ 0004,00000400 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/core_cpus_list ================================================ 10,34 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/core_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/thread_siblings ================================================ 0004,00000400 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu10/topology/thread_siblings_list ================================================ 10,34 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/core_cpus ================================================ 0008,00000800 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/core_cpus_list ================================================ 11,35 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/core_id ================================================ 14 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/thread_siblings ================================================ 0008,00000800 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu11/topology/thread_siblings_list ================================================ 11,35 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/core_cpus ================================================ 0010,00001000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/core_cpus_list ================================================ 12,36 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/core_id ================================================ 16 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/thread_siblings ================================================ 0010,00001000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu12/topology/thread_siblings_list ================================================ 12,36 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/core_cpus ================================================ 0020,00002000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/core_cpus_list ================================================ 13,37 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/core_id ================================================ 17 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/thread_siblings ================================================ 0020,00002000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu13/topology/thread_siblings_list ================================================ 13,37 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/core_cpus ================================================ 0040,00004000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/core_cpus_list ================================================ 14,38 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/core_id ================================================ 18 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/thread_siblings ================================================ 0040,00004000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu14/topology/thread_siblings_list ================================================ 14,38 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/core_cpus ================================================ 0080,00008000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/core_cpus_list ================================================ 15,39 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/core_id ================================================ 20 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/thread_siblings ================================================ 0080,00008000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu15/topology/thread_siblings_list ================================================ 15,39 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/core_cpus ================================================ 0100,00010000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/core_cpus_list ================================================ 16,40 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/core_id ================================================ 21 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/thread_siblings ================================================ 0100,00010000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu16/topology/thread_siblings_list ================================================ 16,40 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/core_cpus ================================================ 0200,00020000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/core_cpus_list ================================================ 17,41 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/core_id ================================================ 22 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/thread_siblings ================================================ 0200,00020000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu17/topology/thread_siblings_list ================================================ 17,41 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/core_cpus ================================================ 0400,00040000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/core_cpus_list ================================================ 18,42 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/core_id ================================================ 24 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/thread_siblings ================================================ 0400,00040000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu18/topology/thread_siblings_list ================================================ 18,42 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/core_cpus ================================================ 0800,00080000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/core_cpus_list ================================================ 19,43 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/core_id ================================================ 25 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/thread_siblings ================================================ 0800,00080000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu19/topology/thread_siblings_list ================================================ 19,43 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/core_cpus ================================================ 0000,04000004 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/core_cpus_list ================================================ 2,26 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/core_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/thread_siblings ================================================ 0000,04000004 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu2/topology/thread_siblings_list ================================================ 2,26 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/core_cpus ================================================ 1000,00100000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/core_cpus_list ================================================ 20,44 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/core_id ================================================ 26 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/thread_siblings ================================================ 1000,00100000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu20/topology/thread_siblings_list ================================================ 20,44 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/core_cpus ================================================ 2000,00200000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/core_cpus_list ================================================ 21,45 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/core_id ================================================ 28 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/thread_siblings ================================================ 2000,00200000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu21/topology/thread_siblings_list ================================================ 21,45 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/core_cpus ================================================ 4000,00400000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/core_cpus_list ================================================ 22,46 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/core_id ================================================ 29 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/thread_siblings ================================================ 4000,00400000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu22/topology/thread_siblings_list ================================================ 22,46 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/core_cpus ================================================ 8000,00800000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/core_cpus_list ================================================ 23,47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/core_id ================================================ 30 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/thread_siblings ================================================ 8000,00800000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu23/topology/thread_siblings_list ================================================ 23,47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/core_cpus ================================================ 0000,01000001 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/core_cpus_list ================================================ 0,24 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/thread_siblings ================================================ 0000,01000001 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu24/topology/thread_siblings_list ================================================ 0,24 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/core_cpus ================================================ 0000,02000002 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/core_cpus_list ================================================ 1,25 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/thread_siblings ================================================ 0000,02000002 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu25/topology/thread_siblings_list ================================================ 1,25 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/core_cpus ================================================ 0000,04000004 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/core_cpus_list ================================================ 2,26 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/core_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/thread_siblings ================================================ 0000,04000004 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu26/topology/thread_siblings_list ================================================ 2,26 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/core_cpus ================================================ 0000,08000008 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/core_cpus_list ================================================ 3,27 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/core_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/thread_siblings ================================================ 0000,08000008 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu27/topology/thread_siblings_list ================================================ 3,27 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/core_cpus ================================================ 0000,10000010 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/core_cpus_list ================================================ 4,28 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/core_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/thread_siblings ================================================ 0000,10000010 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu28/topology/thread_siblings_list ================================================ 4,28 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/core_cpus ================================================ 0000,20000020 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/core_cpus_list ================================================ 5,29 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/core_id ================================================ 6 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/thread_siblings ================================================ 0000,20000020 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu29/topology/thread_siblings_list ================================================ 5,29 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/core_cpus ================================================ 0000,08000008 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/core_cpus_list ================================================ 3,27 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/core_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/thread_siblings ================================================ 0000,08000008 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu3/topology/thread_siblings_list ================================================ 3,27 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/core_cpus ================================================ 0000,40000040 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/core_cpus_list ================================================ 6,30 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/core_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/thread_siblings ================================================ 0000,40000040 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu30/topology/thread_siblings_list ================================================ 6,30 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/core_cpus ================================================ 0000,80000080 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/core_cpus_list ================================================ 7,31 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/core_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/thread_siblings ================================================ 0000,80000080 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu31/topology/thread_siblings_list ================================================ 7,31 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/core_cpus ================================================ 0001,00000100 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/core_cpus_list ================================================ 8,32 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/core_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/thread_siblings ================================================ 0001,00000100 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu32/topology/thread_siblings_list ================================================ 8,32 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/core_cpus ================================================ 0002,00000200 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/core_cpus_list ================================================ 9,33 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/core_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/thread_siblings ================================================ 0002,00000200 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu33/topology/thread_siblings_list ================================================ 9,33 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/core_cpus ================================================ 0004,00000400 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/core_cpus_list ================================================ 10,34 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/core_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/thread_siblings ================================================ 0004,00000400 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu34/topology/thread_siblings_list ================================================ 10,34 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/core_cpus ================================================ 0008,00000800 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/core_cpus_list ================================================ 11,35 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/core_id ================================================ 14 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/thread_siblings ================================================ 0008,00000800 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu35/topology/thread_siblings_list ================================================ 11,35 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/core_cpus ================================================ 0010,00001000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/core_cpus_list ================================================ 12,36 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/core_id ================================================ 16 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/thread_siblings ================================================ 0010,00001000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu36/topology/thread_siblings_list ================================================ 12,36 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/core_cpus ================================================ 0020,00002000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/core_cpus_list ================================================ 13,37 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/core_id ================================================ 17 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/thread_siblings ================================================ 0020,00002000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu37/topology/thread_siblings_list ================================================ 13,37 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/core_cpus ================================================ 0040,00004000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/core_cpus_list ================================================ 14,38 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/core_id ================================================ 18 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/thread_siblings ================================================ 0040,00004000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu38/topology/thread_siblings_list ================================================ 14,38 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/core_cpus ================================================ 0080,00008000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/core_cpus_list ================================================ 15,39 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/core_id ================================================ 20 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/thread_siblings ================================================ 0080,00008000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu39/topology/thread_siblings_list ================================================ 15,39 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/core_cpus ================================================ 0000,10000010 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/core_cpus_list ================================================ 4,28 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/core_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/thread_siblings ================================================ 0000,10000010 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu4/topology/thread_siblings_list ================================================ 4,28 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/core_cpus ================================================ 0100,00010000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/core_cpus_list ================================================ 16,40 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/core_id ================================================ 21 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/thread_siblings ================================================ 0100,00010000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu40/topology/thread_siblings_list ================================================ 16,40 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/core_cpus ================================================ 0200,00020000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/core_cpus_list ================================================ 17,41 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/core_id ================================================ 22 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/thread_siblings ================================================ 0200,00020000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu41/topology/thread_siblings_list ================================================ 17,41 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/core_cpus ================================================ 0400,00040000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/core_cpus_list ================================================ 18,42 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/core_id ================================================ 24 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/thread_siblings ================================================ 0400,00040000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu42/topology/thread_siblings_list ================================================ 18,42 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/core_cpus ================================================ 0800,00080000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/core_cpus_list ================================================ 19,43 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/core_id ================================================ 25 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/thread_siblings ================================================ 0800,00080000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu43/topology/thread_siblings_list ================================================ 19,43 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/core_cpus ================================================ 1000,00100000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/core_cpus_list ================================================ 20,44 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/core_id ================================================ 26 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/thread_siblings ================================================ 1000,00100000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu44/topology/thread_siblings_list ================================================ 20,44 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/core_cpus ================================================ 2000,00200000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/core_cpus_list ================================================ 21,45 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/core_id ================================================ 28 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/thread_siblings ================================================ 2000,00200000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu45/topology/thread_siblings_list ================================================ 21,45 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/core_cpus ================================================ 4000,00400000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/core_cpus_list ================================================ 22,46 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/core_id ================================================ 29 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/thread_siblings ================================================ 4000,00400000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu46/topology/thread_siblings_list ================================================ 22,46 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/core_cpus ================================================ 8000,00800000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/core_cpus_list ================================================ 23,47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/core_id ================================================ 30 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/thread_siblings ================================================ 8000,00800000 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu47/topology/thread_siblings_list ================================================ 23,47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/core_cpus ================================================ 0000,20000020 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/core_cpus_list ================================================ 5,29 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/core_id ================================================ 6 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/thread_siblings ================================================ 0000,20000020 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu5/topology/thread_siblings_list ================================================ 5,29 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/core_cpus ================================================ 0000,40000040 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/core_cpus_list ================================================ 6,30 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/core_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/thread_siblings ================================================ 0000,40000040 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu6/topology/thread_siblings_list ================================================ 6,30 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/core_cpus ================================================ 0000,80000080 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/core_cpus_list ================================================ 7,31 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/core_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/thread_siblings ================================================ 0000,80000080 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu7/topology/thread_siblings_list ================================================ 7,31 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/core_cpus ================================================ 0001,00000100 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/core_cpus_list ================================================ 8,32 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/core_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/thread_siblings ================================================ 0001,00000100 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu8/topology/thread_siblings_list ================================================ 8,32 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/core_cpus ================================================ 0002,00000200 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/core_cpus_list ================================================ 9,33 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/core_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/core_siblings ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/core_siblings_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/die_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/die_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/package_cpus ================================================ ffff,ffffffff ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/package_cpus_list ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/thread_siblings ================================================ 0002,00000200 ================================================ FILE: utils/sysfs/testdata_epyc7402/cpu9/topology/thread_siblings_list ================================================ 9,33 ================================================ FILE: utils/sysfs/testdata_epyc7402/online ================================================ 0-23,27-40,42,44,46-47 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/core_cpus ================================================ 000001 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/core_cpus_list ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/thread_siblings ================================================ 000001 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu0/topology/thread_siblings_list ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/core_cpus ================================================ 000002 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/core_cpus_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/thread_siblings ================================================ 000002 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu1/topology/thread_siblings_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/core_cpus ================================================ 000400 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/core_cpus_list ================================================ 10 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/core_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/thread_siblings ================================================ 000400 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu10/topology/thread_siblings_list ================================================ 10 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/core_cpus ================================================ 000800 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/core_cpus_list ================================================ 11 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/core_id ================================================ 14 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/thread_siblings ================================================ 000800 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu11/topology/thread_siblings_list ================================================ 11 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/core_cpus ================================================ 001000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/core_cpus_list ================================================ 12 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/core_id ================================================ 16 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/thread_siblings ================================================ 001000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu12/topology/thread_siblings_list ================================================ 12 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/core_cpus ================================================ 002000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/core_cpus_list ================================================ 13 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/core_id ================================================ 17 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/thread_siblings ================================================ 002000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu13/topology/thread_siblings_list ================================================ 13 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/core_cpus ================================================ 004000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/core_cpus_list ================================================ 14 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/core_id ================================================ 18 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/thread_siblings ================================================ 004000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu14/topology/thread_siblings_list ================================================ 14 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/core_cpus ================================================ 008000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/core_cpus_list ================================================ 15 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/core_id ================================================ 20 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/thread_siblings ================================================ 008000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu15/topology/thread_siblings_list ================================================ 15 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/core_cpus ================================================ 010000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/core_cpus_list ================================================ 16 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/core_id ================================================ 21 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/thread_siblings ================================================ 010000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu16/topology/thread_siblings_list ================================================ 16 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/core_cpus ================================================ 020000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/core_cpus_list ================================================ 17 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/core_id ================================================ 22 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/thread_siblings ================================================ 020000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu17/topology/thread_siblings_list ================================================ 17 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/core_cpus ================================================ 040000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/core_cpus_list ================================================ 18 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/core_id ================================================ 24 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/thread_siblings ================================================ 040000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu18/topology/thread_siblings_list ================================================ 18 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/core_cpus ================================================ 080000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/core_cpus_list ================================================ 19 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/core_id ================================================ 25 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/thread_siblings ================================================ 080000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu19/topology/thread_siblings_list ================================================ 19 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/core_cpus ================================================ 000004 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/core_cpus_list ================================================ 2 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/core_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/thread_siblings ================================================ 000004 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu2/topology/thread_siblings_list ================================================ 2 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/core_cpus ================================================ 100000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/core_cpus_list ================================================ 20 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/core_id ================================================ 26 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/thread_siblings ================================================ 100000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu20/topology/thread_siblings_list ================================================ 20 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/core_cpus ================================================ 200000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/core_cpus_list ================================================ 21 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/core_id ================================================ 28 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/thread_siblings ================================================ 200000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu21/topology/thread_siblings_list ================================================ 21 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/core_cpus ================================================ 400000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/core_cpus_list ================================================ 22 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/core_id ================================================ 29 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/thread_siblings ================================================ 400000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu22/topology/thread_siblings_list ================================================ 22 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/core_cpus ================================================ 800000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/core_cpus_list ================================================ 23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/core_id ================================================ 30 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/thread_siblings ================================================ 800000 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu23/topology/thread_siblings_list ================================================ 23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/core_cpus ================================================ 000008 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/core_cpus_list ================================================ 3 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/core_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/thread_siblings ================================================ 000008 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu3/topology/thread_siblings_list ================================================ 3 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/core_cpus ================================================ 000010 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/core_cpus_list ================================================ 4 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/core_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/thread_siblings ================================================ 000010 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu4/topology/thread_siblings_list ================================================ 4 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/core_cpus ================================================ 000020 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/core_cpus_list ================================================ 5 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/core_id ================================================ 6 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/thread_siblings ================================================ 000020 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu5/topology/thread_siblings_list ================================================ 5 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/core_cpus ================================================ 000040 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/core_cpus_list ================================================ 6 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/core_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/thread_siblings ================================================ 000040 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu6/topology/thread_siblings_list ================================================ 6 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/core_cpus ================================================ 000080 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/core_cpus_list ================================================ 7 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/core_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/thread_siblings ================================================ 000080 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu7/topology/thread_siblings_list ================================================ 7 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/core_cpus ================================================ 000100 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/core_cpus_list ================================================ 8 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/core_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/thread_siblings ================================================ 000100 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu8/topology/thread_siblings_list ================================================ 8 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/core_cpus ================================================ 000200 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/core_cpus_list ================================================ 9 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/core_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/core_siblings ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/core_siblings_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/die_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/die_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/package_cpus ================================================ ffffff ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/package_cpus_list ================================================ 0-23 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/thread_siblings ================================================ 000200 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/cpu9/topology/thread_siblings_list ================================================ 9 ================================================ FILE: utils/sysfs/testdata_epyc7402_nohyperthreading/online ================================================ 0-10,12,14,20-23 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/online ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/core_cpus ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/core_cpus_list ================================================ 0 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/core_siblings ================================================ b ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/core_siblings_list ================================================ 0-1,3 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/die_cpus ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/die_cpus_list ================================================ 0 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/die_id ================================================ -1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/package_cpus ================================================ b ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/package_cpus_list ================================================ 0-1,3 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/physical_package_id ================================================ 60 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/thread_siblings ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu0/topology/thread_siblings_list ================================================ 0 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/online ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/core_cpus ================================================ 2 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/core_cpus_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/core_siblings ================================================ b ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/core_siblings_list ================================================ 0-1,3 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/die_cpus ================================================ 2 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/die_cpus_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/die_id ================================================ -1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/package_cpus ================================================ b ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/package_cpus_list ================================================ 0-1,3 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/physical_package_id ================================================ 60 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/thread_siblings ================================================ 2 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu1/topology/thread_siblings_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu2/online ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/online ================================================ 1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/core_cpus ================================================ 8 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/core_cpus_list ================================================ 3 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/core_id ================================================ 3 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/core_siblings ================================================ b ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/core_siblings_list ================================================ 0-1,3 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/die_cpus ================================================ 8 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/die_cpus_list ================================================ 3 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/die_id ================================================ -1 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/package_cpus ================================================ b ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/package_cpus_list ================================================ 0-1,3 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/physical_package_id ================================================ 60 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/thread_siblings ================================================ 8 ================================================ FILE: utils/sysfs/testdata_graviton2/cpu3/topology/thread_siblings_list ================================================ 3 ================================================ FILE: utils/sysfs/testdata_graviton2/online ================================================ 1-3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/hotplug/state ================================================ 206 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/core_cpus ================================================ 1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/core_cpus_list ================================================ 0 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/core_siblings ================================================ f ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/core_siblings_list ================================================ 0-3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/die_cpus ================================================ 1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/die_cpus_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/die_id ================================================ -1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/package_cpus ================================================ f ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/package_cpus_list ================================================ 0-3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/thread_siblings ================================================ 1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu0/topology/thread_siblings_list ================================================ 0 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/hotplug/state ================================================ 206 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/core_cpus ================================================ 2 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/core_cpus_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/core_siblings ================================================ f ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/core_siblings_list ================================================ 0-3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/die_cpus ================================================ 2 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/die_cpus_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/die_id ================================================ -1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/package_cpus ================================================ f ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/package_cpus_list ================================================ 0-3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/thread_siblings ================================================ 2 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu1/topology/thread_siblings_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/hotplug/state ================================================ 206 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/core_cpus ================================================ 4 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/core_cpus_list ================================================ 2 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/core_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/core_siblings ================================================ f ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/core_siblings_list ================================================ 0-3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/die_cpus ================================================ 4 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/die_cpus_list ================================================ 2 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/die_id ================================================ -1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/package_cpus ================================================ f ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/package_cpus_list ================================================ 0-3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/thread_siblings ================================================ 4 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu2/topology/thread_siblings_list ================================================ 2 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/hotplug/state ================================================ 206 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/core_cpus ================================================ 8 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/core_cpus_list ================================================ 3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/core_id ================================================ 3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/core_siblings ================================================ f ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/core_siblings_list ================================================ 0-3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/die_cpus ================================================ 8 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/die_cpus_list ================================================ 3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/die_id ================================================ -1 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/package_cpus ================================================ f ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/package_cpus_list ================================================ 0-3 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/thread_siblings ================================================ 8 ================================================ FILE: utils/sysfs/testdata_rpi4/cpu3/topology/thread_siblings_list ================================================ 3 ================================================ FILE: utils/sysfs/testdata_rpi4/hotplug/states ================================================ 24: fs/buffer:dead 25: printk:dead 26: mm/memctrl:dead 27: lib/percpu_cnt:dead 28: lib/radix:dead 29: mm/page_alloc:dead 30: net/dev:dead 35: padata:dead 36: workqueue:prepare 38: hrtimers:prepare 42: relay:prepare 43: slab:prepare 44: md/raid5:prepare 45: RCU/tree:prepare 54: base/topology:prepare 57: trace/RB:preapre 58: mm/zsmalloc:prepare 59: mm/zswap:prepare 60: mm/zswap_pool:prepare 63: timers:prepare 65: fork:vm_stack_cache 86: cpu:bringup 87: idle:dead 88: ap:offline 89: sched:starting 90: RCU/tree:dying 91: irqchip/arm/gic:starting 107: arm64/debug_monitors:starting 108: perf/arm64/hw_breakpoint:starting 110: perf/arm/pmu:starting 113: clockevents/arm/arch_timer:starting 125: kvm/cpu:starting 126: kvm/arm/vgic:starting 128: kvm/arm/timer:starting 129: clockevents/dummy_timer:starting 132: arm64/isndep:starting 133: smpcfd:dying 136: ap:online 137: cpu:teardown 139: smpboot/threads:online 141: irq/affinity:online 144: perf:online 155: perf/arm/ccn:online 168: lockup_detector:online 169: workqueue:online 170: RCU/tree:online 172: mm/writeback:online 173: mm/vmstat:online 174: mm/compaction:online 175: arm64/cpuinfo:online 176: padata:online 177: mm/vmscan:online 178: lib/percpu_cnt:online 179: cpufreq:online 180: leds/trigger:starting 181: printk:online 205: sched:active 206: online 41: smpcfd:prepare ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/core_cpus ================================================ 00000003 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/core_cpus_list ================================================ 0-1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/core_siblings ================================================ 00000003 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/core_siblings_list ================================================ 0-1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/die_cpus ================================================ 00000003 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/die_cpus_list ================================================ 0-1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/package_cpus ================================================ 00000003 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/package_cpus_list ================================================ 0-1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/thread_siblings ================================================ 00000003 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu0/topology/thread_siblings_list ================================================ 0-1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/core_cpus ================================================ 00000003 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/core_cpus_list ================================================ 0-1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/core_siblings ================================================ 00000003 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/core_siblings_list ================================================ 0-1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/die_cpus ================================================ 00000003 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/die_cpus_list ================================================ 0-1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/package_cpus ================================================ 00000003 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/package_cpus_list ================================================ 0-1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/thread_siblings ================================================ 00000003 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu1/topology/thread_siblings_list ================================================ 0-1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/core_cpus ================================================ 00000c00 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/core_cpus_list ================================================ 10-11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/core_siblings ================================================ 00000c00 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/core_siblings_list ================================================ 10-11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/die_cpus ================================================ 00000c00 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/die_cpus_list ================================================ 10-11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/package_cpus ================================================ 00000c00 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/package_cpus_list ================================================ 10-11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/physical_package_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/thread_siblings ================================================ 00000c00 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu10/topology/thread_siblings_list ================================================ 10-11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/core_cpus ================================================ 00000c00 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/core_cpus_list ================================================ 10-11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/core_siblings ================================================ 00000c00 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/core_siblings_list ================================================ 10-11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/die_cpus ================================================ 00000c00 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/die_cpus_list ================================================ 10-11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/package_cpus ================================================ 00000c00 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/package_cpus_list ================================================ 10-11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/physical_package_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/thread_siblings ================================================ 00000c00 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu11/topology/thread_siblings_list ================================================ 10-11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/core_cpus ================================================ 00003000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/core_cpus_list ================================================ 12-13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/core_siblings ================================================ 00003000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/core_siblings_list ================================================ 12-13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/die_cpus ================================================ 00003000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/die_cpus_list ================================================ 12-13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/package_cpus ================================================ 00003000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/package_cpus_list ================================================ 12-13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/physical_package_id ================================================ 6 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/thread_siblings ================================================ 00003000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu12/topology/thread_siblings_list ================================================ 12-13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/core_cpus ================================================ 00003000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/core_cpus_list ================================================ 12-13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/core_siblings ================================================ 00003000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/core_siblings_list ================================================ 12-13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/die_cpus ================================================ 00003000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/die_cpus_list ================================================ 12-13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/package_cpus ================================================ 00003000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/package_cpus_list ================================================ 12-13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/physical_package_id ================================================ 6 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/thread_siblings ================================================ 00003000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu13/topology/thread_siblings_list ================================================ 12-13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/core_cpus ================================================ 0000c000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/core_cpus_list ================================================ 14-15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/core_siblings ================================================ 0000c000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/core_siblings_list ================================================ 14-15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/die_cpus ================================================ 0000c000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/die_cpus_list ================================================ 14-15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/package_cpus ================================================ 0000c000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/package_cpus_list ================================================ 14-15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/physical_package_id ================================================ 7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/thread_siblings ================================================ 0000c000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu14/topology/thread_siblings_list ================================================ 14-15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/core_cpus ================================================ 0000c000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/core_cpus_list ================================================ 14-15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/core_siblings ================================================ 0000c000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/core_siblings_list ================================================ 14-15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/die_cpus ================================================ 0000c000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/die_cpus_list ================================================ 14-15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/package_cpus ================================================ 0000c000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/package_cpus_list ================================================ 14-15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/physical_package_id ================================================ 7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/thread_siblings ================================================ 0000c000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu15/topology/thread_siblings_list ================================================ 14-15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/core_cpus ================================================ 00030000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/core_cpus_list ================================================ 16-17 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/core_siblings ================================================ 00030000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/core_siblings_list ================================================ 16-17 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/die_cpus ================================================ 00030000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/die_cpus_list ================================================ 16-17 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/package_cpus ================================================ 00030000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/package_cpus_list ================================================ 16-17 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/physical_package_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/thread_siblings ================================================ 00030000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu16/topology/thread_siblings_list ================================================ 16-17 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/core_cpus ================================================ 00030000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/core_cpus_list ================================================ 16-17 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/core_siblings ================================================ 00030000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/core_siblings_list ================================================ 16-17 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/die_cpus ================================================ 00030000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/die_cpus_list ================================================ 16-17 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/package_cpus ================================================ 00030000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/package_cpus_list ================================================ 16-17 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/physical_package_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/thread_siblings ================================================ 00030000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu17/topology/thread_siblings_list ================================================ 16-17 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/core_cpus ================================================ 000c0000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/core_cpus_list ================================================ 18-19 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/core_siblings ================================================ 000c0000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/core_siblings_list ================================================ 18-19 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/die_cpus ================================================ 000c0000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/die_cpus_list ================================================ 18-19 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/package_cpus ================================================ 000c0000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/package_cpus_list ================================================ 18-19 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/physical_package_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/thread_siblings ================================================ 000c0000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu18/topology/thread_siblings_list ================================================ 18-19 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/core_cpus ================================================ 000c0000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/core_cpus_list ================================================ 18-19 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/core_siblings ================================================ 000c0000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/core_siblings_list ================================================ 18-19 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/die_cpus ================================================ 000c0000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/die_cpus_list ================================================ 18-19 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/package_cpus ================================================ 000c0000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/package_cpus_list ================================================ 18-19 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/physical_package_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/thread_siblings ================================================ 000c0000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu19/topology/thread_siblings_list ================================================ 18-19 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/core_cpus ================================================ 0000000c ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/core_cpus_list ================================================ 2-3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/core_siblings ================================================ 0000000c ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/core_siblings_list ================================================ 2-3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/die_cpus ================================================ 0000000c ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/die_cpus_list ================================================ 2-3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/package_cpus ================================================ 0000000c ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/package_cpus_list ================================================ 2-3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/thread_siblings ================================================ 0000000c ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu2/topology/thread_siblings_list ================================================ 2-3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/core_cpus ================================================ 00300000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/core_cpus_list ================================================ 20-21 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/core_siblings ================================================ 00300000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/core_siblings_list ================================================ 20-21 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/die_cpus ================================================ 00300000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/die_cpus_list ================================================ 20-21 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/package_cpus ================================================ 00300000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/package_cpus_list ================================================ 20-21 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/physical_package_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/thread_siblings ================================================ 00300000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu20/topology/thread_siblings_list ================================================ 20-21 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/core_cpus ================================================ 00300000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/core_cpus_list ================================================ 20-21 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/core_siblings ================================================ 00300000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/core_siblings_list ================================================ 20-21 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/die_cpus ================================================ 00300000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/die_cpus_list ================================================ 20-21 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/package_cpus ================================================ 00300000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/package_cpus_list ================================================ 20-21 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/physical_package_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/thread_siblings ================================================ 00300000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu21/topology/thread_siblings_list ================================================ 20-21 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/core_cpus ================================================ 00c00000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/core_cpus_list ================================================ 22-23 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/core_siblings ================================================ 00c00000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/core_siblings_list ================================================ 22-23 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/die_cpus ================================================ 00c00000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/die_cpus_list ================================================ 22-23 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/package_cpus ================================================ 00c00000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/package_cpus_list ================================================ 22-23 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/physical_package_id ================================================ 11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/thread_siblings ================================================ 00c00000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu22/topology/thread_siblings_list ================================================ 22-23 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/core_cpus ================================================ 00c00000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/core_cpus_list ================================================ 22-23 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/core_siblings ================================================ 00c00000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/core_siblings_list ================================================ 22-23 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/die_cpus ================================================ 00c00000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/die_cpus_list ================================================ 22-23 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/package_cpus ================================================ 00c00000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/package_cpus_list ================================================ 22-23 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/physical_package_id ================================================ 11 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/thread_siblings ================================================ 00c00000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu23/topology/thread_siblings_list ================================================ 22-23 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/core_cpus ================================================ 03000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/core_cpus_list ================================================ 24-25 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/core_siblings ================================================ 03000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/core_siblings_list ================================================ 24-25 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/die_cpus ================================================ 03000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/die_cpus_list ================================================ 24-25 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/package_cpus ================================================ 03000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/package_cpus_list ================================================ 24-25 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/physical_package_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/thread_siblings ================================================ 03000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu24/topology/thread_siblings_list ================================================ 24-25 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/core_cpus ================================================ 03000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/core_cpus_list ================================================ 24-25 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/core_siblings ================================================ 03000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/core_siblings_list ================================================ 24-25 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/die_cpus ================================================ 03000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/die_cpus_list ================================================ 24-25 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/package_cpus ================================================ 03000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/package_cpus_list ================================================ 24-25 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/physical_package_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/thread_siblings ================================================ 03000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu25/topology/thread_siblings_list ================================================ 24-25 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/core_cpus ================================================ 0c000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/core_cpus_list ================================================ 26-27 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/core_siblings ================================================ 0c000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/core_siblings_list ================================================ 26-27 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/die_cpus ================================================ 0c000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/die_cpus_list ================================================ 26-27 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/package_cpus ================================================ 0c000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/package_cpus_list ================================================ 26-27 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/physical_package_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/thread_siblings ================================================ 0c000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu26/topology/thread_siblings_list ================================================ 26-27 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/core_cpus ================================================ 0c000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/core_cpus_list ================================================ 26-27 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/core_siblings ================================================ 0c000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/core_siblings_list ================================================ 26-27 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/die_cpus ================================================ 0c000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/die_cpus_list ================================================ 26-27 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/package_cpus ================================================ 0c000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/package_cpus_list ================================================ 26-27 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/physical_package_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/thread_siblings ================================================ 0c000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu27/topology/thread_siblings_list ================================================ 26-27 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/core_cpus ================================================ 30000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/core_cpus_list ================================================ 28-29 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/core_siblings ================================================ 30000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/core_siblings_list ================================================ 28-29 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/die_cpus ================================================ 30000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/die_cpus_list ================================================ 28-29 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/package_cpus ================================================ 30000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/package_cpus_list ================================================ 28-29 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/physical_package_id ================================================ 14 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/thread_siblings ================================================ 30000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu28/topology/thread_siblings_list ================================================ 28-29 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/core_cpus ================================================ 30000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/core_cpus_list ================================================ 28-29 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/core_siblings ================================================ 30000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/core_siblings_list ================================================ 28-29 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/die_cpus ================================================ 30000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/die_cpus_list ================================================ 28-29 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/package_cpus ================================================ 30000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/package_cpus_list ================================================ 28-29 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/physical_package_id ================================================ 14 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/thread_siblings ================================================ 30000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu29/topology/thread_siblings_list ================================================ 28-29 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/core_cpus ================================================ 0000000c ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/core_cpus_list ================================================ 2-3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/core_siblings ================================================ 0000000c ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/core_siblings_list ================================================ 2-3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/die_cpus ================================================ 0000000c ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/die_cpus_list ================================================ 2-3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/package_cpus ================================================ 0000000c ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/package_cpus_list ================================================ 2-3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/thread_siblings ================================================ 0000000c ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu3/topology/thread_siblings_list ================================================ 2-3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/core_cpus ================================================ c0000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/core_cpus_list ================================================ 30-31 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/core_siblings ================================================ c0000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/core_siblings_list ================================================ 30-31 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/die_cpus ================================================ c0000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/die_cpus_list ================================================ 30-31 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/package_cpus ================================================ c0000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/package_cpus_list ================================================ 30-31 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/physical_package_id ================================================ 15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/thread_siblings ================================================ c0000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu30/topology/thread_siblings_list ================================================ 30-31 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/core_cpus ================================================ c0000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/core_cpus_list ================================================ 30-31 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/core_siblings ================================================ c0000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/core_siblings_list ================================================ 30-31 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/die_cpus ================================================ c0000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/die_cpus_list ================================================ 30-31 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/package_cpus ================================================ c0000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/package_cpus_list ================================================ 30-31 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/physical_package_id ================================================ 15 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/thread_siblings ================================================ c0000000 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu31/topology/thread_siblings_list ================================================ 30-31 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/core_cpus ================================================ 00000030 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/core_cpus_list ================================================ 4-5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/core_siblings ================================================ 00000030 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/core_siblings_list ================================================ 4-5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/die_cpus ================================================ 00000030 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/die_cpus_list ================================================ 4-5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/package_cpus ================================================ 00000030 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/package_cpus_list ================================================ 4-5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/physical_package_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/thread_siblings ================================================ 00000030 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu4/topology/thread_siblings_list ================================================ 4-5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/core_cpus ================================================ 00000030 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/core_cpus_list ================================================ 4-5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/core_siblings ================================================ 00000030 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/core_siblings_list ================================================ 4-5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/die_cpus ================================================ 00000030 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/die_cpus_list ================================================ 4-5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/package_cpus ================================================ 00000030 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/package_cpus_list ================================================ 4-5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/physical_package_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/thread_siblings ================================================ 00000030 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu5/topology/thread_siblings_list ================================================ 4-5 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/core_cpus ================================================ 000000c0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/core_cpus_list ================================================ 6-7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/core_siblings ================================================ 000000c0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/core_siblings_list ================================================ 6-7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/die_cpus ================================================ 000000c0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/die_cpus_list ================================================ 6-7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/package_cpus ================================================ 000000c0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/package_cpus_list ================================================ 6-7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/physical_package_id ================================================ 3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/thread_siblings ================================================ 000000c0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu6/topology/thread_siblings_list ================================================ 6-7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/core_cpus ================================================ 000000c0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/core_cpus_list ================================================ 6-7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/core_siblings ================================================ 000000c0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/core_siblings_list ================================================ 6-7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/die_cpus ================================================ 000000c0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/die_cpus_list ================================================ 6-7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/package_cpus ================================================ 000000c0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/package_cpus_list ================================================ 6-7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/physical_package_id ================================================ 3 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/thread_siblings ================================================ 000000c0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu7/topology/thread_siblings_list ================================================ 6-7 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/core_cpus ================================================ 00000300 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/core_cpus_list ================================================ 8-9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/core_siblings ================================================ 00000300 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/core_siblings_list ================================================ 8-9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/die_cpus ================================================ 00000300 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/die_cpus_list ================================================ 8-9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/package_cpus ================================================ 00000300 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/package_cpus_list ================================================ 8-9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/physical_package_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/thread_siblings ================================================ 00000300 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu8/topology/thread_siblings_list ================================================ 8-9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/core_cpus ================================================ 00000300 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/core_cpus_list ================================================ 8-9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/core_siblings ================================================ 00000300 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/core_siblings_list ================================================ 8-9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/die_cpus ================================================ 00000300 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/die_cpus_list ================================================ 8-9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/package_cpus ================================================ 00000300 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/package_cpus_list ================================================ 8-9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/physical_package_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/thread_siblings ================================================ 00000300 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/cpu9/topology/thread_siblings_list ================================================ 8-9 ================================================ FILE: utils/sysfs/testdata_single_socket_many_NUMAs/online ================================================ 0-31 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu0/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu0/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu0/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu0/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu0/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,01000001 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu0/topology/thread_siblings_list ================================================ 0,24 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu1/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu1/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu1/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu1/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu1/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,02000002 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu1/topology/thread_siblings_list ================================================ 1,25 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu10/topology/core_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu10/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu10/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu10/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu10/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000004,00000400 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu10/topology/thread_siblings_list ================================================ 10,34 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu11/topology/core_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu11/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu11/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu11/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu11/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000008,00000800 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu11/topology/thread_siblings_list ================================================ 11,35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu12/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu12/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu12/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu12/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu12/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000010,00001000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu12/topology/thread_siblings_list ================================================ 12,36 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu13/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu13/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu13/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu13/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu13/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000020,00002000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu13/topology/thread_siblings_list ================================================ 13,37 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu14/topology/core_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu14/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu14/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu14/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu14/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000040,00004000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu14/topology/thread_siblings_list ================================================ 14,38 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu15/topology/core_id ================================================ 3 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu15/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu15/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu15/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu15/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000080,00008000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu15/topology/thread_siblings_list ================================================ 15,39 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu16/topology/core_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu16/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu16/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu16/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu16/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000100,00010000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu16/topology/thread_siblings_list ================================================ 16,40 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu17/topology/core_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu17/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu17/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu17/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu17/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000200,00020000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu17/topology/thread_siblings_list ================================================ 17,41 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu18/topology/core_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu18/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu18/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu18/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu18/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000400,00040000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu18/topology/thread_siblings_list ================================================ 18,42 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu19/topology/core_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu19/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu19/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu19/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu19/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000800,00080000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu19/topology/thread_siblings_list ================================================ 19,43 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu2/topology/core_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu2/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu2/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu2/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu2/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,04000004 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu2/topology/thread_siblings_list ================================================ 2,26 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu20/topology/core_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu20/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu20/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu20/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu20/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00001000,00100000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu20/topology/thread_siblings_list ================================================ 20,44 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu21/topology/core_id ================================================ 11 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu21/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu21/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu21/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu21/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00002000,00200000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu21/topology/thread_siblings_list ================================================ 21,45 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu22/topology/core_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu22/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu22/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu22/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu22/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00004000,00400000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu22/topology/thread_siblings_list ================================================ 22,46 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu23/topology/core_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu23/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu23/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu23/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu23/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00008000,00800000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu23/topology/thread_siblings_list ================================================ 23,47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu24/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu24/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu24/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu24/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu24/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,01000001 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu24/topology/thread_siblings_list ================================================ 0,24 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu25/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu25/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu25/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu25/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu25/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,02000002 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu25/topology/thread_siblings_list ================================================ 1,25 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu26/topology/core_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu26/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu26/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu26/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu26/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,04000004 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu26/topology/thread_siblings_list ================================================ 2,26 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu27/topology/core_id ================================================ 3 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu27/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu27/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu27/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu27/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,08000008 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu27/topology/thread_siblings_list ================================================ 3,27 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu28/topology/core_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu28/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu28/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu28/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu28/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,10000010 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu28/topology/thread_siblings_list ================================================ 4,28 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu29/topology/core_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu29/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu29/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu29/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu29/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,20000020 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu29/topology/thread_siblings_list ================================================ 5,29 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu3/topology/core_id ================================================ 3 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu3/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu3/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu3/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu3/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,08000008 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu3/topology/thread_siblings_list ================================================ 3,27 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu30/topology/core_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu30/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu30/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu30/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu30/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,40000040 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu30/topology/thread_siblings_list ================================================ 6,30 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu31/topology/core_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu31/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu31/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu31/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu31/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,80000080 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu31/topology/thread_siblings_list ================================================ 7,31 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu32/topology/core_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu32/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu32/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu32/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu32/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001,00000100 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu32/topology/thread_siblings_list ================================================ 8,32 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu33/topology/core_id ================================================ 11 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu33/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu33/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu33/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu33/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000002,00000200 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu33/topology/thread_siblings_list ================================================ 9,33 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu34/topology/core_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu34/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu34/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu34/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu34/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000004,00000400 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu34/topology/thread_siblings_list ================================================ 10,34 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu35/topology/core_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu35/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu35/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu35/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu35/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000008,00000800 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu35/topology/thread_siblings_list ================================================ 11,35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu36/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu36/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu36/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu36/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu36/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000010,00001000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu36/topology/thread_siblings_list ================================================ 12,36 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu37/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu37/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu37/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu37/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu37/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000020,00002000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu37/topology/thread_siblings_list ================================================ 13,37 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu38/topology/core_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu38/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu38/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu38/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu38/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000040,00004000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu38/topology/thread_siblings_list ================================================ 14,38 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu39/topology/core_id ================================================ 3 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu39/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu39/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu39/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu39/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000080,00008000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu39/topology/thread_siblings_list ================================================ 15,39 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu4/topology/core_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu4/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu4/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu4/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu4/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,10000010 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu4/topology/thread_siblings_list ================================================ 4,28 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu40/topology/core_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu40/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu40/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu40/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu40/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000100,00010000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu40/topology/thread_siblings_list ================================================ 16,40 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu41/topology/core_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu41/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu41/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu41/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu41/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000200,00020000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu41/topology/thread_siblings_list ================================================ 17,41 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu42/topology/core_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu42/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu42/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu42/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu42/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000400,00040000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu42/topology/thread_siblings_list ================================================ 18,42 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu43/topology/core_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu43/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu43/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu43/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu43/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000800,00080000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu43/topology/thread_siblings_list ================================================ 19,43 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu44/topology/core_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu44/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu44/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu44/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu44/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00001000,00100000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu44/topology/thread_siblings_list ================================================ 20,44 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu45/topology/core_id ================================================ 11 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu45/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu45/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu45/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu45/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00002000,00200000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu45/topology/thread_siblings_list ================================================ 21,45 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu46/topology/core_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu46/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu46/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu46/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu46/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00004000,00400000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu46/topology/thread_siblings_list ================================================ 22,46 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu47/topology/core_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu47/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000fff0,00fff000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu47/topology/core_siblings_list ================================================ 12-23,36-47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu47/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu47/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00008000,00800000 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu47/topology/thread_siblings_list ================================================ 23,47 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu5/topology/core_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu5/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu5/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu5/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu5/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,20000020 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu5/topology/thread_siblings_list ================================================ 5,29 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu6/topology/core_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu6/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu6/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu6/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu6/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,40000040 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu6/topology/thread_siblings_list ================================================ 6,30 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu7/topology/core_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu7/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu7/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu7/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu7/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,80000080 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu7/topology/thread_siblings_list ================================================ 7,31 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu8/topology/core_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu8/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu8/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu8/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu8/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001,00000100 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu8/topology/thread_siblings_list ================================================ 8,32 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu9/topology/core_id ================================================ 11 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu9/topology/core_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f,ff000fff ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu9/topology/core_siblings_list ================================================ 0-11,24-35 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu9/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu9/topology/thread_siblings ================================================ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000002,00000200 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/cpu9/topology/thread_siblings_list ================================================ 9,33 ================================================ FILE: utils/sysfs/testdata_xeon4214_2socket/online ================================================ 0-47 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/core_cpus ================================================ 00000001 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/core_cpus_list ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/thread_siblings ================================================ 00000001 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu0/topology/thread_siblings_list ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/core_cpus ================================================ 00000002 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/core_cpus_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/core_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/thread_siblings ================================================ 00000002 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu1/topology/thread_siblings_list ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/core_cpus ================================================ 00000400 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/core_cpus_list ================================================ 10 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/core_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/thread_siblings ================================================ 00000400 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu10/topology/thread_siblings_list ================================================ 10 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/core_cpus ================================================ 00000800 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/core_cpus_list ================================================ 11 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/core_id ================================================ 5 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/thread_siblings ================================================ 00000800 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu11/topology/thread_siblings_list ================================================ 11 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/core_cpus ================================================ 00001000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/core_cpus_list ================================================ 12 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/core_id ================================================ 3 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/thread_siblings ================================================ 00001000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu12/topology/thread_siblings_list ================================================ 12 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/core_cpus ================================================ 00002000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/core_cpus_list ================================================ 13 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/core_id ================================================ 3 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/thread_siblings ================================================ 00002000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu13/topology/thread_siblings_list ================================================ 13 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/core_cpus ================================================ 00004000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/core_cpus_list ================================================ 14 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/core_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/thread_siblings ================================================ 00004000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu14/topology/thread_siblings_list ================================================ 14 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/core_cpus ================================================ 00008000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/core_cpus_list ================================================ 15 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/core_id ================================================ 4 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/thread_siblings ================================================ 00008000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu15/topology/thread_siblings_list ================================================ 15 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/core_cpus ================================================ 00010000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/core_cpus_list ================================================ 16 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/core_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/thread_siblings ================================================ 00010000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu16/topology/thread_siblings_list ================================================ 16 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/core_cpus ================================================ 00020000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/core_cpus_list ================================================ 17 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/core_id ================================================ 8 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/thread_siblings ================================================ 00020000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu17/topology/thread_siblings_list ================================================ 17 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/core_cpus ================================================ 00040000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/core_cpus_list ================================================ 18 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/core_id ================================================ 15 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/thread_siblings ================================================ 00040000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu18/topology/thread_siblings_list ================================================ 18 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/core_cpus ================================================ 00080000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/core_cpus_list ================================================ 19 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/core_id ================================================ 15 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/thread_siblings ================================================ 00080000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu19/topology/thread_siblings_list ================================================ 19 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/core_cpus ================================================ 00000004 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/core_cpus_list ================================================ 2 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/core_id ================================================ 7 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/thread_siblings ================================================ 00000004 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu2/topology/thread_siblings_list ================================================ 2 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/core_cpus ================================================ 00100000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/core_cpus_list ================================================ 20 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/core_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/thread_siblings ================================================ 00100000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu20/topology/thread_siblings_list ================================================ 20 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/core_cpus ================================================ 00200000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/core_cpus_list ================================================ 21 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/core_id ================================================ 9 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/thread_siblings ================================================ 00200000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu21/topology/thread_siblings_list ================================================ 21 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/core_cpus ================================================ 00400000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/core_cpus_list ================================================ 22 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/core_id ================================================ 14 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/thread_siblings ================================================ 00400000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu22/topology/thread_siblings_list ================================================ 22 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/core_cpus ================================================ 00800000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/core_cpus_list ================================================ 23 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/core_id ================================================ 14 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/thread_siblings ================================================ 00800000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu23/topology/thread_siblings_list ================================================ 23 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/core_cpus ================================================ 01000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/core_cpus_list ================================================ 24 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/core_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/thread_siblings ================================================ 01000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu24/topology/thread_siblings_list ================================================ 24 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/core_cpus ================================================ 02000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/core_cpus_list ================================================ 25 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/core_id ================================================ 10 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/thread_siblings ================================================ 02000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu25/topology/thread_siblings_list ================================================ 25 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/core_cpus ================================================ 04000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/core_cpus_list ================================================ 26 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/core_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/thread_siblings ================================================ 04000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu26/topology/thread_siblings_list ================================================ 26 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/core_cpus ================================================ 08000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/core_cpus_list ================================================ 27 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/core_id ================================================ 13 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/thread_siblings ================================================ 08000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu27/topology/thread_siblings_list ================================================ 27 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/core_cpus ================================================ 10000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/core_cpus_list ================================================ 28 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/core_id ================================================ 11 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/thread_siblings ================================================ 10000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu28/topology/thread_siblings_list ================================================ 28 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/core_cpus ================================================ 20000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/core_cpus_list ================================================ 29 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/core_id ================================================ 11 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/thread_siblings ================================================ 20000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu29/topology/thread_siblings_list ================================================ 29 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/core_cpus ================================================ 00000008 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/core_cpus_list ================================================ 3 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/core_id ================================================ 7 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/thread_siblings ================================================ 00000008 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu3/topology/thread_siblings_list ================================================ 3 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/core_cpus ================================================ 40000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/core_cpus_list ================================================ 30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/core_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/thread_siblings ================================================ 40000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu30/topology/thread_siblings_list ================================================ 30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/core_cpus ================================================ 80000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/core_cpus_list ================================================ 31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/core_id ================================================ 12 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/thread_siblings ================================================ 80000000 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu31/topology/thread_siblings_list ================================================ 31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/core_cpus ================================================ 00000010 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/core_cpus_list ================================================ 4 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/thread_siblings ================================================ 00000010 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu4/topology/thread_siblings_list ================================================ 4 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/core_cpus ================================================ 00000020 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/core_cpus_list ================================================ 5 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/core_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/thread_siblings ================================================ 00000020 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu5/topology/thread_siblings_list ================================================ 5 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/core_cpus ================================================ 00000040 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/core_cpus_list ================================================ 6 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/core_id ================================================ 6 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/thread_siblings ================================================ 00000040 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu6/topology/thread_siblings_list ================================================ 6 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/core_cpus ================================================ 00000080 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/core_cpus_list ================================================ 7 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/core_id ================================================ 6 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/thread_siblings ================================================ 00000080 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu7/topology/thread_siblings_list ================================================ 7 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/core_cpus ================================================ 00000100 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/core_cpus_list ================================================ 8 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/core_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/core_siblings ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/core_siblings_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/die_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/die_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/package_cpus ================================================ 55555555 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/package_cpus_list ================================================ 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/physical_package_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/thread_siblings ================================================ 00000100 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu8/topology/thread_siblings_list ================================================ 8 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/core_cpus ================================================ 00000200 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/core_cpus_list ================================================ 9 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/core_id ================================================ 2 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/core_siblings ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/core_siblings_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/die_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/die_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/die_id ================================================ 0 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/package_cpus ================================================ aaaaaaaa ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/package_cpus_list ================================================ 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/physical_package_id ================================================ 1 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/thread_siblings ================================================ 00000200 ================================================ FILE: utils/sysfs/testdata_xeon5218_nohyperthread_2socket_nohotplug/cpu9/topology/thread_siblings_list ================================================ 9 ================================================ FILE: utils/sysinfo/sysinfo.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sysinfo import ( "fmt" "os" "regexp" "runtime" "strconv" "strings" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/utils/sysfs" "k8s.io/klog/v2" ) var ( schedulerRegExp = regexp.MustCompile(`.*\[(.*)\].*`) nodeDirRegExp = regexp.MustCompile(`node/node(\d*)`) cpuDirRegExp = regexp.MustCompile(`/cpu(\d+)`) memoryCapacityRegexp = regexp.MustCompile(`MemTotal:\s*([0-9]+) kB`) cpusPath = "/sys/devices/system/cpu" ) const ( cacheLevel2 = 2 hugepagesDir = "hugepages/" ) // Get information about block devices present on the system. // Uses the passed in system interface to retrieve the low level OS information. func GetBlockDeviceInfo(sysfs sysfs.SysFs) (map[string]info.DiskInfo, error) { disks, err := sysfs.GetBlockDevices() if err != nil { return nil, err } diskMap := make(map[string]info.DiskInfo) for _, disk := range disks { name := disk.Name() // Ignore non-disk devices. // TODO(rjnagal): Maybe just match hd, sd, and dm prefixes. if strings.HasPrefix(name, "loop") || strings.HasPrefix(name, "ram") || strings.HasPrefix(name, "sr") { continue } // Ignore "hidden" devices (i.e. nvme path device sysfs entries). // These devices are in the form of /dev/nvme$Xc$Yn$Z and will // not have a device handle (i.e. "hidden") isHidden, err := sysfs.IsBlockDeviceHidden(name) if err != nil { return nil, err } if isHidden { continue } diskInfo := info.DiskInfo{ Name: name, } dev, err := sysfs.GetBlockDeviceNumbers(name) if err != nil { return nil, err } n, err := fmt.Sscanf(dev, "%d:%d", &diskInfo.Major, &diskInfo.Minor) if err != nil || n != 2 { return nil, fmt.Errorf("could not parse device numbers from %s for device %s", dev, name) } out, err := sysfs.GetBlockDeviceSize(name) if err != nil { return nil, err } // Remove trailing newline before conversion. size, err := strconv.ParseUint(strings.TrimSpace(out), 10, 64) if err != nil { return nil, err } // size is in 512 bytes blocks. diskInfo.Size = size * 512 diskInfo.Scheduler = "none" blkSched, err := sysfs.GetBlockDeviceScheduler(name) if err == nil { matches := schedulerRegExp.FindSubmatch([]byte(blkSched)) if len(matches) >= 2 { diskInfo.Scheduler = string(matches[1]) } } device := fmt.Sprintf("%d:%d", diskInfo.Major, diskInfo.Minor) diskMap[device] = diskInfo } return diskMap, nil } // Get information about network devices present on the system. func GetNetworkDevices(sysfs sysfs.SysFs) ([]info.NetInfo, error) { devs, err := sysfs.GetNetworkDevices() if err != nil { return nil, err } netDevices := []info.NetInfo{} for _, dev := range devs { name := dev.Name() // Ignore docker, loopback, and veth devices. ignoredDevices := []string{"lo", "veth", "docker", "nerdctl"} ignored := false for _, prefix := range ignoredDevices { if strings.HasPrefix(name, prefix) { ignored = true break } } if ignored { continue } address, err := sysfs.GetNetworkAddress(name) if err != nil { return nil, err } mtuStr, err := sysfs.GetNetworkMtu(name) if err != nil { return nil, err } var mtu int64 n, err := fmt.Sscanf(mtuStr, "%d", &mtu) if err != nil || n != 1 { return nil, fmt.Errorf("could not parse mtu from %s for device %s", mtuStr, name) } netInfo := info.NetInfo{ Name: name, MacAddress: strings.TrimSpace(address), Mtu: mtu, } speed, err := sysfs.GetNetworkSpeed(name) // Some devices don't set speed. if err == nil { var s int64 n, err := fmt.Sscanf(speed, "%d", &s) if err != nil || n != 1 { return nil, fmt.Errorf("could not parse speed from %s for device %s", speed, name) } netInfo.Speed = s } netDevices = append(netDevices, netInfo) } return netDevices, nil } // GetHugePagesInfo returns information about pre-allocated huge pages // hugepagesDirectory should be top directory of hugepages // Such as: /sys/kernel/mm/hugepages/ func GetHugePagesInfo(sysFs sysfs.SysFs, hugepagesDirectory string) ([]info.HugePagesInfo, error) { var hugePagesInfo []info.HugePagesInfo files, err := sysFs.GetHugePagesInfo(hugepagesDirectory) if err != nil { // treat as non-fatal since kernels and machine can be // configured to disable hugepage support return hugePagesInfo, nil } for _, st := range files { nameArray := strings.Split(st.Name(), "-") pageSizeArray := strings.Split(nameArray[1], "kB") pageSize, err := strconv.ParseUint(string(pageSizeArray[0]), 10, 64) if err != nil { return hugePagesInfo, err } val, err := sysFs.GetHugePagesNr(hugepagesDirectory, st.Name()) if err != nil { return hugePagesInfo, err } var numPages uint64 // we use sscanf as the file as a new-line that trips up ParseUint // it returns the number of tokens successfully parsed, so if // n != 1, it means we were unable to parse a number from the file n, err := fmt.Sscanf(string(val), "%d", &numPages) if err != nil || n != 1 { return hugePagesInfo, fmt.Errorf("could not parse file nr_hugepage for %s, contents %q", st.Name(), string(val)) } hugePagesInfo = append(hugePagesInfo, info.HugePagesInfo{ NumPages: numPages, PageSize: pageSize, }) } return hugePagesInfo, nil } // GetNodesInfo returns information about NUMA nodes and their topology func GetNodesInfo(sysFs sysfs.SysFs) ([]info.Node, int, error) { nodes := []info.Node{} allLogicalCoresCount := 0 nodesDirs, err := sysFs.GetNodesPaths() if err != nil { return nil, 0, err } if len(nodesDirs) == 0 { klog.V(4).Info("Nodes topology is not available, providing CPU topology") return getCPUTopology(sysFs) } for _, nodeDir := range nodesDirs { id, err := getMatchedInt(nodeDirRegExp, nodeDir) if err != nil { return nil, 0, err } node := info.Node{Id: id} cpuDirs, err := sysFs.GetCPUsPaths(nodeDir) if len(cpuDirs) == 0 { klog.Warningf("Found node without any CPU, nodeDir: %s, number of cpuDirs %d, err: %v", nodeDir, len(cpuDirs), err) } else { cores, err := getCoresInfo(sysFs, cpuDirs) if err != nil { return nil, 0, err } node.Cores = cores for _, core := range cores { allLogicalCoresCount += len(core.Threads) } } // On some Linux platforms(such as Arm64 guest kernel), cache info may not exist. // So, we should ignore error here. err = addCacheInfo(sysFs, &node) if err != nil { klog.V(1).Infof("Found node without cache information, nodeDir: %s", nodeDir) } node.Memory, err = getNodeMemInfo(sysFs, nodeDir) if err != nil { return nil, 0, err } hugepagesDirectory := fmt.Sprintf("%s/%s", nodeDir, hugepagesDir) node.HugePages, err = GetHugePagesInfo(sysFs, hugepagesDirectory) if err != nil { return nil, 0, err } node.Distances, err = getDistances(sysFs, nodeDir) if err != nil { return nil, 0, err } nodes = append(nodes, node) } return nodes, allLogicalCoresCount, err } func getCPUTopology(sysFs sysfs.SysFs) ([]info.Node, int, error) { nodes := []info.Node{} cpusPaths, err := sysFs.GetCPUsPaths(cpusPath) if err != nil { return nil, 0, err } cpusCount := len(cpusPaths) if cpusCount == 0 { err = fmt.Errorf("no CPU is available, cpusPath: %s", cpusPath) return nil, 0, err } cpusByPhysicalPackageID, err := getCpusByPhysicalPackageID(sysFs, cpusPaths) if err != nil { return nil, 0, err } if len(cpusByPhysicalPackageID) == 0 { klog.Warningf("Cannot read any physical package id for any CPU") return nil, cpusCount, nil } for physicalPackageID, cpus := range cpusByPhysicalPackageID { node := info.Node{Id: physicalPackageID} cores, err := getCoresInfo(sysFs, cpus) if err != nil { return nil, 0, err } node.Cores = cores // On some Linux platforms(such as Arm64 guest kernel), cache info may not exist. // So, we should ignore error here. err = addCacheInfo(sysFs, &node) if err != nil { klog.V(1).Infof("Found cpu without cache information, cpuPath: %s", cpus) } nodes = append(nodes, node) } return nodes, cpusCount, nil } func getCpusByPhysicalPackageID(sysFs sysfs.SysFs, cpusPaths []string) (map[int][]string, error) { cpuPathsByPhysicalPackageID := make(map[int][]string) for _, cpuPath := range cpusPaths { rawPhysicalPackageID, err := sysFs.GetCPUPhysicalPackageID(cpuPath) if os.IsNotExist(err) { klog.Warningf("Cannot read physical package id for %s, physical_package_id file does not exist, err: %s", cpuPath, err) continue } else if err != nil { return nil, err } physicalPackageID, err := strconv.Atoi(rawPhysicalPackageID) if err != nil { return nil, err } if _, ok := cpuPathsByPhysicalPackageID[physicalPackageID]; !ok { cpuPathsByPhysicalPackageID[physicalPackageID] = make([]string, 0) } cpuPathsByPhysicalPackageID[physicalPackageID] = append(cpuPathsByPhysicalPackageID[physicalPackageID], cpuPath) } return cpuPathsByPhysicalPackageID, nil } // addCacheInfo adds information about cache for NUMA node func addCacheInfo(sysFs sysfs.SysFs, node *info.Node) error { for coreID, core := range node.Cores { threadID := core.Threads[0] //get any thread for core caches, err := GetCacheInfo(sysFs, threadID) if err != nil { return err } numThreadsPerCore := len(core.Threads) numThreadsPerNode := len(node.Cores) * numThreadsPerCore for _, cache := range caches { c := info.Cache{ Id: cache.Id, Size: cache.Size, Level: cache.Level, Type: cache.Type, } if cache.Level > cacheLevel2 { if cache.Cpus == numThreadsPerNode { // Add a node level cache. cacheFound := false for _, nodeCache := range node.Caches { if nodeCache == c { cacheFound = true } } if !cacheFound { node.Caches = append(node.Caches, c) } } else { // Add uncore cache, for architecture in which l3 cache only shared among some cores. uncoreCacheFound := false for _, uncoreCache := range node.Cores[coreID].UncoreCaches { if uncoreCache == c { uncoreCacheFound = true } } if !uncoreCacheFound { node.Cores[coreID].UncoreCaches = append(node.Cores[coreID].UncoreCaches, c) } } } else if cache.Cpus == numThreadsPerCore { // Add core level cache node.Cores[coreID].Caches = append(node.Cores[coreID].Caches, c) } // Ignore unknown caches. } } return nil } // getNodeMemInfo returns information about total memory for NUMA node func getNodeMemInfo(sysFs sysfs.SysFs, nodeDir string) (uint64, error) { rawMem, err := sysFs.GetMemInfo(nodeDir) if err != nil { //Ignore if per-node info is not available. klog.Warningf("Found node without memory information, nodeDir: %s", nodeDir) return 0, nil } matches := memoryCapacityRegexp.FindStringSubmatch(rawMem) if len(matches) != 2 { return 0, fmt.Errorf("failed to match regexp in output: %q", string(rawMem)) } memory, err := strconv.ParseUint(matches[1], 10, 64) if err != nil { return 0, err } memory = memory * 1024 // Convert to bytes return uint64(memory), nil } // getDistances returns information about distances between NUMA nodes func getDistances(sysFs sysfs.SysFs, nodeDir string) ([]uint64, error) { rawDistance, err := sysFs.GetDistances(nodeDir) if err != nil { //Ignore if per-node info is not available. klog.Warningf("Found node without distance information, nodeDir: %s", nodeDir) return nil, nil } distances := []uint64{} for _, distance := range strings.Split(rawDistance, " ") { distanceUint, err := strconv.ParseUint(distance, 10, 64) if err != nil { return nil, fmt.Errorf("cannot convert %s to int", distance) } distances = append(distances, distanceUint) } return distances, nil } // getCoresInfo returns information about physical cores func getCoresInfo(sysFs sysfs.SysFs, cpuDirs []string) ([]info.Core, error) { cores := make([]info.Core, 0, len(cpuDirs)) for _, cpuDir := range cpuDirs { cpuID, err := getMatchedInt(cpuDirRegExp, cpuDir) if err != nil { return nil, fmt.Errorf("unexpected format of CPU directory, cpuDirRegExp %s, cpuDir: %s", cpuDirRegExp, cpuDir) } if !sysFs.IsCPUOnline(cpuDir) { continue } rawPhysicalID, err := sysFs.GetCoreID(cpuDir) if os.IsNotExist(err) { klog.Warningf("Cannot read core id for %s, core_id file does not exist, err: %s", cpuDir, err) continue } else if err != nil { return nil, err } physicalID, err := strconv.Atoi(rawPhysicalID) if err != nil { return nil, err } rawPhysicalPackageID, err := sysFs.GetCPUPhysicalPackageID(cpuDir) if os.IsNotExist(err) { klog.Warningf("Cannot read physical package id for %s, physical_package_id file does not exist, err: %s", cpuDir, err) continue } else if err != nil { return nil, err } physicalPackageID, err := strconv.Atoi(rawPhysicalPackageID) if err != nil { return nil, err } var bookID, drawerID string // s390/s390x additional cpu topology levels if runtime.GOARCH == "s390x" { bookID, err = sysFs.GetBookID(cpuDir) if os.IsNotExist(err) { klog.Warningf("Cannot read book id for %s, book_id file does not exist, err: %s", cpuDir, err) continue } else if err != nil { return nil, err } drawerID, err = sysFs.GetDrawerID(cpuDir) if os.IsNotExist(err) { klog.Warningf("Cannot read drawer id for %s, drawer_id file does not exist, err: %s", cpuDir, err) continue } else if err != nil { return nil, err } } coreIDx := -1 for id, core := range cores { if core.Id == physicalID && core.SocketID == physicalPackageID { // For s390x, we need to check the BookID and DrawerID match as well. if runtime.GOARCH != "s390x" || (core.BookID == bookID && core.DrawerID == drawerID) { coreIDx = id } } } if coreIDx == -1 { cores = append(cores, info.Core{}) coreIDx = len(cores) - 1 } desiredCore := &cores[coreIDx] desiredCore.Id = physicalID desiredCore.SocketID = physicalPackageID desiredCore.BookID = bookID desiredCore.DrawerID = drawerID if len(desiredCore.Threads) == 0 { desiredCore.Threads = []int{cpuID} } else { desiredCore.Threads = append(desiredCore.Threads, cpuID) } } return cores, nil } // GetCacheInfo return information about a cache accessible from the given cpu thread func GetCacheInfo(sysFs sysfs.SysFs, id int) ([]sysfs.CacheInfo, error) { caches, err := sysFs.GetCaches(id) if err != nil { return nil, err } info := []sysfs.CacheInfo{} for _, cache := range caches { if !strings.HasPrefix(cache.Name(), "index") { continue } cacheInfo, err := sysFs.GetCacheInfo(id, cache.Name()) if err != nil { return nil, err } info = append(info, cacheInfo) } return info, nil } func getNetworkStats(name string, sysFs sysfs.SysFs) (info.InterfaceStats, error) { var stats info.InterfaceStats var err error stats.Name = name stats.RxBytes, err = sysFs.GetNetworkStatValue(name, "rx_bytes") if err != nil { return stats, err } stats.RxPackets, err = sysFs.GetNetworkStatValue(name, "rx_packets") if err != nil { return stats, err } stats.RxErrors, err = sysFs.GetNetworkStatValue(name, "rx_errors") if err != nil { return stats, err } stats.RxDropped, err = sysFs.GetNetworkStatValue(name, "rx_dropped") if err != nil { return stats, err } stats.TxBytes, err = sysFs.GetNetworkStatValue(name, "tx_bytes") if err != nil { return stats, err } stats.TxPackets, err = sysFs.GetNetworkStatValue(name, "tx_packets") if err != nil { return stats, err } stats.TxErrors, err = sysFs.GetNetworkStatValue(name, "tx_errors") if err != nil { return stats, err } stats.TxDropped, err = sysFs.GetNetworkStatValue(name, "tx_dropped") if err != nil { return stats, err } return stats, nil } func GetSystemUUID(sysFs sysfs.SysFs) (string, error) { return sysFs.GetSystemUUID() } func getMatchedInt(rgx *regexp.Regexp, str string) (int, error) { matches := rgx.FindStringSubmatch(str) if len(matches) != 2 { return 0, fmt.Errorf("failed to match regexp, str: %s", str) } valInt, err := strconv.Atoi(matches[1]) if err != nil { return 0, err } return valInt, nil } // GetSocketFromCPU returns Socket ID of passed CPU. If is not present, returns -1. func GetSocketFromCPU(topology []info.Node, cpu int) int { for _, node := range topology { found, coreID := node.FindCoreByThread(cpu) if found { return node.Cores[coreID].SocketID } } return -1 } // GetOnlineCPUs returns available cores. func GetOnlineCPUs(topology []info.Node) []int { onlineCPUs := make([]int, 0) for _, node := range topology { for _, core := range node.Cores { onlineCPUs = append(onlineCPUs, core.Threads...) } } return onlineCPUs } ================================================ FILE: utils/sysinfo/sysinfo_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sysinfo import ( "encoding/json" "fmt" "os" "sort" "testing" "github.com/stretchr/testify/assert" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/utils/sysfs" "github.com/google/cadvisor/utils/sysfs/fakesysfs" ) func TestGetHugePagesInfo(t *testing.T) { fakeSys := fakesysfs.FakeSysFs{} hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, &fakesysfs.FileInfo{EntryName: "hugepages-1048576kB"}, } fakeSys.SetHugePages(hugePages, nil) hugePageNr := map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages": "1", } fakeSys.SetHugePagesNr(hugePageNr, nil) hugePagesInfo, err := GetHugePagesInfo(&fakeSys, "/fakeSysfs/devices/system/node/node0/hugepages/") assert.Nil(t, err) assert.Equal(t, 2, len(hugePagesInfo)) } func TestGetHugePagesInfoWithHugePagesDirectory(t *testing.T) { fakeSys := fakesysfs.FakeSysFs{} hugePagesInfo, err := GetHugePagesInfo(&fakeSys, "/fakeSysfs/devices/system/node/node0/hugepages/") assert.Nil(t, err) assert.Equal(t, 0, len(hugePagesInfo)) } func TestGetHugePagesInfoWithWrongDirName(t *testing.T) { fakeSys := fakesysfs.FakeSysFs{} hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-abckB"}, } fakeSys.SetHugePages(hugePages, nil) hugePagesInfo, err := GetHugePagesInfo(&fakeSys, "/fakeSysfs/devices/system/node/node0/hugepages/") assert.NotNil(t, err) assert.Equal(t, 0, len(hugePagesInfo)) } func TestGetHugePagesInfoWithReadingNrHugePagesError(t *testing.T) { fakeSys := fakesysfs.FakeSysFs{} hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, &fakesysfs.FileInfo{EntryName: "hugepages-1048576kB"}, } fakeSys.SetHugePages(hugePages, nil) hugePageNr := map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages": "1", } fakeSys.SetHugePagesNr(hugePageNr, fmt.Errorf("Error in reading nr_hugepages")) hugePagesInfo, err := GetHugePagesInfo(&fakeSys, "/fakeSysfs/devices/system/node/node0/hugepages/") assert.NotNil(t, err) assert.Equal(t, 0, len(hugePagesInfo)) } func TestGetHugePagesInfoWithWrongNrHugePageValue(t *testing.T) { fakeSys := fakesysfs.FakeSysFs{} hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, &fakesysfs.FileInfo{EntryName: "hugepages-1048576kB"}, } fakeSys.SetHugePages(hugePages, nil) hugePageNr := map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "*****", "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages": "1", } fakeSys.SetHugePagesNr(hugePageNr, nil) hugePagesInfo, err := GetHugePagesInfo(&fakeSys, "/fakeSysfs/devices/system/node/node0/hugepages/") assert.NotNil(t, err) assert.Equal(t, 0, len(hugePagesInfo)) } func TestGetNodesInfo(t *testing.T) { testCases := []struct { cache sysfs.CacheInfo nodesPaths []string cpusPaths map[string][]string coresThreads map[string]string memTotal string hugePages []os.FileInfo hugePageNr map[string]string physicalPackageIDs map[string]string nodes int cores int distances []string expectedNodes string }{ { sysfs.CacheInfo{ Id: 0, Size: 32 * 1024, Type: "unified", Level: 3, Cpus: 2, }, []string{ "/fakeSysfs/devices/system/node/node0", "/fakeSysfs/devices/system/node/node1"}, map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", }, "/fakeSysfs/devices/system/node/node1": { "/fakeSysfs/devices/system/node/node0/cpu2", "/fakeSysfs/devices/system/node/node0/cpu3", }, }, map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", }, "MemTotal: 32817192 kB", []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, }, map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages": "1", }, map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", }, 2, 4, []string{ "10 11", "11 10", }, ` [ { "node_id": 0, "memory": 33604804608, "hugepages": [ { "page_size": 2048, "num_pages": 1 } ], "distances": [ 10, 11 ], "cores": [ { "core_id": 0, "thread_ids": [ 0, 1 ], "caches": null, "uncore_caches": null, "socket_id": 0 } ], "caches": [ { "id": 0, "size": 32768, "type": "unified", "level": 3 } ] }, { "node_id": 1, "memory": 33604804608, "hugepages": [ { "page_size": 2048, "num_pages": 1 } ], "distances": [ 11, 10 ], "cores": [ { "core_id": 1, "thread_ids": [ 2, 3 ], "caches": null, "uncore_caches": null, "socket_id": 1 } ], "caches": [ { "id": 0, "size": 32768, "type": "unified", "level": 3 } ] } ] `, }, { sysfs.CacheInfo{ Id: 0, Size: 32 * 1024, Type: "unified", Level: 3, Cpus: 6, }, []string{ "/fakeSysfs/devices/system/node/node0"}, map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", "/fakeSysfs/devices/system/node/node0/cpu2", "/fakeSysfs/devices/system/node/node0/cpu3", "/fakeSysfs/devices/system/node/node0/cpu4", "/fakeSysfs/devices/system/node/node0/cpu5", }, }, map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", "/fakeSysfs/devices/system/node/node0/cpu4": "2", "/fakeSysfs/devices/system/node/node0/cpu5": "2", }, "MemTotal: 32817192 kB", []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, }, map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", }, map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", "/fakeSysfs/devices/system/node/node0/cpu4": "2", "/fakeSysfs/devices/system/node/node0/cpu5": "2", }, 1, 6, []string{ "10", }, ` [ { "node_id": 0, "memory": 33604804608, "distances": [ 10 ], "hugepages": [ { "page_size": 2048, "num_pages": 1 } ], "cores": [ { "core_id": 0, "thread_ids": [ 0, 1 ], "caches": null, "socket_id": 0, "uncore_caches": null }, { "core_id": 1, "thread_ids": [ 2, 3 ], "caches": null, "socket_id": 1, "uncore_caches": null }, { "core_id": 2, "thread_ids": [ 4, 5 ], "caches": null, "socket_id": 2, "uncore_caches": null } ], "caches": [ { "id": 0, "size": 32768, "type": "unified", "level": 3 } ] } ] `, }, } for _, test := range testCases { fakeSys := &fakesysfs.FakeSysFs{} fakeSys.SetCacheInfo(test.cache) fakeSys.SetNodesPaths(test.nodesPaths, nil) fakeSys.SetCPUsPaths(test.cpusPaths, nil) fakeSys.SetCoreThreads(test.coresThreads, nil) fakeSys.SetMemory(test.memTotal, nil) fakeSys.SetHugePages(test.hugePages, nil) fakeSys.SetHugePagesNr(test.hugePageNr, nil) fakeSys.SetPhysicalPackageIDs(test.physicalPackageIDs, nil) for i, node := range test.nodesPaths { fakeSys.SetDistances(node, test.distances[i], nil) } nodes, cores, err := GetNodesInfo(fakeSys) assert.Nil(t, err) assert.Equal(t, test.nodes, len(nodes)) assert.Equal(t, test.cores, cores) nodesJSON, err := json.Marshal(nodes) assert.Nil(t, err) assert.JSONEq(t, test.expectedNodes, string(nodesJSON)) } } func TestGetNodesInfoWithOfflineCPUs(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} c := sysfs.CacheInfo{ Id: 0, Size: 32 * 1024, Type: "unified", Level: 3, Cpus: 1, } fakeSys.SetCacheInfo(c) nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", "/fakeSysfs/devices/system/node/node1", } fakeSys.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", }, "/fakeSysfs/devices/system/node/node1": { "/fakeSysfs/devices/system/node/node0/cpu2", "/fakeSysfs/devices/system/node/node0/cpu3", }, } fakeSys.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", } fakeSys.SetCoreThreads(coreThread, nil) fakeSys.SetOnlineCPUs(map[string]interface{}{ "/fakeSysfs/devices/system/node/node0/cpu0": nil, "/fakeSysfs/devices/system/node/node0/cpu2": nil, }) memTotal := "MemTotal: 32817192 kB" fakeSys.SetMemory(memTotal, nil) hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, } fakeSys.SetHugePages(hugePages, nil) hugePageNr := map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages": "1", } fakeSys.SetHugePagesNr(hugePageNr, nil) physicalPackageIDs := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", } fakeSys.SetPhysicalPackageIDs(physicalPackageIDs, nil) fakeSys.SetDistances("/fakeSysfs/devices/system/node/node0", "10 11", nil) fakeSys.SetDistances("/fakeSysfs/devices/system/node/node1", "11 10", nil) nodes, cores, err := GetNodesInfo(fakeSys) assert.Nil(t, err) assert.Equal(t, 2, len(nodes)) assert.Equal(t, 2, cores) nodesJSON, err := json.Marshal(nodes) assert.Nil(t, err) expectedNodes := ` [ { "node_id": 0, "memory": 33604804608, "hugepages": [ { "page_size": 2048, "num_pages": 1 } ], "distances": [ 10, 11 ], "cores": [ { "core_id": 0, "thread_ids": [ 0 ], "caches": null, "socket_id": 0, "uncore_caches": null } ], "caches": [ { "id": 0, "size": 32768, "type": "unified", "level": 3 } ] }, { "node_id": 1, "memory": 33604804608, "hugepages": [ { "page_size": 2048, "num_pages": 1 } ], "distances": [ 11, 10 ], "cores": [ { "core_id": 1, "thread_ids": [ 2 ], "caches": null, "socket_id": 1, "uncore_caches": null } ], "caches": [ { "id": 0, "size": 32768, "type": "unified", "level": 3 } ] } ] ` assert.JSONEq(t, expectedNodes, string(nodesJSON)) } func TestGetNodesWithoutMemoryInfo(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} c := sysfs.CacheInfo{ Size: 32 * 1024, Type: "unified", Level: 3, Cpus: 2, } fakeSys.SetCacheInfo(c) nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", "/fakeSysfs/devices/system/node/node1", } fakeSys.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", }, "/fakeSysfs/devices/system/node/node1": { "/fakeSysfs/devices/system/node/node0/cpu2", "/fakeSysfs/devices/system/node/node0/cpu3", }, } fakeSys.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", } fakeSys.SetCoreThreads(coreThread, nil) hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, } fakeSys.SetHugePages(hugePages, nil) hugePageNr := map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages": "1", } fakeSys.SetHugePagesNr(hugePageNr, nil) nodes, cores, err := GetNodesInfo(fakeSys) assert.NotNil(t, err) assert.Equal(t, []info.Node([]info.Node(nil)), nodes) assert.Equal(t, 0, cores) } func TestGetNodesInfoWithoutCacheInfo(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", "/fakeSysfs/devices/system/node/node1", } fakeSys.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", }, "/fakeSysfs/devices/system/node/node1": { "/fakeSysfs/devices/system/node/node0/cpu2", "/fakeSysfs/devices/system/node/node0/cpu3", }, } fakeSys.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", } fakeSys.SetCoreThreads(coreThread, nil) memTotal := "MemTotal: 32817192 kB" fakeSys.SetMemory(memTotal, nil) hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, } fakeSys.SetHugePages(hugePages, nil) hugePageNr := map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", "/fakeSysfs/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages": "1", } fakeSys.SetHugePagesNr(hugePageNr, nil) physicalPackageIDs := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", } fakeSys.SetPhysicalPackageIDs(physicalPackageIDs, nil) fakeSys.SetDistances("/fakeSysfs/devices/system/node/node0", "10 11", nil) fakeSys.SetDistances("/fakeSysfs/devices/system/node/node1", "11 10", nil) nodes, cores, err := GetNodesInfo(fakeSys) assert.Nil(t, err) assert.Equal(t, 2, len(nodes)) assert.Equal(t, 4, cores) nodesJSON, err := json.Marshal(nodes) assert.Nil(t, err) expectedNodes := ` [ { "node_id": 0, "memory": 33604804608, "hugepages": [ { "page_size": 2048, "num_pages": 1 } ], "distances": [ 10, 11 ], "cores": [ { "core_id": 0, "thread_ids": [ 0, 1 ], "caches": null, "uncore_caches": null, "socket_id": 0 } ], "caches": null }, { "node_id": 1, "memory": 33604804608, "hugepages": [ { "page_size": 2048, "num_pages": 1 } ], "distances": [ 11, 10 ], "cores": [ { "core_id": 1, "thread_ids": [ 2, 3 ], "caches": null, "uncore_caches": null, "socket_id": 1 } ], "caches": null } ]` assert.JSONEq(t, expectedNodes, string(nodesJSON)) } func TestGetNodesInfoWithoutHugePagesInfo(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} c := sysfs.CacheInfo{ Id: 0, Size: 32 * 1024, Type: "unified", Level: 2, Cpus: 2, } fakeSys.SetCacheInfo(c) nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", "/fakeSysfs/devices/system/node/node1", } fakeSys.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", }, "/fakeSysfs/devices/system/node/node1": { "/fakeSysfs/devices/system/node/node0/cpu2", "/fakeSysfs/devices/system/node/node0/cpu3", }, } fakeSys.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", } fakeSys.SetCoreThreads(coreThread, nil) memTotal := "MemTotal: 32817192 kB" fakeSys.SetMemory(memTotal, nil) physicalPackageIDs := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", } fakeSys.SetPhysicalPackageIDs(physicalPackageIDs, nil) fakeSys.SetDistances("/fakeSysfs/devices/system/node/node0", "10 11", nil) fakeSys.SetDistances("/fakeSysfs/devices/system/node/node1", "11 10", nil) nodes, cores, err := GetNodesInfo(fakeSys) assert.Nil(t, err) assert.Equal(t, 2, len(nodes)) assert.Equal(t, 4, cores) nodesJSON, err := json.Marshal(nodes) assert.Nil(t, err) expectedNodes := ` [ { "node_id": 0, "memory": 33604804608, "distances": [ 10, 11 ], "hugepages": null, "cores": [ { "core_id": 0, "thread_ids": [ 0, 1 ], "caches": [ { "id": 0, "size": 32768, "type": "unified", "level": 2 } ], "uncore_caches": null, "socket_id": 0 } ], "caches": null }, { "node_id": 1, "memory": 33604804608, "hugepages": null, "distances": [ 11, 10 ], "cores": [ { "core_id": 1, "thread_ids": [ 2, 3 ], "caches": [ { "id": 0, "size": 32768, "type": "unified", "level": 2 } ], "uncore_caches": null, "socket_id": 1 } ], "caches": null } ]` assert.JSONEq(t, expectedNodes, string(nodesJSON)) } func TestGetNodesInfoWithoutNodes(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} c := sysfs.CacheInfo{ Id: 0, Size: 32 * 1024, Type: "unified", Level: 1, Cpus: 2, } fakeSys.SetCacheInfo(c) nodesPaths := []string{} fakeSys.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ cpusPath: { cpusPath + "/cpu0", cpusPath + "/cpu1", cpusPath + "/cpu2", cpusPath + "/cpu3", }, } fakeSys.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ cpusPath + "/cpu0": "0", cpusPath + "/cpu1": "0", cpusPath + "/cpu2": "1", cpusPath + "/cpu3": "1", } fakeSys.SetCoreThreads(coreThread, nil) physicalPackageIDs := map[string]string{ "/sys/devices/system/cpu/cpu0": "0", "/sys/devices/system/cpu/cpu1": "0", "/sys/devices/system/cpu/cpu2": "1", "/sys/devices/system/cpu/cpu3": "1", } fakeSys.SetPhysicalPackageIDs(physicalPackageIDs, nil) nodes, cores, err := GetNodesInfo(fakeSys) assert.Nil(t, err) assert.Equal(t, 2, len(nodes)) assert.Equal(t, 4, cores) sort.Slice(nodes, func(i, j int) bool { return nodes[i].Id < nodes[j].Id }) nodesJSON, err := json.Marshal(nodes) assert.Nil(t, err) expectedNodes := `[ { "node_id":0, "memory":0, "distances": null, "hugepages":null, "cores":[ { "core_id":0, "thread_ids":[ 0, 1 ], "caches":[ { "id": 0, "size":32768, "type":"unified", "level":1 } ], "socket_id": 0, "uncore_caches": null } ], "caches":null }, { "node_id":1, "memory":0, "distances": null, "hugepages":null, "cores":[ { "core_id":1, "thread_ids":[ 2, 3 ], "caches":[ { "id": 0, "size":32768, "type":"unified", "level":1 } ], "uncore_caches": null, "socket_id": 1 } ], "caches":null } ]` assert.JSONEq(t, expectedNodes, string(nodesJSON)) } func TestGetNodesInfoWithoutNodesWhenPhysicalPackageIDMissingForOneCPU(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} nodesPaths := []string{} fakeSys.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ cpusPath: { cpusPath + "/cpu0", cpusPath + "/cpu1", }, } fakeSys.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ cpusPath + "/cpu0": "0", cpusPath + "/cpu1": "0", } coreThreadErrors := map[string]error{ cpusPath + "/cpu0": nil, cpusPath + "/cpu1": nil, } fakeSys.SetCoreThreads(coreThread, coreThreadErrors) physicalPackageIDs := map[string]string{ cpusPath + "/cpu0": "0", cpusPath + "/cpu1": "0", } physicalPackageIDErrors := map[string]error{ cpusPath + "/cpu0": nil, cpusPath + "/cpu1": os.ErrNotExist, } fakeSys.SetPhysicalPackageIDs(physicalPackageIDs, physicalPackageIDErrors) nodes, cores, err := GetNodesInfo(fakeSys) assert.Nil(t, err) assert.Equal(t, 1, len(nodes)) assert.Equal(t, 2, cores) sort.Slice(nodes, func(i, j int) bool { return nodes[i].Id < nodes[j].Id }) nodesJSON, err := json.Marshal(nodes) assert.Nil(t, err) fmt.Println(string(nodesJSON)) expectedNodes := `[ { "node_id":0, "memory":0, "distances": null, "hugepages":null, "cores":[ { "core_id":0, "thread_ids":[ 0 ], "caches": null, "socket_id": 0, "uncore_caches": null } ], "caches":null } ]` assert.JSONEq(t, expectedNodes, string(nodesJSON)) } func TestGetNodesInfoWithoutNodesWhenPhysicalPackageIDMissing(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} nodesPaths := []string{} fakeSys.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ cpusPath: { cpusPath + "/cpu0", cpusPath + "/cpu1", }, } fakeSys.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ cpusPath + "/cpu0": "0", cpusPath + "/cpu1": "0", } coreThreadErrors := map[string]error{ cpusPath + "/cpu0": nil, cpusPath + "/cpu1": nil, } fakeSys.SetCoreThreads(coreThread, coreThreadErrors) physicalPackageIDs := map[string]string{ cpusPath + "/cpu0": "0", cpusPath + "/cpu1": "0", } physicalPackageIDErrors := map[string]error{ cpusPath + "/cpu0": os.ErrNotExist, cpusPath + "/cpu1": os.ErrNotExist, } fakeSys.SetPhysicalPackageIDs(physicalPackageIDs, physicalPackageIDErrors) nodes, cores, err := GetNodesInfo(fakeSys) assert.Nil(t, err) assert.Equal(t, 0, len(nodes)) assert.Equal(t, 2, cores) } func TestGetNodesWhenTopologyDirMissingForOneCPU(t *testing.T) { /* Unit test for case in which: - there are two cpus (cpu0 and cpu1) in /sys/devices/system/node/node0/ and /sys/devices/system/cpu - topology directory is missing for cpu1 but it exists for cpu0 */ fakeSys := &fakesysfs.FakeSysFs{} nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", } fakeSys.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", }, } fakeSys.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", } coreThreadErrors := map[string]error{ "/fakeSysfs/devices/system/node/node0/cpu0": nil, "/fakeSysfs/devices/system/node/node0/cpu1": os.ErrNotExist, } fakeSys.SetCoreThreads(coreThread, coreThreadErrors) memTotal := "MemTotal: 32817192 kB" fakeSys.SetMemory(memTotal, nil) hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, } fakeSys.SetHugePages(hugePages, nil) hugePageNr := map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", } fakeSys.SetHugePagesNr(hugePageNr, nil) physicalPackageIDs := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", } physicalPackageIDErrors := map[string]error{ "/fakeSysfs/devices/system/node/node0/cpu0": nil, "/fakeSysfs/devices/system/node/node0/cpu1": os.ErrNotExist, } fakeSys.SetPhysicalPackageIDs(physicalPackageIDs, physicalPackageIDErrors) fakeSys.SetDistances("/fakeSysfs/devices/system/node/node0", "10", nil) nodes, cores, err := GetNodesInfo(fakeSys) assert.Nil(t, err) assert.Equal(t, 1, len(nodes)) assert.Equal(t, 1, cores) sort.Slice(nodes, func(i, j int) bool { return nodes[i].Id < nodes[j].Id }) nodesJSON, err := json.Marshal(nodes) assert.Nil(t, err) expectedNodes := `[ { "node_id":0, "memory":33604804608, "distances" : [ 10 ], "hugepages":[ { "page_size":2048, "num_pages":1 } ], "cores":[ { "core_id":0, "thread_ids":[ 0 ], "caches":null, "socket_id":0, "uncore_caches":null } ], "caches": null } ]` assert.JSONEq(t, expectedNodes, string(nodesJSON)) } func TestGetNodesWhenPhysicalPackageIDMissingForOneCPU(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", } fakeSys.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", }, } fakeSys.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", } coreThreadErrors := map[string]error{ "/fakeSysfs/devices/system/node/node0/cpu0": nil, "/fakeSysfs/devices/system/node/node0/cpu1": nil, } fakeSys.SetCoreThreads(coreThread, coreThreadErrors) memTotal := "MemTotal: 32817192 kB" fakeSys.SetMemory(memTotal, nil) hugePages := []os.FileInfo{ &fakesysfs.FileInfo{EntryName: "hugepages-2048kB"}, } fakeSys.SetHugePages(hugePages, nil) hugePageNr := map[string]string{ "/fakeSysfs/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages": "1", } fakeSys.SetHugePagesNr(hugePageNr, nil) physicalPackageIDs := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", } physicalPackageIDErrors := map[string]error{ "/fakeSysfs/devices/system/node/node0/cpu0": nil, "/fakeSysfs/devices/system/node/node0/cpu1": os.ErrNotExist, } fakeSys.SetPhysicalPackageIDs(physicalPackageIDs, physicalPackageIDErrors) fakeSys.SetDistances("/fakeSysfs/devices/system/node/node0", "10", nil) nodes, cores, err := GetNodesInfo(fakeSys) assert.Nil(t, err) assert.Equal(t, 1, len(nodes)) assert.Equal(t, 1, cores) sort.Slice(nodes, func(i, j int) bool { return nodes[i].Id < nodes[j].Id }) nodesJSON, err := json.Marshal(nodes) assert.Nil(t, err) expectedNodes := `[ { "node_id":0, "memory":33604804608, "distances" : [ 10 ], "hugepages":[ { "page_size":2048, "num_pages":1 } ], "cores":[ { "core_id":0, "thread_ids":[ 0 ], "caches":null, "socket_id":0, "uncore_caches": null } ], "caches": null } ]` assert.JSONEq(t, expectedNodes, string(nodesJSON)) } func TestGetNodeMemInfo(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} memTotal := "MemTotal: 32817192 kB" fakeSys.SetMemory(memTotal, nil) mem, err := getNodeMemInfo(fakeSys, "/fakeSysfs/devices/system/node/node0") assert.Nil(t, err) assert.Equal(t, uint64(32817192*1024), mem) } func TestGetNodeMemInfoWithMissingMemTotaInMemInfo(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} memTotal := "MemXXX: 32817192 kB" fakeSys.SetMemory(memTotal, nil) mem, err := getNodeMemInfo(fakeSys, "/fakeSysfs/devices/system/node/node0") assert.NotNil(t, err) assert.Equal(t, uint64(0), mem) } func TestGetNodeMemInfoWhenMemInfoMissing(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} memTotal := "" fakeSys.SetMemory(memTotal, fmt.Errorf("Cannot read meminfo file")) mem, err := getNodeMemInfo(fakeSys, "/fakeSysfs/devices/system/node/node0") assert.Nil(t, err) assert.Equal(t, uint64(0), mem) } func TestGetCoresInfoWhenCoreIDIsNotDigit(t *testing.T) { sysFs := &fakesysfs.FakeSysFs{} nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", } sysFs.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", }, } sysFs.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "abc", } sysFs.SetCoreThreads(coreThread, nil) cores, err := getCoresInfo(sysFs, []string{"/fakeSysfs/devices/system/node/node0/cpu0"}) assert.NotNil(t, err) assert.Equal(t, []info.Core(nil), cores) } func TestGetCoresInfoWithOnlineOfflineFile(t *testing.T) { sysFs := &fakesysfs.FakeSysFs{} nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", } sysFs.SetNodesPaths(nodesPaths, nil) cpusPaths := map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", }, } sysFs.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", } sysFs.SetCoreThreads(coreThread, nil) sysFs.SetOnlineCPUs(map[string]interface{}{"/fakeSysfs/devices/system/node/node0/cpu0": nil}) sysFs.SetPhysicalPackageIDs(map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", }, nil) cores, err := getCoresInfo( sysFs, []string{"/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1"}, ) assert.NoError(t, err) expected := []info.Core{ { Id: 0, Threads: []int{0}, Caches: nil, SocketID: 0, }, } assert.Equal(t, expected, cores) } func TestGetBlockDeviceInfo(t *testing.T) { fakeSys := fakesysfs.FakeSysFs{} disks, err := GetBlockDeviceInfo(&fakeSys) if err != nil { t.Errorf("expected call to GetBlockDeviceInfo() to succeed. Failed with %s", err) } if len(disks) != 1 { t.Errorf("expected to get one disk entry. Got %d", len(disks)) } key := "8:0" disk, ok := disks[key] if !ok { t.Fatalf("expected key 8:0 to exist in the disk map.") } if disk.Name != "sda" { t.Errorf("expected to get disk named sda. Got %q", disk.Name) } size := uint64(1234567 * 512) if disk.Size != size { t.Errorf("expected to get disk size of %d. Got %d", size, disk.Size) } if disk.Scheduler != "cfq" { t.Errorf("expected to get scheduler type of cfq. Got %q", disk.Scheduler) } } func TestGetNetworkDevices(t *testing.T) { fakeSys := fakesysfs.FakeSysFs{} fakeSys.SetEntryName("eth0") devs, err := GetNetworkDevices(&fakeSys) if err != nil { t.Errorf("expected call to GetNetworkDevices() to succeed. Failed with %s", err) } if len(devs) != 1 { t.Errorf("expected to get one network device. Got %d", len(devs)) } eth := devs[0] if eth.Name != "eth0" { t.Errorf("expected to find device with name eth0. Found name %q", eth.Name) } if eth.Mtu != 1024 { t.Errorf("expected mtu to be set to 1024. Found %d", eth.Mtu) } if eth.Speed != 1000 { t.Errorf("expected device speed to be set to 1000. Found %d", eth.Speed) } if eth.MacAddress != "42:01:02:03:04:f4" { t.Errorf("expected mac address to be '42:01:02:03:04:f4'. Found %q", eth.MacAddress) } } func TestIgnoredNetworkDevices(t *testing.T) { fakeSys := fakesysfs.FakeSysFs{} ignoredDevices := []string{"veth1234", "lo", "docker0", "nerdctl0"} for _, name := range ignoredDevices { fakeSys.SetEntryName(name) devs, err := GetNetworkDevices(&fakeSys) if err != nil { t.Errorf("expected call to GetNetworkDevices() to succeed. Failed with %s", err) } if len(devs) != 0 { t.Errorf("expected dev %s to be ignored, but got info %+v", name, devs) } } } func TestGetCacheInfo(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} cacheInfo := sysfs.CacheInfo{ Id: 0, Size: 1024, Type: "Data", Level: 3, Cpus: 16, } fakeSys.SetCacheInfo(cacheInfo) caches, err := GetCacheInfo(fakeSys, 0) if err != nil { t.Errorf("expected call to GetCacheInfo() to succeed. Failed with %s", err) } if len(caches) != 1 { t.Errorf("expected to get one cache. Got %d", len(caches)) } if caches[0] != cacheInfo { t.Errorf("expected to find cacheinfo %+v. Got %+v", cacheInfo, caches[0]) } } func TestGetNetworkStats(t *testing.T) { expectedStats := info.InterfaceStats{ Name: "eth0", RxBytes: 1024, RxPackets: 1024, RxErrors: 1024, RxDropped: 1024, TxBytes: 1024, TxPackets: 1024, TxErrors: 1024, TxDropped: 1024, } fakeSys := &fakesysfs.FakeSysFs{} netStats, err := getNetworkStats("eth0", fakeSys) if err != nil { t.Errorf("call to getNetworkStats() failed with %s", err) } if expectedStats != netStats { t.Errorf("expected to get stats %+v, got %+v", expectedStats, netStats) } } func TestGetSocketFromCPU(t *testing.T) { topology := []info.Node{ { Id: 0, Memory: 0, HugePages: nil, Cores: []info.Core{ { Id: 0, Threads: []int{0, 1}, Caches: nil, SocketID: 0, }, { Id: 1, Threads: []int{2, 3}, Caches: nil, SocketID: 0, }, }, Caches: nil, }, { Id: 1, Memory: 0, HugePages: nil, Cores: []info.Core{ { Id: 0, Threads: []int{4, 5}, Caches: nil, SocketID: 1, }, { Id: 1, Threads: []int{6, 7}, Caches: nil, SocketID: 1, }, }, Caches: nil, }, } socket := GetSocketFromCPU(topology, 6) assert.Equal(t, socket, 1) // Check if return "-1" when there is no data about passed CPU. socket = GetSocketFromCPU(topology, 8) assert.Equal(t, socket, -1) } func TestGetOnlineCPUs(t *testing.T) { topology := []info.Node{ { Id: 0, Memory: 0, HugePages: nil, Cores: []info.Core{ { Id: 0, Threads: []int{0, 1}, Caches: nil, SocketID: 0, }, { Id: 1, Threads: []int{2, 3}, Caches: nil, SocketID: 0, }, }, Caches: nil, }, { Id: 1, Memory: 0, HugePages: nil, Cores: []info.Core{ { Id: 0, Threads: []int{4, 5}, Caches: nil, SocketID: 1, }, { Id: 1, Threads: []int{6, 7}, Caches: nil, SocketID: 1, }, }, Caches: nil, }, } onlineCPUs := GetOnlineCPUs(topology) assert.Equal(t, onlineCPUs, []int{0, 1, 2, 3, 4, 5, 6, 7}) } func TestGetNodesInfoWithUncoreCacheInfo(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} c := sysfs.CacheInfo{ Id: 0, Size: 32 * 1024, Type: "unified", Level: 3, Cpus: 8, } fakeSys.SetCacheInfo(c) nodesPaths := []string{ "/fakeSysfs/devices/system/node/node0", "/fakeSysfs/devices/system/node/node1", } fakeSys.SetNodesPaths(nodesPaths, nil) memTotal := "MemTotal: 32817192 kB" fakeSys.SetMemory(memTotal, nil) cpusPaths := map[string][]string{ "/fakeSysfs/devices/system/node/node0": { "/fakeSysfs/devices/system/node/node0/cpu0", "/fakeSysfs/devices/system/node/node0/cpu1", }, "/fakeSysfs/devices/system/node/node1": { "/fakeSysfs/devices/system/node/node0/cpu2", "/fakeSysfs/devices/system/node/node0/cpu3", }, } fakeSys.SetCPUsPaths(cpusPaths, nil) coreThread := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", } fakeSys.SetCoreThreads(coreThread, nil) physicalPackageIDs := map[string]string{ "/fakeSysfs/devices/system/node/node0/cpu0": "0", "/fakeSysfs/devices/system/node/node0/cpu1": "0", "/fakeSysfs/devices/system/node/node0/cpu2": "1", "/fakeSysfs/devices/system/node/node0/cpu3": "1", } fakeSys.SetPhysicalPackageIDs(physicalPackageIDs, nil) fakeSys.SetDistances("/fakeSysfs/devices/system/node/node0", "10 11", nil) fakeSys.SetDistances("/fakeSysfs/devices/system/node/node1", "11 10", nil) nodes, cores, err := GetNodesInfo(fakeSys) assert.Nil(t, err) fmt.Println(err) assert.Equal(t, 2, len(nodes)) assert.Equal(t, 4, cores) nodesJSON, err := json.Marshal(nodes) assert.Nil(t, err) expectedNodes := ` [ { "node_id": 0, "memory": 33604804608, "distances" : [ 10, 11 ], "hugepages": null, "cores": [ { "core_id": 0, "thread_ids": [ 0, 1 ], "caches": null, "uncore_caches": [ { "id": 0, "size": 32768, "type": "unified", "level": 3 } ], "socket_id": 0 } ], "caches": null }, { "node_id": 1, "memory": 33604804608, "distances" : [ 11, 10 ], "hugepages": null, "cores": [ { "core_id": 1, "thread_ids": [ 2, 3 ], "caches": null, "uncore_caches": [ { "id": 0, "size": 32768, "type": "unified", "level": 3 } ], "socket_id": 1 } ], "caches": null } ]` assert.JSONEq(t, expectedNodes, string(nodesJSON)) } func TestGetDistances(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} node := "/fakeSysfs/devices/system/node/node0" fakeSys.SetDistances(node, "10 11", nil) distances, err := getDistances(fakeSys, node) assert.Nil(t, err) assert.Len(t, distances, 2) assert.Equal(t, uint64(10), distances[0]) assert.Equal(t, uint64(11), distances[1]) } func TestGetDistancesMissingDistances(t *testing.T) { fakeSys := &fakesysfs.FakeSysFs{} node := "/fakeSysfs/devices/system/node/node0" fakeSys.SetDistances(node, "10 11", fmt.Errorf("no distances file")) distances, err := getDistances(fakeSys, node) assert.Nil(t, err) assert.Len(t, distances, 0) } ================================================ FILE: utils/timed_store.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils import ( "sort" "time" ) type timedStoreDataSlice []timedStoreData func (t timedStoreDataSlice) Less(i, j int) bool { return t[i].timestamp.Before(t[j].timestamp) } func (t timedStoreDataSlice) Len() int { return len(t) } func (t timedStoreDataSlice) Swap(i, j int) { t[i], t[j] = t[j], t[i] } // A time-based buffer for ContainerStats. // Holds information for a specific time period and/or a max number of items. type TimedStore struct { buffer timedStoreDataSlice age time.Duration maxItems int } type timedStoreData struct { timestamp time.Time data interface{} } // Returns a new thread-compatible TimedStore. // A maxItems value of -1 means no limit. func NewTimedStore(age time.Duration, maxItems int) *TimedStore { return &TimedStore{ buffer: make(timedStoreDataSlice, 0), age: age, maxItems: maxItems, } } // Adds an element to the start of the buffer (removing one from the end if necessary). func (s *TimedStore) Add(timestamp time.Time, item interface{}) { data := timedStoreData{ timestamp: timestamp, data: item, } // Common case: data is added in order. if len(s.buffer) == 0 || !timestamp.Before(s.buffer[len(s.buffer)-1].timestamp) { s.buffer = append(s.buffer, data) } else { // Data is out of order; insert it in the correct position. index := sort.Search(len(s.buffer), func(index int) bool { return s.buffer[index].timestamp.After(timestamp) }) s.buffer = append(s.buffer, timedStoreData{}) // Make room to shift the elements copy(s.buffer[index+1:], s.buffer[index:]) // Shift the elements over s.buffer[index] = data } // Remove any elements before eviction time. // TODO(rjnagal): This is assuming that the added entry has timestamp close to now. evictTime := timestamp.Add(-s.age) index := sort.Search(len(s.buffer), func(index int) bool { return s.buffer[index].timestamp.After(evictTime) }) if index < len(s.buffer) { s.buffer = s.buffer[index:] } // Remove any elements if over our max size. if s.maxItems >= 0 && len(s.buffer) > s.maxItems { startIndex := len(s.buffer) - s.maxItems s.buffer = s.buffer[startIndex:] } } // Returns up to maxResult elements in the specified time period (inclusive). // Results are from first to last. maxResults of -1 means no limit. func (s *TimedStore) InTimeRange(start, end time.Time, maxResults int) []interface{} { // No stats, return empty. if len(s.buffer) == 0 { return []interface{}{} } var startIndex int if start.IsZero() { // None specified, start at the beginning. startIndex = len(s.buffer) - 1 } else { // Start is the index before the elements smaller than it. We do this by // finding the first element smaller than start and taking the index // before that element startIndex = sort.Search(len(s.buffer), func(index int) bool { // buffer[index] < start return s.getData(index).timestamp.Before(start) }) - 1 // Check if start is after all the data we have. if startIndex < 0 { return []interface{}{} } } var endIndex int if end.IsZero() { // None specified, end with the latest stats. endIndex = 0 } else { // End is the first index smaller than or equal to it (so, not larger). endIndex = sort.Search(len(s.buffer), func(index int) bool { // buffer[index] <= t -> !(buffer[index] > t) return !s.getData(index).timestamp.After(end) }) // Check if end is before all the data we have. if endIndex == len(s.buffer) { return []interface{}{} } } // Trim to maxResults size. numResults := startIndex - endIndex + 1 if maxResults != -1 && numResults > maxResults { startIndex -= numResults - maxResults numResults = maxResults } // Return in sorted timestamp order so from the "back" to "front". result := make([]interface{}, numResults) for i := 0; i < numResults; i++ { result[i] = s.Get(startIndex - i) } return result } // Gets the element at the specified index. Note that elements are output in LIFO order. func (s *TimedStore) Get(index int) interface{} { return s.getData(index).data } // Gets the data at the specified index. Note that elements are output in LIFO order. func (s *TimedStore) getData(index int) timedStoreData { return s.buffer[len(s.buffer)-index-1] } func (s *TimedStore) Size() int { return len(s.buffer) } ================================================ FILE: utils/timed_store_test.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils import ( "testing" "time" "github.com/stretchr/testify/assert" ) func createTime(id int) time.Time { var zero time.Time return zero.Add(time.Duration(id+1) * time.Second) } func expectSize(t *testing.T, sb *TimedStore, expectedSize int) { if sb.Size() != expectedSize { t.Errorf("Expected size %v, got %v", expectedSize, sb.Size()) } } func expectAllElements(t *testing.T, sb *TimedStore, expected []int) { size := sb.Size() els := make([]interface{}, size) for i := 0; i < size; i++ { els[i] = sb.Get(size - i - 1) } expectElements(t, []interface{}(els), expected) } func expectElements(t *testing.T, actual []interface{}, expected []int) { if len(actual) != len(expected) { t.Errorf("Expected elements %v, got %v", expected, actual) return } for i, el := range actual { if el.(int) != expected[i] { t.Errorf("Expected elements %v, got %v", expected, actual) return } } } func TestAdd(t *testing.T) { sb := NewTimedStore(5*time.Second, 100) // Add 1. sb.Add(createTime(0), 0) expectSize(t, sb, 1) expectAllElements(t, sb, []int{0}) // Fill the buffer. for i := 1; i <= 5; i++ { expectSize(t, sb, i) sb.Add(createTime(i), i) } expectSize(t, sb, 5) expectAllElements(t, sb, []int{1, 2, 3, 4, 5}) // Add more than is available in the buffer sb.Add(createTime(6), 6) expectSize(t, sb, 5) expectAllElements(t, sb, []int{2, 3, 4, 5, 6}) // Replace all elements. for i := 7; i <= 10; i++ { sb.Add(createTime(i), i) } expectSize(t, sb, 5) expectAllElements(t, sb, []int{6, 7, 8, 9, 10}) } func TestGet(t *testing.T) { sb := NewTimedStore(5*time.Second, -1) sb.Add(createTime(1), 1) sb.Add(createTime(2), 2) sb.Add(createTime(3), 3) expectSize(t, sb, 3) assert := assert.New(t) assert.Equal(sb.Get(0).(int), 3) assert.Equal(sb.Get(1).(int), 2) assert.Equal(sb.Get(2).(int), 1) } func TestInTimeRange(t *testing.T) { sb := NewTimedStore(5*time.Second, -1) assert := assert.New(t) var empty time.Time // No elements. assert.Empty(sb.InTimeRange(createTime(0), createTime(5), 10)) assert.Empty(sb.InTimeRange(createTime(0), empty, 10)) assert.Empty(sb.InTimeRange(empty, createTime(5), 10)) assert.Empty(sb.InTimeRange(empty, empty, 10)) // One element. sb.Add(createTime(1), 1) expectSize(t, sb, 1) expectElements(t, sb.InTimeRange(createTime(0), createTime(5), 10), []int{1}) expectElements(t, sb.InTimeRange(createTime(1), createTime(5), 10), []int{1}) expectElements(t, sb.InTimeRange(createTime(0), createTime(1), 10), []int{1}) expectElements(t, sb.InTimeRange(createTime(1), createTime(1), 10), []int{1}) assert.Empty(sb.InTimeRange(createTime(2), createTime(5), 10)) // Two element. sb.Add(createTime(2), 2) expectSize(t, sb, 2) expectElements(t, sb.InTimeRange(createTime(0), createTime(5), 10), []int{1, 2}) expectElements(t, sb.InTimeRange(createTime(1), createTime(5), 10), []int{1, 2}) expectElements(t, sb.InTimeRange(createTime(0), createTime(2), 10), []int{1, 2}) expectElements(t, sb.InTimeRange(createTime(1), createTime(2), 10), []int{1, 2}) expectElements(t, sb.InTimeRange(createTime(1), createTime(1), 10), []int{1}) expectElements(t, sb.InTimeRange(createTime(2), createTime(2), 10), []int{2}) assert.Empty(sb.InTimeRange(createTime(3), createTime(5), 10)) // Many elements. sb.Add(createTime(3), 3) sb.Add(createTime(4), 4) expectSize(t, sb, 4) expectElements(t, sb.InTimeRange(createTime(0), createTime(5), 10), []int{1, 2, 3, 4}) expectElements(t, sb.InTimeRange(createTime(0), createTime(5), 10), []int{1, 2, 3, 4}) expectElements(t, sb.InTimeRange(createTime(1), createTime(5), 10), []int{1, 2, 3, 4}) expectElements(t, sb.InTimeRange(createTime(0), createTime(4), 10), []int{1, 2, 3, 4}) expectElements(t, sb.InTimeRange(createTime(1), createTime(4), 10), []int{1, 2, 3, 4}) expectElements(t, sb.InTimeRange(createTime(0), createTime(2), 10), []int{1, 2}) expectElements(t, sb.InTimeRange(createTime(1), createTime(2), 10), []int{1, 2}) expectElements(t, sb.InTimeRange(createTime(2), createTime(3), 10), []int{2, 3}) expectElements(t, sb.InTimeRange(createTime(3), createTime(4), 10), []int{3, 4}) expectElements(t, sb.InTimeRange(createTime(3), createTime(5), 10), []int{3, 4}) assert.Empty(sb.InTimeRange(createTime(5), createTime(5), 10)) // Start and end time does't ignore maxResults. expectElements(t, sb.InTimeRange(createTime(1), createTime(5), 1), []int{4}) // No start time. expectElements(t, sb.InTimeRange(empty, createTime(5), 10), []int{1, 2, 3, 4}) expectElements(t, sb.InTimeRange(empty, createTime(4), 10), []int{1, 2, 3, 4}) expectElements(t, sb.InTimeRange(empty, createTime(3), 10), []int{1, 2, 3}) expectElements(t, sb.InTimeRange(empty, createTime(2), 10), []int{1, 2}) expectElements(t, sb.InTimeRange(empty, createTime(1), 10), []int{1}) // No end time. expectElements(t, sb.InTimeRange(createTime(0), empty, 10), []int{1, 2, 3, 4}) expectElements(t, sb.InTimeRange(createTime(1), empty, 10), []int{1, 2, 3, 4}) expectElements(t, sb.InTimeRange(createTime(2), empty, 10), []int{2, 3, 4}) expectElements(t, sb.InTimeRange(createTime(3), empty, 10), []int{3, 4}) expectElements(t, sb.InTimeRange(createTime(4), empty, 10), []int{4}) // No start or end time. expectElements(t, sb.InTimeRange(empty, empty, 10), []int{1, 2, 3, 4}) // Start after data. assert.Empty(sb.InTimeRange(createTime(5), createTime(5), 10)) assert.Empty(sb.InTimeRange(createTime(5), empty, 10)) // End before data. assert.Empty(sb.InTimeRange(createTime(0), createTime(0), 10)) assert.Empty(sb.InTimeRange(empty, createTime(0), 10)) } func TestInTimeRangeWithLimit(t *testing.T) { sb := NewTimedStore(5*time.Second, -1) sb.Add(createTime(1), 1) sb.Add(createTime(2), 2) sb.Add(createTime(3), 3) sb.Add(createTime(4), 4) expectSize(t, sb, 4) var empty time.Time // Limit cuts off from latest timestamp. expectElements(t, sb.InTimeRange(empty, empty, 4), []int{1, 2, 3, 4}) expectElements(t, sb.InTimeRange(empty, empty, 3), []int{2, 3, 4}) expectElements(t, sb.InTimeRange(empty, empty, 2), []int{3, 4}) expectElements(t, sb.InTimeRange(empty, empty, 1), []int{4}) assert.Empty(t, sb.InTimeRange(empty, empty, 0)) } func TestLimitedSize(t *testing.T) { sb := NewTimedStore(time.Hour, 5) // Add 1. sb.Add(createTime(0), 0) expectSize(t, sb, 1) expectAllElements(t, sb, []int{0}) // Fill the buffer. for i := 1; i <= 5; i++ { expectSize(t, sb, i) sb.Add(createTime(i), i) } expectSize(t, sb, 5) expectAllElements(t, sb, []int{1, 2, 3, 4, 5}) // Add more than is available in the buffer sb.Add(createTime(6), 6) expectSize(t, sb, 5) expectAllElements(t, sb, []int{2, 3, 4, 5, 6}) // Replace all elements. for i := 7; i <= 10; i++ { sb.Add(createTime(i), i) } expectSize(t, sb, 5) expectAllElements(t, sb, []int{6, 7, 8, 9, 10}) } ================================================ FILE: utils/utils.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils import "fmt" // Returns a mask of all cores on the machine if the passed-in mask is empty. func FixCpuMask(mask string, cores int) string { if mask == "" { if cores > 1 { mask = fmt.Sprintf("0-%d", cores-1) } else { mask = "0" } } return mask } ================================================ FILE: validate/validate.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux // Handler for /validate content. // Validates cadvisor dependencies - kernel, os, docker setup. package validate import ( "fmt" "log" "net/http" "os" "path" "strings" "github.com/google/cadvisor/container/docker" "github.com/google/cadvisor/manager" "github.com/google/cadvisor/utils" "github.com/opencontainers/cgroups" ) const ( ValidatePage = "/validate/" Supported = "[Supported, but not recommended]" Unsupported = "[Unsupported]" Recommended = "[Supported and recommended]" Unknown = "[Unknown]" VersionFormat = "%d.%d%s" OutputFormat = "%s: %s\n\t%s\n\n" ) func getMajorMinor(version string) (int, int, error) { var major, minor int var ign string n, err := fmt.Sscanf(version, VersionFormat, &major, &minor, &ign) if n != 3 || err != nil { log.Printf("Failed to parse version for %s", version) return -1, -1, err } return major, minor, nil } func validateKernelVersion(version string) (string, string) { desc := fmt.Sprintf("Kernel version is %s. Versions >= 2.6 are supported. 3.0+ are recommended.\n", version) major, minor, err := getMajorMinor(version) if err != nil { desc = fmt.Sprintf("Could not parse kernel version. %s", desc) return Unknown, desc } if major < 2 { return Unsupported, desc } if major == 2 && minor < 6 { return Unsupported, desc } if major >= 3 { return Recommended, desc } return Supported, desc } func validateDockerVersion(version string) (string, string) { desc := fmt.Sprintf("Docker version is %s. Versions >= 1.0 are supported. 1.2+ are recommended.\n", version) major, minor, err := getMajorMinor(version) if err != nil { desc = fmt.Sprintf("Could not parse docker version. %s\n\t", desc) return Unknown, desc } if major < 1 { return Unsupported, desc } if major == 1 && minor < 2 { return Supported, desc } return Recommended, desc } func getEnabledCgroups() (map[string]int, error) { out, err := os.ReadFile("/proc/cgroups") if err != nil { return nil, err } cgroups := make(map[string]int) for i, line := range strings.Split(string(out), "\n") { var cgroup string var ign, enabled int if i == 0 || line == "" { continue } n, err := fmt.Sscanf(line, "%s %d %d %d", &cgroup, &ign, &ign, &enabled) if n != 4 || err != nil { if err == nil { err = fmt.Errorf("failed to parse /proc/cgroup entry %s", line) } return nil, err } cgroups[cgroup] = enabled } return cgroups, nil } func areCgroupsPresent(available map[string]int, desired []string) (bool, string) { for _, cgroup := range desired { enabled, ok := available[cgroup] if !ok { reason := fmt.Sprintf("Missing cgroup %s. Available cgroups: %v\n", cgroup, available) return false, reason } if enabled != 1 { reason := fmt.Sprintf("Cgroup %s not enabled. Available cgroups: %v\n", cgroup, available) return false, reason } } return true, "" } func validateCPUCFSBandwidth(availableCgroups map[string]int) string { ok, _ := areCgroupsPresent(availableCgroups, []string{"cpu"}) if !ok { return "\tCpu cfs bandwidth status unknown: cpu cgroup not enabled.\n" } mnt, err := cgroups.FindCgroupMountpoint("/", "cpu") if err != nil { return "\tCpu cfs bandwidth status unknown: cpu cgroup not mounted.\n" } _, err = os.Stat(path.Join(mnt, "cpu.cfs_period_us")) if os.IsNotExist(err) { return "\tCpu cfs bandwidth is disabled. Recompile kernel with \"CONFIG_CFS_BANDWIDTH\" enabled.\n" } return "\tCpu cfs bandwidth is enabled.\n" } func validateMemoryAccounting(availableCgroups map[string]int) string { ok, _ := areCgroupsPresent(availableCgroups, []string{"memory"}) if !ok { return "\tHierarchical memory accounting status unknown: memory cgroup not enabled.\n" } var enabled int if cgroups.IsCgroup2UnifiedMode() { enabled = 1 } else { mnt, err := cgroups.FindCgroupMountpoint("/", "memory") if err != nil { return "\tHierarchical memory accounting status unknown: memory cgroup not mounted.\n" } hier, err := os.ReadFile(path.Join(mnt, "memory.use_hierarchy")) if err != nil { return "\tHierarchical memory accounting status unknown: hierarchy interface unavailable.\n" } n, err := fmt.Sscanf(string(hier), "%d", &enabled) if err != nil || n != 1 { return "\tHierarchical memory accounting status unknown: hierarchy interface unreadable.\n" } } if enabled == 1 { return "\tHierarchical memory accounting enabled. Reported memory usage includes memory used by child containers.\n" } return "\tHierarchical memory accounting disabled. Memory usage does not include usage from child containers.\n" } func validateCgroups() (string, string) { requiredCgroups := []string{"cpu", "cpuacct"} recommendedCgroups := []string{"memory", "blkio", "cpuset", "devices", "freezer"} availableCgroups, err := getEnabledCgroups() desc := fmt.Sprintf("\tFollowing cgroups are required: %v\n\tFollowing other cgroups are recommended: %v\n", requiredCgroups, recommendedCgroups) if err != nil { desc = fmt.Sprintf("Could not parse /proc/cgroups.\n%s", desc) return Unknown, desc } ok, out := areCgroupsPresent(availableCgroups, requiredCgroups) if !ok { out += desc return Unsupported, out } ok, out = areCgroupsPresent(availableCgroups, recommendedCgroups) if !ok { // supported, but not recommended. out += desc return Supported, out } out = fmt.Sprintf("Available cgroups: %v\n", availableCgroups) out += desc out += validateMemoryAccounting(availableCgroups) out += validateCPUCFSBandwidth(availableCgroups) return Recommended, out } func validateDockerInfo() (string, string) { info, err := docker.ValidateInfo(docker.Info, docker.VersionString) if err != nil { return Unsupported, fmt.Sprintf("Docker setup is invalid: %v", err) } desc := fmt.Sprintf("Storage driver is %s.\n", info.Driver) return Recommended, desc } func validateCgroupMounts() (string, string) { const recommendedMount = "/sys/fs/cgroup" desc := fmt.Sprintf("\tAny cgroup mount point that is detectible and accessible is supported. %s is recommended as a standard location.\n", recommendedMount) mnt, err := cgroups.FindCgroupMountpoint("/", "cpu") if err != nil { out := "Could not locate cgroup mount point.\n" out += desc return Unknown, out } mnt = path.Dir(mnt) if !utils.FileExists(mnt) { out := fmt.Sprintf("Cgroup mount directory %s inaccessible.\n", mnt) out += desc return Unsupported, out } mounts, err := os.ReadDir(mnt) if err != nil { out := fmt.Sprintf("Could not read cgroup mount directory %s.\n", mnt) out += desc return Unsupported, out } mountNames := "\tCgroup mount directories: " for _, mount := range mounts { mountNames += mount.Name() + " " } mountNames += "\n" out := fmt.Sprintf("Cgroups are mounted at %s.\n", mnt) out += mountNames out += desc info, err := os.ReadFile("/proc/mounts") if err != nil { out := "Could not read /proc/mounts.\n" out += desc return Unsupported, out } out += "\tCgroup mounts:\n" for _, line := range strings.Split(string(info), "\n") { if strings.Contains(line, " cgroup ") { out += "\t" + line + "\n" } } if mnt == recommendedMount { return Recommended, out } return Supported, out } func validateIoScheduler(containerManager manager.Manager) (string, string) { var desc string mi, err := containerManager.GetMachineInfo() if err != nil { return Unknown, "Machine info not available\n\t" } cfq := false for _, disk := range mi.DiskMap { desc += fmt.Sprintf("\t Disk %q Scheduler type %q.\n", disk.Name, disk.Scheduler) if disk.Scheduler == "cfq" { cfq = true } } // Since we get lot of random block devices, report recommended if // at least one of them is on cfq. Report Supported otherwise. if cfq { desc = "At least one device supports 'cfq' I/O scheduler. Some disk stats can be reported.\n" + desc return Recommended, desc } desc = "None of the devices support 'cfq' I/O scheduler. No disk stats can be reported.\n" + desc return Supported, desc } func HandleRequest(w http.ResponseWriter, containerManager manager.Manager) error { // Get cAdvisor version Info. versionInfo, err := containerManager.GetVersionInfo() if err != nil { return err } out := fmt.Sprintf("cAdvisor version: %s\n\n", versionInfo.CadvisorVersion) // No OS is preferred or unsupported as of now. out += fmt.Sprintf("OS version: %s\n\n", versionInfo.ContainerOsVersion) kernelValidation, desc := validateKernelVersion(versionInfo.KernelVersion) out += fmt.Sprintf(OutputFormat, "Kernel version", kernelValidation, desc) cgroupValidation, desc := validateCgroups() out += fmt.Sprintf(OutputFormat, "Cgroup setup", cgroupValidation, desc) mountsValidation, desc := validateCgroupMounts() out += fmt.Sprintf(OutputFormat, "Cgroup mount setup", mountsValidation, desc) dockerValidation, desc := validateDockerVersion(versionInfo.DockerVersion) out += fmt.Sprintf(OutputFormat, "Docker version", dockerValidation, desc) dockerInfoValidation, desc := validateDockerInfo() out += fmt.Sprintf(OutputFormat, "Docker driver setup", dockerInfoValidation, desc) ioSchedulerValidation, desc := validateIoScheduler(containerManager) out += fmt.Sprintf(OutputFormat, "Block device setup", ioSchedulerValidation, desc) // Output debug info. debugInfo := containerManager.DebugInfo() for category, lines := range debugInfo { out += fmt.Sprintf(OutputFormat, category, "", strings.Join(lines, "\n\t")) } _, err = w.Write([]byte(out)) return err } ================================================ FILE: validate/validate_test.go ================================================ // Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build linux package validate import ( "fmt" "strings" "testing" ) var ( standardDesc = "Versions >= %s are supported. %s+ are recommended" dockerStandardDesc = fmt.Sprintf(standardDesc, "1.0", "1.2") kernelStandardDesc = fmt.Sprintf(standardDesc, "2.6", "3.0") dockerErrorDesc = "Could not parse docker version" kernelErrorDesc = "Could not parse kernel version" ) func TestGetMajorMinor(t *testing.T) { cases := []struct { version string major int minor int err error }{ {"0.1beta", 0, 1, nil}, {"0.1.2", 0, 1, nil}, {"-1.-1beta", -1, -1, nil}, {"0.1", -1, -1, fmt.Errorf("have error")}, {"0", -1, -1, fmt.Errorf("have error")}, {"beta", -1, -1, fmt.Errorf("have error")}, } for i, c := range cases { ma, mi, e := getMajorMinor(c.version) if (e != nil) != (c.err != nil) { t.Errorf("[%d] Unexpected err, should %v, but got %v", i, c.err, e) } if ma != c.major { t.Errorf("[%d] Unexpected major, should %v, but got %v", i, c.major, ma) } if mi != c.minor { t.Errorf("[%d] Unexpected minor, should %v, but got %v", i, c.minor, mi) } } } func TestValidateKernelVersion(t *testing.T) { cases := []struct { version string result string desc string }{ {"2.6.3", Supported, kernelStandardDesc}, {"3.6.3", Recommended, kernelStandardDesc}, {"1.0beta", Unsupported, kernelStandardDesc}, {"0.1beta", Unsupported, kernelStandardDesc}, {"0.1", Unknown, kernelErrorDesc}, {"3.1", Unknown, kernelErrorDesc}, } for i, c := range cases { res, desc := validateKernelVersion(c.version) if res != c.result { t.Errorf("[%d] Unexpected result, should %v, but got %v", i, c.result, res) } if !strings.Contains(desc, c.desc) { t.Errorf("[%d] Unexpected description, should %v, but got %v", i, c.desc, desc) } } } func TestValidateDockerVersion(t *testing.T) { cases := []struct { version string result string desc string }{ {"1.1.3", Supported, dockerStandardDesc}, {"1.6.3", Recommended, dockerStandardDesc}, {"1.0beta", Supported, dockerStandardDesc}, {"0.1beta", Unsupported, dockerStandardDesc}, {"0.1", Unknown, dockerErrorDesc}, {"1.6", Unknown, dockerErrorDesc}, } for i, c := range cases { res, desc := validateDockerVersion(c.version) if res != c.result { t.Errorf("[%d] Unexpected result, should %v, but got %v", i, c.result, res) } if !strings.Contains(desc, c.desc) { t.Errorf("[%d] Unexpected description, should %v, but got %v", i, c.desc, desc) } } } func TestAreCgroupsPresent(t *testing.T) { cases := []struct { available map[string]int desired []string result bool reason string }{ {map[string]int{"memory": 1}, []string{"memory"}, true, ""}, {map[string]int{"memory": 2}, []string{"memory"}, false, "memory not enabled. Available cgroups"}, {map[string]int{"memory": 0}, []string{"memory"}, false, "memory not enabled. Available cgroups"}, {map[string]int{"memory": 1}, []string{"blkio"}, false, "Missing cgroup blkio. Available cgroups"}, } for i, c := range cases { result, reason := areCgroupsPresent(c.available, c.desired) if result != c.result { t.Errorf("[%d] Unexpected result, should %v, but got %v", i, c.result, result) } if (c.reason == "" && reason != "") || (c.reason != "" && !strings.Contains(reason, c.reason)) { t.Errorf("[%d] Unexpected result, should %v, but got %v", i, c.reason, reason) } } } ================================================ FILE: version/version.go ================================================ // Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package version // Build information. Populated at build-time. var ( Version string Revision string Branch string BuildUser string BuildDate string GoVersion string ) // Info provides the iterable version information. var Info = map[string]string{ "version": Version, "revision": Revision, "branch": Branch, "buildUser": BuildUser, "buildDate": BuildDate, "goVersion": GoVersion, } ================================================ FILE: watcher/watcher.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package container defines types for sub-container events and also // defines an interface for container operation handlers. package watcher // SubcontainerEventType indicates an addition or deletion event. type ContainerEventType int const ( ContainerAdd ContainerEventType = iota ContainerDelete ) type ContainerWatchSource int const ( Raw ContainerWatchSource = iota ) // ContainerEvent represents a type ContainerEvent struct { // The type of event that occurred. EventType ContainerEventType // The full container name of the container where the event occurred. Name string // The watcher that detected this change event WatchSource ContainerWatchSource } type ContainerWatcher interface { // Registers a channel to listen for events affecting subcontainers (recursively). Start(events chan ContainerEvent) error // Stops watching for subcontainer changes. Stop() error } ================================================ FILE: zfs/watcher.go ================================================ // Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zfs import ( "fmt" "sync/atomic" "time" zfs "github.com/mistifyio/go-zfs" "k8s.io/klog/v2" ) // usageCache is a typed wrapper around atomic.Value that eliminates the need // for type assertions at every call site. It stores filesystem name strings // mapped to usage values (uint64). type usageCache struct { v atomic.Value } // Load retrieves the current cache map. func (c *usageCache) Load() map[string]uint64 { return c.v.Load().(map[string]uint64) } // Store saves a new cache map. func (c *usageCache) Store(m map[string]uint64) { c.v.Store(m) } // zfsWatcher maintains a cache of filesystem -> usage stats for a // zfs filesystem type ZfsWatcher struct { filesystem string cache usageCache period time.Duration stopChan chan struct{} } // NewThinPoolWatcher returns a new ThinPoolWatcher for the given devicemapper // thin pool name and metadata device or an error. func NewZfsWatcher(filesystem string) (*ZfsWatcher, error) { w := &ZfsWatcher{ filesystem: filesystem, period: 15 * time.Second, stopChan: make(chan struct{}), } w.cache.Store(map[string]uint64{}) return w, nil } // Start starts the ZfsWatcher. func (w *ZfsWatcher) Start() { err := w.Refresh() if err != nil { klog.Errorf("encountered error refreshing zfs watcher: %v", err) } for { select { case <-w.stopChan: return case <-time.After(w.period): start := time.Now() err = w.Refresh() if err != nil { klog.Errorf("encountered error refreshing zfs watcher: %v", err) } // print latency for refresh duration := time.Since(start) klog.V(5).Infof("zfs(%d) took %s", start.Unix(), duration) } } } // Stop stops the ZfsWatcher. func (w *ZfsWatcher) Stop() { close(w.stopChan) } // GetUsage gets the cached usage value of the given filesystem. func (w *ZfsWatcher) GetUsage(filesystem string) (uint64, error) { cache := w.cache.Load() v, ok := cache[filesystem] if !ok { return 0, fmt.Errorf("no cached value for usage of filesystem %v", filesystem) } return v, nil } // Refresh performs a zfs get func (w *ZfsWatcher) Refresh() error { parent, err := zfs.GetDataset(w.filesystem) if err != nil { klog.Errorf("encountered error getting zfs filesystem: %s: %v", w.filesystem, err) return err } children, err := parent.Children(0) if err != nil { klog.Errorf("encountered error getting children of zfs filesystem: %s: %v", w.filesystem, err) return err } newCache := make(map[string]uint64) for _, ds := range children { newCache[ds.Name] = ds.Used } w.cache.Store(newCache) return nil }