Merge "Stop intaking when transfer beam break triggered"
diff --git a/.bazelignore b/.bazelignore
index 0b2e110..9166728 100644
--- a/.bazelignore
+++ b/.bazelignore
@@ -1,11 +1,12 @@
external
node_modules
+scouting/webserver/requests/messages/node_modules
scouting/www/node_modules
-scouting/www/counter_button/node_modules
scouting/www/driver_ranking/node_modules
scouting/www/entry/node_modules
scouting/www/match_list/node_modules
scouting/www/notes/node_modules
+scouting/www/pipes/node_modules
scouting/www/rpc/node_modules
scouting/www/shift_schedule/node_modules
scouting/www/view/node_modules
diff --git a/.bazelrc b/.bazelrc
index a69ccad..3a3c729 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -22,7 +22,6 @@
# Shortcuts for selecting the target platform.
build:k8 --platforms=//tools/platforms:linux_x86
-build:k8_legacy_python --platforms=//tools/platforms:linux_x86_legacy_python --host_platform=//tools/platforms:linux_x86_legacy_python
build:roborio --platforms=//tools/platforms:linux_roborio
build:roborio --platform_suffix=-roborio
build:arm64 --platforms=//tools/platforms:linux_arm64
diff --git a/WORKSPACE b/WORKSPACE
index 1aabe54..f68d1b0 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -912,12 +912,13 @@
data = [
"@//:package.json",
"@//:pnpm-workspace.yaml",
+ "@//scouting/webserver/requests/messages:package.json",
"@//scouting/www:package.json",
- "@//scouting/www/counter_button:package.json",
"@//scouting/www/driver_ranking:package.json",
"@//scouting/www/entry:package.json",
"@//scouting/www/match_list:package.json",
"@//scouting/www/notes:package.json",
+ "@//scouting/www/pipes:package.json",
"@//scouting/www/rpc:package.json",
"@//scouting/www/scan:package.json",
"@//scouting/www/shift_schedule:package.json",
diff --git a/frc971/analysis/foxglove.md b/frc971/analysis/foxglove.md
index 8276584..d241ec0 100644
--- a/frc971/analysis/foxglove.md
+++ b/frc971/analysis/foxglove.md
@@ -8,7 +8,7 @@
is convenient; it won't work when you do not have Internet access, and
has some limitations when it comes to accessing unsecured websockets.
2. Download the foxglove desktop application.
-3. Run our local copy by running `bazel run //frc971/analysis:local_foxglove`
+3. Run our local copy by running `bazel run //aos/analysis:local_foxglove`
This will work offline, and serves foxglove at http://localhost:8000 by
default.
@@ -20,6 +20,9 @@
This will create an MCAP file at the specified path, which you can then open
in any of the various foxglove options.
+Troubleshooting:
+* If you get the error `Check failed: output_`: Check whether `/tmp/log.mcap` already exists under another owner. If so, use a different filename, e.g. `/tmp/<your_name>_log.mcap`
+
# Live Visualization
On the pis, we run a `foxglove_websocket` application by default. This exposes
diff --git a/frc971/control_loops/drivetrain/drivetrain_config.fbs b/frc971/control_loops/drivetrain/drivetrain_config.fbs
index 645eeac..0947063 100644
--- a/frc971/control_loops/drivetrain/drivetrain_config.fbs
+++ b/frc971/control_loops/drivetrain/drivetrain_config.fbs
@@ -98,6 +98,15 @@
max_controllable_offset:double = 0.1 (id: 2);
}
+table SplineFollowerConfig {
+ // Q should be a 5x5 positive-definite matrix; it is used as the state cost
+ // of the LQR controller for the spline-following mode.
+ q:frc971.fbs.Matrix (id: 0);
+ // R should be a 2x2 positive-definite matrix; it is used as the input cost
+ // of the LQR controller for the spline-following mode.
+ r:frc971.fbs.Matrix (id: 1);
+}
+
// These constants are all specified by the drivetrain python code, and
// so are separated out for easy codegen.
table DrivetrainLoopConfig {
@@ -135,6 +144,7 @@
is_simulated:bool = false (id: 14);
down_estimator_config:DownEstimatorConfig (id: 15);
line_follow_config:LineFollowConfig (id: 16);
+ spline_follower_config:SplineFollowerConfig (id: 20);
top_button_use:PistolTopButtonUse = kShift (id: 17);
second_button_use:PistolSecondButtonUse = kShiftLow (id: 18);
bottom_button_use:PistolBottomButtonUse = kSlowDown (id: 19);
diff --git a/frc971/control_loops/drivetrain/drivetrain_config.h b/frc971/control_loops/drivetrain/drivetrain_config.h
index 8e0a58d..3f56082 100644
--- a/frc971/control_loops/drivetrain/drivetrain_config.h
+++ b/frc971/control_loops/drivetrain/drivetrain_config.h
@@ -50,6 +50,33 @@
}
};
+struct SplineFollowerConfig {
+ // The line-following uses an LQR controller with states of
+ // [longitudinal_position, lateral_positoin, theta, left_velocity,
+ // right_velocity] and inputs of [left_voltage, right_voltage]. These Q and R
+ // matrices are the costs for state and input respectively.
+ Eigen::Matrix<double, 5, 5> Q = Eigen::Matrix<double, 5, 5>(
+ (::Eigen::DiagonalMatrix<double, 5>().diagonal() << ::std::pow(60.0, 2.0),
+ ::std::pow(60.0, 2.0), ::std::pow(40.0, 2.0), ::std::pow(30.0, 2.0),
+ ::std::pow(30.0, 2.0))
+ .finished()
+ .asDiagonal());
+ Eigen::Matrix2d R = Eigen::Matrix2d(
+ (::Eigen::DiagonalMatrix<double, 2>().diagonal() << 5.0, 5.0)
+ .finished()
+ .asDiagonal());
+
+ static SplineFollowerConfig FromFlatbuffer(
+ const fbs::SplineFollowerConfig *fbs) {
+ if (fbs == nullptr) {
+ return {};
+ }
+ return SplineFollowerConfig{
+ .Q = ToEigenOrDie<5, 5>(*CHECK_NOTNULL(fbs->q())),
+ .R = ToEigenOrDie<2, 2>(*CHECK_NOTNULL(fbs->r()))};
+ }
+};
+
template <typename Scalar = double>
struct DrivetrainConfig {
// Shifting method we are using.
@@ -125,6 +152,8 @@
PistolSecondButtonUse second_button_use = PistolSecondButtonUse::kShiftLow;
PistolBottomButtonUse bottom_button_use = PistolBottomButtonUse::kSlowDown;
+ SplineFollowerConfig spline_follower_config{};
+
// Converts the robot state to a linear distance position, velocity.
static Eigen::Matrix<Scalar, 2, 1> LeftRightToLinear(
const Eigen::Matrix<Scalar, 7, 1> &left_right) {
@@ -229,7 +258,9 @@
.line_follow_config =
LineFollowConfig::FromFlatbuffer(fbs.line_follow_config()),
ASSIGN(top_button_use), ASSIGN(second_button_use),
- ASSIGN(bottom_button_use)
+ ASSIGN(bottom_button_use),
+ .spline_follower_config = SplineFollowerConfig::FromFlatbuffer(
+ fbs.spline_follower_config()),
#undef ASSIGN
};
}
diff --git a/frc971/control_loops/drivetrain/trajectory.cc b/frc971/control_loops/drivetrain/trajectory.cc
index 163311a..cf9929f 100644
--- a/frc971/control_loops/drivetrain/trajectory.cc
+++ b/frc971/control_loops/drivetrain/trajectory.cc
@@ -770,17 +770,8 @@
// Set up reasonable gain matrices. Current choices of gains are arbitrary
// and just setup to work well enough for the simulation tests.
- // TODO(james): Tune this on a real robot.
- // TODO(james): Pull these out into a config.
- Eigen::Matrix<double, 5, 5> Q;
- Q.setIdentity();
- Q.diagonal() << 30.0, 30.0, 20.0, 15.0, 15.0;
- Q *= 2.0;
- Q = (Q * Q).eval();
-
- Eigen::Matrix<double, 2, 2> R;
- R.setIdentity();
- R *= 5.0;
+ Eigen::Matrix<double, 5, 5> Q = config_->spline_follower_config.Q;
+ Eigen::Matrix<double, 2, 2> R = config_->spline_follower_config.R;
Eigen::Matrix<double, 5, 5> P = Q;
@@ -822,6 +813,7 @@
const Eigen::Matrix<double, 2, 5> K = RBPBinv * APB.transpose();
plan_gains_[i].second = K.cast<float>();
P = AP * A_discrete - APB * K + Q;
+ CHECK_LT(P.norm(), 1e30) << "LQR calculations became unstable.";
}
}
diff --git a/frc971/orin/hardware_monitor.cc b/frc971/orin/hardware_monitor.cc
index f09d0e6..e1c785b 100644
--- a/frc971/orin/hardware_monitor.cc
+++ b/frc971/orin/hardware_monitor.cc
@@ -10,6 +10,7 @@
#include "frc971/orin/hardware_stats_generated.h"
DEFINE_string(config, "aos_config.json", "File path of aos configuration");
+DEFINE_bool(log_voltages, false, "If true, log voltages too.");
namespace frc971::orin {
namespace {
@@ -68,14 +69,19 @@
// Iterate through all thermal zones
std::vector<flatbuffers::Offset<ThermalZone>> thermal_zones;
for (int zone_id = 0; zone_id < 9; zone_id++) {
+ std::optional<std::string> zone_name = ReadFileFirstLine(absl::StrFormat(
+ "/sys/devices/virtual/thermal/thermal_zone%d/type", zone_id));
+ flatbuffers::Offset<flatbuffers::String> name_offset;
+ if (zone_name) {
+ name_offset = builder.fbb()->CreateString(*zone_name);
+ }
+
ThermalZone::Builder thermal_zone_builder =
builder.MakeBuilder<ThermalZone>();
thermal_zone_builder.add_id(zone_id);
- std::optional<std::string> zone_name = ReadFileFirstLine(absl::StrFormat(
- "/sys/devices/virtual/thermal/thermal_zone%d/type", zone_id));
- if (zone_name) {
- thermal_zone_builder.add_name(builder.fbb()->CreateString(*zone_name));
+ if (!name_offset.IsNull()) {
+ thermal_zone_builder.add_name(name_offset);
}
std::optional<std::string> temperature_str =
@@ -93,54 +99,68 @@
std::optional<std::string> fan_speed_str = ReadFileFirstLine(
absl::StrFormat("/sys/class/hwmon/%s/rpm", fan_hwmon_));
- // Iterate through INA3221 electrical reading channels
- std::vector<flatbuffers::Offset<ElectricalReading>> electrical_readings;
- for (int channel = 1; channel <= 3; channel++) {
- ElectricalReading::Builder electrical_reading_builder =
- builder.MakeBuilder<ElectricalReading>();
- electrical_reading_builder.add_channel(channel);
+ flatbuffers::Offset<
+ flatbuffers::Vector<flatbuffers::Offset<ElectricalReading>>>
+ electrical_readings_offset;
+ if (FLAGS_log_voltages) {
+ std::vector<flatbuffers::Offset<ElectricalReading>> electrical_readings;
+ // Iterate through INA3221 electrical reading channels
+ for (int channel = 1; channel <= 3; channel++) {
+ std::optional<std::string> label = ReadFileFirstLine(absl::StrFormat(
+ "/sys/class/hwmon/%s/in%d_label", electrical_hwmon_, channel));
- std::optional<std::string> label = ReadFileFirstLine(absl::StrFormat(
- "/sys/class/hwmon/%s/in%d_label", electrical_hwmon_, channel));
- if (label) {
- electrical_reading_builder.add_label(
- builder.fbb()->CreateString(*label));
+ flatbuffers::Offset<flatbuffers::String> label_offset;
+ if (label) {
+ label_offset = builder.fbb()->CreateString(*label);
+ }
+
+ ElectricalReading::Builder electrical_reading_builder =
+ builder.MakeBuilder<ElectricalReading>();
+ electrical_reading_builder.add_channel(channel);
+
+ if (!label_offset.IsNull()) {
+ electrical_reading_builder.add_label(label_offset);
+ }
+
+ std::optional<std::string> voltage_str =
+ ReadFileFirstLine(absl::StrFormat("/sys/class/hwmon/%s/in%d_input",
+ electrical_hwmon_, channel));
+ uint64_t voltage = 0;
+ if (voltage_str && absl::SimpleAtoi(*voltage_str, &voltage)) {
+ electrical_reading_builder.add_voltage(voltage);
+ }
+
+ std::optional<std::string> current_str = ReadFileFirstLine(
+ absl::StrFormat("/sys/class/hwmon/%s/curr%d_input",
+ electrical_hwmon_, channel));
+ uint64_t current = 0;
+ if (current_str && absl::SimpleAtoi(*current_str, ¤t)) {
+ electrical_reading_builder.add_current(current);
+ }
+
+ uint64_t power = voltage * current / 1000;
+ if (power != 0) {
+ electrical_reading_builder.add_power(power);
+ }
+
+ electrical_readings.emplace_back(electrical_reading_builder.Finish());
}
-
- std::optional<std::string> voltage_str =
- ReadFileFirstLine(absl::StrFormat("/sys/class/hwmon/%s/in%d_input",
- electrical_hwmon_, channel));
- uint64_t voltage = 0;
- if (voltage_str && absl::SimpleAtoi(*voltage_str, &voltage)) {
- electrical_reading_builder.add_voltage(voltage);
- }
-
- std::optional<std::string> current_str =
- ReadFileFirstLine(absl::StrFormat("/sys/class/hwmon/%s/curr%d_input",
- electrical_hwmon_, channel));
- uint64_t current = 0;
- if (current_str && absl::SimpleAtoi(*current_str, ¤t)) {
- electrical_reading_builder.add_current(current);
- }
-
- uint64_t power = voltage * current / 1000;
- if (power != 0) {
- electrical_reading_builder.add_power(power);
- }
-
- electrical_readings.emplace_back(electrical_reading_builder.Finish());
+ electrical_readings_offset =
+ builder.fbb()->CreateVector(electrical_readings);
}
+ auto thermal_zone_offset = builder.fbb()->CreateVector(thermal_zones);
HardwareStats::Builder hardware_stats_builder =
builder.MakeBuilder<HardwareStats>();
- hardware_stats_builder.add_thermal_zones(
- builder.fbb()->CreateVector(thermal_zones));
+ hardware_stats_builder.add_thermal_zones(thermal_zone_offset);
uint64_t fan_speed = 0;
if (fan_speed_str && absl::SimpleAtoi(*fan_speed_str, &fan_speed)) {
hardware_stats_builder.add_fan_speed(fan_speed);
}
- hardware_stats_builder.add_electrical_readings(
- builder.fbb()->CreateVector(electrical_readings));
+ if (!electrical_readings_offset.IsNull()) {
+ hardware_stats_builder.add_electrical_readings(
+ electrical_readings_offset);
+ }
builder.CheckOk(builder.Send(hardware_stats_builder.Finish()));
}
diff --git a/frc971/orin/set_orin_clock.sh b/frc971/orin/set_orin_clock.sh
index 32edb86..bc9dd8f 100755
--- a/frc971/orin/set_orin_clock.sh
+++ b/frc971/orin/set_orin_clock.sh
@@ -6,13 +6,13 @@
ROBOT_PREFIX="9" #71 (Should be one of 79, 89, 99, or 9)
-ORIN_LIST="1"
+ORIN_LIST="1 2"
echo "Setting hwclock on Orins"
for orin in $ORIN_LIST; do
echo "========================================================"
- echo "Setting clock for ${ROBOT_PREFIX}71.1${orin}"
+ echo "Setting clock for ${ROBOT_PREFIX}71.10${orin}"
echo "========================================================"
current_time=`sudo hwclock`
IFS="."
diff --git a/frc971/vision/intrinsics_calibration.cc b/frc971/vision/intrinsics_calibration.cc
index 16a53a7..d3ddba7 100644
--- a/frc971/vision/intrinsics_calibration.cc
+++ b/frc971/vision/intrinsics_calibration.cc
@@ -43,7 +43,19 @@
<< "Need a base intrinsics json to use to auto-capture images when the "
"camera moves.";
std::unique_ptr<aos::ExitHandle> exit_handle = event_loop.MakeExitHandle();
- IntrinsicsCalibration extractor(&event_loop, hostname, FLAGS_channel,
+
+ std::string camera_name = absl::StrCat(
+ "/", aos::network::ParsePiOrOrin(hostname).value(),
+ std::to_string(aos::network::ParsePiOrOrinNumber(hostname).value()),
+ FLAGS_channel);
+ // THIS IS A HACK FOR 2024, since we call Orin2 "Imu"
+ if (aos::network::ParsePiOrOrin(hostname).value() == "orin" &&
+ aos::network::ParsePiOrOrinNumber(hostname).value() == 2) {
+ LOG(INFO) << "\nHACK for 2024: Renaming orin2 to imu\n";
+ camera_name = absl::StrCat("/imu", FLAGS_channel);
+ }
+
+ IntrinsicsCalibration extractor(&event_loop, hostname, camera_name,
FLAGS_camera_id, FLAGS_base_intrinsics,
FLAGS_display_undistorted,
FLAGS_calibration_folder, exit_handle.get());
diff --git a/frc971/vision/intrinsics_calibration_lib.cc b/frc971/vision/intrinsics_calibration_lib.cc
index 59a45ac..5584ed7 100644
--- a/frc971/vision/intrinsics_calibration_lib.cc
+++ b/frc971/vision/intrinsics_calibration_lib.cc
@@ -36,17 +36,27 @@
rvecs_eigen, tvecs_eigen);
}),
image_callback_(
- event_loop,
- absl::StrCat("/", aos::network::ParsePiOrOrin(hostname_).value(),
- std::to_string(cpu_number_.value()), camera_channel_),
+ event_loop, camera_channel_,
[this](cv::Mat rgb_image,
const aos::monotonic_clock::time_point eof) {
+ if (exit_collection_) {
+ return;
+ }
charuco_extractor_.HandleImage(rgb_image, eof);
},
kMaxImageAge),
display_undistorted_(display_undistorted),
calibration_folder_(calibration_folder),
- exit_handle_(exit_handle) {
+ exit_handle_(exit_handle),
+ exit_collection_(false) {
+ if (!FLAGS_visualize) {
+ // The only way to exit into the calibration routines is by hitting "q"
+ // while visualization is running. The event_loop doesn't pause enough
+ // to handle ctrl-c exit requests
+ LOG(INFO) << "Setting visualize to true, since currently the intrinsics "
+ "only works this way";
+ FLAGS_visualize = true;
+ }
LOG(INFO) << "Hostname is: " << hostname_ << " and camera channel is "
<< camera_channel_;
@@ -81,7 +91,11 @@
}
int keystroke = cv::waitKey(1);
-
+ if ((keystroke & 0xFF) == static_cast<int>('q')) {
+ LOG(INFO) << "Going to exit";
+ exit_collection_ = true;
+ exit_handle_->Exit();
+ }
// If we haven't got a valid pose estimate, don't use these points
if (!valid) {
LOG(INFO) << "Skipping because pose is not valid";
@@ -161,9 +175,6 @@
<< kDeltaTThreshold;
}
}
-
- } else if ((keystroke & 0xFF) == static_cast<int>('q')) {
- exit_handle_->Exit();
}
}
@@ -175,8 +186,14 @@
std::string_view camera_id, uint16_t team_number,
double reprojection_error) {
flatbuffers::FlatBufferBuilder fbb;
+ // THIS IS A HACK FOR 2024, since we call Orin2 "Imu"
+ std::string cpu_name = absl::StrFormat("%s%d", cpu_type, cpu_number);
+ if (cpu_type == "orin" && cpu_number == 2) {
+ LOG(INFO) << "Renaming orin2 to imu";
+ cpu_name = "imu";
+ }
flatbuffers::Offset<flatbuffers::String> name_offset =
- fbb.CreateString(absl::StrFormat("%s%d", cpu_type, cpu_number));
+ fbb.CreateString(cpu_name.c_str());
flatbuffers::Offset<flatbuffers::String> camera_id_offset =
fbb.CreateString(camera_id);
flatbuffers::Offset<flatbuffers::Vector<float>> intrinsics_offset =
diff --git a/frc971/vision/intrinsics_calibration_lib.h b/frc971/vision/intrinsics_calibration_lib.h
index 605741f..faa82e9 100644
--- a/frc971/vision/intrinsics_calibration_lib.h
+++ b/frc971/vision/intrinsics_calibration_lib.h
@@ -77,6 +77,8 @@
const bool display_undistorted_;
const std::string calibration_folder_;
aos::ExitHandle *exit_handle_;
+
+ bool exit_collection_;
};
} // namespace frc971::vision
diff --git a/package.json b/package.json
index 6853a14..f37a2b6 100644
--- a/package.json
+++ b/package.json
@@ -34,5 +34,14 @@
"typescript": "5.1.6",
"terser": "5.16.4",
"zone.js": "^0.13.0"
+ },
+ "pnpm": {
+ "packageExtensions": {
+ "angularx-qrcode": {
+ "peerDependencies": {
+ "@angular/platform-browser": "*"
+ }
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index bf6a429..f718ebc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4,6 +4,8 @@
autoInstallPeers: true
excludeLinksFromLockfile: false
+packageExtensionsChecksum: 4cac6673474a9277f5f94a4599fee092
+
importers:
.:
@@ -64,7 +66,7 @@
version: 2.0.3
angularx-qrcode:
specifier: ^16.0.2
- version: 16.0.2(@angular/core@16.2.12)
+ version: 16.0.2(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)
cypress:
specifier: 13.3.1
version: 13.3.1
@@ -99,27 +101,76 @@
specifier: ^0.13.0
version: 0.13.3
- scouting/www: {}
+ scouting/webserver/requests/messages: {}
- scouting/www/counter_button: {}
+ scouting/www:
+ dependencies:
+ '@angular/animations':
+ specifier: v16-lts
+ version: 16.2.12(@angular/core@16.2.12)
+ '@angular/service-worker':
+ specifier: v16-lts
+ version: 16.2.12(@angular/common@16.2.12)(@angular/core@16.2.12)
+ '@org_frc971/scouting/www/driver_ranking':
+ specifier: workspace:*
+ version: link:driver_ranking
+ '@org_frc971/scouting/www/entry':
+ specifier: workspace:*
+ version: link:entry
+ '@org_frc971/scouting/www/match_list':
+ specifier: workspace:*
+ version: link:match_list
+ '@org_frc971/scouting/www/notes':
+ specifier: workspace:*
+ version: link:notes
+ '@org_frc971/scouting/www/pipes':
+ specifier: workspace:*
+ version: link:pipes
+ '@org_frc971/scouting/www/pit_scouting':
+ specifier: workspace:*
+ version: link:pit_scouting
+ '@org_frc971/scouting/www/scan':
+ specifier: workspace:*
+ version: link:scan
+ '@org_frc971/scouting/www/shift_schedule':
+ specifier: workspace:*
+ version: link:shift_schedule
+ '@org_frc971/scouting/www/view':
+ specifier: workspace:*
+ version: link:view
scouting/www/driver_ranking:
dependencies:
'@angular/forms':
specifier: v16-lts
version: 16.2.12(@angular/common@16.2.12)(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)(rxjs@7.5.7)
+ '@org_frc971/scouting/webserver/requests/messages':
+ specifier: workspace:*
+ version: link:../../webserver/requests/messages
scouting/www/entry:
dependencies:
'@angular/forms':
specifier: v16-lts
version: 16.2.12(@angular/common@16.2.12)(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)(rxjs@7.5.7)
- '@org_frc971/scouting/www/counter_button':
+ '@angular/platform-browser':
+ specifier: v16-lts
+ version: 16.2.12(@angular/animations@16.2.12)(@angular/common@16.2.12)(@angular/core@16.2.12)
+ '@org_frc971/scouting/webserver/requests/messages':
specifier: workspace:*
- version: link:../counter_button
+ version: link:../../webserver/requests/messages
+ '@org_frc971/scouting/www/pipes':
+ specifier: workspace:*
+ version: link:../pipes
+ '@org_frc971/scouting/www/rpc':
+ specifier: workspace:*
+ version: link:../rpc
'@types/pako':
specifier: 2.0.3
version: 2.0.3
+ angularx-qrcode:
+ specifier: ^16.0.2
+ version: 16.0.2(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)
pako:
specifier: 2.1.0
version: 2.1.0
@@ -129,6 +180,9 @@
'@angular/forms':
specifier: v16-lts
version: 16.2.12(@angular/common@16.2.12)(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)(rxjs@7.5.7)
+ '@org_frc971/scouting/webserver/requests/messages':
+ specifier: workspace:*
+ version: link:../../webserver/requests/messages
'@org_frc971/scouting/www/rpc':
specifier: workspace:*
version: link:../rpc
@@ -138,20 +192,38 @@
'@angular/forms':
specifier: v16-lts
version: 16.2.12(@angular/common@16.2.12)(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)(rxjs@7.5.7)
+ '@org_frc971/scouting/webserver/requests/messages':
+ specifier: workspace:*
+ version: link:../../webserver/requests/messages
+
+ scouting/www/pipes: {}
scouting/www/pit_scouting:
dependencies:
'@angular/forms':
specifier: v16-lts
version: 16.2.12(@angular/common@16.2.12)(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)(rxjs@7.5.7)
+ '@org_frc971/scouting/webserver/requests/messages':
+ specifier: workspace:*
+ version: link:../../webserver/requests/messages
- scouting/www/rpc: {}
+ scouting/www/rpc:
+ dependencies:
+ '@org_frc971/scouting/webserver/requests/messages':
+ specifier: workspace:*
+ version: link:../../webserver/requests/messages
+ dexie:
+ specifier: ^3.2.5
+ version: 3.2.5(karma@6.4.3)
scouting/www/scan:
dependencies:
'@angular/forms':
specifier: v16-lts
version: 16.2.12(@angular/common@16.2.12)(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)(rxjs@7.5.7)
+ '@org_frc971/scouting/webserver/requests/messages':
+ specifier: workspace:*
+ version: link:../../webserver/requests/messages
'@types/pako':
specifier: 2.0.3
version: 2.0.3
@@ -164,12 +236,21 @@
'@angular/forms':
specifier: v16-lts
version: 16.2.12(@angular/common@16.2.12)(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)(rxjs@7.5.7)
+ '@org_frc971/scouting/webserver/requests/messages':
+ specifier: workspace:*
+ version: link:../../webserver/requests/messages
scouting/www/view:
dependencies:
'@angular/forms':
specifier: v16-lts
version: 16.2.12(@angular/common@16.2.12)(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)(rxjs@7.5.7)
+ '@org_frc971/scouting/webserver/requests/messages':
+ specifier: workspace:*
+ version: link:../../webserver/requests/messages
+ '@org_frc971/scouting/www/rpc':
+ specifier: workspace:*
+ version: link:../rpc
packages:
@@ -358,7 +439,6 @@
'@angular/common': 16.2.12(@angular/core@16.2.12)(rxjs@7.5.7)
'@angular/core': 16.2.12(rxjs@7.5.7)(zone.js@0.13.3)
tslib: 2.6.0
- dev: true
/@babel/cli@7.23.9(@babel/core@7.23.9):
resolution: {integrity: sha512-vB1UXmGDNEhcf1jNAHKT9IlYk1R+hehVTLFlCLHBi8gfuHQGP6uRjgXVYU0EVlI/qwAWpstqkBdf2aez3/z/5Q==}
@@ -612,7 +692,6 @@
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
engines: {node: '>=0.1.90'}
requiresBuild: true
- dev: true
/@cypress/request@3.0.1:
resolution: {integrity: sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==}
@@ -972,7 +1051,6 @@
/@socket.io/component-emitter@3.1.0:
resolution: {integrity: sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==}
- dev: true
/@tootallnate/once@2.0.0:
resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
@@ -1023,13 +1101,11 @@
/@types/cookie@0.4.1:
resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==}
- dev: true
/@types/cors@2.8.17:
resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==}
dependencies:
'@types/node': 20.11.19
- dev: true
/@types/estree@1.0.5:
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
@@ -1053,7 +1129,6 @@
resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==}
dependencies:
undici-types: 5.26.5
- dev: true
/@types/pako@2.0.3:
resolution: {integrity: sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q==}
@@ -1092,7 +1167,6 @@
dependencies:
mime-types: 2.1.35
negotiator: 0.6.3
- dev: true
/acorn@8.9.0:
resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==}
@@ -1144,15 +1218,16 @@
uri-js: 4.4.1
dev: true
- /angularx-qrcode@16.0.2(@angular/core@16.2.12):
+ /angularx-qrcode@16.0.2(@angular/core@16.2.12)(@angular/platform-browser@16.2.12):
resolution: {integrity: sha512-FztOM7vjNu88sGxUU5jG2I+A9TxZBXXYBWINjpwIBbTL+COMgrtzXnScG7TyQeNknv5w3WFJWn59PcngRRYVXA==}
peerDependencies:
'@angular/core': ^16.0.0
+ '@angular/platform-browser': '*'
dependencies:
'@angular/core': 16.2.12(rxjs@7.5.7)(zone.js@0.13.3)
+ '@angular/platform-browser': 16.2.12(@angular/animations@16.2.12)(@angular/common@16.2.12)(@angular/core@16.2.12)
qrcode: 1.5.3
tslib: 2.6.0
- dev: true
/ansi-colors@4.1.3:
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
@@ -1169,7 +1244,6 @@
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
- dev: true
/ansi-regex@6.0.1:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
@@ -1188,7 +1262,6 @@
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
- dev: true
/ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
@@ -1201,7 +1274,6 @@
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
- dev: true
/aproba@2.0.0:
resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
@@ -1258,7 +1330,6 @@
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- dev: true
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -1267,7 +1338,6 @@
/base64id@2.0.0:
resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==}
engines: {node: ^4.5.0 || >= 5.9}
- dev: true
/bcrypt-pbkdf@1.0.2:
resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
@@ -1278,7 +1348,6 @@
/binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
- dev: true
/bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
@@ -1314,14 +1383,12 @@
unpipe: 1.0.0
transitivePeerDependencies:
- supports-color
- dev: true
/brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
- dev: true
/brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
@@ -1334,7 +1401,6 @@
engines: {node: '>=8'}
dependencies:
fill-range: 7.0.1
- dev: true
/browserslist@4.23.0:
resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
@@ -1376,7 +1442,6 @@
/bytes@3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
- dev: true
/cacache@16.1.3:
resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==}
@@ -1432,12 +1497,10 @@
dependencies:
function-bind: 1.1.2
get-intrinsic: 1.2.1
- dev: true
/camelcase@5.3.1:
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
engines: {node: '>=6'}
- dev: true
/caniuse-lite@1.0.30001588:
resolution: {integrity: sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ==}
@@ -1486,7 +1549,6 @@
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.2
- dev: true
/chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
@@ -1543,7 +1605,6 @@
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 6.2.0
- dev: true
/cliui@7.0.4:
resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
@@ -1551,7 +1612,6 @@
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
- dev: true
/cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
@@ -1578,7 +1638,6 @@
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
- dev: true
/color-name@1.1.3:
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
@@ -1586,7 +1645,6 @@
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
- dev: true
/color-support@1.1.3:
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
@@ -1625,7 +1683,6 @@
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
- dev: true
/connect@3.7.0:
resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==}
@@ -1637,7 +1694,6 @@
utils-merge: 1.0.1
transitivePeerDependencies:
- supports-color
- dev: true
/console-control-strings@1.1.0:
resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
@@ -1646,7 +1702,6 @@
/content-type@1.0.5:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
- dev: true
/convert-source-map@1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
@@ -1659,7 +1714,6 @@
/cookie@0.4.2:
resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
engines: {node: '>= 0.6'}
- dev: true
/core-util-is@1.0.2:
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
@@ -1671,7 +1725,6 @@
dependencies:
object-assign: 4.1.1
vary: 1.1.2
- dev: true
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
@@ -1684,7 +1737,6 @@
/custom-event@1.0.1:
resolution: {integrity: sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==}
- dev: true
/cypress@13.3.1:
resolution: {integrity: sha512-g4mJLZxYN+UAF2LMy3Znd4LBnUmS59Vynd81VES59RdW48Yt+QtR2cush3melOoVNz0PPbADpWr8DcUx6mif8Q==}
@@ -1747,7 +1799,6 @@
/date-format@4.0.14:
resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==}
engines: {node: '>=4.0'}
- dev: true
/dayjs@1.11.9:
resolution: {integrity: sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==}
@@ -1762,7 +1813,6 @@
optional: true
dependencies:
ms: 2.0.0
- dev: true
/debug@3.2.7(supports-color@8.1.1):
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
@@ -1787,12 +1837,10 @@
dependencies:
ms: 2.1.2
supports-color: 8.1.1
- dev: true
/decamelize@1.2.0:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
- dev: true
/deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
@@ -1822,12 +1870,10 @@
/depd@2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
- dev: true
/destroy@1.2.0:
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
- dev: true
/dexie@3.2.5(karma@6.4.3):
resolution: {integrity: sha512-MA7vYQvXxWN2+G50D0GLS4FqdYUyRYQsN0FikZIVebOmRoNCSCL9+eUbIF80dqrfns3kmY+83+hE2GN9CnAGyA==}
@@ -1836,15 +1882,12 @@
karma-safari-launcher: 1.0.0(karma@6.4.3)
transitivePeerDependencies:
- karma
- dev: true
/di@0.0.1:
resolution: {integrity: sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==}
- dev: true
/dijkstrajs@1.0.3:
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
- dev: true
/dom-serialize@2.2.1:
resolution: {integrity: sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==}
@@ -1853,7 +1896,6 @@
ent: 2.2.0
extend: 3.0.2
void-elements: 2.0.1
- dev: true
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@@ -1868,7 +1910,6 @@
/ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
- dev: true
/electron-to-chromium@1.4.679:
resolution: {integrity: sha512-NhQMsz5k0d6m9z3qAxnsOR/ebal4NAGsrNVRwcDo4Kc/zQ7KdsTKZUxZoygHcVRb0QDW3waEDIcE3isZ79RP6g==}
@@ -1876,7 +1917,6 @@
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
- dev: true
/emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
@@ -1884,12 +1924,10 @@
/encode-utf8@1.0.3:
resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
- dev: true
/encodeurl@1.0.2:
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
engines: {node: '>= 0.8'}
- dev: true
/encoding@0.1.13:
resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
@@ -1908,7 +1946,6 @@
/engine.io-parser@5.2.2:
resolution: {integrity: sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==}
engines: {node: '>=10.0.0'}
- dev: true
/engine.io@6.5.4:
resolution: {integrity: sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==}
@@ -1928,7 +1965,6 @@
- bufferutil
- supports-color
- utf-8-validate
- dev: true
/enquirer@2.3.6:
resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
@@ -1939,7 +1975,6 @@
/ent@2.2.0:
resolution: {integrity: sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==}
- dev: true
/env-paths@2.2.1:
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
@@ -1953,11 +1988,9 @@
/escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
- dev: true
/escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
- dev: true
/escape-string-regexp@1.0.5:
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
@@ -1974,7 +2007,6 @@
/eventemitter3@4.0.7:
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
- dev: true
/execa@4.1.0:
resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
@@ -2004,7 +2036,6 @@
/extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
- dev: true
/external-editor@3.1.0:
resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
@@ -2056,7 +2087,6 @@
engines: {node: '>=8'}
dependencies:
to-regex-range: 5.0.1
- dev: true
/finalhandler@1.1.2:
resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==}
@@ -2071,7 +2101,6 @@
unpipe: 1.0.0
transitivePeerDependencies:
- supports-color
- dev: true
/find-up@4.1.0:
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
@@ -2079,11 +2108,9 @@
dependencies:
locate-path: 5.0.0
path-exists: 4.0.0
- dev: true
/flatted@3.3.1:
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
- dev: true
/follow-redirects@1.15.5:
resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==}
@@ -2093,7 +2120,6 @@
peerDependenciesMeta:
debug:
optional: true
- dev: true
/foreground-child@3.1.1:
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
@@ -2123,7 +2149,6 @@
graceful-fs: 4.2.11
jsonfile: 4.0.0
universalify: 0.1.2
- dev: true
/fs-extra@9.1.0:
resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
@@ -2155,23 +2180,19 @@
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
- dev: true
/fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
- dev: true
optional: true
/function-bind@1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
- dev: true
/function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
- dev: true
/gauge@4.0.4:
resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
@@ -2195,7 +2216,6 @@
/get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
- dev: true
/get-intrinsic@1.2.1:
resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==}
@@ -2204,7 +2224,6 @@
has: 1.0.3
has-proto: 1.0.1
has-symbols: 1.0.3
- dev: true
/get-stream@5.2.0:
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
@@ -2230,7 +2249,6 @@
engines: {node: '>= 6'}
dependencies:
is-glob: 4.0.3
- dev: true
/glob@10.3.10:
resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
@@ -2253,7 +2271,6 @@
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
- dev: true
/glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
@@ -2280,7 +2297,6 @@
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
- dev: true
/has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
@@ -2290,17 +2306,14 @@
/has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
- dev: true
/has-proto@1.0.1:
resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
engines: {node: '>= 0.4'}
- dev: true
/has-symbols@1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
- dev: true
/has-unicode@2.0.1:
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
@@ -2311,7 +2324,6 @@
engines: {node: '>= 0.4.0'}
dependencies:
function-bind: 1.1.1
- dev: true
/hasown@2.0.1:
resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==}
@@ -2348,7 +2360,6 @@
setprototypeof: 1.2.0
statuses: 2.0.1
toidentifier: 1.0.1
- dev: true
/http-proxy-agent@5.0.0:
resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
@@ -2370,7 +2381,6 @@
requires-port: 1.0.0
transitivePeerDependencies:
- debug
- dev: true
/http-signature@1.3.6:
resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==}
@@ -2407,7 +2417,6 @@
engines: {node: '>=0.10.0'}
dependencies:
safer-buffer: 2.1.2
- dev: true
/iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
@@ -2448,11 +2457,9 @@
dependencies:
once: 1.4.0
wrappy: 1.0.2
- dev: true
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
- dev: true
/ini@2.0.0:
resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
@@ -2494,7 +2501,6 @@
engines: {node: '>=8'}
dependencies:
binary-extensions: 2.2.0
- dev: true
/is-builtin-module@3.2.1:
resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
@@ -2531,19 +2537,16 @@
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
- dev: true
/is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
- dev: true
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
- dev: true
/is-installed-globally@0.4.0:
resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==}
@@ -2569,7 +2572,6 @@
/is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
- dev: true
/is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
@@ -2600,7 +2602,6 @@
/isbinaryfile@4.0.10:
resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==}
engines: {node: '>= 8.0.0'}
- dev: true
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -2664,7 +2665,6 @@
resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
optionalDependencies:
graceful-fs: 4.2.11
- dev: true
/jsonfile@6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
@@ -2695,7 +2695,6 @@
karma: '>=0.9'
dependencies:
karma: 6.4.3
- dev: true
/karma@6.4.3:
resolution: {integrity: sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==}
@@ -2731,7 +2730,6 @@
- debug
- supports-color
- utf-8-validate
- dev: true
/lazy-ass@1.6.0:
resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==}
@@ -2763,7 +2761,6 @@
engines: {node: '>=8'}
dependencies:
p-locate: 4.1.0
- dev: true
/lodash.once@4.1.1:
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
@@ -2771,7 +2768,6 @@
/lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
- dev: true
/log-symbols@4.1.0:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
@@ -2802,7 +2798,6 @@
streamroller: 3.1.5
transitivePeerDependencies:
- supports-color
- dev: true
/lru-cache@10.2.0:
resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
@@ -2893,7 +2888,6 @@
/media-typer@0.3.0:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
- dev: true
/merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
@@ -2902,20 +2896,17 @@
/mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
- dev: true
/mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
- dev: true
/mime@2.6.0:
resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==}
engines: {node: '>=4.0.0'}
hasBin: true
- dev: true
/mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
@@ -2926,7 +2917,6 @@
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
brace-expansion: 1.1.11
- dev: true
/minimatch@5.1.6:
resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
@@ -2944,7 +2934,6 @@
/minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
- dev: true
/minipass-collect@1.0.2:
resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
@@ -3033,7 +3022,6 @@
hasBin: true
dependencies:
minimist: 1.2.8
- dev: true
/mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
@@ -3043,11 +3031,9 @@
/ms@2.0.0:
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
- dev: true
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
- dev: true
/ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -3060,7 +3046,6 @@
/negotiator@0.6.3:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
- dev: true
/node-gyp@9.4.1:
resolution: {integrity: sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==}
@@ -3108,7 +3093,6 @@
/normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
- dev: true
/npm-bundled@3.0.0:
resolution: {integrity: sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==}
@@ -3191,31 +3175,26 @@
/object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
- dev: true
/object-inspect@1.12.3:
resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
- dev: true
/on-finished@2.3.0:
resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
engines: {node: '>= 0.8'}
dependencies:
ee-first: 1.1.1
- dev: true
/on-finished@2.4.1:
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
engines: {node: '>= 0.8'}
dependencies:
ee-first: 1.1.1
- dev: true
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
- dev: true
/onetime@5.1.2:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
@@ -3262,14 +3241,12 @@
engines: {node: '>=6'}
dependencies:
p-try: 2.2.0
- dev: true
/p-locate@4.1.0:
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
engines: {node: '>=8'}
dependencies:
p-limit: 2.3.0
- dev: true
/p-map@4.0.0:
resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
@@ -3281,7 +3258,6 @@
/p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
- dev: true
/pacote@15.2.0:
resolution: {integrity: sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==}
@@ -3321,17 +3297,14 @@
/parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
- dev: true
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
- dev: true
/path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
- dev: true
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
@@ -3365,7 +3338,6 @@
/picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
- dev: true
/pify@2.3.0:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
@@ -3380,7 +3352,6 @@
/pngjs@5.0.0:
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
engines: {node: '>=10.13.0'}
- dev: true
/prettier@2.6.1:
resolution: {integrity: sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A==}
@@ -3443,7 +3414,6 @@
/qjobs@1.2.0:
resolution: {integrity: sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==}
engines: {node: '>=0.9'}
- dev: true
/qrcode@1.5.3:
resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==}
@@ -3454,7 +3424,6 @@
encode-utf8: 1.0.3
pngjs: 5.0.0
yargs: 15.4.1
- dev: true
/qs@6.10.4:
resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==}
@@ -3468,7 +3437,6 @@
engines: {node: '>=0.6'}
dependencies:
side-channel: 1.0.4
- dev: true
/querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
@@ -3477,7 +3445,6 @@
/range-parser@1.2.1:
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
engines: {node: '>= 0.6'}
- dev: true
/raw-body@2.5.2:
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
@@ -3487,7 +3454,6 @@
http-errors: 2.0.0
iconv-lite: 0.4.24
unpipe: 1.0.0
- dev: true
/read-package-json-fast@3.0.2:
resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==}
@@ -3521,7 +3487,6 @@
engines: {node: '>=8.10.0'}
dependencies:
picomatch: 2.3.1
- dev: true
/reflect-metadata@0.1.14:
resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==}
@@ -3536,7 +3501,6 @@
/require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
- dev: true
/require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
@@ -3545,7 +3509,6 @@
/require-main-filename@2.0.0:
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
- dev: true
/requirejs@2.3.6:
resolution: {integrity: sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==}
@@ -3555,7 +3518,6 @@
/requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
- dev: true
/resolve@1.22.2:
resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==}
@@ -3581,14 +3543,12 @@
/rfdc@1.3.0:
resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==}
- dev: true
/rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
hasBin: true
dependencies:
glob: 7.2.3
- dev: true
/rollup@4.12.0:
resolution: {integrity: sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==}
@@ -3635,7 +3595,6 @@
/safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
- dev: true
/semver@5.7.1:
resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
@@ -3665,11 +3624,9 @@
/set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
- dev: true
/setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
- dev: true
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
@@ -3689,7 +3646,6 @@
call-bind: 1.0.2
get-intrinsic: 1.2.1
object-inspect: 1.12.3
- dev: true
/signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
@@ -3751,7 +3707,6 @@
- bufferutil
- supports-color
- utf-8-validate
- dev: true
/socket.io-parser@4.2.4:
resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==}
@@ -3761,7 +3716,6 @@
debug: 4.3.4(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
- dev: true
/socket.io@4.7.4:
resolution: {integrity: sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==}
@@ -3778,7 +3732,6 @@
- bufferutil
- supports-color
- utf-8-validate
- dev: true
/socks-proxy-agent@7.0.0:
resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==}
@@ -3809,7 +3762,6 @@
/source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
- dev: true
/source-map@0.7.4:
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
@@ -3871,12 +3823,10 @@
/statuses@1.5.0:
resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
engines: {node: '>= 0.6'}
- dev: true
/statuses@2.0.1:
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
engines: {node: '>= 0.8'}
- dev: true
/streamroller@3.1.5:
resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==}
@@ -3887,7 +3837,6 @@
fs-extra: 8.1.0
transitivePeerDependencies:
- supports-color
- dev: true
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
@@ -3896,7 +3845,6 @@
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
- dev: true
/string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
@@ -3918,7 +3866,6 @@
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
- dev: true
/strip-ansi@7.1.0:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
@@ -3951,7 +3898,6 @@
engines: {node: '>=10'}
dependencies:
has-flag: 4.0.0
- dev: true
/supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
@@ -4006,7 +3952,6 @@
engines: {node: '>=8.17.0'}
dependencies:
rimraf: 3.0.2
- dev: true
/to-fast-properties@2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
@@ -4018,12 +3963,10 @@
engines: {node: '>=8.0'}
dependencies:
is-number: 7.0.0
- dev: true
/toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
- dev: true
/tough-cookie@4.1.3:
resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==}
@@ -4070,7 +4013,6 @@
dependencies:
media-typer: 0.3.0
mime-types: 2.1.35
- dev: true
/typescript@5.1.6:
resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==}
@@ -4080,11 +4022,9 @@
/ua-parser-js@0.7.37:
resolution: {integrity: sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==}
- dev: true
/undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
- dev: true
/unique-filename@2.0.1:
resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==}
@@ -4117,7 +4057,6 @@
/universalify@0.1.2:
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
engines: {node: '>= 4.0.0'}
- dev: true
/universalify@0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
@@ -4132,7 +4071,6 @@
/unpipe@1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
- dev: true
/untildify@4.0.0:
resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
@@ -4170,7 +4108,6 @@
/utils-merge@1.0.1:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
- dev: true
/uuid@8.3.2:
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
@@ -4194,7 +4131,6 @@
/vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
- dev: true
/verror@1.10.0:
resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
@@ -4208,7 +4144,6 @@
/void-elements@2.0.1:
resolution: {integrity: sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==}
engines: {node: '>=0.10.0'}
- dev: true
/wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
@@ -4218,7 +4153,6 @@
/which-module@2.0.1:
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
- dev: true
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
@@ -4249,7 +4183,6 @@
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
- dev: true
/wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
@@ -4258,7 +4191,6 @@
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
- dev: true
/wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
@@ -4271,7 +4203,6 @@
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- dev: true
/ws@8.11.0:
resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==}
@@ -4284,16 +4215,13 @@
optional: true
utf-8-validate:
optional: true
- dev: true
/y18n@4.0.3:
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
- dev: true
/y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
- dev: true
/yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
@@ -4309,12 +4237,10 @@
dependencies:
camelcase: 5.3.1
decamelize: 1.2.0
- dev: true
/yargs-parser@20.2.9:
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
engines: {node: '>=10'}
- dev: true
/yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
@@ -4336,7 +4262,6 @@
which-module: 2.0.1
y18n: 4.0.3
yargs-parser: 18.1.3
- dev: true
/yargs@16.2.0:
resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
@@ -4349,7 +4274,6 @@
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 20.2.9
- dev: true
/yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 36eb141..cf4c338 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,3 +1,4 @@
packages:
+ - 'scouting/webserver/requests/messages'
- 'scouting/www'
- 'scouting/www/*'
diff --git a/scouting/scouting_qrcode_test.cy.js b/scouting/scouting_qrcode_test.cy.js
index 668cba8..559481e 100644
--- a/scouting/scouting_qrcode_test.cy.js
+++ b/scouting/scouting_qrcode_test.cy.js
@@ -86,7 +86,7 @@
cy.get('#review_data li')
.eq(0)
.should('have.text', ' Started match at position 1 ');
- cy.get('#review_data li').eq(1).should('have.text', 'Picked up Note');
+ cy.get('#review_data li').eq(1).should('have.text', ' Picked up Note ');
cy.get('#review_data li')
.last()
.should(
diff --git a/scouting/scouting_test.cy.js b/scouting/scouting_test.cy.js
index d15cdfc..2de6879 100644
--- a/scouting/scouting_test.cy.js
+++ b/scouting/scouting_test.cy.js
@@ -106,7 +106,7 @@
cy.get('#review_data li')
.eq(0)
.should('have.text', ' Started match at position 1 ');
- cy.get('#review_data li').eq(1).should('have.text', 'Picked up Note');
+ cy.get('#review_data li').eq(1).should('have.text', ' Picked up Note ');
cy.get('#review_data li')
.last()
.should(
diff --git a/scouting/webserver/requests/messages/BUILD b/scouting/webserver/requests/messages/BUILD
index d0534a51..6dee54d 100644
--- a/scouting/webserver/requests/messages/BUILD
+++ b/scouting/webserver/requests/messages/BUILD
@@ -1,3 +1,4 @@
+load("@aspect_rules_js//npm:defs.bzl", "npm_package")
load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_go_library")
load("@com_github_google_flatbuffers//:typescript.bzl", "flatbuffer_ts_library")
@@ -60,3 +61,14 @@
visibility = ["//visibility:public"],
),
) for name in FILE_NAMES]
+
+npm_package(
+ name = "messages",
+ srcs = [
+ ":package.json",
+ ] + [
+ ":{}_ts_fbs_ts".format(lib)
+ for lib in FILE_NAMES
+ ],
+ visibility = ["//visibility:public"],
+)
diff --git a/scouting/webserver/requests/messages/package.json b/scouting/webserver/requests/messages/package.json
new file mode 100644
index 0000000..323b3c4
--- /dev/null
+++ b/scouting/webserver/requests/messages/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@org_frc971/scouting/webserver/requests/messages",
+ "private": true,
+ "dependencies": {
+ }
+}
diff --git a/scouting/webserver/requests/messages/submit_2024_actions.fbs b/scouting/webserver/requests/messages/submit_2024_actions.fbs
index 9462fbe..e927b67 100644
--- a/scouting/webserver/requests/messages/submit_2024_actions.fbs
+++ b/scouting/webserver/requests/messages/submit_2024_actions.fbs
@@ -46,13 +46,21 @@
spotlight:bool (id:2);
}
+table EndAutoPhaseAction {
+}
+
+table EndTeleopPhaseAction {
+}
+
union ActionType {
MobilityAction,
StartMatchAction,
+ EndAutoPhaseAction,
PickupNoteAction,
PlaceNoteAction,
PenaltyAction,
RobotDeathAction,
+ EndTeleopPhaseAction,
EndMatchAction
}
@@ -72,4 +80,4 @@
// submission. I.e. checking that the match information exists in the match
// list should be skipped.
pre_scouting:bool (id: 5);
-}
\ No newline at end of file
+}
diff --git a/scouting/www/BUILD b/scouting/www/BUILD
index a6ca0a1..46742e3 100644
--- a/scouting/www/BUILD
+++ b/scouting/www/BUILD
@@ -36,16 +36,7 @@
"assets/971_144.png",
],
deps = [
- "//:node_modules/@angular/animations",
- "//:node_modules/@angular/service-worker",
- "//scouting/www/driver_ranking",
- "//scouting/www/entry",
- "//scouting/www/match_list",
- "//scouting/www/notes",
- "//scouting/www/pit_scouting",
- "//scouting/www/scan",
- "//scouting/www/shift_schedule",
- "//scouting/www/view",
+ ":node_modules",
],
)
diff --git a/scouting/www/app/app.module.ts b/scouting/www/app/app.module.ts
index decd1f3..e23c2f3 100644
--- a/scouting/www/app/app.module.ts
+++ b/scouting/www/app/app.module.ts
@@ -4,14 +4,15 @@
import {ServiceWorkerModule} from '@angular/service-worker';
import {App} from './app';
-import {EntryModule} from '../entry';
-import {MatchListModule} from '../match_list';
-import {NotesModule} from '../notes';
-import {ShiftScheduleModule} from '../shift_schedule';
-import {ViewModule} from '../view';
-import {DriverRankingModule} from '../driver_ranking';
-import {PitScoutingModule} from '../pit_scouting';
-import {ScanModule} from '../scan';
+import {PipeModule} from '@org_frc971/scouting/www/pipes';
+import {EntryModule} from '@org_frc971/scouting/www/entry';
+import {MatchListModule} from '@org_frc971/scouting/www/match_list';
+import {NotesModule} from '@org_frc971/scouting/www/notes';
+import {ShiftScheduleModule} from '@org_frc971/scouting/www/shift_schedule';
+import {ViewModule} from '@org_frc971/scouting/www/view';
+import {DriverRankingModule} from '@org_frc971/scouting/www/driver_ranking';
+import {PitScoutingModule} from '@org_frc971/scouting/www/pit_scouting';
+import {ScanModule} from '@org_frc971/scouting/www/scan';
@NgModule({
declarations: [App],
@@ -27,6 +28,7 @@
EntryModule,
NotesModule,
MatchListModule,
+ PipeModule,
ShiftScheduleModule,
DriverRankingModule,
ViewModule,
diff --git a/scouting/www/app/app.ts b/scouting/www/app/app.ts
index 1a70b6f..645c224 100644
--- a/scouting/www/app/app.ts
+++ b/scouting/www/app/app.ts
@@ -1,5 +1,7 @@
import {Component, ElementRef, ViewChild, isDevMode} from '@angular/core';
+import {CompLevel} from '@org_frc971/scouting/www/entry';
+
type Tab =
| 'MatchList'
| 'Notes'
@@ -17,7 +19,7 @@
teamNumber: string;
matchNumber: number;
setNumber: number;
- compLevel: string;
+ compLevel: CompLevel;
};
@Component({
diff --git a/scouting/www/counter_button/BUILD b/scouting/www/counter_button/BUILD
deleted file mode 100644
index d081f9d..0000000
--- a/scouting/www/counter_button/BUILD
+++ /dev/null
@@ -1,8 +0,0 @@
-load("@npm//:defs.bzl", "npm_link_all_packages")
-load("//tools/build_rules:js.bzl", "ng_pkg")
-
-npm_link_all_packages(name = "node_modules")
-
-ng_pkg(
- name = "counter_button",
-)
diff --git a/scouting/www/counter_button/counter_button.component.css b/scouting/www/counter_button/counter_button.component.css
deleted file mode 100644
index df95f65..0000000
--- a/scouting/www/counter_button/counter_button.component.css
+++ /dev/null
@@ -1,14 +0,0 @@
-:host {
- display: flex;
- align-items: stretch;
- flex-direction: column;
- text-align: center;
-}
-
-* {
- padding: 10px;
-}
-
-.no-touch-action {
- touch-action: manipulation;
-}
diff --git a/scouting/www/counter_button/counter_button.component.ts b/scouting/www/counter_button/counter_button.component.ts
deleted file mode 100644
index fa84dc6..0000000
--- a/scouting/www/counter_button/counter_button.component.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import {Component, Input, Output, EventEmitter} from '@angular/core';
-
-@Component({
- selector: 'frc971-counter-button',
- templateUrl: './counter_button.ng.html',
- styleUrls: ['./counter_button.component.css'],
-})
-export class CounterButton {
- @Input() value: number = 0;
- @Output() valueChange = new EventEmitter<number>();
-
- update(delta: number) {
- this.value = Math.max(this.value + delta, 0);
-
- this.valueChange.emit(this.value);
- }
-}
diff --git a/scouting/www/counter_button/counter_button.module.ts b/scouting/www/counter_button/counter_button.module.ts
deleted file mode 100644
index 719ce7c..0000000
--- a/scouting/www/counter_button/counter_button.module.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import {NgModule} from '@angular/core';
-
-import {CounterButton} from './counter_button.component';
-
-@NgModule({
- declarations: [CounterButton],
- exports: [CounterButton],
-})
-export class CounterButtonModule {}
diff --git a/scouting/www/counter_button/counter_button.ng.html b/scouting/www/counter_button/counter_button.ng.html
deleted file mode 100644
index 3300ff2..0000000
--- a/scouting/www/counter_button/counter_button.ng.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<h4><ng-content></ng-content></h4>
-<button (click)="update(1)" class="btn btn-secondary btn-block no-touch-action">
- +
-</button>
-<h3>{{value}}</h3>
-<button
- (click)="update(-1)"
- class="btn btn-secondary btn-block no-touch-action"
->
- -
-</button>
diff --git a/scouting/www/counter_button/package.json b/scouting/www/counter_button/package.json
deleted file mode 100644
index 61eb83b..0000000
--- a/scouting/www/counter_button/package.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "@org_frc971/scouting/www/counter_button",
- "private": true
-}
diff --git a/scouting/www/driver_ranking/BUILD b/scouting/www/driver_ranking/BUILD
index a934ffe..1565dad 100644
--- a/scouting/www/driver_ranking/BUILD
+++ b/scouting/www/driver_ranking/BUILD
@@ -9,9 +9,7 @@
"//scouting/www:app_common_css",
],
deps = [
- ":node_modules/@angular/forms",
- "//scouting/webserver/requests/messages:error_response_ts_fbs",
- "//scouting/webserver/requests/messages:submit_driver_ranking_ts_fbs",
- "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+ ":node_modules",
+ "//:node_modules/flatbuffers",
],
)
diff --git a/scouting/www/driver_ranking/driver_ranking.component.ts b/scouting/www/driver_ranking/driver_ranking.component.ts
index 09f62c2..2148b63 100644
--- a/scouting/www/driver_ranking/driver_ranking.component.ts
+++ b/scouting/www/driver_ranking/driver_ranking.component.ts
@@ -1,7 +1,7 @@
import {Component, OnInit} from '@angular/core';
import {Builder, ByteBuffer} from 'flatbuffers';
-import {SubmitDriverRanking} from '../../webserver/requests/messages/submit_driver_ranking_generated';
-import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
+import {SubmitDriverRanking} from '@org_frc971/scouting/webserver/requests/messages/submit_driver_ranking_generated';
+import {ErrorResponse} from '@org_frc971/scouting/webserver/requests/messages/error_response_generated';
// TeamSelection: Display form to input which
// teams to rank and the match number.
diff --git a/scouting/www/driver_ranking/package.json b/scouting/www/driver_ranking/package.json
index 38d9358..73b6f6b 100644
--- a/scouting/www/driver_ranking/package.json
+++ b/scouting/www/driver_ranking/package.json
@@ -2,6 +2,7 @@
"name": "@org_frc971/scouting/www/driver_ranking",
"private": true,
"dependencies": {
- "@angular/forms": "v16-lts"
+ "@angular/forms": "v16-lts",
+ "@org_frc971/scouting/webserver/requests/messages": "workspace:*"
}
}
diff --git a/scouting/www/entry/BUILD b/scouting/www/entry/BUILD
index 48732f9..24da904 100644
--- a/scouting/www/entry/BUILD
+++ b/scouting/www/entry/BUILD
@@ -1,23 +1,38 @@
load("@npm//:defs.bzl", "npm_link_all_packages")
load("//tools/build_rules:js.bzl", "ng_pkg")
+load("//tools/build_rules:template.bzl", "jinja2_template")
npm_link_all_packages(name = "node_modules")
ng_pkg(
name = "entry",
extra_srcs = [
+ ":action_helper.ts",
"//scouting/www:app_common_css",
],
deps = [
- ":node_modules/@angular/forms",
- "//:node_modules/@angular/platform-browser",
- "//:node_modules/@types/pako",
- "//:node_modules/angularx-qrcode",
- "//:node_modules/pako",
- "//scouting/webserver/requests/messages:error_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_matches_response_ts_fbs",
- "//scouting/webserver/requests/messages:submit_2024_actions_ts_fbs",
- "//scouting/www/rpc",
- "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+ ":node_modules",
+ "//:node_modules/flatbuffers",
],
)
+
+jinja2_template(
+ name = "action_helper.ts",
+ src = "action_helper.jinja2.ts",
+ list_parameters = {
+ # Is there a way to auto-generate the list of actions here? Would be
+ # nice not to have a duplicate list here when they're already known in
+ # the .fbs file.
+ "ACTIONS": [
+ "EndMatchAction",
+ "MobilityAction",
+ "PenaltyAction",
+ "PickupNoteAction",
+ "PlaceNoteAction",
+ "RobotDeathAction",
+ "StartMatchAction",
+ "EndAutoPhaseAction",
+ "EndTeleopPhaseAction",
+ ],
+ },
+)
diff --git a/scouting/www/entry/action_helper.jinja2.ts b/scouting/www/entry/action_helper.jinja2.ts
new file mode 100644
index 0000000..bdce4d3
--- /dev/null
+++ b/scouting/www/entry/action_helper.jinja2.ts
@@ -0,0 +1,32 @@
+import {
+ ActionT,
+ ActionType,
+{% for action in ACTIONS %}
+ {{ action }}T,
+{% endfor %}
+} from '@org_frc971/scouting/webserver/requests/messages/submit_2024_actions_generated';
+
+export type ConcreteAction =
+{% for action in ACTIONS %}
+ {{ action }}T {% if not loop.last %} | {% endif %}
+{% endfor %};
+
+export class ActionHelper {
+ constructor(
+ private addAction: (actionType: ActionType, action: ConcreteAction) => void
+ ){}
+
+ {% for action in ACTIONS %}
+ // Calls `addAction` in entry.component.ts with the proper arguments. This
+ // also forces users to specify all the attributes in the `action` object.
+ public add{{ action}}(action: NonFunctionProperties<{{ action }}T>): void {
+ this.addAction(ActionType.{{ action }}, Object.assign(new {{ action }}T(), action));
+ }
+ {% endfor %}
+}
+
+type NonFunctionPropertyNames<T> = {
+ [K in keyof T]: T[K] extends Function ? never : K
+}[keyof T];
+
+type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;
diff --git a/scouting/www/entry/entry.component.ts b/scouting/www/entry/entry.component.ts
index 21fd474..cd59884 100644
--- a/scouting/www/entry/entry.component.ts
+++ b/scouting/www/entry/entry.component.ts
@@ -9,23 +9,32 @@
} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {Builder, ByteBuffer} from 'flatbuffers';
-import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
+import {ErrorResponse} from '@org_frc971/scouting/webserver/requests/messages/error_response_generated';
import {
StartMatchAction,
+ StartMatchActionT,
ScoreType,
StageType,
Submit2024Actions,
MobilityAction,
+ MobilityActionT,
PenaltyAction,
+ PenaltyActionT,
PickupNoteAction,
+ PickupNoteActionT,
PlaceNoteAction,
+ PlaceNoteActionT,
RobotDeathAction,
+ RobotDeathActionT,
EndMatchAction,
+ EndMatchActionT,
ActionType,
Action,
-} from '../../webserver/requests/messages/submit_2024_actions_generated';
-import {Match} from '../../webserver/requests/messages/request_all_matches_response_generated';
-import {MatchListRequestor} from '../rpc';
+ ActionT,
+} from '@org_frc971/scouting/webserver/requests/messages/submit_2024_actions_generated';
+import {Match} from '@org_frc971/scouting/webserver/requests/messages/request_all_matches_response_generated';
+import {MatchListRequestor} from '@org_frc971/scouting/www/rpc';
+import {ActionHelper, ConcreteAction} from './action_helper';
import * as pako from 'pako';
type Section =
@@ -41,7 +50,7 @@
// TODO(phil): Deduplicate with match_list.component.ts.
const COMP_LEVELS = ['qm', 'ef', 'qf', 'sf', 'f'] as const;
-type CompLevel = typeof COMP_LEVELS[number];
+export type CompLevel = typeof COMP_LEVELS[number];
// TODO(phil): Deduplicate with match_list.component.ts.
const COMP_LEVEL_LABELS: Record<CompLevel, string> = {
@@ -59,57 +68,12 @@
// The default index into QR_CODE_PIECE_SIZES.
const DEFAULT_QR_CODE_PIECE_SIZE_INDEX = QR_CODE_PIECE_SIZES.indexOf(750);
-type ActionT =
- | {
- type: 'startMatchAction';
- timestamp?: number;
- position: number;
- }
- | {
- type: 'mobilityAction';
- timestamp?: number;
- mobility: boolean;
- }
- | {
- type: 'pickupNoteAction';
- timestamp?: number;
- auto?: boolean;
- }
- | {
- type: 'placeNoteAction';
- timestamp?: number;
- scoreType: ScoreType;
- auto?: boolean;
- }
- | {
- type: 'robotDeathAction';
- timestamp?: number;
- robotDead: boolean;
- }
- | {
- type: 'penaltyAction';
- timestamp?: number;
- penalties: number;
- }
- | {
- type: 'endMatchAction';
- stageType: StageType;
- trapNote: boolean;
- spotlight: boolean;
- timestamp?: number;
- }
- | {
- // This is not a action that is submitted,
- // It is used for undoing purposes.
- type: 'endAutoPhase';
- timestamp?: number;
- }
- | {
- // This is not a action that is submitted,
- // It is used for undoing purposes.
- type: 'endTeleopPhase';
- timestamp?: number;
- };
+// The actions that are purely used for tracking state. They don't actually
+// have any permanent meaning and will not be saved in the database.
+const STATE_ACTIONS: ActionType[] = [
+ ActionType.EndAutoPhaseAction,
+ ActionType.EndTeleopPhaseAction,
+];
@Component({
selector: 'app-entry',
@@ -124,6 +88,15 @@
readonly QR_CODE_PIECE_SIZES = QR_CODE_PIECE_SIZES;
readonly ScoreType = ScoreType;
readonly StageType = StageType;
+ readonly ActionT = ActionT;
+ readonly ActionType = ActionType;
+ readonly StartMatchActionT = StartMatchActionT;
+ readonly MobilityActionT = MobilityActionT;
+ readonly PickupNoteActionT = PickupNoteActionT;
+ readonly PlaceNoteActionT = PlaceNoteActionT;
+ readonly RobotDeathActionT = RobotDeathActionT;
+ readonly PenaltyActionT = PenaltyActionT;
+ readonly EndMatchActionT = EndMatchActionT;
section: Section = 'Team Selection';
@Input() matchNumber: number = 1;
@@ -136,12 +109,18 @@
matchList: Match[] = [];
+ actionHelper: ActionHelper;
actionList: ActionT[] = [];
progressMessage: string = '';
errorMessage: string = '';
autoPhase: boolean = true;
mobilityCompleted: boolean = false;
+ // TODO(phil): Come up with a better name here.
selectedValue = 0;
+ endGameAction: StageType = StageType.kMISSING;
+ noteIsTrapped: boolean = false;
+ endGameSpotlight: boolean = false;
+
nextTeamNumber = '';
preScouting: boolean = false;
@@ -163,6 +142,12 @@
constructor(private readonly matchListRequestor: MatchListRequestor) {}
ngOnInit() {
+ this.actionHelper = new ActionHelper(
+ (actionType: ActionType, action: ConcreteAction) => {
+ this.addAction(actionType, action);
+ }
+ );
+
// When the user navigated from the match list, we can skip the team
// selection. I.e. we trust that the user clicked the correct button.
this.section = this.skipTeamSelection ? 'Init' : 'Team Selection';
@@ -231,60 +216,58 @@
}
addPenalties(): void {
- this.addAction({type: 'penaltyAction', penalties: this.penalties});
+ this.actionHelper.addPenaltyAction({penalties: this.penalties});
}
- addAction(action: ActionT): void {
- if (action.type == 'startMatchAction') {
+ addAction(actionType: ActionType, action: ConcreteAction): void {
+ let timestamp: number = 0;
+
+ if (actionType == ActionType.StartMatchAction) {
// Unix nanosecond timestamp.
this.matchStartTimestamp = Date.now() * 1e6;
- action.timestamp = 0;
} else {
// Unix nanosecond timestamp relative to match start.
- action.timestamp = Date.now() * 1e6 - this.matchStartTimestamp;
+ timestamp = Date.now() * 1e6 - this.matchStartTimestamp;
}
- if (action.type == 'endMatchAction') {
+ if (actionType == ActionType.EndMatchAction) {
// endMatchAction occurs at the same time as penaltyAction so add to its
// timestamp to make it unique.
- action.timestamp += 1;
+ timestamp += 1;
}
- if (action.type == 'mobilityAction') {
+ if (actionType == ActionType.MobilityAction) {
this.mobilityCompleted = true;
}
- if (action.type == 'pickupNoteAction' || action.type == 'placeNoteAction') {
- action.auto = this.autoPhase;
- }
- this.actionList.push(action);
+ this.actionList.push(new ActionT(BigInt(timestamp), actionType, action));
}
undoLastAction() {
if (this.actionList.length > 0) {
let lastAction = this.actionList.pop();
- switch (lastAction?.type) {
- case 'endAutoPhase':
+ switch (lastAction?.actionTakenType) {
+ case ActionType.EndAutoPhaseAction:
this.autoPhase = true;
this.section = 'Pickup';
- case 'pickupNoteAction':
+ case ActionType.PickupNoteAction:
this.section = 'Pickup';
break;
- case 'endTeleopPhase':
+ case ActionType.EndTeleopPhaseAction:
this.section = 'Pickup';
break;
- case 'placeNoteAction':
+ case ActionType.PlaceNoteAction:
this.section = 'Place';
break;
- case 'endMatchAction':
+ case ActionType.EndMatchAction:
this.section = 'Endgame';
- case 'mobilityAction':
+ case ActionType.MobilityAction:
this.mobilityCompleted = false;
break;
- case 'startMatchAction':
+ case ActionType.StartMatchAction:
this.section = 'Init';
break;
- case 'robotDeathAction':
+ case ActionType.RobotDeathAction:
// TODO(FILIP): Return user to the screen they
// clicked dead robot on. Pickup is fine for now but
// might cause confusion.
@@ -326,111 +309,11 @@
const actionOffsets: number[] = [];
for (const action of this.actionList) {
- let actionOffset: number | undefined;
-
- switch (action.type) {
- case 'startMatchAction':
- const startMatchActionOffset =
- StartMatchAction.createStartMatchAction(builder, action.position);
- actionOffset = Action.createAction(
- builder,
- BigInt(action.timestamp || 0),
- ActionType.StartMatchAction,
- startMatchActionOffset
- );
- break;
- case 'mobilityAction':
- const mobilityActionOffset = MobilityAction.createMobilityAction(
- builder,
- action.mobility
- );
- actionOffset = Action.createAction(
- builder,
- BigInt(action.timestamp || 0),
- ActionType.MobilityAction,
- mobilityActionOffset
- );
- break;
- case 'penaltyAction':
- const penaltyActionOffset = PenaltyAction.createPenaltyAction(
- builder,
- action.penalties
- );
- actionOffset = Action.createAction(
- builder,
- BigInt(action.timestamp || 0),
- ActionType.PenaltyAction,
- penaltyActionOffset
- );
- break;
- case 'pickupNoteAction':
- const pickupNoteActionOffset =
- PickupNoteAction.createPickupNoteAction(
- builder,
- action.auto || false
- );
- actionOffset = Action.createAction(
- builder,
- BigInt(action.timestamp || 0),
- ActionType.PickupNoteAction,
- pickupNoteActionOffset
- );
- break;
- case 'placeNoteAction':
- const placeNoteActionOffset = PlaceNoteAction.createPlaceNoteAction(
- builder,
- action.scoreType,
- action.auto || false
- );
- actionOffset = Action.createAction(
- builder,
- BigInt(action.timestamp || 0),
- ActionType.PlaceNoteAction,
- placeNoteActionOffset
- );
- break;
-
- case 'robotDeathAction':
- const robotDeathActionOffset =
- RobotDeathAction.createRobotDeathAction(builder, action.robotDead);
- actionOffset = Action.createAction(
- builder,
- BigInt(action.timestamp || 0),
- ActionType.RobotDeathAction,
- robotDeathActionOffset
- );
- break;
-
- case 'endMatchAction':
- const endMatchActionOffset = EndMatchAction.createEndMatchAction(
- builder,
- action.stageType,
- action.trapNote,
- action.spotlight
- );
- actionOffset = Action.createAction(
- builder,
- BigInt(action.timestamp || 0),
- ActionType.EndMatchAction,
- endMatchActionOffset
- );
- break;
-
- case 'endAutoPhase':
- // Not important action.
- break;
-
- case 'endTeleopPhase':
- // Not important action.
- break;
-
- default:
- throw new Error(`Unknown action type`);
+ if (STATE_ACTIONS.includes(action.actionTakenType)) {
+ // Actions only used for undo purposes are not submitted.
+ continue;
}
-
- if (actionOffset !== undefined) {
- actionOffsets.push(actionOffset);
- }
+ actionOffsets.push(action.pack(builder));
}
const teamNumberFb = builder.createString(this.teamNumber);
const compLevelFb = builder.createString(this.compLevel);
diff --git a/scouting/www/entry/entry.module.ts b/scouting/www/entry/entry.module.ts
index bcba4ee..8757ced 100644
--- a/scouting/www/entry/entry.module.ts
+++ b/scouting/www/entry/entry.module.ts
@@ -1,12 +1,14 @@
-import {NgModule, Pipe, PipeTransform} from '@angular/core';
+import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule} from '@angular/forms';
import {EntryComponent} from './entry.component';
import {QRCodeModule} from 'angularx-qrcode';
+import {PipeModule} from '@org_frc971/scouting/www/pipes';
+
@NgModule({
declarations: [EntryComponent],
exports: [EntryComponent],
- imports: [CommonModule, FormsModule, QRCodeModule],
+ imports: [PipeModule, CommonModule, FormsModule, QRCodeModule],
})
export class EntryModule {}
diff --git a/scouting/www/entry/entry.ng.html b/scouting/www/entry/entry.ng.html
index 553fa1e..d95bcec 100644
--- a/scouting/www/entry/entry.ng.html
+++ b/scouting/www/entry/entry.ng.html
@@ -91,7 +91,7 @@
type="radio"
name="radio-group"
[value]="i"
- (change)="selectedValue = $event.target.value"
+ [(ngModel)]="selectedValue"
/>
{{ i }}
</label>
@@ -102,7 +102,7 @@
<button
class="btn btn-primary"
[disabled]="!selectedValue"
- (click)="changeSectionTo('Pickup'); addAction({type: 'startMatchAction', position: selectedValue});"
+ (click)="changeSectionTo('Pickup'); actionHelper.addStartMatchAction({position: selectedValue});"
>
Start Match
</button>
@@ -111,7 +111,8 @@
</div>
<div *ngSwitchCase="'Pickup'" id="PickUp" class="container-fluid">
<h6 class="text-muted">
- Last Action: {{actionList[actionList.length - 1].type}}
+ Last Action: {{ActionType[actionList[actionList.length -
+ 1].actionTakenType]}}
</h6>
<!--
Decrease distance between buttons during auto to make space for auto balancing
@@ -123,20 +124,20 @@
<button class="btn btn-secondary" (click)="undoLastAction()">UNDO</button>
<button
class="btn btn-danger"
- (click)="changeSectionTo('Dead'); addAction({type: 'robotDeathAction', robotDead: true});"
+ (click)="changeSectionTo('Dead'); actionHelper.addRobotDeathAction({robotDead: true});"
>
DEAD
</button>
<button
class="btn btn-warning"
- (click)="changeSectionTo('Place'); addAction({type: 'pickupNoteAction'});"
+ (click)="changeSectionTo('Place'); actionHelper.addPickupNoteAction({auto: autoPhase});"
>
NOTE
</button>
<button
*ngIf="autoPhase && !mobilityCompleted"
class="btn btn-light"
- (click)="addAction({type: 'mobilityAction', mobility: true});"
+ (click)="actionHelper.addMobilityAction({mobility: true});"
>
Mobility
</button>
@@ -161,14 +162,14 @@
<button
*ngIf="autoPhase"
class="btn btn-dark"
- (click)="autoPhase = false; addAction({type: 'endAutoPhase'});"
+ (click)="autoPhase = false; actionHelper.addEndAutoPhaseAction({});"
>
Start Teleop
</button>
<button
*ngIf="!autoPhase"
class="btn btn-info"
- (click)="changeSectionTo('Endgame'); addAction({type: 'endTeleopPhase'});"
+ (click)="changeSectionTo('Endgame'); actionHelper.addEndTeleopPhaseAction({});"
>
Endgame
</button>
@@ -176,7 +177,8 @@
</div>
<div *ngSwitchCase="'Place'" id="Place" class="container-fluid">
<h6 class="text-muted">
- Last Action: {{actionList[actionList.length - 1].type}}
+ Last Action: {{ActionType[actionList[actionList.length -
+ 1].actionTakenType]}}
</h6>
<!--
Decrease distance between buttons during auto to make space for auto balancing
@@ -188,13 +190,13 @@
<button class="btn btn-secondary" (click)="undoLastAction()">UNDO</button>
<button
class="btn btn-danger"
- (click)="changeSectionTo('Dead'); addAction({type: 'robotDeathAction', robotDead: true});"
+ (click)="changeSectionTo('Dead'); actionHelper.addRobotDeathAction({robotDead: true});"
>
DEAD
</button>
<button
class="btn btn-info"
- (click)="changeSectionTo('Pickup'); addAction({type: 'placeNoteAction', scoreType: ScoreType.kDROPPED});"
+ (click)="changeSectionTo('Pickup'); actionHelper.addPlaceNoteAction({auto: autoPhase, scoreType: ScoreType.kDROPPED});"
>
Dropped
</button>
@@ -211,7 +213,7 @@
>
<button
class="btn btn-success"
- (click)="changeSectionTo('Pickup'); addAction({type: 'placeNoteAction', scoreType: ScoreType.kAMP});"
+ (click)="changeSectionTo('Pickup'); actionHelper.addPlaceNoteAction({auto: autoPhase, scoreType: ScoreType.kAMP});"
style="width: 48%; height: 12vh; margin: 0px 10px 10px 0px"
>
AMP
@@ -219,21 +221,21 @@
<button
class="btn btn-warning"
- (click)="changeSectionTo('Pickup'); addAction({type: 'placeNoteAction', scoreType: ScoreType.kAMP_AMPLIFIED});"
+ (click)="changeSectionTo('Pickup'); actionHelper.addPlaceNoteAction({auto: autoPhase, scoreType: ScoreType.kAMP_AMPLIFIED});"
style="width: 48%; height: 12vh; margin: 0px 0px 10px 0px"
>
AMP AMPLIFIED
</button>
<button
class="btn btn-success"
- (click)="changeSectionTo('Pickup'); addAction({type: 'placeNoteAction', scoreType: ScoreType.kSPEAKER});"
+ (click)="changeSectionTo('Pickup'); actionHelper.addPlaceNoteAction({auto: autoPhase, scoreType: ScoreType.kSPEAKER});"
style="width: 48%; height: 12vh; margin: 0px 10px 0px 0px"
>
SPEAKER
</button>
<button
class="btn btn-warning"
- (click)="changeSectionTo('Pickup'); addAction({type: 'placeNoteAction', scoreType: ScoreType.kSPEAKER_AMPLIFIED});"
+ (click)="changeSectionTo('Pickup'); actionHelper.addPlaceNoteAction({auto: autoPhase, scoreType: ScoreType.kSPEAKER_AMPLIFIED});"
style="width: 48%; height: 12vh; margin: 0px 0px 0px 0px"
>
SPEAKER AMPLIFIED
@@ -244,21 +246,21 @@
<button
*ngIf="autoPhase"
class="btn btn-success"
- (click)="changeSectionTo('Pickup'); addAction({type: 'placeNoteAction', scoreType: ScoreType.kAMP});"
+ (click)="changeSectionTo('Pickup'); actionHelper.addPlaceNoteAction({auto: autoPhase, scoreType: ScoreType.kAMP});"
>
AMP
</button>
<button
*ngIf="autoPhase"
class="btn btn-warning"
- (click)="changeSectionTo('Pickup'); addAction({type: 'placeNoteAction', scoreType: ScoreType.kSPEAKER});"
+ (click)="changeSectionTo('Pickup'); actionHelper.addPlaceNoteAction({auto: autoPhase, scoreType: ScoreType.kSPEAKER});"
>
SPEAKER
</button>
<button
*ngIf="autoPhase && !mobilityCompleted"
class="btn btn-light"
- (click)="addAction({type: 'mobilityAction', mobility: true});"
+ (click)="actionHelper.addMobilityAction({mobility: true});"
>
Mobility
</button>
@@ -283,14 +285,14 @@
<button
class="btn btn-dark"
*ngIf="autoPhase"
- (click)="autoPhase = false; addAction({type: 'endAutoPhase'});"
+ (click)="autoPhase = false; actionHelper.addEndAutoPhaseAction({});"
>
Start Teleop
</button>
<button
*ngIf="!autoPhase"
class="btn btn-info"
- (click)="changeSectionTo('Endgame'); addAction({type: 'endTeleopPhase'});"
+ (click)="changeSectionTo('Endgame'); actionHelper.addEndTeleopPhaseAction({});"
>
Endgame
</button>
@@ -298,34 +300,33 @@
</div>
<div *ngSwitchCase="'Endgame'" id="Endgame" class="container-fluid">
<h6 class="text-muted">
- Last Action: {{actionList[actionList.length - 1].type}}
+ Last Action: {{ActionType[actionList[actionList.length -
+ 1].actionTakenType]}}
</h6>
<div class="d-grid gap-2">
<button class="btn btn-secondary" (click)="undoLastAction()">UNDO</button>
<button
class="btn btn-danger"
- (click)="changeSectionTo('Dead'); addAction({type: 'robotDeathAction', robotDead: true});"
+ (click)="changeSectionTo('Dead'); actionHelper.addRobotDeathAction({robotDead: true});"
>
DEAD
</button>
<div class="button_row">
<label>
<input
- #park
type="radio"
- id="option1"
name="endgameaction"
- value="park"
+ [value]="StageType.kPARK"
+ [(ngModel)]="endGameAction"
/>
Park
</label>
<label>
<input
- #onStage
type="radio"
- id="option2"
name="endgameaction"
- value="onStage"
+ [value]="StageType.kON_STAGE"
+ [(ngModel)]="endGameAction"
/>
On Stage
</label>
@@ -333,42 +334,32 @@
<div class="button_row">
<label>
<input
- #harmony
type="radio"
- id="option3"
name="endgameaction"
- value="harmony"
+ [value]="StageType.kHARMONY"
+ [(ngModel)]="endGameAction"
/>
Harmony
</label>
<label>
<input
- #na
type="radio"
- id="option2"
name="endgameaction"
- value="na"
+ [value]="StageType.kMISSING"
+ [(ngModel)]="endGameAction"
/>
N/A
</label>
</div>
<label>
- <input
- #trapNote
- type="checkbox"
- id="trapnote"
- name="trapnote"
- value="trapNote"
- />
+ <input type="checkbox" name="trapnote" [(ngModel)]="noteIsTrapped" />
Trap Note
</label>
<label>
<input
- #spotlight
type="checkbox"
- id="spotlight"
name="spotlight"
- value="spotlight"
+ [(ngModel)]="endGameSpotlight"
/>
Spotlight
</label>
@@ -394,7 +385,7 @@
<button
*ngIf="!autoPhase"
class="btn btn-info"
- (click)="changeSectionTo('Review and Submit'); addPenalties(); addAction({type: 'endMatchAction', stageType: (park.checked ? StageType.kPARK : onStage.checked ? StageType.kON_STAGE : harmony.checked ? StageType.kHARMONY : StageType.kMISSING), trapNote: trapNote.checked, spotlight: spotlight.checked});"
+ (click)="changeSectionTo('Review and Submit'); addPenalties(); actionHelper.addEndMatchAction({stageType: endGameAction, trapNote: noteIsTrapped, spotlight: endGameSpotlight});"
>
End Match
</button>
@@ -424,13 +415,13 @@
</div>
<button
class="btn btn-success"
- (click)="changeSectionTo('Pickup'); addAction({type: 'robotDeathAction', robotDead: false}); "
+ (click)="changeSectionTo('Pickup'); actionHelper.addRobotDeathAction({robotDead: false}); "
>
Revive
</button>
<button
class="btn btn-info"
- (click)="changeSectionTo('Review and Submit'); addPenalties(); addAction({type: 'endMatchAction', stageType: (park.checked ? StageType.kPARK : onStage.checked ? StageType.kON_STAGE : harmony.checked ? StageType.kHARMONY : StageType.kMISSING), trapNote: trapNote.checked, spotlight: spotlight.checked});"
+ (click)="changeSectionTo('Review and Submit'); addPenalties(); actionHelper.addEndMatchAction({stageType: endGameAction, trapNote: noteIsTrapped, spotlight: endGameSpotlight});"
>
End Match
</button>
@@ -439,35 +430,41 @@
<div *ngSwitchCase="'Review and Submit'" id="Review" class="container-fluid">
<div class="row">
<ul id="review_data">
- <li
- *ngFor="let action of actionList"
- [ngValue]="action"
- style="display: flex"
- >
- <div [ngSwitch]="action.type" style="padding: 0px">
- <span *ngSwitchCase="'startMatchAction'">
- Started match at position {{action.position}}
+ <li *ngFor="let action of actionList" style="display: flex">
+ <div [ngSwitch]="action.actionTakenType" style="padding: 0px">
+ <span *ngSwitchCase="ActionType.StartMatchAction">
+ Started match at position {{(action.actionTaken | cast:
+ StartMatchActionT).position}}
</span>
- <span *ngSwitchCase="'pickupNoteAction'">Picked up Note</span>
- <span *ngSwitchCase="'placeNoteAction'">
- Placed at {{stringifyScoreType(action.scoreType)}}
+ <span *ngSwitchCase="ActionType.PickupNoteAction">
+ Picked up Note
</span>
- <span *ngSwitchCase="'endAutoPhase'">Ended auto phase</span>
- <span *ngSwitchCase="'endMatchAction'">
- Ended Match; stageType: {{(action.stageType === 0 ? "kON_STAGE" :
- action.stageType === 1 ? "kPARK" : action.stageType === 2 ?
- "kHARMONY" : "kMISSING")}}, trapNote: {{action.trapNote}},
- spotlight: {{action.spotlight}}
+ <span *ngSwitchCase="ActionType.PlaceNoteAction">
+ Placed at {{stringifyScoreType((action.actionTaken | cast:
+ PlaceNoteActionT).scoreType)}}
</span>
- <span *ngSwitchCase="'robotDeathAction'">
- Robot dead: {{action.robotDead}}
+ <span *ngSwitchCase="ActionType.EndAutoPhaseAction">
+ Ended auto phase
</span>
- <span *ngSwitchCase="'mobilityAction'">
- Mobility: {{action.mobility}}
+ <span *ngSwitchCase="ActionType.EndMatchAction">
+ Ended Match; stageType: {{stringifyStageType((action.actionTaken |
+ cast: EndMatchActionT).stageType)}}, trapNote:
+ {{(action.actionTaken | cast: EndMatchActionT).trapNote}},
+ spotlight: {{(action.actionTaken | cast:
+ EndMatchActionT).spotlight}}
</span>
- <span *ngSwitchDefault>{{action.type}}</span>
- <span *ngSwitchCase="'penaltyAction'">
- Penalties: {{action.penalties}}
+ <span *ngSwitchCase="ActionType.RobotDeathAction">
+ Robot dead: {{(action.actionTaken | cast:
+ RobotDeathActionT).robotDead}}
+ </span>
+ <span *ngSwitchCase="ActionType.MobilityAction">
+ Mobility: {{(action.actionTaken | cast:
+ MobilityActionT).mobility}}
+ </span>
+ <span *ngSwitchDefault>{{action.actionTakenType}}</span>
+ <span *ngSwitchCase="ActionType.PenaltyAction">
+ Penalties: {{(action.actionTaken | cast:
+ PenaltyActionT).penalties}}
</span>
</div>
</li>
diff --git a/scouting/www/entry/package.json b/scouting/www/entry/package.json
index a02c0a6..e97d92c 100644
--- a/scouting/www/entry/package.json
+++ b/scouting/www/entry/package.json
@@ -2,9 +2,13 @@
"name": "@org_frc971/scouting/www/entry",
"private": true,
"dependencies": {
+ "angularx-qrcode": "^16.0.2",
"pako": "2.1.0",
+ "@angular/forms": "v16-lts",
+ "@angular/platform-browser": "v16-lts",
"@types/pako": "2.0.3",
- "@org_frc971/scouting/www/counter_button": "workspace:*",
- "@angular/forms": "v16-lts"
+ "@org_frc971/scouting/webserver/requests/messages": "workspace:*",
+ "@org_frc971/scouting/www/rpc": "workspace:*",
+ "@org_frc971/scouting/www/pipes": "workspace:*"
}
}
diff --git a/scouting/www/index.html b/scouting/www/index.html
index 821acf2..ee2bcb4 100644
--- a/scouting/www/index.html
+++ b/scouting/www/index.html
@@ -7,17 +7,20 @@
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="/manifest.json" />
<link
+ href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet"
- href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css"
- integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD"
+ integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
- href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css"
- integrity="d8824f7067cdfea38afec7e9ffaf072125266824206d69ef1f112d72153a505e"
+ href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
/>
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
+ <script
+ src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
+ integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
+ crossorigin="anonymous"
+ ></script>
<script>
// In order to hook into WASM's "finished loading" event, we interact
// with the global Module variable. Maybe some day there'll be a better
diff --git a/scouting/www/match_list/BUILD b/scouting/www/match_list/BUILD
index b2128db..2ff4fee 100644
--- a/scouting/www/match_list/BUILD
+++ b/scouting/www/match_list/BUILD
@@ -9,11 +9,7 @@
"//scouting/www:app_common_css",
],
deps = [
- ":node_modules/@angular/forms",
- "//scouting/webserver/requests/messages:error_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_matches_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_matches_ts_fbs",
- "//scouting/www/rpc",
- "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+ ":node_modules",
+ "//:node_modules/flatbuffers",
],
)
diff --git a/scouting/www/match_list/match_list.component.ts b/scouting/www/match_list/match_list.component.ts
index 8fafdce..08120b3 100644
--- a/scouting/www/match_list/match_list.component.ts
+++ b/scouting/www/match_list/match_list.component.ts
@@ -1,19 +1,23 @@
import {Component, EventEmitter, OnInit, Output} from '@angular/core';
import {Builder, ByteBuffer} from 'flatbuffers';
-import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
-import {RequestAllMatches} from '../../webserver/requests/messages/request_all_matches_generated';
+import {ErrorResponse} from '@org_frc971/scouting/webserver/requests/messages/error_response_generated';
+import {RequestAllMatches} from '@org_frc971/scouting/webserver/requests/messages/request_all_matches_generated';
import {
Match,
RequestAllMatchesResponse,
-} from '../../webserver/requests/messages/request_all_matches_response_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_all_matches_response_generated';
-import {MatchListRequestor} from '../rpc';
+import {MatchListRequestor} from '@org_frc971/scouting/www/rpc';
+
+// TODO(phil): Deduplicate with entry.component.ts.
+const COMP_LEVELS = ['qm', 'ef', 'qf', 'sf', 'f'] as const;
+export type CompLevel = typeof COMP_LEVELS[number];
type TeamInMatch = {
teamNumber: string;
matchNumber: number;
setNumber: number;
- compLevel: string;
+ compLevel: CompLevel;
};
@Component({
@@ -23,6 +27,7 @@
})
export class MatchListComponent implements OnInit {
@Output() selectedTeamEvent = new EventEmitter<TeamInMatch>();
+
progressMessage: string = '';
errorMessage: string = '';
matchList: Match[] = [];
@@ -30,6 +35,14 @@
constructor(private readonly matchListRequestor: MatchListRequestor) {}
+ // Validates that the specified string is a proper comp level.
+ validateCompLevel(compLevel: string): CompLevel {
+ if (COMP_LEVELS.indexOf(compLevel as any) !== -1) {
+ return compLevel as CompLevel;
+ }
+ throw new Error(`Could not parse "${compLevel}" as a valid comp level.`);
+ }
+
// Returns true if the match is fully scouted. Returns false otherwise.
matchIsFullyScouted(match: Match): boolean {
const scouted = match.dataScouted();
diff --git a/scouting/www/match_list/match_list.ng.html b/scouting/www/match_list/match_list.ng.html
index 0ebbe4c..fe26d09 100644
--- a/scouting/www/match_list/match_list.ng.html
+++ b/scouting/www/match_list/match_list.ng.html
@@ -22,7 +22,7 @@
teamNumber: team.teamNumber,
matchNumber: match.matchNumber(),
setNumber: match.setNumber(),
- compLevel: match.compLevel()
+ compLevel: validateCompLevel(match.compLevel()),
})"
class="match-item"
[ngClass]="team.color"
diff --git a/scouting/www/match_list/package.json b/scouting/www/match_list/package.json
index 00977c5..77d2dc5 100644
--- a/scouting/www/match_list/package.json
+++ b/scouting/www/match_list/package.json
@@ -2,6 +2,7 @@
"name": "@org_frc971/scouting/www/match_list",
"private": true,
"dependencies": {
+ "@org_frc971/scouting/webserver/requests/messages": "workspace:*",
"@org_frc971/scouting/www/rpc": "workspace:*",
"@angular/forms": "v16-lts"
}
diff --git a/scouting/www/notes/BUILD b/scouting/www/notes/BUILD
index 64e4ae7..59c508e 100644
--- a/scouting/www/notes/BUILD
+++ b/scouting/www/notes/BUILD
@@ -9,12 +9,7 @@
"//scouting/www:app_common_css",
],
deps = [
- ":node_modules/@angular/forms",
- "//scouting/webserver/requests/messages:error_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_notes_for_team_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_notes_for_team_ts_fbs",
- "//scouting/webserver/requests/messages:submit_notes_response_ts_fbs",
- "//scouting/webserver/requests/messages:submit_notes_ts_fbs",
- "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+ ":node_modules",
+ "//:node_modules/flatbuffers",
],
)
diff --git a/scouting/www/notes/notes.component.ts b/scouting/www/notes/notes.component.ts
index 431ec71..6263d37 100644
--- a/scouting/www/notes/notes.component.ts
+++ b/scouting/www/notes/notes.component.ts
@@ -1,13 +1,13 @@
import {Component, HostListener} from '@angular/core';
import {Builder, ByteBuffer} from 'flatbuffers';
-import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
-import {RequestNotesForTeam} from '../../webserver/requests/messages/request_notes_for_team_generated';
+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';
import {
Note as NoteFb,
RequestNotesForTeamResponse,
-} from '../../webserver/requests/messages/request_notes_for_team_response_generated';
-import {SubmitNotes} from '../../webserver/requests/messages/submit_notes_generated';
-import {SubmitNotesResponse} from '../../webserver/requests/messages/submit_notes_response_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_notes_for_team_response_generated';
+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.
diff --git a/scouting/www/notes/package.json b/scouting/www/notes/package.json
index f1ad3ae..5961469 100644
--- a/scouting/www/notes/package.json
+++ b/scouting/www/notes/package.json
@@ -2,6 +2,7 @@
"name": "@org_frc971/scouting/www/notes",
"private": true,
"dependencies": {
- "@angular/forms": "v16-lts"
+ "@angular/forms": "v16-lts",
+ "@org_frc971/scouting/webserver/requests/messages": "workspace:*"
}
}
diff --git a/scouting/www/package.json b/scouting/www/package.json
index 3ab0035..da5f279 100644
--- a/scouting/www/package.json
+++ b/scouting/www/package.json
@@ -1,4 +1,16 @@
{
"private": true,
- "dependencies": {}
+ "dependencies": {
+ "@angular/animations": "v16-lts",
+ "@angular/service-worker": "v16-lts",
+ "@org_frc971/scouting/www/driver_ranking": "workspace:*",
+ "@org_frc971/scouting/www/entry": "workspace:*",
+ "@org_frc971/scouting/www/match_list": "workspace:*",
+ "@org_frc971/scouting/www/notes": "workspace:*",
+ "@org_frc971/scouting/www/pipes": "workspace:*",
+ "@org_frc971/scouting/www/pit_scouting": "workspace:*",
+ "@org_frc971/scouting/www/scan": "workspace:*",
+ "@org_frc971/scouting/www/shift_schedule": "workspace:*",
+ "@org_frc971/scouting/www/view": "workspace:*"
+ }
}
diff --git a/scouting/www/pipes/BUILD b/scouting/www/pipes/BUILD
new file mode 100644
index 0000000..680eb09
--- /dev/null
+++ b/scouting/www/pipes/BUILD
@@ -0,0 +1,12 @@
+load("@npm//:defs.bzl", "npm_link_all_packages")
+load("//tools/build_rules:js.bzl", "ng_pkg")
+
+npm_link_all_packages(name = "node_modules")
+
+ng_pkg(
+ name = "pipes",
+ extra_srcs = [
+ "public-api.ts",
+ ],
+ generate_public_api = False,
+)
diff --git a/scouting/www/pipes/cast.ts b/scouting/www/pipes/cast.ts
new file mode 100644
index 0000000..1bb24e8
--- /dev/null
+++ b/scouting/www/pipes/cast.ts
@@ -0,0 +1,15 @@
+import {Pipe, PipeTransform} from '@angular/core';
+
+@Pipe({name: 'cast'})
+export class CastPipe implements PipeTransform {
+ /**
+ * Cast (S: SuperType) into (T: Type) using @Generics.
+ * @param value (S: SuperType) obtained from input type.
+ * @optional @param type (T CastingType)
+ * type?: { new (): T }
+ * type?: new () => T
+ */
+ transform<S, T extends S>(value: S, type?: new () => T): T {
+ return <T>value;
+ }
+}
diff --git a/scouting/www/pipes/package.json b/scouting/www/pipes/package.json
new file mode 100644
index 0000000..b4ce582
--- /dev/null
+++ b/scouting/www/pipes/package.json
@@ -0,0 +1,4 @@
+{
+ "name": "@org_frc971/scouting/www/pipes",
+ "private": true
+}
diff --git a/scouting/www/pipes/pipes.module.ts b/scouting/www/pipes/pipes.module.ts
new file mode 100644
index 0000000..b7dd4c4
--- /dev/null
+++ b/scouting/www/pipes/pipes.module.ts
@@ -0,0 +1,12 @@
+import {NgModule} from '@angular/core';
+import {CastPipe} from './cast';
+
+// Export types needed for the public API.
+export {CastPipe};
+
+@NgModule({
+ declarations: [CastPipe],
+ exports: [CastPipe],
+ imports: [],
+})
+export class PipeModule {}
diff --git a/scouting/www/pipes/public-api.ts b/scouting/www/pipes/public-api.ts
new file mode 100644
index 0000000..77a5641
--- /dev/null
+++ b/scouting/www/pipes/public-api.ts
@@ -0,0 +1 @@
+export * from './pipes.module';
diff --git a/scouting/www/pit_scouting/BUILD b/scouting/www/pit_scouting/BUILD
index 740dee1..cfaf5d4 100644
--- a/scouting/www/pit_scouting/BUILD
+++ b/scouting/www/pit_scouting/BUILD
@@ -9,10 +9,7 @@
"//scouting/www:app_common_css",
],
deps = [
- ":node_modules/@angular/forms",
- "//scouting/webserver/requests/messages:error_response_ts_fbs",
- "//scouting/webserver/requests/messages:submit_pit_image_response_ts_fbs",
- "//scouting/webserver/requests/messages:submit_pit_image_ts_fbs",
- "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+ ":node_modules",
+ "//:node_modules/flatbuffers",
],
)
diff --git a/scouting/www/pit_scouting/package.json b/scouting/www/pit_scouting/package.json
index f41150f..2eb2783 100644
--- a/scouting/www/pit_scouting/package.json
+++ b/scouting/www/pit_scouting/package.json
@@ -2,6 +2,7 @@
"name": "@org_frc971/scouting/www/pit_scouting",
"private": true,
"dependencies": {
- "@angular/forms": "v16-lts"
+ "@angular/forms": "v16-lts",
+ "@org_frc971/scouting/webserver/requests/messages": "workspace:*"
}
}
diff --git a/scouting/www/pit_scouting/pit_scouting.component.ts b/scouting/www/pit_scouting/pit_scouting.component.ts
index 7bb884c..294eca2 100644
--- a/scouting/www/pit_scouting/pit_scouting.component.ts
+++ b/scouting/www/pit_scouting/pit_scouting.component.ts
@@ -6,8 +6,8 @@
ViewChildren,
} from '@angular/core';
import {Builder, ByteBuffer} from 'flatbuffers';
-import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
-import {SubmitPitImage} from '../../webserver/requests/messages/submit_pit_image_generated';
+import {ErrorResponse} from '@org_frc971/scouting/webserver/requests/messages/error_response_generated';
+import {SubmitPitImage} from '@org_frc971/scouting/webserver/requests/messages/submit_pit_image_generated';
type Section = 'TeamSelection' | 'Data';
diff --git a/scouting/www/rpc/BUILD b/scouting/www/rpc/BUILD
index 592735c..66cba8d 100644
--- a/scouting/www/rpc/BUILD
+++ b/scouting/www/rpc/BUILD
@@ -10,18 +10,7 @@
],
generate_public_api = False,
deps = [
- "//:node_modules/dexie",
- "//scouting/webserver/requests/messages:error_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_2024_data_scouting_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_2024_data_scouting_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_driver_rankings_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_driver_rankings_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_matches_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_matches_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_notes_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_notes_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_pit_images_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_pit_images_ts_fbs",
- "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+ ":node_modules",
+ "//:node_modules/flatbuffers",
],
)
diff --git a/scouting/www/rpc/match_list_requestor.ts b/scouting/www/rpc/match_list_requestor.ts
index 0a812ce..97ed0b0 100644
--- a/scouting/www/rpc/match_list_requestor.ts
+++ b/scouting/www/rpc/match_list_requestor.ts
@@ -1,11 +1,11 @@
import {Injectable} from '@angular/core';
import {Builder, ByteBuffer} from 'flatbuffers';
-import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
-import {RequestAllMatches} from '../../webserver/requests/messages/request_all_matches_generated';
+import {ErrorResponse} from '@org_frc971/scouting/webserver/requests/messages/error_response_generated';
+import {RequestAllMatches} from '@org_frc971/scouting/webserver/requests/messages/request_all_matches_generated';
import {
Match,
RequestAllMatchesResponse,
-} from '../../webserver/requests/messages/request_all_matches_response_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_all_matches_response_generated';
import {db, MatchListData} from './db';
const MATCH_TYPE_ORDERING = ['qm', 'ef', 'qf', 'sf', 'f'];
@Injectable({providedIn: 'root'})
diff --git a/scouting/www/rpc/package.json b/scouting/www/rpc/package.json
index 6d1369a..bc9a662 100644
--- a/scouting/www/rpc/package.json
+++ b/scouting/www/rpc/package.json
@@ -1,4 +1,8 @@
{
"name": "@org_frc971/scouting/www/rpc",
- "private": true
+ "private": true,
+ "dependencies": {
+ "@org_frc971/scouting/webserver/requests/messages": "workspace:*",
+ "dexie": "^3.2.5"
+ }
}
diff --git a/scouting/www/rpc/view_data_requestor.ts b/scouting/www/rpc/view_data_requestor.ts
index 74fc212..606eef1 100644
--- a/scouting/www/rpc/view_data_requestor.ts
+++ b/scouting/www/rpc/view_data_requestor.ts
@@ -1,26 +1,26 @@
import {Injectable} from '@angular/core';
import {Builder, ByteBuffer} from 'flatbuffers';
-import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
-import {RequestAllNotes} from '../../webserver/requests/messages/request_all_notes_generated';
+import {ErrorResponse} from '@org_frc971/scouting/webserver/requests/messages/error_response_generated';
+import {RequestAllNotes} from '@org_frc971/scouting/webserver/requests/messages/request_all_notes_generated';
import {
Note,
RequestAllNotesResponse,
-} from '../../webserver/requests/messages/request_all_notes_response_generated';
-import {RequestAllDriverRankings} from '../../webserver/requests/messages/request_all_driver_rankings_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_all_notes_response_generated';
+import {RequestAllDriverRankings} from '@org_frc971/scouting/webserver/requests/messages/request_all_driver_rankings_generated';
import {
Ranking,
RequestAllDriverRankingsResponse,
-} from '../../webserver/requests/messages/request_all_driver_rankings_response_generated';
-import {Request2024DataScouting} from '../../webserver/requests/messages/request_2024_data_scouting_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_all_driver_rankings_response_generated';
+import {Request2024DataScouting} from '@org_frc971/scouting/webserver/requests/messages/request_2024_data_scouting_generated';
import {
PitImage,
RequestAllPitImagesResponse,
-} from '../../webserver/requests/messages/request_all_pit_images_response_generated';
-import {RequestAllPitImages} from '../../webserver/requests/messages/request_all_pit_images_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_all_pit_images_response_generated';
+import {RequestAllPitImages} from '@org_frc971/scouting/webserver/requests/messages/request_all_pit_images_generated';
import {
Stats2024,
Request2024DataScoutingResponse,
-} from '../../webserver/requests/messages/request_2024_data_scouting_response_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_2024_data_scouting_response_generated';
@Injectable({providedIn: 'root'})
export class ViewDataRequestor {
diff --git a/scouting/www/scan/BUILD b/scouting/www/scan/BUILD
index 88b2822..ee44b1f 100644
--- a/scouting/www/scan/BUILD
+++ b/scouting/www/scan/BUILD
@@ -9,10 +9,7 @@
"//scouting/www:app_common_css",
],
deps = [
- ":node_modules/@angular/forms",
- ":node_modules/@types/pako",
- ":node_modules/pako",
- "//scouting/webserver/requests/messages:error_response_ts_fbs",
- "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+ ":node_modules",
+ "//:node_modules/flatbuffers",
],
)
diff --git a/scouting/www/scan/package.json b/scouting/www/scan/package.json
index a5950c3..7fa3990 100644
--- a/scouting/www/scan/package.json
+++ b/scouting/www/scan/package.json
@@ -4,6 +4,7 @@
"dependencies": {
"pako": "2.1.0",
"@types/pako": "2.0.3",
- "@angular/forms": "v16-lts"
+ "@angular/forms": "v16-lts",
+ "@org_frc971/scouting/webserver/requests/messages": "workspace:*"
}
}
diff --git a/scouting/www/scan/scan.component.ts b/scouting/www/scan/scan.component.ts
index 98a7b61..4a1c9c8 100644
--- a/scouting/www/scan/scan.component.ts
+++ b/scouting/www/scan/scan.component.ts
@@ -1,5 +1,5 @@
import {Component, NgZone, OnInit, ViewChild, ElementRef} from '@angular/core';
-import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
+import {ErrorResponse} from '@org_frc971/scouting/webserver/requests/messages/error_response_generated';
import {Builder, ByteBuffer} from 'flatbuffers';
import * as pako from 'pako';
diff --git a/scouting/www/shift_schedule/BUILD b/scouting/www/shift_schedule/BUILD
index 3afb557..747ff98 100644
--- a/scouting/www/shift_schedule/BUILD
+++ b/scouting/www/shift_schedule/BUILD
@@ -9,10 +9,7 @@
"//scouting/www:app_common_css",
],
deps = [
- ":node_modules/@angular/forms",
- "//scouting/webserver/requests/messages:error_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_matches_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_matches_ts_fbs",
- "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+ ":node_modules",
+ "//:node_modules/flatbuffers",
],
)
diff --git a/scouting/www/shift_schedule/package.json b/scouting/www/shift_schedule/package.json
index f2d6d7e..a2ce384 100644
--- a/scouting/www/shift_schedule/package.json
+++ b/scouting/www/shift_schedule/package.json
@@ -2,6 +2,7 @@
"name": "@org_frc971/scouting/www/shift_schedule",
"private": true,
"dependencies": {
- "@angular/forms": "v16-lts"
+ "@angular/forms": "v16-lts",
+ "@org_frc971/scouting/webserver/requests/messages": "workspace:*"
}
}
diff --git a/scouting/www/shift_schedule/shift_schedule.component.ts b/scouting/www/shift_schedule/shift_schedule.component.ts
index de0b2e1..316830c 100644
--- a/scouting/www/shift_schedule/shift_schedule.component.ts
+++ b/scouting/www/shift_schedule/shift_schedule.component.ts
@@ -1,6 +1,6 @@
import {Component, OnInit} from '@angular/core';
import {Builder, ByteBuffer} from 'flatbuffers';
-import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
+import {ErrorResponse} from '@org_frc971/scouting/webserver/requests/messages/error_response_generated';
@Component({
selector: 'shift-schedule',
diff --git a/scouting/www/view/BUILD b/scouting/www/view/BUILD
index 738ea00..d967882 100644
--- a/scouting/www/view/BUILD
+++ b/scouting/www/view/BUILD
@@ -9,17 +9,7 @@
"//scouting/www:app_common_css",
],
deps = [
- ":node_modules/@angular/forms",
- "//scouting/webserver/requests/messages:delete_2024_data_scouting_response_ts_fbs",
- "//scouting/webserver/requests/messages:delete_2024_data_scouting_ts_fbs",
- "//scouting/webserver/requests/messages:error_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_2024_data_scouting_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_2024_data_scouting_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_driver_rankings_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_driver_rankings_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_notes_response_ts_fbs",
- "//scouting/webserver/requests/messages:request_all_notes_ts_fbs",
- "//scouting/www/rpc",
- "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+ ":node_modules",
+ "//:node_modules/flatbuffers",
],
)
diff --git a/scouting/www/view/package.json b/scouting/www/view/package.json
index d214f6f..efcbd8a 100644
--- a/scouting/www/view/package.json
+++ b/scouting/www/view/package.json
@@ -2,6 +2,8 @@
"name": "@org_frc971/scouting/www/view",
"private": true,
"dependencies": {
- "@angular/forms": "v16-lts"
+ "@angular/forms": "v16-lts",
+ "@org_frc971/scouting/webserver/requests/messages": "workspace:*",
+ "@org_frc971/scouting/www/rpc": "workspace:*"
}
}
diff --git a/scouting/www/view/view.component.ts b/scouting/www/view/view.component.ts
index ea9a61f..8aa3784 100644
--- a/scouting/www/view/view.component.ts
+++ b/scouting/www/view/view.component.ts
@@ -1,28 +1,31 @@
import {Component, OnInit} from '@angular/core';
import {Builder, ByteBuffer} from 'flatbuffers';
-import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
+import {ErrorResponse} from '@org_frc971/scouting/webserver/requests/messages/error_response_generated';
import {
Ranking,
RequestAllDriverRankingsResponse,
-} from '../../webserver/requests/messages/request_all_driver_rankings_response_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_all_driver_rankings_response_generated';
import {
Stats2024,
Request2024DataScoutingResponse,
-} from '../../webserver/requests/messages/request_2024_data_scouting_response_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_2024_data_scouting_response_generated';
import {
PitImage,
RequestAllPitImagesResponse,
-} from '../../webserver/requests/messages/request_all_pit_images_response_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_all_pit_images_response_generated';
import {
Note,
RequestAllNotesResponse,
-} from '../../webserver/requests/messages/request_all_notes_response_generated';
-import {Delete2024DataScouting} from '../../webserver/requests/messages/delete_2024_data_scouting_generated';
-import {Delete2024DataScoutingResponse} from '../../webserver/requests/messages/delete_2024_data_scouting_response_generated';
+} from '@org_frc971/scouting/webserver/requests/messages/request_all_notes_response_generated';
+import {Delete2024DataScouting} from '@org_frc971/scouting/webserver/requests/messages/delete_2024_data_scouting_generated';
+import {Delete2024DataScoutingResponse} from '@org_frc971/scouting/webserver/requests/messages/delete_2024_data_scouting_response_generated';
-import {ViewDataRequestor} from '../rpc';
+import {
+ MatchListRequestor,
+ ViewDataRequestor,
+} from '@org_frc971/scouting/www/rpc';
type Source = 'Notes' | 'Stats2024' | 'PitImages' | 'DriverRanking';
diff --git a/tools/build_rules/js.bzl b/tools/build_rules/js.bzl
index c2468f8..bb15c2c 100644
--- a/tools/build_rules/js.bzl
+++ b/tools/build_rules/js.bzl
@@ -1,4 +1,5 @@
load("@aspect_rules_js//js:providers.bzl", "JsInfo")
+load("@aspect_rules_js//npm:defs.bzl", "npm_package")
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
load("@aspect_bazel_lib//lib:copy_file.bzl", "copy_file")
@@ -251,6 +252,7 @@
srcs = native.glob(
["**/*.ts", "**/*.css", "**/*.html"],
exclude = test_spec_srcs + [
+ "**/*.jinja2.*",
"public-api.ts",
],
) + extra_srcs
@@ -276,13 +278,20 @@
srcs.append(":_public_api")
ng_project(
- name = name,
+ name = "_lib",
srcs = srcs + [":_index"],
deps = deps + PACKAGE_DEPS,
- visibility = visibility,
+ visibility = ["//visibility:private"],
**kwargs
)
+ npm_package(
+ name = name,
+ srcs = ["package.json", ":_lib"],
+ include_runfiles = False,
+ visibility = visibility,
+ )
+
def rollup_bundle(name, entry_point, node_modules = "//:node_modules", deps = [], visibility = None, **kwargs):
"""Calls the upstream rollup_bundle() and exposes a .min.js file.
diff --git a/tools/lint/prettier.sh b/tools/lint/prettier.sh
index 0198a71..ef4f5ca 100755
--- a/tools/lint/prettier.sh
+++ b/tools/lint/prettier.sh
@@ -28,6 +28,7 @@
# TODO(phil): Support more than just //scouting.
web_files=($(git ls-tree --name-only --full-tree -r @ \
| grep '^scouting/' \
+ | grep -v '\.jinja2\.' \
| (grep \
-e '\.ts$' \
-e '\.js$' \
diff --git a/tsconfig.json b/tsconfig.json
index bd23965..3999b5c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -17,5 +17,10 @@
},
"bazelOptions": {
"workspaceName": "971-Robot-Code"
+ },
+ "angularCompilerOptions": {
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
}
}
diff --git a/y2024/BUILD b/y2024/BUILD
index 7bbf64f..7568050 100644
--- a/y2024/BUILD
+++ b/y2024/BUILD
@@ -152,7 +152,7 @@
"//aos/network:message_bridge_client_fbs",
"//aos/network:message_bridge_server_fbs",
"//frc971/wpilib:pdp_values_fbs",
- #y2019 stuff shouldn't be here (e.g. target selector)
+ # y2019 stuff shouldn't be here (e.g. target selector)
"//y2024/constants:constants_fbs",
"//aos/network:timestamp_fbs",
"//y2024/control_loops/superstructure:superstructure_goal_fbs",
@@ -277,6 +277,7 @@
"//third_party:phoenix6",
"//third_party:wpilib",
"//y2024/constants:constants_fbs",
+ "//y2024/control_loops/superstructure:led_indicator_lib",
"//y2024/control_loops/superstructure:superstructure_can_position_fbs",
"//y2024/control_loops/superstructure:superstructure_output_fbs",
"//y2024/control_loops/superstructure:superstructure_position_fbs",
diff --git a/y2024/constants/7971.json b/y2024/constants/7971.json
index 3beaae0..2fe58cf 100644
--- a/y2024/constants/7971.json
+++ b/y2024/constants/7971.json
@@ -71,7 +71,9 @@
) %}
"zeroing_constants": {{ extend_zero | tojson(indent=2)}},
"potentiometer_offset": 0.0
- }
+ },
+ "disable_extend": false,
+ "disable_climber": false
},
{% include 'y2024/constants/common.json' %}
}
diff --git a/y2024/constants/971.json b/y2024/constants/971.json
index 974fb60..c146417 100644
--- a/y2024/constants/971.json
+++ b/y2024/constants/971.json
@@ -23,7 +23,7 @@
"robot": {
{% set _ = intake_pivot_zero.update(
{
- "measured_absolute_position" : 3.49222521810232
+ "measured_absolute_position" : 3.229
}
) %}
"intake_constants": {{ intake_pivot_zero | tojson(indent=2)}},
@@ -43,12 +43,12 @@
}
) %}
"zeroing_constants": {{ catapult_zero | tojson(indent=2)}},
- "potentiometer_offset": {{ 9.41595277209342 }}
+ "potentiometer_offset": {{ 9.41595277209342 - 1.59041961316453 + 0.478015209219659 }}
},
"altitude_constants": {
{% set _ = altitude_zero.update(
{
- "measured_absolute_position" : 0.1877
+ "measured_absolute_position" : 0.2135
}
) %}
"zeroing_constants": {{ altitude_zero | tojson(indent=2)}},
@@ -57,11 +57,11 @@
"turret_constants": {
{% set _ = turret_zero.update(
{
- "measured_absolute_position" : 0.961143535321169
+ "measured_absolute_position" : 0.2077
}
) %}
"zeroing_constants": {{ turret_zero | tojson(indent=2)}},
- "potentiometer_offset": {{ -6.47164779835404 - 0.0711209027239817 + 1.0576004531907 }}
+ "potentiometer_offset": {{ -6.47164779835404 - 0.0711209027239817 + 1.0576004531907 - 0.343 }}
},
"extend_constants": {
{% set _ = extend_zero.update(
@@ -71,7 +71,9 @@
) %}
"zeroing_constants": {{ extend_zero | tojson(indent=2)}},
"potentiometer_offset": {{ -0.2574404033256 + 0.0170793439542 - 0.177097393974999 + 0.3473623911879 - 0.1577}}
- }
+ },
+ "disable_extend": false,
+ "disable_climber": true
},
{% include 'y2024/constants/common.json' %}
}
diff --git a/y2024/constants/9971.json b/y2024/constants/9971.json
index ec59033..23cad58 100644
--- a/y2024/constants/9971.json
+++ b/y2024/constants/9971.json
@@ -62,7 +62,9 @@
) %}
"zeroing_constants": {{ extend_zero | tojson(indent=2)}},
"potentiometer_offset": 0.0
- }
+ },
+ "disable_extend": false,
+ "disable_climber": false
},
{% include 'y2024/constants/common.json' %}
}
diff --git a/y2024/constants/common.json b/y2024/constants/common.json
index 65fe20e..52fdb74 100644
--- a/y2024/constants/common.json
+++ b/y2024/constants/common.json
@@ -7,43 +7,50 @@
"distance_from_goal": 0.7,
"shot_params": {
"shot_altitude_angle": 0.85,
- "shot_speed_over_ground": 8.0
+ "shot_speed_over_ground": 16.0
}
},
{
"distance_from_goal": 1.24,
"shot_params": {
"shot_altitude_angle": 0.85,
- "shot_speed_over_ground": 8.0
+ "shot_speed_over_ground": 16.0
}
},
{
"distance_from_goal": 1.904,
"shot_params": {
"shot_altitude_angle": 0.73,
- "shot_speed_over_ground": 8.0
+ "shot_speed_over_ground": 16.0
}
},
// 2.2 -> high.
{
"distance_from_goal": 2.744,
"shot_params": {
- "shot_altitude_angle": 0.62,
- "shot_speed_over_ground": 8.0
+ "shot_altitude_angle": 0.61,
+ "shot_speed_over_ground": 16.0
}
},
{
"distance_from_goal": 3.274,
"shot_params": {
- "shot_altitude_angle": 0.58,
- "shot_speed_over_ground": 8.0
+ "shot_altitude_angle": 0.55,
+ "shot_speed_over_ground": 16.0
}
},
{
"distance_from_goal": 4.00,
"shot_params": {
- "shot_altitude_angle": 0.54,
- "shot_speed_over_ground": 8.0
+ "shot_altitude_angle": 0.515,
+ "shot_speed_over_ground": 16.0
+ }
+ },
+ {
+ "distance_from_goal": 4.68,
+ "shot_params": {
+ "shot_altitude_angle": 0.51,
+ "shot_speed_over_ground": 16.0
}
}
],
@@ -82,7 +89,7 @@
"intake_pivot_stator_current_limit": 100,
"intake_roller_supply_current_limit": 20,
"intake_roller_stator_current_limit": 100,
- "transfer_roller_supply_current_limit": 20,
+ "transfer_roller_supply_current_limit": 40,
"transfer_roller_stator_current_limit": 50,
"drivetrain_supply_current_limit": 50,
"drivetrain_stator_current_limit": 200,
@@ -104,7 +111,7 @@
"retention_roller_supply_current_limit": 10
},
"transfer_roller_voltages": {
- "transfer_in": 9.0,
+ "transfer_in": 11.0,
"transfer_out": -4.0,
"extend_moving": 4.0
},
@@ -248,7 +255,7 @@
},
// TODO(Filip): Update the speaker and amp shooter setpoints
"shooter_speaker_set_point": {
- "turret_position": 0.22,
+ "turret_position": 0.13,
"altitude_position": 0.85,
"shot_velocity": 0.0
},
@@ -269,6 +276,5 @@
"ignore_targets": {
"red": [1, 2, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16],
"blue": [1, 2, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16]
- },
- "disable_extend": false
+ }
}
diff --git a/y2024/constants/constants.fbs b/y2024/constants/constants.fbs
index 1554f4c..99d49a4 100644
--- a/y2024/constants/constants.fbs
+++ b/y2024/constants/constants.fbs
@@ -132,6 +132,8 @@
altitude_constants:PotAndAbsEncoderConstants (id: 3);
turret_constants:PotAndAbsEncoderConstants (id: 4);
extend_constants:PotAndAbsEncoderConstants (id: 5);
+ disable_extend:bool (id: 6);
+ disable_climber:bool (id: 7);
}
table ShooterSetPoint {
@@ -197,7 +199,6 @@
altitude_avoid_extend_collision_position: double (id: 28);
autonomous_mode:AutonomousMode (id: 26);
ignore_targets:IgnoreTargets (id: 27);
- disable_extend:bool (id: 29);
}
table Constants {
diff --git a/y2024/constants/test_data/test_team.json b/y2024/constants/test_data/test_team.json
index b717224..37d9de1 100644
--- a/y2024/constants/test_data/test_team.json
+++ b/y2024/constants/test_data/test_team.json
@@ -71,7 +71,9 @@
) %}
"zeroing_constants": {{ extend_zero | tojson(indent=2)}},
"potentiometer_offset": 0.0
- }
+ },
+ "disable_extend": false,
+ "disable_climber": false
},
{% include 'y2024/constants/common.json' %}
}
diff --git a/y2024/control_loops/drivetrain/drivetrain_config.jinja2.json b/y2024/control_loops/drivetrain/drivetrain_config.jinja2.json
index 194b123..1127d6a 100644
--- a/y2024/control_loops/drivetrain/drivetrain_config.jinja2.json
+++ b/y2024/control_loops/drivetrain/drivetrain_config.jinja2.json
@@ -10,7 +10,7 @@
"quickturn_wheel_multiplier": 1.2,
"wheel_multiplier": 1.2,
"pistol_grip_shift_enables_line_follow": false,
- "imu_transform":{
+ "imu_transform": {
"rows": 3,
"cols": 3,
"data": [1, 0, 0, 0, 1, 0, 0, 0, 1]
@@ -22,5 +22,21 @@
},
"top_button_use": "kNone",
"second_button_use": "kTurn1",
- "bottom_button_use": "kControlLoopDriving"
+ "bottom_button_use": "kControlLoopDriving",
+ "spline_follower_config": {
+ "q": {
+ "rows": 5,
+ "cols": 5,
+ "data": [3600, 0, 0, 0, 0,
+ 0, 3600, 0, 0, 0,
+ 0, 0, 1600, 0, 0,
+ 0, 0, 0, 16, 0,
+ 0, 0, 0, 0, 16]
+ },
+ "r": {
+ "rows": 2,
+ "cols": 2,
+ "data": [5, 0, 0, 5]
+ }
+ }
}
diff --git a/y2024/control_loops/python/catapult.py b/y2024/control_loops/python/catapult.py
index 406f56e..6f2e9a5 100644
--- a/y2024/control_loops/python/catapult.py
+++ b/y2024/control_loops/python/catapult.py
@@ -25,14 +25,14 @@
return motor
-kCatapultWithGamePiece = angular_system.AngularSystemParams(
+kCatapultWithoutGamePiece = angular_system.AngularSystemParams(
name='Catapult',
# Add the battery series resistance to make it better match.
motor=AddResistance(control_loop.NMotor(control_loop.KrakenFOC(), 2),
0.00),
G=(14.0 / 60.0) * (12.0 / 24.0),
- # 208.7328 in^2 lb
- J=0.065 + 0.04,
+ # 135.2928 in^2 lb
+ J=0.06,
q_pos=0.80,
q_vel=15.0,
kalman_q_pos=0.12,
@@ -43,14 +43,32 @@
delayed_u=1,
dt=0.005)
-kCatapultWithoutGamePiece = angular_system.AngularSystemParams(
- name='Catapult',
+kCatapultWithGamePiece = angular_system.AngularSystemParams(
+ name='CatapultWithPiece',
+ # Add the battery series resistance to make it better match.
+ motor=AddResistance(control_loop.NMotor(control_loop.KrakenFOC(), 2),
+ 0.00),
+ G=(14.0 / 60.0) * (12.0 / 24.0),
+ # 208.7328 in^2 lb
+ J=0.065 + 0.06,
+ q_pos=0.80,
+ q_vel=15.0,
+ kalman_q_pos=0.12,
+ kalman_q_vel=2.0,
+ kalman_q_voltage=0.7,
+ kalman_r_position=0.05,
+ radius=12 * 0.0254,
+ delayed_u=1,
+ dt=0.005)
+
+kCatapultWithoutGamePieceDecel = angular_system.AngularSystemParams(
+ name='CatapultWithoutPieceDecel',
# Add the battery series resistance to make it better match.
motor=AddResistance(control_loop.NMotor(control_loop.KrakenFOC(), 2),
0.00),
G=(14.0 / 60.0) * (12.0 / 24.0),
# 135.2928 in^2 lb
- J=0.06,
+ J=0.04,
q_pos=0.80,
q_vel=15.0,
kalman_q_pos=0.12,
@@ -76,9 +94,10 @@
)
else:
namespaces = ['y2024', 'control_loops', 'superstructure', 'catapult']
- angular_system.WriteAngularSystem(
- [kCatapultWithoutGamePiece, kCatapultWithGamePiece], argv[1:4],
- argv[4:7], namespaces)
+ angular_system.WriteAngularSystem([
+ kCatapultWithoutGamePiece, kCatapultWithGamePiece,
+ kCatapultWithoutGamePieceDecel
+ ], argv[1:4], argv[4:7], namespaces)
if __name__ == '__main__':
diff --git a/y2024/control_loops/superstructure/BUILD b/y2024/control_loops/superstructure/BUILD
index 6150caa..946579b 100644
--- a/y2024/control_loops/superstructure/BUILD
+++ b/y2024/control_loops/superstructure/BUILD
@@ -78,8 +78,7 @@
hdrs = [
"superstructure.h",
],
- data = [
- ],
+ data = [],
deps = [
":collision_avoidance_lib",
":shooter",
@@ -242,3 +241,31 @@
"//aos/network/www:proxy",
],
)
+
+cc_library(
+ name = "led_indicator_lib",
+ srcs = ["led_indicator.cc"],
+ hdrs = ["led_indicator.h"],
+ data = [
+ "@ctre_phoenix_api_cpp_athena//:shared_libraries",
+ "@ctre_phoenix_cci_athena//:shared_libraries",
+ ],
+ target_compatible_with = ["//tools/platforms/hardware:roborio"],
+ deps = [
+ ":superstructure_output_fbs",
+ ":superstructure_position_fbs",
+ ":superstructure_status_fbs",
+ "//aos/events:event_loop",
+ "//aos/network:message_bridge_client_fbs",
+ "//aos/network:message_bridge_server_fbs",
+ "//frc971/control_loops:control_loop",
+ "//frc971/control_loops:control_loops_fbs",
+ "//frc971/control_loops:profiled_subsystem_fbs",
+ "//frc971/control_loops/drivetrain:drivetrain_output_fbs",
+ "//frc971/control_loops/drivetrain:drivetrain_status_fbs",
+ "//frc971/control_loops/drivetrain/localization:localizer_output_fbs",
+ "//frc971/queues:gyro_fbs",
+ "//third_party:phoenix",
+ "//third_party:wpilib",
+ ],
+)
diff --git a/y2024/control_loops/superstructure/aiming.cc b/y2024/control_loops/superstructure/aiming.cc
index a21c09d..bf68527 100644
--- a/y2024/control_loops/superstructure/aiming.cc
+++ b/y2024/control_loops/superstructure/aiming.cc
@@ -8,9 +8,6 @@
using frc971::control_loops::aiming::ShotMode;
using y2024::control_loops::superstructure::Aimer;
-// When the turret is at 0 the note will be leaving the robot at PI.
-static constexpr double kTurretZeroOffset = M_PI - 0.22;
-
Aimer::Aimer(aos::EventLoop *event_loop,
const y2024::Constants *robot_constants)
: event_loop_(event_loop),
@@ -76,7 +73,7 @@
robot_constants_->common()->turret()->range()),
interpolation_table_.Get(current_goal_.target_distance)
.shot_speed_over_ground,
- /*wrap_mode=*/0.15, kTurretZeroOffset},
+ /*wrap_mode=*/0.15, M_PI - kTurretZeroOffset},
RobotState{
robot_pose, {xdot, ydot}, linear_angular(1), current_goal_.position});
diff --git a/y2024/control_loops/superstructure/aiming.h b/y2024/control_loops/superstructure/aiming.h
index 9bec187..97e319d 100644
--- a/y2024/control_loops/superstructure/aiming.h
+++ b/y2024/control_loops/superstructure/aiming.h
@@ -17,6 +17,9 @@
class Aimer {
public:
+ // When the turret is at 0 the note will be leaving the robot at PI.
+ static constexpr double kTurretZeroOffset = 0.13;
+
Aimer(aos::EventLoop *event_loop, const Constants *robot_constants);
void Update(
diff --git a/y2024/control_loops/superstructure/led_indicator.cc b/y2024/control_loops/superstructure/led_indicator.cc
new file mode 100644
index 0000000..3927548
--- /dev/null
+++ b/y2024/control_loops/superstructure/led_indicator.cc
@@ -0,0 +1,165 @@
+#include "y2024/control_loops/superstructure/led_indicator.h"
+
+namespace led = ctre::phoenix::led;
+namespace chrono = std::chrono;
+
+namespace y2024::control_loops::superstructure {
+
+LedIndicator::LedIndicator(aos::EventLoop *event_loop)
+ : event_loop_(event_loop),
+ drivetrain_output_fetcher_(
+ event_loop_->MakeFetcher<frc971::control_loops::drivetrain::Output>(
+ "/drivetrain")),
+ superstructure_status_fetcher_(
+ event_loop_->MakeFetcher<Status>("/superstructure")),
+ server_statistics_fetcher_(
+ event_loop_->MakeFetcher<aos::message_bridge::ServerStatistics>(
+ "/roborio/aos")),
+ client_statistics_fetcher_(
+ event_loop_->MakeFetcher<aos::message_bridge::ClientStatistics>(
+ "/roborio/aos")),
+ localizer_output_fetcher_(
+ event_loop_->MakeFetcher<frc971::controls::LocalizerOutput>(
+ "/localizer")),
+ gyro_reading_fetcher_(
+ event_loop_->MakeFetcher<frc971::sensors::GyroReading>(
+ "/drivetrain")),
+ drivetrain_status_fetcher_(
+ event_loop_->MakeFetcher<frc971::control_loops::drivetrain::Status>(
+ "/drivetrain")) {
+ led::CANdleConfiguration config;
+ config.statusLedOffWhenActive = true;
+ config.disableWhenLOS = false;
+ config.brightnessScalar = 1.0;
+ candle_.ConfigAllSettings(config, 0);
+
+ event_loop_->AddPhasedLoop([this](int) { DecideColor(); },
+ chrono::milliseconds(20));
+ event_loop_->OnRun(
+ [this]() { startup_time_ = event_loop_->monotonic_now(); });
+}
+
+// This method will be called once per scheduler run
+void LedIndicator::DisplayLed(uint8_t r, uint8_t g, uint8_t b) {
+ candle_.SetLEDs(static_cast<int>(r), static_cast<int>(g),
+ static_cast<int>(b));
+}
+
+bool DisconnectedIMUPiServer(
+ const aos::message_bridge::ServerStatistics &server_statistics) {
+ for (const auto *node_status : *server_statistics.connections()) {
+ if (node_status->state() == aos::message_bridge::State::DISCONNECTED) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DisconnectedIMUPiClient(
+ const aos::message_bridge::ClientStatistics &client_statistics) {
+ for (const auto *node_status : *client_statistics.connections()) {
+ if (node_status->state() == aos::message_bridge::State::DISCONNECTED) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OrinsDisconnected(
+ const frc971::controls::LocalizerOutput &localizer_output) {
+ if (!localizer_output.all_pis_connected()) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void LedIndicator::DecideColor() {
+ superstructure_status_fetcher_.Fetch();
+ server_statistics_fetcher_.Fetch();
+ drivetrain_output_fetcher_.Fetch();
+ drivetrain_status_fetcher_.Fetch();
+ client_statistics_fetcher_.Fetch();
+ gyro_reading_fetcher_.Fetch();
+ localizer_output_fetcher_.Fetch();
+
+ if (localizer_output_fetcher_.get()) {
+ if (localizer_output_fetcher_->image_accepted_count() !=
+ last_accepted_count_) {
+ last_accepted_count_ = localizer_output_fetcher_->image_accepted_count();
+ last_accepted_time_ = event_loop_->monotonic_now();
+ }
+ }
+
+ // Estopped: Red
+ if (superstructure_status_fetcher_.get() &&
+ superstructure_status_fetcher_->estopped()) {
+ DisplayLed(255, 0, 0);
+ return;
+ }
+
+ // If the imu gyro readings are not being sent/updated recently. Only do this
+ // after we've been on for a bit.
+ if (event_loop_->context().monotonic_event_time >
+ startup_time_ + chrono::seconds(5) &&
+ (!gyro_reading_fetcher_.get() ||
+ gyro_reading_fetcher_.context().monotonic_event_time +
+ frc971::controls::kLoopFrequency * 10 <
+ event_loop_->monotonic_now() ||
+ !gyro_reading_fetcher_->has_velocity())) {
+ // Flash red/white
+ if (flash_counter_.Flash()) {
+ DisplayLed(255, 0, 0);
+ } else {
+ DisplayLed(255, 255, 255);
+ }
+ return;
+ }
+
+ if (localizer_output_fetcher_.get() == nullptr ||
+ server_statistics_fetcher_.get() == nullptr ||
+ client_statistics_fetcher_.get() == nullptr ||
+ OrinsDisconnected(*localizer_output_fetcher_) ||
+ DisconnectedIMUPiServer(*server_statistics_fetcher_) ||
+ DisconnectedIMUPiClient(*client_statistics_fetcher_)) {
+ // Flash red/green
+ if (flash_counter_.Flash()) {
+ DisplayLed(255, 0, 0);
+ } else {
+ DisplayLed(0, 255, 0);
+ }
+
+ return;
+ }
+
+ // Not zeroed: Yellow
+ if ((superstructure_status_fetcher_.get() &&
+ !superstructure_status_fetcher_->zeroed()) ||
+ (drivetrain_status_fetcher_.get() &&
+ !drivetrain_status_fetcher_->filters_ready())) {
+ DisplayLed(255, 255, 0);
+ return;
+ }
+
+ // Want to know when we have a note.
+ //
+ if (superstructure_status_fetcher_.get()) {
+ // Check if there is a target that is in sight
+ if (event_loop_->monotonic_now() <
+ last_accepted_time_ + chrono::milliseconds(100)) {
+ if (superstructure_status_fetcher_.get() != nullptr &&
+ superstructure_status_fetcher_->shooter()->auto_aiming()) {
+ DisplayLed(0, 0, 255);
+ return;
+ } else {
+ DisplayLed(0, 255, 0);
+ return;
+ }
+ }
+ }
+ DisplayLed(0, 0, 0);
+}
+
+} // namespace y2024::control_loops::superstructure
diff --git a/y2024/control_loops/superstructure/led_indicator.h b/y2024/control_loops/superstructure/led_indicator.h
new file mode 100644
index 0000000..a7d891a
--- /dev/null
+++ b/y2024/control_loops/superstructure/led_indicator.h
@@ -0,0 +1,96 @@
+#ifndef Y2024_CONTROL_LOOPS_SUPERSTRUCTURE_LED_INDICATOR_H_
+#define Y2024_CONTROL_LOOPS_SUPERSTRUCTURE_LED_INDICATOR_H_
+
+#include "ctre/phoenix/led/CANdle.h"
+
+#include "aos/events/event_loop.h"
+#include "aos/network/message_bridge_client_generated.h"
+#include "aos/network/message_bridge_server_generated.h"
+#include "frc971/control_loops/control_loop.h"
+#include "frc971/control_loops/control_loops_generated.h"
+#include "frc971/control_loops/drivetrain/drivetrain_output_generated.h"
+#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
+#include "frc971/control_loops/drivetrain/localization/localizer_output_generated.h"
+#include "frc971/control_loops/profiled_subsystem_generated.h"
+#include "frc971/queues/gyro_generated.h"
+#include "y2024/control_loops/superstructure/superstructure_output_generated.h"
+#include "y2024/control_loops/superstructure/superstructure_position_generated.h"
+#include "y2024/control_loops/superstructure/superstructure_status_generated.h"
+
+namespace y2024::control_loops::superstructure {
+
+class FlashCounter {
+ public:
+ FlashCounter(size_t flash_iterations) : flash_iterations_(flash_iterations) {}
+
+ bool Flash() {
+ if (counter_ % flash_iterations_ == 0) {
+ flash_ = !flash_;
+ }
+ counter_++;
+ return flash_;
+ }
+
+ private:
+ size_t flash_iterations_;
+ size_t counter_ = 0;
+ bool flash_ = false;
+};
+
+class LedIndicator {
+ public:
+ LedIndicator(aos::EventLoop *event_loop);
+
+ // Colors in order of priority:
+ //
+ // Red: estopped
+ // Flash red/white: imu disconnected
+ // Flash red/green: any orin disconnected
+ // Pink: not zeroed
+ //
+ // State machine:
+ // INTAKING: Flash Orange/Off
+ // LOADED: Yellow
+ // MOVING: Flash Yellow/Off
+ // LOADING_CATAPULT: Flash Purple/Off
+ // READY: Green
+ // FIRING: Purple
+ //
+ // HAS A TARGET: Blue
+ // VISION: Flash Blue/Off
+
+ void DecideColor();
+
+ private:
+ static constexpr size_t kFlashIterations = 5;
+
+ void DisplayLed(uint8_t r, uint8_t g, uint8_t b);
+
+ ctre::phoenix::led::CANdle candle_{8, "rio"};
+
+ aos::EventLoop *event_loop_;
+ aos::Fetcher<frc971::control_loops::drivetrain::Output>
+ drivetrain_output_fetcher_;
+ aos::Fetcher<Status> superstructure_status_fetcher_;
+ aos::Fetcher<aos::message_bridge::ServerStatistics>
+ server_statistics_fetcher_;
+ aos::Fetcher<aos::message_bridge::ClientStatistics>
+ client_statistics_fetcher_;
+ aos::Fetcher<frc971::controls::LocalizerOutput> localizer_output_fetcher_;
+ aos::Fetcher<frc971::sensors::GyroReading> gyro_reading_fetcher_;
+ aos::Fetcher<frc971::control_loops::drivetrain::Status>
+ drivetrain_status_fetcher_;
+
+ size_t last_accepted_count_ = 0;
+ aos::monotonic_clock::time_point last_accepted_time_ =
+ aos::monotonic_clock::min_time;
+
+ aos::monotonic_clock::time_point startup_time_ =
+ aos::monotonic_clock::min_time;
+
+ FlashCounter flash_counter_{kFlashIterations};
+};
+
+} // namespace y2024::control_loops::superstructure
+
+#endif // Y2024_CONTROL_LOOPS_SUPERSTRUCTURE_LED_INDICATOR_H_
diff --git a/y2024/control_loops/superstructure/shooter.cc b/y2024/control_loops/superstructure/shooter.cc
index 79da980..7002657 100644
--- a/y2024/control_loops/superstructure/shooter.cc
+++ b/y2024/control_loops/superstructure/shooter.cc
@@ -186,10 +186,10 @@
{.intake_pivot_position = intake_pivot_position,
.turret_position = turret_.estimated_position(),
.extend_position =
- ((!robot_constants_->common()->disable_extend()) ? extend_position
- : 0.0)},
+ ((!robot_constants_->robot()->disable_extend()) ? extend_position
+ : 0.0)},
turret_goal->unsafe_goal(),
- ((!robot_constants_->common()->disable_extend()) ? extend_goal : 0.0));
+ ((!robot_constants_->robot()->disable_extend()) ? extend_goal : 0.0));
if (!CatapultRetracted()) {
altitude_.set_min_position(
@@ -248,7 +248,7 @@
//
// accel = v^2 / (2 * x)
catapult_.mutable_profile()->set_maximum_velocity(
- catapult::kFreeSpeed * catapult::kOutputRatio * 4.0 / 12.0);
+ catapult::kFreeSpeed * catapult::kOutputRatio * 5.5 / 12.0);
if (disabled) {
state_ = CatapultState::RETRACTING;
@@ -272,6 +272,7 @@
if (subsystems_in_range && shooter_goal != nullptr && fire &&
catapult_close && piece_loaded) {
state_ = CatapultState::FIRING;
+ max_catapult_goal_velocity_ = catapult_.goal(1);
} else {
catapult_.set_controller_index(0);
catapult_.mutable_profile()->set_maximum_acceleration(
@@ -294,10 +295,17 @@
robot_constants_->common()
->current_limits()
->shooting_retention_roller_stator_current_limit();
- catapult_.set_controller_index(1);
+ max_catapult_goal_velocity_ =
+ std::max(max_catapult_goal_velocity_, catapult_.goal(1));
+
+ if (max_catapult_goal_velocity_ > catapult_.goal(1) + 0.1) {
+ catapult_.set_controller_index(2);
+ } else {
+ catapult_.set_controller_index(1);
+ }
catapult_.mutable_profile()->set_maximum_acceleration(400.0);
- catapult_.mutable_profile()->set_maximum_deceleration(500.0);
- catapult_.set_unprofiled_goal(2.0, 0.0);
+ catapult_.mutable_profile()->set_maximum_deceleration(1000.0);
+ catapult_.set_unprofiled_goal(2.45, 0.0);
if (CatapultClose()) {
state_ = CatapultState::RETRACTING;
++shot_count_;
diff --git a/y2024/control_loops/superstructure/shooter.h b/y2024/control_loops/superstructure/shooter.h
index 5363288..e873629 100644
--- a/y2024/control_loops/superstructure/shooter.h
+++ b/y2024/control_loops/superstructure/shooter.h
@@ -138,6 +138,10 @@
CatapultSubsystem catapult_;
+ // Max speed we have seen during this shot. This is used to figure out when
+ // we start decelerating and switch controllers.
+ double max_catapult_goal_velocity_ = 0.0;
+
PotAndAbsoluteEncoderSubsystem turret_;
PotAndAbsoluteEncoderSubsystem altitude_;
diff --git a/y2024/control_loops/superstructure/superstructure.cc b/y2024/control_loops/superstructure/superstructure.cc
index af3f9de..9edc626 100644
--- a/y2024/control_loops/superstructure/superstructure.cc
+++ b/y2024/control_loops/superstructure/superstructure.cc
@@ -167,7 +167,7 @@
// considered ready to accept note from the transfer rollers. If disable
// extend is triggered, this will autoatically be false.
const bool extend_at_retracted =
- (!robot_constants_->common()->disable_extend() &&
+ (!robot_constants_->robot()->disable_extend() &&
PositionNear(extend_.position(), extend_set_points->retracted(),
kExtendThreshold));
@@ -549,7 +549,7 @@
const bool collided = collision_avoidance_.IsCollided({
.intake_pivot_position = intake_pivot_.estimated_position(),
.turret_position = shooter_.turret().estimated_position(),
- .extend_position = ((!robot_constants_->common()->disable_extend())
+ .extend_position = ((!robot_constants_->robot()->disable_extend())
? extend_.estimated_position()
: 0.0),
});
@@ -659,10 +659,15 @@
status->fbb());
// Zero out extend voltage if "disable_extend" is true
- if (robot_constants_->common()->disable_extend()) {
+ if (robot_constants_->robot()->disable_extend()) {
output_struct.extend_voltage = 0.0;
}
+ // Zero out climber voltage if "disable_climber" is true
+ if (robot_constants_->robot()->disable_climber()) {
+ output_struct.climber_voltage = 0.0;
+ }
+
if (output) {
output->CheckOk(output->Send(Output::Pack(*output->fbb(), &output_struct)));
}
diff --git a/y2024/control_loops/superstructure/superstructure_lib_test.cc b/y2024/control_loops/superstructure/superstructure_lib_test.cc
index e3368e9..9e8b3a5 100644
--- a/y2024/control_loops/superstructure/superstructure_lib_test.cc
+++ b/y2024/control_loops/superstructure/superstructure_lib_test.cc
@@ -1450,11 +1450,11 @@
EXPECT_NEAR(
-M_PI_2,
superstructure_status_fetcher_->shooter()->aimer()->turret_position() -
- M_PI - 0.22,
+ M_PI - Aimer::kTurretZeroOffset,
5e-4);
EXPECT_NEAR(-M_PI_2,
superstructure_status_fetcher_->shooter()->turret()->position() -
- M_PI - 0.22,
+ M_PI - Aimer::kTurretZeroOffset,
5e-4);
EXPECT_EQ(
@@ -1496,11 +1496,11 @@
EXPECT_NEAR(
M_PI_2,
superstructure_status_fetcher_->shooter()->aimer()->turret_position() +
- M_PI - 0.22,
+ M_PI - Aimer::kTurretZeroOffset,
5e-4);
EXPECT_NEAR(M_PI_2,
superstructure_status_fetcher_->shooter()->turret()->position() +
- M_PI - 0.22,
+ M_PI - Aimer::kTurretZeroOffset,
5e-4);
EXPECT_EQ(
kDistanceFromSpeaker,
diff --git a/y2024/joystick_reader.cc b/y2024/joystick_reader.cc
index 4a8d414..293e57e 100644
--- a/y2024/joystick_reader.cc
+++ b/y2024/joystick_reader.cc
@@ -51,6 +51,7 @@
const ButtonLocation kCatapultLoad(2, 1);
const ButtonLocation kAmp(2, 4);
const ButtonLocation kFire(2, 8);
+const ButtonLocation kDriverFire(1, 1);
const ButtonLocation kTrap(2, 6);
const ButtonLocation kAutoAim(1, 8);
const ButtonLocation kAimSpeaker(2, 11);
@@ -159,7 +160,8 @@
->shooter_speaker_set_point()
->turret_position());
}
- superstructure_goal_builder->set_fire(data.IsPressed(kFire));
+ superstructure_goal_builder->set_fire(data.IsPressed(kFire) ||
+ data.IsPressed(kDriverFire));
if (data.IsPressed(kRetractClimber)) {
superstructure_goal_builder->set_climber_goal(
diff --git a/y2024/localizer/localizer.cc b/y2024/localizer/localizer.cc
index b8e982e..daef22c 100644
--- a/y2024/localizer/localizer.cc
+++ b/y2024/localizer/localizer.cc
@@ -11,7 +11,7 @@
DEFINE_double(max_pose_error, 1e-5,
"Throw out target poses with a higher pose error than this");
-DEFINE_double(max_distortion, 0.1, "");
+DEFINE_double(max_distortion, 1000.0, "");
DEFINE_double(
max_pose_error_ratio, 0.4,
"Throw out target poses with a higher pose error ratio than this");
diff --git a/y2024/vision/BUILD b/y2024/vision/BUILD
index 4904554..bd4fe76 100644
--- a/y2024/vision/BUILD
+++ b/y2024/vision/BUILD
@@ -167,3 +167,20 @@
"@org_tuxfamily_eigen//:eigen",
],
)
+
+cc_binary(
+ name = "image_replay",
+ srcs = [
+ "image_replay.cc",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//y2024:__subpackages__"],
+ deps = [
+ "//aos:configuration",
+ "//aos:init",
+ "//aos/events:simulated_event_loop",
+ "//aos/events/logging:log_reader",
+ "//frc971/vision:vision_fbs",
+ "//third_party:opencv",
+ ],
+)
diff --git a/y2024/vision/image_replay.cc b/y2024/vision/image_replay.cc
new file mode 100644
index 0000000..f03bcf1
--- /dev/null
+++ b/y2024/vision/image_replay.cc
@@ -0,0 +1,47 @@
+#include "gflags/gflags.h"
+#include "opencv2/imgproc.hpp"
+#include <opencv2/highgui.hpp>
+
+#include "aos/events/logging/log_reader.h"
+#include "aos/events/logging/log_writer.h"
+#include "aos/events/simulated_event_loop.h"
+#include "aos/init.h"
+#include "aos/json_to_flatbuffer.h"
+#include "aos/logging/log_message_generated.h"
+#include "frc971/vision/vision_generated.h"
+
+DEFINE_string(node, "orin1", "The node to view the log from");
+DEFINE_string(channel, "/camera0", "The channel to view the log from");
+
+int main(int argc, char **argv) {
+ aos::InitGoogle(&argc, &argv);
+
+ // open logfiles
+ aos::logger::LogReader reader(
+ aos::logger::SortParts(aos::logger::FindLogs(argc, argv)));
+
+ aos::SimulatedEventLoopFactory factory(reader.configuration());
+ reader.Register(&factory);
+
+ aos::NodeEventLoopFactory *node = factory.GetNodeEventLoopFactory(FLAGS_node);
+
+ std::unique_ptr<aos::EventLoop> image_loop = node->MakeEventLoop("image");
+ image_loop->MakeWatcher(
+ "/" + FLAGS_node + "/" + FLAGS_channel,
+ [](const frc971::vision::CameraImage &msg) {
+ cv::Mat color_image(cv::Size(msg.cols(), msg.rows()), CV_8UC2,
+ (void *)msg.data()->data());
+
+ cv::Mat bgr(color_image.size(), CV_8UC3);
+ cv::cvtColor(color_image, bgr, cv::COLOR_YUV2BGR_YUYV);
+
+ cv::imshow("Replay", bgr);
+ cv::waitKey(1);
+ });
+
+ factory.Run();
+
+ reader.Deregister();
+
+ return 0;
+}
diff --git a/y2024/vision/target_mapping.cc b/y2024/vision/target_mapping.cc
index d2fb26e..fac7e81 100644
--- a/y2024/vision/target_mapping.cc
+++ b/y2024/vision/target_mapping.cc
@@ -32,7 +32,7 @@
"Write the target constraints to this path");
DEFINE_string(dump_stats_to, "/tmp/mapping_stats.txt",
"Write the mapping stats to this path");
-DEFINE_string(field_name, "charged_up",
+DEFINE_string(field_name, "crescendo",
"Field name, for the output json filename and flatbuffer field");
DEFINE_string(json_path, "y2024/vision/maps/target_map.json",
"Specify path for json with initial pose guesses.");
@@ -52,6 +52,8 @@
DEFINE_uint64(skip_to, 1,
"Start at combined image of this number (1 is the first image)");
DEFINE_bool(solve, true, "Whether to solve for the field's target map.");
+DEFINE_bool(split_field, false,
+ "Whether to break solve into two sides of field");
DEFINE_int32(team_number, 0,
"Required: Use the calibration for a node with this team number");
DEFINE_uint64(wait_key, 1,
@@ -89,6 +91,9 @@
// Contains fixed target poses without solving, for use with visualization
static const TargetMapper kFixedTargetMapper;
+ // Map of TargetId to alliance "color" for splitting field
+ static std::map<uint, std::string> kIdAllianceMap;
+
// Change reference frame from camera to robot
static Eigen::Affine3d CameraToRobotDetection(Eigen::Affine3d H_camera_target,
Eigen::Affine3d extrinsics);
@@ -110,8 +115,8 @@
std::vector<DataAdapter::TimestampedDetection> timestamped_target_detections_;
VisualizeRobot vis_robot_;
- // Set of node names which are currently drawn on the display
- std::set<std::string> drawn_nodes_;
+ // Set of camera names which are currently drawn on the display
+ std::set<std::string> drawn_cameras_;
// Number of frames displayed
size_t display_count_;
// Last time we drew onto the display image.
@@ -124,6 +129,9 @@
// used to determine if we need to pause for the user to see this frame
// clearly
double max_delta_T_world_robot_;
+ double ignore_count_;
+
+ std::map<std::string, int> camera_numbering_map_;
std::vector<std::unique_ptr<aos::EventLoop>> mapping_event_loops_;
@@ -138,6 +146,12 @@
{"/imu/camera1", cv::Scalar(255, 165, 0)},
};
+std::map<uint, std::string> TargetMapperReplay::kIdAllianceMap = {
+ {1, "red"}, {2, "red"}, {3, "red"}, {4, "red"},
+ {5, "red"}, {6, "blue"}, {7, "blue"}, {8, "blue"},
+ {9, "blue"}, {10, "blue"}, {11, "red"}, {12, "red"},
+ {13, "red"}, {14, "blue"}, {15, "blue"}, {16, "blue"}};
+
const auto TargetMapperReplay::kFixedTargetMapper =
TargetMapper(FLAGS_json_path, ceres::examples::VectorOfConstraints{});
@@ -152,13 +166,17 @@
: reader_(reader),
timestamped_target_detections_(),
vis_robot_(cv::Size(1280, 1000)),
- drawn_nodes_(),
+ drawn_cameras_(),
display_count_(0),
last_draw_time_(aos::distributed_clock::min_time),
last_H_world_robot_(Eigen::Matrix4d::Identity()),
max_delta_T_world_robot_(0.0) {
reader_->RemapLoggedChannel("/orin1/constants", "y2024.Constants");
reader_->RemapLoggedChannel("/imu/constants", "y2024.Constants");
+ // If it's Box of Orins, don't remap roborio constants
+ if (FLAGS_team_number == 7971) {
+ reader_->RemapLoggedChannel("/roborio/constants", "y2024.Constants");
+ }
reader_->Register();
SendSimulationConstants(reader_->event_loop_factory(), FLAGS_team_number,
@@ -168,6 +186,7 @@
node_list.push_back("imu");
node_list.push_back("orin1");
+ int camera_count = 0;
for (std::string node : node_list) {
const aos::Node *pi =
aos::configuration::GetNode(reader->configuration(), node);
@@ -186,6 +205,10 @@
HandleNodeCaptures(
mapping_event_loops_[mapping_event_loops_.size() - 1].get(),
&constants_fetcher, 1);
+ std::string camera0_name = "/" + node + "/camera0";
+ camera_numbering_map_[camera0_name] = camera_count++;
+ std::string camera1_name = "/" + node + "/camera1";
+ camera_numbering_map_[camera1_name] = camera_count++;
}
if (FLAGS_visualize_solver) {
@@ -205,6 +228,11 @@
std::stringstream label;
label << camera_name << " - ";
+ if (map.target_poses()->size() == 0) {
+ VLOG(2) << "Got 0 AprilTags for camera " << camera_name;
+ return;
+ }
+
for (const auto *target_pose_fbs : *map.target_poses()) {
// Skip detections with invalid ids
if (static_cast<TargetMapper::TargetId>(target_pose_fbs->id()) <
@@ -242,13 +270,18 @@
double distance_from_camera = target_pose_camera.p.norm();
double distortion_factor = target_pose_fbs->distortion_factor();
- if (distance_from_camera > 5.0) {
+ double distance_threshold = 5.0;
+ if (distance_from_camera > distance_threshold) {
+ ignore_count_++;
+ LOG(INFO) << "Ignored " << ignore_count_ << " AprilTags with distance "
+ << distance_from_camera << " > " << distance_threshold;
continue;
}
CHECK(map.has_monotonic_timestamp_ns())
<< "Need detection timestamps for mapping";
+ // Detection is usable, so store it
timestamped_target_detections_.emplace_back(
DataAdapter::TimestampedDetection{
.time = node_distributed_time,
@@ -260,7 +293,7 @@
if (FLAGS_visualize_solver) {
// If we've already drawn this camera_name in the current image,
// display the image before clearing and adding the new poses
- if (drawn_nodes_.count(camera_name) != 0) {
+ if (drawn_cameras_.count(camera_name) != 0) {
display_count_++;
cv::putText(vis_robot_.image_,
"Poses #" + std::to_string(display_count_),
@@ -268,7 +301,7 @@
cv::Scalar(255, 255, 255));
if (display_count_ >= FLAGS_skip_to) {
- VLOG(1) << "Showing image for node " << camera_name
+ VLOG(1) << "Showing image for camera " << camera_name
<< " since we've drawn it already";
cv::imshow("View", vis_robot_.image_);
// Pause if delta_T is too large, but only after first image (to make
@@ -284,10 +317,10 @@
}
max_delta_T_world_robot_ = 0.0;
} else {
- VLOG(1) << "At poses #" << std::to_string(display_count_);
+ VLOG(2) << "At poses #" << std::to_string(display_count_);
}
vis_robot_.ClearImage();
- drawn_nodes_.clear();
+ drawn_cameras_.clear();
}
Eigen::Affine3d H_world_target = PoseUtils::Pose3dToAffine3d(
@@ -316,7 +349,7 @@
max_delta_T_world_robot_ =
std::max(delta_T_world_robot, max_delta_T_world_robot_);
- VLOG(1) << "Drew in info for robot " << camera_name << " and target #"
+ VLOG(1) << "Drew in info for camera " << camera_name << " and target #"
<< target_pose_fbs->id();
drew = true;
last_draw_time_ = node_distributed_time;
@@ -325,26 +358,30 @@
}
if (FLAGS_visualize_solver) {
if (drew) {
- // Collect all the labels from a given node, and add the text
- size_t pi_number =
- static_cast<size_t>(camera_name[camera_name.size() - 1] - '0');
+ // Collect all the labels from a given camera, and add the text
+ // TODO: Need to fix this one
+ int position_number = camera_numbering_map_[camera_name];
cv::putText(vis_robot_.image_, label.str(),
- cv::Point(10, 10 + 20 * pi_number), cv::FONT_HERSHEY_PLAIN,
- 1.0, kOrinColors.at(camera_name));
+ cv::Point(10, 10 + 20 * position_number),
+ cv::FONT_HERSHEY_PLAIN, 1.0, kOrinColors.at(camera_name));
- drawn_nodes_.emplace(camera_name);
+ drawn_cameras_.emplace(camera_name);
} else if (node_distributed_time - last_draw_time_ >
std::chrono::milliseconds(30) &&
- display_count_ >= FLAGS_skip_to) {
- cv::putText(vis_robot_.image_, "No detections", cv::Point(10, 0),
- cv::FONT_HERSHEY_PLAIN, 1.0, kOrinColors.at(camera_name));
+ display_count_ >= FLAGS_skip_to && drew) {
+ // TODO: Check on 30ms value-- does this make sense?
+ double delta_t = (node_distributed_time - last_draw_time_).count() / 1e6;
+ VLOG(1) << "Last result was " << delta_t << "ms ago";
+ cv::putText(vis_robot_.image_, "No detections in last 30ms",
+ cv::Point(10, 0), cv::FONT_HERSHEY_PLAIN, 1.0,
+ kOrinColors.at(camera_name));
// Display and clear the image if we haven't draw in a while
VLOG(1) << "Displaying image due to time lapse";
cv::imshow("View", vis_robot_.image_);
cv::waitKey(FLAGS_wait_key);
vis_robot_.ClearImage();
max_delta_T_world_robot_ = 0.0;
- drawn_nodes_.clear();
+ drawn_cameras_.clear();
}
}
}
@@ -383,21 +420,20 @@
auto target_constraints =
DataAdapter::MatchTargetDetections(timestamped_target_detections_);
- // Remove constraints between the two sides of the field - these are
- // basically garbage because of how far the camera is. We will use seeding
- // below to connect the two sides
- target_constraints.erase(
- std::remove_if(target_constraints.begin(), target_constraints.end(),
- [](const auto &constraint) {
- // TODO(james): This no longer makes sense.
- constexpr TargetMapper::TargetId kMaxRedId = 4;
- TargetMapper::TargetId min_id =
- std::min(constraint.id_begin, constraint.id_end);
- TargetMapper::TargetId max_id =
- std::max(constraint.id_begin, constraint.id_end);
- return (min_id <= kMaxRedId && max_id > kMaxRedId);
- }),
- target_constraints.end());
+ if (FLAGS_split_field) {
+ // Remove constraints between the two sides of the field - these are
+ // basically garbage because of how far the camera is. We will use seeding
+ // below to connect the two sides
+ target_constraints.erase(
+ std::remove_if(
+ target_constraints.begin(), target_constraints.end(),
+ [](const auto &constraint) {
+ return (
+ kIdAllianceMap[static_cast<uint>(constraint.id_begin)] !=
+ kIdAllianceMap[static_cast<uint>(constraint.id_end)]);
+ }),
+ target_constraints.end());
+ }
LOG(INFO) << "Solving for locations of tags with "
<< target_constraints.size() << " constraints";
diff --git a/y2024/wpilib_interface.cc b/y2024/wpilib_interface.cc
index 6b2acc4..301ab79 100644
--- a/y2024/wpilib_interface.cc
+++ b/y2024/wpilib_interface.cc
@@ -53,6 +53,7 @@
#include "frc971/wpilib/wpilib_robot_base.h"
#include "y2024/constants.h"
#include "y2024/constants/constants_generated.h"
+#include "y2024/control_loops/superstructure/led_indicator.h"
#include "y2024/control_loops/superstructure/superstructure_can_position_static.h"
#include "y2024/control_loops/superstructure/superstructure_output_generated.h"
#include "y2024/control_loops/superstructure/superstructure_position_generated.h"
@@ -493,7 +494,7 @@
current_limits->climber_stator_current_limit(),
current_limits->climber_supply_current_limit());
std::shared_ptr<TalonFX> extend =
- (robot_constants->common()->disable_extend())
+ (robot_constants->robot()->disable_extend())
? nullptr
: std::make_shared<TalonFX>(
12, false, "Drivetrain Bus", &canivore_signal_registry,
@@ -714,7 +715,7 @@
can_superstructure_writer.add_talonfx("catapult_two", catapult_two);
can_superstructure_writer.add_talonfx("turret", turret);
can_superstructure_writer.add_talonfx("climber", climber);
- if (!robot_constants->common()->disable_extend()) {
+ if (!robot_constants->robot()->disable_extend()) {
can_superstructure_writer.add_talonfx("extend", extend);
}
can_superstructure_writer.add_talonfx("intake_roller", intake_roller);
@@ -731,6 +732,14 @@
AddLoop(&can_output_event_loop);
+ // Thread 6
+ // Setup led_indicator
+ ::aos::ShmEventLoop led_indicator_event_loop(&config.message());
+ led_indicator_event_loop.set_name("LedIndicator");
+ control_loops::superstructure::LedIndicator led_indicator(
+ &led_indicator_event_loop);
+ AddLoop(&led_indicator_event_loop);
+
RunLoops();
}
};
diff --git a/y2024/y2024_imu.json b/y2024/y2024_imu.json
index ed43e10..2680856 100644
--- a/y2024/y2024_imu.json
+++ b/y2024/y2024_imu.json
@@ -163,7 +163,7 @@
"type": "aos.message_bridge.RemoteMessage",
"source_node": "imu",
"logger": "NOT_LOGGED",
- "frequency": 52,
+ "frequency": 100,
"num_senders": 2,
"max_size": 200
},