Merge "Add solver for april tag mapping"
diff --git a/WORKSPACE b/WORKSPACE
index 6ef1eb9..172e7bb 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1266,11 +1266,22 @@
url = "https://www.frc971.org/Build-Dependencies/aws_sdk-19.0.0-RC1.tar.gz",
)
+# Source code of LZ4 (files under lib/) are under BSD 2-Clause.
+# The rest of the repository (build information, documentation, etc.) is under GPLv2.
+# We only care about the lib/ subfolder anyways, and strip out any other files.
+http_archive(
+ name = "com_github_lz4_lz4",
+ build_file = "//debian:BUILD.lz4.bazel",
+ sha256 = "0b0e3aa07c8c063ddf40b082bdf7e37a1562bda40a0ff5272957f3e987e0e54b",
+ strip_prefix = "lz4-1.9.4/lib",
+ url = "https://github.com/lz4/lz4/archive/refs/tags/v1.9.4.tar.gz",
+)
+
http_file(
name = "com_github_foxglove_mcap_mcap",
executable = True,
- sha256 = "cf4dfcf71e20a60406aaded03a165312c1ca535b509ead90eb1846fc598137d2",
- urls = ["https://github.com/foxglove/mcap/releases/download/releases%2Fmcap-cli%2Fv0.0.5/mcap-linux-amd64"],
+ sha256 = "ae745dd09cf4c9570c1c038a72630c07b073f0ed4b05983d64108ff748a40d3f",
+ urls = ["https://github.com/foxglove/mcap/releases/download/releases%2Fmcap-cli%2Fv0.0.22/mcap-linux-amd64"],
)
http_archive(
diff --git a/aos/BUILD b/aos/BUILD
index 596996b..164f40b 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -514,6 +514,7 @@
"configuration_test.cc",
],
data = [
+ "//aos/events:ping_fbs_reflection_out",
"//aos/events:pingpong_config",
"//aos/events:pong_fbs_reflection_out",
"//aos/testdata:test_configs",
@@ -521,6 +522,7 @@
target_compatible_with = ["@platforms//os:linux"],
deps = [
":configuration",
+ "//aos/events:ping_fbs",
"//aos/testing:flatbuffer_eq",
"//aos/testing:googletest",
"//aos/testing:path",
diff --git a/aos/configuration.cc b/aos/configuration.cc
index d5ac2a1..ad6fb54 100644
--- a/aos/configuration.cc
+++ b/aos/configuration.cc
@@ -68,7 +68,6 @@
}
} // namespace
-
// Define the compare and equal operators for Channel and Application so we can
// insert them in the btree below.
bool operator<(const FlatbufferDetachedBuffer<Channel> &lhs,
@@ -1594,5 +1593,30 @@
return channel->num_readers() + channel->num_senders();
}
+// Searches through configurations for schemas that include a certain type
+const reflection::Schema *GetSchema(const Configuration *config,
+ std::string_view schema_type) {
+ if (config->has_channels()) {
+ std::vector<flatbuffers::Offset<Channel>> channel_offsets;
+ for (const Channel *c : *config->channels()) {
+ if (schema_type == c->type()->string_view()) {
+ return c->schema();
+ }
+ }
+ }
+ return nullptr;
+}
+
+// Copy schema reflection into detached flatbuffer
+std::optional<FlatbufferDetachedBuffer<reflection::Schema>>
+GetSchemaDetachedBuffer(const Configuration *config,
+ std::string_view schema_type) {
+ const reflection::Schema *found_schema = GetSchema(config, schema_type);
+ if (found_schema == nullptr) {
+ return std::nullopt;
+ }
+ return RecursiveCopyFlatBuffer(found_schema);
+}
+
} // namespace configuration
} // namespace aos
diff --git a/aos/configuration.h b/aos/configuration.h
index 8515b18..4d84b23 100644
--- a/aos/configuration.h
+++ b/aos/configuration.h
@@ -212,7 +212,20 @@
// Returns the number of scratch buffers in the queue.
int QueueScratchBufferSize(const Channel *channel);
-// TODO(austin): GetSchema<T>(const Flatbuffer<Configuration> &config);
+// Searches through configurations for schemas that include a certain type.
+const reflection::Schema *GetSchema(const Configuration *config,
+ std::string_view schema_type);
+
+// GetSchema template
+template <typename T>
+const reflection::Schema *GetSchema(const Configuration *config) {
+ return GetSchema(config, T::GetFullyQualifiedName());
+}
+
+// Copy schema reflection into detached flatbuffer
+std::optional<FlatbufferDetachedBuffer<reflection::Schema>>
+GetSchemaDetachedBuffer(const Configuration *config,
+ std::string_view schema_type);
} // namespace configuration
@@ -222,6 +235,7 @@
const FlatbufferDetachedBuffer<Channel> &rhs);
bool operator==(const FlatbufferDetachedBuffer<Channel> &lhs,
const FlatbufferDetachedBuffer<Channel> &rhs);
+
} // namespace aos
#endif // AOS_CONFIGURATION_H_
diff --git a/aos/configuration_test.cc b/aos/configuration_test.cc
index fa74e20..fc45d88 100644
--- a/aos/configuration_test.cc
+++ b/aos/configuration_test.cc
@@ -1,6 +1,7 @@
#include "aos/configuration.h"
#include "absl/strings/strip.h"
+#include "aos/events/ping_generated.h"
#include "aos/json_to_flatbuffer.h"
#include "aos/testing/flatbuffer_eq.h"
#include "aos/testing/path.h"
@@ -1007,10 +1008,47 @@
JsonToFlatbuffer<Channel>(
"{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"num_readers\": 5, "
"\"num_senders\": 10 }");
-
EXPECT_EQ(QueueScratchBufferSize(&channel.message()), 15);
}
+// Tests that GetSchema returns schema of specified type
+TEST_F(ConfigurationTest, GetSchema) {
+ FlatbufferDetachedBuffer<Configuration> config =
+ ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
+ FlatbufferVector<reflection::Schema> expected_schema =
+ FileToFlatbuffer<reflection::Schema>(
+ ArtifactPath("aos/events/ping.bfbs"));
+ EXPECT_EQ(FlatbufferToJson(GetSchema(&config.message(), "aos.examples.Ping")),
+ FlatbufferToJson(expected_schema));
+ EXPECT_EQ(GetSchema(&config.message(), "invalid_name"), nullptr);
+}
+
+// Tests that GetSchema template returns schema of specified type
+TEST_F(ConfigurationTest, GetSchemaTemplate) {
+ FlatbufferDetachedBuffer<Configuration> config =
+ ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
+ FlatbufferVector<reflection::Schema> expected_schema =
+ FileToFlatbuffer<reflection::Schema>(
+ ArtifactPath("aos/events/ping.bfbs"));
+ EXPECT_EQ(FlatbufferToJson(GetSchema<aos::examples::Ping>(&config.message())),
+ FlatbufferToJson(expected_schema));
+}
+
+// Tests that GetSchemaDetachedBuffer returns detached buffer of specified type
+TEST_F(ConfigurationTest, GetSchemaDetachedBuffer) {
+ FlatbufferDetachedBuffer<Configuration> config =
+ ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
+ FlatbufferVector<reflection::Schema> expected_schema =
+ FileToFlatbuffer<reflection::Schema>(
+ ArtifactPath("aos/events/ping.bfbs"));
+ EXPECT_EQ(FlatbufferToJson(
+ GetSchemaDetachedBuffer(&config.message(), "aos.examples.Ping")
+ .value()),
+ FlatbufferToJson(expected_schema));
+ EXPECT_EQ(GetSchemaDetachedBuffer(&config.message(), "invalid_name"),
+ std::nullopt);
+}
+
} // namespace testing
} // namespace configuration
} // namespace aos
diff --git a/aos/events/event_loop_runtime.rs b/aos/events/event_loop_runtime.rs
index 360c931..023cfb6 100644
--- a/aos/events/event_loop_runtime.rs
+++ b/aos/events/event_loop_runtime.rs
@@ -370,6 +370,9 @@
MonotonicInstant(self.0.monotonic_now())
}
+ pub fn realtime_now(&self) -> RealtimeInstant {
+ RealtimeInstant(self.0.realtime_now())
+ }
/// Note that the `'event_loop` input lifetime is intentional. The C++ API requires that it is
/// part of `self.configuration()`, which will always have this lifetime.
///
@@ -711,7 +714,6 @@
where
T: Follow<'a> + 'a;
-// TODO(Brian): Add the realtime timestamps here.
impl<'a, T> TypedContext<'a, T>
where
T: Follow<'a> + 'a,
@@ -730,6 +732,12 @@
pub fn monotonic_remote_time(&self) -> MonotonicInstant {
self.0.monotonic_remote_time()
}
+ pub fn realtime_event_time(&self) -> RealtimeInstant {
+ self.0.realtime_event_time()
+ }
+ pub fn realtime_remote_time(&self) -> RealtimeInstant {
+ self.0.realtime_remote_time()
+ }
pub fn queue_index(&self) -> u32 {
self.0.queue_index()
}
@@ -750,10 +758,11 @@
T::Inner: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- // TODO(Brian): Add the realtime timestamps here.
f.debug_struct("TypedContext")
.field("monotonic_event_time", &self.monotonic_event_time())
.field("monotonic_remote_time", &self.monotonic_remote_time())
+ .field("realtime_event_time", &self.realtime_event_time())
+ .field("realtime_remote_time", &self.realtime_remote_time())
.field("queue_index", &self.queue_index())
.field("remote_queue_index", &self.remote_queue_index())
.field("message", &self.message())
@@ -1020,10 +1029,11 @@
impl fmt::Debug for Context<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- // TODO(Brian): Add the realtime timestamps here.
f.debug_struct("Context")
.field("monotonic_event_time", &self.monotonic_event_time())
.field("monotonic_remote_time", &self.monotonic_remote_time())
+ .field("realtime_event_time", &self.realtime_event_time())
+ .field("realtime_remote_time", &self.realtime_remote_time())
.field("queue_index", &self.queue_index())
.field("remote_queue_index", &self.remote_queue_index())
.field("size", &self.data().map(|data| data.len()))
@@ -1033,7 +1043,6 @@
}
}
-// TODO(Brian): Add the realtime timestamps here.
impl<'context> Context<'context> {
pub fn monotonic_event_time(self) -> MonotonicInstant {
MonotonicInstant(self.0.monotonic_event_time)
@@ -1043,6 +1052,14 @@
MonotonicInstant(self.0.monotonic_remote_time)
}
+ pub fn realtime_event_time(self) -> RealtimeInstant {
+ RealtimeInstant(self.0.realtime_event_time)
+ }
+
+ pub fn realtime_remote_time(self) -> RealtimeInstant {
+ RealtimeInstant(self.0.realtime_remote_time)
+ }
+
pub fn queue_index(self) -> u32 {
self.0.queue_index
}
@@ -1093,9 +1110,6 @@
/// Represents a `aos::monotonic_clock::time_point` in a natural Rust way. This
/// is intended to have the same API as [`std::time::Instant`], any missing
/// functionality can be added if useful.
-///
-/// TODO(Brian): Do RealtimeInstant too. Use a macro? Integer as a generic
-/// parameter to distinguish them? Or just copy/paste?
#[repr(transparent)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct MonotonicInstant(i64);
@@ -1125,6 +1139,34 @@
}
}
+#[repr(transparent)]
+#[derive(Clone, Copy, Eq, PartialEq)]
+pub struct RealtimeInstant(i64);
+
+impl RealtimeInstant {
+ pub const MIN_TIME: Self = Self(i64::MIN);
+
+ pub fn is_min_time(self) -> bool {
+ self == Self::MIN_TIME
+ }
+
+ pub fn duration_since_epoch(self) -> Option<Duration> {
+ if self.is_min_time() {
+ None
+ } else {
+ Some(Duration::from_nanos(self.0.try_into().expect(
+ "monotonic_clock::time_point should always be after the epoch",
+ )))
+ }
+ }
+}
+
+impl fmt::Debug for RealtimeInstant {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.duration_since_epoch().fmt(f)
+ }
+}
+
mod panic_waker {
use std::task::{RawWaker, RawWakerVTable, Waker};
diff --git a/aos/util/BUILD b/aos/util/BUILD
index 19a9172..f8eb09f 100644
--- a/aos/util/BUILD
+++ b/aos/util/BUILD
@@ -86,6 +86,7 @@
"//aos:fast_string_builder",
"//aos:flatbuffer_utils",
"//aos/events:event_loop",
+ "@com_github_lz4_lz4//:lz4",
"@com_github_nlohmann_json//:json",
],
)
diff --git a/aos/util/file.cc b/aos/util/file.cc
index 317206e..cdf0061 100644
--- a/aos/util/file.cc
+++ b/aos/util/file.cc
@@ -36,7 +36,6 @@
void WriteStringToFileOrDie(const std::string_view filename,
const std::string_view contents,
mode_t permissions) {
- ::std::string r;
ScopedFD fd(open(::std::string(filename).c_str(),
O_CREAT | O_WRONLY | O_TRUNC, permissions));
PCHECK(fd.get() != -1) << ": opening " << filename;
diff --git a/aos/util/log_to_mcap.cc b/aos/util/log_to_mcap.cc
index 5330c60..e669658 100644
--- a/aos/util/log_to_mcap.cc
+++ b/aos/util/log_to_mcap.cc
@@ -5,7 +5,12 @@
DEFINE_string(node, "", "Node to replay from the perspective of.");
DEFINE_string(output_path, "/tmp/log.mcap", "Log to output.");
-DEFINE_string(mode, "json", "json or flatbuffer serialization.");
+DEFINE_string(mode, "flatbuffer", "json or flatbuffer serialization.");
+DEFINE_bool(
+ canonical_channel_names, false,
+ "If set, use full channel names; by default, will shorten names to be the "
+ "shortest possible version of the name (e.g., /aos instead of /pi/aos).");
+DEFINE_bool(compress, true, "Whether to use LZ4 compression in MCAP file.");
// Converts an AOS log to an MCAP log that can be fed into Foxglove. To try this
// out, run:
@@ -19,21 +24,43 @@
const std::vector<aos::logger::LogFile> logfiles =
aos::logger::SortParts(aos::logger::FindLogs(argc, argv));
+ CHECK(!logfiles.empty());
+ const std::string logger_node = logfiles.at(0).logger_node;
+ bool all_logs_from_same_node = true;
+ for (const aos::logger::LogFile &log : logfiles) {
+ if (log.logger_node != logger_node) {
+ all_logs_from_same_node = false;
+ break;
+ }
+ }
+ std::string replay_node = FLAGS_node;
+ if (replay_node.empty() && all_logs_from_same_node) {
+ LOG(INFO) << "Guessing \"" << logger_node
+ << "\" as node given that --node was not specified.";
+ replay_node = logger_node;
+ }
aos::logger::LogReader reader(logfiles);
reader.Register();
const aos::Node *node =
- FLAGS_node.empty()
+ (replay_node.empty() ||
+ !aos::configuration::MultiNode(reader.configuration()))
? nullptr
- : aos::configuration::GetNode(reader.configuration(), FLAGS_node);
+ : aos::configuration::GetNode(reader.configuration(), replay_node);
+
std::unique_ptr<aos::EventLoop> mcap_event_loop =
reader.event_loop_factory()->MakeEventLoop("mcap", node);
CHECK(!FLAGS_output_path.empty());
- aos::McapLogger relogger(mcap_event_loop.get(), FLAGS_output_path,
- FLAGS_mode == "flatbuffer"
- ? aos::McapLogger::Serialization::kFlatbuffer
- : aos::McapLogger::Serialization::kJson);
+ aos::McapLogger relogger(
+ mcap_event_loop.get(), FLAGS_output_path,
+ FLAGS_mode == "flatbuffer" ? aos::McapLogger::Serialization::kFlatbuffer
+ : aos::McapLogger::Serialization::kJson,
+ FLAGS_canonical_channel_names
+ ? aos::McapLogger::CanonicalChannelNames::kCanonical
+ : aos::McapLogger::CanonicalChannelNames::kShortened,
+ FLAGS_compress ? aos::McapLogger::Compression::kLz4
+ : aos::McapLogger::Compression::kNone);
reader.event_loop_factory()->Run();
}
diff --git a/aos/util/log_to_mcap_test.py b/aos/util/log_to_mcap_test.py
index 7bdffe4..36f8de0 100644
--- a/aos/util/log_to_mcap_test.py
+++ b/aos/util/log_to_mcap_test.py
@@ -10,6 +10,27 @@
from typing import Sequence, Text
+def make_permutations(options):
+ if len(options) == 0:
+ return [[]]
+ permutations = []
+ for option in options[0]:
+ for sub_permutations in make_permutations(options[1:]):
+ permutations.append([option] + sub_permutations)
+ return permutations
+
+
+def generate_argument_permutations():
+ arg_sets = [["--compress", "--nocompress"],
+ ["--mode=flatbuffer", "--mode=json"],
+ ["--canonical_channel_names", "--nocanonical_channel_names"],
+ ["--mcap_chunk_size=1000", "--mcap_chunk_size=10000000"],
+ ["--fetch", "--nofetch"]]
+ permutations = make_permutations(arg_sets)
+ print(permutations)
+ return permutations
+
+
def main(argv: Sequence[Text]):
parser = argparse.ArgumentParser()
parser.add_argument("--log_to_mcap",
@@ -20,35 +41,38 @@
required=True,
help="Path to logfile generator.")
args = parser.parse_args(argv)
- with tempfile.TemporaryDirectory() as tmpdir:
- log_name = tmpdir + "/test_log/"
- mcap_name = tmpdir + "/log.mcap"
- subprocess.run([args.generate_log, "--output_folder",
- log_name]).check_returncode()
- # Run with a really small chunk size, to force a multi-chunk file.
- subprocess.run([
- args.log_to_mcap, "--output_path", mcap_name, "--mcap_chunk_size",
- "1000", "--mode", "json", log_name
- ]).check_returncode()
- # MCAP attempts to find $HOME/.mcap.yaml, and dies on $HOME not existing. So
- # give it an arbitrary config location (it seems to be fine with a non-existent config).
- doctor_result = subprocess.run([
- args.mcap, "doctor", mcap_name, "--config", tmpdir + "/.mcap.yaml"
- ],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- encoding='utf-8')
- print(doctor_result.stdout)
- print(doctor_result.stderr)
- # mcap doctor doesn't actually return a non-zero exit code on certain failures...
- # See https://github.com/foxglove/mcap/issues/356
- if len(doctor_result.stderr) != 0:
- print("Didn't expect any stderr output.")
- return 1
- if doctor_result.stdout != f"Examining {mcap_name}\n":
- print("Only expected one line of stdout.")
- return 1
- doctor_result.check_returncode()
+ log_to_mcap_argument_permutations = generate_argument_permutations()
+ for log_to_mcap_args in log_to_mcap_argument_permutations:
+ with tempfile.TemporaryDirectory() as tmpdir:
+ log_name = tmpdir + "/test_log/"
+ mcap_name = tmpdir + "/log.mcap"
+ subprocess.run([args.generate_log, "--output_folder",
+ log_name]).check_returncode()
+ # Run with a really small chunk size, to force a multi-chunk file.
+ subprocess.run([
+ args.log_to_mcap, "--output_path", mcap_name,
+ "--mcap_chunk_size", "1000", "--mode", "json", log_name
+ ] + log_to_mcap_args).check_returncode()
+ # MCAP attempts to find $HOME/.mcap.yaml, and dies on $HOME not existing. So
+ # give it an arbitrary config location (it seems to be fine with a non-existent config).
+ doctor_result = subprocess.run([
+ args.mcap, "doctor", mcap_name, "--config",
+ tmpdir + "/.mcap.yaml"
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ encoding='utf-8')
+ print(doctor_result.stdout)
+ print(doctor_result.stderr)
+ # mcap doctor doesn't actually return a non-zero exit code on certain failures...
+ # See https://github.com/foxglove/mcap/issues/356
+ if len(doctor_result.stderr) != 0:
+ print("Didn't expect any stderr output.")
+ return 1
+ if doctor_result.stdout != f"Examining {mcap_name}\nHeader.profile field \"x-aos\" is not a well-known profile.\n":
+ print("Only expected two lines of stdout.")
+ return 1
+ doctor_result.check_returncode()
return 0
diff --git a/aos/util/mcap_logger.cc b/aos/util/mcap_logger.cc
index dc27504..742f284 100644
--- a/aos/util/mcap_logger.cc
+++ b/aos/util/mcap_logger.cc
@@ -3,6 +3,8 @@
#include "absl/strings/str_replace.h"
#include "aos/configuration_schema.h"
#include "aos/flatbuffer_merge.h"
+#include "lz4/lz4.h"
+#include "lz4/lz4frame.h"
#include "single_include/nlohmann/json.hpp"
DEFINE_uint64(mcap_chunk_size, 10'000'000,
@@ -82,11 +84,27 @@
return schema;
}
+namespace {
+std::string_view CompressionName(McapLogger::Compression compression) {
+ switch (compression) {
+ case McapLogger::Compression::kNone:
+ return "";
+ case McapLogger::Compression::kLz4:
+ return "lz4";
+ }
+ LOG(FATAL) << "Unreachable.";
+}
+} // namespace
+
McapLogger::McapLogger(EventLoop *event_loop, const std::string &output_path,
- Serialization serialization)
+ Serialization serialization,
+ CanonicalChannelNames canonical_channels,
+ Compression compression)
: event_loop_(event_loop),
output_(output_path),
serialization_(serialization),
+ canonical_channels_(canonical_channels),
+ compression_(compression),
configuration_channel_([]() {
// Setup a fake Channel for providing the configuration in the MCAP
// file. This is included for convenience so that consumers of the MCAP
@@ -121,8 +139,10 @@
McapLogger::~McapLogger() {
// If we have any data remaining, write one last chunk.
- if (current_chunk_.tellp() > 0) {
- WriteChunk();
+ for (auto &pair : current_chunks_) {
+ if (pair.second.data.tellp() > 0) {
+ WriteChunk(&pair.second);
+ }
}
WriteDataEnd();
@@ -189,16 +209,18 @@
message_counts_[id] = 0;
event_loop_->MakeRawWatcher(
channel, [this, id, channel](const Context &context, const void *) {
- WriteMessage(id, channel, context, ¤t_chunk_);
- if (static_cast<uint64_t>(current_chunk_.tellp()) >
+ ChunkStatus *chunk = ¤t_chunks_[id];
+ WriteMessage(id, channel, context, chunk);
+ if (static_cast<uint64_t>(chunk->data.tellp()) >
FLAGS_mcap_chunk_size) {
- WriteChunk();
+ WriteChunk(chunk);
}
});
fetchers_[id] = event_loop_->MakeRawFetcher(channel);
event_loop_->OnRun([this, id, channel]() {
if (FLAGS_fetch && fetchers_[id]->Fetch()) {
- WriteMessage(id, channel, fetchers_[id]->context(), ¤t_chunk_);
+ WriteMessage(id, channel, fetchers_[id]->context(),
+ ¤t_chunks_[id]);
}
});
}
@@ -214,7 +236,7 @@
config_context.size = configuration_.span().size();
config_context.data = configuration_.span().data();
WriteMessage(configuration_id_, &configuration_channel_.message(),
- config_context, ¤t_chunk_);
+ config_context, ¤t_chunks_[configuration_id_]);
});
}
@@ -321,11 +343,34 @@
// Schema ID
AppendInt16(&string_builder_, schema_id);
// Topic name
- AppendString(&string_builder_,
- override_name.empty()
- ? absl::StrCat(channel->name()->string_view(), " ",
- channel->type()->string_view())
- : override_name);
+ std::string topic_name(override_name);
+ if (topic_name.empty()) {
+ switch (canonical_channels_) {
+ case CanonicalChannelNames::kCanonical:
+ topic_name = absl::StrCat(channel->name()->string_view(), " ",
+ channel->type()->string_view());
+ break;
+ case CanonicalChannelNames::kShortened: {
+ std::set<std::string> names = configuration::GetChannelAliases(
+ event_loop_->configuration(), channel, event_loop_->name(),
+ event_loop_->node());
+ std::string_view shortest_name;
+ for (const std::string &name : names) {
+ if (shortest_name.empty() || name.size() < shortest_name.size()) {
+ shortest_name = name;
+ }
+ }
+ if (shortest_name != channel->name()->string_view()) {
+ VLOG(1) << "Shortening " << channel->name()->string_view() << " "
+ << channel->type()->string_view() << " to " << shortest_name;
+ }
+ topic_name =
+ absl::StrCat(shortest_name, " ", channel->type()->string_view());
+ break;
+ }
+ }
+ }
+ AppendString(&string_builder_, topic_name);
// Encoding
switch (serialization_) {
case Serialization::kJson:
@@ -342,7 +387,7 @@
}
void McapLogger::WriteMessage(uint16_t channel_id, const Channel *channel,
- const Context &context, std::ostream *output) {
+ const Context &context, ChunkStatus *chunk) {
CHECK_NOTNULL(context.data);
message_counts_[channel_id]++;
@@ -353,12 +398,13 @@
earliest_message_ =
std::min(context.monotonic_event_time, earliest_message_.value());
}
- if (!earliest_chunk_message_.has_value()) {
- earliest_chunk_message_ = context.monotonic_event_time;
+ if (!chunk->earliest_message.has_value()) {
+ chunk->earliest_message = context.monotonic_event_time;
} else {
- earliest_chunk_message_ =
- std::min(context.monotonic_event_time, earliest_chunk_message_.value());
+ chunk->earliest_message =
+ std::min(context.monotonic_event_time, chunk->earliest_message.value());
}
+ chunk->latest_message = context.monotonic_event_time;
latest_message_ = context.monotonic_event_time;
string_builder_.Reset();
@@ -396,11 +442,12 @@
total_message_bytes_ += context.size;
total_channel_bytes_[channel] += context.size;
- message_indices_[channel_id].push_back(std::make_pair<uint64_t, uint64_t>(
- context.monotonic_event_time.time_since_epoch().count(),
- output->tellp()));
+ chunk->message_indices[channel_id].push_back(
+ std::make_pair<uint64_t, uint64_t>(
+ context.monotonic_event_time.time_since_epoch().count(),
+ chunk->data.tellp()));
- WriteRecord(OpCode::kMessage, string_builder_.Result(), output);
+ WriteRecord(OpCode::kMessage, string_builder_.Result(), &chunk->data);
}
void McapLogger::WriteRecord(OpCode op, std::string_view record,
@@ -412,43 +459,77 @@
*ostream << record;
}
-void McapLogger::WriteChunk() {
+void McapLogger::WriteChunk(ChunkStatus *chunk) {
string_builder_.Reset();
- CHECK(earliest_chunk_message_.has_value());
+ CHECK(chunk->earliest_message.has_value());
const uint64_t chunk_offset = output_.tellp();
AppendInt64(&string_builder_,
- earliest_chunk_message_->time_since_epoch().count());
- AppendInt64(&string_builder_, latest_message_.time_since_epoch().count());
+ chunk->earliest_message->time_since_epoch().count());
+ CHECK(chunk->latest_message.has_value());
+ AppendInt64(&string_builder_,
+ chunk->latest_message.value().time_since_epoch().count());
- std::string chunk_records = current_chunk_.str();
+ std::string chunk_records = chunk->data.str();
// Reset the chunk buffer.
- current_chunk_.str("");
+ chunk->data.str("");
const uint64_t records_size = chunk_records.size();
// Uncompressed chunk size.
AppendInt64(&string_builder_, records_size);
// Uncompressed CRC (unpopulated).
AppendInt32(&string_builder_, 0);
- AppendString(&string_builder_, "");
- AppendBytes(&string_builder_, chunk_records);
+ // Compression
+ AppendString(&string_builder_, CompressionName(compression_));
+ uint64_t records_size_compressed = records_size;
+ switch (compression_) {
+ case Compression::kNone:
+ AppendBytes(&string_builder_, chunk_records);
+ break;
+ case Compression::kLz4: {
+ // Default preferences.
+ LZ4F_preferences_t *lz4_preferences = nullptr;
+ const uint64_t max_size =
+ LZ4F_compressFrameBound(records_size, lz4_preferences);
+ CHECK_NE(0u, max_size);
+ if (max_size > compression_buffer_.size()) {
+ compression_buffer_.resize(max_size);
+ }
+ records_size_compressed = LZ4F_compressFrame(
+ compression_buffer_.data(), compression_buffer_.size(),
+ reinterpret_cast<const char *>(chunk_records.data()),
+ chunk_records.size(), lz4_preferences);
+ CHECK(!LZ4F_isError(records_size_compressed));
+ AppendBytes(&string_builder_,
+ {reinterpret_cast<const char *>(compression_buffer_.data()),
+ static_cast<size_t>(records_size_compressed)});
+ break;
+ }
+ }
WriteRecord(OpCode::kChunk, string_builder_.Result());
std::map<uint16_t, uint64_t> index_offsets;
const uint64_t message_index_start = output_.tellp();
- for (const auto &indices : message_indices_) {
+ for (const auto &indices : chunk->message_indices) {
index_offsets[indices.first] = output_.tellp();
string_builder_.Reset();
AppendInt16(&string_builder_, indices.first);
AppendMessageIndices(&string_builder_, indices.second);
WriteRecord(OpCode::kMessageIndex, string_builder_.Result());
}
- message_indices_.clear();
+ chunk->message_indices.clear();
chunk_indices_.push_back(ChunkIndex{
- earliest_chunk_message_.value(), latest_message_, chunk_offset,
- message_index_start - chunk_offset, records_size, index_offsets,
- static_cast<uint64_t>(output_.tellp()) - message_index_start});
- earliest_chunk_message_.reset();
+ .start_time = chunk->earliest_message.value(),
+ .end_time = chunk->latest_message.value(),
+ .offset = chunk_offset,
+ .chunk_size = message_index_start - chunk_offset,
+ .records_size = records_size,
+ .records_size_compressed = records_size_compressed,
+ .message_index_offsets = index_offsets,
+ .message_index_size =
+ static_cast<uint64_t>(output_.tellp()) - message_index_start,
+ .compression = compression_});
+ chunk->earliest_message.reset();
}
McapLogger::SummaryOffset McapLogger::WriteStatistics() {
@@ -491,9 +572,9 @@
AppendChannelMap(&string_builder_, index.message_index_offsets);
AppendInt64(&string_builder_, index.message_index_size);
// Compression used.
- AppendString(&string_builder_, "");
+ AppendString(&string_builder_, CompressionName(index.compression));
// Compressed and uncompressed records size.
- AppendInt64(&string_builder_, index.records_size);
+ AppendInt64(&string_builder_, index.records_size_compressed);
AppendInt64(&string_builder_, index.records_size);
WriteRecord(OpCode::kChunkIndex, string_builder_.Result());
}
diff --git a/aos/util/mcap_logger.h b/aos/util/mcap_logger.h
index d7409fb..70a1328 100644
--- a/aos/util/mcap_logger.h
+++ b/aos/util/mcap_logger.h
@@ -36,8 +36,24 @@
kJson,
kFlatbuffer,
};
+ // Whether to attempt to shorten channel names.
+ enum class CanonicalChannelNames {
+ // Just use the full, unambiguous, channel names.
+ kCanonical,
+ // Use GetChannelAliases() to determine the shortest possible name for the
+ // channel for the current node, and use that in the MCAP file. This makes
+ // it so that the channels in the resulting file are more likely to match
+ // the channel names that are used in "real" applications.
+ kShortened,
+ };
+ // Chunk compression to use in the MCAP file.
+ enum class Compression {
+ kNone,
+ kLz4,
+ };
McapLogger(EventLoop *event_loop, const std::string &output_path,
- Serialization serialization);
+ Serialization serialization,
+ CanonicalChannelNames canonical_channels, Compression compression);
~McapLogger();
private:
@@ -77,8 +93,10 @@
uint64_t offset;
// Total size of the Chunk, in bytes.
uint64_t chunk_size;
- // Total size of the records portion of the Chunk, in bytes.
+ // Total uncompressed size of the records portion of the Chunk, in bytes.
uint64_t records_size;
+ // Total size of the records portion of the Chunk, when compressed
+ uint64_t records_size_compressed;
// Mapping of channel IDs to the MessageIndex entry for that channel within
// the referenced Chunk. The MessageIndex is referenced by an offset from
// the start of the file.
@@ -86,6 +104,30 @@
// Total size, in bytes, of all the MessageIndex entries for this Chunk
// together (note that they are required to be contiguous).
uint64_t message_index_size;
+ // Compression used in this Chunk.
+ Compression compression;
+ };
+ // Maintains the state of a single Chunk. In order to maximize read
+ // performance, we currently maintain separate chunks for each channel so
+ // that, in order to read a given channel, only data associated with that
+ // channel nead be read.
+ struct ChunkStatus {
+ // Buffer containing serialized message data for the currently-being-built
+ // chunk.
+ std::stringstream data;
+ // Earliest message observed in this chunk.
+ std::optional<aos::monotonic_clock::time_point> earliest_message;
+ // Latest message observed in this chunk.
+ std::optional<aos::monotonic_clock::time_point> latest_message;
+ // MessageIndex's for each message. The std::map is indexed by channel ID.
+ // The vector is then a series of pairs of (timestamp, offset from start of
+ // data).
+ // Note that currently this will only ever have one entry, for the channel
+ // that this chunk corresponds to. However, the standard provides for there
+ // being more than one channel per chunk and so we still have some code that
+ // supports that.
+ std::map<uint16_t, std::vector<std::pair<uint64_t, uint64_t>>>
+ message_indices;
};
enum class RegisterHandlers { kYes, kNo };
// Helpers to write each type of relevant record.
@@ -98,8 +140,8 @@
const aos::Channel *channel,
std::string_view override_name = "");
void WriteMessage(uint16_t channel_id, const Channel *channel,
- const Context &context, std::ostream *output);
- void WriteChunk();
+ const Context &context, ChunkStatus *chunk);
+ void WriteChunk(ChunkStatus *chunk);
// The helpers for writing records which appear in the Summary section will
// return SummaryOffset's so that they can be referenced in the SummaryOffset
@@ -131,28 +173,23 @@
aos::EventLoop *event_loop_;
std::ofstream output_;
const Serialization serialization_;
+ const CanonicalChannelNames canonical_channels_;
+ const Compression compression_;
size_t total_message_bytes_ = 0;
std::map<const Channel *, size_t> total_channel_bytes_;
- // Buffer containing serialized message data for the currently-being-built
- // chunk.
- std::stringstream current_chunk_;
FastStringBuilder string_builder_;
// Earliest message observed in this logfile.
std::optional<aos::monotonic_clock::time_point> earliest_message_;
- // Earliest message observed in the current chunk.
- std::optional<aos::monotonic_clock::time_point> earliest_chunk_message_;
- // Latest message observed.
+ // Latest message observed in this logfile.
aos::monotonic_clock::time_point latest_message_ =
aos::monotonic_clock::min_time;
// Count of all messages on each channel, indexed by channel ID.
std::map<uint16_t, uint64_t> message_counts_;
std::map<uint16_t, std::unique_ptr<RawFetcher>> fetchers_;
- // MessageIndex's for each message. The std::map is indexed by channel ID. The
- // vector is then a series of pairs of (timestamp, offset from start of
- // current_chunk_).
- std::map<uint16_t, std::vector<std::pair<uint64_t, uint64_t>>>
- message_indices_;
+ // All currently-being-built chunks. Indexed by channel ID. This is used to
+ // segregate channels into separate chunks to support more efficient reading.
+ std::map<uint16_t, ChunkStatus> current_chunks_;
// ChunkIndex's for all fully written Chunks.
std::vector<ChunkIndex> chunk_indices_;
@@ -162,6 +199,9 @@
uint16_t configuration_id_ = 0;
FlatbufferDetachedBuffer<Channel> configuration_channel_;
FlatbufferDetachedBuffer<Configuration> configuration_;
+
+ // Memory buffer to use for compressing data.
+ std::vector<uint8_t> compression_buffer_;
};
} // namespace aos
#endif // AOS_UTIL_MCAP_LOGGER_H_
diff --git a/debian/BUILD.lz4.bazel b/debian/BUILD.lz4.bazel
new file mode 100644
index 0000000..7aa8def
--- /dev/null
+++ b/debian/BUILD.lz4.bazel
@@ -0,0 +1,22 @@
+licenses(["notice"])
+
+cc_library(
+ name = "lz4",
+ srcs = [
+ "lz4.c",
+ "lz4frame.c",
+ "lz4hc.c",
+ "xxhash.c",
+ ],
+ hdrs = [
+ # lz4hc.c tries to #include lz4.c....
+ "lz4.c",
+ "lz4.h",
+ "lz4frame.h",
+ "lz4hc.h",
+ "xxhash.h",
+ ],
+ include_prefix = "lz4",
+ includes = ["."],
+ visibility = ["//visibility:public"],
+)
diff --git a/frc971/control_loops/python/path_edit.py b/frc971/control_loops/python/path_edit.py
index 7c742c8..437b242 100755
--- a/frc971/control_loops/python/path_edit.py
+++ b/frc971/control_loops/python/path_edit.py
@@ -48,7 +48,10 @@
# init editing / viewing modes and pointer location
self.mode = Mode.kPlacing
self.mousex = 0
+ self.lastx = 0
self.mousey = 0
+ self.lasty = 0
+ self.drag_start = None
self.module_path = os.path.dirname(os.path.realpath(sys.argv[0]))
self.path_to_export = os.path.join(self.module_path,
'points_for_pathedit.json')
@@ -406,6 +409,8 @@
self.queue_draw()
def do_button_release_event(self, event):
+ self.drag_start = None
+
self.attempt_append_multisplines()
self.mousex, self.mousey = self.input_transform.transform_point(
event.x, event.y)
@@ -430,6 +435,9 @@
self.mousex, self.mousey = self.input_transform.transform_point(
event.x, event.y)
+ self.lastx = event.x
+ self.lasty = event.y
+
if self.mode == Mode.kPlacing:
if self.active_multispline.addPoint(self.mousex, self.mousey):
self.mode = Mode.kEditing
@@ -462,6 +470,9 @@
index_multisplines, index_splines,
index_points)
+ if self.control_point_index == None:
+ self.drag_start = (event.x, event.y)
+
multispline, result = Multispline.nearest_distance(
self.multisplines, cur_p)
if result and result.fun < 0.1:
@@ -484,6 +495,14 @@
multispline.update_lib_spline()
self.graph.schedule_recalculate(self.multisplines)
+
+ if self.mode == Mode.kEditing and self.drag_start != None and self.control_point_index == None:
+
+ self.zoom_transform.translate(event.x - self.lastx,
+ event.y - self.lasty)
+ self.lastx = event.x
+ self.lasty = event.y
+
self.queue_draw()
def do_scroll_event(self, event):
@@ -505,9 +524,9 @@
scale = (self.field.width + scale_by) / self.field.width
# This restricts the amount it can be scaled.
- if self.zoom_transform.xx <= 0.5:
+ if self.zoom_transform.xx <= 0.05:
scale = max(scale, 1)
- elif self.zoom_transform.xx >= 16:
+ elif self.zoom_transform.xx >= 32:
scale = min(scale, 1)
# undo the scaled translation that the old zoom transform did
diff --git a/go.mod b/go.mod
index 09c71f4..b1720c2 100644
--- a/go.mod
+++ b/go.mod
@@ -7,27 +7,32 @@
github.com/golang/protobuf v1.5.2
github.com/google/flatbuffers v2.0.5+incompatible
google.golang.org/grpc v1.43.0
+ gorm.io/driver/postgres v1.3.7
+ gorm.io/gorm v1.23.5
)
require (
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/davecgh/go-spew v1.1.1
github.com/google/go-querystring v1.1.0 // indirect
- github.com/jackc/pgx v3.6.2+incompatible
github.com/phst/runfiles v0.0.0-20220125203201-388095b3a22d
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
- golang.org/x/text v0.3.6 // indirect
+ golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/protobuf v1.26.0 // indirect
)
require (
- github.com/cockroachdb/apd v1.1.0 // indirect
- github.com/gofrs/uuid v4.0.0+incompatible // indirect
- github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
- github.com/lib/pq v1.10.2 // indirect
- github.com/pkg/errors v0.8.1 // indirect
- github.com/shopspring/decimal v1.2.0 // indirect
- golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
+ github.com/jackc/chunkreader/v2 v2.0.1 // indirect
+ github.com/jackc/pgconn v1.12.1 // indirect
+ github.com/jackc/pgio v1.0.0 // indirect
+ github.com/jackc/pgpassfile v1.0.0 // indirect
+ github.com/jackc/pgproto3/v2 v2.3.0 // indirect
+ github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
+ github.com/jackc/pgtype v1.11.0 // indirect
+ github.com/jackc/pgx/v4 v4.16.1 // indirect
+ github.com/jinzhu/inflection v1.0.0 // indirect
+ github.com/jinzhu/now v1.1.4 // indirect
+ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
)
diff --git a/go.sum b/go.sum
index 7c08101..3082bdc 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
+github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/buildkite/go-buildkite v2.2.0+incompatible h1:yEjSu1axFC88x4dbufhgMDsEnJztPWlLiZzEvzJggXc=
github.com/buildkite/go-buildkite v2.2.0+incompatible/go.mod h1:WTV0aX5KnQ9ofsKMg2CLUBLJNsQ0RwOEKPhrXXZWPcE=
@@ -17,6 +19,9 @@
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
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=
@@ -27,6 +32,9 @@
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -57,41 +65,145 @@
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
-github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
-github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o=
-github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
+github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
+github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
+github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
+github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
+github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
+github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
+github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
+github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8=
+github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono=
+github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
+github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
+github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
+github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
+github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
+github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y=
+github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
+github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
+github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
+github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
+github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
+github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs=
+github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
+github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
+github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
+github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
+github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y=
+github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ=
+github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
+github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/phst/runfiles v0.0.0-20220125203201-388095b3a22d h1:N5aMcF9W9AjW4ed+PJhA7+FjdgPa9gJ+St3mNu2tq1Q=
github.com/phst/runfiles v0.0.0-20220125203201-388095b3a22d/go.mod h1:+oijTyzCf6Qe7sczsCOuoeX11IxZ+UkXXlhLrfyHlzg=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.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_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
+github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+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 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+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-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
+golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@@ -102,22 +214,44 @@
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -149,8 +283,18 @@
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gorm.io/driver/postgres v1.3.7 h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ=
+gorm.io/driver/postgres v1.3.7/go.mod h1:f02ympjIcgtHEGFMZvdgTxODZ9snAHDb4hXfigBVuNI=
+gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
+gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM=
+gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
diff --git a/go_deps.bzl b/go_deps.bzl
index 9d37e42..2869b5e 100644
--- a/go_deps.bzl
+++ b/go_deps.bzl
@@ -5,8 +5,8 @@
maybe_override_go_dep(
name = "co_honnef_go_tools",
importpath = "honnef.co/go/tools",
- sum = "h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=",
- version = "v0.0.0-20190523083050-ea95bdfd59fc",
+ sum = "h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=",
+ version = "v0.0.1-2019.2.3",
)
maybe_override_go_dep(
name = "com_github_antihax_optional",
@@ -69,6 +69,18 @@
version = "v1.1.0",
)
maybe_override_go_dep(
+ name = "com_github_coreos_go_systemd",
+ importpath = "github.com/coreos/go-systemd",
+ sum = "h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=",
+ version = "v0.0.0-20190719114852-fd7a80b32e1f",
+ )
+ maybe_override_go_dep(
+ name = "com_github_creack_pty",
+ importpath = "github.com/creack/pty",
+ sum = "h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=",
+ version = "v1.1.7",
+ )
+ maybe_override_go_dep(
name = "com_github_davecgh_go_spew",
importpath = "github.com/davecgh/go-spew",
sum = "h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=",
@@ -93,6 +105,24 @@
version = "v1.0.0",
)
maybe_override_go_dep(
+ name = "com_github_go_kit_log",
+ importpath = "github.com/go-kit/log",
+ sum = "h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ=",
+ version = "v0.1.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_go_logfmt_logfmt",
+ importpath = "github.com/go-logfmt/logfmt",
+ sum = "h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=",
+ version = "v0.5.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_go_stack_stack",
+ importpath = "github.com/go-stack/stack",
+ sum = "h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=",
+ version = "v1.8.0",
+ )
+ maybe_override_go_dep(
name = "com_github_gofrs_uuid",
importpath = "github.com/gofrs/uuid",
sum = "h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=",
@@ -129,6 +159,12 @@
version = "v1.1.0",
)
maybe_override_go_dep(
+ name = "com_github_google_renameio",
+ importpath = "github.com/google/renameio",
+ sum = "h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=",
+ version = "v0.1.0",
+ )
+ maybe_override_go_dep(
name = "com_github_google_uuid",
importpath = "github.com/google/uuid",
sum = "h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=",
@@ -141,16 +177,118 @@
version = "v1.16.0",
)
maybe_override_go_dep(
- name = "com_github_jackc_fake",
- importpath = "github.com/jackc/fake",
- sum = "h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=",
- version = "v0.0.0-20150926172116-812a484cc733",
+ name = "com_github_jackc_chunkreader",
+ importpath = "github.com/jackc/chunkreader",
+ sum = "h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=",
+ version = "v1.0.0",
)
maybe_override_go_dep(
- name = "com_github_jackc_pgx",
- importpath = "github.com/jackc/pgx",
- sum = "h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o=",
- version = "v3.6.2+incompatible",
+ name = "com_github_jackc_chunkreader_v2",
+ importpath = "github.com/jackc/chunkreader/v2",
+ sum = "h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=",
+ version = "v2.0.1",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jackc_pgconn",
+ importpath = "github.com/jackc/pgconn",
+ sum = "h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8=",
+ version = "v1.12.1",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jackc_pgio",
+ importpath = "github.com/jackc/pgio",
+ sum = "h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=",
+ version = "v1.0.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jackc_pgmock",
+ importpath = "github.com/jackc/pgmock",
+ sum = "h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=",
+ version = "v0.0.0-20210724152146-4ad1a8207f65",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jackc_pgpassfile",
+ importpath = "github.com/jackc/pgpassfile",
+ sum = "h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=",
+ version = "v1.0.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jackc_pgproto3",
+ importpath = "github.com/jackc/pgproto3",
+ sum = "h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=",
+ version = "v1.1.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jackc_pgproto3_v2",
+ importpath = "github.com/jackc/pgproto3/v2",
+ sum = "h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y=",
+ version = "v2.3.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jackc_pgservicefile",
+ importpath = "github.com/jackc/pgservicefile",
+ sum = "h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=",
+ version = "v0.0.0-20200714003250-2b9c44734f2b",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jackc_pgtype",
+ importpath = "github.com/jackc/pgtype",
+ sum = "h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs=",
+ version = "v1.11.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jackc_pgx_v4",
+ importpath = "github.com/jackc/pgx/v4",
+ sum = "h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y=",
+ version = "v4.16.1",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jackc_puddle",
+ importpath = "github.com/jackc/puddle",
+ sum = "h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw=",
+ version = "v1.2.1",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jinzhu_inflection",
+ importpath = "github.com/jinzhu/inflection",
+ sum = "h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=",
+ version = "v1.0.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_jinzhu_now",
+ importpath = "github.com/jinzhu/now",
+ sum = "h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=",
+ version = "v1.1.4",
+ )
+ maybe_override_go_dep(
+ name = "com_github_kisielk_gotool",
+ importpath = "github.com/kisielk/gotool",
+ sum = "h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=",
+ version = "v1.0.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_konsorten_go_windows_terminal_sequences",
+ importpath = "github.com/konsorten/go-windows-terminal-sequences",
+ sum = "h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=",
+ version = "v1.0.2",
+ )
+ maybe_override_go_dep(
+ name = "com_github_kr_pretty",
+ importpath = "github.com/kr/pretty",
+ sum = "h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=",
+ version = "v0.1.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_kr_pty",
+ importpath = "github.com/kr/pty",
+ sum = "h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=",
+ version = "v1.1.8",
+ )
+ maybe_override_go_dep(
+ name = "com_github_kr_text",
+ importpath = "github.com/kr/text",
+ sum = "h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=",
+ version = "v0.1.0",
)
maybe_override_go_dep(
name = "com_github_lib_pq",
@@ -159,6 +297,24 @@
version = "v1.10.2",
)
maybe_override_go_dep(
+ name = "com_github_masterminds_semver_v3",
+ importpath = "github.com/Masterminds/semver/v3",
+ sum = "h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=",
+ version = "v3.1.1",
+ )
+ maybe_override_go_dep(
+ name = "com_github_mattn_go_colorable",
+ importpath = "github.com/mattn/go-colorable",
+ sum = "h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=",
+ version = "v0.1.6",
+ )
+ maybe_override_go_dep(
+ name = "com_github_mattn_go_isatty",
+ importpath = "github.com/mattn/go-isatty",
+ sum = "h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=",
+ version = "v0.0.12",
+ )
+ maybe_override_go_dep(
name = "com_github_phst_runfiles",
importpath = "github.com/phst/runfiles",
sum = "h1:N5aMcF9W9AjW4ed+PJhA7+FjdgPa9gJ+St3mNu2tq1Q=",
@@ -189,16 +345,46 @@
version = "v1.2.0",
)
maybe_override_go_dep(
+ name = "com_github_rogpeppe_go_internal",
+ importpath = "github.com/rogpeppe/go-internal",
+ sum = "h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=",
+ version = "v1.3.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_rs_xid",
+ importpath = "github.com/rs/xid",
+ sum = "h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=",
+ version = "v1.2.1",
+ )
+ maybe_override_go_dep(
+ name = "com_github_rs_zerolog",
+ importpath = "github.com/rs/zerolog",
+ sum = "h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY=",
+ version = "v1.15.0",
+ )
+ maybe_override_go_dep(
+ name = "com_github_satori_go_uuid",
+ importpath = "github.com/satori/go.uuid",
+ sum = "h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=",
+ version = "v1.2.0",
+ )
+ maybe_override_go_dep(
name = "com_github_shopspring_decimal",
importpath = "github.com/shopspring/decimal",
sum = "h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=",
version = "v1.2.0",
)
maybe_override_go_dep(
+ name = "com_github_sirupsen_logrus",
+ importpath = "github.com/sirupsen/logrus",
+ sum = "h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=",
+ version = "v1.4.2",
+ )
+ maybe_override_go_dep(
name = "com_github_stretchr_objx",
importpath = "github.com/stretchr/objx",
- sum = "h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=",
- version = "v0.1.0",
+ sum = "h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=",
+ version = "v0.2.0",
)
maybe_override_go_dep(
name = "com_github_stretchr_testify",
@@ -207,6 +393,12 @@
version = "v1.7.0",
)
maybe_override_go_dep(
+ name = "com_github_zenazn_goji",
+ importpath = "github.com/zenazn/goji",
+ sum = "h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ=",
+ version = "v0.9.0",
+ )
+ maybe_override_go_dep(
name = "com_google_cloud_go",
importpath = "cloud.google.com/go",
sum = "h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=",
@@ -215,8 +407,20 @@
maybe_override_go_dep(
name = "in_gopkg_check_v1",
importpath = "gopkg.in/check.v1",
- sum = "h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=",
- version = "v0.0.0-20161208181325-20d25e280405",
+ sum = "h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=",
+ version = "v1.0.0-20180628173108-788fd7840127",
+ )
+ maybe_override_go_dep(
+ name = "in_gopkg_errgo_v2",
+ importpath = "gopkg.in/errgo.v2",
+ sum = "h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=",
+ version = "v2.1.0",
+ )
+ maybe_override_go_dep(
+ name = "in_gopkg_inconshreveable_log15_v2",
+ importpath = "gopkg.in/inconshreveable/log15.v2",
+ sum = "h1:RlWgLqCMMIYYEVcAR5MDsuHlVkaIPDAF+5Dehzg8L5A=",
+ version = "v2.0.0-20180818164646-67afb5ed74ec",
)
maybe_override_go_dep(
name = "in_gopkg_yaml_v2",
@@ -231,6 +435,18 @@
version = "v3.0.0-20200313102051-9f266ea9e77c",
)
maybe_override_go_dep(
+ name = "io_gorm_driver_postgres",
+ importpath = "gorm.io/driver/postgres",
+ sum = "h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ=",
+ version = "v1.3.7",
+ )
+ maybe_override_go_dep(
+ name = "io_gorm_gorm",
+ importpath = "gorm.io/gorm",
+ sum = "h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM=",
+ version = "v1.23.5",
+ )
+ maybe_override_go_dep(
name = "io_opentelemetry_go_proto_otlp",
importpath = "go.opentelemetry.io/proto/otlp",
sum = "h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8=",
@@ -263,8 +479,8 @@
maybe_override_go_dep(
name = "org_golang_x_crypto",
importpath = "golang.org/x/crypto",
- sum = "h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=",
- version = "v0.0.0-20210711020723-a769d52b0f97",
+ sum = "h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=",
+ version = "v0.0.0-20210921155107-089bfa567519",
)
maybe_override_go_dep(
name = "org_golang_x_exp",
@@ -275,8 +491,14 @@
maybe_override_go_dep(
name = "org_golang_x_lint",
importpath = "golang.org/x/lint",
- sum = "h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=",
- version = "v0.0.0-20190313153728-d0100b6bd8b3",
+ sum = "h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=",
+ version = "v0.0.0-20190930215403-16217165b5de",
+ )
+ maybe_override_go_dep(
+ name = "org_golang_x_mod",
+ importpath = "golang.org/x/mod",
+ sum = "h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=",
+ version = "v0.1.1-0.20191105210325-c90efee705ee",
)
maybe_override_go_dep(
name = "org_golang_x_net",
@@ -311,14 +533,14 @@
maybe_override_go_dep(
name = "org_golang_x_text",
importpath = "golang.org/x/text",
- sum = "h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=",
- version = "v0.3.6",
+ sum = "h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=",
+ version = "v0.3.7",
)
maybe_override_go_dep(
name = "org_golang_x_tools",
importpath = "golang.org/x/tools",
- sum = "h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A=",
- version = "v0.0.0-20190524140312-2c0ae7006135",
+ sum = "h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE=",
+ version = "v0.0.0-20200103221440-774c71fcf114",
)
maybe_override_go_dep(
name = "org_golang_x_xerrors",
@@ -326,3 +548,27 @@
sum = "h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=",
version = "v0.0.0-20200804184101-5ec99f83aff1",
)
+ maybe_override_go_dep(
+ name = "org_uber_go_atomic",
+ importpath = "go.uber.org/atomic",
+ sum = "h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=",
+ version = "v1.6.0",
+ )
+ maybe_override_go_dep(
+ name = "org_uber_go_multierr",
+ importpath = "go.uber.org/multierr",
+ sum = "h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=",
+ version = "v1.5.0",
+ )
+ maybe_override_go_dep(
+ name = "org_uber_go_tools",
+ importpath = "go.uber.org/tools",
+ sum = "h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=",
+ version = "v0.0.0-20190618225709-2cfd321de3ee",
+ )
+ maybe_override_go_dep(
+ name = "org_uber_go_zap",
+ importpath = "go.uber.org/zap",
+ sum = "h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=",
+ version = "v1.13.0",
+ )
diff --git a/scouting/db/BUILD b/scouting/db/BUILD
index 7fbd2e2..154cab6 100644
--- a/scouting/db/BUILD
+++ b/scouting/db/BUILD
@@ -6,7 +6,12 @@
importpath = "github.com/frc971/971-Robot-Code/scouting/db",
target_compatible_with = ["@platforms//cpu:x86_64"],
visibility = ["//visibility:public"],
- deps = ["@com_github_jackc_pgx//stdlib"],
+ deps = [
+ "@io_gorm_driver_postgres//:postgres",
+ "@io_gorm_gorm//:gorm",
+ "@io_gorm_gorm//clause",
+ "@io_gorm_gorm//logger",
+ ],
)
go_test(
@@ -18,4 +23,5 @@
],
embed = [":db"],
target_compatible_with = ["@platforms//cpu:x86_64"],
+ deps = ["@com_github_davecgh_go_spew//spew"],
)
diff --git a/scouting/db/db.go b/scouting/db/db.go
index 3d514e3..82f7fa8 100644
--- a/scouting/db/db.go
+++ b/scouting/db/db.go
@@ -1,33 +1,50 @@
package db
import (
- "database/sql"
"errors"
"fmt"
- _ "github.com/jackc/pgx/stdlib"
+ "gorm.io/driver/postgres"
+ "gorm.io/gorm"
+ "gorm.io/gorm/clause"
+ "gorm.io/gorm/logger"
)
type Database struct {
- *sql.DB
+ *gorm.DB
}
type Match struct {
- MatchNumber, SetNumber int32
- CompLevel string
+ // TODO(phil): Rework this be be one team per row.
+ // Makes queries much simpler.
+ MatchNumber int32 `gorm:"primaryKey"`
+ SetNumber int32 `gorm:"primaryKey"`
+ CompLevel string `gorm:"primaryKey"`
R1, R2, R3, B1, B2, B3 int32
}
type Shift struct {
- MatchNumber int32
+ MatchNumber int32 `gorm:"primaryKey"`
R1scouter, R2scouter, R3scouter, B1scouter, B2scouter, B3scouter string
}
type Stats struct {
- TeamNumber, MatchNumber, SetNumber int32
- CompLevel string
- StartingQuadrant int32
- AutoBallPickedUp [5]bool
+ TeamNumber int32 `gorm:"primaryKey"`
+ MatchNumber int32 `gorm:"primaryKey"`
+ SetNumber int32 `gorm:"primaryKey"`
+ CompLevel string `gorm:"primaryKey"`
+ StartingQuadrant int32
+ // This field is for the balls picked up during auto. Use this field
+ // when using this library. Ignore the AutoBallPickedUpX fields below.
+ AutoBallPickedUp [5]bool `gorm:"-:all"`
+ // These fields are internal implementation details. Do not use these.
+ // TODO(phil): Figure out how to use the JSON gorm serializer instead
+ // of manually serializing/deserializing these.
+ AutoBallPickedUp1 bool
+ AutoBallPickedUp2 bool
+ AutoBallPickedUp3 bool
+ AutoBallPickedUp4 bool
+ AutoBallPickedUp5 bool
// TODO(phil): Re-order auto and teleop fields so auto comes first.
ShotsMissed, UpperGoalShots, LowerGoalShots int32
ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto int32
@@ -50,12 +67,19 @@
}
type NotesData struct {
- TeamNumber int32
- Notes []string
+ ID uint `gorm:"primaryKey"`
+ TeamNumber int32
+ Notes string
+ GoodDriving bool
+ BadDriving bool
+ SketchyClimb bool
+ SolidClimb bool
+ GoodDefense bool
+ BadDefense bool
}
type Ranking struct {
- TeamNumber int
+ TeamNumber int `gorm:"primaryKey"`
Losses, Wins, Ties int32
Rank, Dq int32
}
@@ -66,217 +90,48 @@
var err error
database := new(Database)
- psqlInfo := fmt.Sprintf("postgres://%s:%s@localhost:%d/postgres", user, password, port)
- database.DB, err = sql.Open("pgx", psqlInfo)
+ dsn := fmt.Sprintf("host=localhost user=%s password=%s dbname=postgres port=%d sslmode=disable", user, password, port)
+ database.DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
+ Logger: logger.Default.LogMode(logger.Silent),
+ })
if err != nil {
+ database.Delete()
return nil, errors.New(fmt.Sprint("Failed to connect to postgres: ", err))
}
- statement, err := database.Prepare("CREATE TABLE IF NOT EXISTS matches (" +
- "MatchNumber INTEGER, " +
- "SetNumber INTEGER, " +
- "CompLevel VARCHAR, " +
- "R1 INTEGER, " +
- "R2 INTEGER, " +
- "R3 INTEGER, " +
- "B1 INTEGER, " +
- "B2 INTEGER, " +
- "B3 INTEGER, " +
- "PRIMARY KEY (MatchNumber, SetNumber, CompLevel))")
+ err = database.AutoMigrate(&Match{}, &Shift{}, &Stats{}, &NotesData{}, &Ranking{})
if err != nil {
- database.Close()
- return nil, errors.New(fmt.Sprint("Failed to prepare matches table creation: ", err))
- }
- defer statement.Close()
-
- _, err = statement.Exec()
- if err != nil {
- database.Close()
- return nil, errors.New(fmt.Sprint("Failed to create matches table: ", err))
- }
-
- statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS shift_schedule (" +
- "id SERIAL PRIMARY KEY, " +
- "MatchNumber INTEGER, " +
- "R1Scouter VARCHAR, " +
- "R2Scouter VARCHAR, " +
- "R3Scouter VARCHAR, " +
- "B1Scouter VARCHAR, " +
- "B2Scouter VARCHAR, " +
- "B3scouter VARCHAR)")
- if err != nil {
- database.Close()
- return nil, errors.New(fmt.Sprint("Failed to prepare shift schedule table creation: ", err))
- }
- defer statement.Close()
-
- _, err = statement.Exec()
- if err != nil {
- database.Close()
- return nil, errors.New(fmt.Sprint("Failed to create shift schedule table: ", err))
- }
-
- statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_match_stats (" +
- "TeamNumber INTEGER, " +
- "MatchNumber INTEGER, " +
- "SetNumber INTEGER, " +
- "CompLevel VARCHAR, " +
- "StartingQuadrant INTEGER, " +
- "AutoBall1PickedUp BOOLEAN, " +
- "AutoBall2PickedUp BOOLEAN, " +
- "AutoBall3PickedUp BOOLEAN, " +
- "AutoBall4PickedUp BOOLEAN, " +
- "AutoBall5PickedUp BOOLEAN, " +
- "ShotsMissed INTEGER, " +
- "UpperGoalShots INTEGER, " +
- "LowerGoalShots INTEGER, " +
- "ShotsMissedAuto INTEGER, " +
- "UpperGoalAuto INTEGER, " +
- "LowerGoalAuto INTEGER, " +
- "PlayedDefense INTEGER, " +
- "DefenseReceivedScore INTEGER, " +
- "Climbing INTEGER, " +
- "Comment VARCHAR, " +
- "CollectedBy VARCHAR, " +
- "PRIMARY KEY (TeamNumber, MatchNumber, SetNumber, CompLevel))")
- if err != nil {
- database.Close()
- return nil, errors.New(fmt.Sprint("Failed to prepare stats table creation: ", err))
- }
- defer statement.Close()
-
- _, err = statement.Exec()
- if err != nil {
- database.Close()
- return nil, errors.New(fmt.Sprint("Failed to create team_match_stats table: ", err))
- }
-
- statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_notes (" +
- "id SERIAL PRIMARY KEY, " +
- "TeamNumber INTEGER, " +
- "Notes TEXT)")
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to prepare notes table creation: ", err))
- }
- defer statement.Close()
-
- _, err = statement.Exec()
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to create notes table: ", err))
- }
-
- statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS rankings (" +
- "id SERIAL PRIMARY KEY, " +
- "Losses INTEGER, " +
- "Wins INTEGER, " +
- "Ties INTEGER, " +
- "Rank INTEGER, " +
- "Dq INTEGER, " +
- "TeamNumber INTEGER)")
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to prepare rankings table creation: ", err))
- }
- defer statement.Close()
-
- _, err = statement.Exec()
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to create rankings table: ", err))
+ database.Delete()
+ return nil, errors.New(fmt.Sprint("Failed to create/migrate tables: ", err))
}
return database, nil
}
func (database *Database) Delete() error {
- statement, err := database.Prepare("DROP TABLE IF EXISTS matches")
+ sql, err := database.DB.DB()
if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare dropping matches table: ", err))
+ return err
}
- _, err = statement.Exec()
- if err != nil {
- return errors.New(fmt.Sprint("Failed to drop matches table: ", err))
- }
-
- statement, err = database.Prepare("DROP TABLE IF EXISTS shift_schedule")
- if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare dropping shifts table: ", err))
- }
- _, err = statement.Exec()
- if err != nil {
- return errors.New(fmt.Sprint("Failed to drop shifts table: ", err))
- }
-
- statement, err = database.Prepare("DROP TABLE IF EXISTS team_match_stats")
- if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare dropping stats table: ", err))
- }
- _, err = statement.Exec()
- if err != nil {
- return errors.New(fmt.Sprint("Failed to drop stats table: ", err))
- }
-
- statement, err = database.Prepare("DROP TABLE IF EXISTS team_notes")
- if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare dropping notes table: ", err))
- }
- _, err = statement.Exec()
- if err != nil {
- return errors.New(fmt.Sprint("Failed to drop notes table: ", err))
- }
- return nil
-
- statement, err = database.Prepare("DROP TABLE IF EXISTS rankings")
- if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare dropping rankings table: ", err))
- }
- _, err = statement.Exec()
- if err != nil {
- return errors.New(fmt.Sprint("Failed to drop rankings table: ", err))
- }
- return nil
+ return sql.Close()
}
-// This function will also populate the Stats table with six empty rows every time a match is added
-func (database *Database) AddToMatch(m Match) error {
- statement, err := database.Prepare("INSERT INTO matches(" +
- "MatchNumber, SetNumber, CompLevel, " +
- "R1, R2, R3, B1, B2, B3) " +
- "VALUES (" +
- "$1, $2, $3, " +
- "$4, $5, $6, $7, $8, $9) " +
- "ON CONFLICT (MatchNumber, SetNumber, CompLevel) DO UPDATE SET " +
- "R1 = EXCLUDED.R1, R2 = EXCLUDED.R2, R3 = EXCLUDED.R3, " +
- "B1 = EXCLUDED.B1, B2 = EXCLUDED.B2, B3 = EXCLUDED.B3")
- if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare insertion into match database: ", err))
- }
- defer statement.Close()
+func (database *Database) SetDebugLogLevel() {
+ database.DB.Logger = database.DB.Logger.LogMode(logger.Info)
+}
- _, err = statement.Exec(m.MatchNumber, m.SetNumber, m.CompLevel,
- m.R1, m.R2, m.R3, m.B1, m.B2, m.B3)
- if err != nil {
- return errors.New(fmt.Sprint("Failed to insert into match database: ", err))
- }
- return nil
+func (database *Database) AddToMatch(m Match) error {
+ result := database.Clauses(clause.OnConflict{
+ UpdateAll: true,
+ }).Create(&m)
+ return result.Error
}
func (database *Database) AddToShift(sh Shift) error {
- statement, err := database.Prepare("INSERT INTO shift_schedule(" +
- "MatchNumber, " +
- "R1scouter, R2scouter, R3scouter, B1scouter, B2scouter, B3scouter) " +
- "VALUES (" +
- "$1, " +
- "$2, $3, $4, $5, $6, $7)")
- if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare insertion into shift database: ", err))
- }
- defer statement.Close()
-
- _, err = statement.Exec(sh.MatchNumber,
- sh.R1scouter, sh.R2scouter, sh.R3scouter, sh.B1scouter, sh.B2scouter, sh.B3scouter)
- if err != nil {
- return errors.New(fmt.Sprint("Failed to insert into shift database: ", err))
- }
- return nil
+ result := database.Clauses(clause.OnConflict{
+ UpdateAll: true,
+ }).Create(&sh)
+ return result.Error
}
func (database *Database) AddToStats(s Stats) error {
@@ -297,304 +152,123 @@
" in match ", s.MatchNumber, " in the schedule."))
}
- statement, err := database.Prepare("INSERT INTO team_match_stats(" +
- "TeamNumber, MatchNumber, SetNumber, CompLevel, " +
- "StartingQuadrant, " +
- "AutoBall1PickedUp, AutoBall2PickedUp, AutoBall3PickedUp, " +
- "AutoBall4PickedUp, AutoBall5PickedUp, " +
- "ShotsMissed, UpperGoalShots, LowerGoalShots, " +
- "ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, " +
- "PlayedDefense, DefenseReceivedScore, Climbing, " +
- "Comment, CollectedBy) " +
- "VALUES (" +
- "$1, $2, $3, $4, " +
- "$5, " +
- "$6, $7, $8, " +
- "$9, $10, " +
- "$11, $12, $13, " +
- "$14, $15, $16, " +
- "$17, $18, $19, " +
- "$20, $21)")
- if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare stats update statement: ", err))
- }
- defer statement.Close()
-
- _, err = statement.Exec(
- s.TeamNumber, s.MatchNumber, s.SetNumber, s.CompLevel,
- s.StartingQuadrant,
- s.AutoBallPickedUp[0], s.AutoBallPickedUp[1], s.AutoBallPickedUp[2],
- s.AutoBallPickedUp[3], s.AutoBallPickedUp[4],
- s.ShotsMissed, s.UpperGoalShots, s.LowerGoalShots,
- s.ShotsMissedAuto, s.UpperGoalAuto, s.LowerGoalAuto,
- s.PlayedDefense, s.DefenseReceivedScore, s.Climbing,
- s.Comment, s.CollectedBy)
- if err != nil {
- return errors.New(fmt.Sprint("Failed to update stats database: ", err))
- }
-
- return nil
+ // Unpack the auto balls array.
+ s.AutoBallPickedUp1 = s.AutoBallPickedUp[0]
+ s.AutoBallPickedUp2 = s.AutoBallPickedUp[1]
+ s.AutoBallPickedUp3 = s.AutoBallPickedUp[2]
+ s.AutoBallPickedUp4 = s.AutoBallPickedUp[3]
+ s.AutoBallPickedUp5 = s.AutoBallPickedUp[4]
+ result := database.Create(&s)
+ return result.Error
}
func (database *Database) AddOrUpdateRankings(r Ranking) error {
- statement, err := database.Prepare("UPDATE rankings SET " +
- "Losses = $1, Wins = $2, Ties = $3, " +
- "Rank = $4, Dq = $5, TeamNumber = $6 " +
- "WHERE TeamNumber = $6")
- if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare rankings database update: ", err))
- }
- defer statement.Close()
-
- result, err := statement.Exec(r.Losses, r.Wins, r.Ties,
- r.Rank, r.Dq, r.TeamNumber)
- if err != nil {
- return errors.New(fmt.Sprint("Failed to update rankings database: ", err))
- }
-
- numRowsAffected, err := result.RowsAffected()
- if err != nil {
- return errors.New(fmt.Sprint("Failed to query rows affected: ", err))
- }
- if numRowsAffected == 0 {
- statement, err := database.Prepare("INSERT INTO rankings(" +
- "Losses, Wins, Ties, " +
- "Rank, Dq, TeamNumber) " +
- "VALUES (" +
- "$1, $2, $3, " +
- "$4, $5, $6)")
- if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare insertion into rankings database: ", err))
- }
- defer statement.Close()
-
- _, err = statement.Exec(r.Losses, r.Wins, r.Ties,
- r.Rank, r.Dq, r.TeamNumber)
- if err != nil {
- return errors.New(fmt.Sprint("Failed to insert into rankings database: ", err))
- }
- }
-
- return nil
+ result := database.Clauses(clause.OnConflict{
+ UpdateAll: true,
+ }).Create(&r)
+ return result.Error
}
func (database *Database) ReturnMatches() ([]Match, error) {
- rows, err := database.Query("SELECT * FROM matches")
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to select from matches: ", err))
- }
- defer rows.Close()
-
- matches := make([]Match, 0)
- for rows.Next() {
- var match Match
- err := rows.Scan(&match.MatchNumber, &match.SetNumber, &match.CompLevel,
- &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
- }
- matches = append(matches, match)
- }
- return matches, nil
+ var matches []Match
+ result := database.Find(&matches)
+ return matches, result.Error
}
func (database *Database) ReturnAllShifts() ([]Shift, error) {
- rows, err := database.Query("SELECT * FROM shift_schedule")
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to select from shift: ", err))
- }
- defer rows.Close()
+ var shifts []Shift
+ result := database.Find(&shifts)
+ return shifts, result.Error
+}
- shifts := make([]Shift, 0)
- for rows.Next() {
- var shift Shift
- var id int
- err := rows.Scan(&id, &shift.MatchNumber,
- &shift.R1scouter, &shift.R2scouter, &shift.R3scouter, &shift.B1scouter, &shift.B2scouter, &shift.B3scouter)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to scan from shift: ", err))
- }
- shifts = append(shifts, shift)
+// Packs the stats. This really just consists of taking the individual auto
+// ball booleans and turning them into an array. The individual booleans are
+// cleared so that they don't affect struct comparisons.
+func packStats(stats *Stats) {
+ stats.AutoBallPickedUp = [5]bool{
+ stats.AutoBallPickedUp1,
+ stats.AutoBallPickedUp2,
+ stats.AutoBallPickedUp3,
+ stats.AutoBallPickedUp4,
+ stats.AutoBallPickedUp5,
}
- return shifts, nil
+ stats.AutoBallPickedUp1 = false
+ stats.AutoBallPickedUp2 = false
+ stats.AutoBallPickedUp3 = false
+ stats.AutoBallPickedUp4 = false
+ stats.AutoBallPickedUp5 = false
}
func (database *Database) ReturnStats() ([]Stats, error) {
- rows, err := database.Query("SELECT * FROM team_match_stats")
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM team_match_stats: ", err))
+ var stats []Stats
+ result := database.Find(&stats)
+ // Pack the auto balls array.
+ for i := range stats {
+ packStats(&stats[i])
}
- defer rows.Close()
-
- teams := make([]Stats, 0)
- for rows.Next() {
- var team Stats
- err = rows.Scan(
- &team.TeamNumber, &team.MatchNumber, &team.SetNumber, &team.CompLevel,
- &team.StartingQuadrant,
- &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
- &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
- &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
- &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
- &team.PlayedDefense, &team.DefenseReceivedScore, &team.Climbing,
- &team.Comment, &team.CollectedBy)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
- }
- teams = append(teams, team)
- }
- return teams, nil
+ return stats, result.Error
}
func (database *Database) ReturnRankings() ([]Ranking, error) {
- rows, err := database.Query("SELECT * FROM rankings")
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM rankings: ", err))
- }
- defer rows.Close()
-
- all_rankings := make([]Ranking, 0)
- for rows.Next() {
- var ranking Ranking
- var id int
- err = rows.Scan(&id,
- &ranking.Losses, &ranking.Wins, &ranking.Ties,
- &ranking.Rank, &ranking.Dq, &ranking.TeamNumber)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to scan from rankings: ", err))
- }
- all_rankings = append(all_rankings, ranking)
- }
- return all_rankings, nil
+ var rankins []Ranking
+ result := database.Find(&rankins)
+ return rankins, result.Error
}
func (database *Database) QueryMatches(teamNumber_ int32) ([]Match, error) {
- rows, err := database.Query("SELECT * FROM matches WHERE "+
- "R1 = $1 OR R2 = $2 OR R3 = $3 OR B1 = $4 OR B2 = $5 OR B3 = $6",
- teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to select from matches for team: ", err))
- }
- defer rows.Close()
-
var matches []Match
- for rows.Next() {
- var match Match
- err = rows.Scan(&match.MatchNumber, &match.SetNumber, &match.CompLevel,
- &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
- }
- matches = append(matches, match)
- }
- return matches, nil
+ result := database.
+ Where("r1 = $1 OR r2 = $1 OR r3 = $1 OR b1 = $1 OR b2 = $1 OR b3 = $1", teamNumber_).
+ Find(&matches)
+ return matches, result.Error
}
func (database *Database) QueryAllShifts(matchNumber_ int) ([]Shift, error) {
- rows, err := database.Query("SELECT * FROM shift_schedule WHERE MatchNumber = $1", matchNumber_)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to select from shift for team: ", err))
- }
- defer rows.Close()
-
var shifts []Shift
- for rows.Next() {
- var shift Shift
- var id int
- err = rows.Scan(&id, &shift.MatchNumber,
- &shift.R1scouter, &shift.R2scouter, &shift.R3scouter, &shift.B1scouter, &shift.B2scouter, &shift.B3scouter)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
- }
- shifts = append(shifts, shift)
- }
- return shifts, nil
+ result := database.Where("match_number = ?", matchNumber_).Find(&shifts)
+ return shifts, result.Error
}
func (database *Database) QueryStats(teamNumber_ int) ([]Stats, error) {
- rows, err := database.Query("SELECT * FROM team_match_stats WHERE TeamNumber = $1", teamNumber_)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to select from stats: ", err))
+ var stats []Stats
+ result := database.Where("team_number = ?", teamNumber_).Find(&stats)
+ // Pack the auto balls array.
+ for i := range stats {
+ packStats(&stats[i])
}
- defer rows.Close()
-
- var teams []Stats
- for rows.Next() {
- var team Stats
- err = rows.Scan(
- &team.TeamNumber, &team.MatchNumber, &team.SetNumber, &team.CompLevel,
- &team.StartingQuadrant,
- &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
- &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
- &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
- &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
- &team.PlayedDefense, &team.DefenseReceivedScore, &team.Climbing,
- &team.Comment, &team.CollectedBy)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
- }
- teams = append(teams, team)
- }
- return teams, nil
+ return stats, result.Error
}
-func (database *Database) QueryNotes(TeamNumber int32) (NotesData, error) {
- rows, err := database.Query("SELECT * FROM team_notes WHERE TeamNumber = $1", TeamNumber)
- if err != nil {
- return NotesData{}, errors.New(fmt.Sprint("Failed to select from notes: ", err))
+func (database *Database) QueryNotes(TeamNumber int32) ([]string, error) {
+ var rawNotes []NotesData
+ result := database.Where("team_number = ?", TeamNumber).Find(&rawNotes)
+ if result.Error != nil {
+ return nil, result.Error
}
- defer rows.Close()
- var notes []string
- for rows.Next() {
- var id int32
- var data string
- err = rows.Scan(&id, &TeamNumber, &data)
- if err != nil {
- return NotesData{}, errors.New(fmt.Sprint("Failed to scan from notes: ", err))
- }
- notes = append(notes, data)
+ notes := make([]string, len(rawNotes))
+ for i := range rawNotes {
+ notes[i] = rawNotes[i].Notes
}
- return NotesData{TeamNumber, notes}, nil
+ return notes, nil
}
func (database *Database) QueryRankings(TeamNumber int) ([]Ranking, error) {
- rows, err := database.Query("SELECT * FROM rankings WHERE TeamNumber = $1", TeamNumber)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to select from rankings: ", err))
- }
- defer rows.Close()
-
- all_rankings := make([]Ranking, 0)
- for rows.Next() {
- var ranking Ranking
- var id int
- err = rows.Scan(&id,
- &ranking.Losses, &ranking.Wins, &ranking.Ties,
- &ranking.Rank, &ranking.Dq, &ranking.TeamNumber)
- if err != nil {
- return nil, errors.New(fmt.Sprint("Failed to scan from rankings: ", err))
- }
- all_rankings = append(all_rankings, ranking)
- }
- return all_rankings, nil
+ var rankins []Ranking
+ result := database.Where("team_number = ?", TeamNumber).Find(&rankins)
+ return rankins, result.Error
}
func (database *Database) AddNotes(data NotesData) error {
- if len(data.Notes) > 1 {
- return errors.New("Can only insert one row of notes at a time")
- }
- statement, err := database.Prepare("INSERT INTO " +
- "team_notes(TeamNumber, Notes)" +
- "VALUES ($1, $2)")
- if err != nil {
- return errors.New(fmt.Sprint("Failed to prepare insertion into notes table: ", err))
- }
- defer statement.Close()
-
- _, err = statement.Exec(data.TeamNumber, data.Notes[0])
- if err != nil {
- return errors.New(fmt.Sprint("Failed to insert into Notes database: ", err))
- }
- return nil
+ result := database.Create(&NotesData{
+ TeamNumber: data.TeamNumber,
+ Notes: data.Notes,
+ GoodDriving: data.GoodDriving,
+ BadDriving: data.BadDriving,
+ SketchyClimb: data.SketchyClimb,
+ SolidClimb: data.SolidClimb,
+ GoodDefense: data.GoodDefense,
+ BadDefense: data.BadDefense,
+ })
+ return result.Error
}
diff --git a/scouting/db/db_test.go b/scouting/db/db_test.go
index 438e52e..1e11008 100644
--- a/scouting/db/db_test.go
+++ b/scouting/db/db_test.go
@@ -9,6 +9,8 @@
"strings"
"testing"
"time"
+
+ "github.com/davecgh/go-spew/spew"
)
// Shortcut for error checking. If the specified error is non-nil, print the
@@ -26,7 +28,6 @@
func (fixture dbFixture) TearDown() {
fixture.db.Delete()
- fixture.db.Close()
log.Println("Shutting down testdb")
fixture.server.Process.Signal(os.Interrupt)
fixture.server.Process.Wait()
@@ -55,9 +56,17 @@
}
log.Println("Connected to postgres.")
+ fixture.db.SetDebugLogLevel()
+
return fixture
}
+func checkDeepEqual(t *testing.T, expected interface{}, actual interface{}) {
+ if !reflect.DeepEqual(expected, actual) {
+ t.Fatalf(spew.Sprintf("Got %#v,\nbut expected %#v.", actual, expected))
+ }
+}
+
func TestAddToMatchDB(t *testing.T) {
fixture := createDatabase(t)
defer fixture.TearDown()
@@ -77,9 +86,7 @@
got, err := fixture.db.ReturnMatches()
check(t, err, "Failed ReturnMatches()")
- if !reflect.DeepEqual(correct, got) {
- t.Fatalf("Got %#v,\nbut expected %#v.", got, correct)
- }
+ checkDeepEqual(t, correct, got)
}
func TestAddOrUpdateRankingsDB(t *testing.T) {
@@ -198,6 +205,7 @@
stats := Stats{
TeamNumber: 1236, MatchNumber: 7,
+ SetNumber: 1, CompLevel: "qual",
StartingQuadrant: 2,
AutoBallPickedUp: [5]bool{false, false, false, true, false},
ShotsMissed: 9, UpperGoalShots: 5, LowerGoalShots: 4,
@@ -698,25 +706,20 @@
got, err := fixture.db.QueryRankings(125)
check(t, err, "Failed QueryRankings()")
- if !reflect.DeepEqual(correct, got) {
- t.Errorf("Got %#v,\nbut expected %#v.", got, correct)
- }
+ checkDeepEqual(t, correct, got)
}
func TestNotes(t *testing.T) {
fixture := createDatabase(t)
defer fixture.TearDown()
- expected := NotesData{
- TeamNumber: 1234,
- Notes: []string{"Note 1", "Note 3"},
- }
+ expected := []string{"Note 1", "Note 3"}
- err := fixture.db.AddNotes(NotesData{1234, []string{"Note 1"}})
+ err := fixture.db.AddNotes(NotesData{TeamNumber: 1234, Notes: "Note 1", GoodDriving: true, BadDriving: false, SketchyClimb: false, SolidClimb: true, GoodDefense: false, BadDefense: true})
check(t, err, "Failed to add Note")
- err = fixture.db.AddNotes(NotesData{1235, []string{"Note 2"}})
+ err = fixture.db.AddNotes(NotesData{TeamNumber: 1235, Notes: "Note 2", GoodDriving: false, BadDriving: true, SketchyClimb: false, SolidClimb: true, GoodDefense: false, BadDefense: false})
check(t, err, "Failed to add Note")
- err = fixture.db.AddNotes(NotesData{1234, []string{"Note 3"}})
+ err = fixture.db.AddNotes(NotesData{TeamNumber: 1234, Notes: "Note 3", GoodDriving: true, BadDriving: false, SketchyClimb: false, SolidClimb: true, GoodDefense: true, BadDefense: false})
check(t, err, "Failed to add Note")
actual, err := fixture.db.QueryNotes(1234)
diff --git a/scouting/scouting_test.ts b/scouting/scouting_test.ts
index a34d98c..15a0509 100644
--- a/scouting/scouting_test.ts
+++ b/scouting/scouting_test.ts
@@ -241,7 +241,6 @@
expect(await getHeadingText()).toEqual('Climb');
await element(by.id('high')).click();
- await setTextboxByIdTo('comment', 'A very useful comment here.');
await element(by.buttonText('Next')).click();
expect(await getHeadingText()).toEqual('Other');
@@ -249,6 +248,7 @@
await adjustNthSliderBy(1, 1);
await element(by.id('no_show')).click();
await element(by.id('mechanically_broke')).click();
+ await setTextboxByIdTo('comment', 'A very useful comment here.');
await element(by.buttonText('Next')).click();
expect(await getHeadingText()).toEqual('Review and Submit');
@@ -273,7 +273,6 @@
// Validate Climb.
await expectReviewFieldToBe('Climb Level', 'High');
- await expectReviewFieldToBe('Comments', 'A very useful comment here.');
// Validate Other.
await expectReviewFieldToBe('Defense Played On Rating', '3');
@@ -282,6 +281,7 @@
await expectReviewFieldToBe('Never moved', 'false');
await expectReviewFieldToBe('Battery died', 'false');
await expectReviewFieldToBe('Broke (mechanically)', 'true');
+ await expectReviewFieldToBe('Comments', 'A very useful comment here.');
await element(by.buttonText('Submit')).click();
await browser.wait(
@@ -322,4 +322,36 @@
await element(by.buttonText('Flip')).click();
}
});
+
+ it('should: submit note scouting for multiple teams', async () => {
+ // Navigate to Notes Page.
+ await loadPage();
+ await element(by.cssContainingText('.nav-link', 'Notes')).click();
+ expect(await element(by.id('page-title')).getText()).toEqual('Notes');
+
+ // Add first team.
+ await setTextboxByIdTo('team_number_notes', '1234');
+ await element(by.buttonText('Select')).click();
+
+ // Add note and select keyword for first team.
+ expect(await element(by.id('team-key-1')).getText()).toEqual('1234');
+ await element(by.id('text-input-1')).sendKeys('Good Driving');
+ await element(by.id('Good Driving_0')).click();
+
+ // Navigate to add team selection and add another team.
+ await element(by.id('add-team-button')).click();
+ await setTextboxByIdTo('team_number_notes', '1235');
+ await element(by.buttonText('Select')).click();
+
+ // Add note and select keyword for second team.
+ expect(await element(by.id('team-key-2')).getText()).toEqual('1235');
+ await element(by.id('text-input-2')).sendKeys('Bad Driving');
+ await element(by.id('Bad Driving_1')).click();
+
+ // Submit Notes.
+ await element(by.buttonText('Submit')).click();
+ expect(await element(by.id('team_number_label')).getText()).toEqual(
+ 'Team Number'
+ );
+ });
});
diff --git a/scouting/webserver/main.go b/scouting/webserver/main.go
index 5d4ab01..d2fbdfe 100644
--- a/scouting/webserver/main.go
+++ b/scouting/webserver/main.go
@@ -117,7 +117,7 @@
if err != nil {
log.Fatal("Failed to connect to database: ", err)
}
- defer database.Close()
+ defer database.Delete()
scrapeMatchList := func(year int32, eventCode string) ([]scraping.Match, error) {
if *blueAllianceConfigPtr == "" {
diff --git a/scouting/webserver/requests/messages/submit_notes.fbs b/scouting/webserver/requests/messages/submit_notes.fbs
index cf111b3..1498e26 100644
--- a/scouting/webserver/requests/messages/submit_notes.fbs
+++ b/scouting/webserver/requests/messages/submit_notes.fbs
@@ -3,6 +3,12 @@
table SubmitNotes {
team:int (id: 0);
notes:string (id: 1);
+ good_driving:bool (id: 2);
+ bad_driving:bool (id: 3);
+ sketchy_climb:bool (id: 4);
+ solid_climb:bool (id: 5);
+ good_defense:bool (id: 6);
+ bad_defense:bool (id: 7);
}
root_type SubmitNotes;
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index 67a1722..e33e82d 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -66,7 +66,7 @@
QueryMatches(int32) ([]db.Match, error)
QueryAllShifts(int) ([]db.Shift, error)
QueryStats(int) ([]db.Stats, error)
- QueryNotes(int32) (db.NotesData, error)
+ QueryNotes(int32) ([]string, error)
AddNotes(db.NotesData) error
}
@@ -337,7 +337,33 @@
func parseTeamKey(teamKey string) (int, error) {
// TBA prefixes teams with "frc". Not sure why. Get rid of that.
teamKey = strings.TrimPrefix(teamKey, "frc")
- return strconv.Atoi(teamKey)
+ magnitude := 0
+ if strings.HasSuffix(teamKey, "A") {
+ magnitude = 0
+ teamKey = strings.TrimSuffix(teamKey, "A")
+ } else if strings.HasSuffix(teamKey, "B") {
+ magnitude = 9
+ teamKey = strings.TrimSuffix(teamKey, "B")
+ } else if strings.HasSuffix(teamKey, "C") {
+ magnitude = 8
+ teamKey = strings.TrimSuffix(teamKey, "C")
+ } else if strings.HasSuffix(teamKey, "D") {
+ magnitude = 7
+ teamKey = strings.TrimSuffix(teamKey, "D")
+ } else if strings.HasSuffix(teamKey, "E") {
+ magnitude = 6
+ teamKey = strings.TrimSuffix(teamKey, "E")
+ } else if strings.HasSuffix(teamKey, "F") {
+ magnitude = 5
+ teamKey = strings.TrimSuffix(teamKey, "F")
+ }
+
+ if magnitude != 0 {
+ teamKey = strconv.Itoa(magnitude) + teamKey
+ }
+
+ result, err := strconv.Atoi(teamKey)
+ return result, err
}
// Parses the alliance data from the specified match and returns the three red
@@ -445,8 +471,14 @@
}
err = handler.db.AddNotes(db.NotesData{
- TeamNumber: request.Team(),
- Notes: []string{string(request.Notes())},
+ TeamNumber: request.Team(),
+ Notes: string(request.Notes()),
+ GoodDriving: bool(request.GoodDriving()),
+ BadDriving: bool(request.BadDriving()),
+ SketchyClimb: bool(request.SketchyClimb()),
+ SolidClimb: bool(request.SolidClimb()),
+ GoodDefense: bool(request.GoodDefense()),
+ BadDefense: bool(request.BadDefense()),
})
if err != nil {
respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert notes: %v", err))
@@ -475,14 +507,14 @@
return
}
- notesData, err := handler.db.QueryNotes(request.Team())
+ notes, err := handler.db.QueryNotes(request.Team())
if err != nil {
respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query notes: %v", err))
return
}
var response RequestNotesForTeamResponseT
- for _, data := range notesData.Notes {
+ for _, data := range notes {
response.Notes = append(response.Notes, &request_notes_for_team_response.NoteT{data})
}
diff --git a/scouting/webserver/requests/requests_test.go b/scouting/webserver/requests/requests_test.go
index 44fd5db..85ab916 100644
--- a/scouting/webserver/requests/requests_test.go
+++ b/scouting/webserver/requests/requests_test.go
@@ -314,8 +314,14 @@
builder := flatbuffers.NewBuilder(1024)
builder.Finish((&submit_notes.SubmitNotesT{
- Team: 971,
- Notes: "Notes",
+ Team: 971,
+ Notes: "Notes",
+ GoodDriving: true,
+ BadDriving: false,
+ SketchyClimb: true,
+ SolidClimb: false,
+ GoodDefense: true,
+ BadDefense: false,
}).Pack(builder))
_, err := debug.SubmitNotes("http://localhost:8080", builder.FinishedBytes())
@@ -324,7 +330,16 @@
}
expected := []db.NotesData{
- {TeamNumber: 971, Notes: []string{"Notes"}},
+ {
+ TeamNumber: 971,
+ Notes: "Notes",
+ GoodDriving: true,
+ BadDriving: false,
+ SketchyClimb: true,
+ SolidClimb: false,
+ GoodDefense: true,
+ BadDefense: false,
+ },
}
if !reflect.DeepEqual(database.notes, expected) {
@@ -335,8 +350,14 @@
func TestRequestNotes(t *testing.T) {
database := MockDatabase{
notes: []db.NotesData{{
- TeamNumber: 971,
- Notes: []string{"Notes"},
+ TeamNumber: 971,
+ Notes: "Notes",
+ GoodDriving: true,
+ BadDriving: false,
+ SketchyClimb: true,
+ SolidClimb: false,
+ GoodDefense: true,
+ BadDefense: false,
}},
}
scoutingServer := server.NewScoutingServer()
@@ -584,14 +605,14 @@
return []db.Stats{}, nil
}
-func (database *MockDatabase) QueryNotes(requestedTeam int32) (db.NotesData, error) {
+func (database *MockDatabase) QueryNotes(requestedTeam int32) ([]string, error) {
var results []string
for _, data := range database.notes {
if data.TeamNumber == requestedTeam {
- results = append(results, data.Notes[0])
+ results = append(results, data.Notes)
}
}
- return db.NotesData{TeamNumber: requestedTeam, Notes: results}, nil
+ return results, nil
}
func (database *MockDatabase) AddNotes(data db.NotesData) error {
diff --git a/scouting/www/entry/entry.component.css b/scouting/www/entry/entry.component.css
index 6d13657..a78a00a 100644
--- a/scouting/www/entry/entry.component.css
+++ b/scouting/www/entry/entry.component.css
@@ -8,8 +8,8 @@
}
textarea {
- width: 300px;
- height: 150px;
+ width: 350px;
+ height: 180px;
}
button {
diff --git a/scouting/www/entry/entry.ng.html b/scouting/www/entry/entry.ng.html
index 9be8db7..e73cfb0 100644
--- a/scouting/www/entry/entry.ng.html
+++ b/scouting/www/entry/entry.ng.html
@@ -254,10 +254,6 @@
</label>
<br />
</form>
- <div class="row">
- <h4>Comments</h4>
- <textarea [(ngModel)]="comment" id="comment"></textarea>
- </div>
<div class="buttons">
<button class="btn btn-primary" (click)="prevSection()">Back</button>
<button class="btn btn-primary" (click)="nextSection()">Next</button>
@@ -360,6 +356,15 @@
</form>
</div>
+ <div class="row">
+ <h4>General Comments About Match</h4>
+ <textarea
+ [(ngModel)]="comment"
+ id="comment"
+ placeholder="optional"
+ ></textarea>
+ </div>
+
<div class="buttons">
<button class="btn btn-primary" (click)="prevSection()">Back</button>
<button class="btn btn-primary" (click)="nextSection()">Next</button>
@@ -398,7 +403,6 @@
<h4>Climb</h4>
<ul>
<li>Climb Level: {{level | levelToString}}</li>
- <li>Comments: {{comment}}</li>
</ul>
<h4>Other</h4>
@@ -410,6 +414,7 @@
<li>Battery died: {{batteryDied}}</li>
<li>Broke (mechanically): {{mechanicallyBroke}}</li>
<li>Lost coms: {{lostComs}}</li>
+ <li>Comments: {{comment}}</li>
</ul>
<span class="error_message">{{ errorMessage }}</span>
diff --git a/scouting/www/notes/notes.component.css b/scouting/www/notes/notes.component.css
index 869bdab..67b2351 100644
--- a/scouting/www/notes/notes.component.css
+++ b/scouting/www/notes/notes.component.css
@@ -6,7 +6,6 @@
width: calc(100% - 20px);
}
-.buttons {
- display: flex;
- justify-content: space-between;
+.container-main {
+ padding-left: 20px;
}
diff --git a/scouting/www/notes/notes.component.ts b/scouting/www/notes/notes.component.ts
index 0f0eb82..00faddd 100644
--- a/scouting/www/notes/notes.component.ts
+++ b/scouting/www/notes/notes.component.ts
@@ -1,4 +1,4 @@
-import {Component} from '@angular/core';
+import {Component, HostListener} from '@angular/core';
import {Builder, ByteBuffer} from 'flatbuffers';
import {ErrorResponse} from 'org_frc971/scouting/webserver/requests/messages/error_response_generated';
import {RequestNotesForTeam} from 'org_frc971/scouting/webserver/requests/messages/request_notes_for_team_generated';
@@ -9,88 +9,169 @@
import {SubmitNotes} from 'org_frc971/scouting/webserver/requests/messages/submit_notes_generated';
import {SubmitNotesResponse} from 'org_frc971/scouting/webserver/requests/messages/submit_notes_response_generated';
+/*
+For new games, the keywords being used will likely need to be updated.
+To update the keywords complete the following:
+ 1) Update the Keywords Interface and KEYWORD_CHECKBOX_LABELS in notes.component.ts
+ The keys of Keywords and KEYWORD_CHECKBOX_LABELS should match.
+ 2) In notes.component.ts, update the setTeamNumber() method with the new keywords.
+ 3) Add/Edit the new keywords in /scouting/webserver/requests/messages/submit_notes.fbs.
+ 4) In notes.component.ts, update the submitData() method with the newKeywords
+ so that it matches the updated flatbuffer
+ 5) In db.go, update the NotesData struct and the
+ AddNotes method with the new keywords
+ 6) In db_test.go update the TestNotes method so the test uses the keywords
+ 7) Update the submitNoteScoutingHandler in requests.go with the new keywords
+ 8) Finally, update the corresponding test in requests_test.go (TestSubmitNotes)
+
+ Note: If you change the number of keywords you might need to
+ update how they are displayed in notes.ng.html
+*/
+
+// TeamSelection: Display form to add a team to the teams being scouted.
+// Data: Display the note textbox and keyword selection form
+// for all the teams being scouted.
type Section = 'TeamSelection' | 'Data';
-interface Note {
- readonly data: string;
+// Every keyword checkbox corresponds to a boolean.
+// If the boolean is True, the checkbox is selected
+// and the note scout saw that the robot being scouted
+// displayed said property (ex. Driving really well -> goodDriving)
+interface Keywords {
+ goodDriving: boolean;
+ badDriving: boolean;
+ sketchyClimb: boolean;
+ solidClimb: boolean;
+ goodDefense: boolean;
+ badDefense: boolean;
}
+interface Input {
+ teamNumber: number;
+ notesData: string;
+ keywordsData: Keywords;
+}
+
+const KEYWORD_CHECKBOX_LABELS = {
+ goodDriving: 'Good Driving',
+ badDriving: 'Bad Driving',
+ solidClimb: 'Solid Climb',
+ sketchyClimb: 'Sketchy Climb',
+ goodDefense: 'Good Defense',
+ badDefense: 'Bad Defense',
+} as const;
+
@Component({
selector: 'frc971-notes',
templateUrl: './notes.ng.html',
styleUrls: ['../common.css', './notes.component.css'],
})
export class Notes {
+ // Re-export KEYWORD_CHECKBOX_LABELS so that we can
+ // use it in the checkbox properties.
+ readonly KEYWORD_CHECKBOX_LABELS = KEYWORD_CHECKBOX_LABELS;
+
+ // Necessary in order to iterate the keys of KEYWORD_CHECKBOX_LABELS.
+ Object = Object;
+
section: Section = 'TeamSelection';
- notes: Note[] = [];
errorMessage = '';
+ teamNumberSelection: number = 971;
- teamNumber: number = 971;
- newData = '';
+ // Data inputted by user is stored in this array.
+ // Includes the team number, notes, and keyword selection.
+ newData: Input[] = [];
- async setTeamNumber() {
- const builder = new Builder();
- RequestNotesForTeam.startRequestNotesForTeam(builder);
- RequestNotesForTeam.addTeam(builder, this.teamNumber);
- builder.finish(RequestNotesForTeam.endRequestNotesForTeam(builder));
+ // Keyboard shortcuts to switch between text areas.
+ // Listens for Ctrl + number and focuses on the
+ // corresponding textbox.
+ // More Info: https://angular.io/api/core/HostListener
- const buffer = builder.asUint8Array();
- const res = await fetch('/requests/request/notes_for_team', {
- method: 'POST',
- body: buffer,
- });
-
- const resBuffer = await res.arrayBuffer();
- const fbBuffer = new ByteBuffer(new Uint8Array(resBuffer));
-
- if (res.ok) {
- this.notes = [];
- const parsedResponse =
- RequestNotesForTeamResponse.getRootAsRequestNotesForTeamResponse(
- fbBuffer
- );
- for (let i = 0; i < parsedResponse.notesLength(); i++) {
- const fbNote = parsedResponse.notes(i);
- this.notes.push({data: fbNote.data()});
+ @HostListener('window:keyup', ['$event'])
+ onEvent(event: KeyboardEvent) {
+ if (event.ctrlKey) {
+ if (event.code.includes('Digit')) {
+ this.handleFocus(event.key);
}
- this.section = 'Data';
- } else {
- const parsedResponse = ErrorResponse.getRootAsErrorResponse(fbBuffer);
-
- const errorMessage = parsedResponse.errorMessage();
- this.errorMessage = `Received ${res.status} ${res.statusText}: "${errorMessage}"`;
}
}
- changeTeam() {
+ handleFocus(digit: string) {
+ let textArea = <HTMLInputElement>(
+ document.getElementById('text-input-' + digit)
+ );
+ if (textArea != null) {
+ textArea.focus();
+ }
+ }
+
+ setTeamNumber() {
+ let data: Input = {
+ teamNumber: this.teamNumberSelection,
+ notesData: '',
+ keywordsData: {
+ goodDriving: false,
+ badDriving: false,
+ solidClimb: false,
+ sketchyClimb: false,
+ goodDefense: false,
+ badDefense: false,
+ },
+ };
+
+ this.newData.push(data);
+ this.section = 'Data';
+ }
+
+ removeTeam(index: number) {
+ this.newData.splice(index, 1);
+ if (this.newData.length == 0) {
+ this.section = 'TeamSelection';
+ } else {
+ this.section = 'Data';
+ }
+ }
+
+ addTeam() {
this.section = 'TeamSelection';
}
async submitData() {
- const builder = new Builder();
- const dataFb = builder.createString(this.newData);
- builder.finish(
- SubmitNotes.createSubmitNotes(builder, this.teamNumber, dataFb)
- );
+ for (let i = 0; i < this.newData.length; i++) {
+ const builder = new Builder();
+ const dataFb = builder.createString(this.newData[i].notesData);
+ builder.finish(
+ SubmitNotes.createSubmitNotes(
+ builder,
+ this.newData[i].teamNumber,
+ dataFb,
+ this.newData[i].keywordsData.goodDriving,
+ this.newData[i].keywordsData.badDriving,
+ this.newData[i].keywordsData.sketchyClimb,
+ this.newData[i].keywordsData.solidClimb,
+ this.newData[i].keywordsData.goodDefense,
+ this.newData[i].keywordsData.badDefense
+ )
+ );
- const buffer = builder.asUint8Array();
- const res = await fetch('/requests/submit/submit_notes', {
- method: 'POST',
- body: buffer,
- });
+ const buffer = builder.asUint8Array();
+ const res = await fetch('/requests/submit/submit_notes', {
+ method: 'POST',
+ body: buffer,
+ });
- if (res.ok) {
- this.newData = '';
- this.errorMessage = '';
- await this.setTeamNumber();
- } else {
- const resBuffer = await res.arrayBuffer();
- const fbBuffer = new ByteBuffer(new Uint8Array(resBuffer));
- const parsedResponse = ErrorResponse.getRootAsErrorResponse(fbBuffer);
-
- const errorMessage = parsedResponse.errorMessage();
- this.errorMessage = `Received ${res.status} ${res.statusText}: "${errorMessage}"`;
+ if (!res.ok) {
+ const resBuffer = await res.arrayBuffer();
+ const fbBuffer = new ByteBuffer(new Uint8Array(resBuffer));
+ const parsedResponse = ErrorResponse.getRootAsErrorResponse(fbBuffer);
+ const errorMessage = parsedResponse.errorMessage();
+ this.errorMessage = `Received ${res.status} ${res.statusText}: "${errorMessage}"`;
+ }
}
+
+ this.newData = [];
+ this.errorMessage = '';
+ this.section = 'TeamSelection';
}
}
diff --git a/scouting/www/notes/notes.ng.html b/scouting/www/notes/notes.ng.html
index a69ba88..b51a7ce 100644
--- a/scouting/www/notes/notes.ng.html
+++ b/scouting/www/notes/notes.ng.html
@@ -1,10 +1,12 @@
-<h2>Notes</h2>
+<h2 id="page-title">Notes</h2>
<ng-container [ngSwitch]="section">
<div *ngSwitchCase="'TeamSelection'">
- <label for="team_number_notes">Team Number</label>
+ <label id="team_number_label" class="label" for="team_number_notes">
+ Team Number
+ </label>
<input
- [(ngModel)]="teamNumber"
+ [(ngModel)]="teamNumberSelection"
type="number"
id="team_number_notes"
min="1"
@@ -14,17 +16,107 @@
</div>
<div *ngSwitchCase="'Data'">
- <h3>Scouting team: {{teamNumber}}</h3>
- <ul *ngFor="let note of notes">
- <li class="note">{{ note.data }}</li>
- </ul>
- <textarea class="text-input" [(ngModel)]="newData"></textarea>
- <div class="buttons">
- <button class="btn btn-primary" (click)="changeTeam()">
- Change team
- </button>
- <button class="btn btn-primary" (click)="submitData()">Submit</button>
+ <div class="container-main" *ngFor="let team of newData; let i = index">
+ <div class="pt-2 pb-2">
+ <div class="d-flex flex-row">
+ <div>
+ <button
+ class="btn bg-transparent ml-10 md-5"
+ (click)="removeTeam(i)"
+ >
+ ✖
+ <!--X Symbol-->
+ </button>
+ </div>
+ <div><h3 id="team-key-{{i+1}}">{{team.teamNumber}}</h3></div>
+ </div>
+ <div class="">
+ <!--
+ Note Input Text Areas.
+ ID property is used for keyboard shorcuts to focus
+ on the corresponding text area.
+ The data-toggle and title properties are
+ used for bootstrap tooltips.
+ -->
+ <textarea
+ class="text-input"
+ id="text-input-{{i+1}}"
+ [(ngModel)]="newData[i].notesData"
+ data-toggle="tooltip"
+ title="Ctrl + {{i+1}}"
+ ></textarea>
+ </div>
+ <!--Key Word Checkboxes-->
+ <!--Row 1 (Prevent Overflow on mobile by splitting checkboxes into 2 rows)-->
+ <!--Slice KEYWORD_CHECKBOX_LABELS using https://angular.io/api/common/SlicePipe-->
+ <div class="d-flex flex-row justify-content-around">
+ <div
+ *ngFor="let key of Object.keys(KEYWORD_CHECKBOX_LABELS) | slice:0:((Object.keys(KEYWORD_CHECKBOX_LABELS).length)/2); let k = index"
+ >
+ <div class="form-check">
+ <input
+ class="form-check-input"
+ [(ngModel)]="newData[i]['keywordsData'][key]"
+ type="checkbox"
+ id="{{KEYWORD_CHECKBOX_LABELS[key]}}_{{i}}"
+ name="{{KEYWORD_CHECKBOX_LABELS[key]}}"
+ />
+ <label
+ class="form-check-label"
+ for="{{KEYWORD_CHECKBOX_LABELS[key]}}_{{i}}"
+ >
+ {{KEYWORD_CHECKBOX_LABELS[key]}}
+ </label>
+ <br />
+ </div>
+ </div>
+ </div>
+ <!--Row 2 (Prevent Overflow on mobile by splitting checkboxes into 2 rows)-->
+ <div class="d-flex flex-row justify-content-around">
+ <div
+ *ngFor="let key of Object.keys(KEYWORD_CHECKBOX_LABELS) | slice:3:(Object.keys(KEYWORD_CHECKBOX_LABELS).length); let k = index"
+ >
+ <div class="form-check">
+ <input
+ class="form-check-input"
+ [(ngModel)]="newData[i]['keywordsData'][key]"
+ type="checkbox"
+ id="{{KEYWORD_CHECKBOX_LABELS[key]}}"
+ name="{{KEYWORD_CHECKBOX_LABELS[key]}}"
+ />
+ <label
+ class="form-check-label"
+ for="{{KEYWORD_CHECKBOX_LABELS[key]}}"
+ >
+ {{KEYWORD_CHECKBOX_LABELS[key]}}
+ </label>
+ <br />
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="d-flex flex-row justify-content-center pt-2">
+ <div>
+ <button
+ id="add-team-button"
+ class="btn btn-secondary"
+ (click)="addTeam()"
+ >
+ Add team
+ </button>
+ </div>
+ <div>
+ <button
+ id="submit-button"
+ class="btn btn-success"
+ (click)="submitData()"
+ >
+ Submit
+ </button>
+ </div>
</div>
</div>
+
<div class="error">{{errorMessage}}</div>
</ng-container>
diff --git a/tools/go/go_mirrors.bzl b/tools/go/go_mirrors.bzl
index ee8b1b8..338cc95 100644
--- a/tools/go/go_mirrors.bzl
+++ b/tools/go/go_mirrors.bzl
@@ -1,11 +1,11 @@
# This file is auto-generated. Do not edit.
GO_MIRROR_INFO = {
"co_honnef_go_tools": {
- "filename": "co_honnef_go_tools__v0.0.0-20190523083050-ea95bdfd59fc.zip",
+ "filename": "co_honnef_go_tools__v0.0.1-2019.2.3.zip",
"importpath": "honnef.co/go/tools",
- "sha256": "eeaa82700e96ac5e803d7a9c32363332504beff8fbb1202492b4d43d5a5e7360",
- "strip_prefix": "honnef.co/go/tools@v0.0.0-20190523083050-ea95bdfd59fc",
- "version": "v0.0.0-20190523083050-ea95bdfd59fc",
+ "sha256": "539825114c487680f99df80f6107410e1e53bbfd5deb931b84d1faf2d221638e",
+ "strip_prefix": "honnef.co/go/tools@v0.0.1-2019.2.3",
+ "version": "v0.0.1-2019.2.3",
},
"com_github_antihax_optional": {
"filename": "com_github_antihax_optional__v1.0.0.zip",
@@ -77,6 +77,20 @@
"strip_prefix": "github.com/cockroachdb/apd@v1.1.0",
"version": "v1.1.0",
},
+ "com_github_coreos_go_systemd": {
+ "filename": "com_github_coreos_go_systemd__v0.0.0-20190719114852-fd7a80b32e1f.zip",
+ "importpath": "github.com/coreos/go-systemd",
+ "sha256": "22237f0aed3ab6018a1025c65f4f45b4c05f9aa0c0bb9ec880294273b9a15bf2",
+ "strip_prefix": "github.com/coreos/go-systemd@v0.0.0-20190719114852-fd7a80b32e1f",
+ "version": "v0.0.0-20190719114852-fd7a80b32e1f",
+ },
+ "com_github_creack_pty": {
+ "filename": "com_github_creack_pty__v1.1.7.zip",
+ "importpath": "github.com/creack/pty",
+ "sha256": "e7ea3403784d186aefbe84caed958f8cba2e72a04f30cdb291ece19bec39c8f3",
+ "strip_prefix": "github.com/creack/pty@v1.1.7",
+ "version": "v1.1.7",
+ },
"com_github_davecgh_go_spew": {
"filename": "com_github_davecgh_go_spew__v1.1.1.zip",
"importpath": "github.com/davecgh/go-spew",
@@ -105,6 +119,27 @@
"strip_prefix": "github.com/ghodss/yaml@v1.0.0",
"version": "v1.0.0",
},
+ "com_github_go_kit_log": {
+ "filename": "com_github_go_kit_log__v0.1.0.zip",
+ "importpath": "github.com/go-kit/log",
+ "sha256": "e0676df7357654a000008dfad3b6b211cba3595f32d3e220edd63a4c9d0d9254",
+ "strip_prefix": "github.com/go-kit/log@v0.1.0",
+ "version": "v0.1.0",
+ },
+ "com_github_go_logfmt_logfmt": {
+ "filename": "com_github_go_logfmt_logfmt__v0.5.0.zip",
+ "importpath": "github.com/go-logfmt/logfmt",
+ "sha256": "59a6b59ae3da84f7a58373844ca8d298f5007ce0e173437fc85c26d4fc76ca8b",
+ "strip_prefix": "github.com/go-logfmt/logfmt@v0.5.0",
+ "version": "v0.5.0",
+ },
+ "com_github_go_stack_stack": {
+ "filename": "com_github_go_stack_stack__v1.8.0.zip",
+ "importpath": "github.com/go-stack/stack",
+ "sha256": "78c2667c710f811307038634ffa43af442619acfeaf1efb593aa4e0ded9df48f",
+ "strip_prefix": "github.com/go-stack/stack@v1.8.0",
+ "version": "v1.8.0",
+ },
"com_github_gofrs_uuid": {
"filename": "com_github_gofrs_uuid__v4.0.0+incompatible.zip",
"importpath": "github.com/gofrs/uuid",
@@ -147,6 +182,13 @@
"strip_prefix": "github.com/google/go-querystring@v1.1.0",
"version": "v1.1.0",
},
+ "com_github_google_renameio": {
+ "filename": "com_github_google_renameio__v0.1.0.zip",
+ "importpath": "github.com/google/renameio",
+ "sha256": "b8510bb34078691a20b8e4902d371afe0eb171b2daf953f67cb3960d1926ccf3",
+ "strip_prefix": "github.com/google/renameio@v0.1.0",
+ "version": "v0.1.0",
+ },
"com_github_google_uuid": {
"filename": "com_github_google_uuid__v1.1.2.zip",
"importpath": "github.com/google/uuid",
@@ -161,19 +203,138 @@
"strip_prefix": "github.com/grpc-ecosystem/grpc-gateway@v1.16.0",
"version": "v1.16.0",
},
- "com_github_jackc_fake": {
- "filename": "com_github_jackc_fake__v0.0.0-20150926172116-812a484cc733.zip",
- "importpath": "github.com/jackc/fake",
- "sha256": "bf8b5b51ae03f572a70a0582dc663c5733bba9aca785d39bb0367797148e6d64",
- "strip_prefix": "github.com/jackc/fake@v0.0.0-20150926172116-812a484cc733",
- "version": "v0.0.0-20150926172116-812a484cc733",
+ "com_github_jackc_chunkreader": {
+ "filename": "com_github_jackc_chunkreader__v1.0.0.zip",
+ "importpath": "github.com/jackc/chunkreader",
+ "sha256": "e204c917e2652ffe047f5c8b031192757321f568654e3df8408bf04178df1408",
+ "strip_prefix": "github.com/jackc/chunkreader@v1.0.0",
+ "version": "v1.0.0",
},
- "com_github_jackc_pgx": {
- "filename": "com_github_jackc_pgx__v3.6.2+incompatible.zip",
- "importpath": "github.com/jackc/pgx",
- "sha256": "73675895baa0da97b2f0ce6e895c69b7c77ad994e30ce6a1add2abc3bb17e375",
- "strip_prefix": "github.com/jackc/pgx@v3.6.2+incompatible",
- "version": "v3.6.2+incompatible",
+ "com_github_jackc_chunkreader_v2": {
+ "filename": "com_github_jackc_chunkreader_v2__v2.0.1.zip",
+ "importpath": "github.com/jackc/chunkreader/v2",
+ "sha256": "6e3f4b7d9647f31061f6446ae10de71fc1407e64f84cd0949afac0cd231e8dd2",
+ "strip_prefix": "github.com/jackc/chunkreader/v2@v2.0.1",
+ "version": "v2.0.1",
+ },
+ "com_github_jackc_pgconn": {
+ "filename": "com_github_jackc_pgconn__v1.12.1.zip",
+ "importpath": "github.com/jackc/pgconn",
+ "sha256": "48d34064a1facff7766713d9224502e7376a5d90c1506f99a37c57bfceaf9636",
+ "strip_prefix": "github.com/jackc/pgconn@v1.12.1",
+ "version": "v1.12.1",
+ },
+ "com_github_jackc_pgio": {
+ "filename": "com_github_jackc_pgio__v1.0.0.zip",
+ "importpath": "github.com/jackc/pgio",
+ "sha256": "1a83c03d53f6a40339364cafcbbabb44238203c79ca0c9b98bf582d0df0e0468",
+ "strip_prefix": "github.com/jackc/pgio@v1.0.0",
+ "version": "v1.0.0",
+ },
+ "com_github_jackc_pgmock": {
+ "filename": "com_github_jackc_pgmock__v0.0.0-20210724152146-4ad1a8207f65.zip",
+ "importpath": "github.com/jackc/pgmock",
+ "sha256": "0fffd0a7a67dbdfafa04297e51028c6d2d08cd6691f3b6d78d7ae6502d3d4cf2",
+ "strip_prefix": "github.com/jackc/pgmock@v0.0.0-20210724152146-4ad1a8207f65",
+ "version": "v0.0.0-20210724152146-4ad1a8207f65",
+ },
+ "com_github_jackc_pgpassfile": {
+ "filename": "com_github_jackc_pgpassfile__v1.0.0.zip",
+ "importpath": "github.com/jackc/pgpassfile",
+ "sha256": "1cc79fb0b80f54b568afd3f4648dd1c349f746ad7c379df8d7f9e0eb1cac938b",
+ "strip_prefix": "github.com/jackc/pgpassfile@v1.0.0",
+ "version": "v1.0.0",
+ },
+ "com_github_jackc_pgproto3": {
+ "filename": "com_github_jackc_pgproto3__v1.1.0.zip",
+ "importpath": "github.com/jackc/pgproto3",
+ "sha256": "e3766bee50ed74e49a067b2c4797a2c69015cf104bf3f3624cd483a9e940b4ee",
+ "strip_prefix": "github.com/jackc/pgproto3@v1.1.0",
+ "version": "v1.1.0",
+ },
+ "com_github_jackc_pgproto3_v2": {
+ "filename": "com_github_jackc_pgproto3_v2__v2.3.0.zip",
+ "importpath": "github.com/jackc/pgproto3/v2",
+ "sha256": "6b702c372e13520636243d3be58922968f0630b67e23ba77326ef6ee4cada463",
+ "strip_prefix": "github.com/jackc/pgproto3/v2@v2.3.0",
+ "version": "v2.3.0",
+ },
+ "com_github_jackc_pgservicefile": {
+ "filename": "com_github_jackc_pgservicefile__v0.0.0-20200714003250-2b9c44734f2b.zip",
+ "importpath": "github.com/jackc/pgservicefile",
+ "sha256": "8422a25b9d2b0be05c66ee1ccfdbaab144ce98f1ac678bc647064c560d4cd6e2",
+ "strip_prefix": "github.com/jackc/pgservicefile@v0.0.0-20200714003250-2b9c44734f2b",
+ "version": "v0.0.0-20200714003250-2b9c44734f2b",
+ },
+ "com_github_jackc_pgtype": {
+ "filename": "com_github_jackc_pgtype__v1.11.0.zip",
+ "importpath": "github.com/jackc/pgtype",
+ "sha256": "6a257b81c0bd386d6241219a14ebd41d574a02aeaeb3942670c06441b864dcad",
+ "strip_prefix": "github.com/jackc/pgtype@v1.11.0",
+ "version": "v1.11.0",
+ },
+ "com_github_jackc_pgx_v4": {
+ "filename": "com_github_jackc_pgx_v4__v4.16.1.zip",
+ "importpath": "github.com/jackc/pgx/v4",
+ "sha256": "c3a169a68ff0e56f9f81eee4de4d2fd2a5ec7f4d6be159159325f4863c80bd10",
+ "strip_prefix": "github.com/jackc/pgx/v4@v4.16.1",
+ "version": "v4.16.1",
+ },
+ "com_github_jackc_puddle": {
+ "filename": "com_github_jackc_puddle__v1.2.1.zip",
+ "importpath": "github.com/jackc/puddle",
+ "sha256": "40d73550686666eb1f6df02b65008b2a4c98cfed1254dc4866e6ebe95fbc5c95",
+ "strip_prefix": "github.com/jackc/puddle@v1.2.1",
+ "version": "v1.2.1",
+ },
+ "com_github_jinzhu_inflection": {
+ "filename": "com_github_jinzhu_inflection__v1.0.0.zip",
+ "importpath": "github.com/jinzhu/inflection",
+ "sha256": "cf1087a6f6653ed5f366f85cf0110bbbf581d4e9bc8a4d1a9b56765d94b546c3",
+ "strip_prefix": "github.com/jinzhu/inflection@v1.0.0",
+ "version": "v1.0.0",
+ },
+ "com_github_jinzhu_now": {
+ "filename": "com_github_jinzhu_now__v1.1.4.zip",
+ "importpath": "github.com/jinzhu/now",
+ "sha256": "245473b8e50be3897751ec66dd6be93588de261920e0345b500f692924575872",
+ "strip_prefix": "github.com/jinzhu/now@v1.1.4",
+ "version": "v1.1.4",
+ },
+ "com_github_kisielk_gotool": {
+ "filename": "com_github_kisielk_gotool__v1.0.0.zip",
+ "importpath": "github.com/kisielk/gotool",
+ "sha256": "089dbba6e3aa09944fdb40d72acc86694e8bdde01cfc0f40fe0248309eb80a3f",
+ "strip_prefix": "github.com/kisielk/gotool@v1.0.0",
+ "version": "v1.0.0",
+ },
+ "com_github_konsorten_go_windows_terminal_sequences": {
+ "filename": "com_github_konsorten_go_windows_terminal_sequences__v1.0.2.zip",
+ "importpath": "github.com/konsorten/go-windows-terminal-sequences",
+ "sha256": "4d00d71b8de60bcaf454f8f867210ebcd05e75c0a7c2725904f71aa2f20fb08e",
+ "strip_prefix": "github.com/konsorten/go-windows-terminal-sequences@v1.0.2",
+ "version": "v1.0.2",
+ },
+ "com_github_kr_pretty": {
+ "filename": "com_github_kr_pretty__v0.1.0.zip",
+ "importpath": "github.com/kr/pretty",
+ "sha256": "06063d21457e06dc2aba4a5bd09771147ec3d8ab40b224f26e55c5a76089ca43",
+ "strip_prefix": "github.com/kr/pretty@v0.1.0",
+ "version": "v0.1.0",
+ },
+ "com_github_kr_pty": {
+ "filename": "com_github_kr_pty__v1.1.8.zip",
+ "importpath": "github.com/kr/pty",
+ "sha256": "d66e6fbc65e772289a7ff8c58ab2cdfb886253053b0cea11ba3ca1738b2d6bc6",
+ "strip_prefix": "github.com/kr/pty@v1.1.8",
+ "version": "v1.1.8",
+ },
+ "com_github_kr_text": {
+ "filename": "com_github_kr_text__v0.1.0.zip",
+ "importpath": "github.com/kr/text",
+ "sha256": "9363a4c8f1f3387a36014de51b477b831a13981fc59a5665f9d21609bea9e77c",
+ "strip_prefix": "github.com/kr/text@v0.1.0",
+ "version": "v0.1.0",
},
"com_github_lib_pq": {
"filename": "com_github_lib_pq__v1.10.2.zip",
@@ -182,6 +343,27 @@
"strip_prefix": "github.com/lib/pq@v1.10.2",
"version": "v1.10.2",
},
+ "com_github_masterminds_semver_v3": {
+ "filename": "com_github_masterminds_semver_v3__v3.1.1.zip",
+ "importpath": "github.com/Masterminds/semver/v3",
+ "sha256": "0a46c7403dfeda09b0821e851f8e1cec8f1ea4276281e42ea399da5bc5bf0704",
+ "strip_prefix": "github.com/Masterminds/semver/v3@v3.1.1",
+ "version": "v3.1.1",
+ },
+ "com_github_mattn_go_colorable": {
+ "filename": "com_github_mattn_go_colorable__v0.1.6.zip",
+ "importpath": "github.com/mattn/go-colorable",
+ "sha256": "0da5d3779775f6fe5d007e7ec8e0afc136c4bd7b8c9b5cd73254db26773cf4dc",
+ "strip_prefix": "github.com/mattn/go-colorable@v0.1.6",
+ "version": "v0.1.6",
+ },
+ "com_github_mattn_go_isatty": {
+ "filename": "com_github_mattn_go_isatty__v0.0.12.zip",
+ "importpath": "github.com/mattn/go-isatty",
+ "sha256": "07941d24e0894c29dc42bcd29d644815cd7b5ee84e3c14bbe6d51ad13efcbf07",
+ "strip_prefix": "github.com/mattn/go-isatty@v0.0.12",
+ "version": "v0.0.12",
+ },
"com_github_phst_runfiles": {
"filename": "com_github_phst_runfiles__v0.0.0-20220125203201-388095b3a22d.zip",
"importpath": "github.com/phst/runfiles",
@@ -217,6 +399,34 @@
"strip_prefix": "github.com/rogpeppe/fastuuid@v1.2.0",
"version": "v1.2.0",
},
+ "com_github_rogpeppe_go_internal": {
+ "filename": "com_github_rogpeppe_go_internal__v1.3.0.zip",
+ "importpath": "github.com/rogpeppe/go-internal",
+ "sha256": "191b95c35d85a5683cee6e303a08b4d103bf9de9ececdc6904f21ed90c094b0a",
+ "strip_prefix": "github.com/rogpeppe/go-internal@v1.3.0",
+ "version": "v1.3.0",
+ },
+ "com_github_rs_xid": {
+ "filename": "com_github_rs_xid__v1.2.1.zip",
+ "importpath": "github.com/rs/xid",
+ "sha256": "4abdedc4de69adcb9a4575f99c59d8ab542191e1800b6a91e12a4e9ea8da0026",
+ "strip_prefix": "github.com/rs/xid@v1.2.1",
+ "version": "v1.2.1",
+ },
+ "com_github_rs_zerolog": {
+ "filename": "com_github_rs_zerolog__v1.15.0.zip",
+ "importpath": "github.com/rs/zerolog",
+ "sha256": "8e98c48e7fd132aafbf129664e8fd65229d067d772bff4bd712a497b7a2f00c4",
+ "strip_prefix": "github.com/rs/zerolog@v1.15.0",
+ "version": "v1.15.0",
+ },
+ "com_github_satori_go_uuid": {
+ "filename": "com_github_satori_go_uuid__v1.2.0.zip",
+ "importpath": "github.com/satori/go.uuid",
+ "sha256": "4f741306a0cbe97581e34a638531bcafe3c2848150539a2ec2ba12c5e3e6cbdd",
+ "strip_prefix": "github.com/satori/go.uuid@v1.2.0",
+ "version": "v1.2.0",
+ },
"com_github_shopspring_decimal": {
"filename": "com_github_shopspring_decimal__v1.2.0.zip",
"importpath": "github.com/shopspring/decimal",
@@ -224,12 +434,19 @@
"strip_prefix": "github.com/shopspring/decimal@v1.2.0",
"version": "v1.2.0",
},
+ "com_github_sirupsen_logrus": {
+ "filename": "com_github_sirupsen_logrus__v1.4.2.zip",
+ "importpath": "github.com/sirupsen/logrus",
+ "sha256": "9a8e55830261a4b1c9350d7c45db029c8586c0b2d934d1224cde469425031edd",
+ "strip_prefix": "github.com/sirupsen/logrus@v1.4.2",
+ "version": "v1.4.2",
+ },
"com_github_stretchr_objx": {
- "filename": "com_github_stretchr_objx__v0.1.0.zip",
+ "filename": "com_github_stretchr_objx__v0.2.0.zip",
"importpath": "github.com/stretchr/objx",
- "sha256": "1fa10dab404ed7fc8ed2a033f8784187d5df3513ced3841ce39e46d37850eb1d",
- "strip_prefix": "github.com/stretchr/objx@v0.1.0",
- "version": "v0.1.0",
+ "sha256": "5517d43cfb7e628b9c2c64010b934e346cd24726e3d6eaf02b7f86e10752e968",
+ "strip_prefix": "github.com/stretchr/objx@v0.2.0",
+ "version": "v0.2.0",
},
"com_github_stretchr_testify": {
"filename": "com_github_stretchr_testify__v1.7.0.zip",
@@ -238,6 +455,13 @@
"strip_prefix": "github.com/stretchr/testify@v1.7.0",
"version": "v1.7.0",
},
+ "com_github_zenazn_goji": {
+ "filename": "com_github_zenazn_goji__v0.9.0.zip",
+ "importpath": "github.com/zenazn/goji",
+ "sha256": "0807a255d9d715d18427a6eedd8e4f5a22670b09e5f45fddd229c1ae38da25a9",
+ "strip_prefix": "github.com/zenazn/goji@v0.9.0",
+ "version": "v0.9.0",
+ },
"com_google_cloud_go": {
"filename": "com_google_cloud_go__v0.34.0.zip",
"importpath": "cloud.google.com/go",
@@ -246,11 +470,25 @@
"version": "v0.34.0",
},
"in_gopkg_check_v1": {
- "filename": "in_gopkg_check_v1__v0.0.0-20161208181325-20d25e280405.zip",
+ "filename": "in_gopkg_check_v1__v1.0.0-20180628173108-788fd7840127.zip",
"importpath": "gopkg.in/check.v1",
- "sha256": "4e1817f964ca34e545b81afda0325a5e89cf58de2e413d8207c0afddd0fdc15c",
- "strip_prefix": "gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405",
- "version": "v0.0.0-20161208181325-20d25e280405",
+ "sha256": "4bc535ed2aac48a231af8b6005a0b5f6069dadab9a3d65b1e9f1fe91c74d8e61",
+ "strip_prefix": "gopkg.in/check.v1@v1.0.0-20180628173108-788fd7840127",
+ "version": "v1.0.0-20180628173108-788fd7840127",
+ },
+ "in_gopkg_errgo_v2": {
+ "filename": "in_gopkg_errgo_v2__v2.1.0.zip",
+ "importpath": "gopkg.in/errgo.v2",
+ "sha256": "6b8954819a20ec52982a206fd3eb94629ff53c5790aa77534e6d8daf7de01bee",
+ "strip_prefix": "gopkg.in/errgo.v2@v2.1.0",
+ "version": "v2.1.0",
+ },
+ "in_gopkg_inconshreveable_log15_v2": {
+ "filename": "in_gopkg_inconshreveable_log15_v2__v2.0.0-20180818164646-67afb5ed74ec.zip",
+ "importpath": "gopkg.in/inconshreveable/log15.v2",
+ "sha256": "799307ed46ca30ca0ac2dc0332f3673814b8ff6cc1ee905a462ccfd438e8e695",
+ "strip_prefix": "gopkg.in/inconshreveable/log15.v2@v2.0.0-20180818164646-67afb5ed74ec",
+ "version": "v2.0.0-20180818164646-67afb5ed74ec",
},
"in_gopkg_yaml_v2": {
"filename": "in_gopkg_yaml_v2__v2.2.3.zip",
@@ -266,6 +504,20 @@
"strip_prefix": "gopkg.in/yaml.v3@v3.0.0-20200313102051-9f266ea9e77c",
"version": "v3.0.0-20200313102051-9f266ea9e77c",
},
+ "io_gorm_driver_postgres": {
+ "filename": "io_gorm_driver_postgres__v1.3.7.zip",
+ "importpath": "gorm.io/driver/postgres",
+ "sha256": "b38fed3060ea8ee200d50666a9c6230f2c387d4ab930b70dd859b93f5fac7771",
+ "strip_prefix": "gorm.io/driver/postgres@v1.3.7",
+ "version": "v1.3.7",
+ },
+ "io_gorm_gorm": {
+ "filename": "io_gorm_gorm__v1.23.5.zip",
+ "importpath": "gorm.io/gorm",
+ "sha256": "34219a6d2ac9b9c340f811e5863a98b150db6d1fd5b8f02777299863c1628e0f",
+ "strip_prefix": "gorm.io/gorm@v1.23.5",
+ "version": "v1.23.5",
+ },
"io_opentelemetry_go_proto_otlp": {
"filename": "io_opentelemetry_go_proto_otlp__v0.7.0.zip",
"importpath": "go.opentelemetry.io/proto/otlp",
@@ -302,11 +554,11 @@
"version": "v1.26.0",
},
"org_golang_x_crypto": {
- "filename": "org_golang_x_crypto__v0.0.0-20210711020723-a769d52b0f97.zip",
+ "filename": "org_golang_x_crypto__v0.0.0-20210921155107-089bfa567519.zip",
"importpath": "golang.org/x/crypto",
- "sha256": "b2b28fcf49bf385183f0369851145ddd93989f68d9e675db536a3dd482ca6d76",
- "strip_prefix": "golang.org/x/crypto@v0.0.0-20210711020723-a769d52b0f97",
- "version": "v0.0.0-20210711020723-a769d52b0f97",
+ "sha256": "eb2426a7891915213cc5da1da7b6fc6e9e2cf253d518d8e169e038e287f414e3",
+ "strip_prefix": "golang.org/x/crypto@v0.0.0-20210921155107-089bfa567519",
+ "version": "v0.0.0-20210921155107-089bfa567519",
},
"org_golang_x_exp": {
"filename": "org_golang_x_exp__v0.0.0-20190121172915-509febef88a4.zip",
@@ -316,11 +568,18 @@
"version": "v0.0.0-20190121172915-509febef88a4",
},
"org_golang_x_lint": {
- "filename": "org_golang_x_lint__v0.0.0-20190313153728-d0100b6bd8b3.zip",
+ "filename": "org_golang_x_lint__v0.0.0-20190930215403-16217165b5de.zip",
"importpath": "golang.org/x/lint",
- "sha256": "5c7bb9792bdc4ec4cf1af525cf9998f8a958daf6495852c9a7dbb71738f2f10a",
- "strip_prefix": "golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3",
- "version": "v0.0.0-20190313153728-d0100b6bd8b3",
+ "sha256": "91323fe1a77f13de722a0ce8efc5c5f2da4f26216d858acec64cb23c956fa163",
+ "strip_prefix": "golang.org/x/lint@v0.0.0-20190930215403-16217165b5de",
+ "version": "v0.0.0-20190930215403-16217165b5de",
+ },
+ "org_golang_x_mod": {
+ "filename": "org_golang_x_mod__v0.1.1-0.20191105210325-c90efee705ee.zip",
+ "importpath": "golang.org/x/mod",
+ "sha256": "b1e6cb975c69d29974b4f77fd8a0f2f7e916a1fa971bab60fdd45ffe80a29f32",
+ "strip_prefix": "golang.org/x/mod@v0.1.1-0.20191105210325-c90efee705ee",
+ "version": "v0.1.1-0.20191105210325-c90efee705ee",
},
"org_golang_x_net": {
"filename": "org_golang_x_net__v0.0.0-20210226172049-e18ecbb05110.zip",
@@ -358,18 +617,18 @@
"version": "v0.0.0-20201126162022-7de9c90e9dd1",
},
"org_golang_x_text": {
- "filename": "org_golang_x_text__v0.3.6.zip",
+ "filename": "org_golang_x_text__v0.3.7.zip",
"importpath": "golang.org/x/text",
- "sha256": "2afade648a4cb240afb7b3bf8e3719b615169c90d6281bd6d4ba34629c744579",
- "strip_prefix": "golang.org/x/text@v0.3.6",
- "version": "v0.3.6",
+ "sha256": "e1a9115e61a38da8bdc893d0ba83b65f89cc1114f152a98eb572c5ea6551e8d4",
+ "strip_prefix": "golang.org/x/text@v0.3.7",
+ "version": "v0.3.7",
},
"org_golang_x_tools": {
- "filename": "org_golang_x_tools__v0.0.0-20190524140312-2c0ae7006135.zip",
+ "filename": "org_golang_x_tools__v0.0.0-20200103221440-774c71fcf114.zip",
"importpath": "golang.org/x/tools",
- "sha256": "86687e8cd5adccf8809ba031e59146d0c89047b6267aacc785ffc20b0ce6b735",
- "strip_prefix": "golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135",
- "version": "v0.0.0-20190524140312-2c0ae7006135",
+ "sha256": "1c26b6b98d945255dfb6112d71135de3919350250e44e552a7089f724d0b7bfc",
+ "strip_prefix": "golang.org/x/tools@v0.0.0-20200103221440-774c71fcf114",
+ "version": "v0.0.0-20200103221440-774c71fcf114",
},
"org_golang_x_xerrors": {
"filename": "org_golang_x_xerrors__v0.0.0-20200804184101-5ec99f83aff1.zip",
@@ -378,4 +637,32 @@
"strip_prefix": "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1",
"version": "v0.0.0-20200804184101-5ec99f83aff1",
},
+ "org_uber_go_atomic": {
+ "filename": "org_uber_go_atomic__v1.6.0.zip",
+ "importpath": "go.uber.org/atomic",
+ "sha256": "c5e1e9f48017d7c7f7bb4532235e33242a1508bee68abe3cd301b68fe8ecd552",
+ "strip_prefix": "go.uber.org/atomic@v1.6.0",
+ "version": "v1.6.0",
+ },
+ "org_uber_go_multierr": {
+ "filename": "org_uber_go_multierr__v1.5.0.zip",
+ "importpath": "go.uber.org/multierr",
+ "sha256": "64053b7f6129cf2588f9b9ef1e934a26a0381da0002add973ec99f1294c1fc1e",
+ "strip_prefix": "go.uber.org/multierr@v1.5.0",
+ "version": "v1.5.0",
+ },
+ "org_uber_go_tools": {
+ "filename": "org_uber_go_tools__v0.0.0-20190618225709-2cfd321de3ee.zip",
+ "importpath": "go.uber.org/tools",
+ "sha256": "988dba9c5074080240d33d98e8ce511532f728698db7a9a4ac316c02c94030d6",
+ "strip_prefix": "go.uber.org/tools@v0.0.0-20190618225709-2cfd321de3ee",
+ "version": "v0.0.0-20190618225709-2cfd321de3ee",
+ },
+ "org_uber_go_zap": {
+ "filename": "org_uber_go_zap__v1.13.0.zip",
+ "importpath": "go.uber.org/zap",
+ "sha256": "4b4d15be7b4ce8029ab7c90f2fcb4c98e655172ebaa5cdbe234401081000fa26",
+ "strip_prefix": "go.uber.org/zap@v1.13.0",
+ "version": "v1.13.0",
+ },
}
diff --git a/y2022/BUILD b/y2022/BUILD
index 5d29f04..4a351a5 100644
--- a/y2022/BUILD
+++ b/y2022/BUILD
@@ -47,6 +47,7 @@
],
data = [
":aos_config",
+ ":message_bridge_client.sh",
"//y2022/image_streamer:image_streamer_start",
],
dirs = [
diff --git a/y2022/constants.cc b/y2022/constants.cc
index c97058e..444e87d 100644
--- a/y2022/constants.cc
+++ b/y2022/constants.cc
@@ -131,23 +131,23 @@
// Interpolation table for comp and practice robots
r.shot_interpolation_table = InterpolationTable<Values::ShotParams>({
- {1.0, {0.05, 19.4}},
- {1.6, {0.05, 19.4}},
- {1.9, {0.1, 19.4}},
- {2.12, {0.13, 19.4}},
- {2.9, {0.24, 19.9}},
+ {1.0, {0.12, 19.4}},
+ {1.6, {0.12, 19.4}},
+ {1.9, {0.17, 19.4}},
+ {2.12, {0.21, 19.4}},
+ {2.9, {0.30, 19.9}},
- {3.2, {0.26, 20.7}},
+ {3.2, {0.33, 20.1}},
- {3.60, {0.33, 20.9}},
- {4.50, {0.38, 22.5}},
- {4.9, {0.4, 22.9}},
- {5.4, {0.4, 23.9}},
+ {3.60, {0.39, 20.65}},
+ {4.50, {0.44, 22.3}},
+ {4.9, {0.43, 22.75}}, // up to here
+ {5.4, {0.43, 23.85}},
- {6.0, {0.40, 25.4}},
- {7.0, {0.37, 28.1}},
+ {6.0, {0.42, 25.3}},
+ {7.0, {0.40, 27.7}},
- {10.0, {0.37, 28.1}},
+ {10.0, {0.40, 27.7}},
});
if (false) {
@@ -238,13 +238,22 @@
0.0634440443622909 + 0.213601224728352 + 0.0657973101027296 -
0.114726411377978 - 0.980314029089968 - 0.0266013159299456 +
0.0631240002215899 + 0.222882504808653 + 0.0370686419434252 -
- 0.0965027214840068 - 0.126737479717192;
+ 0.0965027214840068 - 0.126737479717192 - 0.0773753775457 +
+ 2.8132444751306;
turret->subsystem_params.zeroing_constants.measured_absolute_position =
- 1.3081068967929;
+ 1.16683731504739;
flipper_arm_left->potentiometer_offset = -6.4;
flipper_arm_right->potentiometer_offset = 5.56;
+ *turret_range = ::frc971::constants::Range{
+ .lower_hard = -7.0, // Back Hard
+ .upper_hard = 3.4, // Front Hard
+ .lower = -6.4, // Back Soft
+ .upper = 2.9 // Front Soft
+ };
+ turret_params->range = *turret_range;
+
catapult_params->zeroing_constants.measured_absolute_position =
1.71723370408082;
catapult->potentiometer_offset = -2.03383240293769;
@@ -256,6 +265,8 @@
break;
case kPracticeTeamNumber:
+ catapult_params->range.lower = -0.885;
+
r.shot_interpolation_table = InterpolationTable<Values::ShotParams>({
{1.0, {0.08, 20.0}},
{1.6, {0.08, 20.0}},
@@ -276,7 +287,8 @@
{10.0, {0.39, 28.25}},
});
- climber->potentiometer_offset = -0.1209073362519 + 0.0760598;
+ climber->potentiometer_offset =
+ -0.1209073362519 + 0.0760598 - 0.0221716219244 - 0.00321684;
intake_front->potentiometer_offset = 3.06604378582351 - 0.60745632979918;
intake_front->subsystem_params.zeroing_constants
.measured_absolute_position = 0.143667561169188;
@@ -291,14 +303,18 @@
0.0718028442723373 - 0.0793332946417493 + 0.233707527214682 +
0.0828349540635251 + 0.677740533247017 - 0.0828349540635251 -
0.0903654044329345 - 0.105426305171759 - 0.150609007388226 -
- 0.0338870266623506 - 0.0677740533247011;
+ 0.0338870266623506 - 0.0677740533247011 - 0.135548106649404 - 0.6852;
turret->subsystem_params.zeroing_constants.measured_absolute_position =
- 1.50798193457968;
- turret_range->upper = 2.9;
- turret_range->lower = -6.4;
+ 0.8306;
+ *turret_range = ::frc971::constants::Range{
+ .lower_hard = -7.0, // Back Hard
+ .upper_hard = 3.4, // Front Hard
+ .lower = -6.4, // Back Soft
+ .upper = 2.9 // Front Soft
+ };
turret_params->range = *turret_range;
- flipper_arm_left->potentiometer_offset = -4.39536583413615;
- flipper_arm_right->potentiometer_offset = 4.36264091401229;
+ flipper_arm_left->potentiometer_offset = -4.39536583413615 - 0.108401297910291;
+ flipper_arm_right->potentiometer_offset = 4.36264091401229 + 0.175896445665755;
catapult_params->zeroing_constants.measured_absolute_position =
1.62909518684227;
diff --git a/y2022/message_bridge_client.sh b/y2022/message_bridge_client.sh
index c81076a..733905e 100755
--- a/y2022/message_bridge_client.sh
+++ b/y2022/message_bridge_client.sh
@@ -5,7 +5,37 @@
ping -c 1 pi1 -W 1 && break;
sleep 1
done
+while true;
+do
+ ping -c 1 pi2 -W 1 && break;
+ sleep 1
+done
+while true;
+do
+ ping -c 1 pi3 -W 1 && break;
+ sleep 1
+done
+while true;
+do
+ ping -c 1 pi4 -W 1 && break;
+ sleep 1
+done
+while true;
+do
+ ping -c 1 pi5 -W 1 && break;
+ sleep 1
+done
+while true;
+do
+ ping -c 1 pi6 -W 1 && break;
+ sleep 1
+done
+while true;
+do
+ ping -c 1 roborio -W 1 && break;
+ sleep 1
+done
echo Pinged
-exec /home/admin/bin/message_bridge_client "$@"
+exec message_bridge_client "$@"
diff --git a/y2022/vision/camera_definition.py b/y2022/vision/camera_definition.py
index d3e44b7..3b34ca2 100644
--- a/y2022/vision/camera_definition.py
+++ b/y2022/vision/camera_definition.py
@@ -109,24 +109,24 @@
camera_yaw = 0.0
T = np.array([-9.5 * 0.0254, -3.5 * 0.0254, 34.5 * 0.0254])
elif pi_number == "pi3":
- camera_yaw = 179.0 * np.pi / 180.0
+ camera_yaw = 182.0 * np.pi / 180.0
T = np.array([-9.5 * 0.0254, 3.5 * 0.0254, 34.5 * 0.0254])
elif pi_number == "pi4":
camera_yaw = -90.0 * np.pi / 180.0
T = np.array([-10.25 * 0.0254, -5.0 * 0.0254, 27.5 * 0.0254])
elif team_number == 9971:
if pi_number == "pi1":
- camera_yaw = 180.5 * np.pi / 180.0
+ camera_yaw = 179.0 * np.pi / 180.0
T = np.array([-9.5 * 0.0254, 3.25 * 0.0254, 35.5 * 0.0254])
elif pi_number == "pi2":
camera_yaw = 0.0
T = np.array([-9.0 * 0.0254, -3.25 * 0.0254, 35.5 * 0.0254])
elif pi_number == "pi3":
camera_yaw = 90.0 * np.pi / 180.0
- T = np.array([-10.5 * 0.0254, -5.0 * 0.0254, 29.5 * 0.0254])
+ T = np.array([-10.5 * 0.0254, 5.0 * 0.0254, 29.5 * 0.0254])
elif pi_number == "pi4":
camera_yaw = -90.0 * np.pi / 180.0
- T = np.array([-10.5 * 0.0254, 5.0 * 0.0254, 28.0 * 0.0254])
+ T = np.array([-10.5 * 0.0254, -5.0 * 0.0254, 28.5 * 0.0254])
else:
glog.fatal("Unknown team number for extrinsics")
diff --git a/y2022/y2022_imu.json b/y2022/y2022_imu.json
index 817f051..bd2b326 100644
--- a/y2022/y2022_imu.json
+++ b/y2022/y2022_imu.json
@@ -367,7 +367,7 @@
"applications": [
{
"name": "message_bridge_client",
- "executable_name": "message_bridge_client",
+ "executable_name": "message_bridge_client.sh",
"nodes": [
"imu"
]
diff --git a/y2022/y2022_logger.json b/y2022/y2022_logger.json
index a8a4bbd..4024bf6 100644
--- a/y2022/y2022_logger.json
+++ b/y2022/y2022_logger.json
@@ -502,7 +502,7 @@
"applications": [
{
"name": "logger_message_bridge_client",
- "executable_name": "message_bridge_client",
+ "executable_name": "message_bridge_client.sh",
"args": ["--rmem=8388608", "--rt_priority=16"],
"nodes": [
"logger"
diff --git a/y2022/y2022_pi_template.json b/y2022/y2022_pi_template.json
index a6b3f4a..99b04a1 100644
--- a/y2022/y2022_pi_template.json
+++ b/y2022/y2022_pi_template.json
@@ -186,7 +186,7 @@
"name": "/pi{{ NUM }}/camera",
"type": "y2022.vision.TargetEstimate",
"source_node": "pi{{ NUM }}",
- "frequency": 40,
+ "frequency": 80,
"num_senders": 2,
"max_size": 40000,
"logger": "LOCAL_AND_REMOTE_LOGGER",
@@ -358,7 +358,7 @@
"applications": [
{
"name": "message_bridge_client",
- "executable_name": "message_bridge_client",
+ "executable_name": "message_bridge_client.sh",
"args": ["--rt_priority=16"],
"nodes": [
"pi{{ NUM }}"