From 5d44519d0d38caff37319c06dbc3df1c910a5692 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Wed, 1 Sep 2021 17:57:24 -0600 Subject: [PATCH] fix warnings --- appmgr/nginx.conf | 117 +++++++-------------------------- appmgr/src/control.rs | 2 +- appmgr/src/db/model.rs | 12 ++-- appmgr/src/dependencies.rs | 11 ++-- appmgr/src/id.rs | 1 - appmgr/src/inspect.rs | 1 - appmgr/src/install/cleanup.rs | 28 +------- appmgr/src/install/mod.rs | 19 ++---- appmgr/src/install/progress.rs | 3 +- appmgr/src/manager/mod.rs | 2 +- appmgr/src/middleware/auth.rs | 5 +- appmgr/src/migration.rs | 2 +- appmgr/src/net/mdns.rs | 3 - appmgr/src/net/mod.rs | 2 +- appmgr/src/s9pk/manifest.rs | 6 +- appmgr/src/s9pk/mod.rs | 2 - appmgr/src/sound.rs | 12 +++- appmgr/src/status/mod.rs | 18 ++--- appmgr/src/util/mod.rs | 13 ++-- appmgr/src/version/mod.rs | 8 +-- 20 files changed, 68 insertions(+), 199 deletions(-) diff --git a/appmgr/nginx.conf b/appmgr/nginx.conf index d820868fd..0b6a04cb8 100644 --- a/appmgr/nginx.conf +++ b/appmgr/nginx.conf @@ -1,104 +1,33 @@ -## -# You should look at the following URL's in order to grasp a solid understanding -# of Nginx configuration files in order to fully unleash the power of Nginx. -# https://www.nginx.com/resources/wiki/start/ -# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/ -# https://wiki.debian.org/Nginx/DirectoryStructure -# -# In most cases, administrators will remove this file from sites-enabled/ and -# leave it as reference inside of sites-available where it will continue to be -# updated by the nginx packaging team. -# -# This file will automatically load configuration files provided by other -# applications, such as Drupal or Wordpress. These applications will be made -# available underneath a path with that package name, such as /drupal8. -# -# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. -## - -# Default server configuration -# server { - listen 80 default_server; - listen [::]:80 default_server; + listen 80 default_server; + listen [::]:80 default_server; - # SSL configuration - # - # listen 443 ssl default_server; - # listen [::]:443 ssl default_server; - # - # Note: You should disable gzip for SSL traffic. - # See: https://bugs.debian.org/773332 - # - # Read up on ssl_ciphers to ensure a secure configuration. - # See: https://bugs.debian.org/765782 - # - # Self signed certs generated by the ssl-cert package - # Don't use them in a production server! - # - # include snippets/snakeoil.conf; + root /var/www/html; - root /var/www/html; + index index.html index.htm index.nginx-debian.html; - # Add index.php to the list if you are using PHP - index index.html index.htm index.nginx-debian.html; + server_name _; - server_name _; + proxy_buffering off; + proxy_request_buffering off; + proxy_socket_keepalive on; + proxy_http_version 1.1; - proxy_request_buffering off; + location /rpc/ { + proxy_pass http://localhost:5959/; + } - location /rpc { - proxy_pass http://localhost:5959/; - } + location /ws/ { + proxy_pass http://localhost:5960/; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + } - location /ws/ { - proxy_pass http://localhost:5960/; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - } + location /marketplace/ { + proxy_pass https://beta-registry-0-3.start9labs.com/; + } - location / { - # First attempt to serve request as file, then - # as directory, then fall back to displaying a 404. - try_files $uri $uri/ =404; - } - - # pass PHP scripts to FastCGI server - # - #location ~ \.php$ { - # include snippets/fastcgi-php.conf; - # - # # With php-fpm (or other unix sockets): - # fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; - # # With php-cgi (or other tcp sockets): - # fastcgi_pass 127.0.0.1:9000; - #} - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - #location ~ /\.ht { - # deny all; - #} + location / { + try_files $uri $uri/ =404; + } } - - -# Virtual Host configuration for example.com -# -# You can move that to a different file under sites-available/ and symlink that -# to sites-enabled/ to enable it. -# -#server { -# listen 80; -# listen [::]:80; -# -# server_name example.com; -# -# root /var/www/example.com; -# index index.html; -# -# location / { -# try_files $uri $uri/ =404; -# } -#} diff --git a/appmgr/src/control.rs b/appmgr/src/control.rs index 8dafa7999..f8740bfb0 100644 --- a/appmgr/src/control.rs +++ b/appmgr/src/control.rs @@ -1,5 +1,5 @@ use anyhow::anyhow; -use chrono::{DateTime, Utc}; +use chrono::Utc; use indexmap::IndexMap; use patch_db::DbHandle; use rpc_toolkit::command; diff --git a/appmgr/src/db/model.rs b/appmgr/src/db/model.rs index 030a9555f..af458cbb1 100644 --- a/appmgr/src/db/model.rs +++ b/appmgr/src/db/model.rs @@ -1,9 +1,8 @@ -use std::net::Ipv4Addr; use std::sync::Arc; use indexmap::{IndexMap, IndexSet}; use patch_db::json_ptr::JsonPointer; -use patch_db::{DbHandle, HasModel, Map, MapModel, OptionModel}; +use patch_db::{HasModel, Map, MapModel, OptionModel}; use reqwest::Url; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -16,7 +15,6 @@ use crate::s9pk::manifest::{Manifest, ManifestModel, PackageId}; use crate::status::health_check::HealthCheckId; use crate::status::Status; use crate::util::Version; -use crate::Error; #[derive(Debug, Deserialize, Serialize, HasModel)] #[serde(rename_all = "kebab-case")] @@ -145,11 +143,11 @@ impl StaticFiles { icon: format!("/public/package-data/{}/{}/icon.{}", id, version, icon_type), } } - pub fn remote(id: &PackageId, version: &Version, icon_type: &str) -> Self { + pub fn remote(id: &PackageId, version: &Version) -> Self { StaticFiles { - license: format!("/marketplace/package/{}/{}/LICENSE.md", id, version), - instructions: format!("/marketplace/package/{}/{}/INSTRUCTIONS.md", id, version), - icon: format!("/marketplace/package/{}/{}/icon.{}", id, version, icon_type), + license: format!("/marketplace/package/license/{}?spec=={}", id, version), + instructions: format!("/marketplace/package/instructions/{}?spec=={}", id, version), + icon: format!("/marketplace/package/icon/{}?spec=={}", id, version), } } } diff --git a/appmgr/src/dependencies.rs b/appmgr/src/dependencies.rs index 0c3c64f6f..eda2fda6e 100644 --- a/appmgr/src/dependencies.rs +++ b/appmgr/src/dependencies.rs @@ -1,21 +1,18 @@ -use std::collections::HashMap; - use anyhow::anyhow; use emver::VersionRange; -use indexmap::{IndexMap, IndexSet}; +use indexmap::IndexMap; use patch_db::{DbHandle, DiffPatch, HasModel, Map, MapModel}; use serde::{Deserialize, Serialize}; use crate::action::ActionImplementation; -use crate::config::{Config, ConfigSpec}; +use crate::config::Config; use crate::db::model::CurrentDependencyInfo; -use crate::net::interface::InterfaceId; use crate::s9pk::manifest::PackageId; use crate::status::health_check::{HealthCheckId, HealthCheckResult, HealthCheckResultVariant}; -use crate::status::{DependencyErrors, MainStatus, Status}; +use crate::status::MainStatus; use crate::util::Version; use crate::volume::Volumes; -use crate::{Error, ResultExt as _}; +use crate::Error; #[derive(Clone, Debug, thiserror::Error, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] diff --git a/appmgr/src/id.rs b/appmgr/src/id.rs index b6eb33b2a..128578b6d 100644 --- a/appmgr/src/id.rs +++ b/appmgr/src/id.rs @@ -1,6 +1,5 @@ use std::borrow::{Borrow, Cow}; use std::fmt::Debug; -use std::path::Path; use serde::{Deserialize, Deserializer, Serialize, Serializer}; diff --git a/appmgr/src/inspect.rs b/appmgr/src/inspect.rs index 60439af3a..e2b3d1f21 100644 --- a/appmgr/src/inspect.rs +++ b/appmgr/src/inspect.rs @@ -2,7 +2,6 @@ use std::path::PathBuf; use rpc_toolkit::command; -use crate::context::CliContext; use crate::s9pk::manifest::Manifest; use crate::s9pk::reader::S9pkReader; use crate::util::{display_none, display_serializable, IoFormat}; diff --git a/appmgr/src/install/cleanup.rs b/appmgr/src/install/cleanup.rs index 95dfcaff0..9303f7c0b 100644 --- a/appmgr/src/install/cleanup.rs +++ b/appmgr/src/install/cleanup.rs @@ -1,19 +1,13 @@ -use std::borrow::Cow; use std::collections::HashMap; -use std::path::Path; use anyhow::anyhow; use bollard::image::ListImagesOptions; -use bollard::Docker; use patch_db::{DbHandle, PatchDbHandle}; -use tokio::process::Command; -use super::PKG_PUBLIC_DIR; use crate::context::RpcContext; use crate::db::model::{InstalledPackageDataEntry, PackageDataEntry}; -use crate::dependencies::DependencyError; -use crate::s9pk::manifest::{Manifest, PackageId}; -use crate::util::{Invoke, Version}; +use crate::s9pk::manifest::PackageId; +use crate::util::Version; use crate::Error; pub async fn update_dependents<'a, Db: DbHandle, I: IntoIterator>( @@ -171,21 +165,3 @@ pub async fn uninstall( tx.commit(None).await?; Ok(()) } - -#[tokio::test] -async fn test() { - dbg!( - Docker::connect_with_socket_defaults() - .unwrap() - .list_images(Some(ListImagesOptions { - all: false, - filters: { - let mut f = HashMap::new(); - f.insert("reference", vec!["start9/*:latest"]); - f - }, - digests: false - })) - .await - ); -} diff --git a/appmgr/src/install/mod.rs b/appmgr/src/install/mod.rs index ae10baa20..eee54fe05 100644 --- a/appmgr/src/install/mod.rs +++ b/appmgr/src/install/mod.rs @@ -2,29 +2,20 @@ use std::collections::HashSet; use std::fmt::Display; use std::io::SeekFrom; use std::path::Path; -use std::pin::Pin; use std::process::Stdio; -use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::atomic::Ordering; use std::sync::Arc; -use std::task::{Context, Poll}; -use std::time::Duration; use anyhow::anyhow; use emver::VersionRange; use futures::TryStreamExt; use http::{HeaderMap, StatusCode}; -use indexmap::{IndexMap, IndexSet}; -use patch_db::json_ptr::JsonPointer; -use patch_db::{ - DbHandle, HasModel, MapModel, Model, ModelData, OptionModel, PatchDbHandle, Revision, -}; +use indexmap::IndexMap; +use patch_db::{DbHandle, OptionModel}; use reqwest::Response; use rpc_toolkit::command; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use sha2::{Digest, Sha256}; use tokio::fs::{File, OpenOptions}; -use tokio::io::{AsyncRead, AsyncSeek, AsyncSeekExt, AsyncWrite, AsyncWriteExt}; +use tokio::io::{AsyncRead, AsyncSeek, AsyncSeekExt, AsyncWriteExt}; use self::cleanup::cleanup_failed; use crate::context::RpcContext; @@ -74,7 +65,7 @@ pub async fn install( let man: Manifest = man_res.json().await.with_kind(crate::ErrorKind::Registry)?; let progress = InstallProgress::new(s9pk.content_length()); - let static_files = StaticFiles::remote(&man.id, &man.version, man.assets.icon_type()); + let static_files = StaticFiles::remote(&man.id, &man.version); let mut db_handle = ctx.db.handle(); let mut tx = db_handle.begin().await?; let mut pde = crate::db::DatabaseModel::new() diff --git a/appmgr/src/install/progress.rs b/appmgr/src/install/progress.rs index b0a3a2b9e..8a7b34371 100644 --- a/appmgr/src/install/progress.rs +++ b/appmgr/src/install/progress.rs @@ -6,11 +6,10 @@ use std::sync::Arc; use std::task::{Context, Poll}; use std::time::Duration; -use patch_db::{DbHandle, HasModel, OptionModel, PatchDb, PatchDbHandle}; +use patch_db::{DbHandle, HasModel, OptionModel, PatchDb}; use serde::{Deserialize, Serialize}; use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite}; -use crate::db::model::PackageDataEntry; use crate::Error; #[derive(Debug, Deserialize, Serialize, HasModel)] diff --git a/appmgr/src/manager/mod.rs b/appmgr/src/manager/mod.rs index 87e61a438..da2341679 100644 --- a/appmgr/src/manager/mod.rs +++ b/appmgr/src/manager/mod.rs @@ -20,7 +20,7 @@ use crate::net::interface::InterfaceId; use crate::net::NetController; use crate::s9pk::manifest::{Manifest, PackageId}; use crate::util::{Container, Version}; -use crate::{Error, ResultExt}; +use crate::Error; pub struct ManagerMap(RwLock>>); impl ManagerMap { diff --git a/appmgr/src/middleware/auth.rs b/appmgr/src/middleware/auth.rs index b73c30e0a..84d8c04ee 100644 --- a/appmgr/src/middleware/auth.rs +++ b/appmgr/src/middleware/auth.rs @@ -1,6 +1,5 @@ use anyhow::anyhow; use basic_cookies::Cookie; -use chrono::Utc; use digest::Digest; use futures::future::BoxFuture; use futures::FutureExt; @@ -9,9 +8,7 @@ use rpc_toolkit::command_helpers::prelude::RequestParts; use rpc_toolkit::hyper::header::COOKIE; use rpc_toolkit::hyper::http::Error as HttpError; use rpc_toolkit::hyper::{Body, Request, Response}; -use rpc_toolkit::rpc_server_helpers::{ - noop3, noop4, to_response, DynMiddleware, DynMiddlewareStage2, DynMiddlewareStage3, -}; +use rpc_toolkit::rpc_server_helpers::{noop3, to_response, DynMiddleware, DynMiddlewareStage2}; use rpc_toolkit::yajrc::RpcMethod; use rpc_toolkit::Metadata; use sha2::Sha256; diff --git a/appmgr/src/migration.rs b/appmgr/src/migration.rs index dfa030763..16f1b0dfa 100644 --- a/appmgr/src/migration.rs +++ b/appmgr/src/migration.rs @@ -1,6 +1,6 @@ use anyhow::anyhow; use emver::VersionRange; -use indexmap::{IndexMap, IndexSet}; +use indexmap::IndexMap; use patch_db::HasModel; use serde::{Deserialize, Serialize}; diff --git a/appmgr/src/net/mdns.rs b/appmgr/src/net/mdns.rs index 400f246c4..cfa6ea642 100644 --- a/appmgr/src/net/mdns.rs +++ b/appmgr/src/net/mdns.rs @@ -5,14 +5,11 @@ use avahi_sys::{ avahi_entry_group_reset, avahi_free, AvahiEntryGroup, }; use libc::c_void; -use patch_db::{DbHandle, OptionModel}; use tokio::sync::Mutex; use torut::onion::TorSecretKeyV3; use super::interface::InterfaceId; use crate::s9pk::manifest::PackageId; -use crate::util::Apply; -use crate::Error; pub struct MdnsController(Mutex); impl MdnsController { diff --git a/appmgr/src/net/mod.rs b/appmgr/src/net/mod.rs index 1c5ab60ea..9d9cd4c66 100644 --- a/appmgr/src/net/mod.rs +++ b/appmgr/src/net/mod.rs @@ -9,7 +9,7 @@ use self::mdns::MdnsController; use self::tor::TorController; use crate::net::interface::TorConfig; use crate::s9pk::manifest::PackageId; -use crate::{Error, ResultExt}; +use crate::Error; pub mod interface; #[cfg(feature = "avahi")] diff --git a/appmgr/src/s9pk/manifest.rs b/appmgr/src/s9pk/manifest.rs index 34856a371..1122887b3 100644 --- a/appmgr/src/s9pk/manifest.rs +++ b/appmgr/src/s9pk/manifest.rs @@ -1,10 +1,7 @@ use std::borrow::Borrow; -use std::net::Ipv4Addr; use std::path::{Path, PathBuf}; use std::str::FromStr; -use chrono::{DateTime, Utc}; -use indexmap::IndexMap; use patch_db::HasModel; use serde::{Deserialize, Serialize, Serializer}; use url::Url; @@ -16,10 +13,9 @@ use crate::dependencies::Dependencies; use crate::id::{Id, InvalidId, SYSTEM_ID}; use crate::migration::Migrations; use crate::net::interface::Interfaces; -use crate::status::health_check::{HealthCheckResult, HealthChecks}; +use crate::status::health_check::HealthChecks; use crate::util::Version; use crate::volume::Volumes; -use crate::Error; pub const SYSTEM_PACKAGE_ID: PackageId<&'static str> = PackageId(SYSTEM_ID); diff --git a/appmgr/src/s9pk/mod.rs b/appmgr/src/s9pk/mod.rs index 318271724..8043f1655 100644 --- a/appmgr/src/s9pk/mod.rs +++ b/appmgr/src/s9pk/mod.rs @@ -1,9 +1,7 @@ -use std::io::Read; use std::path::PathBuf; use anyhow::anyhow; use rpc_toolkit::command; -use rpc_toolkit::yajrc::RpcError; use crate::context::CliContext; use crate::s9pk::builder::S9pkPacker; diff --git a/appmgr/src/sound.rs b/appmgr/src/sound.rs index 6aa857ae0..4cf933e6b 100644 --- a/appmgr/src/sound.rs +++ b/appmgr/src/sound.rs @@ -1,9 +1,13 @@ -use crate::{Error, ErrorKind, ResultExt}; +use std::cmp::Ordering; +use std::path::Path; +use std::time::Duration; + use divrem::DivRem; use proptest_derive::Arbitrary; -use std::{cmp::Ordering, path::Path, time::Duration}; use tokio::sync::{Mutex, MutexGuard}; +use crate::{Error, ErrorKind, ResultExt}; + lazy_static::lazy_static! { static ref SEMITONE_K: f64 = 2f64.powf(1f64 / 12f64); static ref A_4: f64 = 440f64; @@ -176,7 +180,7 @@ pub enum Semitone { impl Semitone { pub fn rotate(&self, n: isize) -> Semitone { - let mut temp = (*self as isize) + n; + let temp = (*self as isize) + n; match temp.rem_euclid(12) { 0 => Semitone::C, @@ -294,6 +298,7 @@ impl<'a> Iterator for CircleOf<'a> { macro_rules! song { ($tempo:expr, [$($note:expr;)*]) => { { + #[allow(dead_code)] const fn note(semi: Semitone, octave: i8, duration: TimeSlice) -> (Option, TimeSlice) { ( Some(Note { @@ -303,6 +308,7 @@ macro_rules! song { duration, ) } + #[allow(dead_code)] const fn rest(duration: TimeSlice) -> (Option, TimeSlice) { (None, duration) } diff --git a/appmgr/src/status/mod.rs b/appmgr/src/status/mod.rs index 73c816854..3d3a08694 100644 --- a/appmgr/src/status/mod.rs +++ b/appmgr/src/status/mod.rs @@ -2,27 +2,19 @@ use std::collections::HashMap; use std::sync::Arc; use anyhow::anyhow; -use bollard::container::{ListContainersOptions, StartContainerOptions, StopContainerOptions}; -use bollard::models::{ContainerStateStatusEnum, ContainerSummaryInner}; -use bollard::Docker; use chrono::{DateTime, Utc}; -use futures::{StreamExt, TryFutureExt}; +use futures::StreamExt; use indexmap::IndexMap; -use patch_db::{DbHandle, HasModel, Map, MapModel, Model, ModelData, ModelDataMut}; +use patch_db::{DbHandle, HasModel, Map, MapModel, ModelData}; use serde::{Deserialize, Serialize}; use self::health_check::{HealthCheckId, HealthCheckResult}; -use crate::action::docker::DockerAction; use crate::context::RpcContext; -use crate::db::model::{ - CurrentDependencyInfo, InstalledPackageDataEntryModel, PackageDataEntryModel, -}; -use crate::dependencies::{Dependencies, DependencyError}; +use crate::db::model::CurrentDependencyInfo; +use crate::dependencies::DependencyError; use crate::manager::{Manager, Status as ManagerStatus}; -use crate::net::interface::InterfaceId; use crate::s9pk::manifest::{Manifest, PackageId}; use crate::status::health_check::HealthCheckResultVariant; -use crate::util::Invoke; use crate::Error; pub mod health_check; @@ -326,7 +318,7 @@ impl DependencyErrors { current_dependencies: &IndexMap, ) -> Result { let mut res = IndexMap::new(); - for (dep_id, info) in current_dependencies { + for dep_id in current_dependencies.keys() { if let Err(e) = manifest .dependencies .0 diff --git a/appmgr/src/util/mod.rs b/appmgr/src/util/mod.rs index 400956662..959981606 100644 --- a/appmgr/src/util/mod.rs +++ b/appmgr/src/util/mod.rs @@ -1,7 +1,7 @@ use std::future::Future; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; use std::path::Path; use std::process::{exit, Stdio}; use std::str::FromStr; @@ -9,14 +9,13 @@ use std::time::Duration; use anyhow::anyhow; use async_trait::async_trait; -use clap::{Arg, ArgMatches}; +use clap::ArgMatches; use digest::Digest; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::Value; -use sqlx::{Executor, Sqlite}; use tokio::fs::File; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf}; -use tokio::sync::{Mutex, RwLock}; +use tokio::sync::RwLock; use crate::{Error, ResultExt as _}; @@ -770,7 +769,7 @@ impl IoFormat { pub fn display_serializable(t: T, matches: &ArgMatches<'_>) { let format = match matches.value_of("format").map(|f| f.parse()) { Some(Ok(f)) => f, - Some(Err(e)) => { + Some(Err(_)) => { eprintln!("unrecognized formatter"); exit(1) } @@ -791,7 +790,7 @@ pub fn parse_stdin_deserializable Deserialize<'de>>( ) -> Result { let format = match matches.value_of("format").map(|f| f.parse()) { Some(Ok(f)) => f, - Some(Err(e)) => { + Some(Err(_)) => { eprintln!("unrecognized formatter"); exit(1) } @@ -800,7 +799,7 @@ pub fn parse_stdin_deserializable Deserialize<'de>>( format.from_reader(stdin) } -pub fn parse_duration(arg: &str, matches: &ArgMatches<'_>) -> Result { +pub fn parse_duration(arg: &str, _: &ArgMatches<'_>) -> Result { let units_idx = arg.find(|c: char| c.is_alphabetic()).ok_or_else(|| { Error::new( anyhow!("Must specify units for duration"), diff --git a/appmgr/src/version/mod.rs b/appmgr/src/version/mod.rs index c1fefd2dd..378297921 100644 --- a/appmgr/src/version/mod.rs +++ b/appmgr/src/version/mod.rs @@ -1,11 +1,11 @@ use std::cmp::Ordering; use async_trait::async_trait; -use futures::stream::TryStreamExt; use lazy_static::lazy_static; use patch_db::DbHandle; use rpc_toolkit::command; -use tokio_compat_02::FutureExt; + +use crate::Error; // mod v0_1_0; // mod v0_1_1; @@ -31,10 +31,6 @@ use tokio_compat_02::FutureExt; // pub use v0_2_12::Version as Current; pub type Current = (); -use crate::context::{CliContext, RpcContext}; -use crate::util::{to_yaml_async_writer, AsyncCompat}; -use crate::{Error, ResultExt as _}; - #[derive(serde::Serialize, serde::Deserialize)] #[serde(untagged)] enum Version {